Skip to content
Snippets Groups Projects
main.js 32.28 KiB
// Amira Abdel-Rahman
// (c) Massachusetts Institute of Technology 2019

var color1= 0xffffff; /*white*/
var color2= 0x020227;  /*kohly*/
var color3= 0x1c5c61; /*teal*/
var color4= "#fa6e70"; //red/orange
var color5="#380152"; //purple
var color6="#696767"; //grey
var color7="#03dbfc"; //blue

///////////globals (in case of hierarichal)/////////////
var camera;
var gui = new dat.GUI();

var clock = new THREE.Clock();

var timeElapsed = clock.getElapsedTime();
var currTimeStep=0;
var increase=true;

var setupEmpty={//empty
	nodes: [
		],
	edges: [
		],

	//material properties - AISI 1095 Carbon Steel (Spring Steel)
	ndofs   : 3*6,

	animation :  {
	
		showDisplacement : false,
		exaggeration : 1000,
		speed:3.0
		
	},
	viz :  {
		minStress:10e6,
		maxStress: -10e6,
		colorMaps:[coolwarm,YlGnBu, winter ,jet],
		colorMap:0,
		
	},
	
};

var setup=JSON.parse(JSON.stringify(setupEmpty));


function animate(){
	timeElapsed = clock.getElapsedTime();
	requestAnimationFrame(animate);
	if(increase){
		currTimeStep+=setup.animation.speed*setup.animation.speed*2.0; //todo change to globalSetup
	}else{
		currTimeStep-=setup.animation.speed*setup.animation.speed*2.0; //todo change to globalSetup
	}
	
}
animate();
///////////////////////////////

////////////threejs object and utils//////////////////////

function threejs(setup,containerName,container1Name,static=true,live=false,empty=false){
	// this.line;
	this.setup=setup;
	this.renderer;
	this.scene;
	// this.camera;
	this.controls;
	this.containerName=containerName;
	this.container = document.getElementById( this.containerName );
	this.container1Name=container1Name;
	// this.line1;
	this.matLineBasic;
	this.matLineDashed;
	this.matLineBasicBasic;
	this.matLineBasicDashed;
	this.static=static;
	this.labelRenderer=[];
	this.counter=0;
	this.numFile=0;
	this.live=live;
	this.thinLines=false;
	this.speed=this.setup.animation.speed;
	this.empty=empty;
	
	// viewport
	

}

threejs.prototype.init=function() {

	this.renderer = new THREE.WebGLRenderer( { antialias: true } );
	this.renderer.setPixelRatio( window.devicePixelRatio );
	this.renderer.setClearColor( color2, 1.0 );
	this.renderer.setSize( this.getWidth(), this.getHeight() );
	this.container.appendChild( this.renderer.domElement );
	this.scene = new THREE.Scene();

	camera = new THREE.PerspectiveCamera( 60, this.getWidth() / this.getHeight(), 1, 10000 );
	camera.position.set( - 40, 40, 60 );
	camera = new THREE.OrthographicCamera( this.getWidth() / - 2, this.getWidth() / 2, this.getHeight() / 2, this.getHeight() / - 2, 1, 1000 );
	camera.position.set( 0, 125, 0 );

	this.controls = new THREE.OrbitControls( camera, this.renderer.domElement );
	// this.controls.target.set( this.setup.voxelSize/2.0*this.setup.scale, this.setup.voxelSize*2.0*this.setup.scale, this.setup.voxelSize/2.0*this.setup.scale );
	this.controls.minDistance = 1;
	this.controls.maxDistance = 500;

	

	var helper = new THREE.GridHelper( 100, 100 );
    helper.position.y = -this.setup.voxelSize/2.0;
    helper.material.opacity = 0.5;
	helper.material.transparent = true;
	helper.scale.x=2.0
	helper.scale.z=2.0
	this.scene.add( helper );

	

	// this.labelRenderer = new THREE.CSS2DRenderer();
	// this.labelRenderer.setSize( this.getWidth(), this.getHeight() );
	// this.labelRenderer.domElement.style.position = 'absolute';
	// this.labelRenderer.domElement.style.top = 0;
	// this.container.appendChild( this.labelRenderer.domElement ); 
	// this.controls = new THREE.OrbitControls( camera, this.labelRenderer.domElement );
	
	
	// draw forces
	
	// draw degrees of freedom
	window.addEventListener( 'resize', onWindowResize, false );
	onWindowResize();
	if(!this.empty){
		this.matLineBasic = new THREE.LineMaterial( {
			color: 0xffffff,
			vertexColors: THREE.VertexColors,
			linewidth: 5, // in pixels
			//resolution:  // to be set by renderer, eventually
			dashed: false
	
		} );
	
		this.matLineBasicBasic = new THREE.LineBasicMaterial( {
			color: 0xffffff,
			vertexColors: THREE.VertexColors,
			linewidth: 5, // in pixels
			//resolution:  // to be set by renderer, eventually
	
		} );
	
		
		// matLineDashed.defines.USE_DASH = ""; 
		this.matLineDashed = new THREE.LineMaterial( {
			color: 0xffffff,
			linewidth: 5, // in pixels
			vertexColors: THREE.VertexColors,
			//resolution:  // to be set by renderer, eventually
			dashed: false
		} );
	
		this.matLineBasicDashed = new THREE.LineBasicMaterial( {
			color: 0xffffff,
			linewidth: 5, // in pixels
			vertexColors: THREE.VertexColors,
	
		} );

		this.drawStructure();
		this.colorEdges();
		this.drawConstraintBoundingBoxes();

		if(!this.live){
			if(!this.static){//dynamic
				// initialize(this.setup);
				this.renderEuler();
				this.animateEuler()
			}else{
				this.render();
				this.animate();
			}

		}else{
			this.renderLive();
			this.animateLive();
		}

		guiCreate(this);

	}else{


		this.renderEmpty();
		this.animateEmpty();
	}

	
	
};

threejs.prototype.drawStructure=function() {
	//draw edges
	for(var i=0;i<this.setup.edges.length;i++){
		//this.createEdge(this.setup.nodes[this.setup.edges[i].source].position,this.setup.nodes[this.setup.edges[i].target].position,this.setup.edges[i].id,false);
		if(this.live){
			this.createEdge(this.setup.nodes[this.setup.edges[i].source].position,this.setup.nodes[this.setup.edges[i].target].position,this.setup.edges[i].id,true,this.setup.edges[i].area);
		}else{
			this.createEdge(this.setup.nodes[this.setup.edges[i].source].position,this.setup.nodes[this.setup.edges[i].target].position,this.setup.edges[i].id,true);
		}
		
	}
	
	// draw nodes
	for(var i=0;i<this.setup.nodes.length;i++){
		//this.createNode(this.setup.nodes[i].position,this.setup.nodes[i].id,false,this.setup.nodes[i].restrained_degrees_of_freedom[0]);
		var loaded=false;
		if(this.setup.nodes[i].force.x!=0||this.setup.nodes[i].force.y!=0||this.setup.nodes[i].force.z!=0){
			loaded=true;
		}
		this.createNode(this.setup.nodes[i].position,this.setup.nodes[i].id,true,this.setup.nodes[i].restrained_degrees_of_freedom[0],loaded);
	}

	this.drawForces();
};

threejs.prototype.createEdge=function(fromPoint,toPoint,name,displacement,lineWidth=1.0) {
	fromPoint=toThreeVec(fromPoint);//todo utils
	toPoint=toThreeVec(toPoint);//todo utils
	var positions = [];
	var positionss = [];
	var colors = [];
	var points =[fromPoint,toPoint];

	var spline = new THREE.CatmullRomCurve3( points );
	var divisions = Math.round( 2 * points.length );

	var color = new THREE.Color();

	var colorss = new Float32Array( (divisions+1) * 3 );

	var count=0;

	for ( var i = 0, l = divisions; i <= l; i ++ ) {
		var point = spline.getPoint( i / l );
		positionss.push( new THREE.Vector3( point.x, point.y, point.z) );
		positions.push(  point.x, point.y, point.z );
		// color.setHSL( i / l, 1.0, 0.5 );
		color=interpolateLinearly(i / l, this.setup.viz.colorMaps[this.setup.viz.colorMap]);
		// color=interpolateLinearly(i / l, coolwarm);
		colors.push(  new THREE.Vector3( color[0], color[1], color[2]));
		colorss[count]=color[0]
		colorss[count+1]=color[1]
		colorss[count+2]=color[2]
		count+=3
	}

	
	if(this.thinLines){
		var geometry = new THREE.BufferGeometry().setFromPoints( positionss );
	}else{
		var geometry = new THREE.LineGeometry();
		geometry.setPositions( positions );
		geometry.setColors( colors );

	}

	
	
	var line;
	if(displacement){

		if(this.thinLines){
			line = new THREE.Line( geometry, this.matLineBasicDashed.clone() );
		}else{
			line = new THREE.Line2( geometry, this.matLineDashed );
		}
	}else{
		if(this.thinLines){
			line = new THREE.Line( geometry, this.matLineBasicBasic.clone() );
		}else{
			line = new THREE.Line2( geometry, this.matLineBasic );
		}
	}

	if(this.thinLines){
		line.geometry.setAttribute( 'color',new THREE.BufferAttribute( colorss, 3 ) );
		line.geometry.colorsNeedUpdate = true; 
		line.material.transparent=true;
		line.material.opacity=lineWidth;
		line.material.needsUpdate=true;
	}else{
		line.computeLineDistances();
		line.scale.set( 1, 1, 1 );

	}

	
	if(displacement){
		line.name='d'+name;
	}else{
		line.name=name;
	}

	this.scene.add( line );

	

};

threejs.prototype.createNode=function(point,name,displacement,restrained,loaded=false) {
	var geometry = new THREE.BoxGeometry( 1, 1, 1 );
	var material;

	if(restrained){
		material = new THREE.MeshBasicMaterial( {color: color4} );
	}else if(loaded){
		material = new THREE.MeshBasicMaterial( {color: color7} );
	}else {
		material = new THREE.MeshBasicMaterial( {color: color3} );
	}

	if(displacement){
		material.transparent=true;
		material.opacity=0.7;
	}else{
		material.transparent=true;
		material.opacity=0.0;

	}
	var cube = new THREE.Mesh( geometry, material );
	cube.position.set(point.x, point.y, point.z);
	cube.scale.set(0.05*this.setup.voxelSize, 0.05*this.setup.voxelSize,0.05*this.setup.voxelSize);
	// console.log(this.setup.voxelSize);
	// this.setup.voxelSize=1.5;
	if(this.setup.hierarchical){
		cube.scale.set(0.9*this.setup.voxelSize, 0.9*this.setup.voxelSize,0.9*this.setup.voxelSize);
	}
	
	if(displacement){
		cube.name='d'+name;
	}else{
		cube.name=name;
	}
	
	// var earthDiv = document.createElement( 'div' );
	// earthDiv.className = 'label';
	// earthDiv.textContent = name;
	// earthDiv.style.marginTop = '-1em';
	// var earthLabel = new THREE.CSS2DObject( earthDiv );
	// earthLabel.position.set( point.x*0.1, point.y*0.1, point.z*0.1 );
	// cube.add( earthLabel );
	

	this.scene.add( cube );

};

threejs.prototype.editEdge=function(fromPoint,toPoint,name) {
	var edge = this.scene.getObjectByName(name);


	var positions = [];
	var points =[fromPoint,toPoint];

	var spline = new THREE.CatmullRomCurve3( points );
	var divisions = Math.round( 2 * points.length );

	// var color = new THREE.Color();
	var positionss = new Float32Array( (divisions+1) * 3 );
	var count=0;

	for ( var i = 0, l = divisions; i <=l; i ++ ) {
		var point = spline.getPoint( i / l );
		positions.push( point.x, point.y, point.z );
		positionss[count]=point.x
		positionss[count+1]=point.y
		positionss[count+2]=point.z
		count+=3
		
	}
	// edge.geometry.setDrawRange( 0, newValue );
	// edge.geometry.setPositions( positions );
	// edge.geometry.attributes.position.needsUpdate = true; 
	// edge.geometry.setPositions( positions );
	// geometry.setColors( colors );

	if(this.thinLines){
		edge.geometry.setAttribute( 'position',new THREE.BufferAttribute( positionss, 3 ) );
		edge.geometry.attributes.position.needsUpdate = true; 

	}else{
		edge.geometry.setPositions( positions );
	}
	
	
};

threejs.prototype.drawForces=function() {
	for(var i=0;i<this.setup.nodes.length;i++){
		
		var dx=0.1;
		var o=toThreeVec(this.setup.nodes[i].position);
		o.multiplyScalar(this.setup.scale);
		var dir = toThreeVec(this.setup.nodes[i].force);
		var length = dir.length ();
		dir.normalize();
		var scale=0.00002*this.setup.scale;
		if(length!=0){
			var arrowhelper=new THREE.ArrowHelper( dir, o.sub(dir), scale*length, color7 ,scale*length, scale*length);
			// var arrowhelper=new THREE.ArrowHelper( dir, o.sub(dir), scale*length, color7);
			arrowhelper.name="f"+i;
			this.scene.add(arrowhelper);
		}
	}
};

threejs.prototype.updateForce1=function(id,o,dir){

	var length = dir.length();
	dir.normalize();
	// var scale=0.2;
	var scale=0.00002*this.setup.scale;
	if(length!=0){
		var arrow = this.scene.getObjectByName("f"+id.substring(1));
		if(arrow){
			// arrowhelper=new THREE.ArrowHelper( force.normalize(), arrow.position, scale*length, color7 ,scale*length, scale*length);
			// arrowhelper.name="f"+id.substring(1);
			// arrow.setDirection(force.normalize());
			// arrow.setLength(scale*length,scale*length,scale*length);
			// arrow=new THREE.ArrowHelper( dir, o.sub(dir), scale*length, color7 ,scale*length, scale*length);
			// console.log("here")
			var pos=o.sub(dir);
			arrow.position.x=pos.x;
			arrow.position.y=pos.y;
			arrow.position.z=pos.z;

		}
	}

}

threejs.prototype.updateForce=function(id,f){
	// var scale=0.00000001;
	var scale=0.00002*this.setup.scale;
	var force=new THREE.Vector3(f,0,0);
	var length = force.length();
	
	var arrow = this.scene.getObjectByName("f"+id.substring(1));
	if(arrow){
		// arrowhelper=new THREE.ArrowHelper( force.normalize(), arrow.position, scale*length, color7 ,scale*length, scale*length);
		// arrowhelper.name="f"+id.substring(1);
		arrow.setDirection(force.normalize());
		arrow.setLength(scale*length,scale*length,scale*length);

	}

}

///////
threejs.prototype.animateEmpty=function() {
	requestAnimationFrame( this.animateEmpty.bind(this));
	this.renderEmpty();
	
};

threejs.prototype.animate=function() {
	requestAnimationFrame( this.animate.bind(this));
	this.render();
	
};

threejs.prototype.animateEuler=function() {
	requestAnimationFrame( this.animateEuler.bind(this));
	this.renderEuler();
	
};

threejs.prototype.animateLive=function() {
	requestAnimationFrame( this.animateLive.bind(this));
	this.renderLive();
	
};

threejs.prototype.renderEmpty=function(){
	// main scene
	// this.labelRenderer.render( this.scene, camera );

	this.renderer.setViewport( 0, 0, this.getWidth(), this.getHeight() );
	// renderer will set this eventually
	this.renderer.render( this.scene, camera );

};

threejs.prototype.render=function(){
	// main scene
	// this.labelRenderer.render( this.scene, camera );

	this.renderer.setClearColor( color2, 1 );
	this.renderer.setViewport( 0, 0, this.getWidth(), this.getHeight() );
	// renderer will set this eventually
	this.matLineBasic.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.matLineDashed.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.renderer.render( this.scene, camera );

	var speed=this.setup.animation.speed;
	var exaggeration=this.setup.animation.exaggeration;
	// var exaggeration=0.01;
	
	if(this.setup.animation.showDisplacement){
		//displacement animation edges
		for(var i=0;i<this.setup.edges.length;i++){
			var fromPoint=new THREE.Vector3(0,0,0);
			var toPoint=new THREE.Vector3(0,0,0);
			var node1=this.setup.nodes[this.setup.edges[i].source];
			var node2=this.setup.nodes[this.setup.edges[i].target];

			fromPoint.x = node1.position.x+node1.displacement.x*exaggeration+ Math.sin(timeElapsed*speed)* node1.displacement.x*exaggeration ;
			fromPoint.y = node1.position.y+node1.displacement.y*exaggeration+ Math.sin(timeElapsed*speed)* node1.displacement.y*exaggeration ;
			fromPoint.z = node1.position.z+node1.displacement.z*exaggeration+ Math.sin(timeElapsed*speed)* node1.displacement.z*exaggeration ;

			var node = this.scene.getObjectByName('d'+node1.id);

			node.position.x = fromPoint.x;
			node.position.y = fromPoint.y;
			node.position.z = fromPoint.z;

			node.rotation.x = 0+node1.angle.x*exaggeration+ Math.sin(timeElapsed*speed)* node1.angle.x*exaggeration ;
			node.rotation.y = 0+node1.angle.y*exaggeration+ Math.sin(timeElapsed*speed)* node1.angle.y*exaggeration ;
			node.rotation.z = 0+node1.angle.z*exaggeration+ Math.sin(timeElapsed*speed)* node1.angle.z*exaggeration ;
		

			toPoint.x   = node2.position.x+node2.displacement.x*exaggeration+ Math.sin(timeElapsed*speed)* node2.displacement.x*exaggeration ;
			toPoint.y   = node2.position.y+node2.displacement.y*exaggeration+ Math.sin(timeElapsed*speed)* node2.displacement.y*exaggeration ;
			toPoint.z   = node2.position.z+node2.displacement.z*exaggeration+ Math.sin(timeElapsed*speed)* node2.displacement.z*exaggeration ;

			node = this.scene.getObjectByName('d'+node2.id);

			node.position.x = toPoint.x;
			node.position.y = toPoint.y;
			node.position.z = toPoint.z;

			node.rotation.x = 0+node2.angle.x*exaggeration+ Math.sin(timeElapsed*speed)* node2.angle.x*exaggeration ;
			node.rotation.y = 0+node2.angle.y*exaggeration+ Math.sin(timeElapsed*speed)* node2.angle.y*exaggeration ;
			node.rotation.z = 0+node2.angle.z*exaggeration+ Math.sin(timeElapsed*speed)* node2.angle.z*exaggeration ;
		
			this.editEdge(fromPoint,toPoint,'d'+this.setup.edges[i].id);
			
			
		}

	}

};
threejs.prototype.renderEuler1=function(){


	var dt=0.0251646;
	// simulateParallel( this.setup,10,dt,false,2); 
	doTimeStep(this.setup,dt,false,this.counter,1);
	// this.colorEdges();
	// simulateParallel(setup1,three.setup.numTimeSteps,dt,static,2);
		

	// main scene
	this.renderer.setClearColor( color2, 1 );
	this.renderer.setViewport( 0, 0, this.getWidth(), this.getHeight() );
	// renderer will set this eventually
	this.matLineBasic.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.matLineDashed.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.renderer.render( this.scene, camera );

	var speed=this.setup.animation.speed;
	var exaggeration=this.setup.animation.exaggeration;
	var exaggeration=1.0;
	// console.log(this.setup.nodes[0].posTimeSteps)
	//todo later change how it's implemented
	if(this.setup.nodes[0].posTimeSteps){
		var numIntervals=this.setup.nodes[0].posTimeSteps.length;
		// if(currTimeStep>=numIntervals){
		// 	currTimeStep=numIntervals-1;
		// 	increase=false;
		// }else if(currTimeStep<0){
		// 	currTimeStep=0;
		// 	increase=true;
		// }
		if(currTimeStep>=numIntervals){
			currTimeStep=0;
		}

		var index=parseInt(currTimeStep);
		currTimeStep=this.counter;
		index=this.counter;
		
		if(this.setup.animation.showDisplacement){
			//displacement animation edges
			for(var i=0;i<this.setup.edges.length;i++){
				var fromPoint=new THREE.Vector3(0,0,0);
				var toPoint=new THREE.Vector3(0,0,0);
				var node1=this.setup.nodes[this.setup.edges[i].source];
				var node2=this.setup.nodes[this.setup.edges[i].target];

				fromPoint.x =  node1.position.x+node1.posTimeSteps[index].x*exaggeration ;
				fromPoint.y =  node1.position.y+node1.posTimeSteps[index].y*exaggeration ;
				fromPoint.z =  node1.position.z+node1.posTimeSteps[index].z*exaggeration ;

				var node = this.scene.getObjectByName('d'+node1.id);
				//todo check if this is effecient or ject go thought nodes

				node.position.x = fromPoint.x;
				node.position.y = fromPoint.y;
				node.position.z = fromPoint.z;

				node.rotation.x = 0+node1.angTimeSteps[index].x*exaggeration ;
				node.rotation.y = 0+node1.angTimeSteps[index].y*exaggeration ;
				node.rotation.z = 0+node1.angTimeSteps[index].z*exaggeration ;

				var scale=0.1;
				
				this.updateForce(node1.id,getForce(node1.position,currTimeStep).length()*scale);
			

				toPoint.x   =  node2.position.x+node2.posTimeSteps[index].x*exaggeration ;
				toPoint.y   =  node2.position.y+node2.posTimeSteps[index].y*exaggeration ;
				toPoint.z   =  node2.position.z+node2.posTimeSteps[index].z*exaggeration ;

				node = this.scene.getObjectByName('d'+node2.id);

				node.position.x = toPoint.x;
				node.position.y = toPoint.y;
				node.position.z = toPoint.z;

				node.rotation.x = 0+node2.angTimeSteps[index].x*exaggeration ;
				node.rotation.y = 0+node2.angTimeSteps[index].y*exaggeration ;
				node.rotation.z = 0+node2.angTimeSteps[index].z*exaggeration ;

				this.updateForce(node2.id,getForce(node2.position,currTimeStep).length()*scale);
			

				this.editEdge(fromPoint,toPoint,'d'+this.setup.edges[i].id);
				if(globalSetup.updateStress){
					this.colorEdge(this.setup.edges[i].stressTimeSteps[index],'d'+this.setup.edges[i].id);
				}
				
				
			}

		}
	}

	this.counter++;

};

threejs.prototype.renderEuler=function(){

		

	// main scene
	this.renderer.setClearColor( color2, 1 );
	this.renderer.setViewport( 0, 0, this.getWidth(), this.getHeight() );
	// renderer will set this eventually
	this.matLineBasic.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.matLineDashed.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.renderer.render( this.scene, camera );

	var speed=this.setup.animation.speed;
	var exaggeration=this.setup.animation.exaggeration;
	
	// console.log(this.setup.nodes[0].posTimeSteps.length)
	
	//todo later change how it's implemented
	if(this.setup.nodes[0].posTimeSteps){
		var numIntervals=this.setup.nodes[0].posTimeSteps.length;
		// console.log(numIntervals)
		
		// if(currTimeStep>=numIntervals){
		// 	currTimeStep=numIntervals-1;
		// 	increase=false;
		// }else if(currTimeStep<0){
		// 	currTimeStep=0;
		// 	increase=true;
		// }
		if(currTimeStep>=numIntervals){
			currTimeStep=0;
		}

		var index=parseInt(currTimeStep);
		
		
		if(this.setup.animation.showDisplacement){
			// console.log(index)
			//displacement animation edges
			for(var i=0;i<this.setup.edges.length;i++){
				var fromPoint=new THREE.Vector3(0,0,0);
				var toPoint=new THREE.Vector3(0,0,0);
				var node1=this.setup.nodes[this.setup.edges[i].source];
				var node2=this.setup.nodes[this.setup.edges[i].target];

				fromPoint.x =  node1.position.x+node1.posTimeSteps[index].x*exaggeration ;
				fromPoint.y =  node1.position.y+node1.posTimeSteps[index].y*exaggeration ;
				fromPoint.z =  node1.position.z+node1.posTimeSteps[index].z*exaggeration ;

				var node = this.scene.getObjectByName('d'+node1.id);
				//todo check if this is effecient or ject go thought nodes

				node.position.x = fromPoint.x;
				node.position.y = fromPoint.y;
				node.position.z = fromPoint.z;

				node.rotation.x = 0+node1.angTimeSteps[index].x*exaggeration ;
				node.rotation.y = 0+node1.angTimeSteps[index].y*exaggeration ;
				node.rotation.z = 0+node1.angTimeSteps[index].z*exaggeration ;

				var scale=0.1;
				
				// this.updateForce(node1.id,getForce(node1.position,currTimeStep).length()*scale);
			

				toPoint.x   =  node2.position.x+node2.posTimeSteps[index].x*exaggeration ;
				toPoint.y   =  node2.position.y+node2.posTimeSteps[index].y*exaggeration ;
				toPoint.z   =  node2.position.z+node2.posTimeSteps[index].z*exaggeration ;

				node = this.scene.getObjectByName('d'+node2.id);

				node.position.x = toPoint.x;
				node.position.y = toPoint.y;
				node.position.z = toPoint.z;

				node.rotation.x = 0+node2.angTimeSteps[index].x*exaggeration ;
				node.rotation.y = 0+node2.angTimeSteps[index].y*exaggeration ;
				node.rotation.z = 0+node2.angTimeSteps[index].z*exaggeration ;

				// this.updateForce(node2.id,getForce(node2.position,currTimeStep).length()*scale);
			

				this.editEdge(fromPoint,toPoint,'d'+this.setup.edges[i].id);
				if(this.setup.updateStress){
					this.colorEdge(this.setup.edges[i].stressTimeSteps[index],'d'+this.setup.edges[i].id);
				}
				
				
			}

		}
	}

	

};

threejs.prototype.renderLive=function(){
	// main scene
	// this.labelRenderer.render( this.scene, camera );

	this.renderer.setClearColor( color2, 1 );
	this.renderer.setViewport( 0, 0, this.getWidth(), this.getHeight() );
	// renderer will set this eventually
	this.matLineBasic.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.matLineDashed.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
	this.renderer.render( this.scene, camera );

	var speed=this.speed;
	var exaggeration=this.setup.animation.exaggeration;
	// var exaggeration=0.01;
	
	if(this.setup.animation.showDisplacement){
		//displacement animation edges
		for(var i=0;i<this.setup.edges.length;i++){
			var fromPoint=new THREE.Vector3(0,0,0);
			var toPoint=new THREE.Vector3(0,0,0);
			var node1=this.setup.nodes[this.setup.edges[i].source];
			var node2=this.setup.nodes[this.setup.edges[i].target];

			fromPoint.x = node1.position.x+node1.displacement.x*exaggeration;
			fromPoint.y = node1.position.y+node1.displacement.y*exaggeration;
			fromPoint.z = node1.position.z+node1.displacement.z*exaggeration;

			var node = this.scene.getObjectByName('d'+node1.id);

			var dir = toThreeVec(node1.force);
			var length = dir.length();
			if(length!=0){
				this.updateForce1(node1.id,fromPoint.clone(),dir);
			}

			node.position.x = fromPoint.x;
			node.position.y = fromPoint.y;
			node.position.z = fromPoint.z;

			node.rotation.x = 0+node1.angle.x;
			node.rotation.y = 0+node1.angle.y;
			node.rotation.z = 0+node1.angle.z;

			if(typeof node1.size !== 'undefined'){
				node.scale.x = 0.5*node1.size;
				node.scale.y = 0.5*node1.size;
				node.scale.z = 0.5*node1.size;
			}
			
		

			toPoint.x   = node2.position.x+node2.displacement.x*exaggeration;
			toPoint.y   = node2.position.y+node2.displacement.y*exaggeration;
			toPoint.z   = node2.position.z+node2.displacement.z*exaggeration;

			node = this.scene.getObjectByName('d'+node2.id);

			var dir = toThreeVec(node2.force);
			var length = dir.length();
			if(length!=0){
				this.updateForce1(node2.id,toPoint.clone(),dir);
			}

			node.position.x = toPoint.x;
			node.position.y = toPoint.y;
			node.position.z = toPoint.z;

			node.rotation.x = 0+node2.angle.x;
			node.rotation.y = 0+node2.angle.y;
			node.rotation.z = 0+node2.angle.z;

			if(typeof node2.size !== 'undefined'){
				node.scale.x = 0.5*node2.size;
				node.scale.y = 0.5*node2.size;
				node.scale.z = 0.5*node2.size;
			}
		

			// this.editEdge(fromPoint,toPoint,'d'+this.setup.edges[i].id);
			this.editEdge(fromPoint,toPoint,'d'+this.setup.edges[i].id);
			// uncomment this to make it faster
			this.colorEdge(this.setup.edges[i].stress,'d'+this.setup.edges[i].id);
			
		}

		this.counter++;
		var numFile=this.numFile;
		var s=this.setup;

		if(this.counter>this.speed*0.5){
			//get new setup
			// this.colorEdges();
			$.getJSON("../json/"+this.folderName+"/"+numFile+".json", function(json) {
				// console.log(numFile)
				// console.log(json.nodes)
				// this.setup.nodes=json.nodes;
				s.nodes=json.nodes;
				s.edges=json.edges;
				s.viz.minStress=json.viz.minStress;
				s.viz.maxStress=json.viz.maxStress;
				// s=json;
				// console.log("opened file:"+ numFile);
			});
			this.setup=s;
			this.numFile++;
			if (this.numFile>s.maxNumFiles-1){
				this.numFile=0;
			}
			this.counter=0;
		}

	}

	
};

threejs.prototype.renderLast=function(){
	// main scene
	// this.labelRenderer.render( this.scene, camera );
	if(this.live){

		this.renderer.setClearColor( color2, 1 );
		this.renderer.setViewport( 0, 0, this.getWidth(), this.getHeight() );
		// renderer will set this eventually
		this.matLineBasic.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
		this.matLineDashed.resolution.set( this.getWidth(), this.getHeight() ); // resolution of the viewport
		this.renderer.render( this.scene, camera );

		var speed=this.setup.animation.speed;
		var exaggeration=this.setup.animation.exaggeration;
		
	
		var s=this.setup;
		var numFile=s.maxNumFiles-1;
		

		//get new setup
		// this.colorEdges();
		$.getJSON("../json/"+this.folderName+"/"+numFile+".json", function(json) {
			// console.log(json.nodes)
			// this.setup.nodes=json.nodes;
			s.nodes=json.nodes;
			s.edges=json.edges;
			s.viz.minStress=json.viz.minStress;
			s.viz.maxStress=json.viz.maxStress;
			// s=json;
			// console.log("opened file:"+ numFile);
		});
		this.setup=s;
		this.numFile++;
		if (this.numFile>s.maxNumFiles){
			this.numFile=0;
		}
		

		//displacement animation edges
		for(var i=0;i<this.setup.edges.length;i++){
			var fromPoint=new THREE.Vector3(0,0,0);
			var toPoint=new THREE.Vector3(0,0,0);
			var node1=this.setup.nodes[this.setup.edges[i].source];
			var node2=this.setup.nodes[this.setup.edges[i].target];

			fromPoint.x = node1.position.x+node1.displacement.x*exaggeration;
			fromPoint.y = node1.position.y+node1.displacement.y*exaggeration;
			fromPoint.z = node1.position.z+node1.displacement.z*exaggeration;

			var node = this.scene.getObjectByName('d'+node1.id);

			node.position.x = fromPoint.x;
			node.position.y = fromPoint.y;
			node.position.z = fromPoint.z;

			node.rotation.x = 0+node1.angle.x;
			node.rotation.y = 0+node1.angle.y;
			node.rotation.z = 0+node1.angle.z;

			if(typeof node.size !== 'undefined'){
				node.scale.x = 0.5*node1.size;
				node.scale.y = 0.5*node1.size;
				node.scale.z = 0.5*node1.size;
			}
		

			toPoint.x   = node2.position.x+node2.displacement.x*exaggeration;
			toPoint.y   = node2.position.y+node2.displacement.y*exaggeration;
			toPoint.z   = node2.position.z+node2.displacement.z*exaggeration;

			node = this.scene.getObjectByName('d'+node2.id);

			node.position.x = toPoint.x;
			node.position.y = toPoint.y;
			node.position.z = toPoint.z;

			node.rotation.x = 0+node2.angle.x;
			node.rotation.y = 0+node2.angle.y;
			node.rotation.z = 0+node2.angle.z;

			if(typeof node.size !== 'undefined'){
				node.scale.x = 0.5*node2.size;
				node.scale.y = 0.5*node2.size;
				node.scale.z = 0.5*node2.size;
			}
		

			this.editEdge(fromPoint,toPoint,'d'+this.setup.edges[i].id);
			
		}
	}

	
};
//////////////////////////////////////////

threejs.prototype.getWidth=function(){
	// return container.style.width;
	if(this.container1Name===""){
		return window.innerWidth;
	}else{
		return $('#'+this.container1Name).width() ;
	}
    
};
threejs.prototype.getHeight=function(){
    // return container.style.height;
	if(this.container1Name===""){
		console.log()
		return window.innerHeight ;
	}else{
		return $('#'+this.container1Name).height() ;
	}
};

/////events////
//todo change 
function onWindowResize() {
	if(typeof three !== 'undefined'){
		camera.aspect = three.getWidth() / three.getHeight();
		camera.updateProjectionMatrix();
		three.renderer.setSize( three.getWidth(), three.getHeight() );
	}
	if(typeof three1 !== 'undefined'){
		camera.aspect = three1.getWidth() / three1.getHeight();
		camera.updateProjectionMatrix();
		three1.renderer.setSize( three1.getWidth(), three1.getHeight() );
	}
	
}
////////////////

threejs.prototype.colorEdges=function() {
	
	for(var ii=0;ii<this.setup.edges.length;ii++){
		var element=this.setup.edges[ii];
		//this.colorEdge(element.stress,element.id);
		this.colorEdge(element.stress,'d'+element.id);
	}
};

threejs.prototype.colorEdge=function(val,name) {
	
	var colors = [];
	var val=map(val,this.setup.viz.minStress,this.setup.viz.maxStress,1.0,0.0);
	var divisions = Math.round( 2 * 2 );
	var colorss = new Float32Array( (divisions+1) * 3 );
	var count=0;

	for ( var i = 0, l = divisions; i <= l; i ++ ) {
		color=interpolateLinearly(val, this.setup.viz.colorMaps[this.setup.viz.colorMap]);
		colors.push( color[0], color[1], color[2]);
		colorss[count]=color[0]
		colorss[count+1]=color[1]
		colorss[count+2]=color[2]
		count+=3
	}
	var edge = this.scene.getObjectByName(name);
	if(this.thinLines){
		edge.geometry.setAttribute( 'color',new THREE.BufferAttribute( colorss, 3 ) );
		color=interpolateLinearly(val, this.setup.viz.colorMaps[this.setup.viz.colorMap]);
		edge.geometry.colorsNeedUpdate = true; 
		edge.material.needsUpdate=true;
	}else{
		edge.geometry.setColors( colors );

	}
	

};

threejs.prototype.drawConstraintBoundingBoxes=function() {
	let supports=this.setup.supports;
	let loads=this.setup.loads;
	let mat=this.setup.materials;
	let disps=this.setup.fixedDisplacements;
	if (supports ) {
		for (var i=0;i< supports.length;i++) {
			let s=supports[i][0];
			this.drawBox1(s.min,s.max,color4);
		}
	}
	if (loads ) {
		for (var i=0;i< loads.length;i++) {
			let l=loads[i][0];
			this.drawBox1(l.min,l.max,color7);
		}
		
	}
	if (disps ) {
		for (var i=0;i< disps.length;i++) {
			let l=disps[i][0];
			this.drawBox1(l.min,l.max,color7);
		}
		
	}
	if (mat ) {
		
		for (var i=0;i< mat.length;i++) {
			let l=mat[i][0];
			// console.log(l)
			this.drawBox1(l.min,l.max,color5);
		}
		
	}
	
};

threejs.prototype.drawBox=function(min,max,color) {
	var box = new THREE.Box3(new THREE.Vector3(min[0],min[1],min[2]),new THREE.Vector3(max[0],max[1],max[2]));
	var helper = new THREE.Box3Helper( box, color );
	this.scene.add( helper );
	// todo add name??
};

threejs.prototype.drawBox1=function(min,max,color) {
	var box = new THREE.Box3(new THREE.Vector3(min.x,min.y,min.z),new THREE.Vector3(max.x,max.y,max.z));
	var helper = new THREE.Box3Helper( box, color );
	this.scene.add( helper );
	// todo add name??
};
/////////////////gui////////////////
function guiCreate (three){
	

	var f1 = gui.addFolder('Displacement Animation '+three.containerName);
	f1.add(three.setup.animation, 'showDisplacement');
	f1.add(three.setup.animation, 'exaggeration', 0, 1000);
	f1.add(three.setup.animation, 'speed', 0, 10);

	var f2 = gui.addFolder('Stresses Visualization '+three.containerName);
	f2.add(three.setup.viz, 'minStress', -1000, 0).listen();
	f2.add(three.setup.viz, 'maxStress', 0, 1000).listen();
	f2.add(three.setup.viz, 'colorMap', {coolwarm:0, YlGnBu:1, winter:2,jet:3});

	// gui.add(setup, 'solve');

	for (j in f2.__controllers) f2.__controllers[j].onChange (updateColors.bind(this)); //todo check three
	for (j in f1.__controllers) f1.__controllers[j].onChange (renderLast.bind(this)); //todo check three
	
}

//todo remove this
function updateColors(){
	three.colorEdges();
	if(typeof three1 !== 'undefined'){
		three1.colorEdges();
	}
}

function renderLast(){
	three.renderLast();
	if(typeof three1 !== 'undefined'){
		three1.renderLast();
	}
	
}