viewer_compressed.js 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Do not edit this file; automatically generated by blockscad_build.py.
  2. "use strict";
  3. var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{};
  4. Blockscad.Viewer=function(g,l,p,k){var c=GL.create();this.gl=c;this.angleX=-60;this.angleY=0;this.angleZ=-45;this.viewpointX=0;this.viewpointY=-5;this.viewpointZ=k;this.defaultColor=[1,.5,1,1];this.touch={lastX:0,lastY:0,scale:0,ctrl:0,shiftTimer:null,shiftControl:null,cur:null};this.lineOverlay=this.drawLines=!1;c.canvas.width=l;c.canvas.height=p;c.viewport(0,0,l,p);c.matrixMode(c.PROJECTION);c.loadIdentity();c.perspective(45,l/p,1,3E3);c.matrixMode(c.MODELVIEW);c.blendFunc(c.SRC_ALPHA,c.ONE_MINUS_SRC_ALPHA);
  5. c.clearColor(1,1,1,1);c.enable(c.DEPTH_TEST);c.enable(c.CULL_FACE);c.polygonOffset(1,1);this.blackShader=new GL.Shader("void main() {gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;}","void main() {gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);}");this.lightingShader=new GL.Shader("varying vec3 color;varying float alpha;varying vec3 normal;varying vec3 light;void main() {const vec3 lightDir = vec3(1.0, 2.0, 3.0) / 3.741657386773941;light = lightDir;color = gl_Color.rgb;alpha = gl_Color.a;normal = gl_NormalMatrix * gl_Normal;gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;}",
  6. "varying vec3 color;varying float alpha;varying vec3 normal;varying vec3 light;void main() {vec3 n = normalize(normal);float diffuse = max(0.0, dot(light, n));float specular = pow(max(0.0, -reflect(light, n).z), 18.0) * sqrt(diffuse);gl_FragColor = vec4(mix(color * (0.3 + 0.7 * diffuse), vec3(1.0), specular), alpha);}");var n=this,a=$('<div class="shift-scene"><div class="arrow arrow-left" /><div class="arrow arrow-right" /><div class="arrow arrow-top" /><div class="arrow arrow-bottom" /></div>');
  7. this.touch.shiftControl=a;$(g).append(c.canvas).append(a).hammer({drag_lock_to_axis:!0}).on("transform",function(a){2<=a.gesture.touches.length&&(n.clearShift(),n.onTransform(a),a.preventDefault())}).on("touch",function(b){if("touch"!=b.gesture.pointerType)b.preventDefault();else if(1==b.gesture.touches.length){var d=b.gesture.center;n.touch.shiftTimer=setTimeout(function(){a.addClass("active").css({left:d.pageX+"px",top:d.pageY+"px"});n.touch.shiftTimer=null;n.touch.cur="shifting"},500)}else n.clearShift()}).on("drag",
  8. function(a){if("touch"!=a.gesture.pointerType)a.preventDefault();else if(!n.touch.cur||"dragging"==n.touch.cur)n.clearShift(),n.onPanTilt(a);else if("shifting"==n.touch.cur)n.onShift(a)}).on("touchend",function(b){n.clearShift();n.touch.cur&&a.removeClass("active shift-horizontal shift-vertical")}).on("transformend dragstart dragend",function(a){if("transformend"==a.type&&"transforming"==n.touch.cur||"dragend"==a.type&&"shifting"==n.touch.cur||"dragend"==a.type&&"dragging"==n.touch.cur)n.touch.cur=
  9. null;n.touch.lastX=0;n.touch.lastY=0;n.touch.scale=0});c.onmousemove=function(a){n.onMouseMove(a)};c.ondraw=function(){n.onDraw()};c.onmousewheel=function(a){var b=0;a.wheelDelta?b=a.wheelDelta:a.detail&&(b=-40*a.detail);b&&(a=Math.pow(1.003,-(b/2)),b=n.getZoom(),n.setZoom(b*a))};this.clear()};
  10. Blockscad.Viewer.prototype={setCsg:function(g){this.gl.makeCurrent();this.meshes=Blockscad.Viewer.csgToMeshes(g,this.defaultColor);this.onDraw()},rendered_resize:function(g,l){this.gl.canvas.width=g;this.gl.canvas.height=l;this.gl.viewport(0,0,g,l);this.gl.matrixMode(this.gl.PROJECTION);this.gl.loadIdentity();this.gl.perspective(45,g/l,1,3E3);this.gl.matrixMode(this.gl.MODELVIEW);this.onDraw()},viewReset:function(g){g=g?g:document.getElementById("viewMenu").value;"diagonal"==g?(this.angleX=-60,this.angleY=
  11. 0,this.angleZ=-45,this.viewpointX=0,this.viewpointY=-5,this.viewpointZ=100):"top"==g?(this.viewpointY=this.viewpointX=this.angleZ=this.angleY=this.angleX=0,this.viewpointZ=100):"bottom"==g?(this.angleX=180,this.viewpointY=this.viewpointX=this.angleZ=this.angleY=0,this.viewpointZ=100):"right"==g?(this.angleX=-90,this.viewpointY=this.viewpointX=this.angleZ=this.angleY=0,this.viewpointZ=100):"front"==g?(this.angleX=-90,this.angleY=0,this.angleZ=-90,this.viewpointY=this.viewpointX=0,this.viewpointZ=100):
  12. "left"==g?(this.angleX=-90,this.angleY=0,this.angleZ=180,this.viewpointY=this.viewpointX=0,this.viewpointZ=100):"back"==g&&(this.angleX=-90,this.angleY=0,this.angleZ=90,this.viewpointY=this.viewpointX=0,this.viewpointZ=100);this.onDraw()},clear:function(){this.meshes=[];this.onDraw()},supported:function(){return!!this.gl},ZOOM_MAX:1500,ZOOM_MIN:5,onZoomChanged:null,plate:!0,setZoom:function(g){g=Math.max(g,0);g=Math.min(g,1);this.viewpointZ=this.ZOOM_MIN+g*(this.ZOOM_MAX-this.ZOOM_MIN);if(this.onZoomChanged)this.onZoomChanged();
  13. this.onDraw()},getZoom:function(){return(this.viewpointZ-this.ZOOM_MIN)/(this.ZOOM_MAX-this.ZOOM_MIN)},zoomOut:function(){var g=this.getZoom();this.setZoom(1.15*g)},zoomIn:function(){var g=this.getZoom();this.setZoom(.85*g)},onMouseMove:function(g){if(g.dragging){var l=g.button;g.which&&(l=g.which);g.preventDefault();g.altKey||3==l?(this.angleY+=g.deltaX,this.angleX+=g.deltaY):g.shiftKey||2==l?(l=.005,this.viewpointX+=l*g.deltaX*this.viewpointZ,this.viewpointY-=l*g.deltaY*this.viewpointZ):g.ctrlKey?
  14. (l=Math.pow(1.006,g.deltaX+g.deltaY),g=this.getZoom(),this.setZoom(g*l)):(this.angleZ+=g.deltaX,this.angleX+=g.deltaY);this.onDraw()}},clearShift:function(){this.touch.shiftTimer&&(clearTimeout(this.touch.shiftTimer),this.touch.shiftTimer=null);return this},onPanTilt:function(g){this.touch.cur="dragging";var l=0;!this.touch.lastY||"up"!=g.gesture.direction&&"down"!=g.gesture.direction?!this.touch.lastX||"left"!=g.gesture.direction&&"right"!=g.gesture.direction||(l=g.gesture.deltaX-this.touch.lastX,
  15. this.angleZ+=l):(l=g.gesture.deltaY-this.touch.lastY,this.angleX+=l);if(l)this.onDraw();this.touch.lastX=g.gesture.deltaX;this.touch.lastY=g.gesture.deltaY},onShift:function(g){this.touch.cur="shifting";var l=0;!this.touch.lastY||"up"!=g.gesture.direction&&"down"!=g.gesture.direction||(this.touch.shiftControl.removeClass("shift-horizontal").addClass("shift-vertical").css("top",g.gesture.center.pageY+"px"),l=g.gesture.deltaY-this.touch.lastY,this.viewpointY-=.005*l*this.viewpointZ,this.angleX+=l);
  16. !this.touch.lastX||"left"!=g.gesture.direction&&"right"!=g.gesture.direction||(this.touch.shiftControl.removeClass("shift-vertical").addClass("shift-horizontal").css("left",g.gesture.center.pageX+"px"),l=g.gesture.deltaX-this.touch.lastX,this.viewpointX+=.005*l*this.viewpointZ,this.angleZ+=l);if(l)this.onDraw();this.touch.lastX=g.gesture.deltaX;this.touch.lastY=g.gesture.deltaY},onTransform:function(g){this.touch.cur="transforming";if(this.touch.scale){var l=1/(1+g.gesture.scale-this.touch.scale),
  17. p=this.getZoom();this.setZoom(p*l)}this.touch.scale=g.gesture.scale;return this},onDraw:function(g,l,p){var k=this.gl;k.makeCurrent();g&&k.clearColor(1,1,1,1);if(g&&this.meshes[0]){l+=3*Math.PI/4;var c=this.bsph,n=this.bbox,n=1.3-(n[1].z-n[0].z)/(2*c.radius),a=2.6*c.radius;k.matrixMode(k.PROJECTION);k.loadIdentity();k.perspective(45,k.canvas.width/k.canvas.height,1,3E3);k.matrixMode(k.MODELVIEW);k.loadIdentity();k.lookAt(c.center.x+a*Math.sin(l),c.center.y+a*Math.cos(l),c.center.z+n*a/2,c.center.x,
  18. c.center.y,c.center.z,0,0,1)}else k.matrixMode(k.PROJECTION),k.loadIdentity(),k.perspective(45,k.canvas.width/k.canvas.height,1,3E3),k.matrixMode(k.MODELVIEW),k.loadIdentity(),k.translate(this.viewpointX,this.viewpointY,-this.viewpointZ),k.rotate(this.angleX,1,0,0),k.rotate(this.angleY,0,1,0),k.rotate(this.angleZ,0,0,1);k.clear(k.COLOR_BUFFER_BIT|k.DEPTH_BUFFER_BIT);k.enable(k.BLEND);this.lineOverlay||k.enable(k.POLYGON_OFFSET_FILL);for(l=0;l<this.meshes.length;l++)c=this.meshes[l],0<c.vertices.length&&
  19. this.lightingShader.draw(c,k.TRIANGLES);this.lineOverlay||k.disable(k.POLYGON_OFFSET_FILL);k.disable(k.BLEND);if(this.drawLines){this.lineOverlay&&k.disable(k.DEPTH_TEST);k.enable(k.BLEND);for(l=0;l<this.meshes.length;l++)c=this.meshes[l],0<c.vertices.length&&this.blackShader.draw(c,k.LINES);k.disable(k.BLEND);this.lineOverlay&&k.enable(k.DEPTH_TEST)}if(Blockscad.drawAxes&&!g){k.enable(k.BLEND);k.blendFunc(k.SRC_ALPHA,k.ONE_MINUS_SRC_ALPHA);k.begin(k.LINES);if(this.plate){k.color(.8,.8,.8,.5);for(l=
  20. -100;100>=l;l++)l%10&&0!==l&&(k.vertex(-100,l,0),k.vertex(100,l,0),k.vertex(l,-100,0),k.vertex(l,100,0),l<200/2.8&&l>-200/2.8&&(k.vertex(-.5,0,l),k.vertex(.5,0,l),k.vertex(0,-.5,l),k.vertex(0,.5,l)));k.color(.5,.5,.5,.5);for(l=10;100>=l;l+=10)0!==l&&(k.vertex(-100,l,0),k.vertex(100,l,0),k.vertex(l,-100,0),k.vertex(l,100,0),k.vertex(-100,-l,0),k.vertex(100,-l,0),k.vertex(-l,-100,0),k.vertex(-l,100,0),l<200/2.8&&(k.vertex(-1,0,l),k.vertex(1,0,l),k.vertex(0,-1,l),k.vertex(0,1,l),k.vertex(-1,0,-l),k.vertex(1,
  21. 0,-l),k.vertex(0,-1,-l),k.vertex(0,1,-l)))}k.color(1,0,0,1);k.vertex(0,0,0);k.vertex(100,0,0);for(l=-100;0>l;l++)l%2&&(k.vertex(l,0,0),k.vertex(l+1,0,0));k.color(0,.7,0,1);k.vertex(0,0,0);k.vertex(0,100,0);for(l=-100;0>l;l++)l%2&&(k.vertex(0,l,0),k.vertex(0,l+1,0));k.color(.1,.1,.4,1);k.vertex(0,0,0);k.vertex(0,0,200/2.8);for(l=Math.floor(-200/2.8);0>l;l++)l%2&&(k.vertex(0,0,l),k.vertex(0,0,l+1));k.color(0,0,0,1);k.vertex(102.5,-2.5,0);k.vertex(107.5,2.5,0);k.vertex(102.5,2.5,0);k.vertex(107.5,-2.5,
  22. 0);k.vertex(-2.5,110,0);k.vertex(0,107.5,0);k.vertex(0,107.5,0);k.vertex(2.5,110,0);k.vertex(0,102.5,0);k.vertex(0,107.5,0);k.vertex(-2.5,0,200/2.8+7.5);k.vertex(2.5,0,200/2.8+7.5);k.vertex(-2.5,0,200/2.8+2.5);k.vertex(2.5,0,200/2.8+2.5);k.vertex(-2.5,0,200/2.8+2.5);k.vertex(2.5,0,200/2.8+7.5);k.end();k.disable(k.BLEND)}if(g)return p=[],p[0]=this.gl.canvas.toDataURL("image/jpeg",g),k=document.createElement("canvas"),l=k.getContext("2d"),k.height=.5*this.gl.canvas.height,k.width=.5*this.gl.canvas.height,
  23. l.drawImage(this.gl.canvas,0,0,k.width,k.height),l=document.createElement("canvas"),c=l.getContext("2d"),l.height=.5*k.height,l.width=.5*k.width,c.drawImage(k,0,0,.5*k.width,.5*k.height),p[1]=l.toDataURL("image/jpeg",g),p;if(p)return this.gl.canvas.toDataURL("image/jpeg",p)},takePic:function(g,l){return this.onDraw(g,l)},takeCameraPic:function(g){return this.onDraw(0,0,g)}};
  24. Blockscad.Viewer.csgToMeshes=function(g,l){for(var p=g.canonicalized(),k=new GL.Mesh({normals:!0,colors:!0}),c=[k],n=[],a=[],b=[],p=p.toPolygons(),d=p.length,e=0;e<d;e++){var f=p[e],h=l;f.shared&&f.shared.color&&(h=f.shared.color);f.color&&(h=f.color);4>h.length&&h.push(1);for(var f=f.vertices.map(function(b){b.getTag();var d;d=n.length;n.push([b.pos.x,b.pos.y,b.pos.z]);a.push(h);return d}),m=2;m<f.length;m++)b.push([f[0],f[m-1],f[m]]);65E3<n.length&&(k.triangles=b,k.vertices=n,k.colors=a,k.computeWireframe(),
  25. k.computeNormals(),k=new GL.Mesh({normals:!0,colors:!0}),b=[],a=[],n=[],c.push(k))}k.triangles=b;k.vertices=n;k.colors=a;k.computeWireframe();k.computeNormals();return c};Blockscad.makeAbsoluteUrl=function(g,l){if(!g.match(/^[a-z]+\:/i)){var p=l.split("/");0<p.length&&p.splice(p.length-1,1);var k=g.split("/"),c=[];p.concat(k).map(function(g){".."==g?0<c.length&&c.splice(c.length-1,1):c.push(g)});g="";for(p=0;p<c.length;p++)0<p&&(g+="/"),g+=c[p]}return g};Blockscad.isChrome=function(){return 0<=navigator.userAgent.search("Chrome")};
  26. Blockscad.parseCodeInWorker=function(g,l,p){try{var k=openscadOpenJscadParser.parse(g);if(!k||!k.length)throw Error("parser produced no output at all");self.postMessage({cmd:"parsed",err:"haha"});Blockscad.runMainInWorker(k)}catch(c){self.postMessage({cmd:"errorParse",err:c.toString()})}};
  27. Blockscad.runMainInWorker=function(g){g=new Function(g);try{if("function"!=typeof g)throw Error("Your code has an error somewhere. Parsing your blocks failed.");var l=g();if("object"==typeof l[0]&&(l[0]instanceof CSG||l[0]instanceof CAG)){var p=l[0];p instanceof CAG&&(p=p.extrude({offset:[0,0,.1]}));if(1==l.length){var k=p.toCompactBinary();self.postMessage({cmd:"finalMesh",result:k})}else{var c=l[0],n=l.slice(1),c=c.union(n);c instanceof CAG&&(c=c.extrude({offset:[0,0,.1]}));self.postMessage({cmd:"log",
  28. txt:"number of polys final: "+c.polygons.length});var a=c.toCompactBinary();self.postMessage({cmd:"finalMesh",result:a})}}else throw Error("Nothing to Render!");}catch(b){self.postMessage({cmd:"error",err:b.toString()})}};
  29. Blockscad.parseBlockscadScriptSync=function(g,l){var p;p="//SYNC\n"+("_includePath = "+JSON.stringify(_includePath)+";\n");p=p+g+"return main();function include(fn) {if(0) {_csg_libraries.push(fn);} else if(0) {var url = _includePath!=='undefined'?_includePath:'./';var index = url.indexOf('index.html');if(index!=-1) {url = url.substring(0,index);}importScripts(url+fn);} else {var xhr = new XMLHttpRequest();xhr.open('GET',_includePath+fn,false);console.log('include:'+_includePath+fn);xhr.onload = function() {var src = this.responseText;eval(src);};xhr.onerror = function() {};xhr.send();}}";return(new Function(p))()};
  30. Blockscad.parseBlockscadScriptASync=function(g,l){var p=document.location.href.replace(/\?.*$/,""),k=p=p.replace(/#.*$/,""),p="//ASYNC\n"+("var _csg_baseurl="+JSON.stringify(p)+";\n"),p=p+"\n\n\n\n//// The following code was added by BlocksCAD:\n"+("var _csg_baselibraries="+JSON.stringify("blockscad/csg.js blockscad/formats.js opentype/dist/opentype.min.js blockscad/viewer.js blockscad/underscore.js blockscad/openscad-openjscad-translator.js".split(" "))+";\n"),p=p+("var _csg_libraries="+JSON.stringify([])+
  31. ";\n"),p=p+("var _csg_blockscadurl="+JSON.stringify(k)+";\n"),p=p+("var _csg_makeAbsoluteURL="+Blockscad.makeAbsoluteUrl.toString()+";\n"),p=p+"_csg_baselibraries = _csg_baselibraries.map(function(l){return _csg_makeAbsoluteURL(l,_csg_blockscadurl);});\n_csg_libraries = _csg_libraries.map(function(l){return _csg_makeAbsoluteURL(l,_csg_baseurl);});\n_csg_baselibraries.map(function(l){importScripts(l)});\n_csg_libraries.map(function(l){importScripts(l)});\nself.addEventListener('message', function(e) {if(e.data && e.data.cmd == 'render'){"+
  32. ("Blockscad.resolution = "+Blockscad.resolution+";"),k=Blockscad.textToBlobUrl(p+"Blockscad.csg_filename = e.data.csg_filename;Blockscad.csg_commands = e.data.csg_commands;Blockscad.fonts = {};var fontkeys = e.data.fontkeys;var fontdata = e.data.fontdata;for (var i = 0; i < fontkeys.length; i++) { Blockscad.fonts[fontkeys[i]] = opentype.parse(fontdata[i]); } Blockscad.parseCodeInWorker(e.data.data);}},false);\n");if(!window.Worker)throw Error("Your browser doesn't support Web Workers. Please try the Chrome or Firefox browser instead.");
  33. k=new Worker(k);k.onmessage=function(a){if(a.data)if("rendered"==a.data.cmd||"finalMesh"==a.data.cmd){var b=a.data.result["class"];if("CSG"==b)b=CSG.fromCompactBinary(a.data.result);else if("CAG"==b)b=CAG.fromCompactBinary(a.data.result);else throw Error("cannot parse final result");l(a.data.cmd,b)}else"error"==a.data.cmd?l(a.data.err,null):"errorParse"==a.data.cmd?(console.log("caught parsing error:",a.data.err),$("#error-message").html(a.data.err),$("#error-message").addClass("has-error"),l(a.data.err,
  34. null)):"parsed"==a.data.cmd?$("#render-ongoing").html(Blockscad.Msg.RENDER_IN_PROGRESS+'<img id=busy src="imgs/busy2.gif">'):"log"==a.data.cmd&&console.log(a.data.txt)};k.onerror=function(a){l("Error in line "+a.lineno+": "+a.message,null)};var p=[],c=[],n;for(n in Blockscad.fonts)p.push(n),c.push(Blockscad.fonts[n]);k.postMessage({cmd:"render",data:g,fontkeys:p,fontdata:c,csg_filename:Blockscad.csg_filename,csg_commands:Blockscad.csg_commands});return k};
  35. Blockscad.getWindowURL=function(){if(window.URL)return window.URL;if(window.webkitURL)return window.webkitURL;throw Error("Your browser doesn't support window.URL");};Blockscad.textToBlobUrl=function(g){var l=Blockscad.getWindowURL();g=new Blob([g]);l=l.createObjectURL(g);if(!l)throw Error("createObjectURL() failed");return l};
  36. Blockscad.revokeBlobUrl=function(g){if(window.URL)window.URL.revokeObjectURL(g);else if(window.webkitURL)window.webkitURL.revokeObjectURL(g);else throw Error("Your browser doesn't support window.URL");};Blockscad.AlertUserOfUncaughtExceptions=function(){window.onerror=function(g,l,p){g=g.replace(/^Uncaught /i,"");alert(g+"\n\n("+l+" line "+p+")")}};
  37. Blockscad.Processor=function(g,l){this.containerdiv=g;this.onchange=l;this.rpicviewer=this.picviewer=this.viewer=this.picdiv=this.viewerdiv=null;this.initialViewerDistance=100;this.processing=!1;this.currentObject=null;this.hasOutputFile=this.hasValidCurrentObject=!1;this.worker=null;this.paramDefinitions=[];this.paramControls=[];this.script=null;this.debugging=this.hasError=!1;this.img=this.imgStrip=this.thumbnail="none";this.createElements()};
  38. Blockscad.Processor.convertToSolid=function(g){if("object"!=typeof g||!(g instanceof CAG||g instanceof CSG))throw Error("Cannot convert to solid");return g};
  39. Blockscad.Processor.prototype={createElements:function(){for(var g=this;7<this.containerdiv.children.length;)this.containerdiv.removeChild(7);var l=document.createElement("div");l.style.width="100%";l.style.height="100%";l.style.top="0px";l.style.position="absolute";l.style.zIndex="9";this.containerdiv.appendChild(l);this.viewerdiv=l;var p=document.createElement("div");p.setAttribute("id","picdiv");p.style.width=Blockscad.picSize[0]+"px";p.style.height=Blockscad.picSize[1]+"px";p.style.top="0px";
  40. p.style.right="10px";p.style.position="absolute";p.style.zIndex="-1";document.getElementById("blocklyDiv").appendChild(p);this.picdiv=p;var k=document.createElement("div");k.setAttribute("id","picdiv");k.style.width=Blockscad.rpicSize[0]+"px";k.style.height=Blockscad.rpicSize[1]+"px";k.style.top="0px";k.style.right="10px";k.style.position="absolute";k.style.zIndex="-1";document.getElementById("blocklyDiv").appendChild(k);this.rpicdiv=k;try{this.picviewer=new Blockscad.Viewer(this.picdiv,p.offsetWidth,
  41. p.offsetHeight,this.initialViewerDistance)}catch(c){this.picdiv.innerHTML="<b><br><br>Error: "+c.toString()+"</b><br><br>BlocksCAD currently requires Google Chrome or Firefox with WebGL enabled"}$("#picdiv").addClass("hidden");try{this.rpicviewer=new Blockscad.Viewer(this.rpicdiv,k.offsetWidth,k.offsetHeight,this.initialViewerDistance)}catch(c){this.rpicdiv.innerHTML="<b><br><br>Error: "+c.toString()+"</b><br><br>BlocksCAD currently requires Google Chrome or Firefox with WebGL enabled"}$("#rpicdiv").addClass("hidden");
  42. try{this.viewer=new Blockscad.Viewer(this.viewerdiv,l.offsetWidth,l.offsetHeight,this.initialViewerDistance)}catch(c){this.viewerdiv.innerHTML="<b><br><br>Error: "+c.toString()+"</b><br><br>BlocksCAD currently requires Google Chrome or Firefox with WebGL enabled"}this.abortbutton=document.getElementById("abortButton");this.renderbutton=document.getElementById("renderButton");this.ongoingrender=document.getElementById("render-ongoing");this.abortbutton.onclick=function(c){g.abort()};this.formatDropdown=
  43. document.getElementById("render-type");this.formatDropdown.onchange=function(c){g.currentFormat=g.formatDropdown.options[g.formatDropdown.selectedIndex].value;g.updateDownloadLink()};this.generateOutputFileButton=document.getElementById("stlButton");this.generateOutputFileButton.onclick=function(c){g.generateOutputFile()};this.enableItems()},setCurrentObject:function(g,l){var p=Blockscad.Processor.convertToSolid(g);this.currentObject=p;this.hasValidCurrentObject=!0;this.viewer&&this.viewer.setCsg(p);
  44. this.picviewer&&(this.picviewer.bbox=p.getBounds(),this.picviewer.bsph=p.getBoundingSphere(),this.picviewer.setCsg(p));this.rpicviewer&&(this.rpicviewer.bbox=p.getBounds(),this.rpicviewer.bsph=p.getBoundingSphere(),this.rpicviewer.setCsg(p));if(l){for($("#stl_buttons").removeClass("hidden");0<this.formatDropdown.options.length;)this.formatDropdown.options.remove(0);var k=this;this.supportedFormatsForCurrentObject().forEach(function(c){var g=document.createElement("option");g.setAttribute("value",
  45. c);g.appendChild(document.createTextNode(k.formatInfo(c).displayName));k.formatDropdown.options.add(g)});this.updateDownloadLink()}},selectedFormat:function(){return this.formatDropdown.options[this.formatDropdown.selectedIndex].value},selectedFormatInfo:function(){return this.formatInfo(this.selectedFormat())},updateDownloadLink:function(){var g=this.selectedFormatInfo().extension;this.generateOutputFileButton.innerHTML=Blockscad.Msg.GENERATE_STL+" "+g.toUpperCase()},clearViewer:function(){this.clearOutputFile();
  46. this.setCurrentObject(new CSG);this.hasValidCurrentObject=!1;this.img=this.imgStrip=this.thumbnail="none";$("#stl_buttons").addClass("hidden");this.enableItems()},abort:function(){if(this.processing&&($("#renderButton").prop("disabled",!1),$("#render-ongoing").html(Blockscad.Msg.PARSE_IN_PROGRESS+'<img id=busy src="imgs/busy2.gif">'),this.processing=!1,this.worker.terminate(),this.enableItems(),this.onchange))this.onchange()},enableItems:function(){this.abortbutton.style.display=this.processing?"inline-block":
  47. "none";this.renderbutton.style.display=this.processing?"none":"inline-block";this.ongoingrender.style.display=this.processing?"inline-block":"none"},setError:function(g){this.hasError=""!=g;$("#error-message").text(g);this.enableItems()},setDebugging:function(g){this.debugging=g},setBlockscad:function(g){this.script=g;this.rebuildSolid()},rebuildSolid:function(){this.abort();this.setError("");this.clearViewer();this.processing=!0;$("#renderButton").html(Blockscad.Msg.RENDER_BUTTON);$("#renderButton").prop("disabled",
  48. !1);this.enableItems();var g=this,l=this.debugging;if(!l)try{this.worker=Blockscad.parseBlockscadScriptASync(this.script,function(k,c){if(k&&"finalMesh"==k){$("#render-ongoing").html(Blockscad.Msg.PARSE_IN_PROGRESS+'<img id=busy src="imgs/busy2.gif">');g.processing=!1;g.setCurrentObject(c,!0);var l=g.picviewer.takePic(Blockscad.picQuality,0,1);g.img=l[0];g.thumbnail=l[1];g.imgStrip=g.takeRotatingPic(1,Blockscad.numRotPics);g.processing=!1;g.worker=null}else k&&"rendered"==k?($("#render-ongoing").html('Prepare for Download...<img id=busy src="imgs/busy2.gif">'),
  49. g.setCurrentObject(c,!1),l=g.picviewer.takePic(Blockscad.picQuality,0,1),g.img=l[0],g.thumbnail=l[1],g.imgStrip=g.takeRotatingPic(1,Blockscad.numRotPics)):(console.log("what is going on?"),console.log("error in proc"+k),g.processing=!1,g.worker=null,g.setError(k));if(g.onchange)g.onchange();g.enableItems()})}catch(k){console.log("async failed, try sync compute, error: "+k.message),l=!0}if(l){try{var p=Blockscad.parseBlockscadScriptSync(this.script,this.debugging);g.setCurrentObject(p);g.processing=
  50. !1}catch(k){g.processing=!1,(l=k.stack)||(l=k.toString()),g.setError(l)}g.enableItems();if(g.onchange)g.onchange()}},hasSolid:function(){return this.hasValidCurrentObject},isProcessing:function(){return this.processing},clearOutputFile:function(){if(this.hasOutputFile&&(this.outputFileBlobUrl&&(Blockscad.revokeBlobUrl(this.outputFileBlobUrl),this.outputFileBlobUrl=null),this.enableItems(),this.onchange))this.onchange()},generateOutputFile:function(){this.clearOutputFile();this.hasValidCurrentObject&&
  51. this.generateAndSaveRenderedFile()},currentObjectToBlob:function(){var g=this.selectedFormat();if("stla"==g)g=this.currentObject.toStlString(),g=new Blob([g],{type:"text/plain; charset=utf-8"});else if("stlb"==g)g=this.currentObject.toStlBinary({webBlob:!0});else if("amf"==g)g=this.currentObject.toAMFString({producer:"BlocksCAD "+Blockscad.version,date:new Date}),g=new Blob([g],{type:"text/plain; charset=utf-8"});else if("x3d"==g)g=this.currentObject.toX3D(),g=new Blob([g],{type:"text/plain; charset=utf-8"});
  52. else if("dxf"==g)g=this.currentObject.toDxf(),g=new Blob([g],{type:"text/plain; charset=utf-8"});else if("obj"==g)g=this.currentObject.toObj(),g=new Blob([g],{type:"text/plain; charset=utf-8"});else throw Error("Not supported");return g},supportedFormatsForCurrentObject:function(){if(this.currentObject instanceof CSG)return-1!=navigator.userAgent.indexOf("Safari")&&-1==navigator.userAgent.indexOf("Chrome")?["stla","amf","x3d"]:["stlb","stla","x3d","obj","amf"];if(this.currentObject instanceof CAG)return["dxf"];
  53. throw Error("Not supported");},formatInfo:function(g){return{stla:{displayName:"STL (ASCII)",extension:"stl",mimetype:"application/sla"},obj:{displayName:"OBJ (ASCII)",extension:"obj",mimetype:"application/sla"},stlb:{displayName:"STL (Binary)",extension:"stl",mimetype:"application/sla"},amf:{displayName:"AMF",extension:"amf",mimetype:"application/amf+xml"},x3d:{displayName:"X3D",extension:"x3d",mimetype:"model/x3d+xml"},dxf:{displayName:"DXF",extension:"dxf",mimetype:"application/dxf"}}[g]},generateAndSaveRenderedFile:function(){var g=
  54. this.currentObjectToBlob(),l=this.selectedFormatInfo().extension,p=$("#project-name").val();p?saveAs(g,p+"."+l):($("#message-text").html("<h4>"+Blockscad.Msg.SAVE_FAILED+" "+Blockscad.Msg.SAVE_FAILED_PROJECT_NAME+".</h4>"),$("#message-modal").modal())},takeRotatingPic:function(g,l){var p=[],k=[],c=document.createElement("canvas");c.width=Blockscad.rpicSize[0]*l;c.height=Blockscad.rpicSize[0];for(var n=c.getContext("2d"),a=0;a<l;a+=1)p[a]=this.rpicviewer.takePic(g,2*Math.PI/l*-a)[0],k[a]=new Image,
  55. k[a].src=p[a],n.drawImage(k[a],a*Blockscad.rpicSize[0],0);return c.toDataURL("image/jpeg")}};
  56. Blockscad.pathToPoints=function(g,l){var p=[],k=[],c=[],n=2,a,b,d,e,f,h;2<l&&(n=l);10<n&&(n=10);if(g&&g.commands&&0<g.commands.length)for(var m=0,q=[],u=0;u<g.commands.length;u++)switch(g.commands[u].type){case "M":2<c.length&&k.push(c);c=[];p.push([g.commands[u].x,-1*g.commands[u].y]);c.push(m++);q=[g.commands[u].x,-1*g.commands[u].y];break;case "L":p.push([g.commands[u].x,-1*g.commands[u].y]);c.push(m++);q=[g.commands[u].x,-1*g.commands[u].y];break;case "C":a=[g.commands[u].x,-1*g.commands[u].y];
  57. b=[g.commands[u].x1,-1*g.commands[u].y1];d=[g.commands[u].x2,-1*g.commands[u].y2];for(var J=1;J<=n;J++)h=J/n,e=q[1]*Math.pow(1-h,3)+3*b[1]*Math.pow(1-h,2)*h+3*d[1]*Math.pow(1-h,1)*h*h+a[1]*Math.pow(h,3),p.push([e,f]),c.push(m++);q=a;break;case "Q":a=[g.commands[u].x,-1*g.commands[u].y];b=[g.commands[u].x1,-1*g.commands[u].y1];for(J=1;J<=n;J++)h=J/n,e=q[0]*Math.pow(1-h,2)+2*b[0]*Math.pow(1-h,1)*h+a[0]*Math.pow(h,2),f=q[1]*Math.pow(1-h,2)+2*b[1]*Math.pow(1-h,1)*h+a[1]*Math.pow(h,2),p.push([e,f]),c.push(m++);
  58. q=a;break;case "Z":2<c.length&&(k.push(c),c=[])}3>p.length&&(p=[]);return[p,k]};(function(g){function l(a,b){return a-b}function p(a,b,d){for(var c=0,f=a.length;f>c;){var h=Math.floor((c+f)/2);0<d(b,a[h])?c=h+1:f=h}a.splice(c,0,b)}function k(a,b){return a.index-b.index}var c=function(){this.polygons=[];this.properties=new c.Properties;this.isRetesselated=this.isCanonicalized=!0};c.defaultResolution2D=32;c.defaultResolution3D=12;c.fromPolygons=function(a){var b=new c;b.polygons=a;b.isCanonicalized=!1;b.isRetesselated=!1;return b};c.fromSlices=function(a){return(new c.Polygon.createFromPoints([[0,
  59. 0,0],[1,0,0],[1,1,0],[0,1,0]])).solidFromSlices(a)};c.fromObject=function(a){a=a.polygons.map(function(a){return c.Polygon.fromObject(a)});a=c.fromPolygons(a);return a=a.canonicalized()};c.uniqBy=function(a,b){var d={};return a.filter(function(a){a=b(a);return d.hasOwnProperty(a)?!1:d[a]=!0})};c.fromCompactBinary=function(a){if("CSG"!=a["class"])throw Error("Not a CSG");for(var b=[],d=a.planeData,e=d.length/4,f=0,h,m,q,u,g=0;g<e;g++)h=d[f++],m=d[f++],q=d[f++],u=d[f++],h=c.Vector3D.Create(h,m,q),h=
  60. new c.Plane(h,u),b.push(h);d=[];e=a.vertexData;g=e.length/3;for(u=f=0;u<g;u++)h=e[f++],m=e[f++],q=e[f++],h=c.Vector3D.Create(h,m,q),h=new c.Vertex(h),d.push(h);m=a.shared.map(function(a){return c.Polygon.Shared.fromObject(a)});q=[];e=a.numPolygons;g=a.numVerticesPerPolygon;u=a.polygonVertices;var k=a.polygonPlaneIndexes;a=a.polygonSharedIndexes;for(var l,n,p=f=0;p<e;p++){h=g[p];l=[];for(n=0;n<h;n++)l.push(d[u[f++]]);h=b[k[p]];n=m[a[p]];h=new c.Polygon(l,n,h);q.push(h)}b=c.fromPolygons(q);b.isCanonicalized=
  61. !0;b.isRetesselated=!0;return b};c.prototype={toPolygons:function(){return this.polygons},union:function(a){a instanceof Array?(a=a.slice(0),a.push(this)):a=[this,a];for(var b=1;b<a.length;b+=2)a.push(a[b-1].unionSub(a[b]));return a[b-1].reTesselated().canonicalized()},unionSub:function(a,b,d){if(this.mayOverlap(a)){var e=new c.Tree(this.polygons),f=new c.Tree(a.polygons);e.clipTo(f,!1);f.clipTo(e);f.invert();f.clipTo(e);f.invert();e=e.allPolygons().concat(f.allPolygons());e=c.fromPolygons(e);e.properties=
  62. this.properties._merge(a.properties);b&&(e=e.reTesselated());d&&(e=e.canonicalized());return e}return this.unionForNonIntersecting(a)},unionForNonIntersecting:function(a){var b=this.polygons.concat(a.polygons),b=c.fromPolygons(b);b.properties=this.properties._merge(a.properties);b.isCanonicalized=this.isCanonicalized&&a.isCanonicalized;b.isRetesselated=this.isRetesselated&&a.isRetesselated;return b},subtract:function(a){a=a instanceof Array?a:[a];for(var b=this,d=0;d<a.length;d++)var c=d==a.length-
  63. 1,b=b.subtractSub(a[d],c,c);return b},subtractSub:function(a,b,d){var e=new c.Tree(this.polygons),f=new c.Tree(a.polygons);e.invert();e.clipTo(f);f.clipTo(e,!0);e.addPolygons(f.allPolygons());e.invert();e=c.fromPolygons(e.allPolygons());e.properties=this.properties._merge(a.properties);b&&(e=e.reTesselated());d&&(e=e.canonicalized());return e},intersect:function(a){a=a instanceof Array?a:[a];for(var b=this,d=0;d<a.length;d++)var c=d==a.length-1,b=b.intersectSub(a[d],c,c);return b},intersectSub:function(a,
  64. b,d){var e=new c.Tree(this.polygons),f=new c.Tree(a.polygons);e.invert();f.clipTo(e);f.invert();e.clipTo(f);f.clipTo(e);e.addPolygons(f.allPolygons());e.invert();e=c.fromPolygons(e.allPolygons());e.properties=this.properties._merge(a.properties);b&&(e=e.reTesselated());d&&(e=e.canonicalized());return e},hull:function(a){var b=[];b.push(this);for(var d=0;d<a.length;d++)b.push(a[d]);for(d=0;d<b.length;d++)if(!(b[d]instanceof c))throw"ERROR: don't mix 2D and 3D shapes in hull";a=b;Array.isArray(a)||
  65. (a=[a]);for(var e=[],d=0;d<a.length;d++)for(var f=0;f<a[d].polygons.length;f++)for(var h=0;h<a[d].polygons[f].vertices.length;h++)e.push([a[d].polygons[f].vertices[h].pos._x,a[d].polygons[f].vertices[h].pos._y,a[d].polygons[f].vertices[h].pos._z]);e=c.uniqBy(e,JSON.stringify);a=[];for(d=0;d<e.length;d++)a.push(c.Vector3D.Create(e[d][0],e[d][1],e[d][2]));e=b[0].polygons[0].shared?b[0].polygons[0].shared.color:null;f=(new c.quickHull3D).build(a);b=[];for(d=0;d<f.length;d++){for(var h=[],m=0;m<f[d].length;m++)h.push(a[f[d][m]]);
  66. h=new c.Polygon.createFromPoints(h);e&&h.sC(e);b.push(h)}a=c.fromPolygons(b);a.isCanonicalized=!0;a.isRetesselated=!0;return c.fromPolygons(b)},invert:function(){var a=this.polygons.map(function(a){return a.flipped()});return c.fromPolygons(a)},transform1:function(a){var b=this.polygons.map(function(b){return b.transform(a)}),b=c.fromPolygons(b);b.properties=this.properties._transform(a);b.isRetesselated=this.isRetesselated;return b},transform:function(a){var b=a.isMirroring(),d={},e={},f=this.polygons.map(function(f){var h;
  67. h=f.plane;var q=h.getTag();q in e?h=e[q]:(h=h.transform(a),e[q]=h);q=f.vertices.map(function(b){var c=b.getTag();c in d?b=d[c]:(b=b.transform(a),d[c]=b);return b});b&&q.reverse();return new c.Polygon(q,f.shared,h)}),f=c.fromPolygons(f);f.properties=this.properties._transform(a);f.isRetesselated=this.isRetesselated;f.isCanonicalized=this.isCanonicalized;return f},taper:function(a,b){0>=b&&(b=1E-4);var d=this.getBounds(),e=0,f=0;a[0]?(e=d[1].x-d[0].x,f=d[0].x):a[1]?(e=d[1].y-d[0].y,f=d[0].y):a[2]&&
  68. (e=d[1].z-d[0].z,f=d[0].z);for(var d=[],h,m,q=0;q<this.polygons.length;q++)if(m=this.polygons[q].shared?this.polygons[q].shared.color:null,3<this.polygons[q].vertices.length)for(var u=this.polygons[q].vertices,g=[u[0].pos.x,u[0].pos.y,u[0].pos.z],k=1;k<this.polygons[q].vertices.length-1;k++)h=[],h[0]=g,h[1]=[u[k].pos.x,u[k].pos.y,u[k].pos.z],h[2]=[u[k+1].pos.x,u[k+1].pos.y,u[k+1].pos.z],h=new c.Polygon.createFromPoints(h),m&&h.sC(m),d.push(h);else d.push(this.polygons[q]);g=[];for(q=0;q<d.length;q++){m=
  69. d[q].shared?d[q].shared.color:null;h=[];for(k=0;k<d[q].vertices.length;k++){3<d[q].vertices.length&&console.log("bad facet - more than 3 vertices!");u=d[q].vertices[k].pos;if(a[0])var l=u.x,n=u.y*(1+(b-1)*(u.x-f)/e),p=u.z*(1+(b-1)*(u.x-f)/e);else a[1]?(n=u.y,l=u.x*(1+(b-1)*(u.y-f)/e),p=u.z*(1+(b-1)*(u.y-f)/e)):(p=u.z,n=u.y*(1+(b-1)*(u.z-f)/e),l=u.x*(1+(b-1)*(u.z-f)/e));h[k]=[l,n,p]}g[q]=new c.Polygon.createFromPoints(h);m&&g[q].sC(m)}return c.fromPolygons(g)},toString:function(){var a="CSG solid:\n";
  70. this.polygons.map(function(b){a+=b.toString()});return a},expand:function(a,b){var d=this.expandedShell(a,b,!0),d=d.reTesselated();d.properties=this.properties;return d},contract:function(a,b){var d=this.expandedShell(a,b,!1),d=this.subtract(d),d=d.reTesselated();d.properties=this.properties;return d},stretchAtPlane:function(a,b,d){a=c.Plane.fromNormalAndPoint(a,b);b=new c.OrthoNormalBasis(a);b=this.sectionCut(b).extrudeInOrthonormalBasis(b,d);var e=this.cutByPlane(a),f=this.cutByPlane(a.flipped());
  71. return e.union([b,f.tr(a.normal.times(d))])},expandedShell:function(a,b,d){var e=this.reTesselated(),f;f=d?e:new c;e.polygons.map(function(b){var d=b.plane.normal.unit().times(2*a);b=b.tr(d.times(-.5)).extrude(d);f=f.unionSub(b,!1,!1)});var h={};e.polygons.map(function(a){for(var b=a.vertices.length,d=a.vertices[b-1],c=d.getTag(),e=0;e<b;e++){var f=a.vertices[e],m=f.getTag(),c=m<c?m+"-"+c:c+"-"+m;c in h?d=h[c]:(d={v1:d,v2:f,planenormals:[]},h[c]=d);d.planenormals.push(a.plane.normal);c=m;d=f}});for(var m in h){var q=
  72. h[m],u=q.v1.pos,g=q.v2.pos;d=g.minus(u).unit();var k=q.planenormals[0].unit(),n=k.cross(d),p=[];for(d=0;d<b;d++)p.push(d*Math.PI*2/b);d=0;for(var B=q.planenormals.length;d<B;d++){var v=q.planenormals[d],t=n.dot(v),y=k.dot(v),A=Math.atan2(t,y);0>A&&(A+=2*Math.PI);p.push(A);A=Math.atan2(-t,-y);0>A&&(A+=2*Math.PI);p.push(A)}var p=p.sort(l),q=p.length,w,x,B=[],v=[],z=[];for(d=-1;d<q;d++)A=p[0>d?d+q:d],t=Math.sin(A),y=Math.cos(A),y=k.times(y*a).plus(n.times(t*a)),t=u.plus(y),y=g.plus(y),A=!1,0<=d&&1E-5>
  73. t.distanceTo(w)&&(A=!0),A||(0<=d&&(B.push(new c.Vertex(t)),v.push(new c.Vertex(y)),w=[new c.Vertex(x),new c.Vertex(y),new c.Vertex(t),new c.Vertex(w)],w=new c.Polygon(w),z.push(w)),w=t,x=y);v.reverse();z.push(new c.Polygon(B));z.push(new c.Polygon(v));d=c.fromPolygons(z);f=f.unionSub(d,!1,!1)}var D={};e.polygons.map(function(a){a.vertices.map(function(b){var d=b.getTag();d in D?b=D[d]:(b={pos:b.pos,normals:[]},D[d]=b);b.normals.push(a.plane.normal)})});for(var C in D){e=D[C];m=e.normals[0].unit();
  74. u=null;g=0;for(d=1;d<e.normals.length;d++)k=e.normals[d].unit(),w=m.cross(k).length(),.05<w&&w>g&&(g=w,u=k);u||(u=m.randomNonParallelVector());d=m.cross(u).unit();u=d.cross(m);d=c.sphere({center:e.pos,radius:a,resolution:b,axes:[m,d,u]});f=f.unionSub(d,!1,!1)}return f},canonicalized:function(){if(this.isCanonicalized)return this;var a=(new c.fuzzyCSGFactory).getCSG(this);a.isCanonicalized=!0;a.isRetesselated=this.isRetesselated;a.properties=this.properties;return a},reTesselated:function(){if(this.isRetesselated)return this;
  75. var a={},b=this.isCanonicalized,d=new c.fuzzyCSGFactory;this.polygons.map(function(c){var e=c.plane,f=c.shared;b||(e=d.getPlane(e),f=d.getPolygonShared(f));e=e.getTag()+"/"+f.getTag();e in a?a[e].push(c):a[e]=[c]});var e=[],f;for(f in a){var h=a[f];if(2>h.length)e=e.concat(h);else{var m=[];c.reTesselateCoplanarPolygons(h,m);e=e.concat(m)}}e=c.fromPolygons(e);e.isRetesselated=!0;e.properties=this.properties;return e},getBounds:function(){if(!this.cachedBoundingBox){for(var a=new c.Vector3D(0,0,0),
  76. b=new c.Vector3D(0,0,0),d=this.polygons,e=d.length,f=0;f<e;f++){var h=d[f].boundingBox();0===f?(a=h[0],b=h[1]):(a=a.min(h[0]),b=b.max(h[1]))}this.cachedBoundingBox=[a,b]}return this.cachedBoundingBox},getBoundingSphere:function(){if(!this.cachedBoundingSphere){var a;a=this.cachedBoundingBox?this.cachedBoundingBox:this.getBounds();a={center:a[0].plus(a[1]).dividedBy(2),radius:0};for(var b=0;b<this.polygons.length;b++)for(var d=0;d<this.polygons[b].vertices.length;d++){var e=this.polygons[b].vertices[d];
  77. a.radius=Math.max(a.radius,(new c.Vector3D(e.pos.x,e.pos.y,e.pos.z)).minus(a.center).lengthSquared())}a.radius=Math.sqrt(a.radius);this.cachedBoundingSphere=a}return this.cachedBoundingSphere},mayOverlap:function(a){if(0===this.polygons.length||0===a.polygons.length)return!1;var b=this.getBounds();a=a.getBounds();return b[1].x<a[0].x||b[0].x>a[1].x||b[1].y<a[0].y||b[0].y>a[1].y||b[1].z<a[0].z||b[0].z>a[1].z?!1:!0},cutByPlane:function(a){if(0===this.polygons.length)return new c;var b=a.normal.times(a.w),
  78. d=0;this.polygons.map(function(a){a.vertices.map(function(a){a=a.pos.distanceToSquared(b);a>d&&(d=a)})});var d=Math.sqrt(d),d=1.01*d,e=[],f=new c.OrthoNormalBasis(a);e.push(new c.Vertex(f.to3D(new c.Vector2D(d,-d))));e.push(new c.Vertex(f.to3D(new c.Vector2D(-d,-d))));e.push(new c.Vertex(f.to3D(new c.Vector2D(-d,d))));e.push(new c.Vertex(f.to3D(new c.Vector2D(d,d))));a=(new c.Polygon(e,null,a.flipped())).extrude(a.normal.times(-d));a=this.intersect(a);a.properties=this.properties;return a},connectTo:function(a,
  79. b,d,c){a=a.getTransformationTo(b,d,c);return this.transform(a)},setShared:function(a){var b=this.polygons.map(function(b){return new c.Polygon(b.vertices,a,b.plane)}),b=c.fromPolygons(b);b.properties=this.properties;b.isRetesselated=this.isRetesselated;b.isCanonicalized=this.isCanonicalized;return b},sC:function(a){var b=c.Polygon.Shared.fromColor.apply(this,arguments);return this.setShared(b)},toCompactBinary:function(){var a=this.canonicalized(),b=a.polygons.length,d=0,c=0,f={},h=[],m=0,q={},u=
  80. 0,g=[],k=[],l={},n=0;a.polygons.map(function(a){a.vertices.map(function(a){++d;var b=a.getTag();b in f||(f[b]=c++,h.push(a))});var b=a.plane.getTag();b in q||(q[b]=m++,g.push(a.plane));b=a.shared.getTag();b in l||(l[b]=n++,k.push(a.shared))});for(var p=new Uint32Array(b),v=new Uint32Array(b),t=new Uint32Array(d),y=new Uint32Array(b),A=new Float64Array(3*c),w=new Float64Array(4*m),x=0,u=0;u<b;++u){var z=a.polygons[u];p[u]=z.vertices.length;z.vertices.map(function(a){a=a.getTag();a=f[a];t[x++]=a});
  81. var D=z.plane.getTag();y[u]=q[D];z=z.shared.getTag();v[u]=l[z]}var C=0;h.map(function(a){a=a.pos;A[C++]=a._x;A[C++]=a._y;A[C++]=a._z});var F=0;g.map(function(a){var b=a.normal;w[F++]=b._x;w[F++]=b._y;w[F++]=b._z;w[F++]=a.w});return{"class":"CSG",numPolygons:b,numVerticesPerPolygon:p,polygonPlaneIndexes:y,polygonSharedIndexes:v,polygonVertices:t,vertexData:A,planeData:w,shared:k}},toPointCloud:function(a){var b=this.reTesselated(),d=new c,e={};b.polygons.map(function(a){a.vertices.map(function(a){e[a.getTag()]=
  82. a.pos})});for(var f in e)b=c.cube({center:e[f],radius:a}),d=d.unionSub(b,!1,!1);return d=d.reTesselated()},getTransformationAndInverseTransformationToFlatLying:function(){if(0===this.polygons.length)return new c.Matrix4x4;var a=this.canonicalized(),b={};a.polygons.map(function(a){b[a.plane.getTag()]=a.plane});var d=new c.Vector3D(1,0,0),e=new c.Vector3D(0,1,0),f=new c.Vector3D(0,0,1),h=new c.Connector([0,0,0],[0,0,-1],d),m=new c.Connector([0,0,0],[0,0,-1],e),q=!0,u=0,g=0,k,l,n;for(n in b){var p=b[n],
  83. v=p.normal.times(p.w),t;t=p.normal.cross(d).length();var y=p.normal.cross(e).length();t>y?(t=new c.Connector(v,p.normal,d),v=t.getTransformationTo(h,!1,0),t=h.getTransformationTo(t,!1,0)):(t=new c.Connector(v,p.normal,e),v=t.getTransformationTo(m,!1,0),t=m.getTransformationTo(t,!1,0));var y=a.transform(v),p=-p.normal.dot(f),A=y.getBounds(),y=A[1].z-A[0].z;q||(y<u?q=!0:y==u&&p>g&&(q=!0));q&&(u=new c.Vector3D([-.5*(A[1].x+A[0].x),-.5*(A[1].y+A[0].y),-A[0].z]),v=v.multiply(c.Matrix4x4.translation(u)),
  84. t=c.Matrix4x4.translation(u.negated()).multiply(t),u=y,g=p,k=v,l=t);q=!1}return[k,l]},getTransformationToFlatLying:function(){return this.getTransformationAndInverseTransformationToFlatLying()[0]},lieFlat:function(){var a=this.getTransformationToFlatLying();return this.transform(a)},projectToOrthoNormalBasis:function(a){var b=[];this.polygons.filter(function(b){return b.plane.normal.minus(a.plane.normal).lengthSquared()<1E-5*1E-5}).map(function(d){d=d.projectToOrthoNormalBasis(a);0<d.sides.length&&
  85. b.push(d)});return(new n).union(b)},sectionCut:function(a){var b=a.plane,d=a.plane.flipped(),b=new c.Plane(b.normal,b.w),d=new c.Plane(d.normal,d.w+5E-5),b=this.cutByPlane(b),b=b.cutByPlane(d);return b.projectToOrthoNormalBasis(a)},toTriangles:function(){var a=[];this.polygons.forEach(function(b){for(var d=b.vertices[0],e=b.vertices.length-3;0<=e;e--)a.push(new c.Polygon([d,b.vertices[e+1],b.vertices[e+2]],b.shared,b.plane))});return a},getFeatures:function(a){a instanceof Array||(a=[a]);var b=this.toTriangles().map(function(b){return b.getTetraFeatures(a)}).reduce(function(a,
  86. b){return b.map(function(b,d){return b+(0===a?0:a[d])})},0);return 1==b.length?b[0]:b}};c.parseOption=function(a,b,d){a&&b in a&&(d=a[b]);return d};c.parseOptionAs3DVector=function(a,b,d){a=c.parseOption(a,b,d);return a=new c.Vector3D(a)};c.parseOptionAs3DVectorList=function(a,b,d){return c.parseOption(a,b,d).map(function(a){return new c.Vector3D(a)})};c.parseOptionAs2DVector=function(a,b,d){a=c.parseOption(a,b,d);return a=new c.Vector2D(a)};c.parseOptionAsFloat=function(a,b,d){a=c.parseOption(a,
  87. b,d);"string"==typeof a&&(a=Number(a));if(isNaN(a)||"number"!=typeof a)throw Error("Parameter "+b+" should be a number");return a};c.parseOptionAsInt=function(a,b,d){a=c.parseOption(a,b,d);a=Number(Math.floor(a));if(isNaN(a))throw Error("Parameter "+b+" should be a number");return a};c.parseOptionAsBool=function(a,b,d){a=c.parseOption(a,b,d);"string"==typeof a&&("true"==a?a=!0:"false"==a?a=!1:0==a&&(a=!1));return!!a};c.cube=function(a){var b,d;a=a||{};if("corner1"in a||"corner2"in a){if("center"in
  88. a||"radius"in a)throw Error("cube: should either give a radius and center parameter, or a corner1 and corner2 parameter");corner1=c.parseOptionAs3DVector(a,"corner1",[0,0,0]);corner2=c.parseOptionAs3DVector(a,"corner2",[1,1,1]);b=corner1.plus(corner2).times(.5);d=corner2.minus(corner1).times(.5)}else b=c.parseOptionAs3DVector(a,"center",[0,0,0]),d=c.parseOptionAs3DVector(a,"radius",[1,1,1]);if(0>d.x||0>d.y||0>d.z)throw Error("Dimension should be positive");if(5E-4>d.x||5E-4>d.y||5E-4>d.z)return console.log("Throwing out a zero-length cube."),
  89. new c;a=c.fromPolygons([[[0,4,6,2],[-1,0,0]],[[1,3,7,5],[1,0,0]],[[0,1,5,4],[0,-1,0]],[[2,6,7,3],[0,1,0]],[[0,2,3,1],[0,0,-1]],[[4,5,7,6],[0,0,1]]].map(function(a){a=a[0].map(function(a){a=new c.Vector3D(b.x+d.x*(2*!!(a&1)-1),b.y+d.y*(2*!!(a&2)-1),b.z+d.z*(2*!!(a&4)-1));return new c.Vertex(a)});return new c.Polygon(a,null)}));a.properties.cube=new c.Properties;a.properties.cube.center=new c.Vector3D(b);a.properties.cube.facecenters=[new c.Connector((new c.Vector3D([d.x,0,0])).plus(b),[1,0,0],[0,0,
  90. 1]),new c.Connector((new c.Vector3D([-d.x,0,0])).plus(b),[-1,0,0],[0,0,1]),new c.Connector((new c.Vector3D([0,d.y,0])).plus(b),[0,1,0],[0,0,1]),new c.Connector((new c.Vector3D([0,-d.y,0])).plus(b),[0,-1,0],[0,0,1]),new c.Connector((new c.Vector3D([0,0,d.z])).plus(b),[0,0,1],[1,0,0]),new c.Connector((new c.Vector3D([0,0,-d.z])).plus(b),[0,0,-1],[1,0,0])];return a};c.sphere=function(a){a=a||{};var b=c.parseOptionAs3DVector(a,"center",[0,0,0]),d=c.parseOptionAsFloat(a,"radius",1),e=c.parseOptionAsInt(a,
  91. "res",c.defaultResolution3D),f,h;if(0>d)throw Error("Radius should be positive");if(1E-6>d)return console.log("Throwing out a zero-radius sphere."),new c;"axes"in a?(f=a.axes[0].unit().times(d),h=a.axes[1].unit().times(d),a=a.axes[2].unit().times(d)):(f=(new c.Vector3D([1,0,0])).times(d),h=(new c.Vector3D([0,-1,0])).times(d),a=(new c.Vector3D([0,0,1])).times(d));4>e&&(e=4);for(var d=Math.round(e/4),m,q=[],u=0;u<=e;u++){var g=2*Math.PI*u/e,g=f.times(Math.cos(g)).plus(h.times(Math.sin(g)));if(0<u)for(var k,
  92. l,p,n=0;n<=d;n++){k=.5*Math.PI*n/d;var v=Math.cos(k),t=Math.sin(k);0<n&&(k=[],k.push(new c.Vertex(b.plus(m.times(l).minus(a.times(p))))),k.push(new c.Vertex(b.plus(g.times(l).minus(a.times(p))))),n<d&&k.push(new c.Vertex(b.plus(g.times(v).minus(a.times(t))))),k.push(new c.Vertex(b.plus(m.times(v).minus(a.times(t))))),q.push(new c.Polygon(k)),k=[],k.push(new c.Vertex(b.plus(m.times(l).plus(a.times(p))))),k.push(new c.Vertex(b.plus(g.times(l).plus(a.times(p))))),n<d&&k.push(new c.Vertex(b.plus(g.times(v).plus(a.times(t))))),
  93. k.push(new c.Vertex(b.plus(m.times(v).plus(a.times(t))))),k.reverse(),q.push(new c.Polygon(k)));l=v;p=t}m=g}e=c.fromPolygons(q);e.properties.sphere=new c.Properties;e.properties.sphere.center=new c.Vector3D(b);e.properties.sphere.facepoint=b.plus(f);return e};c.cylinder=function(a){function b(a,b,e){b=b*Math.PI*m/180;b=k.times(Math.cos(b)).plus(g.times(Math.sin(b)));a=d.plus(u.times(a)).plus(b.times(e));return new c.Vertex(a)}var d=c.parseOptionAs3DVector(a,"start",[0,-1,0]),e=c.parseOptionAs3DVector(a,
  94. "end",[0,1,0]),f=c.parseOptionAsFloat(a,"radius",1),h=c.parseOptionAsFloat(a,"radiusEnd",f),f=c.parseOptionAsFloat(a,"radiusStart",f),m=c.parseOptionAsFloat(a,"sectorAngle",360),m=360<m?m%360:m;if(0>h||0>f)throw Error("Radius should be non-negative");if(5E-4>Math.abs(e.z-d.z)||5E-4>h&&5E-4>f)return console.log("throwing out a zero-height cylinder or a cylinder with both ends < 0.0005"),new c;var q=c.parseOptionAsInt(a,"res",c.defaultResolution2D),u=e.minus(d);a=u.unit();var k=a.randomNonParallelVector().unit(),
  95. g=k.cross(a).unit(),l=new c.Vertex(d),p=new c.Vertex(e),n=[];if(0<m){for(var v=0;v<q;v++){var t=v/q,y=(v+1)/q;h==f?(n.push(new c.Polygon([l,b(0,t,h),b(0,y,h)])),n.push(new c.Polygon([b(0,y,h),b(0,t,h),b(1,t,h),b(1,y,h)])),n.push(new c.Polygon([p,b(1,y,h),b(1,t,h)]))):(0<f&&(n.push(new c.Polygon([l,b(0,t,f),b(0,y,f)])),n.push(new c.Polygon([b(0,t,f),b(1,t,h),b(0,y,f)]))),0<h&&(n.push(new c.Polygon([p,b(1,y,h),b(1,t,h)])),n.push(new c.Polygon([b(1,t,h),b(1,y,h),b(0,y,f)]))))}360>m&&(n.push(new c.Polygon([l,
  96. p,b(0,0,f)])),n.push(new c.Polygon([b(0,0,f),p,b(1,0,h)])),n.push(new c.Polygon([l,b(0,1,f),p])),n.push(new c.Polygon([b(0,1,f),b(1,1,h),p])))}q=c.fromPolygons(n);q.properties.cylinder=new c.Properties;q.properties.cylinder.start=new c.Connector(d,a.negated(),k);q.properties.cylinder.end=new c.Connector(e,a,k);e=d.plus(u.times(.5));h=k.rotate(d,a,-m/2).times((f+h)/2);f=h.cross(a);q.properties.cylinder.facepointH=new c.Connector(e.plus(h),h,a);q.properties.cylinder.facepointH90=new c.Connector(e.plus(f),
  97. f,a);return q};c.roundedCylinder=function(a){var b=c.parseOptionAs3DVector(a,"start",[0,-1,0]),d=c.parseOptionAs3DVector(a,"end",[0,1,0]),e=c.parseOptionAsFloat(a,"radius",1),f=d.minus(b),h;h=Math.abs(f.x)>Math.abs(f.y)?new c.Vector3D(0,1,0):new c.Vector3D(1,0,0);var m=c.parseOptionAs3DVector(a,"normal",h);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>a&&(a=4);h=[];var q=Math.floor(.25*a);if(1E-10>f.length())return c.sphere({center:b,radius:e,resolution:a});for(var k=f.unit().times(e),
  98. f=k.cross(m).unit().times(e),e=f.cross(k).unit().times(e),g,m=0;m<=a;m++){var l=2*Math.PI*m/a,l=f.times(Math.cos(l)).plus(e.times(Math.sin(l)));if(0<m){var n=[];n.push(new c.Vertex(b.plus(l)));n.push(new c.Vertex(b.plus(g)));n.push(new c.Vertex(d.plus(g)));n.push(new c.Vertex(d.plus(l)));h.push(new c.Polygon(n));for(var p,B,v=0;v<=q;v++){var n=.5*Math.PI*v/q,t=Math.cos(n),y=Math.sin(n);0<v&&(n=[],n.push(new c.Vertex(b.plus(g.times(p).minus(k.times(B))))),n.push(new c.Vertex(b.plus(l.times(p).minus(k.times(B))))),
  99. v<q&&n.push(new c.Vertex(b.plus(l.times(t).minus(k.times(y))))),n.push(new c.Vertex(b.plus(g.times(t).minus(k.times(y))))),h.push(new c.Polygon(n)),n=[],n.push(new c.Vertex(d.plus(g.times(p).plus(k.times(B))))),n.push(new c.Vertex(d.plus(l.times(p).plus(k.times(B))))),v<q&&n.push(new c.Vertex(d.plus(l.times(t).plus(k.times(y))))),n.push(new c.Vertex(d.plus(g.times(t).plus(k.times(y))))),n.reverse(),h.push(new c.Polygon(n)));p=t;B=y}}g=l}g=c.fromPolygons(h);p=k.unit();B=f.unit();g.properties.roundedCylinder=
  100. new c.Properties;g.properties.roundedCylinder.start=new c.Connector(b,p.negated(),B);g.properties.roundedCylinder.end=new c.Connector(d,p,B);g.properties.roundedCylinder.facepoint=b.plus(f);return g};c.roundedCube=function(a){var b,d;a=a||{};if("corner1"in a||"corner2"in a){if("center"in a||"radius"in a)throw Error("roundedCube: should either give a radius and center parameter, or a corner1 and corner2 parameter");corner1=c.parseOptionAs3DVector(a,"corner1",[0,0,0]);corner2=c.parseOptionAs3DVector(a,
  101. "corner2",[1,1,1]);b=corner1.plus(corner2).times(.5);d=corner2.minus(corner1).times(.5)}else b=c.parseOptionAs3DVector(a,"center",[0,0,0]),d=c.parseOptionAs3DVector(a,"radius",[1,1,1]);d=d.abs();var e=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>e&&(e=4);1==e%2&&8>e&&(e=8);a=c.parseOptionAs3DVector(a,"roundradius",[.2,.2,.2]);a=c.Vector3D.Create(Math.max(a.x,.01),Math.max(a.y,.01),Math.max(a.z,.01));var f=d.minus(a);if(0>f.x||0>f.y||0>f.z)throw"roundradius <= radius!";e=c.sphere({radius:1,
  102. resolution:e});e=e.scale(a);1E-5<f.x&&(e=e.stretchAtPlane([1,0,0],[0,0,0],2*f.x));1E-5<f.y&&(e=e.stretchAtPlane([0,1,0],[0,0,0],2*f.y));1E-5<f.z&&(e=e.stretchAtPlane([0,0,1],[0,0,0],2*f.z));e=e.tr([-f.x+b.x,-f.y+b.y,-f.z+b.z]);e=e.reTesselated();e.properties.roundedCube=new c.Properties;e.properties.roundedCube.center=new c.Vertex(b);e.properties.roundedCube.facecenters=[new c.Connector((new c.Vector3D([d.x,0,0])).plus(b),[1,0,0],[0,0,1]),new c.Connector((new c.Vector3D([-d.x,0,0])).plus(b),[-1,0,
  103. 0],[0,0,1]),new c.Connector((new c.Vector3D([0,d.y,0])).plus(b),[0,1,0],[0,0,1]),new c.Connector((new c.Vector3D([0,-d.y,0])).plus(b),[0,-1,0],[0,0,1]),new c.Connector((new c.Vector3D([0,0,d.z])).plus(b),[0,0,1],[1,0,0]),new c.Connector((new c.Vector3D([0,0,-d.z])).plus(b),[0,0,-1],[1,0,0])];return e};c.polyhedron=function(a){a=a||{};if("points"in a!=="faces"in a)throw Error("polyhedron needs 'points' and 'faces' arrays");var b=c.parseOptionAs3DVectorList(a,"points",[[1,1,0],[1,-1,0],[-1,-1,0],[-1,
  104. 1,0],[0,0,1]]).map(function(a){return new c.Vertex(a)});a=c.parseOption(a,"faces",[[0,1,4],[1,2,4],[2,3,4],[3,0,4],[1,0,3],[2,1,3]]);a.forEach(function(a){a.reverse()});a=a.map(function(a){return new c.Polygon(a.map(function(a){return b[a]}))});return c.fromPolygons(a).reTesselated()};c.IsFloat=function(a){return!isNaN(a)||Infinity===a||-Infinity===a};c.solve2Linear=function(a,b,d,c,f,h){var e=1/(a*c-b*d);return[(f*c-b*h)*e,(-f*d+a*h)*e]};c.Vector3D=function(a,b,d){if(3==arguments.length)this._x=
  105. parseFloat(a),this._y=parseFloat(b),this._z=parseFloat(d);else if(2==arguments.length)this._x=parseFloat(a),this._y=parseFloat(b),this._z=0;else{var e=!0;if(1==arguments.length)if("object"==typeof a)a instanceof c.Vector3D?(this._x=a._x,this._y=a._y,this._z=a._z):a instanceof c.Vector2D?(this._x=a._x,this._y=a._y,this._z=0):a instanceof Array?2>a.length||3<a.length?e=!1:(this._x=parseFloat(a[0]),this._y=parseFloat(a[1]),this._z=3==a.length?parseFloat(a[2]):0):"x"in a&&"y"in a?(this._x=parseFloat(a.x),
  106. this._y=parseFloat(a.y),this._z="z"in a?parseFloat(a.z):0):e=!1;else{var f=parseFloat(a);this._z=this._y=this._x=f}else e=!1;e&&(c.IsFloat(this._x)&&c.IsFloat(this._y)&&c.IsFloat(this._z)||(e=!1));if(!e)throw Error("wrong arguments");}};c.Vector3D.Create=function(a,b,d){var e=Object.create(c.Vector3D.prototype);e._x=a;e._y=b;e._z=d;return e};c.Vector3D.prototype={get x(){return this._x},get y(){return this._y},get z(){return this._z},set x(a){throw Error("Vector3D is immutable");},set y(a){throw Error("Vector3D is immutable");
  107. },set z(a){throw Error("Vector3D is immutable");},clone:function(){return c.Vector3D.Create(this._x,this._y,this._z)},negated:function(){return c.Vector3D.Create(-this._x,-this._y,-this._z)},abs:function(){return c.Vector3D.Create(Math.abs(this._x),Math.abs(this._y),Math.abs(this._z))},plus:function(a){return c.Vector3D.Create(this._x+a._x,this._y+a._y,this._z+a._z)},minus:function(a){return c.Vector3D.Create(this._x-a._x,this._y-a._y,this._z-a._z)},times:function(a){return c.Vector3D.Create(this._x*
  108. a,this._y*a,this._z*a)},dividedBy:function(a){return c.Vector3D.Create(this._x/a,this._y/a,this._z/a)},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z},lerp:function(a,b){return this.plus(a.minus(this).times(b))},lengthSquared:function(){return this.dot(this)},length:function(){return Math.sqrt(this.lengthSquared())},unit:function(){return this.dividedBy(this.length())},cross:function(a){return c.Vector3D.Create(this._y*a._z-this._z*a._y,this._z*a._x-this._x*a._z,this._x*a._y-this._y*
  109. a._x)},distanceTo:function(a){return this.minus(a).length()},distanceToSquared:function(a){return this.minus(a).lengthSquared()},equals:function(a){return this._x==a._x&&this._y==a._y&&this._z==a._z},multiply4x4:function(a){return a.leftMultiply1x3Vector(this)},transform:function(a){return a.leftMultiply1x3Vector(this)},toString:function(){return"("+this._x.toFixed(2)+", "+this._y.toFixed(2)+", "+this._z.toFixed(2)+")"},randomNonParallelVector:function(){var a=this.abs();return a._x<=a._y&&a._x<=
  110. a._z?c.Vector3D.Create(1,0,0):a._y<=a._x&&a._y<=a._z?c.Vector3D.Create(0,1,0):c.Vector3D.Create(0,0,1)},min:function(a){return c.Vector3D.Create(Math.min(this._x,a._x),Math.min(this._y,a._y),Math.min(this._z,a._z))},max:function(a){return c.Vector3D.Create(Math.max(this._x,a._x),Math.max(this._y,a._y),Math.max(this._z,a._z))},setZero:function(){this._z=this._y=this._x=0},hAdd:function(a,b){a._x+=b._x;a._y+=b._y;a._z+=b._z},hTimes:function(a,b){a._x*=b;a._y*=b;a._z*=b},normalize:function(){var a=this.lengthSquared(),
  111. b=a-1;if(4.440892098500626E-16<b||-4.440892098500626E-16>b)a=Math.sqrt(a),this._x/=a,this._y/=a,this._z/=a},set:function(a,b,d){this._x=a;this._y=b;this._z=d}};c.Vertex=function(a){this.pos=a};c.Vertex.fromObject=function(a){a=new c.Vector3D(a.pos);return new c.Vertex(a)};c.Vertex.prototype={flipped:function(){return this},getTag:function(){var a=this.tag;a||(this.tag=a=c.getTag());return a},interpolate:function(a,b){var d=this.pos.lerp(a.pos,b);return new c.Vertex(d)},transform:function(a){a=this.pos.multiply4x4(a);
  112. return new c.Vertex(a)},toString:function(){return this.pos.toString()}};c.hVertex=function(a,b,d,e){this.pnt=new c.Vector3D(a,b,d);4==arguments.length&&(this.index=e);this.face=this.prev=this.next=null};c.hVertex.prototype={clone:function(){return new c.hVertex(this._x,this._y,this._z,this.index)}};c.hVertexList=function(){this.tail=this.head=null};c.hVertexList.prototype={clear:function(){this.tail=this.head=null},add:function(a){null==this.head?this.head=a:this.tail.next=a;a.prev=this.tail;a.next=
  113. null;this.tail=a},addAll:function(a){null==this.head?this.head=a:this.tail.next=a;for(a.prev=this.tail;null!=a.next;)a=a.next;this.tail=a},"delete":function(a,b){1==arguments.length?(null==a.prev?this.head=a.next:a.prev.next=a.next,null==a.next?this.tail=a.prev:a.next.prev=a.prev):2==arguments.length&&(null==a.prev?this.head=b.next:a.prev.next=b.next,null==b.next?this.tail=a.prev:b.next.prev=a.prev)},insertBefore:function(a,b){a.prev=b.prev;null==b.prev?this.head=a:b.prev.next=a;a.next=b;b.prev=a},
  114. first:function(){return this.head},isEmpty:function(){return null==this.head}};c.HalfEdge=function(a,b){2==arguments.length?(this.vertex=a,this.face=b):this.face=this.vertex=null;this.opposite=this.next=this.prev=null};c.HalfEdge.prototype={setNext:function(a){this.next=a},getNext:function(){return this.next},setPrev:function(a){this.prev=a},getPrev:function(){return this.prev},getFace:function(){return this.face},getOpposite:function(){return this.opposite},setOpposite:function(a){this.opposite=
  115. a;a.opposite=this},head:function(){return this.vertex},tail:function(){return null!=this.prev?this.prev.vertex:null},oppositeFace:function(){return null!=this.opposite?this.opposite.face:null},getVertexString:function(){return null!=this.tail()?""+this.tail().index+"-"+this.head().index:"? -"+this.head().index},length:function(){return null!=this.tail()?this.head().pnt.distanceTo(this.tail().pnt):-1},lengthSquared:function(){return null!=this.tail()?this.head().pnt.distanceToSquared(this.tail().pnt):
  116. -1}};c.Face=function(){this.normal=new c.Vector3D(0,0,0);this.centroid=new c.Vector3D(0,0,0);this.mark=1;this.he0=null;this.numVerts=this.index=this.planeOffset=this.area=-1;this.outside=this.next=null};c.Face.prototype={computeCentroid:function(a){a.setZero();var b=this.he0;do a.hAdd(a,b.head().pnt),b=b.next;while(b!=this.he0);a.hTimes(a,1/this.numVerts)},computeNormal:function(a,b){var d=this.he0.next,c=d.next,f=this.he0.head().pnt,d=d.head().pnt,h=d._x-f._x,m=d._y-f._y,d=d._z-f._z;this.normal.setZero();
  117. for(this.numVerts=2;c!=this.he0;){var q=h,k=m,g=d,d=c.head().pnt,h=d._x-f._x,m=d._y-f._y,d=d._z-f._z;this.normal._x+=k*d-g*m;this.normal._y+=g*h-q*d;this.normal._z+=q*m-k*h;c=c.next;this.numVerts++}this.area=this.normal.length();this.normal.hTimes(this.normal,1/this.area);if(2==arguments.length&&this.area<b){c=null;f=0;d=this.he0;do h=d.lengthSquared(),h>f&&(c=d,f=h);while(d!=this.he0);d=c.head().pnt;p1=c.tail().pnt;h=Math.sqrt(f);c=(d._x-p1._x)/h;f=(d._y-p1._y)/h;d=(d._z-p1._z)/h;h=this.normal._x*
  118. c+this.normal._y*f+this.normal._z*d;this.normal._x-=h*c;this.normal._y-=h*f;this.normal._z-=h*d;this.normal.normalize()}},computeNormalAndCentroid:function(a){1==arguments.length?this.computeNormal(this.normal,a):this.computeNormal(this.normal);this.computeCentroid(this.centroid);this.planeOffset=this.normal.dot(this.centroid)},createTriangle:function(a,b,d,e){var f=new c.Face;a=new c.HalfEdge(a,f);b=new c.HalfEdge(b,f);d=new c.HalfEdge(d,f);a.prev=d;a.next=b;b.prev=a;b.next=d;d.prev=b;d.next=a;f.he0=
  119. a;e?f.computeNormalAndCentroid(e):f.computeNormalAndCentroid(0);return f},create:function(a,b){for(var d=new c.Face,e=null,f=0;f<b.length;f++){var h=new c.HalfEdge(a[b[f]],d);null!=e?(h.setPrev(e),e.setNext(h)):d.he0=h;e=h}d.he0.setPrev(e);e.setNext(d.he0);d.computeNormalAndCentroid();return d},getEdge:function(a){for(var b=this.he0;0<a;)b=b.next,a--;for(;0>a;)b=b.prev,a++;return b},getFirstEdge:function(){return this.he0},findEdge:function(a,b){var d=this.he0;do{if(d.head()==b&&d.tail()==a)return d;
  120. d=d.next}while(d!=this.he0);return null},distanceToPlane:function(a){return this.normal._x*a._x+this.normal._y*a._y+this.normal._z*a._z-this.planeOffset},getNormal:function(){return this.normal},getCentroid:function(){return this.centroid},numVertices:function(){return this.numVerts},getVertexString:function(){var a="",b=this.he0;do a=0==a.length?a+b.head().index:a+(" "+b.head().index),b=b.next;while(b!=this.he0);return a},getVertexIndices:function(a){var b=this.he0,d=0;do a[d++]=b.head().index,b=
  121. b.next;while(b!=this.he0)},connectHalfEdges:function(a,b){var d=null;if(a.oppositeFace()==b.oppositeFace()){var c=b.oppositeFace(),f;a==this.he0&&(this.he0=b);3==c.numVertices()?(f=b.getOpposite().prev.getOpposite(),c.mark=3,d=c):(f=b.getOpposite().next,c.he0==f.prev&&(c.he0=f),f.prev=f.prev.prev,f.prev.next=f);b.prev=a.prev;b.prev.next=b;b.opposite=f;f.opposite=b;c.computeNormalAndCentroid()}else a.next=b,b.prev=a;return d},checkConsistency:function(){var a=this.he0,b=0,d=0;if(3>this.numVerts)throw"face"+
  122. this.getVertexString()+": unreflected half edge "+a.getVertexString();do{var c=a.getOpposite();if(null==c)throw"face "+this.getVertexString()+": unreflected half edge "+a.getVertexString();if(c.getOpposite()!=a)throw"face "+this.getVertexString()+": opposite half edge "+c.getVertexString()+" has opposite "+c.getOpposite().getVertexString();if(c.head()!=a.tail()||a.head()!=c.tail())throw"face "+this.getVertexString()+": half edge "+a.getVertexString()+" reflected by "+c.getVertexString();var f=c.face;
  123. if(null==f)throw"face "+this.getVertexString()+": no face on half edge "+c.getVertexString();if(3==f.mark)throw"face "+this.getVertexString()+": opposite face "+f.getVertexString()+" not on hull";c=Math.abs(this.distanceToPlane(a.head().pnt));c>b&&(b=c);d++;a=a.next}while(a!=this.he0);if(d!=this.numVerts)throw"face "+this.getVertexString()+" numVerts="+this.numVerts+" should be "+d;},mergeAdjacentFace:function(a,b){var d=a.oppositeFace(),c=0;b[c++]=d;d.mark=3;for(var f=a.getOpposite(),h=a.prev,m=
  124. a.next,q=f.prev,f=f.next;h.oppositeFace()==d;)h=h.prev,f=f.next;for(;m.oppositeFace()==d;)q=q.prev,m=m.next;for(d=f;d!=q.next;d=d.next)d.face=this;a==this.he0&&(this.he0=m);m=this.connectHalfEdges(q,m);null!=m&&(b[c++]=m);m=this.connectHalfEdges(h,f);null!=m&&(b[c++]=m);this.computeNormalAndCentroid();this.checkConsistency();return c},areaSquared:function(a,b){var d=a.tail().pnt,c=a.head().pnt,f=b.head().pnt,h=c._x-d._x,m=c._y-d._y,q=c._z-d._z,c=f._x-d._x,k=f._y-d._y,f=f._z-d._z,d=m*f-q*k,q=q*c-h*
  125. f,h=h*k-m*c;return d*d+q*q+h*h},triangulate:function(a,b){var d;if(!(4>this.numVertices)){var e=this.he0.head();d=this.he0.next;var f=d.opposite,h=null;for(d=d.next;d!=this.he0.prev;d=d.next){var m=createTriangle(e,d.prev.head(),d.head(),b);m.he0.next.setOpposite(f);m.he0.prev.setOpposite(d.opposite);f=m.he0;a.add(m);null==h&&(h=m)}d=new c.HalfEdge(this.he0.prev.prev.head(),this);d.setOpposite(f);d.prev=this.he0;d.prev.next=d;d.next=this.he0.prev;d.next.prev=d;computeNormalAndCentroid(b);checkConsistency();
  126. for(m=h;null!=m;m=m.next)m.checkConsistency()}}};c.FaceList=function(){this.tail=this.head=null};c.FaceList.prototype={clear:function(){this.tail=this.head=null},add:function(a){null==this.head?this.head=a:this.tail.next=a;a.next=null;this.tail=a},first:function(){return this.head},isEmpty:function(){return null==this.head}};c.quickHull3D=function(){this.AUTOMATIC_TOLERANCE=-1;this.DOUBLE_PREC=2.220446049250313E-16;this.findIndex=-1;this.debug=!0;this.charLength=0;this.pointBuffer=[];this.vertexPointIndices=
  127. [];this.discardedFaces=[];this.maxVtxs=[];this.minVtxs=[];for(var a=0;3>a;a++)this.maxVtxs.push(new c.hVertex(0,0,0,a)),this.minVtxs.push(new c.hVertex(0,0,0,a)),this.discardedFaces.push(new c.Face);this.faces=[];this.horizon=[];this.newFaces=new c.FaceList;this.unclaimed=new c.hVertexList;this.claimed=new c.hVertexList;this.numPoints=this.numFaces=this.numVertices=0;this.explicitTolerance=this.AUTOMATIC_TOLERANCE;this.tolerance=0};c.quickHull3D.prototype={build:function(a){if(4>a.length)return console.log("cannot build hull - fewer than four points"),
  128. null;this.initBuffers(a,a.length);return this.buildHull()},initBuffers:function(a,b){this.pointBuffer=[];for(var d=0;d<b;d++)this.pointBuffer.push(new c.hVertex(a[d]._x,a[d]._y,a[d]._z,d)),this.vertexPointIndices.push(0);this.faces=[];this.claimed.clear();this.numVertices=b;this.numFaces=0;this.numPoints=b},buildHull:function(){var a=0,b;this.computeMaxAndMin();for(this.createInitialSimplex();null!=(b=this.nextPointToAdd());)this.addPointToHull(b),a++;this.reindexFacesAndVertices();return this.getFaces()},
  129. computeMaxAndMin:function(){for(var a=this.pointBuffer[0],b=0;3>b;b++)this.maxVtxs[b]=this.pointBuffer[0],this.minVtxs[b]=this.pointBuffer[0];for(var d=[a.pnt._x,a.pnt._y,a.pnt._z],a=[a.pnt._x,a.pnt._y,a.pnt._z],b=0;b<this.numPoints;b++){var c=this.pointBuffer[b].pnt;c._x>d[0]?(d[0]=c._x,this.maxVtxs[0]=this.pointBuffer[b]):c._x<a[0]&&(a[0]=c._x,this.minVtxs[0]=this.pointBuffer[b]);c._y>d[1]?(d[1]=c._y,this.maxVtxs[1]=this.pointBuffer[b]):c._y<a[1]&&(a[1]=c._y,this.minVtxs[1]=this.pointBuffer[b]);
  130. c._z>d[2]?(d[2]=c._z,this.maxVtxs[2]=this.pointBuffer[b]):c._z<a[2]&&(a[2]=c._z,this.minVtxs[2]=this.pointBuffer[b])}this.charLength=Math.max(d[0]-a[0],d[1]-a[1],d[2]-a[2]);this.tolerance=this.explicitTolerance==this.AUTOMATIC_TOLERANCE?3*this.DOUBLE_PREC*(Math.max(Math.abs(d[0]),Math.abs(a[0]))+Math.max(Math.abs(d[1]),Math.abs(a[1]))+Math.max(Math.abs(d[2]),Math.abs(a[2]))):this.explicitTolerance},createInitialSimplex:function(){var a=0,b=0,d=this.maxVtxs[0].pnt._x-this.minVtxs[0].pnt._x,e=this.maxVtxs[1].pnt._y-
  131. this.minVtxs[1].pnt._y,f=this.maxVtxs[2].pnt._z-this.minVtxs[2].pnt._z;d>a&&(a=d,b=0);e>a&&(a=e,b=1);f>a&&(a=f,b=2);if(a<=this.tolerance)throw"hull points are all coincident - fail!";a=[];a[0]=this.maxVtxs[b];a[1]=this.minVtxs[b];e=new c.Vector3D(a[1].pnt._x,a[1].pnt._y,a[1].pnt._z);e=e.minus(a[0].pnt);e.normalize();d=new c.Vector3D(0,0,0);for(b=f=0;b<this.numPoints;b++){var h=this.pointBuffer[b],m=c.Vector3D.Create(h.pnt._x,h.pnt._y,h.pnt._z),m=m.minus(a[0].pnt),h=c.Vector3D.Create(e._x,e._y,e._z),
  132. h=h.cross(m),m=h.lengthSquared();m>f&&this.pointBuffer[b]!=a[0]&&this.pointBuffer[b]!=a[1]&&(f=m,a[2]=this.pointBuffer[b],d.set(h._x,h._y,h._z))}if(Math.sqrt(f)<=100*this.tolerance)throw"Input points to hull appear to be co-linear";d.normalize();e=0;m=a[2].pnt.dot(d);for(b=0;b<this.numPoints;b++)f=Math.abs(this.pointBuffer[b].pnt.dot(d)-m),f>e&&this.pointBuffer[b]!=a[0]&&this.pointBuffer[b]!=a[1]&&this.pointBuffer[b]!=a[2]&&(e=f,a[3]=this.pointBuffer[b]);if(Math.abs(e)<=100*this.tolerance)throw"Input points appear to be coplanar";
  133. h=[new c.Face,new c.Face,new c.Face,new c.Face];if(0>a[3].pnt.dot(d)-m)for(h[0]=h[0].createTriangle(a[0],a[1],a[2]),h[1]=h[1].createTriangle(a[3],a[1],a[0]),h[2]=h[2].createTriangle(a[3],a[2],a[1]),h[3]=h[3].createTriangle(a[3],a[0],a[2]),b=0;3>b;b++)d=(b+1)%3,h[b+1].getEdge(1).setOpposite(h[d+1].getEdge(0)),h[b+1].getEdge(2).setOpposite(h[0].getEdge(d));else for(h[0]=h[0].createTriangle(a[0],a[2],a[1]),h[1]=h[1].createTriangle(a[3],a[0],a[1]),h[2]=h[2].createTriangle(a[3],a[1],a[2]),h[3]=h[3].createTriangle(a[3],
  134. a[2],a[0]),b=0;3>b;b++)d=(b+1)%3,h[b+1].getEdge(0).setOpposite(h[d+1].getEdge(1)),h[b+1].getEdge(2).setOpposite(h[0].getEdge((3-b)%3));for(b=0;4>b;b++)this.faces.push(h[b]);for(b=0;b<this.numPoints;b++)if(m=this.pointBuffer[b],m!=a[0]&&m!=a[1]&&m!=a[2]&&m!=a[3]){for(var e=this.tolerance,q=null,d=0;4>d;d++)f=h[d].distanceToPlane(m.pnt),f>e&&(q=h[d],e=f);null!=q&&this.addPointToFace(m,q)}},addPointToFace:function(a,b){a.face=b;null==b.outside?this.claimed.add(a):this.claimed.insertBefore(a,b.outside);
  135. b.outside=a},nextPointToAdd:function(){if(this.claimed.isEmpty())return null;for(var a=this.claimed.first().face,b=null,d=0,c=a.outside;null!=c&&c.face==a;c=c.next){var f=a.distanceToPlane(c.pnt);f>d&&(d=f,b=c)}return b},addPointToHull:function(a){this.horizon=[];this.unclaimed.clear();this.removePointFromFace(a,a.face);this.calculateHorizon(a.pnt,null,a.face,this.horizon);this.newFaces.clear();this.addNewFaces(this.newFaces,a,this.horizon);for(a=this.newFaces.first();null!=a;a=a.next)if(1==a.mark)for(;this.doAdjacentMerge(a,
  136. 1););for(a=this.newFaces.first();null!=a;a=a.next)if(2==a.mark)for(a.mark=1;this.doAdjacentMerge(a,2););this.resolveUnclaimedPoints(this.newFaces)},removePointFromFace:function(a,b){a==b.outside&&(b.outside=null!=a.next&&a.next.face==b?a.next:null);this.claimed["delete"](a)},calculateHorizon:function(a,b,d,c){this.deleteFacePoints(d,null);d.mark=3;d=null==b?b=d.getEdge(0):b.getNext();do{var e=d.oppositeFace();1==e.mark&&(e.distanceToPlane(a)>this.tolerance?this.calculateHorizon(a,d.getOpposite(),
  137. e,c):c.push(d));d=d.getNext()}while(d!=b)},oppFaceDistance:function(a){return a.face.distanceToPlane(a.opposite.face.getCentroid())},doAdjacentMerge:function(a,b){var d=a.he0,c=!0;do{var f=d.oppositeFace(),h=!1;if(2==b){if(this.oppFaceDistance(d)>-1*this.tolerance||this.oppFaceDistance(d.opposite)>-1*this.tolerance)h=!0}else a.area>f.area?this.oppFaceDistance(d)>-this.tolerance?h=!0:this.oppFaceDistance(d.opposite)>-this.tolerance&&(c=!1):this.oppFaceDistance(d.opposite)>-this.tolerance?h=!0:this.oppFaceDistance(d)>
  138. -this.tolerance&&(c=!1);if(h){d=a.mergeAdjacentFace(d,this.discardedFaces);for(c=0;c<d;c++)this.deleteFacePoints(this.discardedFaces[c],a);return!0}d=d.next}while(d!=a.he0);c||(a.mark=2);return!1},deleteFacePoints:function(a,b){var d=this.removeAllPointsFromFace(a);if(null!=d)if(null==b)this.unclaimed.addAll(d);else for(var c=d;null!=c;c=d)d=c.next,b.distanceToPlane(c.pnt)>this.tolerance?this.addPointToFace(c,b):this.unclaimed.add(c)},removeAllPointsFromFace:function(a){if(null!=a.outside){for(var b=
  139. a.outside;null!=b.next&&b.next.face==a;)b=b.next;this.claimed["delete"](a.outside,b);b.next=null;return a.outside}return null},addNewFaces:function(a,b,d){a.clear();for(var c=null,f=null,h=0;h<d.length;h++){var m=this.addAdjoiningFace(b,d[h]);null!=c?m.next.setOpposite(c):f=m;a.add(m.getFace());c=m}f.next.setOpposite(c)},addAdjoiningFace:function(a,b){var d=new c.Face,d=d.createTriangle(a,b.tail(),b.head());this.faces.push(d);d.getEdge(-1).setOpposite(b.getOpposite());return d.getEdge(0)},resolveUnclaimedPoints:function(a){for(var b=
  140. this.unclaimed.first(),d=b;null!=d;d=b){for(var b=d.next,c=this.tolerance,f=null,h=a.first();null!=h;h=h.next)if(1==h.mark){var m=h.distanceToPlane(d.pnt);m>c&&(c=m,f=h);if(c>1E3*this.tolerance)break}null!=f&&this.addPointToFace(d,f)}},reindexFacesAndVertices:function(){for(var a=0;a<this.numPoints;a++)this.pointBuffer[a].index=-1;this.numFaces=0;for(var b=[],a=0;a<this.faces.length;a++){var d=this.faces[a];1==d.mark&&(this.markFaceVertices(d,0),this.numFaces++,b.push(d))}this.faces=b;for(a=this.numVertices=
  141. 0;a<this.numPoints;a++)b=this.pointBuffer[a],0==b.index&&(this.vertexPointIndices[this.numVertices]=a,b.index=this.numVertices++)},markFaceVertices:function(a,b){var d=a.getFirstEdge(),c=d;do c.head().index=b,c=c.next;while(c!=d)},getFaces:function(){for(var a=[],b=0;b<this.faces.length;b++){var d=this.faces[b];a.push([]);this.getFaceIndices(a[b],d)}return a},getFaceIndices:function(a,b){var d=b.he0,c=0;do{var f=d.head().index,f=this.vertexPointIndices[f];a[c++]=f;d=d.next}while(d!=b.he0)},getVertices:function(){for(var a=
  142. [],b=0;b<this.numVertices;b++){var d=this.pointBuffer[this.vertexPointIndices[b]].pnt;a.push([d._x,d._y,d._z])}return a},printPoints:function(){for(var a=0;a<this.pointBuffer.length;a++){var b=this.pointBuffer[a].pnt;console.log(a+": "+b._x+", "+b._y+", "+b._z)}}};c.Plane=function(a,b){this.normal=a;this.w=b};c.Plane.fromObject=function(a){var b=new c.Vector3D(a.normal);a=parseFloat(a.w);return new c.Plane(b,a)};c.Plane.EPSILON=1E-5;c.Plane.fromVector3Ds=function(a,b,d){b=b.minus(a).cross(d.minus(a)).unit();
  143. return new c.Plane(b,b.dot(a))};c.Plane.anyPlaneFromVector3Ds=function(a,b,d){b=b.minus(a);d=d.minus(a);1E-5>b.length()&&(b=d.randomNonParallelVector());1E-5>d.length()&&(d=b.randomNonParallelVector());d=b.cross(d);1E-5>d.length()&&(d=b.randomNonParallelVector(),d=b.cross(d));d=d.unit();return new c.Plane(d,d.dot(a))};c.Plane.fromPoints=function(a,b,d){a=new c.Vector3D(a);b=new c.Vector3D(b);d=new c.Vector3D(d);return c.Plane.fromVector3Ds(a,b,d)};c.Plane.fromNormalAndPoint=function(a,b){a=new c.Vector3D(a);
  144. b=new c.Vector3D(b);a=a.unit();var d=b.dot(a);return new c.Plane(a,d)};c.Plane.prototype={flipped:function(){return new c.Plane(this.normal.negated(),-this.w)},getTag:function(){var a=this.tag;a||(this.tag=a=c.getTag());return a},equals:function(a){return this.normal.equals(a.normal)&&this.w==a.w},transform:function(a){var b=a.isMirroring(),d=this.normal.randomNonParallelVector(),e=this.normal.cross(d),f=this.normal.cross(e),d=this.normal.times(this.w),e=d.plus(e),f=d.plus(f),d=d.multiply4x4(a),e=
  145. e.multiply4x4(a),f=f.multiply4x4(a);a=c.Plane.fromVector3Ds(d,e,f);b&&(a=a.flipped());return a},splitPolygon:function(a){var b={type:null,front:null,back:null},d=this.normal,e=a.vertices,f=e.length;if(a.plane.equals(this))b.type=0;else{for(var h=c.Plane.EPSILON,m=this.w,q=!1,k=!1,g=[],l=-h,n=0;n<f;n++){var p=d.dot(e[n].pos)-m,B=0>p;g.push(B);p>h&&(q=!0);p<l&&(k=!0)}if(q||k)if(k)if(q){b.type=4;d=[];h=[];B=g[0];for(m=0;m<f;m++)q=e[m],l=m+1,l>=f&&(l=0),k=g[l],B==k?B?h.push(q):d.push(q):(l=this.splitLineBetweenPoints(q.pos,
  146. e[l].pos),l=new c.Vertex(l),B?(h.push(q),h.push(l),d.push(l)):(d.push(q),d.push(l),h.push(l))),B=k;e=c.Plane.EPSILON*c.Plane.EPSILON;if(3<=h.length)for(f=h[h.length-1],m=0;m<h.length;m++)q=h[m],q.pos.distanceToSquared(f.pos)<e&&(h.splice(m,1),m--),f=q;if(3<=d.length)for(f=d[d.length-1],m=0;m<d.length;m++)q=d[m],q.pos.distanceToSquared(f.pos)<e&&(d.splice(m,1),m--),f=q;3<=d.length&&(b.front=new c.Polygon(d,a.shared,a.plane));3<=h.length&&(b.back=new c.Polygon(h,a.shared,a.plane))}else b.type=3;else b.type=
  147. 2;else p=d.dot(a.plane.normal),b.type=0<=p?0:1}return b},splitLineBetweenPoints:function(a,b){var d=b.minus(a),c=(this.w-this.normal.dot(a))/this.normal.dot(d);isNaN(c)&&(c=0);1<c&&(c=1);0>c&&(c=0);return a.plus(d.times(c))},intersectWithLine:function(a){return a.intersectWithPlane(this)},intersectWithPlane:function(a){return c.Line3D.fromPlanes(this,a)},signedDistanceToPoint:function(a){return this.normal.dot(a)-this.w},toString:function(){return"[normal: "+this.normal.toString()+", w: "+this.w+
  148. "]"},mirrorPoint:function(a){var b=this.signedDistanceToPoint(a);return a.minus(this.normal.times(2*b))}};c.Polygon=function(a,b,d){this.vertices=a;b||(b=c.Polygon.defaultShared);this.shared=b;this.plane=3<=arguments.length?d:c.Plane.fromVector3Ds(a[0].pos,a[1].pos,a[2].pos)};c.Polygon.fromObject=function(a){var b=a.vertices.map(function(a){return c.Vertex.fromObject(a)}),d=c.Polygon.Shared.fromObject(a.shared);a=c.Plane.fromObject(a.plane);return new c.Polygon(b,d,a)};c.Polygon.prototype={checkIfConvex:function(){if(!c.Polygon.verticesConvex(this.vertices,
  149. this.plane.normal))throw c.Polygon.verticesConvex(this.vertices,this.plane.normal),Error("Not convex!");},sC:function(a){this.shared=c.Polygon.Shared.fromColor.apply(this,arguments);return this},getSignedVolume:function(){for(var a=0,b=0;b<this.vertices.length-2;b++)a+=this.vertices[0].pos.dot(this.vertices[b+1].pos.cross(this.vertices[b+2].pos));return a/6},getArea:function(){for(var a=0,b=0;b<this.vertices.length-2;b++)a+=this.vertices[b+1].pos.minus(this.vertices[0].pos).cross(this.vertices[b+
  150. 2].pos.minus(this.vertices[b+1].pos)).length();return a/2},getTetraFeatures:function(a){var b=[];a.forEach(function(a){"volume"==a?b.push(this.getSignedVolume()):"area"==a&&b.push(this.getArea())},this);return b},extrude:function(a){var b=[],d=this;0<d.plane.normal.dot(a)&&(d=d.flipped());b.push(d);a=d.tr(a);for(var e=this.vertices.length,f=0;f<e;f++){var h=[],m=f<e-1?f+1:0;h.push(d.vertices[f].pos);h.push(a.vertices[f].pos);h.push(a.vertices[m].pos);h.push(d.vertices[m].pos);h=c.Polygon.createFromPoints(h,
  151. this.shared);b.push(h)}a=a.flipped();b.push(a);return c.fromPolygons(b)},tr:function(a){return this.transform(c.Matrix4x4.translation(a))},boundingSphere:function(){if(!this.cachedBoundingSphere){var a=this.boundingBox(),b=a[0].plus(a[1]).times(.5),a=a[1].minus(b).length();this.cachedBoundingSphere=[b,a]}return this.cachedBoundingSphere},boundingBox:function(){if(!this.cachedBoundingBox){var a,b,d=this.vertices,e=d.length;b=a=0===e?new c.Vector3D(0,0,0):d[0].pos;for(var f=1;f<e;f++){var h=d[f].pos;
  152. a=a.min(h);b=b.max(h)}this.cachedBoundingBox=[a,b]}return this.cachedBoundingBox},flipped:function(){var a=this.vertices.map(function(a){return a.flipped()});a.reverse();var b=this.plane.flipped();return new c.Polygon(a,this.shared,b)},transform:function(a){var b=this.vertices.map(function(b){return b.transform(a)}),d=this.plane.transform(a);a.isMirroring()&&b.reverse();return new c.Polygon(b,this.shared,d)},toString:function(){var a="Polygon plane: "+this.plane.toString()+"\n";this.vertices.map(function(b){a+=
  153. " "+b.toString()+"\n"});return a},projectToOrthoNormalBasis:function(a){var b=this.vertices.map(function(b){return a.to2D(b.pos)}),b=n.fromPointsNoCheck(b),d=b.area();1E-5>Math.abs(d)?b=new n:0>d&&(b=b.flipped());return b},solidFromSlices:function(a){var b=[],d=null,e=null,f=null,h=null,m=2,q=!1,k,g=null;a&&(q=!!a.loop,a.numslices&&(m=a.numslices),a.callback&&(k=a.callback));if(!k){var l=new c.Polygon.createFromPoints([[0,0,0],[1,0,0],[1,1,0],[0,1,0]]);k=function(a,b){return 0==a||1==a?l.tr([0,0,
  154. a]):null}}a=0;for(--m;a<=m;a++)if(d=k.call(this,a/m,a)){if(!(d instanceof c.Polygon))throw Error("CSG.Polygon.solidFromSlices callback error: CSG.Polygon expected");d.checkIfConvex();e?(null===g&&(g=0>e.plane.signedDistanceToPoint(d.vertices[0].pos)),this._addWalls(b,e,d,g)):f=d;e=d}h=d;q?f.vertices.length==h.vertices.length&&f.vertices.every(function(a,b){return a.pos.equals(h.vertices[b].pos)})||this._addWalls(b,h,f,g):(b.unshift(g?f:f.flipped()),b.push(g?h.flipped():h));return c.fromPolygons(b)},
  155. _addWalls:function(a,b,d,e){b=b.vertices.slice(0);var f=d.vertices.slice(0);d=d.shared||null;b[0].pos.equals(b[b.length-1].pos)||b.push(b[0]);f[0].pos.equals(f[f.length-1].pos)||f.push(f[0]);e&&(b=b.reverse(),f=f.reverse());e=f.length-1;for(var h=b.length-1,m=e-h,q=0<m,g=0>m,l=[],m=Math.abs(m);0<m;m--)l.push({len:Infinity,index:-1});var n;if(g)for(m=0;m<h;m++){n=b[m].pos.distanceToSquared(b[m+1].pos);for(var p=l.length-1;0<=p;p--)if(l[p].len>n){l[p].len=n;l.index=p;break}}else if(q)for(m=0;m<e;m++)for(n=
  156. f[m].pos.distanceToSquared(f[m+1].pos),p=l.length-1;0<=p;p--)if(l[p].len>n){l[p].len=n;l.index=p;break}l.sort(k);m=b[0];n=f[0];for(var r,B,v=p=0,t=e+h;p+v<t;){if(l.length)if(q&&v==l[0].index){r=f[++v];a.push(new c.Polygon([r,n,m],d));n=r;l.shift();continue}else if(g&&p==l[0].index){r=b[++p];a.push(new c.Polygon([n,m,r],d));m=r;l.shift();continue}r=p<h?n.pos.distanceToSquared(b[p+1].pos):Infinity;B=v<e?m.pos.distanceToSquared(f[v+1].pos):Infinity;r<=B?(r=b[++p],a.push(new c.Polygon([n,m,r],d)),m=r):
  157. v<e&&(r=f[++v],a.push(new c.Polygon([r,n,m],d)),n=r)}return a}};c.Polygon.verticesConvex=function(a,b){var d=a.length;if(2<d)for(var e=a[d-2].pos,f=a[d-1].pos,h=0;h<d;h++){var m=a[h].pos;if(!c.Polygon.isConvexPoint(e,f,m,b))return!1;e=f;f=m}return!0};c.Polygon.createFromPoints=function(a,b,d){3>arguments.length&&new c.Vector3D(0,0,0);var e=[];a.map(function(a){a=new c.Vector3D(a);a=new c.Vertex(a);e.push(a)});return 3>arguments.length?new c.Polygon(e,b):new c.Polygon(e,b,d)};c.Polygon.isConvexPoint=
  158. function(a,b,d,c){return 0<=b.minus(a).cross(d.minus(b)).dot(c)};c.Polygon.isStrictlyConvexPoint=function(a,b,d,c){return 1E-5<=b.minus(a).cross(d.minus(b)).dot(c)};c.Polygon.Shared=function(a){if(null!==a&&4!=a.length)throw Error("Expecting 4 element array");this.color=a};c.Polygon.Shared.fromObject=function(a){return new c.Polygon.Shared(a.color)};c.Polygon.Shared.fromColor=function(a){var b;if(1==arguments.length)b=arguments[0].slice();else{b=[];for(var d=0;d<arguments.length;d++)b.push(arguments[d])}if(3==
  159. b.length)b.push(1);else if(4!=b.length)throw Error("setColor expects either an array with 3 or 4 elements, or 3 or 4 parameters.");return new c.Polygon.Shared(b)};c.Polygon.Shared.prototype={getTag:function(){var a=this.tag;a||(this.tag=a=c.getTag());return a},getHash:function(){return this.color?this.color.join("/"):"null"}};c.Polygon.defaultShared=new c.Polygon.Shared(null);c.PolygonTreeNode=function(){this.parent=null;this.children=[];this.polygon=null;this.removed=!1};c.PolygonTreeNode.prototype=
  160. {addPolygons:function(a){if(!this.isRootNode())throw Error("Assertion failed");var b=this;a.map(function(a){b.addChild(a)})},remove:function(){if(!this.removed){this.removed=!0;var a=this.parent.children,b=a.indexOf(this);if(0>b)throw Error("Assertion failed");a.splice(b,1);this.parent.recursivelyInvalidatePolygon()}},isRemoved:function(){return this.removed},isRootNode:function(){return!this.parent},invert:function(){if(!this.isRootNode())throw Error("Assertion failed");this.invertSub()},getPolygon:function(){if(!this.polygon)throw Error("Assertion failed");
  161. return this.polygon},getPolygons:function(a){var b=[this],d=[b],c,f,h,m;for(c=0;c<d.length;++c)for(b=d[c],f=0,h=b.length;f<h;f++)m=b[f],m.polygon?a.push(m.polygon):d.push(m.children)},splitByPlane:function(a,b,d,c,f){if(this.children.length){var e=[this.children],m,q,k,g,l;for(m=0;m<e.length;m++)for(l=e[m],q=0,k=l.length;q<k;q++)g=l[q],g.children.length?e.push(g.children):g._splitByPlane(a,b,d,c,f)}else this._splitByPlane(a,b,d,c,f)},_splitByPlane:function(a,b,c,e,f){var d=this.polygon;if(d){var m=
  162. d.boundingSphere(),q=m[1]+1E-4,m=a.normal.dot(m[0])-a.w;if(m>q)e.push(this);else if(m<-q)f.push(this);else switch(a=a.splitPolygon(d),a.type){case 0:b.push(this);break;case 1:c.push(this);break;case 2:e.push(this);break;case 3:f.push(this);break;case 4:a.front&&(b=this.addChild(a.front),e.push(b)),a.back&&(e=this.addChild(a.back),f.push(e))}}},addChild:function(a){var b=new c.PolygonTreeNode;b.parent=this;b.polygon=a;this.children.push(b);return b},invertSub:function(){var a=[this],b=[a],c,e,f,h;
  163. for(c=0;c<b.length;c++)for(a=b[c],e=0,f=a.length;e<f;e++)h=a[e],h.polygon&&(h.polygon=h.polygon.flipped()),b.push(h.children)},recursivelyInvalidatePolygon:function(){for(var a=this;a.polygon;)a.polygon=null,a.parent&&(a=a.parent)}};c.Tree=function(a){this.polygonTree=new c.PolygonTreeNode;this.rootnode=new c.Node(null);a&&this.addPolygons(a)};c.Tree.prototype={invert:function(){this.polygonTree.invert();this.rootnode.invert()},clipTo:function(a,b){this.rootnode.clipTo(a,b?!0:!1)},allPolygons:function(){var a=
  164. [];this.polygonTree.getPolygons(a);return a},addPolygons:function(a){var b=this;a=a.map(function(a){return b.polygonTree.addChild(a)});this.rootnode.addPolygonTreeNodes(a)}};c.Node=function(a){this.back=this.front=this.plane=null;this.polygontreenodes=[];this.parent=a};c.Node.prototype={invert:function(){var a=[this],b,c;for(b=0;b<a.length;b++){c=a[b];c.plane&&(c.plane=c.plane.flipped());c.front&&a.push(c.front);c.back&&a.push(c.back);var e=c.front;c.front=c.back;c.back=e}},clipPolygons:function(a,
  165. b){var c={node:this,polygontreenodes:a},e,f=[];do{e=c.node;a=c.polygontreenodes;if(e.plane){for(var c=[],h=[],m=b?c:h,q=e.plane,k=a.length,g=0;g<k;g++){var l=a[g];l.isRemoved()||l.splitByPlane(q,m,c,h,c)}e.front&&0<h.length&&f.push({node:e.front,polygontreenodes:h});h=c.length;if(e.back&&0<h)f.push({node:e.back,polygontreenodes:c});else for(var g=0;g<h;g++)c[g].remove()}c=f.pop()}while("undefined"!==typeof c)},clipTo:function(a,b){var c=this,e=[];do 0<c.polygontreenodes.length&&a.rootnode.clipPolygons(c.polygontreenodes,
  166. b),c.front&&e.push(c.front),c.back&&e.push(c.back),c=e.pop();while("undefined"!==typeof c)},addPolygonTreeNodes:function(a){a={node:this,polygontreenodes:a};var b,d=[];do{b=a.node;a=a.polygontreenodes;if(0!==a.length){var e=b;if(!b.plane){var f=a[0].getPolygon().plane;b.plane=f}for(var f=[],h=[],m=0,q=a.length;m<q;++m)a[m].splitByPlane(e.plane,e.polygontreenodes,h,f,h);0<f.length&&(b.front||(b.front=new c.Node(b)),d.push({node:b.front,polygontreenodes:f}));0<h.length&&(b.back||(b.back=new c.Node(b)),
  167. d.push({node:b.back,polygontreenodes:h}))}a=d.pop()}while("undefined"!==typeof a)},getParentPlaneNormals:function(a,b){0<b&&this.parent&&(a.push(this.parent.plane.normal),this.parent.getParentPlaneNormals(a,b-1))}};c.Matrix4x4=function(a){this.elements=1<=arguments.length?a:[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]};c.Matrix4x4.prototype={plus:function(a){for(var b=[],d=0;16>d;d++)b[d]=this.elements[d]+a.elements[d];return new c.Matrix4x4(b)},minus:function(a){for(var b=[],d=0;16>d;d++)b[d]=this.elements[d]-
  168. a.elements[d];return new c.Matrix4x4(b)},multiply:function(a){var b=this.elements[0],d=this.elements[1],e=this.elements[2],f=this.elements[3],h=this.elements[4],m=this.elements[5],q=this.elements[6],g=this.elements[7],k=this.elements[8],l=this.elements[9],n=this.elements[10],p=this.elements[11],B=this.elements[12],v=this.elements[13],t=this.elements[14],y=this.elements[15],A=a.elements[0],w=a.elements[1],x=a.elements[2],z=a.elements[3],D=a.elements[4],C=a.elements[5],F=a.elements[6],H=a.elements[7],
  169. K=a.elements[8],L=a.elements[9],N=a.elements[10],M=a.elements[11],O=a.elements[12],P=a.elements[13],Q=a.elements[14];a=a.elements[15];var I=[];I[0]=b*A+d*D+e*K+f*O;I[1]=b*w+d*C+e*L+f*P;I[2]=b*x+d*F+e*N+f*Q;I[3]=b*z+d*H+e*M+f*a;I[4]=h*A+m*D+q*K+g*O;I[5]=h*w+m*C+q*L+g*P;I[6]=h*x+m*F+q*N+g*Q;I[7]=h*z+m*H+q*M+g*a;I[8]=k*A+l*D+n*K+p*O;I[9]=k*w+l*C+n*L+p*P;I[10]=k*x+l*F+n*N+p*Q;I[11]=k*z+l*H+n*M+p*a;I[12]=B*A+v*D+t*K+y*O;I[13]=B*w+v*C+t*L+y*P;I[14]=B*x+v*F+t*N+y*Q;I[15]=B*z+v*H+t*M+y*a;return new c.Matrix4x4(I)},
  170. clone:function(){var a=this.elements.map(function(a){return a});return new c.Matrix4x4(a)},rightMultiply1x3Vector:function(a){var b=a._x,d=a._y,e=a._z;a=b*this.elements[0]+d*this.elements[1]+e*this.elements[2]+1*this.elements[3];var f=b*this.elements[4]+d*this.elements[5]+e*this.elements[6]+1*this.elements[7],h=b*this.elements[8]+d*this.elements[9]+e*this.elements[10]+1*this.elements[11],b=b*this.elements[12]+d*this.elements[13]+e*this.elements[14]+1*this.elements[15];1!=b&&(b=1/b,a*=b,f*=b,h*=b);
  171. return new c.Vector3D(a,f,h)},leftMultiply1x3Vector:function(a){var b=a._x,d=a._y,e=a._z;a=b*this.elements[0]+d*this.elements[4]+e*this.elements[8]+1*this.elements[12];var f=b*this.elements[1]+d*this.elements[5]+e*this.elements[9]+1*this.elements[13],h=b*this.elements[2]+d*this.elements[6]+e*this.elements[10]+1*this.elements[14],b=b*this.elements[3]+d*this.elements[7]+e*this.elements[11]+1*this.elements[15];1!=b&&(b=1/b,a*=b,f*=b,h*=b);return new c.Vector3D(a,f,h)},rightMultiply1x2Vector:function(a){var b=
  172. a.x,d=a.y;a=b*this.elements[0]+d*this.elements[1]+0*this.elements[2]+1*this.elements[3];var e=b*this.elements[4]+d*this.elements[5]+0*this.elements[6]+1*this.elements[7],b=b*this.elements[12]+d*this.elements[13]+0*this.elements[14]+1*this.elements[15];1!=b&&(b=1/b,a*=b,e*=b);return new c.Vector2D(a,e)},leftMultiply1x2Vector:function(a){var b=a.x,d=a.y;a=b*this.elements[0]+d*this.elements[4]+0*this.elements[8]+1*this.elements[12];var e=b*this.elements[1]+d*this.elements[5]+0*this.elements[9]+1*this.elements[13],
  173. b=b*this.elements[3]+d*this.elements[7]+0*this.elements[11]+1*this.elements[15];1!=b&&(b=1/b,a*=b,e*=b);return new c.Vector2D(a,e)},isMirroring:function(){var a=new c.Vector3D(this.elements[0],this.elements[4],this.elements[8]),b=new c.Vector3D(this.elements[1],this.elements[5],this.elements[9]),d=new c.Vector3D(this.elements[2],this.elements[6],this.elements[10]);return 0>a.cross(b).dot(d)}};c.Matrix4x4.unity=function(){return new c.Matrix4x4};c.Matrix4x4.rotationX=function(a){var b=1/180*Math.PI*
  174. a;a=Math.cos(b);b=Math.sin(b);return new c.Matrix4x4([1,0,0,0,0,a,b,0,0,-b,a,0,0,0,0,1])};c.Matrix4x4.rotationY=function(a){var b=1/180*Math.PI*a;a=Math.cos(b);b=Math.sin(b);return new c.Matrix4x4([a,0,-b,0,0,1,0,0,b,0,a,0,0,0,0,1])};c.Matrix4x4.rotationZ=function(a){var b=1/180*Math.PI*a;a=Math.cos(b);b=Math.sin(b);return new c.Matrix4x4([a,b,0,0,-b,a,0,0,0,0,1,0,0,0,0,1])};c.Matrix4x4.rotation=function(a,b,d){a=new c.Vector3D(a);b=new c.Vector3D(b);b=c.Plane.fromNormalAndPoint(b,a);b=new c.OrthoNormalBasis(b);
  175. var e=c.Matrix4x4.translation(a.negated()),e=e.multiply(b.getProjectionMatrix()),e=e.multiply(c.Matrix4x4.rotationZ(d)),e=e.multiply(b.getInverseProjectionMatrix());return e=e.multiply(c.Matrix4x4.translation(a))};c.Matrix4x4.translation=function(a){a=new c.Vector3D(a);return new c.Matrix4x4([1,0,0,0,0,1,0,0,0,0,1,0,a.x,a.y,a.z,1])};c.Matrix4x4.mirroring=function(a){var b=a.normal.x,d=a.normal.y,e=a.normal.z;a=a.w;return new c.Matrix4x4([1-2*b*b,-2*d*b,-2*e*b,0,-2*b*d,1-2*d*d,-2*e*d,0,-2*b*e,-2*d*
  176. e,1-2*e*e,0,-2*b*a,-2*d*a,-2*e*a,1])};c.Matrix4x4.scaling=function(a){a=new c.Vector3D(a);return new c.Matrix4x4([a.x,0,0,0,0,a.y,0,0,0,0,a.z,0,0,0,0,1])};c.Vector2D=function(a,b){if(2==arguments.length)this._x=parseFloat(a),this._y=parseFloat(b);else{var d=!0;if(1==arguments.length)if("object"==typeof a)a instanceof c.Vector2D?(this._x=a._x,this._y=a._y):a instanceof Array?(this._x=parseFloat(a[0]),this._y=parseFloat(a[1])):"x"in a&&"y"in a?(this._x=parseFloat(a.x),this._y=parseFloat(a.y)):d=!1;
  177. else{var e=parseFloat(a);this._y=this._x=e}else d=!1;d&&(c.IsFloat(this._x)&&c.IsFloat(this._y)||(d=!1));if(!d)throw Error("wrong arguments");}};c.Vector2D.fromAngle=function(a){return c.Vector2D.fromAngleRadians(a)};c.Vector2D.fromAngleDegrees=function(a){return c.Vector2D.fromAngleRadians(Math.PI*a/180)};c.Vector2D.fromAngleRadians=function(a){return c.Vector2D.Create(Math.cos(a),Math.sin(a))};c.Vector2D.Create=function(a,b){var d=Object.create(c.Vector2D.prototype);d._x=a;d._y=b;return d};c.Vector2D.prototype=
  178. {get x(){return this._x},get y(){return this._y},set x(a){throw Error("Vector2D is immutable");},set y(a){throw Error("Vector2D is immutable");},toVector3D:function(a){return new c.Vector3D(this._x,this._y,a)},equals:function(a){return this._x==a._x&&this._y==a._y},clone:function(){return c.Vector2D.Create(this._x,this._y)},negated:function(){return c.Vector2D.Create(-this._x,-this._y)},plus:function(a){return c.Vector2D.Create(this._x+a._x,this._y+a._y)},minus:function(a){return c.Vector2D.Create(this._x-
  179. a._x,this._y-a._y)},times:function(a){return c.Vector2D.Create(this._x*a,this._y*a)},dividedBy:function(a){return c.Vector2D.Create(this._x/a,this._y/a)},dot:function(a){return this._x*a._x+this._y*a._y},lerp:function(a,b){return this.plus(a.minus(this).times(b))},length:function(){return Math.sqrt(this.dot(this))},distanceTo:function(a){return this.minus(a).length()},distanceToSquared:function(a){return this.minus(a).lengthSquared()},lengthSquared:function(){return this.dot(this)},unit:function(){return this.dividedBy(this.length())},
  180. cross:function(a){return this._x*a._y-this._y*a._x},normal:function(){return c.Vector2D.Create(this._y,-this._x)},multiply4x4:function(a){return a.leftMultiply1x2Vector(this)},transform:function(a){return a.leftMultiply1x2Vector(this)},angle:function(){return this.angleRadians()},angleDegrees:function(){return 180*this.angleRadians()/Math.PI},angleRadians:function(){return Math.atan2(this._y,this._x)},min:function(a){return c.Vector2D.Create(Math.min(this._x,a._x),Math.min(this._y,a._y))},max:function(a){return c.Vector2D.Create(Math.max(this._x,
  181. a._x),Math.max(this._y,a._y))},toString:function(){return"("+this._x.toFixed(2)+", "+this._y.toFixed(2)+")"},abs:function(){return c.Vector2D.Create(Math.abs(this._x),Math.abs(this._y))}};c.Line2D=function(a,b){a=new c.Vector2D(a);b=parseFloat(b);var d=a.length();b*=d;this.normal=a=a.times(1/d);this.w=b};c.Line2D.fromPoints=function(a,b){a=new c.Vector2D(a);b=new c.Vector2D(b);var d=b.minus(a).normal().negated().unit(),e=a.dot(d);return new c.Line2D(d,e)};c.Line2D.prototype={reverse:function(){return new c.Line2D(this.normal.negated(),
  182. -this.w)},equals:function(a){return a.normal.equals(this.normal)&&a.w==this.w},origin:function(){return this.normal.times(this.w)},direction:function(){return this.normal.normal()},xAtY:function(a){return(this.w-this.normal._y*a)/this.normal.x},absDistanceToPoint:function(a){a=new c.Vector2D(a);a=a.dot(this.normal);return Math.abs(a-this.w)},intersectWithLine:function(a){a=c.solve2Linear(this.normal.x,this.normal.y,a.normal.x,a.normal.y,this.w,a.w);return a=new c.Vector2D(a)},transform:function(a){var b=
  183. new c.Vector2D(0,0),d=this.normal.times(this.w),b=b.multiply4x4(a),b=this.normal.multiply4x4(a).minus(b);a=d.multiply4x4(a);a=b.dot(a);return new c.Line2D(b,a)}};c.Line3D=function(a,b){a=new c.Vector3D(a);b=new c.Vector3D(b);this.point=a;this.direction=b.unit()};c.Line3D.fromPoints=function(a,b){a=new c.Vector3D(a);b=new c.Vector3D(b);var d=b.minus(a);return new c.Line3D(a,d)};c.Line3D.fromPlanes=function(a,b){var d=a.normal.cross(b.normal),e=d.length();if(1E-10>e)throw Error("Parallel planes");var d=
  184. d.times(1/e),e=Math.abs(d.x),f=Math.abs(d.y),h=Math.abs(d.z);e>=f&&e>=h?(e=c.solve2Linear(a.normal.y,a.normal.z,b.normal.y,b.normal.z,a.w,b.w),e=new c.Vector3D(0,e[0],e[1])):f>=e&&f>=h?(e=c.solve2Linear(a.normal.x,a.normal.z,b.normal.x,b.normal.z,a.w,b.w),e=new c.Vector3D(e[0],0,e[1])):(e=c.solve2Linear(a.normal.x,a.normal.y,b.normal.x,b.normal.y,a.w,b.w),e=new c.Vector3D(e[0],e[1],0));return new c.Line3D(e,d)};c.Line3D.prototype={intersectWithPlane:function(a){a=(a.w-a.normal.dot(this.point))/a.normal.dot(this.direction);
  185. return this.point.plus(this.direction.times(a))},clone:function(a){return new c.Line3D(this.point.clone(),this.direction.clone())},reverse:function(){return new c.Line3D(this.point.clone(),this.direction.negated())},transform:function(a){var b=this.point.multiply4x4(a);a=this.point.plus(this.direction).multiply4x4(a).minus(b);return new c.Line3D(b,a)},closestPointOnLine:function(a){a=new c.Vector3D(a);a=a.minus(this.point).dot(this.direction)/this.direction.dot(this.direction);return this.point.plus(this.direction.times(a))},
  186. distanceToPoint:function(a){a=new c.Vector3D(a);var b=this.closestPointOnLine(a);return a.minus(b).length()},equals:function(a){return!this.direction.equals(a.direction)||1E-8<this.distanceToPoint(a.point)?!1:!0}};c.OrthoNormalBasis=function(a,b){b=2>arguments.length?a.normal.randomNonParallelVector():new c.Vector3D(b);this.v=a.normal.cross(b).unit();this.u=this.v.cross(a.normal);this.plane=a;this.planeorigin=a.normal.times(a.w)};c.OrthoNormalBasis.GetCartesian=function(a,b){var d=a+"/"+b,e;if("X/Y"==
  187. d)d=[0,0,1],e=[1,0,0];else if("Y/-X"==d)d=[0,0,1],e=[0,1,0];else if("-X/-Y"==d)d=[0,0,1],e=[-1,0,0];else if("-Y/X"==d)d=[0,0,1],e=[0,-1,0];else if("-X/Y"==d)d=[0,0,-1],e=[-1,0,0];else if("-Y/-X"==d)d=[0,0,-1],e=[0,-1,0];else if("X/-Y"==d)d=[0,0,-1],e=[1,0,0];else if("Y/X"==d)d=[0,0,-1],e=[0,1,0];else if("X/Z"==d)d=[0,-1,0],e=[1,0,0];else if("Z/-X"==d)d=[0,-1,0],e=[0,0,1];else if("-X/-Z"==d)d=[0,-1,0],e=[-1,0,0];else if("-Z/X"==d)d=[0,-1,0],e=[0,0,-1];else if("-X/Z"==d)d=[0,1,0],e=[-1,0,0];else if("-Z/-X"==
  188. d)d=[0,1,0],e=[0,0,-1];else if("X/-Z"==d)d=[0,1,0],e=[1,0,0];else if("Z/X"==d)d=[0,1,0],e=[0,0,1];else if("Y/Z"==d)d=[1,0,0],e=[0,1,0];else if("Z/-Y"==d)d=[1,0,0],e=[0,0,1];else if("-Y/-Z"==d)d=[1,0,0],e=[0,-1,0];else if("-Z/Y"==d)d=[1,0,0],e=[0,0,-1];else if("-Y/Z"==d)d=[-1,0,0],e=[0,-1,0];else if("-Z/-Y"==d)d=[-1,0,0],e=[0,0,-1];else if("Y/-Z"==d)d=[-1,0,0],e=[0,1,0];else if("Z/Y"==d)d=[-1,0,0],e=[0,0,1];else throw Error("CSG.OrthoNormalBasis.GetCartesian: invalid combination of axis identifiers. Should pass two string arguments from [X,Y,Z,-X,-Y,-Z], being two different axes.");
  189. return new c.OrthoNormalBasis(new c.Plane(new c.Vector3D(d),0),new c.Vector3D(e))};c.OrthoNormalBasis.Z0Plane=function(){var a=new c.Plane(new c.Vector3D([0,0,1]),0);return new c.OrthoNormalBasis(a,new c.Vector3D([1,0,0]))};c.OrthoNormalBasis.prototype={getProjectionMatrix:function(){return new c.Matrix4x4([this.u.x,this.v.x,this.plane.normal.x,0,this.u.y,this.v.y,this.plane.normal.y,0,this.u.z,this.v.z,this.plane.normal.z,0,0,0,-this.plane.w,1])},getInverseProjectionMatrix:function(){var a=this.plane.normal.times(this.plane.w);
  190. return new c.Matrix4x4([this.u.x,this.u.y,this.u.z,0,this.v.x,this.v.y,this.v.z,0,this.plane.normal.x,this.plane.normal.y,this.plane.normal.z,0,a.x,a.y,a.z,1])},to2D:function(a){return new c.Vector2D(a.dot(this.u),a.dot(this.v))},to3D:function(a){return this.planeorigin.plus(this.u.times(a.x)).plus(this.v.times(a.y))},line3Dto2D:function(a){var b=a.point;a=a.direction.plus(b);b=this.to2D(b);a=this.to2D(a);return c.Line2D.fromPoints(b,a)},line2Dto3D:function(a){var b=a.origin();a=a.direction().plus(b);
  191. b=this.to3D(b);a=this.to3D(a);return c.Line3D.fromPoints(b,a)},transform:function(a){var b=this.plane.transform(a),d=this.u.transform(a);a=(new c.Vector3D(0,0,0)).transform(a);d=d.minus(a);return new c.OrthoNormalBasis(b,d)}};c.interpolateBetween2DPointsForY=function(a,b,c){c-=a.y;var d=b.y-a.y;0>d&&(c=-c,d=-d);return a.x+(0>=c?0:c>=d?1:1E-10>d?.5:c/d)*(b.x-a.x)};c.reTesselateCoplanarPolygons=function(a,b){var d=a.length;if(0<d){for(var e=a[0].plane,f=a[0].shared,h=new c.OrthoNormalBasis(e),m=[],
  192. q=[],g={},k={},n={},E=1/1E-5*10,r=0;r<d;r++){var B=a[r],v=[],t=B.vertices.length,y=-1;if(0<t){for(var A,w,x=0;x<t;x++){var z=h.to2D(B.vertices[x].pos),D=Math.floor(z.y*E),C;D in n?C=n[D]:D+1 in n?C=n[D+1]:D-1 in n?C=n[D-1]:(C=z.y,n[D]=z.y);z=c.Vector2D.Create(z.x,C);v.push(z);z=z.y;if(0===x||z<A)A=z,y=x;if(0===x||z>w)w=z;z in k||(k[z]={});k[z][r]=!0}A>=w?(v=[],t=0,y=-1):(A in g||(g[A]=[]),g[A].push(r))}v.reverse();y=t-y-1;m.push(v);q.push(y)}var d=[],F;for(F in k)d.push(F);d.sort(l);n=[];E=[];for(B=
  193. 0;B<d.length;B++){y=[];D=d[B];F=Number(D);A=k[D];for(C=0;C<n.length;++C)if(x=n[C],r=x.polygonindex,A[r]){for(var v=m[r],t=v.length,r=x.leftvertexindex,H=x.rightvertexindex;;){w=r+1;w>=t&&(w=0);if(v[w].y!=F)break;r=w}z=H-1;0>z&&(z=t-1);v[z].y==F&&(H=z);r!=x.leftvertexindex&&r==H?(n.splice(C,1),--C):(x.leftvertexindex=r,x.rightvertexindex=H,x.topleft=v[r],x.topright=v[H],w=r+1,w>=t&&(w=0),x.bottomleft=v[w],z=H-1,0>z&&(z=t-1),x.bottomright=v[z])}if(B>=d.length-1)n=[],A=null;else{A=Number(d[B+1]);var K=
  194. .5*(F+A),D=g[D],L;for(L in D){r=D[L];v=m[r];t=v.length;for(C=w=q[r];;){x=C+1;x>=t&&(x=0);if(v[x].y!=F)break;if(x==w)break;C=x}for(H=w;;){x=H-1;0>x&&(x=t-1);if(v[x].y!=F)break;if(x==C)break;H=x}w=C+1;w>=t&&(w=0);z=H-1;0>z&&(z=t-1);p(n,{polygonindex:r,leftvertexindex:C,rightvertexindex:H,topleft:v[C],topright:v[H],bottomleft:v[w],bottomright:v[z]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1:
  195. d<e?-1:0})}}for(var N in n)x=n[N],r=x.polygonindex,v=m[r],t=v.length,w=c.interpolateBetween2DPointsForY(x.topleft,x.bottomleft,F),v=c.Vector2D.Create(w,F),w=c.interpolateBetween2DPointsForY(x.topright,x.bottomright,F),t=c.Vector2D.Create(w,F),w=c.interpolateBetween2DPointsForY(x.topleft,x.bottomleft,A),r=c.Vector2D.Create(w,A),w=c.interpolateBetween2DPointsForY(x.topright,x.bottomright,A),x=c.Vector2D.Create(w,A),x={topleft:v,topright:t,bottomleft:r,bottomright:x,leftline:c.Line2D.fromPoints(v,r),
  196. rightline:c.Line2D.fromPoints(x,t)},0<y.length&&(r=y[y.length-1],v=x.topleft.distanceTo(r.topright),t=x.bottomleft.distanceTo(r.bottomright),1E-5>v&&1E-5>t&&(x.topleft=r.topleft,x.leftline=r.leftline,x.bottomleft=r.bottomleft,y.splice(y.length-1,1))),y.push(x);if(0<B){F={};A={};for(x=0;x<y.length;x++)for(w=y[x],r=0;r<E.length;r++)if(!A[r]&&(z=E[r],1E-5>z.bottomleft.distanceTo(w.topleft)&&1E-5>z.bottomright.distanceTo(w.topright))){A[r]=!0;v=w.leftline.direction().x-z.leftline.direction().x;t=w.rightline.direction().x-
  197. z.rightline.direction().x;D=1E-5>Math.abs(v);t=(C=1E-5>Math.abs(t))||0<=t;(D||0<=v)&&t&&(w.outpolygon=z.outpolygon,w.leftlinecontinues=D,w.rightlinecontinues=C,F[r]=!0);break}for(r=0;r<E.length;r++)if(!F[r]){z=E[r];z.outpolygon.rightpoints.push(z.bottomright);1E-5<z.bottomright.distanceTo(z.bottomleft)&&z.outpolygon.leftpoints.push(z.bottomleft);z.outpolygon.leftpoints.reverse();var M=[];z.outpolygon.rightpoints.concat(z.outpolygon.leftpoints).map(function(a){a=h.to3D(a);a=new c.Vertex(a);M.push(a)});
  198. x=new c.Polygon(M,f,e);b.push(x)}}for(x=0;x<y.length;x++)w=y[x],w.outpolygon?(w.leftlinecontinues||w.outpolygon.leftpoints.push(w.topleft),w.rightlinecontinues||w.outpolygon.rightpoints.push(w.topright)):(w.outpolygon={leftpoints:[],rightpoints:[]},w.outpolygon.leftpoints.push(w.topleft),1E-5<w.topleft.distanceTo(w.topright)&&w.outpolygon.rightpoints.push(w.topright));E=y}}};c.fuzzyFactory=function(a,b){this.lookuptable={};this.multiplier=1/b};c.fuzzyFactory.prototype={lookupOrCreate:function(a,b){var c=
  199. "",e=this.multiplier;a.forEach(function(a){c+=Math.round(a*e)+"/"});if(c in this.lookuptable)return this.lookuptable[c];for(var f=b(a),h=a.map(function(a){a=Math.floor(a*e);return[""+a+"/",""+(a+1)+"/"]}),m=1<<a.length,q=0;q<m;++q){var g=q,c="";h.forEach(function(a){c+=a[g&1];g>>=1});this.lookuptable[c]=f}return f}};c.fuzzyCSGFactory=function(){this.vertexfactory=new c.fuzzyFactory(3,1E-5);this.planefactory=new c.fuzzyFactory(4,1E-5);this.polygonsharedfactory={}};c.fuzzyCSGFactory.prototype={getPolygonShared:function(a){var b=
  200. a.getHash();return b in this.polygonsharedfactory?this.polygonsharedfactory[b]:this.polygonsharedfactory[b]=a},getVertex:function(a){return this.vertexfactory.lookupOrCreate([a.pos._x,a.pos._y,a.pos._z],function(b){return a})},getPlane:function(a){return this.planefactory.lookupOrCreate([a.normal._x,a.normal._y,a.normal._z,a.w],function(b){return a})},getPolygon:function(a){var b=this.getPlane(a.plane),d=this.getPolygonShared(a.shared),e=this;a=a.vertices.map(function(a){return e.getVertex(a)});var f=
  201. [];if(0<a.length){var h=a[a.length-1].getTag();a.forEach(function(a){var b=a.getTag();b!=h&&f.push(a);h=b})}3>f.length&&(f=[]);return new c.Polygon(f,d,b)},getCSG:function(a){var b=this,d=[];a.polygons.forEach(function(a){a=b.getPolygon(a);3<=a.vertices.length&&d.push(a)});return c.fromPolygons(d)}};c.staticTag=1;c.getTag=function(){return c.staticTag++};c.Properties=function(){};c.Properties.prototype={_transform:function(a){var b=new c.Properties;c.Properties.transformObj(this,b,a);return b},_merge:function(a){var b=
  202. new c.Properties;c.Properties.cloneObj(this,b);c.Properties.addFrom(b,a);return b}};c.Properties.transformObj=function(a,b,d){for(var e in a)if("_transform"!=e&&"_merge"!=e){var f=a[e],h=f;"object"==typeof f&&("transform"in f&&"function"==typeof f.transform?h=f.transform(d):f instanceof Array?(h=[],c.Properties.transformObj(f,h,d)):f instanceof c.Properties&&(h=new c.Properties,c.Properties.transformObj(f,h,d)));b[e]=h}};c.Properties.cloneObj=function(a,b){for(var d in a)if("_transform"!=d&&"_merge"!=
  203. d){var e=a[d],f=e;if("object"==typeof e)if(e instanceof Array)for(var f=[],h=0;h<e.length;h++)f.push(e[h]);else e instanceof c.Properties&&(f=new c.Properties,c.Properties.cloneObj(e,f));b[d]=f}};c.Properties.addFrom=function(a,b){for(var d in b)"_transform"!=d&&"_merge"!=d&&(d in a&&"object"==typeof a[d]&&a[d]instanceof c.Properties&&"object"==typeof b[d]&&b[d]instanceof c.Properties?c.Properties.addFrom(a[d],b[d]):d in a||(a[d]=b[d]))};c.Connector=function(a,b,d){this.point=new c.Vector3D(a);this.axisvector=
  204. (new c.Vector3D(b)).unit();this.normalvector=(new c.Vector3D(d)).unit()};c.Connector.prototype={normalized:function(){var a=this.axisvector.unit(),b=this.normalvector.cross(a).unit(),b=a.cross(b);return new c.Connector(this.point,a,b)},transform:function(a){var b=this.point.multiply4x4(a),d=this.point.plus(this.axisvector).multiply4x4(a).minus(b);a=this.point.plus(this.normalvector).multiply4x4(a).minus(b);return new c.Connector(b,d,a)},getTransformationTo:function(a,b,d){b=b?!0:!1;d=d?Number(d):
  205. 0;var e=this.normalized();a=a.normalized();var f=c.Matrix4x4.translation(this.point.negated()),h=c.Plane.anyPlaneFromVector3Ds(new c.Vector3D(0,0,0),e.axisvector,a.axisvector),h=new c.OrthoNormalBasis(h),m=h.to2D(e.axisvector).angle(),q=h.to2D(a.axisvector).angle(),m=180*(q-m)/Math.PI;b&&(m+=180);f=f.multiply(h.getProjectionMatrix());f=f.multiply(c.Matrix4x4.rotationZ(m));f=f.multiply(h.getInverseProjectionMatrix());e=e.transform(f);b=c.Plane.fromNormalAndPoint(a.axisvector,new c.Vector3D(0,0,0));
  206. b=new c.OrthoNormalBasis(b);m=b.to2D(e.normalvector).angle();q=b.to2D(a.normalvector).angle();m=180*(q-m)/Math.PI;m+=d;f=f.multiply(b.getProjectionMatrix());f=f.multiply(c.Matrix4x4.rotationZ(m));f=f.multiply(b.getInverseProjectionMatrix());return f=f.multiply(c.Matrix4x4.translation(a.point))},axisLine:function(){return new c.Line3D(this.point,this.axisvector)},extend:function(a){a=this.point.plus(this.axisvector.unit().times(a));return new c.Connector(a,this.axisvector,this.normalvector)}};c.ConnectorList=
  207. function(a){this.connectors_=a?a.slice():[]};c.ConnectorList.defaultNormal=[0,0,1];c.ConnectorList.fromPath2D=function(a,b,d){if(3===arguments.length)return c.ConnectorList._fromPath2DTangents(a,b,d);if(2==arguments.length)return c.ConnectorList._fromPath2DExplicit(a,b);throw"call with path2D and either 2 direction vectors, or a function returning direction vectors";};c.ConnectorList._fromPath2DTangents=function(a,b,d){var e,f=a.points.length,h=new c.ConnectorList([new c.Connector(a.points[0],b,c.ConnectorList.defaultNormal)]);
  208. a.points.slice(1,f-1).forEach(function(b,d){e=a.points[d+2].minus(a.points[d]).toVector3D(0);h.appendConnector(new c.Connector(b.toVector3D(0),e,c.ConnectorList.defaultNormal))},this);h.appendConnector(new c.Connector(a.points[f-1],d,c.ConnectorList.defaultNormal));h.closed=a.closed;return h};c.ConnectorList._fromPath2DExplicit=function(a,b){function d(a,b,c){"function"==typeof a&&(a=a(b,c));return a}var e=new c.ConnectorList(a.points.map(function(a,e){return new c.Connector(a.toVector3D(0),c.Vector3D.Create(1,
  209. 0,0).rZ(d(b,a,e)),c.ConnectorList.defaultNormal)},this));e.closed=a.closed;return e};c.ConnectorList.prototype={setClosed:function(a){this.closed=!!closed},appendConnector:function(a){this.connectors_.push(a)},followWith:function(a){function b(a,b){"function"==typeof a&&(a=a(b.point,b.axisvector,b.normalvector));return a}this.verify();var d=[],e,f=this.connectors_[this.connectors_.length-1],h=b(a,f);this.connectors_.forEach(function(c,g){e=b(a,c);g||this.closed?d.push.apply(d,h._toWallPolygons({toConnector1:f,
  210. toConnector2:c,cag:e})):d.push.apply(d,e._toPlanePolygons({toConnector:c,flipped:!0}));g!=this.connectors_.length-1||this.closed||d.push.apply(d,e._toPlanePolygons({toConnector:c}));h=e;f=c},this);return c.fromPolygons(d).reTesselated().canonicalized()},verify:function(){for(var a,b,c=0;c<this.connectors_.length-1;c++){a=this.connectors_[c];b=this.connectors_[c+1];if(0>=b.point.minus(a.point).dot(a.axisvector))throw"Invalid ConnectorList. Each connectors position needs to be within a <90deg range of previous connectors axisvector";
  211. if(0>=a.axisvector.dot(b.axisvector))throw"invalid ConnectorList. No neighboring connectors axisvectors may span a >=90deg angle";}}};c.Path2D=function(a,b){b=!!b;a=a||[];var d=null;b&&0<a.length&&(d=new c.Vector2D(a[a.length-1]));var e=[];a.map(function(a){a=new c.Vector2D(a);var b=!1;null!==d&&(b=1E-5>a.distanceTo(d));b||e.push(a);d=a});this.points=e;this.closed=b};c.Path2D.arc=function(a){var b=c.parseOptionAs2DVector(a,"center",0),d=c.parseOptionAsFloat(a,"radius",1),e=c.parseOptionAsFloat(a,
  212. "startangle",0),f=c.parseOptionAsFloat(a,"endangle",360),h=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D);for(a=c.parseOptionAsBool(a,"maketangent",!1);720<=f-e;)f-=360;for(;-720>=f-e;)f+=360;var m=[],g,k=Math.abs(f-e);if(1E-5>k)g=c.Vector2D.fromAngle(e/180*Math.PI).times(d),m.push(g.plus(b));else{h=Math.floor(h*k/360)+1;k=.5*h/k;.25<k&&(k=.25);for(var l=a?h+2:h,n=0;n<=l;n++)g=n,a&&(g=(n-1)*(h-2*k)/h+k,0>g&&(g=0),g>h&&(g=h)),g=c.Vector2D.fromAngle((e+g*(f-e)/h)/180*Math.PI).times(d),m.push(g.plus(b))}return new c.Path2D(m,
  213. !1)};c.Path2D.prototype={concat:function(a){if(this.closed||a.closed)throw Error("Paths must not be closed");a=this.points.concat(a.points);return new c.Path2D(a)},appendPoint:function(a){if(this.closed)throw Error("Path must not be closed");a=new c.Vector2D(a);a=this.points.concat([a]);return new c.Path2D(a)},appendPoints:function(a){if(this.closed)throw Error("Path must not be closed");var b=this.points;a.forEach(function(a){b.push(new c.Vector2D(a))});return new c.Path2D(b)},close:function(){return new c.Path2D(this.points,
  214. !0)},rectangularExtrude:function(a,b,c){return this.expandToCAG(a/2,c).extrude({offset:[0,0,b]})},expandToCAG:function(a,b){var c=[],e=this.points.length,f=0;this.closed&&2<e&&(f=-1);for(var h,m=f;m<e;m++){var g=m;0>g&&(g=e-1);g=new n.Vertex(this.points[g]);m>f&&(h=new n.Side(h,g),c.push(h));h=g}return n.fromSides(c).expandedShell(a,b)},innerToCAG:function(){if(!this.closed)throw Error("The path should be closed!");return n.fromPoints(this.points)},transform:function(a){var b=this.points.map(function(b){return b.multiply4x4(a)});
  215. return new c.Path2D(b,this.closed)},appendBezier:function(a,b){2>arguments.length&&(b={});if(this.closed)throw Error("Path must not be closed");if(!(a instanceof Array))throw Error("appendBezier: should pass an array of control points");if(1>a.length)throw Error("appendBezier: need at least 1 control point");if(1>this.points.length)throw Error("appendBezier: path must already contain a point (the endpoint of the path is used as the starting point for the bezier curve)");var d=c.parseOptionAsInt(b,
  216. "resolution",c.defaultResolution2D);4>d&&(d=4);var e=[],f=[];f.push(this.points[this.points.length-1]);for(var h=0;h<a.length;++h){var m=a[h];if(null===m){if(0!=h)throw Error("appendBezier: null can only be passed as the first control point");if(2>a.length)throw Error("appendBezier: null can only be passed if there is at least one more control point");if("lastBezierControlPoint"in this)m=this.lastBezierControlPoint;else{if(2>this.points.length)throw Error("appendBezier: null is passed as a control point but this requires a previous bezier curve or at least two points in the existing path");
  217. m=this.points[this.points.length-2]}m=this.points[this.points.length-1].times(2).minus(m)}else m=new c.Vector2D(m);f.push(m)}for(var g=f.length-1,m=1,h=0;h<=g;++h)0<h&&(m*=h),e.push(m);for(var k=[],h=0;h<=g;++h)k.push(e[g]/(e[h]*e[g-h]));for(var e=function(a){for(var b=1,d=Math.pow(1-a,g),e=1!=a?1/(1-a):1,h=new c.Vector2D(0,0),m=0;m<=g;++m)m==g&&(d=1),h=h.plus(f[m].times(k[m]*b*d)),b*=a,d*=e;return h},m=[],l=[],n=g+1,h=0;h<n;++h){var p=h/(n-1),r=e(p);m.push(r);l.push(p)}h=1;for(d=Math.sin(2*Math.PI/
  218. d);h<m.length-1;)if(n=m[h].minus(m[h-1]).unit(),p=m[h+1].minus(m[h]).unit(),n=n.cross(p),Math.abs(n)>d){var p=l[h-1],r=l[h+1],n=p+1*(r-p)/3,p=p+2*(r-p)/3,r=e(n),B=e(p);m.splice(h,1,r,B);l.splice(h,1,n,p);h--;1>h&&(h=1)}else++h;m=this.points.concat(m.slice(1));e=new c.Path2D(m);e.lastBezierControlPoint=f[f.length-2];return e},appendArc:function(a,b){2>arguments.length&&(b={});if(this.closed)throw Error("Path must not be closed");if(1>this.points.length)throw Error("appendArc: path must already contain a point (the endpoint of the path is used as the starting point for the arc)");
  219. var d=c.parseOptionAsInt(b,"resolution",c.defaultResolution2D);4>d&&(d=4);var e,f;if("xradius"in b||"yradius"in b){if("radius"in b)throw Error("Should either give an xradius and yradius parameter, or a radius parameter");e=c.parseOptionAsFloat(b,"xradius",0);f=c.parseOptionAsFloat(b,"yradius",0)}else f=e=c.parseOptionAsFloat(b,"radius",0);var h=c.parseOptionAsFloat(b,"xaxisrotation",0),m=c.parseOptionAsBool(b,"clockwise",!1),g=c.parseOptionAsBool(b,"large",!1),k=this.points[this.points.length-1];
  220. a=new c.Vector2D(a);var l=!m,m=[];if(0==e||0==f)m.push(a);else{e=Math.abs(e);f=Math.abs(f);var n=h*Math.PI/180,h=Math.cos(n),n=Math.sin(n),p=k.minus(a).times(.5),p=new c.Vector2D(h*p.x+n*p.y,-n*p.x+h*p.y),r=p.x*p.x/(e*e)+p.y*p.y/(f*f);1<r&&(r=Math.sqrt(r),e*=r,f*=r);r=Math.sqrt((e*e*f*f-e*e*p.y*p.y-f*f*p.x*p.x)/(e*e*p.y*p.y+f*f*p.x*p.x));l==g&&(r=-r);g=(new c.Vector2D(e*p.y/f,-f*p.x/e)).times(r);k=(new c.Vector2D(h*g.x-n*g.y,n*g.x+h*g.y)).plus(k.plus(a).times(.5));r=new c.Vector2D((p.x-g.x)/e,(p.y-
  221. g.y)/f);p=new c.Vector2D((-p.x-g.x)/e,(-p.y-g.y)/f);g=r.angleRadians();p=(p.angleRadians()-g)%(2*Math.PI);!l&&0<p?p-=2*Math.PI:l&&0>p&&(p+=2*Math.PI);d=Math.ceil(Math.abs(p)/(2*Math.PI)*d)+1;1>d&&(d=1);for(l=1;l<=d;l++){var B=g+l/d*p,r=Math.cos(B),B=Math.sin(B),r=(new c.Vector2D(h*e*r-n*f*B,n*e*r+h*f*B)).plus(k);m.push(r)}}m=this.points.concat(m);return new c.Path2D(m)}};c.addTransformationMethodsToPrototype=function(a){a.mirrored=function(a){return this.transform(c.Matrix4x4.mirroring(a))};a.mirroredX=
  222. function(){var a=new c.Plane(c.Vector3D.Create(1,0,0),0);return this.mirrored(a)};a.mirroredY=function(){var a=new c.Plane(c.Vector3D.Create(0,1,0),0);return this.mirrored(a)};a.mirroredZ=function(){var a=new c.Plane(c.Vector3D.Create(0,0,1),0);return this.mirrored(a)};a.tr=function(a){return this.transform(c.Matrix4x4.translation(a))};a.scale=function(a){return this.transform(c.Matrix4x4.scaling(a))};a.rX=function(a){return this.transform(c.Matrix4x4.rotationX(a))};a.rY=function(a){return this.transform(c.Matrix4x4.rotationY(a))};
  223. a.rZ=function(a){return this.transform(c.Matrix4x4.rotationZ(a))};a.rotate=function(a,d,e){return this.transform(c.Matrix4x4.rotation(a,d,e))}};c.addCenteringToPrototype=function(a,b){a.center=function(a){a=Array.prototype.map.call(arguments,function(a){return a});a.length||(a=b.slice());var c=this.getBounds();return this.tr(b.map(function(b){return-1<a.indexOf(b)?-(c[0][b]+c[1][b])/2:0}))}};var n=function(){this.sides=[]};n.fromSides=function(a){var b=new n;b.sides=a;return b};n.fromPoints=function(a){var b=
  224. a.length;if(3>b)throw Error("CAG shape needs at least 3 points");var d=[],b=new c.Vector2D(a[b-1]),e=new n.Vertex(b);a.map(function(a){a=new c.Vector2D(a);a=new n.Vertex(a);var b=new n.Side(e,a);d.push(b);e=a});a=n.fromSides(d);if(a.isSelfIntersecting())throw Error("Polygon is self intersecting!");b=a.area();if(1E-5>Math.abs(b))throw Error("Degenerate polygon!");0>b&&(a=a.flipped());return a=a.canonicalized()};n.fromPointsNoCheck=function(a){var b=[],d=new c.Vector2D(a[a.length-1]),e=new n.Vertex(d);
  225. a.map(function(a){a=new c.Vector2D(a);a=new n.Vertex(a);var d=new n.Side(e,a);b.push(d);e=a});return n.fromSides(b)};n.fromFakeCSG=function(a){a=a.polygons.map(function(a){return n.Side._fromFakePolygon(a)}).filter(function(a){return null!==a});return n.fromSides(a)};n.linesIntersect=function(a,b,d,e){if(b.equals(d)||e.equals(a)){if(1E-5>e.minus(d).unit().plus(b.minus(a).unit()).length())return!0}else{b=b.minus(a);e=e.minus(d);if(1E-9>Math.abs(b.cross(e)))return!1;a=c.solve2Linear(-b.x,e.x,-b.y,e.y,
  226. a.x-d.x,a.y-d.y);if(1E-6<a[0]&&.999999>a[0]&&1E-5<a[1]&&.999999>a[1])return!0}return!1};n.circle=function(a){a=a||{};var b=c.parseOptionAs2DVector(a,"center",[0,0]),d=c.parseOptionAsFloat(a,"radius",1);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D);var e=[],f;if(0>d)throw Error("Radius should be positive.");if(5E-4>d)return new n;for(var h=0;h<=a;h++){var m=c.Vector2D.fromAngleRadians(2*Math.PI*h/a).times(d).plus(b),m=new n.Vertex(m);0<h&&e.push(new n.Side(f,m));f=m}return n.fromSides(e)};
  227. n.rectangle=function(a){a=a||{};var b;if("corner1"in a||"corner2"in a){if("center"in a||"radius"in a)throw Error("rectangle: should either give a radius and center parameter, or a corner1 and corner2 parameter");corner1=c.parseOptionAs2DVector(a,"corner1",[0,0]);corner2=c.parseOptionAs2DVector(a,"corner2",[1,1]);b=corner1.plus(corner2).times(.5);a=corner2.minus(corner1).times(.5)}else b=c.parseOptionAs2DVector(a,"center",[0,0]),a=c.parseOptionAs2DVector(a,"radius",[1,1]);if(0>a.x||0>a.y)throw Error("Dimension should be positive.");
  228. if(5E-4>a.x||5E-4>a.y)return console.log("Throwing out a zero-length rectangle."),new n;var d=new c.Vector2D(a.x,-a.y);b=[b.plus(a),b.plus(d),b.minus(a),b.minus(d)];return n.fromPoints(b)};n.roundedRectangle=function(a){a=a||{};var b,d;if("corner1"in a||"corner2"in a){if("center"in a||"radius"in a)throw Error("roundedRectangle: should either give a radius and center parameter, or a corner1 and corner2 parameter");corner1=c.parseOptionAs2DVector(a,"corner1",[0,0]);corner2=c.parseOptionAs2DVector(a,
  229. "corner2",[1,1]);b=corner1.plus(corner2).times(.5);d=corner2.minus(corner1).times(.5)}else b=c.parseOptionAs2DVector(a,"center",[0,0]),d=c.parseOptionAs2DVector(a,"radius",[1,1]);d=d.abs();var e=c.parseOptionAsFloat(a,"roundradius",.2);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D);e=Math.min(e,Math.min(d.x,d.y)-.1);e=Math.max(0,e);d=new c.Vector2D(d.x-e,d.y-e);b=n.rectangle({center:b,radius:d});0<e&&(b=b.expand(e,a));return b};n.fromCompactBinary=function(a){if("CAG"!=a["class"])throw Error("Not a CAG");
  230. for(var b=[],d=a.vertexData,e=d.length/2,f=0,h=0;h<e;h++){var m=d[f++],g=d[f++],m=new c.Vector2D(m,g),m=new n.Vertex(m);b.push(m)}d=[];e=a.sideVertexIndices.length/2;for(h=f=0;h<e;h++)m=a.sideVertexIndices[f++],g=a.sideVertexIndices[f++],m=new n.Side(b[m],b[g]),d.push(m);a=n.fromSides(d);a.isCanonicalized=!0;return a};n.prototype={toString:function(){var a="CAG ("+this.sides.length+" sides):\n";this.sides.map(function(b){a+=" "+b.toString()+"\n"});return a},_toCSGWall:function(a,b){var d=this.sides.map(function(c){return c.toPolygon3D(a,
  231. b)});return c.fromPolygons(d)},_toVector3DPairs:function(a){var b=this.sides.map(function(a){var b=a.vertex0.pos;a=a.vertex1.pos;return[c.Vector3D.Create(b.x,b.y,0),c.Vector3D.Create(a.x,a.y,0)]});"undefined"!=typeof a&&(b=b.map(function(b){return b.map(function(b){return b.transform(a)})}));return b},_toPlanePolygons:function(a){var b=a.flipped||!1,d=[0,0,0],e=[0,0,1],f=[0,1,0],h=new c.Connector(d,e,f),d=a.translation||d,e=a.axisVector||e,f=a.normalVector||f;a=a.toConnector||new c.Connector(d,e,
  232. f);var m=h.getTransformationTo(a,!1,0);a=this.getBounds();a[0]=a[0].minus(new c.Vector2D(1,1));a[1]=a[1].plus(new c.Vector2D(1,1));h=this._toCSGWall(-1,1);a=c.fromPolygons([new c.Polygon([new c.Vertex(new c.Vector3D(a[0].x,a[0].y,0)),new c.Vertex(new c.Vector3D(a[1].x,a[0].y,0)),new c.Vertex(new c.Vector3D(a[1].x,a[1].y,0)),new c.Vertex(new c.Vector3D(a[0].x,a[1].y,0))])]);b&&(a=a.invert());a=a.intersectSub(h);return a.polygons.filter(function(a){return.99<Math.abs(a.plane.normal.z)}).map(function(a){return a.transform(m)})},
  233. _toWallPolygons:function(a){var b=new c.Connector([0,0,0],[0,0,1],[0,1,0]),d=a.toConnector1,e=a.toConnector2;if(!(d instanceof c.Connector&&e instanceof c.Connector))throw"could not parse CSG.Connector arguments toConnector1 or toConnector2";if(a.cag&&a.cag.sides.length!=this.sides.length)throw"target cag needs same sides count as start cag";a=a.cag||this;var d=b.getTransformationTo(d,!1,0),b=b.getTransformationTo(e,!1,0),e=this._toVector3DPairs(d),f=a._toVector3DPairs(b),h=[];e.forEach(function(a,
  234. b){h.push(new c.Polygon([new c.Vertex(f[b][1]),new c.Vertex(f[b][0]),new c.Vertex(a[0])]));h.push(new c.Polygon([new c.Vertex(f[b][1]),new c.Vertex(a[0]),new c.Vertex(a[1])]))});return h},union:function(a){a=a instanceof Array?a:[a];var b=this._toCSGWall(-1,1),b=b.union(a.map(function(a){return a._toCSGWall(-1,1).reTesselated()}),!1,!1);return n.fromFakeCSG(b).canonicalized()},subtract:function(a){a=a instanceof Array?a:[a];var b=this._toCSGWall(-1,1);a.map(function(a){b=b.subtractSub(a._toCSGWall(-1,
  235. 1),!1,!1)});b=b.reTesselated();b=b.canonicalized();b=n.fromFakeCSG(b);return b=b.canonicalized()},intersect:function(a){a=a instanceof Array?a:[a];var b=this._toCSGWall(-1,1);a.map(function(a){b=b.intersectSub(a._toCSGWall(-1,1),!1,!1)});b=b.reTesselated();b=b.canonicalized();b=n.fromFakeCSG(b);return b=b.canonicalized()},transform:function(a){var b=a.isMirroring(),c=this.sides.map(function(b){return b.transform(a)}),c=n.fromSides(c);b&&(c=c.flipped());return c},taper:function(a,b){0>=b&&(b=1E-4);
  236. var d=this.getBounds(),e;a[0]?(e=d[1].x-d[0].x,d=d[0].x):(e=d[1].y-d[0].y,d=d[0].y);for(var f=[],h=[],m=0;m<this.sides.length;m++){var g=this.sides[m];a[0]&&(h[0]=[g.vertex0.pos.x,g.vertex0.pos.y*(1+(b-1)*(g.vertex0.pos.x-d)/e)],h[1]=[g.vertex1.pos.x,g.vertex1.pos.y*(1+(b-1)*(g.vertex1.pos.x-d)/e)]);a[1]&&(h[0]=[g.vertex0.pos.x*(1+(b-1)*(g.vertex0.pos.y-d)/e),g.vertex0.pos.y],h[1]=[g.vertex1.pos.x*(1+(b-1)*(g.vertex1.pos.y-d)/e),g.vertex1.pos.y]);g=new n.Side(new n.Vertex(new c.Vector2D(h[0])),new n.Vertex(new c.Vector2D(h[1])));
  237. f.push(g)}return n.fromSides(f)},area:function(){var a=0;this.sides.map(function(b){a+=b.vertex0.pos.cross(b.vertex1.pos)});return a*=.5},flipped:function(){var a=this.sides.map(function(a){return a.flipped()});a.reverse();return n.fromSides(a)},getBounds:function(){var a,b=a=0===this.sides.length?new c.Vector2D(0,0):this.sides[0].vertex0.pos;this.sides.map(function(c){a=a.min(c.vertex0.pos);a=a.min(c.vertex1.pos);b=b.max(c.vertex0.pos);b=b.max(c.vertex1.pos)});return[a,b]},isSelfIntersecting:function(a){for(var b=
  238. this.sides.length,c=0;c<b;c++)for(var e=this.sides[c],f=c+1;f<b;f++){var h=this.sides[f];if(n.linesIntersect(e.vertex0.pos,e.vertex1.pos,h.vertex0.pos,h.vertex1.pos))return a&&(OpenJsCad.log(e),OpenJsCad.log(h)),!0}return!1},expandedShell:function(a,b){b=b||8;4>b&&(b=4);var d=[],e={};this.canonicalized().sides.map(function(b){var c=b.vertex1.pos.minus(b.vertex0.pos),f=c.length();if(1E-5<f)for(c=c.times(1/f),c=c.normal().times(a),c=[b.vertex1.pos.plus(c),b.vertex1.pos.minus(c),b.vertex0.pos.minus(c),
  239. b.vertex0.pos.plus(c)],c=n.fromPoints(c),d.push(c),c=0;2>c;c++){var f=0===c?b.vertex0.pos:b.vertex1.pos,h=0===c?b.vertex1.pos:b.vertex0.pos,g=f.x+" "+f.y;g in e||(e[g]=[]);e[g].push({p1:f,p2:h})}});for(var f in e){var h=e[f],g,k=h[0].p1;if(2==h.length){g=h[1].p2;h=h[0].p2.minus(k).angleDegrees();g=g.minus(k).angleDegrees();g<h&&(g+=360);g>=h+360&&(g-=360);if(g<h+180){var l=g;g=h+360;h=l}h+=90;g-=90}else h=0,g=360;if(l=g>h+359.999)h=0,g=360;if(g>h+1E-5){var p=[];l||p.push(k);var G=Math.round(b*(g-
  240. h)/360);1>G&&(G=1);for(var E=0;E<=G;E++){var r=h+E/G*(g-h);E==G&&(r=g);r=k.plus(c.Vector2D.fromAngleDegrees(r).times(a));(!l||0<E)&&p.push(r)}k=n.fromPointsNoCheck(p);d.push(k)}}f=new n;return f=f.union(d)},expand:function(a,b){return this.union(this.expandedShell(a,b))},contract:function(a,b){return this.subtract(this.expandedShell(a,b))},extrudeInOrthonormalBasis:function(a,b){if(!(a instanceof c.OrthoNormalBasis))throw Error("extrudeInPlane: the first parameter should be a CSG.OrthoNormalBasis");
  241. var d=this.extrude({offset:[0,0,b]}),e=a.getInverseProjectionMatrix();return d=d.transform(e)},extrudeInPlane:function(a,b,d){return this.extrudeInOrthonormalBasis(c.OrthoNormalBasis.GetCartesian(a,b),d)},extrude:function(a){if(0==this.sides.length)return new c;var b=c.parseOptionAs3DVector(a,"offset",[0,0,1]),d=c.parseOptionAsFloat(a,"twistangle",0),e=c.parseOptionAsInt(a,"twiststeps",c.defaultResolution3D),f=c.parseOptionAs2DVector(a,"scale",[1,1]);a=f.x;f=f.y;1E-4>a&&(a=1E-4);1E-4>f&&(f=1E-4);
  242. if(0==b.z)throw"offset cannot be orthogonal to Z axis";if(0==d||1>e)e=1;for(var h=c.Vector3D.Create(0,1,0),g=[],g=g.concat(this._toPlanePolygons({translation:[0,0,0],normalVector:h,flipped:!(0>b.z)})),g=g.concat(this._toPlanePolygons({translation:b,normalVector:h.rZ(d),flipped:0>b.z})),k=0;k<e;k++)var l=new c.Connector(b.times(k/e),[0,0,b.z],h.rZ(k*d/e)),n=new c.Connector(b.times((k+1)/e),[0,0,b.z],h.rZ((k+1)*d/e)),g=g.concat(this._toWallPolygons({toConnector1:l,toConnector2:n}));d=[];for(k=0;k<g.length;k++){e=
  243. [];for(h=0;h<g[k].vertices.length;h++)l=g[k].vertices[h].pos.z,e[h]=[g[k].vertices[h].pos._x*(1+(a-1)*l/b.z),g[k].vertices[h].pos._y*(1+(f-1)*l/b.z),l];d[k]=new c.Polygon.createFromPoints(e);d[k].shared=g[k].shared}return c.fromPolygons(d)},rotateExtrude:function(a){var b=c.parseOptionAsFloat(a,"angle",360),d=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D),b=360<b?b%360:b;a=[0,0,0];var e=c.Vector3D.Create(0,1,0),f=[0,0,1],h=[],g=new c.Connector(a,e,f);if(0<b&&360>b)var k=new c.Connector(a,
  244. e.rZ(-b),f),h=h.concat(this._toPlanePolygons({toConnector:g,flipped:!0})),h=h.concat(this._toPlanePolygons({toConnector:k}));for(var l=k=b/d;l<=b+1E-5;l+=k)d=new c.Connector(a,e.rZ(-l),f),h=h.concat(this._toWallPolygons({toConnector1:g,toConnector2:d})),g=d;return c.fromPolygons(h).reTesselated()},rotate_extrude:function(a){if(0==this.sides.length)return new c;var b=c.parseOptionAsInt(a,"faces",10),d=c.parseOptionAsInt(a,"twist",0),e=Math.abs(c.parseOptionAsInt(a,"radius",0));a=c.parseOptionAsInt(a,
  245. "tsteps",0);3>b&&(b=3);a=Math.ceil(a/b);1>a&&(a=1);for(var f=n.fromPoints([[-.001,1E5],[2E5,1E5],[2E5,-1E5],[-.001,-1E5]]),h=n.fromPoints([[.001,1E5],[-2E5,1E5],[-2E5,-1E5],[.001,-1E5]]),g=this.tr([e,0,0]),f=g.subtract(f),h=g.subtract(h),h=0!=f.sides.length?f.mirroredX().union(h):h,h=h.tr([-e,0,0]),g=[],f=0;f<b+2;f++)G=new c.Matrix4x4.rotationZ(d/360*f/b*360),g[f]=h.transform(G),g[f]=g[f].tr([e,0,0]),g[f]=g[f].canonicalized();h=h.tr([e,0,0]);d=[];for(f=0;f<b;f++)for(e=0;e<h.sides.length;e++){var k=
  246. [],l=[],p,G;p=new c.Matrix4x4.rotationZ(f/b*360);G=new c.Matrix4x4.rotationZ((f+1)/b*360);k[0]=new c.Vector3D(g[f].sides[e].vertex0.pos.x,0,g[f].sides[e].vertex0.pos.y);k[1]=new c.Vector3D(g[f].sides[e].vertex1.pos.x,0,g[f].sides[e].vertex1.pos.y);k[2]=new c.Vector3D(g[f+1].sides[e].vertex1.pos.x,0,g[f+1].sides[e].vertex1.pos.y);k[3]=new c.Vector3D(g[f+1].sides[e].vertex0.pos.x,0,g[f+1].sides[e].vertex0.pos.y);k[0]=p.rightMultiply1x3Vector(k[0]);k[1]=p.rightMultiply1x3Vector(k[1]);k[2]=G.rightMultiply1x3Vector(k[2]);
  247. k[3]=G.rightMultiply1x3Vector(k[3]);G=(k[3]._x-k[0]._x)/a;p=(k[3]._y-k[0]._y)/a;for(var E=(k[3]._z-k[0]._z)/a,r=(k[2]._x-k[1]._x)/a,B=(k[2]._y-k[1]._y)/a,v=(k[2]._z-k[1]._z)/a,t=0;t<a;t++){l[0]=new c.Vector3D(k[0]._x+t*G,k[0]._y+t*p,k[0]._z+t*E);l[1]=new c.Vector3D(k[1]._x+t*r,k[1]._y+t*B,k[1]._z+t*v);l[2]=new c.Vector3D(k[1]._x+(t+1)*r,k[1]._y+(t+1)*B,k[1]._z+(t+1)*v);l[3]=new c.Vector3D(k[0]._x+(t+1)*G,k[0]._y+(t+1)*p,k[0]._z+(t+1)*E);var y=new c.Polygon([new c.Vertex(l[0]),new c.Vertex(l[1]),new c.Vertex(l[2])]),
  248. A=new c.Polygon([new c.Vertex(l[0]),new c.Vertex(l[2]),new c.Vertex(l[3])]);d.push(y);d.push(A)}}b=c.fromPolygons(d);b=b.reTesselated();return b=b.canonicalized()},hull:function(a){n.ConvexHullPoint=function(a,b,c){this.index=a;this.angle=b;this.distance=c;this.compare=function(a){return this.angle<a.angle?-1:this.angle>a.angle?1:this.distance<a.distance?-1:this.distance>a.distance?1:0}};n.ConvexHull=function(){this.indices=this.points=null;this.getIndices=function(){return this.indices};this.clear=
  249. function(){this.points=this.indices=null};this.ccw=function(a,b,c){a=(this.points[b].x-this.points[a].x)*(this.points[c].y-this.points[a].y)-(this.points[b].y-this.points[a].y)*(this.points[c].x-this.points[a].x);return 1E-5>a?0:a};this.angle=function(a,b){return Math.atan2(this.points[b].y-this.points[a].y,this.points[b].x-this.points[a].x)};this.distance=function(a,b){return(this.points[b].x-this.points[a].x)*(this.points[b].x-this.points[a].x)+(this.points[b].y-this.points[a].y)*(this.points[b].y-
  250. this.points[a].y)};this.compute=function(a){this.indices=null;if(!(3>a.length)){this.points=a;var b=0;for(a=1;a<this.points.length;a++)this.points[a].y==this.points[b].y?this.points[a].x<this.points[b].x&&(b=a):this.points[a].y<this.points[b].y&&(b=a);var c=[],d=0,e=0;for(a=0;a<this.points.length;a++)a!=b&&(d=this.angle(b,a),0>d&&(d+=Math.PI),e=this.distance(b,a),c.push(new n.ConvexHullPoint(a,d,e)));c.sort(function(a,b){return a.compare(b)});d=Array(this.points.length+1);e=2;for(a=0;a<this.points.length;a++)a!=
  251. b&&(d[e]=c[e-2].index,e++);d[0]=d[this.points.length];d[1]=b;c=2;for(a=3;a<=this.points.length;a++){for(;0>=this.ccw(d[c-1],d[c],d[a]);)c--;c++;b=d[a];d[a]=d[c];d[c]=b}this.indices=Array(c);for(a=0;a<c;a++)this.indices[a]=d[a+1]}}};var b=a,c=[];c.push(this);for(var e=0;e<b.length;e++)c.push(b[e]);for(var b=[],f=[],e=0;e<c.length;e++){a=c[e];if(!(a instanceof n))throw"ERROR: don't mix 2D and 3D shapes in hull";for(var h=0;h<a.sides.length;h++){var g=a.sides[h].vertex0.pos.x,k=a.sides[h].vertex0.pos.y;
  252. f[""+g+","+k]||(b.push({x:g,y:k}),f[""+g+","+k]++)}}e=new n.ConvexHull;e.compute(b);if((c=e.getIndices())&&0<c.length){a=[];for(e=0;e<c.length;e++)a.push(b[c[e]]);return n.fromPoints(a)}},check:function(){var a=[];this.isSelfIntersecting(!0)&&a.push("Self intersects");var b={};this.sides.map(function(a){function c(a){a=a.x+" "+a.y;a in b||(b[a]=0);b[a]++}c(a.vertex0.pos);c(a.vertex1.pos)});for(var c in b){var e=b[c];e&1&&a.push("Uneven number of sides ("+e+") for point "+c)}c=this.area();c<1E-5*1E-5&&
  253. a.push("Area is "+c);if(0<a.length){var f="";a.map(function(a){f+=a+"\n"});throw Error(f);}},canonicalized:function(){if(this.isCanonicalized)return this;var a=(new n.fuzzyCAGFactory).getCAG(this);a.isCanonicalized=!0;return a},toCompactBinary:function(){var a=this.canonicalized(),b={},c=[],e=0,f=new Uint32Array(2*a.sides.length),h=0;a.sides.map(function(a){[a.vertex0,a.vertex1].map(function(a){var d=a.getTag(),g;d in b?g=b[d]:(g=e++,b[d]=g,c.push(a));f[h++]=g})});var g=new Float64Array(2*e),k=0;
  254. c.map(function(a){a=a.pos;g[k++]=a._x;g[k++]=a._y});return{"class":"CAG",sideVertexIndices:f,vertexData:g}},getOutlinePaths:function(){var a={},b={};this.canonicalized().sides.map(function(c){var d=c.getTag();a[d]=c;c=c.vertex0.getTag();c in b||(b[c]=[]);b[c].push(d)});for(var d=[];;){var e=null,f;for(f in b){var h=b[f],e=h[0];h.splice(0,1);0===h.length&&delete b[f];break}if(null===e)break;for(var h=[],g=a[e],e=g.vertex0.getTag();;){h.push(g.vertex0.pos);var k=g.vertex1.getTag();if(k==e)break;if(!(k in
  255. b))throw Error("Area is not closed!");var l=b[k],p=-1;if(1==l.length)p=0;else for(var n=null,g=g.direction().angleDegrees(),E=0;E<l.length;E++){var r=a[l[E]].direction().angleDegrees()-g;-180>r&&(r+=360);180<=r&&(r-=360);if(0>p||r>n)p=E,n=r}n=l[p];l.splice(p,1);0===l.length&&delete b[k];g=a[n]}h=new c.Path2D(h,!0);d.push(h)}return d},overCutInsideCorners:function(a){var b=this.canonicalized(),d={};b.sides.map(function(a){a.vertex0.getTag()in d||(d[a.vertex0.getTag()]={pos:a.vertex0.pos,from:[],to:[]});
  256. d[a.vertex0.getTag()].to.push(a.vertex1.pos);a.vertex1.getTag()in d||(d[a.vertex1.getTag()]={pos:a.vertex1.pos,from:[],to:[]});d[a.vertex1.getTag()].from.push(a.vertex0.pos)});var e=[],f;for(f in d){var h=d[f];if(1==h.from.length&&1==h.to.length){var g=h.pos,k=h.to[0],h=g.minus(h.from[0]).unit(),k=k.minus(g).unit();if(.001>h.cross(k)){var l=k.angleRadians()-h.angleRadians()+Math.PI;0>l?l+=2*Math.PI:l>=2*Math.PI&&(l-=2*Math.PI);for(var k=k.minus(h).unit(),p=30/180*Math.PI,h=a/Math.cos(p/2),g=g.plus(k.times(h)),
  257. k=l+k.angleRadians(),l=2*(Math.PI-l),p=2*Math.ceil(l/p/2),G=[g],E=0;E<=p;E++){var r=c.Vector2D.fromAngleRadians(k+E/p*l).times(h).plus(g);G.push(r)}e.push(n.fromPoints(G))}}}return b.subtract(e)}};n.Vertex=function(a){this.pos=a};n.Vertex.prototype={toString:function(){return"("+this.pos.x.toFixed(2)+","+this.pos.y.toFixed(2)+")"},getTag:function(){var a=this.tag;a||(this.tag=a=c.getTag());return a}};n.Side=function(a,b){if(!(a instanceof n.Vertex))throw Error("Assertion failed");if(!(b instanceof
  258. n.Vertex))throw Error("Assertion failed");this.vertex0=a;this.vertex1=b};n.Side._fromFakePolygon=function(a){a.vertices.forEach(function(a){if(!(-1.001<=a.pos.z&&-.999>a.pos.z||.999<=a.pos.z&&1.001>a.pos.z))throw"Assertion failed: _fromFakePolygon expects abs z values of 1";});if(4>a.vertices.length)return null;var b=[];a=a.vertices.filter(function(a,c){if(0<a.pos.z)return b.push(c),!0}).map(function(a){return new c.Vector2D(a.pos.x,a.pos.y)});if(2!=a.length)throw"Assertion failed: _fromFakePolygon: not enough points found";
  259. var d=b[1]-b[0];if(1==d||3==d)1==d&&a.reverse();else throw"Assertion failed: _fromFakePolygon: unknown index ordering";return new n.Side(new n.Vertex(a[0]),new n.Vertex(a[1]))};n.Side.prototype={toString:function(){return this.vertex0+" -> "+this.vertex1},toPolygon3D:function(a,b){var d=[new c.Vertex(this.vertex0.pos.toVector3D(a)),new c.Vertex(this.vertex1.pos.toVector3D(a)),new c.Vertex(this.vertex1.pos.toVector3D(b)),new c.Vertex(this.vertex0.pos.toVector3D(b))];return new c.Polygon(d)},transform:function(a){var b=
  260. this.vertex0.pos.transform(a);a=this.vertex1.pos.transform(a);return new n.Side(new n.Vertex(b),new n.Vertex(a))},flipped:function(){return new n.Side(this.vertex1,this.vertex0)},direction:function(){return this.vertex1.pos.minus(this.vertex0.pos)},getTag:function(){var a=this.tag;a||(this.tag=a=c.getTag());return a},lengthSquared:function(){var a=this.vertex1.pos.x-this.vertex0.pos.x,b=this.vertex1.pos.y-this.vertex0.pos.y;return a*a+b*b},length:function(){return Math.sqrt(this.lengthSquared())}};
  261. n.fuzzyCAGFactory=function(){this.vertexfactory=new c.fuzzyFactory(2,1E-5)};n.fuzzyCAGFactory.prototype={getVertex:function(a){return this.vertexfactory.lookupOrCreate([a.pos._x,a.pos._y],function(b){return a})},getSide:function(a){var b=this.getVertex(a.vertex0);a=this.getVertex(a.vertex1);return new n.Side(b,a)},getCAG:function(a){var b=this;a=a.sides.map(function(a){return b.getSide(a)}).filter(function(a){return 1E-5<a.length()});return n.fromSides(a)}};c.addTransformationMethodsToPrototype(c.prototype);
  262. c.addTransformationMethodsToPrototype(c.Vector2D.prototype);c.addTransformationMethodsToPrototype(c.Vector3D.prototype);c.addTransformationMethodsToPrototype(c.Vertex.prototype);c.addTransformationMethodsToPrototype(c.Plane.prototype);c.addTransformationMethodsToPrototype(c.Polygon.prototype);c.addTransformationMethodsToPrototype(c.Line3D.prototype);c.addTransformationMethodsToPrototype(c.Connector.prototype);c.addTransformationMethodsToPrototype(c.Path2D.prototype);c.addTransformationMethodsToPrototype(c.Line2D.prototype);
  263. c.addTransformationMethodsToPrototype(n.prototype);c.addTransformationMethodsToPrototype(n.Side.prototype);c.addTransformationMethodsToPrototype(c.OrthoNormalBasis.prototype);c.addCenteringToPrototype(c.prototype,["x","y","z"]);c.addCenteringToPrototype(n.prototype,["x","y"]);c.Polygon2D=function(a){this.sides=n.fromPoints(a).sides};c.Polygon2D.prototype=n.prototype;g.CSG=c;g.CAG=n})(this);"undefined"!==typeof module&&(CSG=require(lib+"csg.js").CSG,CAG=require(lib+"csg.js").CAG,Blob=require(lib+"Blob.js").Blob);
  264. (function(g){CSG.prototype.toX3D=function(){var g={},p=[],k={};this.polygons.map(function(a){var b=0,c=0,d=1;a.shared&&a.shared.color&&(b=a.shared.color[0],c=a.shared.color[1],d=a.shared.color[2]);for(var e=[],f=a.vertices.length,h,l=0;l<f;l++)h=a.vertices[l],h.getTag()in k||(p.push(h.pos._x.toString()+" "+h.pos._y.toString()+" "+h.pos._z.toString()),k[h.getTag()]=p.length-1),e.push(k[h.getTag()]);a=e.join(" ");b=b.toString()+" "+c.toString()+" "+d.toString();b in g||(g[b]=[]);g[b].push(a)});var c=
  265. document.implementation.createDocumentType("X3D","ISO//Web3D//DTD X3D 3.1//EN","http://www.web3d.org/specifications/x3d-3.1.dtd"),c=document.implementation.createDocument(null,"X3D",c);c.insertBefore(c.createProcessingInstruction("xml",'version="1.0" encoding="UTF-8"'),c.doctype);var n=c.getElementsByTagName("X3D")[0];n.setAttribute("profile","Interchange");n.setAttribute("version","3.1");n.setAttribute("xsd:noNamespaceSchemaLocation","http://www.web3d.org/specifications/x3d-3.1.xsd");n.setAttribute("xmlns:xsd",
  266. "http://www.w3.org/2001/XMLSchema-instance");var a=c.createElement("Scene");n.appendChild(a);var n=!1,b;for(b in g){var d=g[b],e=c.createElement("Shape");a.appendChild(e);var f=c.createElement("Appearance");e.appendChild(f);var h=c.createElement("Material");f.appendChild(h);h.setAttribute("diffuseColor",b);h.setAttribute("ambientIntensity","1.0");f=c.createElement("IndexedFaceSet");e.appendChild(f);f.setAttribute("solid","true");f.setAttribute("coordIndex",d.join(" -1 ")+" -1");d=c.createElement("Coordinate");
  267. f.appendChild(d);n?d.setAttribute("USE","coords_mesh"):(d.setAttribute("DEF","coords_mesh"),d.setAttribute("point",p.join(" ")),n=!0)}b=(new XMLSerializer).serializeToString(c);return new Blob([b],{type:"model/x3d+xml"})};CSG.prototype.toStlBinary=function(){var g=new ArrayBuffer(4),p=new Int32Array(g,0,1),g=new Int8Array(g,0,4);p[0]=287454020;if(68!=g[0])throw Error("Binary STL output is currently only supported on little-endian (Intel) processors");var k=0;this.polygons.map(function(a){a=a.vertices.length;
  268. k+=3<=a?a-2:0});p=new Uint8Array(80);for(g=0;80>g;g++)p[g]=65;g=new Uint32Array(1);g[0]=k;var c=new ArrayBuffer(50*k),n=new Int8Array(c),a=new ArrayBuffer(50),b=new Int8Array(a),d=new Float32Array(a,0,12),e=new Uint16Array(a,48,1),f=0;this.polygons.map(function(a){for(var c=a.vertices.length,h=0;h<c-2;h++){var g=a.plane.normal;d[0]=g._x;d[1]=g._y;d[2]=g._z;for(var g=3,k=0;3>k;k++){var l=a.vertices[k+(0<k?h:0)].pos;d[g++]=l._x;d[g++]=l._y;d[g++]=l._z}e[0]=0;n.set(b,f);f+=50}});return new Blob([p.buffer,
  269. g.buffer,c],{type:"application/sla"})};CSG.prototype.toStlString=function(){var g="solid csg.js\n";this.polygons.map(function(l){g+=l.toStlString()});g+="endsolid csg.js\n";return new Blob([g],{type:"application/sla"})};CSG.Vector3D.prototype.toStlString=function(){return this._x+" "+this._y+" "+this._z};CSG.Vertex.prototype.toStlString=function(){return"vertex "+this.pos.toStlString()+"\n"};CSG.Polygon.prototype.toStlString=function(){var g="";if(3<=this.vertices.length)for(var p=this.vertices[0].toStlString(),
  270. k=0;k<this.vertices.length-2;k++)g+="facet normal "+this.plane.normal.toStlString()+"\nouter loop\n",g+=p,g+=this.vertices[k+1].toStlString(),g+=this.vertices[k+2].toStlString(),g+="endloop\nendfacet\n";return g};CSG.prototype.toObj=function(){for(var g="# OBJ file\n",p={},k="",c={},n=1,a,b,d,e=1,f,h=0;h<this.polygons.length;h++){f=this.polygons[h];f.shared&&f.shared.color?(a=255*f.shared.color[0],b=255*f.shared.color[1],d=255*f.shared.color[2],f.shared.color[3]&&(e=f.shared.color[3])):e=d=b=a=0;
  271. a=a.toFixed(0)+"-"+b.toFixed(0)+"-"+d.toFixed(0)+"-"+e.toFixed(0);c[a]||(c[a]="");c[a]+="f ";for(b=0;b<this.polygons[h].vertices.length;b++)d=f.vertices[b],d="v "+d.pos._x+" "+d.pos._y+" "+d.pos._z+"\n",p[d]?c[a]+=p[d]+" ":(p[d]=n.toString(),k+=d,c[a]+=n.toString()+" ",n++);c[a]+="\n"}g+=k;for(h in c)g+="g "+h+"\n",g+=c[h];return g};CAG.PathsToDxf=function(g){var l="999\nDXF generated by OpenJsCad\n",l=l+" 0\nSECTION\n 2\nHEADER\n",l=l+" 0\nENDSEC\n",l=l+" 0\nSECTION\n 2\nTABLES\n",l=l+" 0\nTABLE\n 2\nLTYPE\n 70\n1\n",
  272. l=l+" 0\nLTYPE\n 2\nCONTINUOUS\n 3\nSolid Line\n 72\n65\n 73\n0\n 40\n0.0\n",l=l+" 0\nENDTAB\n",l=l+" 0\nTABLE\n 2\nLAYER\n 70\n1\n",l=l+" 0\nLAYER\n 2\nOpenJsCad\n 62\n7\n 6\ncontinuous\n",l=l+" 0\nENDTAB\n",l=l+" 0\nTABLE\n 2\nSTYLE\n 70\n0\n 0\nENDTAB\n",l=l+" 0\nTABLE\n 2\nVIEW\n 70\n0\n 0\nENDTAB\n",l=l+" 0\nENDSEC\n",l=l+" 0\nSECTION\n 2\nBLOCKS\n",l=l+" 0\nENDSEC\n",l=l+" 0\nSECTION\n 2\nENTITIES\n";g.map(function(g){var c=g.points.length+(g.closed?1:0);l+=" 0\nLWPOLYLINE\n 8\nOpenJsCad\n 90\n"+
  273. c+"\n 70\n"+(g.closed?1:0)+"\n";for(var k=0;k<c;k++){var a=k;a>=g.points.length&&(a-=g.points.length);a=g.points[a];l+=" 10\n"+a.x+"\n 20\n"+a.y+"\n 30\n0.0\n"}});l+=" 0\nENDSEC\n 0\nEOF\n";return new Blob([l],{type:"application/dxf"})};CAG.prototype.toDxf=function(){var g=this.getOutlinePaths();return CAG.PathsToDxf(g)};CSG.prototype.toAMFString=function(g){var l='<?xml version="1.0" encoding="UTF-8"?>\n<amf'+(g&&g.unit?' unit="+m.unit"':"")+">\n",k;for(k in g)l+='<metadata type="'+k+'">'+g[k]+
  274. "</metadata>\n";l+='<object id="0">\n<mesh>\n<vertices>\n';this.polygons.map(function(c){for(var a=0;a<c.vertices.length;a++)l+=c.vertices[a].toAMFString()});var l=l+"</vertices>\n",c=0;this.polygons.map(function(g){l+="<volume>\n";if(!(3>g.vertices.length)){var a=1,b=.4,d=1,e=1;g.shared&&g.shared.color?(a=g.shared.color[0],b=g.shared.color[1],d=g.shared.color[2],e=g.shared.color[3]):g.color&&(a=g.color[0],b=g.color[1],d=g.color[2],3<g.color.length()&&(e=g.color[3]));l+="<color><r>"+a+"</r><g>"+b+
  275. "</g><b>"+d+"</b>"+(void 0!==e?"<a>"+e+"</a>":"")+"</color>";for(a=0;a<g.vertices.length-2;a++)l+="<triangle>",l+="<v1>"+c+"</v1>",l+="<v2>"+(c+a+1)+"</v2>",l+="<v3>"+(c+a+2)+"</v3>",l+="</triangle>\n";c+=g.vertices.length;l+="</volume>\n"}});l+="</mesh>\n</object>\n";l+="</amf>\n";return new Blob([l],{type:"application/amf+xml"})};CSG.Vector3D.prototype.toAMFString=function(){return"<x>"+this._x+"</x><y>"+this._y+"</y><z>"+this._z+"</z>"};CSG.Vertex.prototype.toAMFString=function(){return"<vertex><coordinates>"+
  276. this.pos.toAMFString()+"</coordinates></vertex>\n"};g.CSG=CSG;g.CAG=CAG})(this);