From 350a181265cbb44d2dcb6ea60b72f02adc4fb0e0 Mon Sep 17 00:00:00 2001
From: Amanda Ghassaei <amandaghassaei@gmail.com>
Date: Wed, 21 Jan 2015 19:22:47 -0500
Subject: [PATCH] z axis is up

---
 dependencies/OrbitControls.js | 262 +++++++++++++++++++++++-----------
 js/models/lattice.js          |   5 +
 js/models/threeModel.js       |   2 +
 js/threeViews/latticeView.js  |  16 +--
 4 files changed, 192 insertions(+), 93 deletions(-)

diff --git a/dependencies/OrbitControls.js b/dependencies/OrbitControls.js
index 936ffacb..4af88f78 100644
--- a/dependencies/OrbitControls.js
+++ b/dependencies/OrbitControls.js
@@ -34,6 +34,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 	// "target" sets the location of focus, where the control orbits around
 	// and where it pans with respect to.
 	this.target = new THREE.Vector3();
+
 	// center is old, deprecated; use "target" instead
 	this.center = this.target;
 
@@ -41,6 +42,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 	// backwards compatibility
 	this.noZoom = false;
 	this.zoomSpeed = 1.0;
+
 	// Limits to how far you can dolly in and out
 	this.minDistance = 0;
 	this.maxDistance = Infinity;
@@ -62,11 +64,20 @@ THREE.OrbitControls = function ( object, domElement ) {
 	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 disable use of the keys
 	this.noKeys = false;
+
 	// 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
 
@@ -81,25 +92,43 @@ THREE.OrbitControls = function ( object, domElement ) {
 	var panStart = new THREE.Vector2();
 	var panEnd = new THREE.Vector2();
 	var panDelta = new THREE.Vector2();
+	var panOffset = new THREE.Vector3();
+
+	var offset = new THREE.Vector3();
 
 	var dollyStart = new THREE.Vector2();
 	var dollyEnd = new THREE.Vector2();
 	var dollyDelta = new THREE.Vector2();
 
+	var theta;
+	var phi;
 	var phiDelta = 0;
 	var thetaDelta = 0;
 	var scale = 1;
 	var pan = new THREE.Vector3();
 
 	var lastPosition = new THREE.Vector3();
+	var lastQuaternion = new THREE.Quaternion();
 
 	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();
+
+	// 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();
+
 	// events
 
 	var changeEvent = { type: 'change' };
-
+	var startEvent = { type: 'start'};
+	var endEvent = { type: 'end'};
 
 	this.rotateLeft = function ( angle ) {
 
@@ -128,12 +157,12 @@ THREE.OrbitControls = function ( object, domElement ) {
 	// pass in distance in world space to move left
 	this.panLeft = function ( distance ) {
 
-		var panOffset = new THREE.Vector3();
 		var te = this.object.matrix.elements;
+
 		// get X column of matrix
-		panOffset.set( te[0], te[1], te[2] );
-		panOffset.multiplyScalar(-distance);
-		
+		panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
+		panOffset.multiplyScalar( - distance );
+
 		pan.add( panOffset );
 
 	};
@@ -141,18 +170,19 @@ THREE.OrbitControls = function ( object, domElement ) {
 	// pass in distance in world space to move up
 	this.panUp = function ( distance ) {
 
-		var panOffset = new THREE.Vector3();
 		var te = this.object.matrix.elements;
+
 		// get Y column of matrix
-		panOffset.set( te[4], te[5], te[6] );
-		panOffset.multiplyScalar(distance);
-		
+		panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
+		panOffset.multiplyScalar( distance );
+
 		pan.add( panOffset );
+
 	};
-	
-	// main entry point; pass in Vector2 of change desired in pixel space,
+
+	// pass in x,y of change desired in pixel space,
 	// right and down are positive
-	this.pan = function ( delta ) {
+	this.pan = function ( deltaX, deltaY ) {
 
 		var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
 
@@ -164,20 +194,21 @@ THREE.OrbitControls = function ( object, domElement ) {
 			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 );
+			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 * delta.x * targetDistance / element.clientHeight );
-			scope.panUp( 2 * delta.y * targetDistance / element.clientHeight );
+			scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
+			scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
 
 		} else if ( scope.object.top !== undefined ) {
 
 			// orthographic
-			scope.panLeft( delta.x * (scope.object.right - scope.object.left) / element.clientWidth );
-			scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / element.clientHeight );
+			scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
+			scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
 
 		} else {
 
-			// camera neither orthographic or perspective - warn user
+			// camera neither orthographic or perspective
 			console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
 
 		}
@@ -211,17 +242,21 @@ THREE.OrbitControls = function ( object, domElement ) {
 	this.update = function () {
 
 		var position = this.object.position;
-		var offset = position.clone().sub( this.target );
+
+		offset.copy( position ).sub( this.target );
+
+		// rotate offset to "y-axis-is-up" space
+		offset.applyQuaternion( quat );
 
 		// angle from z-axis around y-axis
 
-		var theta = Math.atan2( offset.x, offset.z );
+		theta = Math.atan2( offset.x, offset.z );
 
 		// angle from y-axis
 
-		var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
+		phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
 
-		if ( this.autoRotate ) {
+		if ( this.autoRotate && state === STATE.NONE ) {
 
 			this.rotateLeft( getAutoRotationAngle() );
 
@@ -230,6 +265,9 @@ THREE.OrbitControls = function ( object, domElement ) {
 		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 ) );
 
@@ -240,7 +278,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		// 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( pan );
 
@@ -248,6 +286,9 @@ THREE.OrbitControls = function ( object, domElement ) {
 		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 );
@@ -255,19 +296,48 @@ THREE.OrbitControls = function ( object, domElement ) {
 		thetaDelta = 0;
 		phiDelta = 0;
 		scale = 1;
-		pan.set(0,0,0);
+		pan.set( 0, 0, 0 );
 
-		if ( lastPosition.distanceTo( this.object.position ) > 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 ( lastPosition.distanceToSquared( this.object.position ) > EPS
+		    || 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS ) {
 
 			this.dispatchEvent( changeEvent );
 
 			lastPosition.copy( this.object.position );
+			lastQuaternion.copy (this.object.quaternion );
 
 		}
 
 	};
 
 
+	this.reset = function () {
+
+		state = STATE.NONE;
+
+		this.target.copy( this.target0 );
+		this.object.position.copy( this.position0 );
+
+		this.update();
+
+	};
+
+	this.getPolarAngle = function () {
+
+		return phi;
+
+	};
+
+	this.getAzimuthalAngle = function () {
+
+		return theta
+
+	};
+
 	function getAutoRotationAngle() {
 
 		return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
@@ -282,25 +352,25 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function onMouseDown( event ) {
 
-		if ( scope.enabled === false ) { return; }
+		if ( scope.enabled === false ) return;
 		event.preventDefault();
 
-		if ( event.button === 0 ) {
-			if ( scope.noRotate === true ) { return; }
+		if ( event.button === scope.mouseButtons.ORBIT ) {
+			if ( scope.noRotate === true ) return;
 
 			state = STATE.ROTATE;
 
 			rotateStart.set( event.clientX, event.clientY );
 
-		} else if ( event.button === 1 ) {
-			if ( scope.noZoom === true ) { return; }
+		} else if ( event.button === scope.mouseButtons.ZOOM ) {
+			if ( scope.noZoom === true ) return;
 
 			state = STATE.DOLLY;
 
 			dollyStart.set( event.clientX, event.clientY );
 
-		} else if ( event.button === 2 ) {
-			if ( scope.noPan === true ) { return; }
+		} else if ( event.button === scope.mouseButtons.PAN ) {
+			if ( scope.noPan === true ) return;
 
 			state = STATE.PAN;
 
@@ -308,9 +378,11 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		}
 
-		// Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
-		scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
-		scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
+		if ( state !== STATE.NONE ) {
+			document.addEventListener( 'mousemove', onMouseMove, false );
+			document.addEventListener( 'mouseup', onMouseUp, false );
+			scope.dispatchEvent( startEvent );
+		}
 
 	}
 
@@ -331,6 +403,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 			// rotating across whole screen goes 360 degrees around
 			scope.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
 			scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
 
@@ -361,15 +434,14 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 			panEnd.set( event.clientX, event.clientY );
 			panDelta.subVectors( panEnd, panStart );
-			
-			scope.pan( panDelta );
+
+			scope.pan( panDelta.x, panDelta.y );
 
 			panStart.copy( panEnd );
 
 		}
 
-		// Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
-		scope.update();
+		if ( state !== STATE.NONE ) scope.update();
 
 	}
 
@@ -377,25 +449,27 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		if ( scope.enabled === false ) return;
 
-		// Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
-		scope.domElement.removeEventListener( 'mousemove', onMouseMove, false );
-		scope.domElement.removeEventListener( 'mouseup', onMouseUp, false );
-
+		document.removeEventListener( 'mousemove', onMouseMove, false );
+		document.removeEventListener( 'mouseup', onMouseUp, false );
+		scope.dispatchEvent( endEvent );
 		state = STATE.NONE;
 
 	}
 
 	function onMouseWheel( event ) {
 
-		if ( scope.enabled === false || scope.noZoom === true ) return;
+		if ( scope.enabled === false || scope.noZoom === true || state !== STATE.NONE ) return;
+
+		event.preventDefault();
+		event.stopPropagation();
 
 		var delta = 0;
 
-		if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
+		if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
 
 			delta = event.wheelDelta;
 
-		} else if ( event.detail ) { // Firefox
+		} else if ( event.detail !== undefined ) { // Firefox
 
 			delta = - event.detail;
 
@@ -411,55 +485,51 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		}
 
+		scope.update();
+		scope.dispatchEvent( startEvent );
+		scope.dispatchEvent( endEvent );
+
 	}
 
 	function onKeyDown( event ) {
 
-		if ( scope.enabled === false ) { return; }
-		if ( scope.noKeys === true ) { return; }
-		if ( scope.noPan === true ) { return; }
+		if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
 
-		// pan a pixel - I guess for precise positioning?
-		// Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
-		var needUpdate = false;
-		
 		switch ( event.keyCode ) {
 
 			case scope.keys.UP:
-				scope.pan( new THREE.Vector2( 0, scope.keyPanSpeed ) );
-				needUpdate = true;
+				scope.pan( 0, scope.keyPanSpeed );
+				scope.update();
 				break;
+
 			case scope.keys.BOTTOM:
-				scope.pan( new THREE.Vector2( 0, -scope.keyPanSpeed ) );
-				needUpdate = true;
+				scope.pan( 0, - scope.keyPanSpeed );
+				scope.update();
 				break;
+
 			case scope.keys.LEFT:
-				scope.pan( new THREE.Vector2( scope.keyPanSpeed, 0 ) );
-				needUpdate = true;
+				scope.pan( scope.keyPanSpeed, 0 );
+				scope.update();
 				break;
+
 			case scope.keys.RIGHT:
-				scope.pan( new THREE.Vector2( -scope.keyPanSpeed, 0 ) );
-				needUpdate = true;
+				scope.pan( - scope.keyPanSpeed, 0 );
+				scope.update();
 				break;
-		}
-
-		// Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be
-		if ( needUpdate ) {
-
-			scope.update();
 
 		}
 
 	}
-	
+
 	function touchstart( event ) {
 
-		if ( scope.enabled === false ) { return; }
+		if ( scope.enabled === false ) return;
 
 		switch ( event.touches.length ) {
 
 			case 1:	// one-fingered touch: rotate
-				if ( scope.noRotate === true ) { return; }
+
+				if ( scope.noRotate === true ) return;
 
 				state = STATE.TOUCH_ROTATE;
 
@@ -467,7 +537,8 @@ THREE.OrbitControls = function ( object, domElement ) {
 				break;
 
 			case 2:	// two-fingered touch: dolly
-				if ( scope.noZoom === true ) { return; }
+
+				if ( scope.noZoom === true ) return;
 
 				state = STATE.TOUCH_DOLLY;
 
@@ -478,7 +549,8 @@ THREE.OrbitControls = function ( object, domElement ) {
 				break;
 
 			case 3: // three-fingered touch: pan
-				if ( scope.noPan === true ) { return; }
+
+				if ( scope.noPan === true ) return;
 
 				state = STATE.TOUCH_PAN;
 
@@ -486,14 +558,18 @@ THREE.OrbitControls = function ( object, domElement ) {
 				break;
 
 			default:
+
 				state = STATE.NONE;
 
 		}
+
+		if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
+
 	}
 
 	function touchmove( event ) {
 
-		if ( scope.enabled === false ) { return; }
+		if ( scope.enabled === false ) return;
 
 		event.preventDefault();
 		event.stopPropagation();
@@ -503,8 +579,9 @@ THREE.OrbitControls = function ( object, domElement ) {
 		switch ( event.touches.length ) {
 
 			case 1: // one-fingered touch: rotate
-				if ( scope.noRotate === true ) { return; }
-				if ( state !== STATE.TOUCH_ROTATE ) { return; }
+
+				if ( scope.noRotate === true ) return;
+				if ( state !== STATE.TOUCH_ROTATE ) return;
 
 				rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
 				rotateDelta.subVectors( rotateEnd, rotateStart );
@@ -515,11 +592,14 @@ THREE.OrbitControls = function ( object, domElement ) {
 				scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
 
 				rotateStart.copy( rotateEnd );
+
+				scope.update();
 				break;
 
 			case 2: // two-fingered touch: dolly
-				if ( scope.noZoom === true ) { return; }
-				if ( state !== STATE.TOUCH_DOLLY ) { return; }
+
+				if ( scope.noZoom === true ) 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;
@@ -539,21 +619,27 @@ THREE.OrbitControls = function ( object, domElement ) {
 				}
 
 				dollyStart.copy( dollyEnd );
+
+				scope.update();
 				break;
 
 			case 3: // three-fingered touch: pan
-				if ( scope.noPan === true ) { return; }
-				if ( state !== STATE.TOUCH_PAN ) { return; }
+
+				if ( scope.noPan === true ) return;
+				if ( state !== STATE.TOUCH_PAN ) return;
 
 				panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
 				panDelta.subVectors( panEnd, panStart );
-				
-				scope.pan( panDelta );
+
+				scope.pan( panDelta.x, panDelta.y );
 
 				panStart.copy( panEnd );
+
+				scope.update();
 				break;
 
 			default:
+
 				state = STATE.NONE;
 
 		}
@@ -562,9 +648,11 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function touchend( /* event */ ) {
 
-		if ( scope.enabled === false ) { return; }
+		if ( scope.enabled === false ) return;
 
+		scope.dispatchEvent( endEvent );
 		state = STATE.NONE;
+
 	}
 
 	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
@@ -572,12 +660,16 @@ THREE.OrbitControls = function ( object, domElement ) {
 	this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
 	this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
 
-	this.domElement.addEventListener( 'keydown', onKeyDown, false );
-
 	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 );
\ No newline at end of file
+THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
+THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
diff --git a/js/models/lattice.js b/js/models/lattice.js
index 1d87d74b..93fd06f4 100644
--- a/js/models/lattice.js
+++ b/js/models/lattice.js
@@ -70,6 +70,11 @@ Lattice = Backbone.Model.extend({
             }
         }
         return nodes;
+    },
+
+    fillWithParts: function(){
+
+
     }
 
 });
\ No newline at end of file
diff --git a/js/models/threeModel.js b/js/models/threeModel.js
index 91ee142a..ae00b876 100644
--- a/js/models/threeModel.js
+++ b/js/models/threeModel.js
@@ -17,6 +17,8 @@ function ThreeModel(){
         camera.position.x = 125;
         camera.position.y = 100;
         camera.position.z = 165;
+        camera.up.set(0,0,1);//set z axis as "up"
+
         scene.fog = new THREE.FogExp2(0xcccccc, 0.002);
 
         // lights
diff --git a/js/threeViews/latticeView.js b/js/threeViews/latticeView.js
index 0c26bdfe..04c91590 100644
--- a/js/threeViews/latticeView.js
+++ b/js/threeViews/latticeView.js
@@ -35,20 +35,20 @@ LatticeView = Backbone.View.extend({
 
         var size=50, step = 5;
         for (var i=-size;i<=size;i+=step){
-            xyPlaneGeo.vertices.push(new THREE.Vector3(-size, -size, i));
-            xyPlaneGeo.vertices.push(new THREE.Vector3(size, -size, i));
+            xyPlaneGeo.vertices.push(new THREE.Vector3(-size, i, -size));
+            xyPlaneGeo.vertices.push(new THREE.Vector3(size, i, -size));
             xyPlaneGeo.vertices.push(new THREE.Vector3(i, -size, -size));
-            xyPlaneGeo.vertices.push(new THREE.Vector3(i, -size, size));
+            xyPlaneGeo.vertices.push(new THREE.Vector3(i, size, -size));
 
-            xzPlaneGeo.vertices.push(new THREE.Vector3(-size, -size, i));
-            xzPlaneGeo.vertices.push(new THREE.Vector3(-size, size, i));
             xzPlaneGeo.vertices.push(new THREE.Vector3(-size, i, -size));
             xzPlaneGeo.vertices.push(new THREE.Vector3(-size, i, size));
+            xzPlaneGeo.vertices.push(new THREE.Vector3(-size, -size, i));
+            xzPlaneGeo.vertices.push(new THREE.Vector3(-size, size, i));
 
-            yzPlaneGeo.vertices.push(new THREE.Vector3(-size, i, -size));
-            yzPlaneGeo.vertices.push(new THREE.Vector3(size, i, -size));
+            yzPlaneGeo.vertices.push(new THREE.Vector3(-size, -size, i));
+            yzPlaneGeo.vertices.push(new THREE.Vector3(size, -size, i));
             yzPlaneGeo.vertices.push(new THREE.Vector3(i, -size, -size));
-            yzPlaneGeo.vertices.push(new THREE.Vector3(i, size, -size));
+            yzPlaneGeo.vertices.push(new THREE.Vector3(i, -size, size));
         }
 
         this.addPlane(xyPlaneGeo);
-- 
GitLab