From d4904ed298f1d639414621594f1abc826b39b84a Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Tue, 29 Sep 2015 09:39:52 -0600 Subject: [PATCH 1/9] Implements threejs in the viewer, no touch controls implemented yet --- blockscad/OrbitControls.js | 1116 ++++++++++++++ blockscad/blockscad.js | 2 +- blockscad/blockscad_build.py | 6 +- blockscad/blockscad_compressed.js | 1157 ++++++++++++--- blockscad/lightgl.js | 2250 ----------------------------- blockscad/three.min.js | 869 +++++++++++ blockscad/threeViewer.js | 888 ++++++++++++ blockscad/viewer.js | 10 +- blockscad/viewer_compressed.js | 352 +++-- index.html | 1 + index.html~ | 608 ++++++++ 11 files changed, 4661 insertions(+), 2598 deletions(-) create mode 100644 blockscad/OrbitControls.js delete mode 100644 blockscad/lightgl.js create mode 100644 blockscad/three.min.js create mode 100644 blockscad/threeViewer.js create mode 100644 index.html~ diff --git a/blockscad/OrbitControls.js b/blockscad/OrbitControls.js new file mode 100644 index 00000000..d8396519 --- /dev/null +++ b/blockscad/OrbitControls.js @@ -0,0 +1,1116 @@ +/** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + */ +/*global THREE, console */ + +( function () { + + function OrbitConstraint ( object ) { + + this.object = object; + + // "target" sets the location of focus, where the object orbits around + // and where it pans with respect to. + this.target = new THREE.Vector3(); + + // Limits to how far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; + + // Limits to how far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.25; + + //////////// + // internals + + var scope = this; + + var EPS = 0.000001; + + // Current position in spherical coordinate system. + var theta; + var phi; + + // Pending changes + var phiDelta = 0; + var thetaDelta = 0; + var scale = 1; + var panOffset = new THREE.Vector3(); + var zoomChanged = false; + + // API + + this.getPolarAngle = function () { + + return phi; + + }; + + this.getAzimuthalAngle = function () { + + return theta; + + }; + + this.rotateLeft = function ( angle ) { + + thetaDelta -= angle; + + }; + + this.rotateUp = function ( angle ) { + + phiDelta -= angle; + + }; + + // pass in distance in world space to move left + this.panLeft = function() { + + var v = new THREE.Vector3(); + + return function panLeft ( distance ) { + + var te = this.object.matrix.elements; + + // get X column of matrix + v.set( te[ 0 ], te[ 1 ], te[ 2 ] ); + v.multiplyScalar( - distance ); + + panOffset.add( v ); + + }; + + }(); + + // pass in distance in world space to move up + this.panUp = function() { + + var v = new THREE.Vector3(); + + return function panUp ( distance ) { + + var te = this.object.matrix.elements; + + // get Y column of matrix + v.set( te[ 4 ], te[ 5 ], te[ 6 ] ); + v.multiplyScalar( distance ); + + panOffset.add( v ); + + }; + + }(); + + // pass in x,y of change desired in pixel space, + // right and down are positive + this.pan = function ( deltaX, deltaY, screenWidth, screenHeight ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + // perspective + var position = scope.object.position; + var offset = position.clone().sub( scope.target ); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); + + // we actually don't use screenWidth, since perspective camera is fixed to screen height + scope.panLeft( 2 * deltaX * targetDistance / screenHeight ); + scope.panUp( 2 * deltaY * targetDistance / screenHeight ); + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + // orthographic + scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth ); + scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight ); + + } else { + + // camera neither orthographic or perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + + } + + }; + + this.dollyIn = function ( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale /= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + + } + + }; + + this.dollyOut = function ( dollyScale ) { + + if ( scope.object instanceof THREE.PerspectiveCamera ) { + + scale *= dollyScale; + + } else if ( scope.object instanceof THREE.OrthographicCamera ) { + + scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + + } + + }; + + this.update = function() { + + var offset = new THREE.Vector3(); + + // so camera.up is the orbit axis + var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + var quatInverse = quat.clone().inverse(); + + var lastPosition = new THREE.Vector3(); + var lastQuaternion = new THREE.Quaternion(); + + return function () { + + var position = this.object.position; + + offset.copy( position ).sub( this.target ); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion( quat ); + + // angle from z-axis around y-axis + + theta = Math.atan2( offset.x, offset.z ); + + // angle from y-axis + + phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); + + theta += thetaDelta; + phi += phiDelta; + + // restrict theta to be between desired limits + theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) ); + + // restrict phi to be between desired limits + phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); + + // restrict phi to be betwee EPS and PI-EPS + phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); + + var radius = offset.length() * scale; + + // restrict radius to be between desired limits + radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); + + // move target to panned location + this.target.add( panOffset ); + + offset.x = radius * Math.sin( phi ) * Math.sin( theta ); + offset.y = radius * Math.cos( phi ); + offset.z = radius * Math.sin( phi ) * Math.cos( theta ); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion( quatInverse ); + + position.copy( this.target ).add( offset ); + + this.object.lookAt( this.target ); + + if ( this.enableDamping === true ) { + + thetaDelta *= ( 1 - this.dampingFactor ); + phiDelta *= ( 1 - this.dampingFactor ); + + } else { + + thetaDelta = 0; + phiDelta = 0; + + } + + scale = 1; + panOffset.set( 0, 0, 0 ); + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( zoomChanged || + lastPosition.distanceToSquared( this.object.position ) > EPS || + 8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) { + + lastPosition.copy( this.object.position ); + lastQuaternion.copy( this.object.quaternion ); + zoomChanged = false; + + return true; + + } + + return false; + + }; + + }(); + + }; + + + // This set of controls performs orbiting, dollying (zooming), and panning. It maintains + // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is + // supported. + // + // Orbit - left mouse / touch: one finger move + // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish + // Pan - right mouse, or arrow keys / touch: three finter swipe + + THREE.OrbitControls = function ( object, domElement ) { + + var constraint = new OrbitConstraint( object ); + + this.domElement = ( domElement !== undefined ) ? domElement : document; + + // API + + Object.defineProperty( this, 'constraint', { + + get: function() { + + return constraint; + + } + + } ); + + this.getPolarAngle = function () { + + return constraint.getPolarAngle(); + + }; + + this.getAzimuthalAngle = function () { + + return constraint.getAzimuthalAngle(); + + }; + + // Set to false to disable this control + this.enabled = true; + + // center is old, deprecated; use "target" instead + this.center = this.target; + + // This option actually enables dollying in and out; left as "zoom" for + // backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; + + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; + + // Set to false to disable panning + this.enablePan = true; + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // Set to false to disable use of the keys + this.enableKeys = true; + + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // Mouse buttons + this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; + + //////////// + // internals + + var scope = this; + + var rotateStart = new THREE.Vector2(); + var rotateEnd = new THREE.Vector2(); + var rotateDelta = new THREE.Vector2(); + + var panStart = new THREE.Vector2(); + var panEnd = new THREE.Vector2(); + var panDelta = new THREE.Vector2(); + + var dollyStart = new THREE.Vector2(); + var dollyEnd = new THREE.Vector2(); + var dollyDelta = new THREE.Vector2(); + + var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; + + var state = STATE.NONE; + + // for reset + + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // events + + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + // pass in x,y of change desired in pixel space, + // right and down are positive + function pan( deltaX, deltaY ) { + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight ); + + } + + this.update = function () { + + if ( this.autoRotate && state === STATE.NONE ) { + + constraint.rotateLeft( getAutoRotationAngle() ); + + } + + if ( constraint.update() === true ) { + + this.dispatchEvent( changeEvent ); + + } + + }; + + this.reset = function () { + + state = STATE.NONE; + + this.target.copy( this.target0 ); + this.object.position.copy( this.position0 ); + this.object.zoom = this.zoom0; + + this.object.updateProjectionMatrix(); + this.dispatchEvent( changeEvent ); + + this.update(); + + }; + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function onMouseDown( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + if ( event.button === scope.mouseButtons.ORBIT ) { + + if ( scope.enableRotate === false ) return; + + state = STATE.ROTATE; + + rotateStart.set( event.clientX, event.clientY ); + + } else if ( event.button === scope.mouseButtons.ZOOM ) { + + if ( scope.enableZoom === false ) return; + + state = STATE.DOLLY; + + dollyStart.set( event.clientX, event.clientY ); + + } else if ( event.button === scope.mouseButtons.PAN ) { + + if ( scope.enablePan === false ) return; + + state = STATE.PAN; + + panStart.set( event.clientX, event.clientY ); + + } + + if ( state !== STATE.NONE ) { + + document.addEventListener( 'mousemove', onMouseMove, false ); + document.addEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( startEvent ); + + } + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if ( state === STATE.ROTATE ) { + + if ( scope.enableRotate === false ) return; + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + + // rotating up and down along whole screen attempts to go 360, but limited to 180 + constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + } else if ( state === STATE.DOLLY ) { + + if ( scope.enableZoom === false ) return; + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + constraint.dollyIn( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + constraint.dollyOut( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + } else if ( state === STATE.PAN ) { + + if ( scope.enablePan === false ) return; + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + } + + if ( state !== STATE.NONE ) scope.update(); + + } + + function onMouseUp( /* event */ ) { + + if ( scope.enabled === false ) return; + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + scope.dispatchEvent( endEvent ); + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + + if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return; + + event.preventDefault(); + event.stopPropagation(); + + var delta = 0; + + if ( event.wheelDelta !== undefined ) { + + // WebKit / Opera / Explorer 9 + + delta = event.wheelDelta; + + } else if ( event.detail !== undefined ) { + + // Firefox + + delta = - event.detail; + + } + + if ( delta > 0 ) { + + constraint.dollyOut( getZoomScale() ); + + } else if ( delta < 0 ) { + + constraint.dollyIn( getZoomScale() ); + + } + + scope.update(); + scope.dispatchEvent( startEvent ); + scope.dispatchEvent( endEvent ); + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; + + switch ( event.keyCode ) { + + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + scope.update(); + break; + + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + scope.update(); + break; + + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + scope.update(); + break; + + } + + } + + function touchstart( event ) { + + if ( scope.enabled === false ) return; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.enableRotate === false ) return; + + state = STATE.TOUCH_ROTATE; + + rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + case 2: // two-fingered touch: dolly + + if ( scope.enableZoom === false ) return; + + state = STATE.TOUCH_DOLLY; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + break; + + case 3: // three-fingered touch: pan + + if ( scope.enablePan === false ) return; + + state = STATE.TOUCH_PAN; + + panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + break; + + default: + + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent ); + + } + + function touchmove( event ) { + + if ( scope.enabled === false ) return; + + event.preventDefault(); + event.stopPropagation(); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + switch ( event.touches.length ) { + + case 1: // one-fingered touch: rotate + + if ( scope.enableRotate === false ) return; + if ( state !== STATE.TOUCH_ROTATE ) return; + + rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + rotateDelta.subVectors( rotateEnd, rotateStart ); + + // rotating across whole screen goes 360 degrees around + constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); + // rotating up and down along whole screen attempts to go 360, but limited to 180 + constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); + + rotateStart.copy( rotateEnd ); + + scope.update(); + break; + + case 2: // two-fingered touch: dolly + + if ( scope.enableZoom === false ) return; + if ( state !== STATE.TOUCH_DOLLY ) return; + + var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; + var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; + var distance = Math.sqrt( dx * dx + dy * dy ); + + dollyEnd.set( 0, distance ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + constraint.dollyOut( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + constraint.dollyIn( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + + scope.update(); + break; + + case 3: // three-fingered touch: pan + + if ( scope.enablePan === false ) return; + if ( state !== STATE.TOUCH_PAN ) return; + + panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); + panDelta.subVectors( panEnd, panStart ); + + pan( panDelta.x, panDelta.y ); + + panStart.copy( panEnd ); + + scope.update(); + break; + + default: + + state = STATE.NONE; + + } + + } + + function touchend( /* event */ ) { + + if ( scope.enabled === false ) return; + + scope.dispatchEvent( endEvent ); + state = STATE.NONE; + + } + + function contextmenu( event ) { + + event.preventDefault(); + + } + + this.dispose = function() { + + this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); + this.domElement.removeEventListener( 'mousedown', onMouseDown, false ); + this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.removeEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.removeEventListener( 'touchstart', touchstart, false ); + this.domElement.removeEventListener( 'touchend', touchend, false ); + this.domElement.removeEventListener( 'touchmove', touchmove, false ); + + document.removeEventListener( 'mousemove', onMouseMove, false ); + document.removeEventListener( 'mouseup', onMouseUp, false ); + + window.removeEventListener( 'keydown', onKeyDown, false ); + + } + + this.domElement.addEventListener( 'contextmenu', contextmenu, false ); + + this.domElement.addEventListener( 'mousedown', onMouseDown, false ); + this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); + this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox + + this.domElement.addEventListener( 'touchstart', touchstart, false ); + this.domElement.addEventListener( 'touchend', touchend, false ); + this.domElement.addEventListener( 'touchmove', touchmove, false ); + + window.addEventListener( 'keydown', onKeyDown, false ); + + // force an update at start + this.update(); + + }; + + THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); + THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; + + Object.defineProperties( THREE.OrbitControls.prototype, { + + object: { + + get: function () { + + return this.constraint.object; + + } + + }, + + target: { + + get: function () { + + return this.constraint.target; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' ); + this.constraint.target.copy( value ); + + } + + }, + + minDistance : { + + get: function () { + + return this.constraint.minDistance; + + }, + + set: function ( value ) { + + this.constraint.minDistance = value; + + } + + }, + + maxDistance : { + + get: function () { + + return this.constraint.maxDistance; + + }, + + set: function ( value ) { + + this.constraint.maxDistance = value; + + } + + }, + + minZoom : { + + get: function () { + + return this.constraint.minZoom; + + }, + + set: function ( value ) { + + this.constraint.minZoom = value; + + } + + }, + + maxZoom : { + + get: function () { + + return this.constraint.maxZoom; + + }, + + set: function ( value ) { + + this.constraint.maxZoom = value; + + } + + }, + + minPolarAngle : { + + get: function () { + + return this.constraint.minPolarAngle; + + }, + + set: function ( value ) { + + this.constraint.minPolarAngle = value; + + } + + }, + + maxPolarAngle : { + + get: function () { + + return this.constraint.maxPolarAngle; + + }, + + set: function ( value ) { + + this.constraint.maxPolarAngle = value; + + } + + }, + + minAzimuthAngle : { + + get: function () { + + return this.constraint.minAzimuthAngle; + + }, + + set: function ( value ) { + + this.constraint.minAzimuthAngle = value; + + } + + }, + + maxAzimuthAngle : { + + get: function () { + + return this.constraint.maxAzimuthAngle; + + }, + + set: function ( value ) { + + this.constraint.maxAzimuthAngle = value; + + } + + }, + + enableDamping : { + + get: function () { + + return this.constraint.enableDamping; + + }, + + set: function ( value ) { + + this.constraint.enableDamping = value; + + } + + }, + + dampingFactor : { + + get: function () { + + return this.constraint.dampingFactor; + + }, + + set: function ( value ) { + + this.constraint.dampingFactor = value; + + } + + }, + + // backward compatibility + + noZoom: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + return ! this.enableZoom; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); + this.enableZoom = ! value; + + } + + }, + + noRotate: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + return ! this.enableRotate; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); + this.enableRotate = ! value; + + } + + }, + + noPan: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + return ! this.enablePan; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); + this.enablePan = ! value; + + } + + }, + + noKeys: { + + get: function () { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + return ! this.enableKeys; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); + this.enableKeys = ! value; + + } + + }, + + staticMoving : { + + get: function () { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + return ! this.constraint.enableDamping; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); + this.constraint.enableDamping = ! value; + + } + + }, + + dynamicDampingFactor : { + + get: function () { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + return this.constraint.dampingFactor; + + }, + + set: function ( value ) { + + console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); + this.constraint.dampingFactor = value; + + } + + } + + } ); + +}() ); + diff --git a/blockscad/blockscad.js b/blockscad/blockscad.js index 6fcf4b18..caa848b9 100644 --- a/blockscad/blockscad.js +++ b/blockscad/blockscad.js @@ -170,7 +170,7 @@ Blockscad.init = function() { // toggle whether or not we draw the axes, then redraw Blockscad.drawAxes = (Blockscad.drawAxes + 1) % 2; $( '#axesButton' ).toggleClass("btn-pushed"); - gProcessor.viewer.onDraw(); + gProcessor.viewer.toggleAxes(); }); // can I bind a click to a tab? diff --git a/blockscad/blockscad_build.py b/blockscad/blockscad_build.py index cdf12e4c..34d0d73b 100755 --- a/blockscad/blockscad_build.py +++ b/blockscad/blockscad_build.py @@ -56,7 +56,7 @@ def gen_blockscad(self): # Read in all the source files. filenames = ['storage.js','utils.js','blockscad.js', 'FileSaver.js', - 'text.js','lightgl.js','toolbox.js','deflate.js', 'stl.js'] + 'text.js','three.min.js','OrbitControls.js','toolbox.js','deflate.js', 'stl.js'] for filename in filenames: f = open(filename) print filename @@ -79,7 +79,7 @@ def gen_viewer(self): ] # Read in all the source files. - filenames = ['viewer.js', 'csg.js', 'formats.js'] + filenames = ['threeViewer.js', 'csg.js', 'formats.js'] for filename in filenames: f = open(filename) print filename @@ -165,4 +165,4 @@ def file_lookup(name): n = int(name[6:]) return filenames[n] if __name__ == '__main__': - Gen_compressed('').start() \ No newline at end of file + Gen_compressed('').start() diff --git a/blockscad/blockscad_compressed.js b/blockscad/blockscad_compressed.js index f6d24c95..9ec4fc70 100644 --- a/blockscad/blockscad_compressed.js +++ b/blockscad/blockscad_compressed.js @@ -1,143 +1,976 @@ // Do not edit this file; automatically generated by blockscad_build.py. "use strict"; var BlocklyStorage=BlocklyStorage||{},Blockscad=Blockscad||{};Blockscad.Auth=Blockscad.Auth||{};var Blockly=Blockly||{};Blockly.Xml=Blockly.Xml||{}; -BlocklyStorage.backupBlocks_=function(){console.log("in backupBlocks");if("localStorage"in window){localStorage.clear();for(var a=Blockly.Xml.workspaceToDom(Blockscad.workspace),d=window.location.href.split("#")[0],e=d+"proj_name",h=d+"current_project",m=Blockscad.workspace.getAllBlocks(),k=0;kBlockscad.csg_commands[l].length){var n=Base64.toBase64(RawDeflate.deflate(Base64.utob(Blockscad.csg_commands[l]))); -window.localStorage.setItem(r,n);window.localStorage.setItem(w,Blockscad.csg_center[l])}}}window.localStorage.setItem(d,Blockly.Xml.domToText(a));window.localStorage.setItem(e,$("#project-name").val());window.localStorage.setItem(h,Blockscad.Auth.current_project)}};BlocklyStorage.backupOnUnload=function(){window.addEventListener("unload",BlocklyStorage.backupBlocks_,!1)}; -BlocklyStorage.restoreBlocks=function(){var a=window.location.href.split("#")[0],d=a+"proj_name",e=a+"current_project";console.log(window.localStorage);if("localStorage"in window&&window.localStorage[a]){var h=Blockly.Xml.textToDom(window.localStorage[a]);Blockly.Xml.domToWorkspace(Blockscad.workspace,h);for(var h=Blockscad.workspace.getAllBlocks(),m=0;mBlockscad.csg_commands[f].length){var l=Base64.toBase64(RawDeflate.deflate(Base64.utob(Blockscad.csg_commands[f]))); +window.localStorage.setItem(h,l);window.localStorage.setItem(k,Blockscad.csg_center[f])}}}window.localStorage.setItem(b,Blockly.Xml.domToText(a));window.localStorage.setItem(c,$("#project-name").val());window.localStorage.setItem(d,Blockscad.Auth.current_project)}};BlocklyStorage.backupOnUnload=function(){window.addEventListener("unload",BlocklyStorage.backupBlocks_,!1)}; +BlocklyStorage.restoreBlocks=function(){var a=window.location.href.split("#")[0],b=a+"proj_name",c=a+"current_project";console.log(window.localStorage);if("localStorage"in window&&window.localStorage[a]){var d=Blockly.Xml.textToDom(window.localStorage[a]);Blockly.Xml.domToWorkspace(Blockscad.workspace,d);for(var d=Blockscad.workspace.getAllBlocks(),e=0;ee[0]?1:a[0]screen.availWidth&&a.setAttribute("content","width=725, initial-scale=.35, user-scalable=no")}; +BSUtils.init=function(){var a=BSUtils.isRtl();document.head.parentElement.setAttribute("dir",a?"rtl":"ltr");document.head.parentElement.setAttribute("lang",BSUtils.LANG);for(var a=[],b,c=0;cb[0]?1:a[0]screen.availWidth&&a.setAttribute("content","width=725, initial-scale=.35, user-scalable=no")}; BSUtils.initReadonly=function(){Blockly.inject(document.getElementById("blockly"),{path:"./",readOnly:!0,rtl:BSUtils.isRtl(),scrollbars:!1});var a=BSUtils.getStringParamFromUrl("xml",""),a=Blockly.Xml.textToDom(""+a+"");Blockly.Xml.domToWorkspace(Blockly.mainWorkspace,a)}; -BSUtils.loadBlocks=function(a){try{var d=window.sessionStorage.loadOnceBlocks}catch(e){d=null}"BlocklyStorage"in window&&1=d.length?"?lang="+a:d.match(/[?&]lang=[^&]*/)?d.replace(/([?&]lang=)[^&]*/,"$1"+a):d.replace(/\?/,"?lang="+a+"&");window.location=window.location.protocol+"//"+ -window.location.host+window.location.pathname+d};BSUtils.isDialogVisible_=!1;BSUtils.dialogOrigin_=null;BSUtils.dialogDispose_=null; -BSUtils.showDialog=function(a,d,e,h,m,k){function l(){BSUtils.isDialogVisible_&&(r.style.visibility="visible",r.style.zIndex=1,w.style.visibility="hidden")}BSUtils.isDialogVisible_&&BSUtils.hideDialog(!1);BSUtils.isDialogVisible_=!0;BSUtils.dialogOrigin_=d;BSUtils.dialogDispose_=k;var r=document.getElementById("dialog");k=document.getElementById("dialogShadow");var w=document.getElementById("dialogBorder"),n;for(n in m)r.style[n]=m[n];h&&(k.style.visibility="visible",k.style.opacity=.3,h=document.createElement("div"), -h.id="dialogHeader",r.appendChild(h),BSUtils.dialogMouseDownWrapper_=Blockly.bindEvent_(h,"mousedown",null,BSUtils.dialogMouseDown_));r.appendChild(a);a.className=a.className.replace("dialogHiddenContent","");e&&d?(BSUtils.matchBorder_(d,!1,.2),BSUtils.matchBorder_(r,!0,.8),window.setTimeout(l,175)):l()};BSUtils.dialogStartX_=0;BSUtils.dialogStartY_=0; -BSUtils.dialogMouseDown_=function(a){BSUtils.dialogUnbindDragEvents_();if(!Blockly.isRightButton(a)){var d=document.getElementById("dialog");BSUtils.dialogStartX_=d.offsetLeft-a.clientX;BSUtils.dialogStartY_=d.offsetTop-a.clientY;BSUtils.dialogMouseUpWrapper_=Blockly.bindEvent_(document,"mouseup",null,BSUtils.dialogUnbindDragEvents_);BSUtils.dialogMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",null,BSUtils.dialogMouseMove_);a.stopPropagation()}}; -BSUtils.dialogMouseMove_=function(a){var d=document.getElementById("dialog"),e=BSUtils.dialogStartX_+a.clientX;a=BSUtils.dialogStartY_+a.clientY;a=Math.max(a,0);a=Math.min(a,window.innerHeight-d.offsetHeight);e=Math.max(e,0);e=Math.min(e,window.innerWidth-d.offsetWidth);d.style.left=e+"px";d.style.top=a+"px"}; +BSUtils.loadBlocks=function(a){try{var b=window.sessionStorage.loadOnceBlocks}catch(c){b=null}"BlocklyStorage"in window&&1=b.length?"?lang="+a:b.match(/[?&]lang=[^&]*/)?b.replace(/([?&]lang=)[^&]*/,"$1"+a):b.replace(/\?/,"?lang="+a+"&");window.location=window.location.protocol+"//"+ +window.location.host+window.location.pathname+b};BSUtils.isDialogVisible_=!1;BSUtils.dialogOrigin_=null;BSUtils.dialogDispose_=null; +BSUtils.showDialog=function(a,b,c,d,e,g){function f(){BSUtils.isDialogVisible_&&(h.style.visibility="visible",h.style.zIndex=1,k.style.visibility="hidden")}BSUtils.isDialogVisible_&&BSUtils.hideDialog(!1);BSUtils.isDialogVisible_=!0;BSUtils.dialogOrigin_=b;BSUtils.dialogDispose_=g;var h=document.getElementById("dialog");g=document.getElementById("dialogShadow");var k=document.getElementById("dialogBorder"),l;for(l in e)h.style[l]=e[l];d&&(g.style.visibility="visible",g.style.opacity=.3,d=document.createElement("div"), +d.id="dialogHeader",h.appendChild(d),BSUtils.dialogMouseDownWrapper_=Blockly.bindEvent_(d,"mousedown",null,BSUtils.dialogMouseDown_));h.appendChild(a);a.className=a.className.replace("dialogHiddenContent","");c&&b?(BSUtils.matchBorder_(b,!1,.2),BSUtils.matchBorder_(h,!0,.8),window.setTimeout(f,175)):f()};BSUtils.dialogStartX_=0;BSUtils.dialogStartY_=0; +BSUtils.dialogMouseDown_=function(a){BSUtils.dialogUnbindDragEvents_();if(!Blockly.isRightButton(a)){var b=document.getElementById("dialog");BSUtils.dialogStartX_=b.offsetLeft-a.clientX;BSUtils.dialogStartY_=b.offsetTop-a.clientY;BSUtils.dialogMouseUpWrapper_=Blockly.bindEvent_(document,"mouseup",null,BSUtils.dialogUnbindDragEvents_);BSUtils.dialogMouseMoveWrapper_=Blockly.bindEvent_(document,"mousemove",null,BSUtils.dialogMouseMove_);a.stopPropagation()}}; +BSUtils.dialogMouseMove_=function(a){var b=document.getElementById("dialog"),c=BSUtils.dialogStartX_+a.clientX;a=BSUtils.dialogStartY_+a.clientY;a=Math.max(a,0);a=Math.min(a,window.innerHeight-b.offsetHeight);c=Math.max(c,0);c=Math.min(c,window.innerWidth-b.offsetWidth);b.style.left=c+"px";b.style.top=a+"px"}; BSUtils.dialogUnbindDragEvents_=function(){BSUtils.dialogMouseUpWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseUpWrapper_),BSUtils.dialogMouseUpWrapper_=null);BSUtils.dialogMouseMoveWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseMoveWrapper_),BSUtils.dialogMouseMoveWrapper_=null)}; -BSUtils.hideDialog=function(a){function d(){h.style.visibility="hidden";m.style.visibility="hidden"}if(BSUtils.isDialogVisible_){BSUtils.dialogUnbindDragEvents_();BSUtils.dialogMouseDownWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseDownWrapper_),BSUtils.dialogMouseDownWrapper_=null);BSUtils.isDialogVisible_=!1;BSUtils.dialogDispose_&&BSUtils.dialogDispose_();BSUtils.dialogDispose_=null;var e=!1===a?null:BSUtils.dialogOrigin_;a=document.getElementById("dialog");var h=document.getElementById("dialogShadow"), -m=document.getElementById("dialogBorder");h.style.opacity=0;e?(BSUtils.matchBorder_(a,!1,.8),BSUtils.matchBorder_(e,!0,.2),window.setTimeout(d,175)):d();a.style.visibility="hidden";a.style.zIndex=-1;for((e=document.getElementById("dialogHeader"))&&e.parentNode.removeChild(e);a.firstChild;)e=a.firstChild,e.className+=" dialogHiddenContent",document.body.appendChild(e)}}; -BSUtils.matchBorder_=function(a,d,e){function h(){m.style.width=k.width+"px";m.style.height=k.height+"px";m.style.left=k.x+"px";m.style.top=k.y+"px";m.style.opacity=e}if(a){var m=document.getElementById("dialogBorder"),k=BSUtils.getBBox_(a);d?(m.className="dialogAnimate",window.setTimeout(h,1)):(m.className="",h());m.style.visibility="visible"}}; -BSUtils.getBBox_=function(a){var d=a.offsetHeight,e=a.offsetWidth,h=0,m=0;do h+=a.offsetLeft,m+=a.offsetTop,a=a.offsetParent;while(a);return{height:d,width:e,x:h,y:m}}; -BSUtils.storageAlert=function(a){var d=document.getElementById("containerStorage");d.textContent="";a=a.split("\n");for(var e=0;e$("#main").height()-$(".resizableDiv").height()&&$(".resizableDiv").height($("#main").height()-70);20>$("#main").width()-$(".resizableDiv").width()&&$(".resizableDiv").width($("#main").width()- +BSUtils.hideDialog=function(a){function b(){d.style.visibility="hidden";e.style.visibility="hidden"}if(BSUtils.isDialogVisible_){BSUtils.dialogUnbindDragEvents_();BSUtils.dialogMouseDownWrapper_&&(Blockly.unbindEvent_(BSUtils.dialogMouseDownWrapper_),BSUtils.dialogMouseDownWrapper_=null);BSUtils.isDialogVisible_=!1;BSUtils.dialogDispose_&&BSUtils.dialogDispose_();BSUtils.dialogDispose_=null;var c=!1===a?null:BSUtils.dialogOrigin_;a=document.getElementById("dialog");var d=document.getElementById("dialogShadow"), +e=document.getElementById("dialogBorder");d.style.opacity=0;c?(BSUtils.matchBorder_(a,!1,.8),BSUtils.matchBorder_(c,!0,.2),window.setTimeout(b,175)):b();a.style.visibility="hidden";a.style.zIndex=-1;for((c=document.getElementById("dialogHeader"))&&c.parentNode.removeChild(c);a.firstChild;)c=a.firstChild,c.className+=" dialogHiddenContent",document.body.appendChild(c)}}; +BSUtils.matchBorder_=function(a,b,c){function d(){e.style.width=g.width+"px";e.style.height=g.height+"px";e.style.left=g.x+"px";e.style.top=g.y+"px";e.style.opacity=c}if(a){var e=document.getElementById("dialogBorder"),g=BSUtils.getBBox_(a);b?(e.className="dialogAnimate",window.setTimeout(d,1)):(e.className="",d());e.style.visibility="visible"}}; +BSUtils.getBBox_=function(a){var b=a.offsetHeight,c=a.offsetWidth,d=0,e=0;do d+=a.offsetLeft,e+=a.offsetTop,a=a.offsetParent;while(a);return{height:b,width:c,x:d,y:e}}; +BSUtils.storageAlert=function(a){var b=document.getElementById("containerStorage");b.textContent="";a=a.split("\n");for(var c=0;c$("#main").height()-$(".resizableDiv").height()&&$(".resizableDiv").height($("#main").height()-70);20>$("#main").width()-$(".resizableDiv").width()&&$(".resizableDiv").width($("#main").width()- 20);$(".resizableDiv").position({of:$("#main"),my:"right top",at:"right top",offset:"-12 -55"})},!1);Blockscad.workspace=Blockly.inject(document.getElementById("blocklyDiv"),{media:"blockly/media/",zoom:{enabled:!0,scaleSpeed:1.1,controls:!0},trashcan:!1,toolbox:Blockscad.Toolbox.adv});Blockscad.Toolbox.setColorScheme(Blockscad.Toolbox.colorScheme.one);Blockscad.Toolbox.setCatColors();$("#advancedToolbox").hide();BSUtils.loadBlocks("");"BlocklyStorage"in window&&BlocklyStorage.backupOnUnload();$(".resizableDiv").resizable({handles:"s,w,sw", -resize:function(a,d){var m=$(window).height();gProcessor&&(m=gProcessor.viewerdiv.offsetHeight,gProcessor.viewer.rendered_resize(gProcessor.viewerdiv.offsetWidth,m));20>$("#main").width()-d.size.width&&(d.size.width=$("#main").width()-20);70>$("#main").height()-d.size.height&&(d.size.height=$("#main").height()-70);d.position.left=$(window).width()-(d.size.width+12);d.position.top=55}});Blockly.fireUiEvent(window,"resize");Blockscad.offline||Blockscad.Auth.init();BSUtils.bindClick("trashButton",function(){Blockscad.discard()}); -BSUtils.bindClick("renderButton",Blockscad.doRender);BSUtils.bindClick("undoButton",Blockscad.onUndo);BSUtils.bindClick("redoButton",Blockscad.onRedo);$("#axesButton").click(function(){Blockscad.drawAxes=(Blockscad.drawAxes+1)%2;$("#axesButton").toggleClass("btn-pushed");gProcessor.viewer.onDraw()});$("#displayCode").click(function(){var a=document.getElementById("openScadPre"),d=Blockly.OpenSCAD.workspaceToCode(Blockscad.workspace);a.textContent=d;"function"==typeof prettyPrintOne&&(d=a.innerHTML, -d=prettyPrintOne(d,"js"),a.innerHTML=d);Blockly.fireUiEvent(window,"resize")});$("#renderButton").prop("disabled",!0);$("#throw-it-away").click(Blockscad.clearProject);$("#main").on("click",".new-project",Blockscad.newProject);Blockscad.readStlFile=function(a){var d=a.target.files[0];d?(a=new FileReader,a.onload=function(a){a=importSTL(a.target.result);var e=a[0];(a=a[1])||(a="blah");for(var l=d.name.substr(0,d.name.lastIndexOf("("))||d.name,l=l.substr(0,d.name.lastIndexOf("."))||l,r=l=l.replace(/^\s+|\s+$/g, -""),w=1,n=0;Blockscad.csg_commands[r]&&!n;)e!=Blockscad.csg_commands[r]?(r=l+"_"+w,w++):n=1;Blockscad.csg_commands[r]=e;Blockscad.csg_filename[r]=n?Blockscad.csg_filename[r]+(d.name+":::"):d.name+":::";Blockscad.csg_center[r]=a;Blockscad.currentInterestingBlock?(l=Blockscad.currentInterestingBlock.getField("STL_FILENAME"),e=Blockscad.currentInterestingBlock.getField("STL_BUTTON"),w=Blockscad.currentInterestingBlock.getField("STL_CONTENTS"),l.setText(d.name),l.setVisible(!0),e.setVisible(!1),w.setText(r), -Blockscad.currentInterestingBlock.setCommentText(d.name+"\ncenter:("+a+")"),Blockscad.currentInterestingBlock=null):(r=Blockly.Xml.textToDom(''+d.name+'Browse'+r+""),r=Blockly.Xml.domToBlock(Blockscad.workspace,r.firstChild),e=r.getField("STL_BUTTON"),e.setVisible(!1),r.setCommentText(d.name+"\ncenter:("+ -a+")"),r.render())},a.readAsBinaryString(d),$("#importStl")[0].value="",$("#displayBlocks").click(),$("#renderButton").prop("disabled",!1)):alert("Failed to load file")};$("#file-menu").on("change","#loadLocal",function(d){a(d,!0)});$("#file-menu").on("change","#importLocal",function(d){a(d,!1)});$("#file-menu").on("change","#importStl",function(a){Blockscad.readStlFile(a)});gProcessor=new Blockscad.Processor(document.getElementById("renderDiv"));BSUtils.bindClick("viewReset",Blockscad.resetView); +resize:function(a,b){var e=$(window).height();gProcessor&&(e=gProcessor.viewerdiv.offsetHeight,gProcessor.viewer.rendered_resize(gProcessor.viewerdiv.offsetWidth,e));20>$("#main").width()-b.size.width&&(b.size.width=$("#main").width()-20);70>$("#main").height()-b.size.height&&(b.size.height=$("#main").height()-70);b.position.left=$(window).width()-(b.size.width+12);b.position.top=55}});Blockly.fireUiEvent(window,"resize");Blockscad.offline||Blockscad.Auth.init();BSUtils.bindClick("trashButton",function(){Blockscad.discard()}); +BSUtils.bindClick("renderButton",Blockscad.doRender);BSUtils.bindClick("undoButton",Blockscad.onUndo);BSUtils.bindClick("redoButton",Blockscad.onRedo);$("#axesButton").click(function(){Blockscad.drawAxes=(Blockscad.drawAxes+1)%2;$("#axesButton").toggleClass("btn-pushed");gProcessor.viewer.toggleAxes()});$("#displayCode").click(function(){var a=document.getElementById("openScadPre"),b=Blockly.OpenSCAD.workspaceToCode(Blockscad.workspace);a.textContent=b;"function"==typeof prettyPrintOne&&(b=a.innerHTML, +b=prettyPrintOne(b,"js"),a.innerHTML=b);Blockly.fireUiEvent(window,"resize")});$("#renderButton").prop("disabled",!0);$("#throw-it-away").click(Blockscad.clearProject);$("#main").on("click",".new-project",Blockscad.newProject);Blockscad.readStlFile=function(a){var b=a.target.files[0];b?(a=new FileReader,a.onload=function(a){a=importSTL(a.target.result);var c=a[0];(a=a[1])||(a="blah");for(var f=b.name.substr(0,b.name.lastIndexOf("("))||b.name,f=f.substr(0,b.name.lastIndexOf("."))||f,h=f=f.replace(/^\s+|\s+$/g, +""),k=1,l=0;Blockscad.csg_commands[h]&&!l;)c!=Blockscad.csg_commands[h]?(h=f+"_"+k,k++):l=1;Blockscad.csg_commands[h]=c;Blockscad.csg_filename[h]=l?Blockscad.csg_filename[h]+(b.name+":::"):b.name+":::";Blockscad.csg_center[h]=a;Blockscad.currentInterestingBlock?(f=Blockscad.currentInterestingBlock.getField("STL_FILENAME"),c=Blockscad.currentInterestingBlock.getField("STL_BUTTON"),k=Blockscad.currentInterestingBlock.getField("STL_CONTENTS"),f.setText(b.name),f.setVisible(!0),c.setVisible(!1),k.setText(h), +Blockscad.currentInterestingBlock.setCommentText(b.name+"\ncenter:("+a+")"),Blockscad.currentInterestingBlock=null):(h=Blockly.Xml.textToDom(''+b.name+'Browse'+h+""),h=Blockly.Xml.domToBlock(Blockscad.workspace,h.firstChild),c=h.getField("STL_BUTTON"),c.setVisible(!1),h.setCommentText(b.name+"\ncenter:("+ +a+")"),h.render())},a.readAsBinaryString(b),$("#importStl")[0].value="",$("#displayBlocks").click(),$("#renderButton").prop("disabled",!1)):alert("Failed to load file")};$("#file-menu").on("change","#loadLocal",function(b){a(b,!0)});$("#file-menu").on("change","#importLocal",function(b){a(b,!1)});$("#file-menu").on("change","#importStl",function(a){Blockscad.readStlFile(a)});gProcessor=new Blockscad.Processor(document.getElementById("renderDiv"));BSUtils.bindClick("viewReset",Blockscad.resetView); Blockscad.undo={blockList:[],oldBlockList:[],undoStack:[],redoStack:[],current_xml:null,blockCount:0,yesthis:0,fieldChanging:0,blockIds:[],fieldValues:[],parentIds:[],oldBlockIds:[],oldFieldValues:[],oldParentIds:[],just_did_undo:0};Blockscad.workspace.addUndoListener(Blockscad.workspaceChanged);Blockscad.offline||Blockscad.Auth.checkForUser();$("#help-menu").on("click","#about",function(){$("#about-modal").modal("show")});$("#file-menu").on("click","#saveLocal",Blockscad.saveBlocksLocal);$("#simpleToolbox").on("click", function(){console.log("switching to simple toolbox");$("#simpleToolbox").hide();$("#advancedToolbox").show();Blockscad.workspace&&(Blockscad.Toolbox.catIDs=[],Blockscad.workspace.updateToolbox(Blockscad.Toolbox.sim),Blockscad.Toolbox.setCatColors())});$("#advancedToolbox").on("click",function(){console.log("switching to advanced toolbox");$("#advancedToolbox").hide();$("#simpleToolbox").show();Blockscad.workspace&&(Blockscad.Toolbox.catIDs=[],Blockscad.workspace.updateToolbox(Blockscad.Toolbox.adv), Blockscad.Toolbox.setCatColors())});$("#colors_one").on("click",function(){console.log("switching block color scheme");Blockscad.workspace&&(Blockscad.Toolbox.setColorScheme(Blockscad.Toolbox.colorScheme.one),Blockscad.Toolbox.setCatColors(),Blockscad.workspace.clear(),Blockly.Xml.domToWorkspace(Blockscad.workspace,Blockscad.undo.current_xml))});$("#colors_two").on("click",function(){console.log("switching block color scheme");Blockscad.workspace&&(Blockscad.Toolbox.setColorScheme(Blockscad.Toolbox.colorScheme.two), -Blockscad.Toolbox.setCatColors(),Blockscad.workspace.clear(),Blockly.Xml.domToWorkspace(Blockscad.workspace,Blockscad.undo.current_xml))});$(function(){$(".dropdown-menu > li > a.trigger").on("click",function(a){var d=$(this).next(),m=$(this).parent().parent();($(this).hasClass("left-caret")||$(this).hasClass("right-caret"))&&$(this).toggleClass("right-caret left-caret");m.find(".left-caret").not(this).toggleClass("right-caret left-caret");m.find(".sub-menu:visible").not(d).hide();d.toggle();a.stopPropagation()}); +Blockscad.Toolbox.setCatColors(),Blockscad.workspace.clear(),Blockly.Xml.domToWorkspace(Blockscad.workspace,Blockscad.undo.current_xml))});$(function(){$(".dropdown-menu > li > a.trigger").on("click",function(a){var b=$(this).next(),e=$(this).parent().parent();($(this).hasClass("left-caret")||$(this).hasClass("right-caret"))&&$(this).toggleClass("right-caret left-caret");e.find(".left-caret").not(this).toggleClass("right-caret left-caret");e.find(".sub-menu:visible").not(b).hide();b.toggle();a.stopPropagation()}); $(".dropdown-menu > li > a:not(.trigger)").on("click",function(){var a=$(this).closest(".dropdown");a.find(".left-caret").toggleClass("right-caret left-caret");a.find(".sub-menu:visible").hide()})})};document.write(' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + +
+
+
+ +
+
+ + + +
+ +
+
+ + +
+ + +
+
Rendering
+
+
+
+
+ +
+
+ +

+      
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c88b555db42175324af7a2e44001354d79b59c1d Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Tue, 29 Sep 2015 09:40:44 -0600 Subject: [PATCH 2/9] Implements threejs in the viewer, no touch controls implemented yet --- index.html~ | 608 ---------------------------------------------------- 1 file changed, 608 deletions(-) delete mode 100644 index.html~ diff --git a/index.html~ b/index.html~ deleted file mode 100644 index 180e1b36..00000000 --- a/index.html~ +++ /dev/null @@ -1,608 +0,0 @@ - - - - - - - - - BlocksCAD - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- - - - -
-
-
- -
-
- - - -
- -
-
- - -
- - -
-
Rendering
-
-
-
-
- -
-
- -

-      
- -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9389d378c0387643943f985725edcff5a79db679 Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Thu, 1 Oct 2015 09:36:57 -0600 Subject: [PATCH 3/9] touch screen tested, you can pan the viewer using three fingers, cleaned up --- blockscad/threeViewer.js | 96 +------------- blockscad/viewer_compressed.js | 234 ++++++++++++++++----------------- 2 files changed, 116 insertions(+), 214 deletions(-) diff --git a/blockscad/threeViewer.js b/blockscad/threeViewer.js index 203fb4e4..19e77e47 100644 --- a/blockscad/threeViewer.js +++ b/blockscad/threeViewer.js @@ -56,8 +56,6 @@ Blockscad.Viewer = function(containerelement, width, height, initialdepth) { }; - - Blockscad.Viewer.prototype = { setCsg: function(csg) { // if(0&&csg.length) { // preparing multiple CSG's (not union-ed), not yet working @@ -123,92 +121,8 @@ Blockscad.Viewer.prototype = { return !!this.gl; }, - ZOOM_MAX: 1500, - ZOOM_MIN: 5, - onZoomChanged: null, - plate: true, // render plate - setZoom: function(coeff) { //0...1 - //zoom y esas cosas, uso orbit control - }, - - getZoom: function() { - //zoom y esas cosas, uso orbit control - }, - clearShift: function() { - if(this.touch.shiftTimer) { - clearTimeout(this.touch.shiftTimer); - this.touch.shiftTimer = null; - } - return this; - }, - //pan & tilt with one finger - // no se si esto sea necesario usando three orbit control - onPanTilt: function(e) { - this.touch.cur = 'dragging'; - var delta = 0; - if (this.touch.lastY && (e.gesture.direction == 'up' || e.gesture.direction == 'down')) { - //tilt - delta = e.gesture.deltaY - this.touch.lastY; - this.angleX += delta; - } else if (this.touch.lastX && (e.gesture.direction == 'left' || e.gesture.direction == 'right')) { - //pan - delta = e.gesture.deltaX - this.touch.lastX; - this.angleZ += delta; - } - if (delta) - this.onDraw(); - this.touch.lastX = e.gesture.deltaX; - this.touch.lastY = e.gesture.deltaY; - }, - //shift after 0.5s touch&hold - onShift: function(e) { - this.touch.cur = 'shifting'; - var factor = 5e-3; - var delta = 0; - - if (this.touch.lastY && (e.gesture.direction == 'up' || e.gesture.direction == 'down')) { - this.touch.shiftControl - .removeClass('shift-horizontal') - .addClass('shift-vertical') - .css('top', e.gesture.center.pageY + 'px'); - delta = e.gesture.deltaY - this.touch.lastY; - this.viewpointY -= factor * delta * this.viewpointZ; - this.angleX += delta; - } - if (this.touch.lastX && (e.gesture.direction == 'left' || e.gesture.direction == 'right')) { - this.touch.shiftControl - .removeClass('shift-vertical') - .addClass('shift-horizontal') - .css('left', e.gesture.center.pageX + 'px'); - delta = e.gesture.deltaX - this.touch.lastX; - this.viewpointX += factor * delta * this.viewpointZ; - this.angleZ += delta; - } - if (delta) - this.onDraw(); - this.touch.lastX = e.gesture.deltaX; - this.touch.lastY = e.gesture.deltaY; - }, - //zooming - onTransform: function(e) { - this.touch.cur = 'transforming'; - if (this.touch.scale) { - var factor = 1 / (1 + e.gesture.scale - this.touch.scale); - var coeff = this.getZoom(); - coeff *= factor; - this.setZoom( coeff); - } - this.touch.scale = e.gesture.scale; - return this; - }, - onDraw: function(e) { - - if (Blockscad.drawAxes) { - //dibuja o elimina ejes y el plano cuadriculado - - } - }, + toggleAxes:function(e) { if (this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")) { this.scene.remove( this.scene.getObjectByName("axes"));//remove axes @@ -300,14 +214,6 @@ Blockscad.Viewer.csgToThreeMesh = function( csg_model ) { var three_mesh = new THREE.Mesh( three_geometry, material ); return three_mesh; } - - -Blockscad.Viewer.csgToMeshes = function(initial_csg) { - var csg = initial_csg.canonicalized(); - var mesh; - var meshes = [ mesh ]; - return meshes; -}; Blockscad.makeAbsoluteUrl = function(url, baseurl) { // console.log("in makeAbsoluteUrl: ",url + " " + baseurl); if(!url.match(/^[a-z]+\:/i)) { diff --git a/blockscad/viewer_compressed.js b/blockscad/viewer_compressed.js index 2b9a55a0..0a7ef7ec 100644 --- a/blockscad/viewer_compressed.js +++ b/blockscad/viewer_compressed.js @@ -1,44 +1,40 @@ // Do not edit this file; automatically generated by blockscad_build.py. "use strict"; var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{}; -Blockscad.Viewer=function(h,m,k,r){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,m/k,1,1E4);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.shadowMap.enabled=!0;this.renderer.shadowMapSoft=!1;this.renderer.shadowCameraNear=1;this.renderer.shadowCameraFar=this.camera.far;this.renderer.shadowCameraFov=45;this.renderer.shadowMapBias= -.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(m,k);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(1E3);this.GridPlane=this.buildGridPlane(500); -this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,n=function(){requestAnimationFrame(n);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};n()}; -Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(h,m){this.renderer.setSize(h,m);this.camera.aspect=h/m;this.camera.updateProjectionMatrix()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"front"== -h.value?(this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==h.value?(this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==h.value?(this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==h.value?(this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==h.value?(this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.camera.position.set(50, --50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},ZOOM_MAX:1500,ZOOM_MIN:5,onZoomChanged:null,plate:!0,setZoom:function(h){},getZoom:function(){},clearShift:function(){this.touch.shiftTimer&&(clearTimeout(this.touch.shiftTimer),this.touch.shiftTimer=null);return this},onPanTilt:function(h){this.touch.cur="dragging";var m=0;!this.touch.lastY||"up"!=h.gesture.direction&&"down"!=h.gesture.direction?!this.touch.lastX||"left"!=h.gesture.direction&&"right"!=h.gesture.direction|| -(m=h.gesture.deltaX-this.touch.lastX,this.angleZ+=m):(m=h.gesture.deltaY-this.touch.lastY,this.angleX+=m);if(m)this.onDraw();this.touch.lastX=h.gesture.deltaX;this.touch.lastY=h.gesture.deltaY},onShift:function(h){this.touch.cur="shifting";var m=0;!this.touch.lastY||"up"!=h.gesture.direction&&"down"!=h.gesture.direction||(this.touch.shiftControl.removeClass("shift-horizontal").addClass("shift-vertical").css("top",h.gesture.center.pageY+"px"),m=h.gesture.deltaY-this.touch.lastY,this.viewpointY-=.005* -m*this.viewpointZ,this.angleX+=m);!this.touch.lastX||"left"!=h.gesture.direction&&"right"!=h.gesture.direction||(this.touch.shiftControl.removeClass("shift-vertical").addClass("shift-horizontal").css("left",h.gesture.center.pageX+"px"),m=h.gesture.deltaX-this.touch.lastX,this.viewpointX+=.005*m*this.viewpointZ,this.angleZ+=m);if(m)this.onDraw();this.touch.lastX=h.gesture.deltaX;this.touch.lastY=h.gesture.deltaY},onTransform:function(h){this.touch.cur="transforming";if(this.touch.scale){var m=1/(1+ -h.gesture.scale-this.touch.scale),k=this.getZoom();this.setZoom(k*m)}this.touch.scale=h.gesture.scale;return this},onDraw:function(h){},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes),this.scene.add(this.GridPlane))},buildLine:function(h,m,k,r,c){var n=new THREE.Geometry;k=r?new THREE.LineDashedMaterial({linewidth:c, -color:k,dashSize:1,gapSize:1}):new THREE.LineBasicMaterial({linewidth:c,color:k});n.vertices.push(h.clone());n.vertices.push(m.clone());n.computeLineDistances();return new THREE.Line(n,k,THREE.LineSegments)},buildAxes:function(h){var m=new THREE.Object3D;m.name="axes";m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(h,0,0),16711680,!1,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(-h,0,0),16711680,!0,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0, -h,0),65280,!1,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,-h,0),65280,!0,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,h),255,!1,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,-h),255,!0,1));return m},buildGridPlane:function(h){var m=new THREE.Object3D;m.name="GridPlane";h/=2;for(var k=-h;0>k;k++)m.add(this.buildLine(new THREE.Vector3(k,-h,0),new THREE.Vector3(k,h,0),14540253,!1,1)),m.add(this.buildLine(new THREE.Vector3(-h, -k,0),new THREE.Vector3(h,k,0),14540253,!1,1));for(k=1;k<=h;k++)m.add(this.buildLine(new THREE.Vector3(k,-h,0),new THREE.Vector3(k,h,0),14540253,!1,1)),m.add(this.buildLine(new THREE.Vector3(-h,k,0),new THREE.Vector3(h,k,0),14540253,!1,1));for(k=-h;0>k;k+=10)m.add(this.buildLine(new THREE.Vector3(k,-h,0),new THREE.Vector3(k,h,0),12895428,!1,1)),m.add(this.buildLine(new THREE.Vector3(-h,k,0),new THREE.Vector3(h,k,0),12895428,!1,1));for(k=10;k<=h;k+=10)m.add(this.buildLine(new THREE.Vector3(k,-h,0), -new THREE.Vector3(k,h,0),12895428,!1,1)),m.add(this.buildLine(new THREE.Vector3(-h,k,0),new THREE.Vector3(h,k,0),12895428,!1,1));return m}};Blockscad.Viewer.getGeometryVertice=function(h,m){h.vertices.push(new THREE.Vector3(m.x,m.y,m.z));return h.vertices.length-1}; -Blockscad.Viewer.csgToThreeMesh=function(h){var m=h.canonicalized(),k,r,c;h=new THREE.Geometry;var n=m.toPolygons();if(!CSG)throw"CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js";for(m=0;mh;h++)m.add(this.buildLine(new THREE.Vector3(h,-k,0),new THREE.Vector3(h,k,0),14540253,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k,h,0),14540253,!1,1));for(h=1;h<=k;h++)m.add(this.buildLine(new THREE.Vector3(h, +-k,0),new THREE.Vector3(h,k,0),14540253,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k,h,0),14540253,!1,1));for(h=-k;0>h;h+=10)m.add(this.buildLine(new THREE.Vector3(h,-k,0),new THREE.Vector3(h,k,0),12895428,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k,h,0),12895428,!1,1));for(h=10;h<=k;h+=10)m.add(this.buildLine(new THREE.Vector3(h,-k,0),new THREE.Vector3(h,k,0),12895428,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k, +h,0),12895428,!1,1));return m}};Blockscad.Viewer.getGeometryVertice=function(k,m){k.vertices.push(new THREE.Vector3(m.x,m.y,m.z));return k.vertices.length-1}; +Blockscad.Viewer.csgToThreeMesh=function(k){var m=k.canonicalized(),h,r,c;k=new THREE.Geometry;var n=m.toPolygons();if(!CSG)throw"CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js";for(m=0;m

Error: "+k.toString()+"

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(k){h.abort();$("#renderButton").prop("disabled",!1)};this.formatDropdown=document.getElementById("render-type");this.formatDropdown.onchange=function(k){h.currentFormat=h.formatDropdown.options[h.formatDropdown.selectedIndex].value; -h.updateDownloadLink()};this.generateOutputFileButton=document.getElementById("stlButton");this.generateOutputFileButton.onclick=function(k){h.generateOutputFile()};this.enableItems();this.clearViewer()},setCurrentObject:function(h){this.currentObject=h;if(this.viewer){var m=Blockscad.Processor.convertToSolid(h);this.viewer.setCsg(m);h.length&&(this.currentObject=m)}this.hasValidCurrentObject=!0;for($("#stl_buttons").show();0c;){var g=Math.floor((c+f)/2);0

Error: "+h.toString()+"

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(h){k.abort();$("#renderButton").prop("disabled",!1)};this.formatDropdown=document.getElementById("render-type");this.formatDropdown.onchange=function(h){k.currentFormat=k.formatDropdown.options[k.formatDropdown.selectedIndex].value; +k.updateDownloadLink()};this.generateOutputFileButton=document.getElementById("stlButton");this.generateOutputFileButton.onclick=function(h){k.generateOutputFile()};this.enableItems();this.clearViewer()},setCurrentObject:function(k){this.currentObject=k;if(this.viewer){var m=Blockscad.Processor.convertToSolid(k);this.viewer.setCsg(m);k.length&&(this.currentObject=m)}this.hasValidCurrentObject=!0;for($("#stl_buttons").show();0c;){var g=Math.floor((c+f)/2);0b&&(a=e,b=f)}return a},getPolygon:function(){var a=[new c.Vertex(this._a),new c.Vertex(this._b),new c.Vertex(this._c)];return new c.Polygon(a,null,this._halfSpace.getPlane())},toString:function(){return"[a: "+this._a+"/b: "+this._b+"/c: "+this._c+"/halfSpace: "+this._halfSpace+"/points: "+ this._points+"]"}};var g=[];g.push(this);for(var l=0;la[0].x+a[0].y+a[0].z){var d=a[0];a[0]=a[b];a[b]=d}a[b].x+a[b].y+a[b].za.normal.dot(g[2])){var z=g[2];g[2]=g[l];g[l]=z}var z=new f(g[0],g[1],g[2]),C=new f(g[0],g[2],g[1]);a=[z,C];for(l=3;la[0].x+a[0].y+a[0].z){var d=a[0];a[0]=a[b];a[b]=d}a[b].x+a[b].y+a[b].za.normal.dot(g[2])){var z=g[2];g[2]=g[l];g[l]=z}var z=new f(g[0],g[1],g[2]),F=new f(g[0],g[2],g[1]);a=[z,F];for(l=3;lF&&(F+=2*Math.PI);p.push(F);F=Math.atan2(-u,-w);0>F&&(F+=2*Math.PI);p.push(F)}var p=p.sort(m),t=p.length,v,x,h=[],n=[],y=[];for(d=-1;dd?d+t:d],u=Math.sin(F), -w=Math.cos(F),w=k.times(w*a).plus(q.times(u*a)),u=z.plus(w),w=C.plus(w),F=!1,0<=d&&1E-5>u.distanceTo(v)&&(F=!0),F||(0<=d&&(h.push(new c.Vertex(u)),n.push(new c.Vertex(w)),v=[new c.Vertex(x),new c.Vertex(w),new c.Vertex(u),new c.Vertex(v)],v=new c.Polygon(v),y.push(v)),v=u,x=w);n.reverse();y.push(new c.Polygon(h));y.push(new c.Polygon(n));d=c.fromPolygons(y);f=f.unionSub(d,!1,!1)}var r={};e.polygons.map(function(a){a.vertices.map(function(b){var c=b.getTag();c in r?b=r[c]:(b={pos:b.pos,normals:[]}, -r[c]=b);b.normals.push(a.plane.normal)})});for(var B in r){e=r[B];l=e.normals[0].unit();z=null;C=0;for(d=1;dC&&(C=v,z=k);z||(z=l.randomNonParallelVector());d=l.cross(z).unit();z=d.cross(l);d=c.sphere({center:e.pos,radius:a,resolution:b,axes:[l,d,z]});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; +planenormals:[]},g[d]=c);c.planenormals.push(a.plane.normal);d=l;c=f}});for(var l in g){var t=g[l],z=t.v1.pos,F=t.v2.pos;d=F.minus(z).unit();var h=t.planenormals[0].unit(),q=h.cross(d),p=[];for(d=0;dB&&(B+=2*Math.PI);p.push(B);B=Math.atan2(-x,-w);0>B&&(B+=2*Math.PI);p.push(B)}var p=p.sort(m),t=p.length,u,y,k=[],n=[],A=[];for(d=-1;dd?d+t:d],x=Math.sin(B), +w=Math.cos(B),w=h.times(w*a).plus(q.times(x*a)),x=z.plus(w),w=F.plus(w),B=!1,0<=d&&1E-5>x.distanceTo(u)&&(B=!0),B||(0<=d&&(k.push(new c.Vertex(x)),n.push(new c.Vertex(w)),u=[new c.Vertex(y),new c.Vertex(w),new c.Vertex(x),new c.Vertex(u)],u=new c.Polygon(u),A.push(u)),u=x,y=w);n.reverse();A.push(new c.Polygon(k));A.push(new c.Polygon(n));d=c.fromPolygons(A);f=f.unionSub(d,!1,!1)}var r={};e.polygons.map(function(a){a.vertices.map(function(b){var c=b.getTag();c in r?b=r[c]:(b={pos:b.pos,normals:[]}, +r[c]=b);b.normals.push(a.plane.normal)})});for(var D in r){e=r[D];l=e.normals[0].unit();z=null;F=0;for(d=1;dF&&(F=u,z=h);z||(z=l.randomNonParallelVector());d=l.cross(z).unit();z=d.cross(l);d=c.sphere({center:e.pos,radius:a,resolution:b,axes:[l,d,z]});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;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 g=a[f];if(2>g.length)e=e.concat(g);else{var l=[];c.reTesselateCoplanarPolygons(g,l);e=e.concat(l)}}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),b=new c.Vector3D(0,0,0),d=this.polygons,e=d.length,f=0;fa[1].x||b[1].ya[1].y||b[1].z a[1].z?!1:!0},cutByPlane:function(a){if(0===this.polygons.length)return new c;var b=a.normal.times(a.w),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,b,c,e){a=a.getTransformationTo(b,c,e);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},setColor: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,c=0,e=0,f={},g=[],l=0,t={},z=0,k=[],D=[],q={},p=0;a.polygons.map(function(a){a.vertices.map(function(a){++c;var b=a.getTag();b in f||(f[b]=e++,g.push(a))});var b=a.plane.getTag();b in t||(t[b]=l++,k.push(a.plane));b=a.shared.getTag();b in q||(q[b]=p++,D.push(a.shared))});for(var h=new Uint32Array(b),m=new Uint32Array(b),n=new Uint32Array(c),w=new Uint32Array(b),F=new Float64Array(3*e),v=new Float64Array(4*l),x=0,z=0;zw?(n=new c.Connector(m,h.normal,d),m=n.getTransformationTo(g,!1,0),n=g.getTransformationTo(n,!1,0)):(n=new c.Connector(m,h.normal,e),m=n.getTransformationTo(l,!1,0),n=l.getTransformationTo(n,!1,0));var w=a.transform(m),h=-h.normal.dot(f),F=w.getBounds(),w=F[1].z-F[0].z;t||(wk&&(t=!0));t&&(z=new c.Vector3D([-.5*(F[1].x+F[0].x),-.5*(F[1].y+ -F[0].y),-F[0].z]),m=m.multiply(c.Matrix4x4.translation(z)),n=c.Matrix4x4.translation(z.negated()).multiply(n),z=w,k=h,D=m,q=n);t=!1}return[D,q]},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(c){c= +0,0],[0,0,-1],e),t=!0,z=0,h=0,v,q,p;for(p in b){var k=b[p],m=k.normal.times(k.w),n;n=k.normal.cross(d).length();var w=k.normal.cross(e).length();n>w?(n=new c.Connector(m,k.normal,d),m=n.getTransformationTo(g,!1,0),n=g.getTransformationTo(n,!1,0)):(n=new c.Connector(m,k.normal,e),m=n.getTransformationTo(l,!1,0),n=l.getTransformationTo(n,!1,0));var w=a.transform(m),k=-k.normal.dot(f),B=w.getBounds(),w=B[1].z-B[0].z;t||(wh&&(t=!0));t&&(z=new c.Vector3D([-.5*(B[1].x+B[0].x),-.5*(B[1].y+ +B[0].y),-B[0].z]),m=m.multiply(c.Matrix4x4.translation(z)),n=c.Matrix4x4.translation(z.negated()).multiply(n),z=w,h=k,v=m,q=n);t=!1}return[v,q]},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(c){c= c.projectToOrthoNormalBasis(a);0l)throw Error("Assertion failed");t.splice(l,1);0===t.length&&delete b[g];l=q[e].indexOf(g);if(0>l)throw Error("Assertion failed");q[e].splice(l,1);0===q[e].length&&delete q[e];l=p[f].indexOf(g);if(0>l)throw Error("Assertion failed");p[f].splice(l,1);0===p[f].length&&delete p[f]},t=function(a,c,d){var e=a.getTag(),f=c.getTag();if(e==f)throw Error("Assertion failed");var g=e+"/"+f;if(f+"/"+e in b)return m(c,a,null), -null;a={vertex0:a,vertex1:c,polygonindex:d};g in b?b[g].push(a):b[g]=[a];e in q?q[e].push(g):q[e]=[g];f in p?p[f].push(g):p[f]=[g];return g},z=a.polygons.slice(0);for(;;){g=!0;for(h in b)g=!1,f[h]=!0;if(g)break;for(d=!1;;){g=null;for(h in f){g=h;break}if(null===g)break;e=!0;if(g in b){g=b[g];if(0===g.length)throw Error("Assertion failed");for(var g=g[0],n=0;2>n;n++){var u=0===n?g.vertex0:g.vertex1,k=0===n?g.vertex1:g.vertex0,w=u.getTag(),F=k.getTag(),v=[];0===n?w in p&&(v=p[w]):w in q&&(v=q[w]);for(var x= -0;xG&&1E-10>r.plus(y.times(G)).distanceToSquared(B)){d=l.polygonindex;e=z[d];u=l.vertex1.getTag();n=-1;for(w=0;wn)throw Error("Assertion failed");u=e.vertices.slice(0); -u.splice(n,0,k);e=new c.Polygon(u,e.shared);z[d]=e;m(l.vertex0,l.vertex1,d);e=t(l.vertex0,k,d);k=t(k,l.vertex1,d);null!==e&&(f[e]=!0);null!==k&&(f[k]=!0);e=!1;n=2;d=!0;break}}}}}e&&delete f[h]}if(!d)break}g=c.fromPolygons(z);g.properties=a.properties;g.isCanonicalized=!0;g.isRetesselated=!0;a=g}g=!0;for(h in b){g=!1;break}g||OpenJsCad.log("!sidemapisempty");return 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, +h=z.getTag(),v=l+"/"+h,l=h+"/"+l;l in b?(g=b[l],g.splice(-1,1),0===g.length&&delete b[l]):(g={vertex0:g,vertex1:z,polygonindex:d},v in b?b[v].push(g):b[v]=[g]);g=z;l=h}}var q={},p={},f={},g=!0;for(v in b)g=!1,f[v]=!0,b[v].map(function(a){var b=a.vertex0.getTag();a=a.vertex1.getTag();b in q?q[b].push(v):q[b]=[v];a in p?p[a].push(v):p[a]=[v]});if(!g){var k=function(a,c,d){var e=a.getTag(),f=c.getTag(),g=e+"/"+f;if(!(g in b))throw Error("Assertion failed");for(var l=-1,t=b[g],z=0;zl)throw Error("Assertion failed");t.splice(l,1);0===t.length&&delete b[g];l=q[e].indexOf(g);if(0>l)throw Error("Assertion failed");q[e].splice(l,1);0===q[e].length&&delete q[e];l=p[f].indexOf(g);if(0>l)throw Error("Assertion failed");p[f].splice(l,1);0===p[f].length&&delete p[f]},t=function(a,c,d){var e=a.getTag(),f=c.getTag();if(e==f)throw Error("Assertion failed");var g=e+"/"+f;if(f+"/"+e in b)return k(c,a,null), +null;a={vertex0:a,vertex1:c,polygonindex:d};g in b?b[g].push(a):b[g]=[a];e in q?q[e].push(g):q[e]=[g];f in p?p[f].push(g):p[f]=[g];return g},z=a.polygons.slice(0);for(;;){g=!0;for(v in b)g=!1,f[v]=!0;if(g)break;for(d=!1;;){g=null;for(v in f){g=v;break}if(null===g)break;e=!0;if(g in b){g=b[g];if(0===g.length)throw Error("Assertion failed");for(var g=g[0],m=0;2>m;m++){var n=0===m?g.vertex0:g.vertex1,h=0===m?g.vertex1:g.vertex0,w=n.getTag(),B=h.getTag(),u=[];0===m?w in p&&(u=p[w]):w in q&&(u=q[w]);for(var y= +0;yE&&1E-10>r.plus(A.times(E)).distanceToSquared(D)){d=l.polygonindex;e=z[d];n=l.vertex1.getTag();m=-1;for(w=0;wm)throw Error("Assertion failed");n=e.vertices.slice(0); +n.splice(m,0,h);e=new c.Polygon(n,e.shared);z[d]=e;k(l.vertex0,l.vertex1,d);e=t(l.vertex0,h,d);h=t(h,l.vertex1,d);null!==e&&(f[e]=!0);null!==h&&(f[h]=!0);e=!1;m=2;d=!0;break}}}}}e&&delete f[v]}if(!d)break}g=c.fromPolygons(z);g.properties=a.properties;g.isCanonicalized=!0;g.isRetesselated=!0;a=g}g=!0;for(v in b){g=!1;break}g||OpenJsCad.log("!sidemapisempty");return 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,b){return b.map(function(b,c){return b+(0===a?0:a[c])})},0);return 1==b.length?b[0]:b}};c.parseOption=function(a,b,c){a&&b in a&&(c=a[b]);return c};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,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 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."),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,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,"resolution",c.defaultResolution3D),f,g;if(0>=d)throw Error("Radius should be positive");if(5E-4>d)return console.log("Throwing out a zero-radius sphere."),new c;"axes"in a?(f=a.axes[0].unit().times(d),g=a.axes[1].unit().times(d),a=a.axes[2].unit().times(d)):(f=(new c.Vector3D([1,0,0])).times(d),g=(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),l,t=[],k=0;k<=e;k++){var h=2*Math.PI*k/e,h=f.times(Math.cos(h)).plus(g.times(Math.sin(h)));if(0g||0>f)throw Error("Radius should be non-negative");if(0===g&&0===f)throw Error("Either radiusStart or radiusEnd should be nonzero"); -if(5E-4>Math.abs(e.z-d.z))return console.log("throwing out a zero-height cylinder"),new c;var t=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D),k=e.minus(d);a=k.unit();var h=a.randomNonParallelVector().unit(),m=h.cross(a).unit(),q=new c.Vertex(d),p=new c.Vertex(e),n=[];if(0l&&(n.push(new c.Polygon([q,p,b(0,0,f)])),n.push(new c.Polygon([b(0,0,f),p,b(1,0,g)])),n.push(new c.Polygon([q,b(0,1,f),p])),n.push(new c.Polygon([b(0,1,f),b(1,1,g),p])))}t=c.fromPolygons(n);t.properties.cylinder=new c.Properties;t.properties.cylinder.start=new c.Connector(d,a.negated(),h);t.properties.cylinder.end=new c.Connector(e, -a,h);e=d.plus(k.times(.5));g=h.rotate(d,a,-l/2).times((f+g)/2);f=g.cross(a);t.properties.cylinder.facepointH=new c.Connector(e.plus(g),g,a);t.properties.cylinder.facepointH90=new c.Connector(e.plus(f),f,a);return t};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),g;g=Math.abs(f.x)>Math.abs(f.y)?new c.Vector3D(0,1,0):new c.Vector3D(1,0,0);var l=c.parseOptionAs3DVector(a,"normal", -g);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>a&&(a=4);g=[];var t=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),f=k.cross(l).unit().times(e),e=f.cross(k).unit().times(e),h,l=0;l<=a;l++){var m=2*Math.PI*l/a,m=f.times(Math.cos(m)).plus(e.times(Math.sin(m)));if(0e&&(e=4);for(var d=Math.round(e/4),l,t=[],z=0;z<=e;z++){var h=2*Math.PI*z/e,h=f.times(Math.cos(h)).plus(g.times(Math.sin(h)));if(0g||0>f)throw Error("Radius should be non-negative");if(0===g&&0===f)throw Error("Either radiusStart or radiusEnd should be nonzero"); +if(5E-4>Math.abs(e.z-d.z))return console.log("throwing out a zero-height cylinder"),new c;var t=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D),h=e.minus(d);a=h.unit();var k=a.randomNonParallelVector().unit(),v=k.cross(a).unit(),q=new c.Vertex(d),p=new c.Vertex(e),m=[];if(0l&&(m.push(new c.Polygon([q,p,b(0,0,f)])),m.push(new c.Polygon([b(0,0,f),p,b(1,0,g)])),m.push(new c.Polygon([q,b(0,1,f),p])),m.push(new c.Polygon([b(0,1,f),b(1,1,g),p])))}t=c.fromPolygons(m);t.properties.cylinder=new c.Properties;t.properties.cylinder.start=new c.Connector(d,a.negated(),k);t.properties.cylinder.end=new c.Connector(e, +a,k);e=d.plus(h.times(.5));g=k.rotate(d,a,-l/2).times((f+g)/2);f=g.cross(a);t.properties.cylinder.facepointH=new c.Connector(e.plus(g),g,a);t.properties.cylinder.facepointH90=new c.Connector(e.plus(f),f,a);return t};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),g;g=Math.abs(f.x)>Math.abs(f.y)?new c.Vector3D(0,1,0):new c.Vector3D(1,0,0);var l=c.parseOptionAs3DVector(a,"normal", +g);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>a&&(a=4);g=[];var t=Math.floor(.25*a);if(1E-10>f.length())return c.sphere({center:b,radius:e,resolution:a});for(var h=f.unit().times(e),f=h.cross(l).unit().times(e),e=f.cross(h).unit().times(e),k,l=0;l<=a;l++){var m=2*Math.PI*l/a,m=f.times(Math.cos(m)).plus(e.times(Math.sin(m)));if(0e&&(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,resolution:e});e=e.scale(a);1E-5b.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); 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= -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 g=c.Plane.EPSILON,l=this.w,t=!1,k=!1,h=[],m=-g,q=0;qn;h.push(E);n>g&&(t=!0);n=f&&(m=0),k=h[m],E==k?E?g.push(t):d.push(t):(m=this.splitLineBetweenPoints(t.pos, -e[m].pos),m=new c.Vertex(m),E?(g.push(t),g.push(m),d.push(m)):(d.push(t),d.push(m),g.push(m))),E=k;e=c.Plane.EPSILON*c.Plane.EPSILON;if(3<=g.length)for(f=g[g.length-1],l=0;le&&(e=0);return a.plus(c.times(e))},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+ +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 g=c.Plane.EPSILON,l=this.w,t=!1,h=!1,k=[],m=-g,q=0;qp;k.push(n);p>g&&(t=!0);p=f&&(m=0),h=k[m],n==h?n?g.push(t):d.push(t):(m=this.splitLineBetweenPoints(t.pos, +e[m].pos),m=new c.Vertex(m),n?(g.push(t),g.push(m),d.push(m)):(d.push(t),d.push(m),g.push(m))),n=h;e=c.Plane.EPSILON*c.Plane.EPSILON;if(3<=g.length)for(f=g[g.length-1],l=0;le&&(e=0);return a.plus(c.times(e))},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+ "]"},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, this.plane.normal))throw c.Polygon.verticesConvex(this.vertices,this.plane.normal),Error("Not convex!");},setColor:function(a){this.shared=c.Polygon.Shared.fromColor.apply(this,arguments);return this},getSignedVolume:function(){for(var a=0,b=0;bMath.abs(c)?b=new n:0>c&&(b=b.flipped());return b},solidFromSlices:function(a){var b=[],d=null,e=null,f=null,g=null,l=2,t=!1,k,h=null;a&&(t=Boolean(a.loop),a.numslices&&(l=a.numslices),a.callback&&(k=a.callback));if(!k){var m=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?m.translate([0, -0,a]):null}}a=0;for(--l;a<=l;a++)if(d=k.call(this,a/l,a)){if(!(d instanceof c.Polygon))throw Error("CSG.Polygon.solidFromSlices callback error: CSG.Polygon expected");d.checkIfConvex();e?(null===h&&(h=0>e.plane.signedDistanceToPoint(d.vertices[0].pos)),this._addWalls(b,e,d,h)):f=d;e=d}g=d;t?f.vertices.length==g.vertices.length&&f.vertices.every(function(a,b){return a.pos.equals(g.vertices[b].pos)})||this._addWalls(b,g,f,h):(b.unshift(h?f:f.flipped()),b.push(h?g.flipped():g));return c.fromPolygons(b)}, -_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 g=b.length-1,l=e-g,t=0l,h=[],l=Math.abs(l);0m){h[n].len=m;h.index=n;break}}else if(t)for(l=0;lm){h[n].len=m;h.index=n;break}h.sort(r);l=b[0];m=f[0];for(var p,E,A=n=0,u=e+g;n+Aarguments.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= +" "+b.toString()+"\n"});return a},projectToOrthoNormalBasis:function(a){var b=this.vertices.map(function(b){return a.to2D(b.pos)}),b=n.fromPointsNoCheck(b),c=b.area();1E-5>Math.abs(c)?b=new n:0>c&&(b=b.flipped());return b},solidFromSlices:function(a){var b=[],d=null,e=null,f=null,g=null,l=2,t=!1,h,m=null;a&&(t=Boolean(a.loop),a.numslices&&(l=a.numslices),a.callback&&(h=a.callback));if(!h){var k=new c.Polygon.createFromPoints([[0,0,0],[1,0,0],[1,1,0],[0,1,0]]);h=function(a,b){return 0==a||1==a?k.translate([0, +0,a]):null}}a=0;for(--l;a<=l;a++)if(d=h.call(this,a/l,a)){if(!(d instanceof c.Polygon))throw Error("CSG.Polygon.solidFromSlices callback error: CSG.Polygon expected");d.checkIfConvex();e?(null===m&&(m=0>e.plane.signedDistanceToPoint(d.vertices[0].pos)),this._addWalls(b,e,d,m)):f=d;e=d}g=d;t?f.vertices.length==g.vertices.length&&f.vertices.every(function(a,b){return a.pos.equals(g.vertices[b].pos)})||this._addWalls(b,g,f,m):(b.unshift(m?f:f.flipped()),b.push(m?g.flipped():g));return c.fromPolygons(b)}, +_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 g=b.length-1,l=e-g,h=0l,k=[],l=Math.abs(l);0n){k[q].len=n;k.index=q;break}}else if(h)for(l=0;ln){k[q].len=n;k.index=q;break}k.sort(r);l=b[0];n=f[0];for(var p,J,C=q=0,x=e+g;q+Carguments.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= function(a,b,c,e){return 0<=b.minus(a).cross(c.minus(b)).dot(e)};c.Polygon.isStrictlyConvexPoint=function(a,b,c,e){return 1E-5<=b.minus(a).cross(c.minus(b)).dot(e)};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;db)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"); -return this.polygon},getPolygons:function(a){var b=[this],c=[b],e,f,g,l;for(e=0;ek)e.push(this);else if(l<-k)f.push(this);else switch(a=a.splitPolygon(g),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,g; +return this.polygon},getPolygons:function(a){var b=[this],c=[b],e,f,g,l;for(e=0;eh)e.push(this);else if(l<-h)f.push(this);else switch(a=a.splitPolygon(g),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,g; for(c=0;cd;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]- -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],g=this.elements[4],l=this.elements[5],k=this.elements[6],h=this.elements[7],m=this.elements[8],n=this.elements[9],q=this.elements[10],p=this.elements[11],E=this.elements[12],A=this.elements[13],u=this.elements[14],w=this.elements[15],r=a.elements[0],v=a.elements[1],x=a.elements[2],y=a.elements[3],H=a.elements[4],B=a.elements[5],G=a.elements[6],I=a.elements[7], -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 J=[];J[0]=b*r+d*H+e*K+f*O;J[1]=b*v+d*B+e*L+f*P;J[2]=b*x+d*G+e*N+f*Q;J[3]=b*y+d*I+e*M+f*a;J[4]=g*r+l*H+k*K+h*O;J[5]=g*v+l*B+k*L+h*P;J[6]=g*x+l*G+k*N+h*Q;J[7]=g*y+l*I+k*M+h*a;J[8]=m*r+n*H+q*K+p*O;J[9]=m*v+n*B+q*L+p*P;J[10]=m*x+n*G+q*N+p*Q;J[11]=m*y+n*I+q*M+p*a;J[12]=E*r+A*H+u*K+w*O;J[13]=E*v+A*B+u*L+w*P;J[14]=E*x+A*G+u*N+w*Q;J[15]=E*y+A*I+u*M+w*a;return new c.Matrix4x4(J)}, +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],g=this.elements[4],l=this.elements[5],h=this.elements[6],k=this.elements[7],m=this.elements[8],n=this.elements[9],q=this.elements[10],p=this.elements[11],r=this.elements[12],C=this.elements[13],x=this.elements[14],w=this.elements[15],B=a.elements[0],u=a.elements[1],y=a.elements[2],A=a.elements[3],G=a.elements[4],D=a.elements[5],E=a.elements[6],H=a.elements[7], +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*B+d*G+e*K+f*O;I[1]=b*u+d*D+e*L+f*P;I[2]=b*y+d*E+e*N+f*Q;I[3]=b*A+d*H+e*M+f*a;I[4]=g*B+l*G+h*K+k*O;I[5]=g*u+l*D+h*L+k*P;I[6]=g*y+l*E+h*N+k*Q;I[7]=g*A+l*H+h*M+k*a;I[8]=m*B+n*G+q*K+p*O;I[9]=m*u+n*D+q*L+p*P;I[10]=m*y+n*E+q*N+p*Q;I[11]=m*A+n*H+q*M+p*a;I[12]=r*B+C*G+x*K+w*O;I[13]=r*u+C*D+x*L+w*P;I[14]=r*y+C*E+x*N+w*Q;I[15]=r*A+C*H+x*M+w*a;return new c.Matrix4x4(I)}, 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],g=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,g*=b); return new c.Vector3D(a,f,g)},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],g=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,g*=b);return new c.Vector3D(a,f,g)},rightMultiply1x2Vector:function(a){var b= 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], @@ -145,36 +141,36 @@ 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= 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); 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); 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 e=b.y-a.y;0>e&&(c=-c,e=-e);return a.x+(0>=c?0:c>=e?1:1E-10>e?.5:c/e)*(b.x-a.x)};c.reTesselateCoplanarPolygons=function(a,b){var d=a.length;if(0v)v=y;y in C||(C[y]={});C[y][p]=!0}r>=v?(A=[],u=0,w=-1):(r in n||(n[r]=[]),n[r].push(p))}A.reverse();w=u-w-1;l.push(A);h.push(w)}var d=[],G;for(G in C)d.push(G);d.sort(m);D=[];q=[];for(E= -0;E=u&&(v=0);if(A[v].y!=G)break;p=v}y=I-1;0>y&&(y=u-1);A[y].y==G&&(I=y);p!=x.leftvertexindex&&p==I?(D.splice(B,1),--B):(x.leftvertexindex=p,x.rightvertexindex=I,x.topleft=A[p],x.topright=A[I],v=p+1,v>=u&&(v=0),x.bottomleft=A[v],y=I-1,0>y&&(y=u-1),x.bottomright=A[y])}if(E>=d.length-1)D=[],r=null;else{r=Number(d[E+1]);var K= -.5*(G+r),H=n[H],L;for(L in H){p=H[L];A=l[p];u=A.length;for(B=v=h[p];;){x=B+1;x>=u&&(x=0);if(A[x].y!=G)break;if(x==v)break;B=x}for(I=v;;){x=I-1;0>x&&(x=u-1);if(A[x].y!=G)break;if(x==B)break;I=x}v=B+1;v>=u&&(v=0);y=I-1;0>y&&(y=u-1);k(D,{polygonindex:p,leftvertexindex:B,rightvertexindex:I,topleft:A[B],topright:A[I],bottomleft:A[v],bottomright:A[y]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1: -dA&&1E-5>u&&(x.topleft=p.topleft,x.leftline=p.leftline,x.bottomleft=p.bottomleft,w.splice(w.length-1,1))),w.push(x);if(0y.bottomleft.distanceTo(v.topleft)&&1E-5>y.bottomright.distanceTo(v.topright))){r[p]=!0;A=v.leftline.direction().x-y.leftline.direction().x;u=v.rightline.direction().x- -y.rightline.direction().x;H=1E-5>Math.abs(A);u=(B=1E-5>Math.abs(u))||0<=u;(H||0<=A)&&u&&(v.outpolygon=y.outpolygon,v.leftlinecontinues=H,v.rightlinecontinues=B,G[p]=!0);break}for(p=0;p>=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= +t=[],k={},n={},v={},q=1/1E-5*10,p=0;pu)u=A;A in n||(n[A]={});n[A][p]=!0}B>=u?(C=[],x=0,w=-1):(B in k||(k[B]=[]),k[B].push(p))}C.reverse();w=x-w-1;l.push(C);t.push(w)}var d=[],E;for(E in n)d.push(E);d.sort(m);v=[];q=[];for(r= +0;r=x&&(u=0);if(C[u].y!=E)break;p=u}A=H-1;0>A&&(A=x-1);C[A].y==E&&(H=A);p!=y.leftvertexindex&&p==H?(v.splice(D,1),--D):(y.leftvertexindex=p,y.rightvertexindex=H,y.topleft=C[p],y.topright=C[H],u=p+1,u>=x&&(u=0),y.bottomleft=C[u],A=H-1,0>A&&(A=x-1),y.bottomright=C[A])}if(r>=d.length-1)v=[],B=null;else{B=Number(d[r+1]);var K= +.5*(E+B),G=k[G],L;for(L in G){p=G[L];C=l[p];x=C.length;for(D=u=t[p];;){y=D+1;y>=x&&(y=0);if(C[y].y!=E)break;if(y==u)break;D=y}for(H=u;;){y=H-1;0>y&&(y=x-1);if(C[y].y!=E)break;if(y==D)break;H=y}u=D+1;u>=x&&(u=0);A=H-1;0>A&&(A=x-1);h(v,{polygonindex:p,leftvertexindex:D,rightvertexindex:H,topleft:C[D],topright:C[H],bottomleft:C[u],bottomright:C[A]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1: +dC&&1E-5>x&&(y.topleft=p.topleft,y.leftline=p.leftline,y.bottomleft=p.bottomleft,w.splice(w.length-1,1))),w.push(y);if(0A.bottomleft.distanceTo(u.topleft)&&1E-5>A.bottomright.distanceTo(u.topright))){B[p]=!0;C=u.leftline.direction().x-A.leftline.direction().x;x=u.rightline.direction().x- +A.rightline.direction().x;G=1E-5>Math.abs(C);x=(D=1E-5>Math.abs(x))||0<=x;(G||0<=C)&&x&&(u.outpolygon=A.outpolygon,u.leftlinecontinues=G,u.rightlinecontinues=D,E[p]=!0);break}for(p=0;p>=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= 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= [];if(0f.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= 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],g=f;"object"==typeof f&&("transform"in f&&"function"==typeof f.transform?g=f.transform(d):f instanceof Array?(g=[],c.Properties.transformObj(f,g,d)):f instanceof c.Properties&&(g=new c.Properties,c.Properties.transformObj(f,g,d)));b[e]=g}};c.Properties.cloneObj=function(a,b){for(var d in a)if("_transform"!=d&&"_merge"!= d){var e=a[d],f=e;if("object"==typeof e)if(e instanceof Array)for(var f=[],g=0;g=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"; +0,0).rotateZ(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],g=b(a,f);this.connectors_.forEach(function(c,h){e=b(a,c);h||this.closed?d.push.apply(d,g._toWallPolygons({toConnector1:f, +toConnector2:c,cag:e})):d.push.apply(d,e._toPlanePolygons({toConnector:c,flipped:!0}));h!=this.connectors_.length-1||this.closed||d.push.apply(d,e._toPlanePolygons({toConnector:c}));g=e;f=c},this);return c.fromPolygons(d).reTesselated().canonicalized()},verify:function(){for(var a,b,c=0;c=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"; 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&&0a.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, -"startangle",0),f=c.parseOptionAsFloat(a,"endangle",360),g=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 l=[],k,h=Math.abs(f-e);if(1E-5>h)k=c.Vector2D.fromAngle(e/180*Math.PI).times(d),l.push(k.plus(b));else{g=Math.floor(g*h/360)+1;h=.5*g/h;.25k&&(k=0),k>g&&(k=g)),k=c.Vector2D.fromAngle((e+k*(f-e)/g)/180*Math.PI).times(d),l.push(k.plus(b))}return new c.Path2D(l, +"startangle",0),f=c.parseOptionAsFloat(a,"endangle",360),g=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 l=[],h,k=Math.abs(f-e);if(1E-5>k)h=c.Vector2D.fromAngle(e/180*Math.PI).times(d),l.push(h.plus(b));else{g=Math.floor(g*k/360)+1;k=.5*g/k;.25h&&(h=0),h>g&&(h=g)),h=c.Vector2D.fromAngle((e+h*(f-e)/g)/180*Math.PI).times(d),l.push(h.plus(b))}return new c.Path2D(l, !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, -!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&&2k&&(k=e-1);k=new n.Vertex(this.points[k]);l>f&&(g=new n.Side(g,k),c.push(g));g=k}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)}); +!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&&2h&&(h=e-1);h=new n.Vertex(this.points[h]);l>f&&(g=new n.Side(g,h),c.push(g));g=h}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)}); 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, "resolution",c.defaultResolution2D);4>d&&(d=4);var e=[],f=[];f.push(this.points[this.points.length-1]);for(var g=0;ga.length)throw Error("appendBezier: null can only be passed if there is at least one more control point");if("lastBezierControlPoint"in this)l=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"); -l=this.points[this.points.length-2]}l=this.points[this.points.length-1].times(2).minus(l)}else l=new c.Vector2D(l);f.push(l)}for(var k=f.length-1,l=1,g=0;g<=k;++g)0d){var q=m[g-1],p=m[g+1],n=q+1*(p-q)/3,q=q+2*(p-q)/3,p=e(n),r=e(q);l.splice(g,1,p,r);m.splice(g,1,n,q);g--;1>g&&(g=1)}else++g;l=this.points.concat(l.slice(1));e=new c.Path2D(l);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)"); -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 g=c.parseOptionAsFloat(b,"xaxisrotation",0),l=c.parseOptionAsBool(b,"clockwise",!1),k=c.parseOptionAsBool(b,"large",!1),h=this.points[this.points.length-1]; -a=new c.Vector2D(a);var m=!l,l=[];if(0==e||0==f)l.push(a);else{e=Math.abs(e);f=Math.abs(f);var n=g*Math.PI/180,g=Math.cos(n),n=Math.sin(n),q=h.minus(a).times(.5),q=new c.Vector2D(g*q.x+n*q.y,-n*q.x+g*q.y),p=q.x*q.x/(e*e)+q.y*q.y/(f*f);1q&&(q+=2*Math.PI);d=Math.ceil(Math.abs(q)/(2*Math.PI)*d)+1;1>d&&(d=1);for(m=1;m<=d;m++){var r=k+m/d*q,p=Math.cos(r),r=Math.sin(r),p=(new c.Vector2D(g*e*p-n*f*r,n*e*p+g*f*r)).plus(h);l.push(p)}}l=this.points.concat(l);return new c.Path2D(l)}};c.addTransformationMethodsToPrototype=function(a){a.mirrored=function(a){return this.transform(c.Matrix4x4.mirroring(a))};a.mirroredX= +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 g=c.parseOptionAsFloat(b,"xaxisrotation",0),l=c.parseOptionAsBool(b,"clockwise",!1),h=c.parseOptionAsBool(b,"large",!1),k=this.points[this.points.length-1]; +a=new c.Vector2D(a);var m=!l,l=[];if(0==e||0==f)l.push(a);else{e=Math.abs(e);f=Math.abs(f);var n=g*Math.PI/180,g=Math.cos(n),n=Math.sin(n),q=k.minus(a).times(.5),q=new c.Vector2D(g*q.x+n*q.y,-n*q.x+g*q.y),p=q.x*q.x/(e*e)+q.y*q.y/(f*f);1q&&(q+=2*Math.PI);d=Math.ceil(Math.abs(q)/(2*Math.PI)*d)+1;1>d&&(d=1);for(m=1;m<=d;m++){var r=h+m/d*q,p=Math.cos(r),r=Math.sin(r),p=(new c.Vector2D(g*e*p-n*f*r,n*e*p+g*f*r)).plus(k);l.push(p)}}l=this.points.concat(l);return new c.Path2D(l)}};c.addTransformationMethodsToPrototype=function(a){a.mirrored=function(a){return this.transform(c.Matrix4x4.mirroring(a))};a.mirroredX= 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.translate=function(a){return this.transform(c.Matrix4x4.translation(a))};a.scale=function(a){return this.transform(c.Matrix4x4.scaling(a))};a.rotateX=function(a){return this.transform(c.Matrix4x4.rotationX(a))};a.rotateY=function(a){return this.transform(c.Matrix4x4.rotationY(a))}; a.rotateZ=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.translate(b.map(function(b){return-1b)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- @@ -183,7 +179,7 @@ e.x,-b.y,e.y,a.x-d.x,a.y-d.y);if(1E-6a[0]&&1E-5a[1 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."); 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, "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);var f=Math.min(d.x,d.y),e=Math.min(e,f-.1),e=Math.max(0,e);d=new c.Vector2D(d.x-e,d.y-e);b=n.rectangle({center:b,radius:d});0b&&(b=4);var d=[],e={};this.canonicalized().sides.map(function(b){var c=b.vertex1.pos.minus(b.vertex0.pos),g=c.length();if(1E-5c;c++){var g=0=== -c?b.vertex0.pos:b.vertex1.pos,f=0===c?b.vertex1.pos:b.vertex0.pos,k=g.x+" "+g.y;k in e||(e[k]=[]);e[k].push({p1:g,p2:f})}});for(var f in e){var g=e[f],l,k=g[0].p1;if(2==g.length){l=g[1].p2;g=g[0].p2.minus(k).angleDegrees();l=l.minus(k).angleDegrees();l=g+360&&(l-=360);if(lg+359.999)g=0,l=360;if(l>g+1E-5){var m=[];h||m.push(k);var r=Math.round(b*(l-g)/360);1>r&&(r=1);for(var q=0;q<=r;q++){var p=g+q/r*(l-g);q==r&&(p=l);p=k.plus(c.Vector2D.fromAngleDegrees(p).times(a)); -(!h||0=g+360&&(l-=360);if(lg+359.999)g=0,l=360;if(l>g+1E-5){var m=[];k||m.push(h);var v=Math.round(b*(l-g)/360);1>v&&(v=1);for(var q=0;q<=v;q++){var p=g+q/v*(l-g);q==v&&(p=l);p=h.plus(c.Vector2D.fromAngleDegrees(p).times(a)); +(!k||0a)a=1;for(var e=c.Vector3D.Create(0,1,0),f=[],f=f.concat(this._toPlanePolygons({translation:[0,0,0],normalVector:e,flipped:!(0>b.z)})),f=f.concat(this._toPlanePolygons({translation:b, -normalVector:e.rotateZ(d),flipped:0>b.z})),g=0;gb)var h=new c.Connector(a,e.rotateZ(-b),f),g=g.concat(this._toPlanePolygons({toConnector:k,flipped:!0})),g=g.concat(this._toPlanePolygons({toConnector:h}));for(var m=h=b/d;m<=b+1E-5;m+=h)d=new c.Connector(a,e.rotateZ(-m),f),g=g.concat(this._toWallPolygons({toConnector1:k,toConnector2:d})),k=d;return c.fromPolygons(g).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,"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]]),g=n.fromPoints([[.001,1E5],[-2E5,1E5],[-2E5,-1E5],[.001,-1E5]]),k=this.translate([e,0,0]),f=k.subtract(f),g=k.subtract(g),g=0!=f.sides.length?f.mirroredX().union(g):g,g=g.translate([-e,0,0]),k=[],f=0;fa.angle?1:this.distancea.distance?1:0}};ConvexHull=function(){this.indices= +normalVector:e.rotateZ(d),flipped:0>b.z})),g=0;gb)var k=new c.Connector(a,e.rotateZ(-b),f),g=g.concat(this._toPlanePolygons({toConnector:h,flipped:!0})),g=g.concat(this._toPlanePolygons({toConnector:k}));for(var m=k=b/d;m<=b+1E-5;m+=k)d=new c.Connector(a,e.rotateZ(-m),f),g=g.concat(this._toWallPolygons({toConnector1:h,toConnector2:d})),h=d;return c.fromPolygons(g).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,"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]]),g=n.fromPoints([[.001,1E5],[-2E5,1E5],[-2E5,-1E5],[.001,-1E5]]),h=this.translate([e,0,0]),f=h.subtract(f),g=h.subtract(g),g=0!=f.sides.length?f.mirroredX().union(g):g,g=g.translate([-e,0,0]),h=[],f=0;fa.angle?1:this.distancea.distance?1:0}};ConvexHull=function(){this.indices= this.points=null;this.getIndices=function(){return this.indices};this.clear=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-this.points[a].y)};this.compute=function(a){this.indices=null;if(!(3>a.length)){this.points=a;var b=0;for(a=1;ad&&(d+=Math.PI),e=this.distance(b,a),c.push(new 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.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;ap&&(p+=360);180<=p&&(p-=360);if(0>n||p>r)n=q,r=p}r=m[n];m.splice(n,1);0===m.length&&delete b[h];k=a[r]}g=new c.Path2D(g,!0);d.push(g)}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:[]});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 g=d[f];if(1==g.from.length&&1==g.to.length){var k=g.pos,h=g.to[0],g=k.minus(g.from[0]).unit(),h=h.minus(k).unit();if(.001>g.cross(h)){var m=h.angleRadians()-g.angleRadians()+Math.PI;0>m?m+=2*Math.PI:m>=2*Math.PI&&(m-=2*Math.PI);for(var h=h.minus(g).unit(),r=30/180* -Math.PI,g=a/Math.cos(r/2),k=k.plus(h.times(g)),h=m+h.angleRadians(),m=2*(Math.PI-m),r=2*Math.ceil(m/r/2),D=[k],q=0;q<=r;q++){var p=c.Vector2D.fromAngleRadians(h+q/r*m).times(g).plus(k);D.push(p)}e.push(n.fromPoints(D))}}}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"); +d=Array(this.points.length+1);e=2;for(a=0;a=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;ap&&(p+=360);180<=p&&(p-=360);if(0>n||p>r)n=q,r=p}r=m[n];m.splice(n,1);0===m.length&&delete b[k];h=a[r]}g=new c.Path2D(g,!0);d.push(g)}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:[]});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 g=d[f];if(1==g.from.length&&1==g.to.length){var h=g.pos,k=g.to[0],g=h.minus(g.from[0]).unit(),k=k.minus(h).unit();if(.001>g.cross(k)){var m=k.angleRadians()-g.angleRadians()+Math.PI;0>m?m+=2*Math.PI:m>=2*Math.PI&&(m-=2*Math.PI);for(var k=k.minus(g).unit(),r=30/180* +Math.PI,g=a/Math.cos(r/2),h=h.plus(k.times(g)),k=m+k.angleRadians(),m=2*(Math.PI-m),r=2*Math.ceil(m/r/2),v=[h],q=0;q<=r;q++){var p=c.Vector2D.fromAngleRadians(k+q/r*m).times(g).plus(h);v.push(p)}e.push(n.fromPoints(v))}}}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 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 "+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= 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())}}; 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-5h;h++)k[h]=65;h=new Uint32Array(1);h[0]=r;var c=new ArrayBuffer(50*r),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,k=0;km;m++){var r=a.vertices[m+(0= -h.points.length&&(a-=h.points.length);a=h.points[a];k+=" 10\n"+a.x+"\n 20\n"+a.y+"\n 30\n0.0\n"}});k+=" 0\nENDSEC\n 0\nEOF\n";return new Blob([k],{type:"application/dxf"})};CAG.prototype.toDxf=function(){var h=this.getOutlinePaths();return CAG.PathsToDxf(h)};CSG.prototype.toAMFString=function(h){var k='\n\n",r;for(r in h)k+=''+h[r]+"\n";k+='\n\n\n';this.polygons.map(function(c){for(var a= -0;a\n",c=0;this.polygons.map(function(h){k+="\n";if(!(3>h.vertices.length)){var a=1,b=.4,d=1,e=1;h.shared&&h.shared.color?(a=h.shared.color[0],b=h.shared.color[1],d=h.shared.color[2],e=h.shared.color[3]):h.color&&(a=h.color[0],b=h.color[1],d=h.color[2],3"+a+""+b+""+d+""+(void 0!==e?""+e+"":"")+"";for(a=0;a",k+=""+c+"",k+=""+(c+a+1)+"",k+=""+(c+a+2)+"",k+="\n";c+=h.vertices.length;k+="\n"}});k+="\n\n";k+="\n";return new Blob([k],{type:"application/amf+xml"})};CSG.Vector3D.prototype.toAMFString=function(){return""+this._x+""+this._y+""+this._z+""};CSG.Vertex.prototype.toAMFString=function(){return""+this.pos.toAMFString()+"\n"};h.CSG=CSG;h.CAG=CAG})(this); \ No newline at end of file +"http://www.w3.org/2001/XMLSchema-instance");var a=c.createElement("Scene");n.appendChild(a);var n=!1,b;for(b in k){var d=k[b],e=c.createElement("Shape");a.appendChild(e);var f=c.createElement("Appearance");e.appendChild(f);var g=c.createElement("Material");f.appendChild(g);g.setAttribute("diffuseColor",b);g.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"); +f.appendChild(d);n?d.setAttribute("USE","coords_mesh"):(d.setAttribute("DEF","coords_mesh"),d.setAttribute("point",h.join(" ")),n=!0)}b=(new XMLSerializer).serializeToString(c);return new Blob([b],{type:"model/x3d+xml"})};CSG.prototype.toStlBinary=function(){var k=new ArrayBuffer(4),h=new Int32Array(k,0,1),k=new Int8Array(k,0,4);h[0]=287454020;if(68!=k[0])throw Error("Binary STL output is currently only supported on little-endian (Intel) processors");var r=0;this.polygons.map(function(a){a=a.vertices.length; +r+=3<=a?a-2:0});h=new Uint8Array(80);for(k=0;80>k;k++)h[k]=65;k=new Uint32Array(1);k[0]=r;var c=new ArrayBuffer(50*r),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;hm;m++){var r=a.vertices[m+(0= +k.points.length&&(a-=k.points.length);a=k.points[a];h+=" 10\n"+a.x+"\n 20\n"+a.y+"\n 30\n0.0\n"}});h+=" 0\nENDSEC\n 0\nEOF\n";return new Blob([h],{type:"application/dxf"})};CAG.prototype.toDxf=function(){var k=this.getOutlinePaths();return CAG.PathsToDxf(k)};CSG.prototype.toAMFString=function(k){var h='\n\n",r;for(r in k)h+=''+k[r]+"\n";h+='\n\n\n';this.polygons.map(function(c){for(var a= +0;a\n",c=0;this.polygons.map(function(k){h+="\n";if(!(3>k.vertices.length)){var a=1,b=.4,d=1,e=1;k.shared&&k.shared.color?(a=k.shared.color[0],b=k.shared.color[1],d=k.shared.color[2],e=k.shared.color[3]):k.color&&(a=k.color[0],b=k.color[1],d=k.color[2],3"+a+""+b+""+d+""+(void 0!==e?""+e+"":"")+"";for(a=0;a",h+=""+c+"",h+=""+(c+a+1)+"",h+=""+(c+a+2)+"",h+="\n";c+=k.vertices.length;h+="\n"}});h+="\n\n";h+="\n";return new Blob([h],{type:"application/amf+xml"})};CSG.Vector3D.prototype.toAMFString=function(){return""+this._x+""+this._y+""+this._z+""};CSG.Vertex.prototype.toAMFString=function(){return""+this.pos.toAMFString()+"\n"};k.CSG=CSG;k.CAG=CAG})(this); \ No newline at end of file From 212f554e582ba2d4f64c11ec4bd3ce003fe329e9 Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Thu, 1 Oct 2015 11:23:37 -0600 Subject: [PATCH 4/9] added axes labels and z axis hashmarks --- blockscad/threeViewer.js | 29 ++- blockscad/viewer_compressed.js | 346 +++++++++++++++++---------------- 2 files changed, 202 insertions(+), 173 deletions(-) diff --git a/blockscad/threeViewer.js b/blockscad/threeViewer.js index 19e77e47..8e4e1198 100644 --- a/blockscad/threeViewer.js +++ b/blockscad/threeViewer.js @@ -39,7 +39,7 @@ Blockscad.Viewer = function(containerelement, width, height, initialdepth) { this.light.castShadow = true; this.light.position.copy( this.camera.position ); this.scene.add(this.light); - this.axes = this.buildAxes( 1000 ); + this.axes = this.buildAxes( 500 ); this.GridPlane = this.buildGridPlane(500); this.scene.add(this.axes); this.scene.add(this.GridPlane); @@ -146,6 +146,7 @@ Blockscad.Viewer.prototype = { return axis; }, buildAxes: function( length ){ + length=length/2; var axes = new THREE.Object3D(); axes.name ="axes"; axes.add( this.buildLine( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( length, 0, 0 ), 0xFF0000, false,1)); // +X @@ -154,6 +155,20 @@ Blockscad.Viewer.prototype = { axes.add( this.buildLine( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, -length, 0 ), 0x00FF00, true,1)); // -Y axes.add( this.buildLine( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, length ), 0x0000FF, false,1)); // +Z axes.add( this.buildLine( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, -length ), 0x0000FF, true,1)); // -Z + + //draw X character + axes.add(this.buildLine( new THREE.Vector3( -5+length+5, -5, 0 ), new THREE.Vector3(5+length+5, 5, 0 ), 0x000000, false,1)); + axes.add(this.buildLine( new THREE.Vector3( 5+length+5, -5, 0 ), new THREE.Vector3(-5+length+5, 5, 0 ), 0x000000, false,1)); + + //draw Y character + axes.add(this.buildLine( new THREE.Vector3( 0, 0+length, 0 ), new THREE.Vector3(0, 5+length, 0 ), 0x000000, false,1)); + axes.add(this.buildLine( new THREE.Vector3( 0, 5+length, 0 ), new THREE.Vector3(5, 10+length, 0 ), 0x000000, false,1)); + axes.add(this.buildLine( new THREE.Vector3( 0, 5+length, 0 ), new THREE.Vector3(-5, 10+length, 0 ), 0x000000, false,1)); + //draw Z character + axes.add(this.buildLine( new THREE.Vector3( -5, 0, 0+length+5), new THREE.Vector3(5, 0, 0 +length+5), 0x000000, false,1)); + axes.add(this.buildLine( new THREE.Vector3( -5, 0, 0+length +5), new THREE.Vector3(5, 0,10 +length+5), 0x000000, false,1)); + axes.add(this.buildLine( new THREE.Vector3( 5, 0, 10+length +5), new THREE.Vector3(-5, 0, 10+length+5), 0x000000, false,1)); + return axes; }, buildGridPlane: function(size){ @@ -167,19 +182,31 @@ Blockscad.Viewer.prototype = { for(var x=1; x<=size; x++) { GridPlane.add(this.buildLine( new THREE.Vector3( x, -size, 0 ), new THREE.Vector3( x, size, 0 ), 0xDDDDDD, false,1 )); GridPlane.add(this.buildLine( new THREE.Vector3( -size, x, 0 ), new THREE.Vector3( size, x, 0 ), 0xDDDDDD, false,1 )); + //draw hashmarks on z axis + GridPlane.add(this.buildLine( new THREE.Vector3( -0.5, -0.5, x ), new THREE.Vector3( 0.5, 0.5, x ), 0xDDDDDD, false,1 )); + GridPlane.add(this.buildLine( new THREE.Vector3( 0.5, -0.5, x ), new THREE.Vector3( -0.5, 0.5, x ), 0xDDDDDD, false,1 )); } for(var x=-size; x<0; x+=10) { GridPlane.add(this.buildLine( new THREE.Vector3( x, -size, 0 ), new THREE.Vector3( x, size, 0 ), 0xC4C4C4, false,1 )); GridPlane.add(this.buildLine( new THREE.Vector3( -size, x, 0 ), new THREE.Vector3( size, x, 0 ), 0xC4C4C4, false,1 )); + //draw mayor hashmarks on -z axis + GridPlane.add(this.buildLine( new THREE.Vector3( -1, -1, x ), new THREE.Vector3( 1, 1, x ), 0xC4C4C4, false,1 )); + GridPlane.add(this.buildLine( new THREE.Vector3( 1, -1, x ), new THREE.Vector3( -1, 1, x ), 0xC4C4C4, false,1 )); + } for(var x=10; x<=size; x+=10) { GridPlane.add(this.buildLine( new THREE.Vector3( x, -size, 0 ), new THREE.Vector3( x, size, 0 ), 0xC4C4C4, false,1 )); GridPlane.add(this.buildLine( new THREE.Vector3( -size, x, 0 ), new THREE.Vector3( size, x, 0 ), 0xC4C4C4, false,1 )); + //draw mayor hashmarks on z axis + GridPlane.add(this.buildLine( new THREE.Vector3( -1, -1, x ), new THREE.Vector3( 1, 1, x ), 0xC4C4C4, false,1 )); + GridPlane.add(this.buildLine( new THREE.Vector3( 1, -1, x ), new THREE.Vector3( -1, 1, x ), 0xC4C4C4, false,1 )); + } return GridPlane; } }; + Blockscad.Viewer.getGeometryVertice= function( threeGeometry, vertice_position ){ threeGeometry.vertices.push( new THREE.Vector3( vertice_position.x, vertice_position.y, vertice_position.z ) ); return threeGeometry.vertices.length - 1; diff --git a/blockscad/viewer_compressed.js b/blockscad/viewer_compressed.js index 0a7ef7ec..ef08387a 100644 --- a/blockscad/viewer_compressed.js +++ b/blockscad/viewer_compressed.js @@ -1,126 +1,128 @@ // Do not edit this file; automatically generated by blockscad_build.py. "use strict"; var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{}; -Blockscad.Viewer=function(k,m,h,r){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,m/h,1,1E4);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.shadowMap.enabled=!0;this.renderer.shadowMapSoft=!1;this.renderer.shadowCameraNear=1;this.renderer.shadowCameraFar=this.camera.far;this.renderer.shadowCameraFov=45;this.renderer.shadowMapBias= -.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(m,h);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(1E3);this.GridPlane=this.buildGridPlane(500); -this.scene.add(this.axes);this.scene.add(this.GridPlane);$(k).append(this.renderer.domElement);var c=this,n=function(){requestAnimationFrame(n);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};n()}; -Blockscad.Viewer.prototype={setCsg:function(k){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(k);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(k,m){this.renderer.setSize(k,m);this.camera.aspect=k/m;this.camera.updateProjectionMatrix()},viewReset:function(){var k=document.getElementById("viewMenu");"top"==k.value?(this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"front"== -k.value?(this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==k.value?(this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==k.value?(this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==k.value?(this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==k.value?(this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==k.value&&(this.camera.position.set(50, --50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},toggleAxes:function(k){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes),this.scene.add(this.GridPlane))},buildLine:function(k,m,h,r,c){var n=new THREE.Geometry;h=r?new THREE.LineDashedMaterial({linewidth:c,color:h,dashSize:1,gapSize:1}):new THREE.LineBasicMaterial({linewidth:c, -color:h});n.vertices.push(k.clone());n.vertices.push(m.clone());n.computeLineDistances();return new THREE.Line(n,h,THREE.LineSegments)},buildAxes:function(k){var m=new THREE.Object3D;m.name="axes";m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(k,0,0),16711680,!1,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(-k,0,0),16711680,!0,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,k,0),65280,!1,1));m.add(this.buildLine(new THREE.Vector3(0,0,0), -new THREE.Vector3(0,-k,0),65280,!0,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,k),255,!1,1));m.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,-k),255,!0,1));return m},buildGridPlane:function(k){var m=new THREE.Object3D;m.name="GridPlane";k/=2;for(var h=-k;0>h;h++)m.add(this.buildLine(new THREE.Vector3(h,-k,0),new THREE.Vector3(h,k,0),14540253,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k,h,0),14540253,!1,1));for(h=1;h<=k;h++)m.add(this.buildLine(new THREE.Vector3(h, --k,0),new THREE.Vector3(h,k,0),14540253,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k,h,0),14540253,!1,1));for(h=-k;0>h;h+=10)m.add(this.buildLine(new THREE.Vector3(h,-k,0),new THREE.Vector3(h,k,0),12895428,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k,h,0),12895428,!1,1));for(h=10;h<=k;h+=10)m.add(this.buildLine(new THREE.Vector3(h,-k,0),new THREE.Vector3(h,k,0),12895428,!1,1)),m.add(this.buildLine(new THREE.Vector3(-k,h,0),new THREE.Vector3(k, -h,0),12895428,!1,1));return m}};Blockscad.Viewer.getGeometryVertice=function(k,m){k.vertices.push(new THREE.Vector3(m.x,m.y,m.z));return k.vertices.length-1}; -Blockscad.Viewer.csgToThreeMesh=function(k){var m=k.canonicalized(),h,r,c;k=new THREE.Geometry;var n=m.toPolygons();if(!CSG)throw"CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js";for(m=0;m

Error: "+h.toString()+"

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(h){k.abort();$("#renderButton").prop("disabled",!1)};this.formatDropdown=document.getElementById("render-type");this.formatDropdown.onchange=function(h){k.currentFormat=k.formatDropdown.options[k.formatDropdown.selectedIndex].value; -k.updateDownloadLink()};this.generateOutputFileButton=document.getElementById("stlButton");this.generateOutputFileButton.onclick=function(h){k.generateOutputFile()};this.enableItems();this.clearViewer()},setCurrentObject:function(k){this.currentObject=k;if(this.viewer){var m=Blockscad.Processor.convertToSolid(k);this.viewer.setCsg(m);k.length&&(this.currentObject=m)}this.hasValidCurrentObject=!0;for($("#stl_buttons").show();0c;){var g=Math.floor((c+f)/2);0 +f;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),14540253,!1,1));for(f=1;f<=h;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-.5,-.5,f),new THREE.Vector3(.5,.5,f),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(.5, +-.5,f),new THREE.Vector3(-.5,.5,f),14540253,!1,1));for(f=-h;0>f;f+=10)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-1,-1,f),new THREE.Vector3(1,1,f),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(1,-1,f),new THREE.Vector3(-1,1,f),12895428,!1,1));for(f=10;f<=h;f+=10)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f, +h,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-1,-1,f),new THREE.Vector3(1,1,f),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(1,-1,f),new THREE.Vector3(-1,1,f),12895428,!1,1));return l}};Blockscad.Viewer.getGeometryVertice=function(h,l){h.vertices.push(new THREE.Vector3(l.x,l.y,l.z));return h.vertices.length-1}; +Blockscad.Viewer.csgToThreeMesh=function(h){var l=h.canonicalized(),f,t,c;h=new THREE.Geometry;var m=l.toPolygons();if(!CSG)throw"CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js";for(l=0;l

Error: "+f.toString()+"

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(f){h.abort();$("#renderButton").prop("disabled",!1)};this.formatDropdown=document.getElementById("render-type");this.formatDropdown.onchange=function(f){h.currentFormat=h.formatDropdown.options[h.formatDropdown.selectedIndex].value; +h.updateDownloadLink()};this.generateOutputFileButton=document.getElementById("stlButton");this.generateOutputFileButton.onclick=function(f){h.generateOutputFile()};this.enableItems();this.clearViewer()},setCurrentObject:function(h){this.currentObject=h;if(this.viewer){var l=Blockscad.Processor.convertToSolid(h);this.viewer.setCsg(l);h.length&&(this.currentObject=l)}this.hasValidCurrentObject=!0;for($("#stl_buttons").show();0c;){var g=Math.floor((c+k)/2);0b&&(a=e,b=f)}return a},getPolygon:function(){var a=[new c.Vertex(this._a),new c.Vertex(this._b),new c.Vertex(this._c)];return new c.Polygon(a,null,this._halfSpace.getPlane())},toString:function(){return"[a: "+this._a+"/b: "+this._b+"/c: "+this._c+"/halfSpace: "+this._halfSpace+"/points: "+ -this._points+"]"}};var g=[];g.push(this);for(var l=0;la[0].x+a[0].y+a[0].z){var d=a[0];a[0]=a[b];a[b]=d}a[b].x+a[b].y+a[b].za.normal.dot(g[2])){var z=g[2];g[2]=g[l];g[l]=z}var z=new f(g[0],g[1],g[2]),F=new f(g[0],g[2],g[1]);a=[z,F];for(l=3;lB&&(B+=2*Math.PI);p.push(B);B=Math.atan2(-x,-w);0>B&&(B+=2*Math.PI);p.push(B)}var p=p.sort(m),t=p.length,u,y,k=[],n=[],A=[];for(d=-1;dd?d+t:d],x=Math.sin(B), -w=Math.cos(B),w=h.times(w*a).plus(q.times(x*a)),x=z.plus(w),w=F.plus(w),B=!1,0<=d&&1E-5>x.distanceTo(u)&&(B=!0),B||(0<=d&&(k.push(new c.Vertex(x)),n.push(new c.Vertex(w)),u=[new c.Vertex(y),new c.Vertex(w),new c.Vertex(x),new c.Vertex(u)],u=new c.Polygon(u),A.push(u)),u=x,y=w);n.reverse();A.push(new c.Polygon(k));A.push(new c.Polygon(n));d=c.fromPolygons(A);f=f.unionSub(d,!1,!1)}var r={};e.polygons.map(function(a){a.vertices.map(function(b){var c=b.getTag();c in r?b=r[c]:(b={pos:b.pos,normals:[]}, -r[c]=b);b.normals.push(a.plane.normal)})});for(var D in r){e=r[D];l=e.normals[0].unit();z=null;F=0;for(d=1;dF&&(F=u,z=h);z||(z=l.randomNonParallelVector());d=l.cross(z).unit();z=d.cross(l);d=c.sphere({center:e.pos,radius:a,resolution:b,axes:[l,d,z]});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;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 g=a[f];if(2>g.length)e=e.concat(g);else{var l=[];c.reTesselateCoplanarPolygons(g,l);e=e.concat(l)}}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),b=new c.Vector3D(0,0,0),d=this.polygons,e=d.length,f=0;fa[1].x||b[1].ya[1].y||b[1].z -a[1].z?!1:!0},cutByPlane:function(a){if(0===this.polygons.length)return new c;var b=a.normal.times(a.w),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)); +b){var c;c=b?new d(a,b):a;this._data.push(c)},putp:function(a,b){var c;c=b?new d(a,b):a;for(var e=0,k=this._data.length;eb&&(a=e,b=k)}return a},getPolygon:function(){var a=[new c.Vertex(this._a),new c.Vertex(this._b),new c.Vertex(this._c)];return new c.Polygon(a,null,this._halfSpace.getPlane())},toString:function(){return"[a: "+this._a+"/b: "+this._b+"/c: "+this._c+"/halfSpace: "+this._halfSpace+"/points: "+ +this._points+"]"}};var g=[];g.push(this);for(var n=0;na[0].x+a[0].y+a[0].z){var d=a[0];a[0]=a[b];a[b]=d}a[b].x+a[b].y+a[b].za.normal.dot(g[2])){var C=g[2];g[2]=g[n];g[n]=C}var C=new k(g[0],g[1],g[2]),f=new k(g[0],g[2],g[1]);a=[C,f];for(n=3;nA&&(A+=2*Math.PI);r.push(A);A=Math.atan2(-u,-w);0>A&&(A+=2*Math.PI);r.push(A)}var r=r.sort(l),z=r.length,v,x,h=[],m=[],y=[];for(d=-1;dd?d+z:d],u=Math.sin(A), +w=Math.cos(A),w=q.times(w*a).plus(p.times(u*a)),u=C.plus(w),w=f.plus(w),A=!1,0<=d&&1E-5>u.distanceTo(v)&&(A=!0),A||(0<=d&&(h.push(new c.Vertex(u)),m.push(new c.Vertex(w)),v=[new c.Vertex(x),new c.Vertex(w),new c.Vertex(u),new c.Vertex(v)],v=new c.Polygon(v),y.push(v)),v=u,x=w);m.reverse();y.push(new c.Polygon(h));y.push(new c.Polygon(m));d=c.fromPolygons(y);k=k.unionSub(d,!1,!1)}var t={};e.polygons.map(function(a){a.vertices.map(function(b){var c=b.getTag();c in t?b=t[c]:(b={pos:b.pos,normals:[]}, +t[c]=b);b.normals.push(a.plane.normal)})});for(var D in t){e=t[D];n=e.normals[0].unit();C=null;f=0;for(d=1;df&&(f=v,C=q);C||(C=n.randomNonParallelVector());d=n.cross(C).unit();C=d.cross(n);d=c.sphere({center:e.pos,radius:a,resolution:b,axes:[n,d,C]});k=k.unionSub(d,!1,!1)}return k},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;var a={},b=this.isCanonicalized,d=new c.fuzzyCSGFactory;this.polygons.map(function(c){var e=c.plane,k=c.shared;b||(e=d.getPlane(e),k=d.getPolygonShared(k));e=e.getTag()+"/"+k.getTag();e in a?a[e].push(c):a[e]=[c]});var e=[],k;for(k in a){var g=a[k];if(2>g.length)e=e.concat(g);else{var n=[];c.reTesselateCoplanarPolygons(g,n);e=e.concat(n)}}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),b=new c.Vector3D(0,0,0),d=this.polygons,e=d.length,k=0;ka[1].x||b[1].ya[1].y||b[1].z +a[1].z?!1:!0},cutByPlane:function(a){if(0===this.polygons.length)return new c;var b=a.normal.times(a.w),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=[],k=new c.OrthoNormalBasis(a);e.push(new c.Vertex(k.to3D(new c.Vector2D(d,-d))));e.push(new c.Vertex(k.to3D(new c.Vector2D(-d,-d))));e.push(new c.Vertex(k.to3D(new c.Vector2D(-d,d))));e.push(new c.Vertex(k.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,b,c,e){a=a.getTransformationTo(b,c,e);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},setColor: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,c=0,e=0,f={},g=[],l=0,t={},z=0,h=[],v=[],q={},p=0;a.polygons.map(function(a){a.vertices.map(function(a){++c;var b=a.getTag();b in f||(f[b]=e++,g.push(a))});var b=a.plane.getTag();b in t||(t[b]=l++,h.push(a.plane));b=a.shared.getTag();b in q||(q[b]=p++,v.push(a.shared))});for(var k=new Uint32Array(b),m=new Uint32Array(b),n=new Uint32Array(c),w=new Uint32Array(b),B=new Float64Array(3*e),u=new Float64Array(4*l),y=0,z=0;zw?(n=new c.Connector(m,k.normal,d),m=n.getTransformationTo(g,!1,0),n=g.getTransformationTo(n,!1,0)):(n=new c.Connector(m,k.normal,e),m=n.getTransformationTo(l,!1,0),n=l.getTransformationTo(n,!1,0));var w=a.transform(m),k=-k.normal.dot(f),B=w.getBounds(),w=B[1].z-B[0].z;t||(wh&&(t=!0));t&&(z=new c.Vector3D([-.5*(B[1].x+B[0].x),-.5*(B[1].y+ -B[0].y),-B[0].z]),m=m.multiply(c.Matrix4x4.translation(z)),n=c.Matrix4x4.translation(z.negated()).multiply(n),z=w,h=k,v=m,q=n);t=!1}return[v,q]},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(c){c= -c.projectToOrthoNormalBasis(a);0l)throw Error("Assertion failed");t.splice(l,1);0===t.length&&delete b[g];l=q[e].indexOf(g);if(0>l)throw Error("Assertion failed");q[e].splice(l,1);0===q[e].length&&delete q[e];l=p[f].indexOf(g);if(0>l)throw Error("Assertion failed");p[f].splice(l,1);0===p[f].length&&delete p[f]},t=function(a,c,d){var e=a.getTag(),f=c.getTag();if(e==f)throw Error("Assertion failed");var g=e+"/"+f;if(f+"/"+e in b)return k(c,a,null), -null;a={vertex0:a,vertex1:c,polygonindex:d};g in b?b[g].push(a):b[g]=[a];e in q?q[e].push(g):q[e]=[g];f in p?p[f].push(g):p[f]=[g];return g},z=a.polygons.slice(0);for(;;){g=!0;for(v in b)g=!1,f[v]=!0;if(g)break;for(d=!1;;){g=null;for(v in f){g=v;break}if(null===g)break;e=!0;if(g in b){g=b[g];if(0===g.length)throw Error("Assertion failed");for(var g=g[0],m=0;2>m;m++){var n=0===m?g.vertex0:g.vertex1,h=0===m?g.vertex1:g.vertex0,w=n.getTag(),B=h.getTag(),u=[];0===m?w in p&&(u=p[w]):w in q&&(u=q[w]);for(var y= -0;yE&&1E-10>r.plus(A.times(E)).distanceToSquared(D)){d=l.polygonindex;e=z[d];n=l.vertex1.getTag();m=-1;for(w=0;wm)throw Error("Assertion failed");n=e.vertices.slice(0); -n.splice(m,0,h);e=new c.Polygon(n,e.shared);z[d]=e;k(l.vertex0,l.vertex1,d);e=t(l.vertex0,h,d);h=t(h,l.vertex1,d);null!==e&&(f[e]=!0);null!==h&&(f[h]=!0);e=!1;m=2;d=!0;break}}}}}e&&delete f[v]}if(!d)break}g=c.fromPolygons(z);g.properties=a.properties;g.isCanonicalized=!0;g.isRetesselated=!0;a=g}g=!0;for(v in b){g=!1;break}g||OpenJsCad.log("!sidemapisempty");return 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, +this.canonicalized(),b=a.polygons.length,c=0,e=0,k={},g=[],n=0,z={},f=0,G=[],q=[],p={},r=0;a.polygons.map(function(a){a.vertices.map(function(a){++c;var b=a.getTag();b in k||(k[b]=e++,g.push(a))});var b=a.plane.getTag();b in z||(z[b]=n++,G.push(a.plane));b=a.shared.getTag();b in p||(p[b]=r++,q.push(a.shared))});for(var h=new Uint32Array(b),l=new Uint32Array(b),m=new Uint32Array(c),w=new Uint32Array(b),A=new Float64Array(3*e),v=new Float64Array(4*n),x=0,f=0;fw?(m=new c.Connector(l,h.normal,d),l=m.getTransformationTo(g,!1,0),m=g.getTransformationTo(m,!1,0)):(m=new c.Connector(l,h.normal,e),l=m.getTransformationTo(n,!1,0),m=n.getTransformationTo(m,!1,0));var w=a.transform(l),h=-h.normal.dot(k),A=w.getBounds(),w=A[1].z-A[0].z;z||(wG&&(z=!0));z&&(f=new c.Vector3D([-.5*(A[1].x+A[0].x),-.5*(A[1].y+ +A[0].y),-A[0].z]),l=l.multiply(c.Matrix4x4.translation(f)),m=c.Matrix4x4.translation(f.negated()).multiply(m),f=w,G=h,q=l,p=m);z=!1}return[q,p]},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(c){c= +c.projectToOrthoNormalBasis(a);0n)throw Error("Assertion failed");z.splice(n,1);0===z.length&&delete b[g];n=p[e].indexOf(g);if(0>n)throw Error("Assertion failed");p[e].splice(n,1);0===p[e].length&&delete p[e];n=r[k].indexOf(g);if(0>n)throw Error("Assertion failed");r[k].splice(n,1);0===r[k].length&&delete r[k]},z=function(a,c,d){var e=a.getTag(),k=c.getTag();if(e==k)throw Error("Assertion failed");var g=e+"/"+k;if(k+"/"+e in b)return l(c,a,null), +null;a={vertex0:a,vertex1:c,polygonindex:d};g in b?b[g].push(a):b[g]=[a];e in p?p[e].push(g):p[e]=[g];k in r?r[k].push(g):r[k]=[g];return g},f=a.polygons.slice(0);for(;;){g=!0;for(q in b)g=!1,k[q]=!0;if(g)break;for(d=!1;;){g=null;for(q in k){g=q;break}if(null===g)break;e=!0;if(g in b){g=b[g];if(0===g.length)throw Error("Assertion failed");for(var g=g[0],m=0;2>m;m++){var u=0===m?g.vertex0:g.vertex1,h=0===m?g.vertex1:g.vertex0,w=u.getTag(),A=h.getTag(),v=[];0===m?w in r&&(v=r[w]):w in p&&(v=p[w]);for(var x= +0;xE&&1E-10>t.plus(y.times(E)).distanceToSquared(D)){d=n.polygonindex;e=f[d];u=n.vertex1.getTag();m=-1;for(w=0;wm)throw Error("Assertion failed");u=e.vertices.slice(0); +u.splice(m,0,h);e=new c.Polygon(u,e.shared);f[d]=e;l(n.vertex0,n.vertex1,d);e=z(n.vertex0,h,d);h=z(h,n.vertex1,d);null!==e&&(k[e]=!0);null!==h&&(k[h]=!0);e=!1;m=2;d=!0;break}}}}}e&&delete k[q]}if(!d)break}g=c.fromPolygons(f);g.properties=a.properties;g.isCanonicalized=!0;g.isRetesselated=!0;a=g}g=!0;for(q in b){g=!1;break}g||OpenJsCad.log("!sidemapisempty");return 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,b){return b.map(function(b,c){return b+(0===a?0:a[c])})},0);return 1==b.length?b[0]:b}};c.parseOption=function(a,b,c){a&&b in a&&(c=a[b]);return c};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,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 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."),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,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,"resolution",c.defaultResolution3D),f,g;if(0>=d)throw Error("Radius should be positive");if(5E-4>d)return console.log("Throwing out a zero-radius sphere."),new c;"axes"in a?(f=a.axes[0].unit().times(d),g=a.axes[1].unit().times(d),a=a.axes[2].unit().times(d)):(f=(new c.Vector3D([1,0,0])).times(d),g=(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),l,t=[],z=0;z<=e;z++){var h=2*Math.PI*z/e,h=f.times(Math.cos(h)).plus(g.times(Math.sin(h)));if(0g||0>f)throw Error("Radius should be non-negative");if(0===g&&0===f)throw Error("Either radiusStart or radiusEnd should be nonzero"); -if(5E-4>Math.abs(e.z-d.z))return console.log("throwing out a zero-height cylinder"),new c;var t=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D),h=e.minus(d);a=h.unit();var k=a.randomNonParallelVector().unit(),v=k.cross(a).unit(),q=new c.Vertex(d),p=new c.Vertex(e),m=[];if(0l&&(m.push(new c.Polygon([q,p,b(0,0,f)])),m.push(new c.Polygon([b(0,0,f),p,b(1,0,g)])),m.push(new c.Polygon([q,b(0,1,f),p])),m.push(new c.Polygon([b(0,1,f),b(1,1,g),p])))}t=c.fromPolygons(m);t.properties.cylinder=new c.Properties;t.properties.cylinder.start=new c.Connector(d,a.negated(),k);t.properties.cylinder.end=new c.Connector(e, -a,k);e=d.plus(h.times(.5));g=k.rotate(d,a,-l/2).times((f+g)/2);f=g.cross(a);t.properties.cylinder.facepointH=new c.Connector(e.plus(g),g,a);t.properties.cylinder.facepointH90=new c.Connector(e.plus(f),f,a);return t};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),g;g=Math.abs(f.x)>Math.abs(f.y)?new c.Vector3D(0,1,0):new c.Vector3D(1,0,0);var l=c.parseOptionAs3DVector(a,"normal", -g);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>a&&(a=4);g=[];var t=Math.floor(.25*a);if(1E-10>f.length())return c.sphere({center:b,radius:e,resolution:a});for(var h=f.unit().times(e),f=h.cross(l).unit().times(e),e=f.cross(h).unit().times(e),k,l=0;l<=a;l++){var m=2*Math.PI*l/a,m=f.times(Math.cos(m)).plus(e.times(Math.sin(m)));if(0=d)throw Error("Radius should be positive");if(5E-4>d)return console.log("Throwing out a zero-radius sphere."),new c;"axes"in a?(k=a.axes[0].unit().times(d),g=a.axes[1].unit().times(d),a=a.axes[2].unit().times(d)):(k=(new c.Vector3D([1,0,0])).times(d),g=(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),n,z=[],f=0;f<=e;f++){var h=2*Math.PI*f/e,h=k.times(Math.cos(h)).plus(g.times(Math.sin(h)));if(0g||0>k)throw Error("Radius should be non-negative");if(0===g&&0===k)throw Error("Either radiusStart or radiusEnd should be nonzero"); +if(5E-4>Math.abs(e.z-d.z))return console.log("throwing out a zero-height cylinder"),new c;var f=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D),C=e.minus(d);a=C.unit();var h=a.randomNonParallelVector().unit(),q=h.cross(a).unit(),p=new c.Vertex(d),r=new c.Vertex(e),l=[];if(0n&&(l.push(new c.Polygon([p,r,b(0,0,k)])),l.push(new c.Polygon([b(0,0,k),r,b(1,0,g)])),l.push(new c.Polygon([p,b(0,1,k),r])),l.push(new c.Polygon([b(0,1,k),b(1,1,g),r])))}f=c.fromPolygons(l);f.properties.cylinder=new c.Properties;f.properties.cylinder.start=new c.Connector(d,a.negated(),h);f.properties.cylinder.end=new c.Connector(e, +a,h);e=d.plus(C.times(.5));g=h.rotate(d,a,-n/2).times((k+g)/2);k=g.cross(a);f.properties.cylinder.facepointH=new c.Connector(e.plus(g),g,a);f.properties.cylinder.facepointH90=new c.Connector(e.plus(k),k,a);return f};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),k=d.minus(b),g;g=Math.abs(k.x)>Math.abs(k.y)?new c.Vector3D(0,1,0):new c.Vector3D(1,0,0);var n=c.parseOptionAs3DVector(a,"normal", +g);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>a&&(a=4);g=[];var f=Math.floor(.25*a);if(1E-10>k.length())return c.sphere({center:b,radius:e,resolution:a});for(var h=k.unit().times(e),k=h.cross(n).unit().times(e),e=k.cross(h).unit().times(e),l,n=0;n<=a;n++){var q=2*Math.PI*n/a,q=k.times(Math.cos(q)).plus(e.times(Math.sin(q)));if(0e&&(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,resolution:e});e=e.scale(a);1E-5k.x||0>k.y||0>k.z)throw"roundradius <= radius!";e=c.sphere({radius:1,resolution:e});e=e.scale(a);1E-5a.length||3a.length||3b.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); -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= -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 g=c.Plane.EPSILON,l=this.w,t=!1,h=!1,k=[],m=-g,q=0;qp;k.push(n);p>g&&(t=!0);p=f&&(m=0),h=k[m],n==h?n?g.push(t):d.push(t):(m=this.splitLineBetweenPoints(t.pos, -e[m].pos),m=new c.Vertex(m),n?(g.push(t),g.push(m),d.push(m)):(d.push(t),d.push(m),g.push(m))),n=h;e=c.Plane.EPSILON*c.Plane.EPSILON;if(3<=g.length)for(f=g[g.length-1],l=0;le&&(e=0);return a.plus(c.times(e))},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+ +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),k=this.normal.cross(e),d=this.normal.times(this.w),e=d.plus(e),k=d.plus(k),d=d.multiply4x4(a),e= +e.multiply4x4(a),k=k.multiply4x4(a);a=c.Plane.fromVector3Ds(d,e,k);b&&(a=a.flipped());return a},splitPolygon:function(a){var b={type:null,front:null,back:null},d=this.normal,e=a.vertices,k=e.length;if(a.plane.equals(this))b.type=0;else{for(var g=c.Plane.EPSILON,n=this.w,f=!1,h=!1,l=[],q=-g,p=0;pr;l.push(m);r>g&&(f=!0);r=k&&(q=0),h=l[q],m==h?m?g.push(f):d.push(f):(q=this.splitLineBetweenPoints(f.pos, +e[q].pos),q=new c.Vertex(q),m?(g.push(f),g.push(q),d.push(q)):(d.push(f),d.push(q),g.push(q))),m=h;e=c.Plane.EPSILON*c.Plane.EPSILON;if(3<=g.length)for(k=g[g.length-1],n=0;ne&&(e=0);return a.plus(c.times(e))},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+ "]"},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, this.plane.normal))throw c.Polygon.verticesConvex(this.vertices,this.plane.normal),Error("Not convex!");},setColor:function(a){this.shared=c.Polygon.Shared.fromColor.apply(this,arguments);return this},getSignedVolume:function(){for(var a=0,b=0;bMath.abs(c)?b=new n:0>c&&(b=b.flipped());return b},solidFromSlices:function(a){var b=[],d=null,e=null,f=null,g=null,l=2,t=!1,h,m=null;a&&(t=Boolean(a.loop),a.numslices&&(l=a.numslices),a.callback&&(h=a.callback));if(!h){var k=new c.Polygon.createFromPoints([[0,0,0],[1,0,0],[1,1,0],[0,1,0]]);h=function(a,b){return 0==a||1==a?k.translate([0, -0,a]):null}}a=0;for(--l;a<=l;a++)if(d=h.call(this,a/l,a)){if(!(d instanceof c.Polygon))throw Error("CSG.Polygon.solidFromSlices callback error: CSG.Polygon expected");d.checkIfConvex();e?(null===m&&(m=0>e.plane.signedDistanceToPoint(d.vertices[0].pos)),this._addWalls(b,e,d,m)):f=d;e=d}g=d;t?f.vertices.length==g.vertices.length&&f.vertices.every(function(a,b){return a.pos.equals(g.vertices[b].pos)})||this._addWalls(b,g,f,m):(b.unshift(m?f:f.flipped()),b.push(m?g.flipped():g));return c.fromPolygons(b)}, -_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 g=b.length-1,l=e-g,h=0l,k=[],l=Math.abs(l);0n){k[q].len=n;k.index=q;break}}else if(h)for(l=0;ln){k[q].len=n;k.index=q;break}k.sort(r);l=b[0];n=f[0];for(var p,J,C=q=0,x=e+g;q+Carguments.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= +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;0Math.abs(c)?b=new m:0>c&&(b=b.flipped());return b},solidFromSlices:function(a){var b=[],d=null,e=null,k=null,g=null,n=2,f=!1,h,l=null;a&&(f=Boolean(a.loop),a.numslices&&(n=a.numslices),a.callback&&(h=a.callback));if(!h){var q=new c.Polygon.createFromPoints([[0,0,0],[1,0,0],[1,1,0],[0,1,0]]);h=function(a,b){return 0==a||1==a?q.translate([0, +0,a]):null}}a=0;for(--n;a<=n;a++)if(d=h.call(this,a/n,a)){if(!(d instanceof c.Polygon))throw Error("CSG.Polygon.solidFromSlices callback error: CSG.Polygon expected");d.checkIfConvex();e?(null===l&&(l=0>e.plane.signedDistanceToPoint(d.vertices[0].pos)),this._addWalls(b,e,d,l)):k=d;e=d}g=d;f?k.vertices.length==g.vertices.length&&k.vertices.every(function(a,b){return a.pos.equals(g.vertices[b].pos)})||this._addWalls(b,g,k,l):(b.unshift(l?k:k.flipped()),b.push(l?g.flipped():g));return c.fromPolygons(b)}, +_addWalls:function(a,b,d,e){b=b.vertices.slice(0);var k=d.vertices.slice(0);d=d.shared||null;b[0].pos.equals(b[b.length-1].pos)||b.push(b[0]);k[0].pos.equals(k[k.length-1].pos)||k.push(k[0]);e&&(b=b.reverse(),k=k.reverse());e=k.length-1;for(var g=b.length-1,n=e-g,f=0n,l=[],n=Math.abs(n);0q){l[p].len=q;l.index=p;break}}else if(f)for(n=0;nq){l[p].len=q;l.index=p;break}l.sort(t);n=b[0];q=k[0];for(var m,J,B=p=0,u=e+g;p+Barguments.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= function(a,b,c,e){return 0<=b.minus(a).cross(c.minus(b)).dot(e)};c.Polygon.isStrictlyConvexPoint=function(a,b,c,e){return 1E-5<=b.minus(a).cross(c.minus(b)).dot(e)};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;db)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"); -return this.polygon},getPolygons:function(a){var b=[this],c=[b],e,f,g,l;for(e=0;eh)e.push(this);else if(l<-h)f.push(this);else switch(a=a.splitPolygon(g),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,g; -for(c=0;cf)e.push(this);else if(n<-f)k.push(this);else switch(a=a.splitPolygon(g),a.type){case 0:b.push(this);break;case 1:c.push(this);break;case 2:e.push(this);break;case 3:k.push(this);break;case 4:a.front&&(b=this.addChild(a.front),e.push(b)),a.back&&(e=this.addChild(a.back),k.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,k,g; +for(c=0;cd;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]- -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],g=this.elements[4],l=this.elements[5],h=this.elements[6],k=this.elements[7],m=this.elements[8],n=this.elements[9],q=this.elements[10],p=this.elements[11],r=this.elements[12],C=this.elements[13],x=this.elements[14],w=this.elements[15],B=a.elements[0],u=a.elements[1],y=a.elements[2],A=a.elements[3],G=a.elements[4],D=a.elements[5],E=a.elements[6],H=a.elements[7], -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*B+d*G+e*K+f*O;I[1]=b*u+d*D+e*L+f*P;I[2]=b*y+d*E+e*N+f*Q;I[3]=b*A+d*H+e*M+f*a;I[4]=g*B+l*G+h*K+k*O;I[5]=g*u+l*D+h*L+k*P;I[6]=g*y+l*E+h*N+k*Q;I[7]=g*A+l*H+h*M+k*a;I[8]=m*B+n*G+q*K+p*O;I[9]=m*u+n*D+q*L+p*P;I[10]=m*y+n*E+q*N+p*Q;I[11]=m*A+n*H+q*M+p*a;I[12]=r*B+C*G+x*K+w*O;I[13]=r*u+C*D+x*L+w*P;I[14]=r*y+C*E+x*N+w*Q;I[15]=r*A+C*H+x*M+w*a;return new c.Matrix4x4(I)}, -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],g=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,g*=b); -return new c.Vector3D(a,f,g)},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],g=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,g*=b);return new c.Vector3D(a,f,g)},rightMultiply1x2Vector:function(a){var b= +a.elements[d];return new c.Matrix4x4(b)},multiply:function(a){var b=this.elements[0],d=this.elements[1],e=this.elements[2],k=this.elements[3],g=this.elements[4],n=this.elements[5],f=this.elements[6],h=this.elements[7],l=this.elements[8],m=this.elements[9],p=this.elements[10],r=this.elements[11],t=this.elements[12],B=this.elements[13],u=this.elements[14],w=this.elements[15],A=a.elements[0],v=a.elements[1],x=a.elements[2],y=a.elements[3],F=a.elements[4],D=a.elements[5],E=a.elements[6],H=a.elements[7], +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*F+e*K+k*O;I[1]=b*v+d*D+e*L+k*P;I[2]=b*x+d*E+e*N+k*Q;I[3]=b*y+d*H+e*M+k*a;I[4]=g*A+n*F+f*K+h*O;I[5]=g*v+n*D+f*L+h*P;I[6]=g*x+n*E+f*N+h*Q;I[7]=g*y+n*H+f*M+h*a;I[8]=l*A+m*F+p*K+r*O;I[9]=l*v+m*D+p*L+r*P;I[10]=l*x+m*E+p*N+r*Q;I[11]=l*y+m*H+p*M+r*a;I[12]=t*A+B*F+u*K+w*O;I[13]=t*v+B*D+u*L+w*P;I[14]=t*x+B*E+u*N+w*Q;I[15]=t*y+B*H+u*M+w*a;return new c.Matrix4x4(I)}, +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 k=b*this.elements[4]+d*this.elements[5]+e*this.elements[6]+1*this.elements[7],g=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,k*=b,g*=b); +return new c.Vector3D(a,k,g)},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 k=b*this.elements[1]+d*this.elements[5]+e*this.elements[9]+1*this.elements[13],g=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,k*=b,g*=b);return new c.Vector3D(a,k,g)},rightMultiply1x2Vector:function(a){var b= 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], 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* 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); @@ -133,92 +135,92 @@ cross:function(a){return this._x*a._y-this._y*a._x},normal:function(){return c.V 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(), -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= 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= -d.times(1/e),e=Math.abs(d.x),f=Math.abs(d.y),g=Math.abs(d.z);e>=f&&e>=g?(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>=g?(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); +d.times(1/e),e=Math.abs(d.x),k=Math.abs(d.y),g=Math.abs(d.z);e>=k&&e>=g?(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])):k>=e&&k>=g?(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); 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))}, 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-8arguments.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"== 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"== 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."); 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); 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); -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 e=b.y-a.y;0>e&&(c=-c,e=-e);return a.x+(0>=c?0:c>=e?1:1E-10>e?.5:c/e)*(b.x-a.x)};c.reTesselateCoplanarPolygons=function(a,b){var d=a.length;if(0u)u=A;A in n||(n[A]={});n[A][p]=!0}B>=u?(C=[],x=0,w=-1):(B in k||(k[B]=[]),k[B].push(p))}C.reverse();w=x-w-1;l.push(C);t.push(w)}var d=[],E;for(E in n)d.push(E);d.sort(m);v=[];q=[];for(r= -0;r=x&&(u=0);if(C[u].y!=E)break;p=u}A=H-1;0>A&&(A=x-1);C[A].y==E&&(H=A);p!=y.leftvertexindex&&p==H?(v.splice(D,1),--D):(y.leftvertexindex=p,y.rightvertexindex=H,y.topleft=C[p],y.topright=C[H],u=p+1,u>=x&&(u=0),y.bottomleft=C[u],A=H-1,0>A&&(A=x-1),y.bottomright=C[A])}if(r>=d.length-1)v=[],B=null;else{B=Number(d[r+1]);var K= -.5*(E+B),G=k[G],L;for(L in G){p=G[L];C=l[p];x=C.length;for(D=u=t[p];;){y=D+1;y>=x&&(y=0);if(C[y].y!=E)break;if(y==u)break;D=y}for(H=u;;){y=H-1;0>y&&(y=x-1);if(C[y].y!=E)break;if(y==D)break;H=y}u=D+1;u>=x&&(u=0);A=H-1;0>A&&(A=x-1);h(v,{polygonindex:p,leftvertexindex:D,rightvertexindex:H,topleft:C[D],topright:C[H],bottomleft:C[u],bottomright:C[A]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1: -dC&&1E-5>x&&(y.topleft=p.topleft,y.leftline=p.leftline,y.bottomleft=p.bottomleft,w.splice(w.length-1,1))),w.push(y);if(0A.bottomleft.distanceTo(u.topleft)&&1E-5>A.bottomright.distanceTo(u.topright))){B[p]=!0;C=u.leftline.direction().x-A.leftline.direction().x;x=u.rightline.direction().x- -A.rightline.direction().x;G=1E-5>Math.abs(C);x=(D=1E-5>Math.abs(x))||0<=x;(G||0<=C)&&x&&(u.outpolygon=A.outpolygon,u.leftlinecontinues=G,u.rightlinecontinues=D,E[p]=!0);break}for(p=0;p>=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= -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= -[];if(0f.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= -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],g=f;"object"==typeof f&&("transform"in f&&"function"==typeof f.transform?g=f.transform(d):f instanceof Array?(g=[],c.Properties.transformObj(f,g,d)):f instanceof c.Properties&&(g=new c.Properties,c.Properties.transformObj(f,g,d)));b[e]=g}};c.Properties.cloneObj=function(a,b){for(var d in a)if("_transform"!=d&&"_merge"!= -d){var e=a[d],f=e;if("object"==typeof e)if(e instanceof Array)for(var f=[],g=0;ge&&(c=-c,e=-e);return a.x+(0>=c?0:c>=e?1:1E-10>e?.5:c/e)*(b.x-a.x)};c.reTesselateCoplanarPolygons=function(a,b){var d=a.length;if(0v)v=y;y in G||(G[y]={});G[y][r]=!0}A>=v?(B=[],u=0,w=-1):(A in m||(m[A]=[]),m[A].push(r))}B.reverse();w=u-w-1;n.push(B);h.push(w)}var d=[],E;for(E in G)d.push(E);d.sort(l);q=[];p=[];for(t= +0;t=u&&(v=0);if(B[v].y!=E)break;r=v}y=H-1;0>y&&(y=u-1);B[y].y==E&&(H=y);r!=x.leftvertexindex&&r==H?(q.splice(D,1),--D):(x.leftvertexindex=r,x.rightvertexindex=H,x.topleft=B[r],x.topright=B[H],v=r+1,v>=u&&(v=0),x.bottomleft=B[v],y=H-1,0>y&&(y=u-1),x.bottomright=B[y])}if(t>=d.length-1)q=[],A=null;else{A=Number(d[t+1]);var K= +.5*(E+A),F=m[F],L;for(L in F){r=F[L];B=n[r];u=B.length;for(D=v=h[r];;){x=D+1;x>=u&&(x=0);if(B[x].y!=E)break;if(x==v)break;D=x}for(H=v;;){x=H-1;0>x&&(x=u-1);if(B[x].y!=E)break;if(x==D)break;H=x}v=D+1;v>=u&&(v=0);y=H-1;0>y&&(y=u-1);f(q,{polygonindex:r,leftvertexindex:D,rightvertexindex:H,topleft:B[D],topright:B[H],bottomleft:B[v],bottomright:B[y]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1: +dB&&1E-5>u&&(x.topleft=r.topleft,x.leftline=r.leftline,x.bottomleft=r.bottomleft,w.splice(w.length-1,1))),w.push(x);if(0y.bottomleft.distanceTo(v.topleft)&&1E-5>y.bottomright.distanceTo(v.topright))){A[r]=!0;B=v.leftline.direction().x-y.leftline.direction().x;u=v.rightline.direction().x- +y.rightline.direction().x;F=1E-5>Math.abs(B);u=(D=1E-5>Math.abs(u))||0<=u;(F||0<=B)&&u&&(v.outpolygon=y.outpolygon,v.leftlinecontinues=F,v.rightlinecontinues=D,E[r]=!0);break}for(r=0;r>=1});this.lookuptable[c]=k}return k}};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= +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 k= +[];if(0k.length&&(k=[]);return new c.Polygon(k,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= +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 k=a[e],g=k;"object"==typeof k&&("transform"in k&&"function"==typeof k.transform?g=k.transform(d):k instanceof Array?(g=[],c.Properties.transformObj(k,g,d)):k instanceof c.Properties&&(g=new c.Properties,c.Properties.transformObj(k,g,d)));b[e]=g}};c.Properties.cloneObj=function(a,b){for(var d in a)if("_transform"!=d&&"_merge"!= +d){var e=a[d],k=e;if("object"==typeof e)if(e instanceof Array)for(var k=[],g=0;g=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"; +0;var e=this.normalized();a=a.normalized();var k=c.Matrix4x4.translation(this.point.negated()),g=c.Plane.anyPlaneFromVector3Ds(new c.Vector3D(0,0,0),e.axisvector,a.axisvector),g=new c.OrthoNormalBasis(g),n=g.to2D(e.axisvector).angle(),f=g.to2D(a.axisvector).angle(),n=180*(f-n)/Math.PI;b&&(n+=180);k=k.multiply(g.getProjectionMatrix());k=k.multiply(c.Matrix4x4.rotationZ(n));k=k.multiply(g.getInverseProjectionMatrix());e=e.transform(k);b=c.Plane.fromNormalAndPoint(a.axisvector,new c.Vector3D(0,0,0)); +b=new c.OrthoNormalBasis(b);n=b.to2D(e.normalvector).angle();f=b.to2D(a.normalvector).angle();n=180*(f-n)/Math.PI;n+=d;k=k.multiply(b.getProjectionMatrix());k=k.multiply(c.Matrix4x4.rotationZ(n));k=k.multiply(b.getInverseProjectionMatrix());return k=k.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= +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,k=a.points.length,g=new c.ConnectorList([new c.Connector(a.points[0],b,c.ConnectorList.defaultNormal)]); +a.points.slice(1,k-1).forEach(function(b,d){e=a.points[d+2].minus(a.points[d]).toVector3D(0);g.appendConnector(new c.Connector(b.toVector3D(0),e,c.ConnectorList.defaultNormal))},this);g.appendConnector(new c.Connector(a.points[k-1],d,c.ConnectorList.defaultNormal));g.closed=a.closed;return g};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, +0,0).rotateZ(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,k=this.connectors_[this.connectors_.length-1],g=b(a,k);this.connectors_.forEach(function(c,f){e=b(a,c);f||this.closed?d.push.apply(d,g._toWallPolygons({toConnector1:k, +toConnector2:c,cag:e})):d.push.apply(d,e._toPlanePolygons({toConnector:c,flipped:!0}));f!=this.connectors_.length-1||this.closed||d.push.apply(d,e._toPlanePolygons({toConnector:c}));g=e;k=c},this);return c.fromPolygons(d).reTesselated().canonicalized()},verify:function(){for(var a,b,c=0;c=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"; 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&&0a.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, -"startangle",0),f=c.parseOptionAsFloat(a,"endangle",360),g=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 l=[],h,k=Math.abs(f-e);if(1E-5>k)h=c.Vector2D.fromAngle(e/180*Math.PI).times(d),l.push(h.plus(b));else{g=Math.floor(g*k/360)+1;k=.5*g/k;.25h&&(h=0),h>g&&(h=g)),h=c.Vector2D.fromAngle((e+h*(f-e)/g)/180*Math.PI).times(d),l.push(h.plus(b))}return new c.Path2D(l, +"startangle",0),k=c.parseOptionAsFloat(a,"endangle",360),g=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D);for(a=c.parseOptionAsBool(a,"maketangent",!1);720<=k-e;)k-=360;for(;-720>=k-e;)k+=360;var n=[],f,h=Math.abs(k-e);if(1E-5>h)f=c.Vector2D.fromAngle(e/180*Math.PI).times(d),n.push(f.plus(b));else{g=Math.floor(g*h/360)+1;h=.5*g/h;.25f&&(f=0),f>g&&(f=g)),f=c.Vector2D.fromAngle((e+f*(k-e)/g)/180*Math.PI).times(d),n.push(f.plus(b))}return new c.Path2D(n, !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, -!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&&2h&&(h=e-1);h=new n.Vertex(this.points[h]);l>f&&(g=new n.Side(g,h),c.push(g));g=h}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)}); +!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,k=0;this.closed&&2h&&(h=e-1);h=new m.Vertex(this.points[h]);f>k&&(g=new m.Side(g,h),c.push(g));g=h}return m.fromSides(c).expandedShell(a,b)},innerToCAG:function(){if(!this.closed)throw Error("The path should be closed!");return m.fromPoints(this.points)},transform:function(a){var b=this.points.map(function(b){return b.multiply4x4(a)}); 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, -"resolution",c.defaultResolution2D);4>d&&(d=4);var e=[],f=[];f.push(this.points[this.points.length-1]);for(var g=0;ga.length)throw Error("appendBezier: null can only be passed if there is at least one more control point");if("lastBezierControlPoint"in this)l=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"); -l=this.points[this.points.length-2]}l=this.points[this.points.length-1].times(2).minus(l)}else l=new c.Vector2D(l);f.push(l)}for(var h=f.length-1,l=1,g=0;g<=h;++g)0d){var q=m[g-1],p=m[g+1],n=q+1*(p-q)/3,q=q+2*(p-q)/3,p=e(n),r=e(q);l.splice(g,1,p,r);m.splice(g,1,n,q);g--;1>g&&(g=1)}else++g;l=this.points.concat(l.slice(1));e=new c.Path2D(l);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)"); -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 g=c.parseOptionAsFloat(b,"xaxisrotation",0),l=c.parseOptionAsBool(b,"clockwise",!1),h=c.parseOptionAsBool(b,"large",!1),k=this.points[this.points.length-1]; -a=new c.Vector2D(a);var m=!l,l=[];if(0==e||0==f)l.push(a);else{e=Math.abs(e);f=Math.abs(f);var n=g*Math.PI/180,g=Math.cos(n),n=Math.sin(n),q=k.minus(a).times(.5),q=new c.Vector2D(g*q.x+n*q.y,-n*q.x+g*q.y),p=q.x*q.x/(e*e)+q.y*q.y/(f*f);1q&&(q+=2*Math.PI);d=Math.ceil(Math.abs(q)/(2*Math.PI)*d)+1;1>d&&(d=1);for(m=1;m<=d;m++){var r=h+m/d*q,p=Math.cos(r),r=Math.sin(r),p=(new c.Vector2D(g*e*p-n*f*r,n*e*p+g*f*r)).plus(k);l.push(p)}}l=this.points.concat(l);return new c.Path2D(l)}};c.addTransformationMethodsToPrototype=function(a){a.mirrored=function(a){return this.transform(c.Matrix4x4.mirroring(a))};a.mirroredX= +"resolution",c.defaultResolution2D);4>d&&(d=4);var e=[],k=[];k.push(this.points[this.points.length-1]);for(var g=0;ga.length)throw Error("appendBezier: null can only be passed if there is at least one more control point");if("lastBezierControlPoint"in this)f=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"); +f=this.points[this.points.length-2]}f=this.points[this.points.length-1].times(2).minus(f)}else f=new c.Vector2D(f);k.push(f)}for(var h=k.length-1,f=1,g=0;g<=h;++g)0d){var p=m[g-1],r=m[g+1],q=p+1*(r-p)/3,p=p+2*(r-p)/3,r=e(q),t=e(p);f.splice(g,1,r,t);m.splice(g,1,q,p);g--;1>g&&(g=1)}else++g;f=this.points.concat(f.slice(1));e=new c.Path2D(f);e.lastBezierControlPoint=k[k.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)"); +var d=c.parseOptionAsInt(b,"resolution",c.defaultResolution2D);4>d&&(d=4);var e,k;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);k=c.parseOptionAsFloat(b,"yradius",0)}else k=e=c.parseOptionAsFloat(b,"radius",0);var g=c.parseOptionAsFloat(b,"xaxisrotation",0),f=c.parseOptionAsBool(b,"clockwise",!1),h=c.parseOptionAsBool(b,"large",!1),l=this.points[this.points.length-1]; +a=new c.Vector2D(a);var m=!f,f=[];if(0==e||0==k)f.push(a);else{e=Math.abs(e);k=Math.abs(k);var q=g*Math.PI/180,g=Math.cos(q),q=Math.sin(q),p=l.minus(a).times(.5),p=new c.Vector2D(g*p.x+q*p.y,-q*p.x+g*p.y),r=p.x*p.x/(e*e)+p.y*p.y/(k*k);1p&&(p+=2*Math.PI);d=Math.ceil(Math.abs(p)/(2*Math.PI)*d)+1;1>d&&(d=1);for(m=1;m<=d;m++){var t=h+m/d*p,r=Math.cos(t),t=Math.sin(t),r=(new c.Vector2D(g*e*r-q*k*t,q*e*r+g*k*t)).plus(l);f.push(r)}}f=this.points.concat(f);return new c.Path2D(f)}};c.addTransformationMethodsToPrototype=function(a){a.mirrored=function(a){return this.transform(c.Matrix4x4.mirroring(a))};a.mirroredX= 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.translate=function(a){return this.transform(c.Matrix4x4.translation(a))};a.scale=function(a){return this.transform(c.Matrix4x4.scaling(a))};a.rotateX=function(a){return this.transform(c.Matrix4x4.rotationX(a))};a.rotateY=function(a){return this.transform(c.Matrix4x4.rotationY(a))}; -a.rotateZ=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.translate(b.map(function(b){return-1b)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);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,a.x-d.x,a.y-d.y);if(1E-6a[0]&&1E-5a[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 g=0;g<=a;g++){var l=c.Vector2D.fromAngleRadians(2*Math.PI*g/a).times(d).plus(b),l=new n.Vertex(l);0=a.x||0>=a.y)throw Error("Dimension should be positive."); -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, -"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);var f=Math.min(d.x,d.y),e=Math.min(e,f-.1),e=Math.max(0,e);d=new c.Vector2D(d.x-e,d.y-e);b=n.rectangle({center:b,radius:d});0b&&(b=4);var d=[],e={};this.canonicalized().sides.map(function(b){var c=b.vertex1.pos.minus(b.vertex0.pos),g=c.length();if(1E-5c;c++){var g=0=== -c?b.vertex0.pos:b.vertex1.pos,f=0===c?b.vertex1.pos:b.vertex0.pos,h=g.x+" "+g.y;h in e||(e[h]=[]);e[h].push({p1:g,p2:f})}});for(var f in e){var g=e[f],l,h=g[0].p1;if(2==g.length){l=g[1].p2;g=g[0].p2.minus(h).angleDegrees();l=l.minus(h).angleDegrees();l=g+360&&(l-=360);if(lg+359.999)g=0,l=360;if(l>g+1E-5){var m=[];k||m.push(h);var v=Math.round(b*(l-g)/360);1>v&&(v=1);for(var q=0;q<=v;q++){var p=g+q/v*(l-g);q==v&&(p=l);p=h.plus(c.Vector2D.fromAngleDegrees(p).times(a)); -(!k||0a)a=1;for(var e=c.Vector3D.Create(0,1,0),f=[],f=f.concat(this._toPlanePolygons({translation:[0,0,0],normalVector:e,flipped:!(0>b.z)})),f=f.concat(this._toPlanePolygons({translation:b, -normalVector:e.rotateZ(d),flipped:0>b.z})),g=0;gb)var k=new c.Connector(a,e.rotateZ(-b),f),g=g.concat(this._toPlanePolygons({toConnector:h,flipped:!0})),g=g.concat(this._toPlanePolygons({toConnector:k}));for(var m=k=b/d;m<=b+1E-5;m+=k)d=new c.Connector(a,e.rotateZ(-m),f),g=g.concat(this._toWallPolygons({toConnector1:h,toConnector2:d})),h=d;return c.fromPolygons(g).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,"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]]),g=n.fromPoints([[.001,1E5],[-2E5,1E5],[-2E5,-1E5],[.001,-1E5]]),h=this.translate([e,0,0]),f=h.subtract(f),g=h.subtract(g),g=0!=f.sides.length?f.mirroredX().union(g):g,g=g.translate([-e,0,0]),h=[],f=0;fa.angle?1:this.distancea.distance?1:0}};ConvexHull=function(){this.indices= +a.rotateZ=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.translate(b.map(function(b){return-1b)throw Error("CAG shape needs at least 3 points");var d=[],b=new c.Vector2D(a[b-1]),e=new m.Vertex(b);a.map(function(a){a=new c.Vector2D(a);a=new m.Vertex(a);var b=new m.Side(e,a);d.push(b);e=a});a=m.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()};m.fromPointsNoCheck=function(a){var b=[],d=new c.Vector2D(a[a.length- +1]),e=new m.Vertex(d);a.map(function(a){a=new c.Vector2D(a);a=new m.Vertex(a);var d=new m.Side(e,a);b.push(d);e=a});return m.fromSides(b)};m.fromFakeCSG=function(a){a=a.polygons.map(function(a){return m.Side._fromFakePolygon(a)}).filter(function(a){return null!==a});return m.fromSides(a)};m.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,a.x-d.x,a.y-d.y);if(1E-6a[0]&&1E-5a[1])return!0}return!1};m.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=[],k;if(0>=d)throw Error("Radius should be positive.");if(5E-4>d)return new m;for(var g=0;g<=a;g++){var f=c.Vector2D.fromAngleRadians(2*Math.PI*g/a).times(d).plus(b),f=new m.Vertex(f);0=a.x||0>=a.y)throw Error("Dimension should be positive."); +if(5E-4>a.x||5E-4>a.y)return console.log("Throwing out a zero-length rectangle."),new m;var d=new c.Vector2D(a.x,-a.y);b=[b.plus(a),b.plus(d),b.minus(a),b.minus(d)];return m.fromPoints(b)};m.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, +"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);var k=Math.min(d.x,d.y),e=Math.min(e,k-.1),e=Math.max(0,e);d=new c.Vector2D(d.x-e,d.y-e);b=m.rectangle({center:b,radius:d});0b&&(b=4);var d=[],e={};this.canonicalized().sides.map(function(b){var c=b.vertex1.pos.minus(b.vertex0.pos),g=c.length();if(1E-5c;c++){var g=0=== +c?b.vertex0.pos:b.vertex1.pos,k=0===c?b.vertex1.pos:b.vertex0.pos,f=g.x+" "+g.y;f in e||(e[f]=[]);e[f].push({p1:g,p2:k})}});for(var k in e){var g=e[k],f,h=g[0].p1;if(2==g.length){f=g[1].p2;g=g[0].p2.minus(h).angleDegrees();f=f.minus(h).angleDegrees();f=g+360&&(f-=360);if(fg+359.999)g=0,f=360;if(f>g+1E-5){var t=[];l||t.push(h);var q=Math.round(b*(f-g)/360);1>q&&(q=1);for(var p=0;p<=q;p++){var r=g+p/q*(f-g);p==q&&(r=f);r=h.plus(c.Vector2D.fromAngleDegrees(r).times(a)); +(!l||0a)a=1;for(var e=c.Vector3D.Create(0,1,0),k=[],k=k.concat(this._toPlanePolygons({translation:[0,0,0],normalVector:e,flipped:!(0>b.z)})),k=k.concat(this._toPlanePolygons({translation:b, +normalVector:e.rotateZ(d),flipped:0>b.z})),g=0;gb)var h=new c.Connector(a,e.rotateZ(-b),k),g=g.concat(this._toPlanePolygons({toConnector:f,flipped:!0})),g=g.concat(this._toPlanePolygons({toConnector:h}));for(var l=h=b/d;l<=b+1E-5;l+=h)d=new c.Connector(a,e.rotateZ(-l),k),g=g.concat(this._toWallPolygons({toConnector1:f,toConnector2:d})),f=d;return c.fromPolygons(g).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,"tsteps",0);3>b&&(b=3);a=Math.ceil(a/b);1>a&&(a=1);for(var k=m.fromPoints([[-.001,1E5],[2E5,1E5],[2E5,-1E5],[-.001,-1E5]]),g=m.fromPoints([[.001,1E5],[-2E5,1E5],[-2E5,-1E5],[.001,-1E5]]),f=this.translate([e,0,0]),k=f.subtract(k),g=f.subtract(g),g=0!=k.sides.length?k.mirroredX().union(g):g,g=g.translate([-e,0,0]),f=[],k=0;ka.angle?1:this.distancea.distance?1:0}};ConvexHull=function(){this.indices= this.points=null;this.getIndices=function(){return this.indices};this.clear=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-this.points[a].y)};this.compute=function(a){this.indices=null;if(!(3>a.length)){this.points=a;var b=0;for(a=1;ad&&(d+=Math.PI),e=this.distance(b,a),c.push(new 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.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;ap&&(p+=360);180<=p&&(p-=360);if(0>n||p>r)n=q,r=p}r=m[n];m.splice(n,1);0===m.length&&delete b[k];h=a[r]}g=new c.Path2D(g,!0);d.push(g)}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:[]});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 g=d[f];if(1==g.from.length&&1==g.to.length){var h=g.pos,k=g.to[0],g=h.minus(g.from[0]).unit(),k=k.minus(h).unit();if(.001>g.cross(k)){var m=k.angleRadians()-g.angleRadians()+Math.PI;0>m?m+=2*Math.PI:m>=2*Math.PI&&(m-=2*Math.PI);for(var k=k.minus(g).unit(),r=30/180* -Math.PI,g=a/Math.cos(r/2),h=h.plus(k.times(g)),k=m+k.angleRadians(),m=2*(Math.PI-m),r=2*Math.ceil(m/r/2),v=[h],q=0;q<=r;q++){var p=c.Vector2D.fromAngleRadians(k+q/r*m).times(g).plus(h);v.push(p)}e.push(n.fromPoints(v))}}}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 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 "+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= -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())}}; -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=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;ar&&(r+=360);180<=r&&(r-=360);if(0>t||r>q)t=p,q=r}q=m[t];m.splice(t,1);0===m.length&&delete b[l];h=a[q]}g=new c.Path2D(g,!0);d.push(g)}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:[]});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 g=d[f];if(1==g.from.length&&1==g.to.length){var h=g.pos,l=g.to[0],g=h.minus(g.from[0]).unit(),l=l.minus(h).unit();if(.001>g.cross(l)){var t=l.angleRadians()-g.angleRadians()+Math.PI;0>t?t+=2*Math.PI:t>=2*Math.PI&&(t-=2*Math.PI);for(var l=l.minus(g).unit(),G=30/180* +Math.PI,g=a/Math.cos(G/2),h=h.plus(l.times(g)),l=t+l.angleRadians(),t=2*(Math.PI-t),G=2*Math.ceil(t/G/2),q=[h],p=0;p<=G;p++){var r=c.Vector2D.fromAngleRadians(l+p/G*t).times(g).plus(h);q.push(r)}e.push(m.fromPoints(q))}}}return b.subtract(e)}};m.Vertex=function(a){this.pos=a};m.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}};m.Side=function(a,b){if(!(a instanceof m.Vertex))throw Error("Assertion failed"); +if(!(b instanceof m.Vertex))throw Error("Assertion failed");this.vertex0=a;this.vertex1=b};m.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 "+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= +this.vertex0.pos.transform(a);a=this.vertex1.pos.transform(a);return new m.Side(new m.Vertex(b),new m.Vertex(a))},flipped:function(){return new m.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())}}; +m.fuzzyCAGFactory=function(){this.vertexfactory=new c.fuzzyFactory(2,1E-5)};m.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 m.Side(b,a)},getCAG:function(a){var b=this;a=a.sides.map(function(a){return b.getSide(a)}).filter(function(a){return 1E-5k;k++)h[k]=65;k=new Uint32Array(1);k[0]=r;var c=new ArrayBuffer(50*r),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;hm;m++){var r=a.vertices[m+(0= -k.points.length&&(a-=k.points.length);a=k.points[a];h+=" 10\n"+a.x+"\n 20\n"+a.y+"\n 30\n0.0\n"}});h+=" 0\nENDSEC\n 0\nEOF\n";return new Blob([h],{type:"application/dxf"})};CAG.prototype.toDxf=function(){var k=this.getOutlinePaths();return CAG.PathsToDxf(k)};CSG.prototype.toAMFString=function(k){var h='\n\n",r;for(r in k)h+=''+k[r]+"\n";h+='\n\n\n';this.polygons.map(function(c){for(var a= -0;a\n",c=0;this.polygons.map(function(k){h+="\n";if(!(3>k.vertices.length)){var a=1,b=.4,d=1,e=1;k.shared&&k.shared.color?(a=k.shared.color[0],b=k.shared.color[1],d=k.shared.color[2],e=k.shared.color[3]):k.color&&(a=k.color[0],b=k.color[1],d=k.color[2],3"+a+""+b+""+d+""+(void 0!==e?""+e+"":"")+"";for(a=0;a",h+=""+c+"",h+=""+(c+a+1)+"",h+=""+(c+a+2)+"",h+="\n";c+=k.vertices.length;h+="\n"}});h+="\n\n";h+="\n";return new Blob([h],{type:"application/amf+xml"})};CSG.Vector3D.prototype.toAMFString=function(){return""+this._x+""+this._y+""+this._z+""};CSG.Vertex.prototype.toAMFString=function(){return""+this.pos.toAMFString()+"\n"};k.CSG=CSG;k.CAG=CAG})(this); \ No newline at end of file +c.addTransformationMethodsToPrototype(m.prototype);c.addTransformationMethodsToPrototype(m.Side.prototype);c.addTransformationMethodsToPrototype(c.OrthoNormalBasis.prototype);c.addCenteringToPrototype(c.prototype,["x","y","z"]);c.addCenteringToPrototype(m.prototype,["x","y"]);c.Polygon2D=function(a){this.sides=m.fromPoints(a).sides};c.Polygon2D.prototype=m.prototype;h.CSG=c;h.CAG=m})(this);"undefined"!==typeof module&&(CSG=require(lib+"csg.js").CSG,CAG=require(lib+"csg.js").CAG,Blob=require(lib+"Blob.js").Blob); +(function(h){CSG.prototype.toX3D=function(){var h={},f=[],t={};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=[],g=a.vertices.length,k,m=0;mh;h++)f[h]=65;h=new Uint32Array(1);h[0]=t;var c=new ArrayBuffer(50*t),m=new Int8Array(c),a=new ArrayBuffer(50),b=new Int8Array(a),d=new Float32Array(a,0,12),e=new Uint16Array(a,48,1),k=0;this.polygons.map(function(a){for(var c=a.vertices.length,f=0;fl;l++){var q=a.vertices[l+(0= +h.points.length&&(a-=h.points.length);a=h.points[a];f+=" 10\n"+a.x+"\n 20\n"+a.y+"\n 30\n0.0\n"}});f+=" 0\nENDSEC\n 0\nEOF\n";return new Blob([f],{type:"application/dxf"})};CAG.prototype.toDxf=function(){var h=this.getOutlinePaths();return CAG.PathsToDxf(h)};CSG.prototype.toAMFString=function(h){var f='\n\n",t;for(t in h)f+=''+h[t]+"\n";f+='\n\n\n';this.polygons.map(function(c){for(var a= +0;a\n",c=0;this.polygons.map(function(h){f+="\n";if(!(3>h.vertices.length)){var a=1,b=.4,d=1,e=1;h.shared&&h.shared.color?(a=h.shared.color[0],b=h.shared.color[1],d=h.shared.color[2],e=h.shared.color[3]):h.color&&(a=h.color[0],b=h.color[1],d=h.color[2],3"+a+""+b+""+d+""+(void 0!==e?""+e+"":"")+"";for(a=0;a",f+=""+c+"",f+=""+(c+a+1)+"",f+=""+(c+a+2)+"",f+="\n";c+=h.vertices.length;f+="\n"}});f+="\n\n";f+="\n";return new Blob([f],{type:"application/amf+xml"})};CSG.Vector3D.prototype.toAMFString=function(){return""+this._x+""+this._y+""+this._z+""};CSG.Vertex.prototype.toAMFString=function(){return""+this.pos.toAMFString()+"\n"};h.CSG=CSG;h.CAG=CAG})(this); \ No newline at end of file From ae6894a95563c3af4c22d19d882c0b4bd226c388 Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Thu, 1 Oct 2015 11:32:38 -0600 Subject: [PATCH 5/9] added checkmark on Switch to three.js on TODO file --- TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO b/TODO index 6e72cfd5..07e87591 100644 --- a/TODO +++ b/TODO @@ -14,7 +14,7 @@ FEATURES TO ADD AND FIX AND STUFF [x]Text (and strings) [ ]Draft [ ]Minkowski Sum -[ ]Switch to three.js +[x]Switch to three.js [ ]Transparency (like openscad's #, or alpha channel in color) [ ]Internationalization support (bring back from blockly) [ ]Simplified mode (elementary-friendly, hiding distracting fancy stuff) From e7bc1d5e0bc263a28330659122a11cb3e4963441 Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Fri, 2 Oct 2015 08:22:56 -0600 Subject: [PATCH 6/9] Fixed reset view not working after pan --- blockscad/threeViewer.js | 9 ++++++++- blockscad/viewer_compressed.js | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/blockscad/threeViewer.js b/blockscad/threeViewer.js index 8e4e1198..55a96ca7 100644 --- a/blockscad/threeViewer.js +++ b/blockscad/threeViewer.js @@ -81,37 +81,44 @@ Blockscad.Viewer.prototype = { var whichView = document.getElementById("viewMenu"); if (whichView.value == "top") { + this.controls.reset(); this.camera.position.set( 0, 0, 50 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } else if (whichView.value == "front") { + this.controls.reset(); this.camera.position.set( 0, -50, 0 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } else if (whichView.value == "left") { + this.controls.reset(); this.camera.position.set( -50, 0, 0 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } else if (whichView.value == "right") { + this.controls.reset(); this.camera.position.set( 50, 0, 0 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } else if (whichView.value == "bottom") { + this.controls.reset(); this.camera.position.set( 0, 0, -50 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } - else if (whichView.value == "back") { + else if (whichView.value == "back") { + this.controls.reset(); this.camera.position.set( 0, 50, 0 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } else if (whichView.value == "diagonal") { + this.controls.reset(); this.camera.position.set( 50, -50, 50 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } diff --git a/blockscad/viewer_compressed.js b/blockscad/viewer_compressed.js index ef08387a..cabb21bb 100644 --- a/blockscad/viewer_compressed.js +++ b/blockscad/viewer_compressed.js @@ -4,15 +4,16 @@ var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{}; Blockscad.Viewer=function(h,l,f,t){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,l/f,1,1E4);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.shadowMap.enabled=!0;this.renderer.shadowMapSoft=!1;this.renderer.shadowCameraNear=1;this.renderer.shadowCameraFar=this.camera.far;this.renderer.shadowCameraFov=45;this.renderer.shadowMapBias= .0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(500);this.GridPlane=this.buildGridPlane(500); this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,m=function(){requestAnimationFrame(m);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};m()}; -Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(h,l){this.renderer.setSize(h,l);this.camera.aspect=h/l;this.camera.updateProjectionMatrix()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"front"== -h.value?(this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==h.value?(this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==h.value?(this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==h.value?(this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==h.value?(this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.camera.position.set(50, --50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes),this.scene.add(this.GridPlane))},buildLine:function(h,l,f,t,c){var m=new THREE.Geometry;f=t?new THREE.LineDashedMaterial({linewidth:c,color:f,dashSize:1,gapSize:1}):new THREE.LineBasicMaterial({linewidth:c, -color:f});m.vertices.push(h.clone());m.vertices.push(l.clone());m.computeLineDistances();return new THREE.Line(m,f,THREE.LineSegments)},buildAxes:function(h){h/=2;var l=new THREE.Object3D;l.name="axes";l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(h,0,0),16711680,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(-h,0,0),16711680,!0,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,h,0),65280,!1,1));l.add(this.buildLine(new THREE.Vector3(0, -0,0),new THREE.Vector3(0,-h,0),65280,!0,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,h),255,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,-h),255,!0,1));l.add(this.buildLine(new THREE.Vector3(-5+h+5,-5,0),new THREE.Vector3(5+h+5,5,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(5+h+5,-5,0),new THREE.Vector3(-5+h+5,5,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0+h,0),new THREE.Vector3(0,5+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0, -5+h,0),new THREE.Vector3(5,10+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,5+h,0),new THREE.Vector3(-5,10+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(-5,0,0+h+5),new THREE.Vector3(5,0,0+h+5),0,!1,1));l.add(this.buildLine(new THREE.Vector3(-5,0,0+h+5),new THREE.Vector3(5,0,10+h+5),0,!1,1));l.add(this.buildLine(new THREE.Vector3(5,0,10+h+5),new THREE.Vector3(-5,0,10+h+5),0,!1,1));return l},buildGridPlane:function(h){var l=new THREE.Object3D;l.name="GridPlane";h/=2;for(var f=-h;0> -f;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),14540253,!1,1));for(f=1;f<=h;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-.5,-.5,f),new THREE.Vector3(.5,.5,f),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(.5, --.5,f),new THREE.Vector3(-.5,.5,f),14540253,!1,1));for(f=-h;0>f;f+=10)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-1,-1,f),new THREE.Vector3(1,1,f),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(1,-1,f),new THREE.Vector3(-1,1,f),12895428,!1,1));for(f=10;f<=h;f+=10)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f, -h,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-1,-1,f),new THREE.Vector3(1,1,f),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(1,-1,f),new THREE.Vector3(-1,1,f),12895428,!1,1));return l}};Blockscad.Viewer.getGeometryVertice=function(h,l){h.vertices.push(new THREE.Vector3(l.x,l.y,l.z));return h.vertices.length-1}; +Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(h,l){this.renderer.setSize(h,l);this.camera.aspect=h/l;this.camera.updateProjectionMatrix()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.controls.reset(),this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0, +0,0))):"front"==h.value?(this.controls.reset(),this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==h.value?(this.controls.reset(),this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==h.value?(this.controls.reset(),this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==h.value?(this.controls.reset(),this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==h.value? +(this.controls.reset(),this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.controls.reset(),this.camera.position.set(50,-50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes), +this.scene.add(this.GridPlane))},buildLine:function(h,l,f,t,c){var m=new THREE.Geometry;f=t?new THREE.LineDashedMaterial({linewidth:c,color:f,dashSize:1,gapSize:1}):new THREE.LineBasicMaterial({linewidth:c,color:f});m.vertices.push(h.clone());m.vertices.push(l.clone());m.computeLineDistances();return new THREE.Line(m,f,THREE.LineSegments)},buildAxes:function(h){h/=2;var l=new THREE.Object3D;l.name="axes";l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(h,0,0),16711680,!1,1));l.add(this.buildLine(new THREE.Vector3(0, +0,0),new THREE.Vector3(-h,0,0),16711680,!0,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,h,0),65280,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,-h,0),65280,!0,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,h),255,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,-h),255,!0,1));l.add(this.buildLine(new THREE.Vector3(-5+h+5,-5,0),new THREE.Vector3(5+h+5,5,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(5+ +h+5,-5,0),new THREE.Vector3(-5+h+5,5,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0+h,0),new THREE.Vector3(0,5+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,5+h,0),new THREE.Vector3(5,10+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,5+h,0),new THREE.Vector3(-5,10+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(-5,0,0+h+5),new THREE.Vector3(5,0,0+h+5),0,!1,1));l.add(this.buildLine(new THREE.Vector3(-5,0,0+h+5),new THREE.Vector3(5,0,10+h+5),0,!1,1));l.add(this.buildLine(new THREE.Vector3(5, +0,10+h+5),new THREE.Vector3(-5,0,10+h+5),0,!1,1));return l},buildGridPlane:function(h){var l=new THREE.Object3D;l.name="GridPlane";h/=2;for(var f=-h;0>f;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),14540253,!1,1));for(f=1;f<=h;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h, +f,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-.5,-.5,f),new THREE.Vector3(.5,.5,f),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(.5,-.5,f),new THREE.Vector3(-.5,.5,f),14540253,!1,1));for(f=-h;0>f;f+=10)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-1,-1,f),new THREE.Vector3(1,1,f),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(1, +-1,f),new THREE.Vector3(-1,1,f),12895428,!1,1));for(f=10;f<=h;f+=10)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(-1,-1,f),new THREE.Vector3(1,1,f),12895428,!1,1)),l.add(this.buildLine(new THREE.Vector3(1,-1,f),new THREE.Vector3(-1,1,f),12895428,!1,1));return l}}; +Blockscad.Viewer.getGeometryVertice=function(h,l){h.vertices.push(new THREE.Vector3(l.x,l.y,l.z));return h.vertices.length-1}; Blockscad.Viewer.csgToThreeMesh=function(h){var l=h.canonicalized(),f,t,c;h=new THREE.Geometry;var m=l.toPolygons();if(!CSG)throw"CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js";for(l=0;l Date: Fri, 2 Oct 2015 09:36:59 -0600 Subject: [PATCH 7/9] Increased zoom speed --- blockscad/threeViewer.js | 1 + blockscad/viewer_compressed.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/blockscad/threeViewer.js b/blockscad/threeViewer.js index 55a96ca7..4eb9565d 100644 --- a/blockscad/threeViewer.js +++ b/blockscad/threeViewer.js @@ -34,6 +34,7 @@ Blockscad.Viewer = function(containerelement, width, height, initialdepth) { this.controls.enableDamping = true; this.controls.dampingFactor = 0.5; this.controls.enableZoom = true; + this.controls.zoomSpeed = 3; var light = new THREE.DirectionalLight(0xffffff, 1); this.light=light; this.light.castShadow = true; diff --git a/blockscad/viewer_compressed.js b/blockscad/viewer_compressed.js index cabb21bb..611c7db0 100644 --- a/blockscad/viewer_compressed.js +++ b/blockscad/viewer_compressed.js @@ -2,8 +2,8 @@ "use strict"; var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{}; Blockscad.Viewer=function(h,l,f,t){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,l/f,1,1E4);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.shadowMap.enabled=!0;this.renderer.shadowMapSoft=!1;this.renderer.shadowCameraNear=1;this.renderer.shadowCameraFar=this.camera.far;this.renderer.shadowCameraFov=45;this.renderer.shadowMapBias= -.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(500);this.GridPlane=this.buildGridPlane(500); -this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,m=function(){requestAnimationFrame(m);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};m()}; +.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.controls.zoomSpeed=3;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(500); +this.GridPlane=this.buildGridPlane(500);this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,m=function(){requestAnimationFrame(m);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};m()}; Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(h,l){this.renderer.setSize(h,l);this.camera.aspect=h/l;this.camera.updateProjectionMatrix()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.controls.reset(),this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0, 0,0))):"front"==h.value?(this.controls.reset(),this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==h.value?(this.controls.reset(),this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==h.value?(this.controls.reset(),this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==h.value?(this.controls.reset(),this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==h.value? (this.controls.reset(),this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.controls.reset(),this.camera.position.set(50,-50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes), From 031f5e02d9cf3afa3b92d0edf27b677dd9f2b0e9 Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Fri, 2 Oct 2015 10:10:33 -0600 Subject: [PATCH 8/9] Reduced 3d workspace area to original size --- blockscad/threeViewer.js | 4 ++-- blockscad/viewer_compressed.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blockscad/threeViewer.js b/blockscad/threeViewer.js index 4eb9565d..77cc3170 100644 --- a/blockscad/threeViewer.js +++ b/blockscad/threeViewer.js @@ -40,8 +40,8 @@ Blockscad.Viewer = function(containerelement, width, height, initialdepth) { this.light.castShadow = true; this.light.position.copy( this.camera.position ); this.scene.add(this.light); - this.axes = this.buildAxes( 500 ); - this.GridPlane = this.buildGridPlane(500); + this.axes = this.buildAxes( 200 ); + this.GridPlane = this.buildGridPlane(200); this.scene.add(this.axes); this.scene.add(this.GridPlane); $(containerelement).append(this.renderer.domElement); diff --git a/blockscad/viewer_compressed.js b/blockscad/viewer_compressed.js index 611c7db0..dc387227 100644 --- a/blockscad/viewer_compressed.js +++ b/blockscad/viewer_compressed.js @@ -2,8 +2,8 @@ "use strict"; var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{}; Blockscad.Viewer=function(h,l,f,t){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,l/f,1,1E4);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.shadowMap.enabled=!0;this.renderer.shadowMapSoft=!1;this.renderer.shadowCameraNear=1;this.renderer.shadowCameraFar=this.camera.far;this.renderer.shadowCameraFov=45;this.renderer.shadowMapBias= -.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.controls.zoomSpeed=3;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(500); -this.GridPlane=this.buildGridPlane(500);this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,m=function(){requestAnimationFrame(m);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};m()}; +.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.controls.zoomSpeed=3;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(200); +this.GridPlane=this.buildGridPlane(200);this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,m=function(){requestAnimationFrame(m);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};m()}; Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(h,l){this.renderer.setSize(h,l);this.camera.aspect=h/l;this.camera.updateProjectionMatrix()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.controls.reset(),this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0, 0,0))):"front"==h.value?(this.controls.reset(),this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==h.value?(this.controls.reset(),this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==h.value?(this.controls.reset(),this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==h.value?(this.controls.reset(),this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==h.value? (this.controls.reset(),this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.controls.reset(),this.camera.position.set(50,-50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes), From 81d0a85274a20117b035e56c54b5b4a55e0e6be4 Mon Sep 17 00:00:00 2001 From: Juan Blanco Segleau Date: Fri, 2 Oct 2015 16:55:57 -0600 Subject: [PATCH 9/9] Removed render loop, rendering on demand now, controls feels sluggish --- blockscad/threeViewer.js | 44 +++++++------------ blockscad/viewer_compressed.js | 78 +++++++++++++++++----------------- 2 files changed, 55 insertions(+), 67 deletions(-) diff --git a/blockscad/threeViewer.js b/blockscad/threeViewer.js index 77cc3170..a2e5c5d7 100644 --- a/blockscad/threeViewer.js +++ b/blockscad/threeViewer.js @@ -11,7 +11,7 @@ var CAG = CAG || {}; Blockscad.Viewer = function(containerelement, width, height, initialdepth) { var scene = new THREE.Scene(); this.scene=scene; - var camera = new THREE.PerspectiveCamera( 45, width/height, 1, 10000 ); + var camera = new THREE.PerspectiveCamera( 45, width/height, 1, 1000 ); this.camera=camera; this.camera.position.set( 50, -50, 50 ); this.camera.up.set( 0, 0, 1 ); @@ -19,25 +19,15 @@ Blockscad.Viewer = function(containerelement, width, height, initialdepth) { var renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer=renderer; this.renderer.setClearColor( 0xEDEDED, 1.0 ); - this.renderer.shadowMap.enabled = true; - this.renderer.shadowMapSoft = false; - this.renderer.shadowCameraNear = 1; - this.renderer.shadowCameraFar = this.camera.far; - this.renderer.shadowCameraFov = 45; - this.renderer.shadowMapBias = 0.0039; - this.renderer.shadowMapDarkness = 0.5; - this.renderer.shadowMapWidth = 1024; - this.renderer.shadowMapHeight = 1024; this.renderer.setSize( width, height ); var controls = new THREE.OrbitControls( this.camera, this.renderer.domElement ); this.controls=controls; - this.controls.enableDamping = true; - this.controls.dampingFactor = 0.5; + this.controls.enableDamping = false; this.controls.enableZoom = true; this.controls.zoomSpeed = 3; var light = new THREE.DirectionalLight(0xffffff, 1); this.light=light; - this.light.castShadow = true; + this.light.castShadow = false; this.light.position.copy( this.camera.position ); this.scene.add(this.light); this.axes = this.buildAxes( 200 ); @@ -45,16 +35,15 @@ Blockscad.Viewer = function(containerelement, width, height, initialdepth) { this.scene.add(this.axes); this.scene.add(this.GridPlane); $(containerelement).append(this.renderer.domElement); - var this_viewer =this; - //render loop - var render = function () { - requestAnimationFrame( render ); - this_viewer.controls.update(); - this_viewer.light.position.copy(this_viewer.camera.position ); - this_viewer.renderer.render(this_viewer.scene, this_viewer.camera); - }; - render(); - + this.renderer.render(this.scene, this.camera); + var this_viewer=this; + //render function + var render = function(){ + this_viewer.light.position.copy( this_viewer.camera.position ); + this_viewer.renderer.render( this_viewer.scene, this_viewer.camera); + } + this.render=render; + this.controls.addEventListener( 'change', render); }; Blockscad.Viewer.prototype = { @@ -69,13 +58,14 @@ Blockscad.Viewer.prototype = { this.threeMesh = Blockscad.Viewer.csgToThreeMesh(csg); this.threeMesh.name="threeMesh"; this.scene.add(this.threeMesh); + this.render(); }, rendered_resize: function(width, height) { this.renderer.setSize( width, height ); this.camera.aspect = width / height; this.camera.updateProjectionMatrix(); - + this.render(); }, viewReset: function() { @@ -123,10 +113,7 @@ Blockscad.Viewer.prototype = { this.camera.position.set( 50, -50, 50 ); this.camera.lookAt( new THREE.Vector3( 0, 0, 0 ) ); } - - }, - supported: function() { - return !!this.gl; + this.render(); }, @@ -139,6 +126,7 @@ Blockscad.Viewer.prototype = { this.scene.add(this.axes); this.scene.add(this.GridPlane); } + this.render(); }, buildLine: function( src, dst, colorHex, dashed, lineWidth ){ var geom = new THREE.Geometry(),mat; diff --git a/blockscad/viewer_compressed.js b/blockscad/viewer_compressed.js index dc387227..6ddc1511 100644 --- a/blockscad/viewer_compressed.js +++ b/blockscad/viewer_compressed.js @@ -1,13 +1,13 @@ // Do not edit this file; automatically generated by blockscad_build.py. "use strict"; var Blockscad=Blockscad||{},CSG=CSG||{},CAG=CAG||{}; -Blockscad.Viewer=function(h,l,f,t){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,l/f,1,1E4);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.shadowMap.enabled=!0;this.renderer.shadowMapSoft=!1;this.renderer.shadowCameraNear=1;this.renderer.shadowCameraFar=this.camera.far;this.renderer.shadowCameraFov=45;this.renderer.shadowMapBias= -.0039;this.renderer.shadowMapDarkness=.5;this.renderer.shadowMapWidth=1024;this.renderer.shadowMapHeight=1024;this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!0;this.controls.dampingFactor=.5;this.controls.enableZoom=!0;this.controls.zoomSpeed=3;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!0;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(200); -this.GridPlane=this.buildGridPlane(200);this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);var c=this,m=function(){requestAnimationFrame(m);c.controls.update();c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};m()}; -Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh)},rendered_resize:function(h,l){this.renderer.setSize(h,l);this.camera.aspect=h/l;this.camera.updateProjectionMatrix()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.controls.reset(),this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0, +Blockscad.Viewer=function(h,l,f,t){this.scene=new THREE.Scene;this.camera=new THREE.PerspectiveCamera(45,l/f,1,1E3);this.camera.position.set(50,-50,50);this.camera.up.set(0,0,1);this.camera.lookAt(new THREE.Vector3(0,0,0));this.renderer=new THREE.WebGLRenderer({antialias:!0});this.renderer.setClearColor(15592941,1);this.renderer.setSize(l,f);this.controls=new THREE.OrbitControls(this.camera,this.renderer.domElement);this.controls.enableDamping=!1;this.controls.enableZoom=!0;this.controls.zoomSpeed= +3;this.light=new THREE.DirectionalLight(16777215,1);this.light.castShadow=!1;this.light.position.copy(this.camera.position);this.scene.add(this.light);this.axes=this.buildAxes(200);this.GridPlane=this.buildGridPlane(200);this.scene.add(this.axes);this.scene.add(this.GridPlane);$(h).append(this.renderer.domElement);this.renderer.render(this.scene,this.camera);var c=this;this.render=h=function(){c.light.position.copy(c.camera.position);c.renderer.render(c.scene,c.camera)};this.controls.addEventListener("change", +h)}; +Blockscad.Viewer.prototype={setCsg:function(h){this.scene.remove(this.scene.getObjectByName("threeMesh"));this.threeMesh=Blockscad.Viewer.csgToThreeMesh(h);this.threeMesh.name="threeMesh";this.scene.add(this.threeMesh);this.render()},rendered_resize:function(h,l){this.renderer.setSize(h,l);this.camera.aspect=h/l;this.camera.updateProjectionMatrix();this.render()},viewReset:function(){var h=document.getElementById("viewMenu");"top"==h.value?(this.controls.reset(),this.camera.position.set(0,0,50),this.camera.lookAt(new THREE.Vector3(0, 0,0))):"front"==h.value?(this.controls.reset(),this.camera.position.set(0,-50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"left"==h.value?(this.controls.reset(),this.camera.position.set(-50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"right"==h.value?(this.controls.reset(),this.camera.position.set(50,0,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"bottom"==h.value?(this.controls.reset(),this.camera.position.set(0,0,-50),this.camera.lookAt(new THREE.Vector3(0,0,0))):"back"==h.value? -(this.controls.reset(),this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.controls.reset(),this.camera.position.set(50,-50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)))},supported:function(){return!!this.gl},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes), -this.scene.add(this.GridPlane))},buildLine:function(h,l,f,t,c){var m=new THREE.Geometry;f=t?new THREE.LineDashedMaterial({linewidth:c,color:f,dashSize:1,gapSize:1}):new THREE.LineBasicMaterial({linewidth:c,color:f});m.vertices.push(h.clone());m.vertices.push(l.clone());m.computeLineDistances();return new THREE.Line(m,f,THREE.LineSegments)},buildAxes:function(h){h/=2;var l=new THREE.Object3D;l.name="axes";l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(h,0,0),16711680,!1,1));l.add(this.buildLine(new THREE.Vector3(0, +(this.controls.reset(),this.camera.position.set(0,50,0),this.camera.lookAt(new THREE.Vector3(0,0,0))):"diagonal"==h.value&&(this.controls.reset(),this.camera.position.set(50,-50,50),this.camera.lookAt(new THREE.Vector3(0,0,0)));this.render()},toggleAxes:function(h){this.scene.getObjectByName("axes")&&this.scene.getObjectByName("GridPlane")?(this.scene.remove(this.scene.getObjectByName("axes")),this.scene.remove(this.scene.getObjectByName("GridPlane"))):(this.scene.add(this.axes),this.scene.add(this.GridPlane)); +this.render()},buildLine:function(h,l,f,t,c){var m=new THREE.Geometry;f=t?new THREE.LineDashedMaterial({linewidth:c,color:f,dashSize:1,gapSize:1}):new THREE.LineBasicMaterial({linewidth:c,color:f});m.vertices.push(h.clone());m.vertices.push(l.clone());m.computeLineDistances();return new THREE.Line(m,f,THREE.LineSegments)},buildAxes:function(h){h/=2;var l=new THREE.Object3D;l.name="axes";l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(h,0,0),16711680,!1,1));l.add(this.buildLine(new THREE.Vector3(0, 0,0),new THREE.Vector3(-h,0,0),16711680,!0,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,h,0),65280,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,-h,0),65280,!0,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,h),255,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,-h),255,!0,1));l.add(this.buildLine(new THREE.Vector3(-5+h+5,-5,0),new THREE.Vector3(5+h+5,5,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(5+ h+5,-5,0),new THREE.Vector3(-5+h+5,5,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,0+h,0),new THREE.Vector3(0,5+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,5+h,0),new THREE.Vector3(5,10+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(0,5+h,0),new THREE.Vector3(-5,10+h,0),0,!1,1));l.add(this.buildLine(new THREE.Vector3(-5,0,0+h+5),new THREE.Vector3(5,0,0+h+5),0,!1,1));l.add(this.buildLine(new THREE.Vector3(-5,0,0+h+5),new THREE.Vector3(5,0,10+h+5),0,!1,1));l.add(this.buildLine(new THREE.Vector3(5, 0,10+h+5),new THREE.Vector3(-5,0,10+h+5),0,!1,1));return l},buildGridPlane:function(h){var l=new THREE.Object3D;l.name="GridPlane";h/=2;for(var f=-h;0>f;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h,f,0),14540253,!1,1));for(f=1;f<=h;f++)l.add(this.buildLine(new THREE.Vector3(f,-h,0),new THREE.Vector3(f,h,0),14540253,!1,1)),l.add(this.buildLine(new THREE.Vector3(-h,f,0),new THREE.Vector3(h, @@ -36,53 +36,53 @@ isProcessing:function(){return this.processing},clearOutputFile:function(){if(th else if("stlb"==h)l=this.currentObject.toStlBinary({webBlob:!0});else if("amf"==h)l=this.currentObject.toAMFString({producer:"OpenJSCAD.org "+version,date:new Date}),l=new Blob([l],{type:this.formatInfo(h).mimetype});else if("x3d"==h)l=this.currentObject.fixTJunctions().toX3D();else if("dxf"==h)l=this.currentObject.toDxf();else throw Error("Not supported");return l},supportedFormatsForCurrentObject:function(){if(this.currentObject instanceof CSG)return["stlb","stla","amf","x3d"];if(this.currentObject instanceof CAG)return["dxf"];throw Error("Not supported");},formatInfo:function(h){return{stla:{displayName:"STL (ASCII)",extension:"stl",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"}}[h]},generateAndSaveRenderedFile:function(){var h=this.currentObjectToBlob(), l=this.selectedFormatInfo().extension,f=$("#project-name").val();f?saveAs(h,f+"."+l):alert("Could not save",this.selectedFormatInfo().displayName," file. Please give your project a name, then try again.")}};(function(h){function l(a,b){return a-b}function f(a,b,d){for(var c=0,k=a.length;k>c;){var g=Math.floor((c+k)/2);0b&&(a=e,b=k)}return a},getPolygon:function(){var a=[new c.Vertex(this._a),new c.Vertex(this._b),new c.Vertex(this._c)];return new c.Polygon(a,null,this._halfSpace.getPlane())},toString:function(){return"[a: "+this._a+"/b: "+this._b+"/c: "+this._c+"/halfSpace: "+this._halfSpace+"/points: "+ this._points+"]"}};var g=[];g.push(this);for(var n=0;na[0].x+a[0].y+a[0].z){var d=a[0];a[0]=a[b];a[b]=d}a[b].x+a[b].y+a[b].za.normal.dot(g[2])){var C=g[2];g[2]=g[n];g[n]=C}var C=new k(g[0],g[1],g[2]),f=new k(g[0],g[2],g[1]);a=[C,f];for(n=3;na[0].x+a[0].y+a[0].z){var d=a[0];a[0]=a[b];a[b]=d}a[b].x+a[b].y+a[b].za.normal.dot(g[2])){var C=g[2];g[2]=g[n];g[n]=C}var C=new k(g[0],g[1],g[2]),f=new k(g[0],g[2],g[1]);a=[C,f];for(n=3;nA&&(A+=2*Math.PI);r.push(A);A=Math.atan2(-u,-w);0>A&&(A+=2*Math.PI);r.push(A)}var r=r.sort(l),z=r.length,v,x,h=[],m=[],y=[];for(d=-1;dd?d+z:d],u=Math.sin(A), -w=Math.cos(A),w=q.times(w*a).plus(p.times(u*a)),u=C.plus(w),w=f.plus(w),A=!1,0<=d&&1E-5>u.distanceTo(v)&&(A=!0),A||(0<=d&&(h.push(new c.Vertex(u)),m.push(new c.Vertex(w)),v=[new c.Vertex(x),new c.Vertex(w),new c.Vertex(u),new c.Vertex(v)],v=new c.Polygon(v),y.push(v)),v=u,x=w);m.reverse();y.push(new c.Polygon(h));y.push(new c.Polygon(m));d=c.fromPolygons(y);k=k.unionSub(d,!1,!1)}var t={};e.polygons.map(function(a){a.vertices.map(function(b){var c=b.getTag();c in t?b=t[c]:(b={pos:b.pos,normals:[]}, +planenormals:[]},g[d]=c);c.planenormals.push(a.plane.normal);d=n;c=k}});for(var n in g){var A=g[n],C=A.v1.pos,f=A.v2.pos;d=f.minus(C).unit();var q=A.planenormals[0].unit(),p=q.cross(d),r=[];for(d=0;dB&&(B+=2*Math.PI);r.push(B);B=Math.atan2(-m,-w);0>B&&(B+=2*Math.PI);r.push(B)}var r=r.sort(l),A=r.length,v,x,h=[],z=[],y=[];for(d=-1;dd?d+A:d],m=Math.sin(B), +w=Math.cos(B),w=q.times(w*a).plus(p.times(m*a)),m=C.plus(w),w=f.plus(w),B=!1,0<=d&&1E-5>m.distanceTo(v)&&(B=!0),B||(0<=d&&(h.push(new c.Vertex(m)),z.push(new c.Vertex(w)),v=[new c.Vertex(x),new c.Vertex(w),new c.Vertex(m),new c.Vertex(v)],v=new c.Polygon(v),y.push(v)),v=m,x=w);z.reverse();y.push(new c.Polygon(h));y.push(new c.Polygon(z));d=c.fromPolygons(y);k=k.unionSub(d,!1,!1)}var t={};e.polygons.map(function(a){a.vertices.map(function(b){var c=b.getTag();c in t?b=t[c]:(b={pos:b.pos,normals:[]}, t[c]=b);b.normals.push(a.plane.normal)})});for(var D in t){e=t[D];n=e.normals[0].unit();C=null;f=0;for(d=1;df&&(f=v,C=q);C||(C=n.randomNonParallelVector());d=n.cross(C).unit();C=d.cross(n);d=c.sphere({center:e.pos,radius:a,resolution:b,axes:[n,d,C]});k=k.unionSub(d,!1,!1)}return k},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;var a={},b=this.isCanonicalized,d=new c.fuzzyCSGFactory;this.polygons.map(function(c){var e=c.plane,k=c.shared;b||(e=d.getPlane(e),k=d.getPolygonShared(k));e=e.getTag()+"/"+k.getTag();e in a?a[e].push(c):a[e]=[c]});var e=[],k;for(k in a){var g=a[k];if(2>g.length)e=e.concat(g);else{var n=[];c.reTesselateCoplanarPolygons(g,n);e=e.concat(n)}}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),b=new c.Vector3D(0,0,0),d=this.polygons,e=d.length,k=0;ka[1].x||b[1].ya[1].y||b[1].z a[1].z?!1:!0},cutByPlane:function(a){if(0===this.polygons.length)return new c;var b=a.normal.times(a.w),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=[],k=new c.OrthoNormalBasis(a);e.push(new c.Vertex(k.to3D(new c.Vector2D(d,-d))));e.push(new c.Vertex(k.to3D(new c.Vector2D(-d,-d))));e.push(new c.Vertex(k.to3D(new c.Vector2D(-d,d))));e.push(new c.Vertex(k.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,b,c,e){a=a.getTransformationTo(b,c,e);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},setColor: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,c=0,e=0,k={},g=[],n=0,z={},f=0,G=[],q=[],p={},r=0;a.polygons.map(function(a){a.vertices.map(function(a){++c;var b=a.getTag();b in k||(k[b]=e++,g.push(a))});var b=a.plane.getTag();b in z||(z[b]=n++,G.push(a.plane));b=a.shared.getTag();b in p||(p[b]=r++,q.push(a.shared))});for(var h=new Uint32Array(b),l=new Uint32Array(b),m=new Uint32Array(c),w=new Uint32Array(b),A=new Float64Array(3*e),v=new Float64Array(4*n),x=0,f=0;fw?(m=new c.Connector(l,h.normal,d),l=m.getTransformationTo(g,!1,0),m=g.getTransformationTo(m,!1,0)):(m=new c.Connector(l,h.normal,e),l=m.getTransformationTo(n,!1,0),m=n.getTransformationTo(m,!1,0));var w=a.transform(l),h=-h.normal.dot(k),A=w.getBounds(),w=A[1].z-A[0].z;z||(wG&&(z=!0));z&&(f=new c.Vector3D([-.5*(A[1].x+A[0].x),-.5*(A[1].y+ -A[0].y),-A[0].z]),l=l.multiply(c.Matrix4x4.translation(f)),m=c.Matrix4x4.translation(f.negated()).multiply(m),f=w,G=h,q=l,p=m);z=!1}return[q,p]},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(c){c= -c.projectToOrthoNormalBasis(a);0n)throw Error("Assertion failed");z.splice(n,1);0===z.length&&delete b[g];n=p[e].indexOf(g);if(0>n)throw Error("Assertion failed");p[e].splice(n,1);0===p[e].length&&delete p[e];n=r[k].indexOf(g);if(0>n)throw Error("Assertion failed");r[k].splice(n,1);0===r[k].length&&delete r[k]},z=function(a,c,d){var e=a.getTag(),k=c.getTag();if(e==k)throw Error("Assertion failed");var g=e+"/"+k;if(k+"/"+e in b)return l(c,a,null), -null;a={vertex0:a,vertex1:c,polygonindex:d};g in b?b[g].push(a):b[g]=[a];e in p?p[e].push(g):p[e]=[g];k in r?r[k].push(g):r[k]=[g];return g},f=a.polygons.slice(0);for(;;){g=!0;for(q in b)g=!1,k[q]=!0;if(g)break;for(d=!1;;){g=null;for(q in k){g=q;break}if(null===g)break;e=!0;if(g in b){g=b[g];if(0===g.length)throw Error("Assertion failed");for(var g=g[0],m=0;2>m;m++){var u=0===m?g.vertex0:g.vertex1,h=0===m?g.vertex1:g.vertex0,w=u.getTag(),A=h.getTag(),v=[];0===m?w in r&&(v=r[w]):w in p&&(v=p[w]);for(var x= -0;xE&&1E-10>t.plus(y.times(E)).distanceToSquared(D)){d=n.polygonindex;e=f[d];u=n.vertex1.getTag();m=-1;for(w=0;wm)throw Error("Assertion failed");u=e.vertices.slice(0); -u.splice(m,0,h);e=new c.Polygon(u,e.shared);f[d]=e;l(n.vertex0,n.vertex1,d);e=z(n.vertex0,h,d);h=z(h,n.vertex1,d);null!==e&&(k[e]=!0);null!==h&&(k[h]=!0);e=!1;m=2;d=!0;break}}}}}e&&delete k[q]}if(!d)break}g=c.fromPolygons(f);g.properties=a.properties;g.isCanonicalized=!0;g.isRetesselated=!0;a=g}g=!0;for(q in b){g=!1;break}g||OpenJsCad.log("!sidemapisempty");return 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, +0,0],[0,0,-1],e),A=!0,f=0,G=0,q,p,r;for(r in b){var h=b[r],l=h.normal.times(h.w),m;m=h.normal.cross(d).length();var w=h.normal.cross(e).length();m>w?(m=new c.Connector(l,h.normal,d),l=m.getTransformationTo(g,!1,0),m=g.getTransformationTo(m,!1,0)):(m=new c.Connector(l,h.normal,e),l=m.getTransformationTo(n,!1,0),m=n.getTransformationTo(m,!1,0));var w=a.transform(l),h=-h.normal.dot(k),B=w.getBounds(),w=B[1].z-B[0].z;A||(wG&&(A=!0));A&&(f=new c.Vector3D([-.5*(B[1].x+B[0].x),-.5*(B[1].y+ +B[0].y),-B[0].z]),l=l.multiply(c.Matrix4x4.translation(f)),m=c.Matrix4x4.translation(f.negated()).multiply(m),f=w,G=h,q=l,p=m);A=!1}return[q,p]},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(c){c= +c.projectToOrthoNormalBasis(a);0n)throw Error("Assertion failed");A.splice(n,1);0===A.length&&delete b[g];n=p[e].indexOf(g);if(0>n)throw Error("Assertion failed");p[e].splice(n,1);0===p[e].length&&delete p[e];n=r[k].indexOf(g);if(0>n)throw Error("Assertion failed");r[k].splice(n,1);0===r[k].length&&delete r[k]},A=function(a,c,d){var e=a.getTag(),k=c.getTag();if(e==k)throw Error("Assertion failed");var g=e+"/"+k;if(k+"/"+e in b)return l(c,a,null), +null;a={vertex0:a,vertex1:c,polygonindex:d};g in b?b[g].push(a):b[g]=[a];e in p?p[e].push(g):p[e]=[g];k in r?r[k].push(g):r[k]=[g];return g},f=a.polygons.slice(0);for(;;){g=!0;for(q in b)g=!1,k[q]=!0;if(g)break;for(d=!1;;){g=null;for(q in k){g=q;break}if(null===g)break;e=!0;if(g in b){g=b[g];if(0===g.length)throw Error("Assertion failed");for(var g=g[0],m=0;2>m;m++){var u=0===m?g.vertex0:g.vertex1,h=0===m?g.vertex1:g.vertex0,w=u.getTag(),B=h.getTag(),v=[];0===m?w in r&&(v=r[w]):w in p&&(v=p[w]);for(var x= +0;xE&&1E-10>t.plus(y.times(E)).distanceToSquared(D)){d=n.polygonindex;e=f[d];u=n.vertex1.getTag();m=-1;for(w=0;wm)throw Error("Assertion failed");u=e.vertices.slice(0); +u.splice(m,0,h);e=new c.Polygon(u,e.shared);f[d]=e;l(n.vertex0,n.vertex1,d);e=A(n.vertex0,h,d);h=A(h,n.vertex1,d);null!==e&&(k[e]=!0);null!==h&&(k[h]=!0);e=!1;m=2;d=!0;break}}}}}e&&delete k[q]}if(!d)break}g=c.fromPolygons(f);g.properties=a.properties;g.isCanonicalized=!0;g.isRetesselated=!0;a=g}g=!0;for(q in b){g=!1;break}g||OpenJsCad.log("!sidemapisempty");return 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,b){return b.map(function(b,c){return b+(0===a?0:a[c])})},0);return 1==b.length?b[0]:b}};c.parseOption=function(a,b,c){a&&b in a&&(c=a[b]);return c};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,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 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."),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,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,"resolution",c.defaultResolution3D),k,g;if(0>=d)throw Error("Radius should be positive");if(5E-4>d)return console.log("Throwing out a zero-radius sphere."),new c;"axes"in a?(k=a.axes[0].unit().times(d),g=a.axes[1].unit().times(d),a=a.axes[2].unit().times(d)):(k=(new c.Vector3D([1,0,0])).times(d),g=(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),n,z=[],f=0;f<=e;f++){var h=2*Math.PI*f/e,h=k.times(Math.cos(h)).plus(g.times(Math.sin(h)));if(0e&&(e=4);for(var d=Math.round(e/4),n,A=[],f=0;f<=e;f++){var h=2*Math.PI*f/e,h=k.times(Math.cos(h)).plus(g.times(Math.sin(h)));if(0g||0>k)throw Error("Radius should be non-negative");if(0===g&&0===k)throw Error("Either radiusStart or radiusEnd should be nonzero"); if(5E-4>Math.abs(e.z-d.z))return console.log("throwing out a zero-height cylinder"),new c;var f=c.parseOptionAsInt(a,"resolution",c.defaultResolution2D),C=e.minus(d);a=C.unit();var h=a.randomNonParallelVector().unit(),q=h.cross(a).unit(),p=new c.Vertex(d),r=new c.Vertex(e),l=[];if(0n&&(l.push(new c.Polygon([p,r,b(0,0,k)])),l.push(new c.Polygon([b(0,0,k),r,b(1,0,g)])),l.push(new c.Polygon([p,b(0,1,k),r])),l.push(new c.Polygon([b(0,1,k),b(1,1,g),r])))}f=c.fromPolygons(l);f.properties.cylinder=new c.Properties;f.properties.cylinder.start=new c.Connector(d,a.negated(),h);f.properties.cylinder.end=new c.Connector(e, a,h);e=d.plus(C.times(.5));g=h.rotate(d,a,-n/2).times((k+g)/2);k=g.cross(a);f.properties.cylinder.facepointH=new c.Connector(e.plus(g),g,a);f.properties.cylinder.facepointH90=new c.Connector(e.plus(k),k,a);return f};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),k=d.minus(b),g;g=Math.abs(k.x)>Math.abs(k.y)?new c.Vector3D(0,1,0):new c.Vector3D(1,0,0);var n=c.parseOptionAs3DVector(a,"normal", g);a=c.parseOptionAsInt(a,"resolution",c.defaultResolution3D);4>a&&(a=4);g=[];var f=Math.floor(.25*a);if(1E-10>k.length())return c.sphere({center:b,radius:e,resolution:a});for(var h=k.unit().times(e),k=h.cross(n).unit().times(e),e=k.cross(h).unit().times(e),l,n=0;n<=a;n++){var q=2*Math.PI*n/a,q=k.times(Math.cos(q)).plus(e.times(Math.sin(q)));if(0e&&(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 k=d.minus(a);if(0>k.x||0>k.y||0>k.z)throw"roundradius <= radius!";e=c.sphere({radius:1,resolution:e});e=e.scale(a);1E-5Math.abs(c)?b=new m:0>c&&(b=b.flipped());return b},solidFromSlices:function(a){var b=[],d=null,e=null,k=null,g=null,n=2,f=!1,h,l=null;a&&(f=Boolean(a.loop),a.numslices&&(n=a.numslices),a.callback&&(h=a.callback));if(!h){var q=new c.Polygon.createFromPoints([[0,0,0],[1,0,0],[1,1,0],[0,1,0]]);h=function(a,b){return 0==a||1==a?q.translate([0, 0,a]):null}}a=0;for(--n;a<=n;a++)if(d=h.call(this,a/n,a)){if(!(d instanceof c.Polygon))throw Error("CSG.Polygon.solidFromSlices callback error: CSG.Polygon expected");d.checkIfConvex();e?(null===l&&(l=0>e.plane.signedDistanceToPoint(d.vertices[0].pos)),this._addWalls(b,e,d,l)):k=d;e=d}g=d;f?k.vertices.length==g.vertices.length&&k.vertices.every(function(a,b){return a.pos.equals(g.vertices[b].pos)})||this._addWalls(b,g,k,l):(b.unshift(l?k:k.flipped()),b.push(l?g.flipped():g));return c.fromPolygons(b)}, _addWalls:function(a,b,d,e){b=b.vertices.slice(0);var k=d.vertices.slice(0);d=d.shared||null;b[0].pos.equals(b[b.length-1].pos)||b.push(b[0]);k[0].pos.equals(k[k.length-1].pos)||k.push(k[0]);e&&(b=b.reverse(),k=k.reverse());e=k.length-1;for(var g=b.length-1,n=e-g,f=0n,l=[],n=Math.abs(n);0q){l[p].len=q;l.index=p;break}}else if(f)for(n=0;nq){l[p].len=q;l.index=p;break}l.sort(t);n=b[0];q=k[0];for(var m,J,B=p=0,u=e+g;p+Barguments.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= +k[n].pos.distanceToSquared(k[n+1].pos),p=l.length-1;0<=p;p--)if(l[p].len>q){l[p].len=q;l.index=p;break}l.sort(t);n=b[0];q=k[0];for(var m,J,z=p=0,u=e+g;p+zarguments.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= function(a,b,c,e){return 0<=b.minus(a).cross(c.minus(b)).dot(e)};c.Polygon.isStrictlyConvexPoint=function(a,b,c,e){return 1E-5<=b.minus(a).cross(c.minus(b)).dot(e)};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;db)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"); @@ -120,8 +120,8 @@ for(c=0;cd;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]- -a.elements[d];return new c.Matrix4x4(b)},multiply:function(a){var b=this.elements[0],d=this.elements[1],e=this.elements[2],k=this.elements[3],g=this.elements[4],n=this.elements[5],f=this.elements[6],h=this.elements[7],l=this.elements[8],m=this.elements[9],p=this.elements[10],r=this.elements[11],t=this.elements[12],B=this.elements[13],u=this.elements[14],w=this.elements[15],A=a.elements[0],v=a.elements[1],x=a.elements[2],y=a.elements[3],F=a.elements[4],D=a.elements[5],E=a.elements[6],H=a.elements[7], -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*F+e*K+k*O;I[1]=b*v+d*D+e*L+k*P;I[2]=b*x+d*E+e*N+k*Q;I[3]=b*y+d*H+e*M+k*a;I[4]=g*A+n*F+f*K+h*O;I[5]=g*v+n*D+f*L+h*P;I[6]=g*x+n*E+f*N+h*Q;I[7]=g*y+n*H+f*M+h*a;I[8]=l*A+m*F+p*K+r*O;I[9]=l*v+m*D+p*L+r*P;I[10]=l*x+m*E+p*N+r*Q;I[11]=l*y+m*H+p*M+r*a;I[12]=t*A+B*F+u*K+w*O;I[13]=t*v+B*D+u*L+w*P;I[14]=t*x+B*E+u*N+w*Q;I[15]=t*y+B*H+u*M+w*a;return new c.Matrix4x4(I)}, +a.elements[d];return new c.Matrix4x4(b)},multiply:function(a){var b=this.elements[0],d=this.elements[1],e=this.elements[2],k=this.elements[3],g=this.elements[4],n=this.elements[5],f=this.elements[6],h=this.elements[7],l=this.elements[8],m=this.elements[9],p=this.elements[10],r=this.elements[11],t=this.elements[12],z=this.elements[13],u=this.elements[14],w=this.elements[15],B=a.elements[0],v=a.elements[1],x=a.elements[2],y=a.elements[3],F=a.elements[4],D=a.elements[5],E=a.elements[6],H=a.elements[7], +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*B+d*F+e*K+k*O;I[1]=b*v+d*D+e*L+k*P;I[2]=b*x+d*E+e*N+k*Q;I[3]=b*y+d*H+e*M+k*a;I[4]=g*B+n*F+f*K+h*O;I[5]=g*v+n*D+f*L+h*P;I[6]=g*x+n*E+f*N+h*Q;I[7]=g*y+n*H+f*M+h*a;I[8]=l*B+m*F+p*K+r*O;I[9]=l*v+m*D+p*L+r*P;I[10]=l*x+m*E+p*N+r*Q;I[11]=l*y+m*H+p*M+r*a;I[12]=t*B+z*F+u*K+w*O;I[13]=t*v+z*D+u*L+w*P;I[14]=t*x+z*E+u*N+w*Q;I[15]=t*y+z*H+u*M+w*a;return new c.Matrix4x4(I)}, 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 k=b*this.elements[4]+d*this.elements[5]+e*this.elements[6]+1*this.elements[7],g=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,k*=b,g*=b); return new c.Vector3D(a,k,g)},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 k=b*this.elements[1]+d*this.elements[5]+e*this.elements[9]+1*this.elements[13],g=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,k*=b,g*=b);return new c.Vector3D(a,k,g)},rightMultiply1x2Vector:function(a){var b= 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], @@ -144,12 +144,12 @@ 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= 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); 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); 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 e=b.y-a.y;0>e&&(c=-c,e=-e);return a.x+(0>=c?0:c>=e?1:1E-10>e?.5:c/e)*(b.x-a.x)};c.reTesselateCoplanarPolygons=function(a,b){var d=a.length;if(0v)v=y;y in G||(G[y]={});G[y][r]=!0}A>=v?(B=[],u=0,w=-1):(A in m||(m[A]=[]),m[A].push(r))}B.reverse();w=u-w-1;n.push(B);h.push(w)}var d=[],E;for(E in G)d.push(E);d.sort(l);q=[];p=[];for(t= -0;t=u&&(v=0);if(B[v].y!=E)break;r=v}y=H-1;0>y&&(y=u-1);B[y].y==E&&(H=y);r!=x.leftvertexindex&&r==H?(q.splice(D,1),--D):(x.leftvertexindex=r,x.rightvertexindex=H,x.topleft=B[r],x.topright=B[H],v=r+1,v>=u&&(v=0),x.bottomleft=B[v],y=H-1,0>y&&(y=u-1),x.bottomright=B[y])}if(t>=d.length-1)q=[],A=null;else{A=Number(d[t+1]);var K= -.5*(E+A),F=m[F],L;for(L in F){r=F[L];B=n[r];u=B.length;for(D=v=h[r];;){x=D+1;x>=u&&(x=0);if(B[x].y!=E)break;if(x==v)break;D=x}for(H=v;;){x=H-1;0>x&&(x=u-1);if(B[x].y!=E)break;if(x==D)break;H=x}v=D+1;v>=u&&(v=0);y=H-1;0>y&&(y=u-1);f(q,{polygonindex:r,leftvertexindex:D,rightvertexindex:H,topleft:B[D],topright:B[H],bottomleft:B[v],bottomright:B[y]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1: -dB&&1E-5>u&&(x.topleft=r.topleft,x.leftline=r.leftline,x.bottomleft=r.bottomleft,w.splice(w.length-1,1))),w.push(x);if(0y.bottomleft.distanceTo(v.topleft)&&1E-5>y.bottomright.distanceTo(v.topright))){A[r]=!0;B=v.leftline.direction().x-y.leftline.direction().x;u=v.rightline.direction().x- -y.rightline.direction().x;F=1E-5>Math.abs(B);u=(D=1E-5>Math.abs(u))||0<=u;(F||0<=B)&&u&&(v.outpolygon=y.outpolygon,v.leftlinecontinues=F,v.rightlinecontinues=D,E[r]=!0);break}for(r=0;rv)v=y;y in G||(G[y]={});G[y][r]=!0}B>=v?(z=[],u=0,w=-1):(B in m||(m[B]=[]),m[B].push(r))}z.reverse();w=u-w-1;n.push(z);h.push(w)}var d=[],E;for(E in G)d.push(E);d.sort(l);q=[];p=[];for(t= +0;t=u&&(v=0);if(z[v].y!=E)break;r=v}y=H-1;0>y&&(y=u-1);z[y].y==E&&(H=y);r!=x.leftvertexindex&&r==H?(q.splice(D,1),--D):(x.leftvertexindex=r,x.rightvertexindex=H,x.topleft=z[r],x.topright=z[H],v=r+1,v>=u&&(v=0),x.bottomleft=z[v],y=H-1,0>y&&(y=u-1),x.bottomright=z[y])}if(t>=d.length-1)q=[],B=null;else{B=Number(d[t+1]);var K= +.5*(E+B),F=m[F],L;for(L in F){r=F[L];z=n[r];u=z.length;for(D=v=h[r];;){x=D+1;x>=u&&(x=0);if(z[x].y!=E)break;if(x==v)break;D=x}for(H=v;;){x=H-1;0>x&&(x=u-1);if(z[x].y!=E)break;if(x==D)break;H=x}v=D+1;v>=u&&(v=0);y=H-1;0>y&&(y=u-1);f(q,{polygonindex:r,leftvertexindex:D,rightvertexindex:H,topleft:z[D],topright:z[H],bottomleft:z[v],bottomright:z[y]},function(a,b){var d=c.interpolateBetween2DPointsForY(a.topleft,a.bottomleft,K),e=c.interpolateBetween2DPointsForY(b.topleft,b.bottomleft,K);return d>e?1: +dz&&1E-5>u&&(x.topleft=r.topleft,x.leftline=r.leftline,x.bottomleft=r.bottomleft,w.splice(w.length-1,1))),w.push(x);if(0y.bottomleft.distanceTo(v.topleft)&&1E-5>y.bottomright.distanceTo(v.topright))){B[r]=!0;z=v.leftline.direction().x-y.leftline.direction().x;u=v.rightline.direction().x- +y.rightline.direction().x;F=1E-5>Math.abs(z);u=(D=1E-5>Math.abs(u))||0<=u;(F||0<=z)&&u&&(v.outpolygon=y.outpolygon,v.leftlinecontinues=F,v.rightlinecontinues=D,E[r]=!0);break}for(r=0;r>=1});this.lookuptable[c]=k}return k}};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= 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 k= @@ -197,8 +197,8 @@ normalVector:e.rotateZ(d),flipped:0>b.z})),g=0;gb)var h=new c.Connector(a,e.rotateZ(-b),k),g=g.concat(this._toPlanePolygons({toConnector:f,flipped:!0})),g=g.concat(this._toPlanePolygons({toConnector:h}));for(var l=h=b/d;l<=b+1E-5;l+=h)d=new c.Connector(a,e.rotateZ(-l),k),g=g.concat(this._toWallPolygons({toConnector1:f,toConnector2:d})),f=d;return c.fromPolygons(g).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,"tsteps",0);3>b&&(b=3);a=Math.ceil(a/b);1>a&&(a=1);for(var k=m.fromPoints([[-.001,1E5],[2E5,1E5],[2E5,-1E5],[-.001,-1E5]]),g=m.fromPoints([[.001,1E5],[-2E5,1E5],[-2E5,-1E5],[.001,-1E5]]),f=this.translate([e,0,0]),k=f.subtract(k),g=f.subtract(g),g=0!=k.sides.length?k.mirroredX().union(g):g,g=g.translate([-e,0,0]),f=[],k=0;ka.angle?1:this.distancea.distance?1:0}};ConvexHull=function(){this.indices= +h[1]=t.rightMultiply1x3Vector(h[1]);h[2]=q.rightMultiply1x3Vector(h[2]);h[3]=q.rightMultiply1x3Vector(h[3]);q=(h[3]._x-h[0]._x)/a;t=(h[3]._y-h[0]._y)/a;for(var p=(h[3]._z-h[0]._z)/a,r=(h[2]._x-h[1]._x)/a,J=(h[2]._y-h[1]._y)/a,z=(h[2]._z-h[1]._z)/a,u=0;ua.angle?1:this.distancea.distance?1:0}};ConvexHull=function(){this.indices= this.points=null;this.getIndices=function(){return this.indices};this.clear=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-this.points[a].y)};this.compute=function(a){this.indices=null;if(!(3>a.length)){this.points=a;var b=0;for(a=1;ad&&(d+=Math.PI),e=this.distance(b,a),c.push(new 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.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