API Docs for:
Show:

File: workspace\templates\dirConScript.js

;
//<script>


if( typeof(startupScripts) == 'undefined'){

	var startupScripts = [
		function(){},
		function(){},
		function(){},
		function(){},
		function(){},
		function(){},
		function(){},
		function(){}
	];

}




// Put recieved data about assembly into here. The code handles the rest.
// theXMLFile should be a string, and theSTLFiles as a binary ArrayBuffer
// Any text-based STL files should be in an 8-bit encoding
/**
*
* The function which handles the actual dir_rendering of the solution file animation
* and loading in the models
*
* @method dir_recieveData
* @for directionConfirmGlobal
* @param {String} theXMLFile
* @param {Object} theSTLFiles
* @return {Void}
*
*/
function dir_receiveData(theXMLFile, theSTLFiles){

	theXML=theXMLFile;

	parts.length=0;
	var pos=0;
	var lim=theSTLFiles.length;
	var partGeom;
	var partMesh;

	while(pos<lim){
		partGeom=null;
		partGeom=theSTLFiles[pos];
		if(partGeom===null){
			partGeom=parseStlBinary(fileReaders[pos].Reader.result);
		}

		partMesh=new THREE.Mesh(
				partGeom,
				new THREE.MeshNormalMaterial()
		);
		parts.push({
			Mesh: partMesh,
			Name: fileReaders[pos].Name
		})
		scene.add(partMesh);

		pos++;
	}

	dir_renderParts();

}



// Gets called when the user submits the table and everything is properly filled out
/**
*
* Is called whenever the user submits the part table and every entry has been
* properly filled out.
*
* @method dir_sendData
* @for directionConfirmGlobal
* @param {String} theXMLText The contents of the disassembly directions in the webpage, as a string
* in XML formatting
* @return {Void}
*
*/
function dir_sendData(theXMLText){

	// Do whatever you want with the resulting data to send it off, if you want


}






/**
*
* Given an HTML element corresponding to a "confirm" button, moves the parent element
* to the confirmed section of the webpage
*
* @method dir_confirmPair
* @for directionConfirmGlobal
* @param {HTML Element} theButton The confirm button of the element to be moved
* @return {Void}
*
*/
function dir_confirmPair(theButton){
	document.getElementById("confirmed").appendChild(theButton.parentElement);
	theButton.innerHTML="unconfirm";
	theButton.onclick=function(){
		dir_deconfirmPair(theButton);
	};
}



/**
*
* Given an HTML element corresponding to a "unconfirm" button, moves the parent element
* to the unconfirmed section of the webpage
*
* @method dir_deconfirmPair
* @for directionConfirmGlobal
* @param {HTML Element} theButton The unconfirm button of the element to be moved
* @return {Void}
*
*/
function dir_deconfirmPair(theButton){
	document.getElementById("unconfirmed").appendChild(theButton.parentElement);
	theButton.innerHTML="confirm";
	theButton.onclick=function(){
		dir_confirmPair(theButton);
	};
}



/**
*
* Given an HTML element corresponding to a "focus" button, makes the corresponding pair
* of parts to be displayed
*
* @method dir_changeCurrentPair
* @for directionConfirmGlobal
* @param {HTML Element} theButton The confirm button of the element to be moved
* @return {Void}
*
*/
function dir_changeCurrentPair(theButton){

	if(lastPair!==null){
		return;
	}

	lastPair=currentPair;
	var theRef=theButton.parentElement.Ref;
	var theMov=theButton.parentElement.Mov;
	var pos=0;
	var lim=assemblyPairs.length;
	while(pos<lim){
		if(assemblyPairs[pos].Ref.Name===theRef & assemblyPairs[pos].Mov.Name===theMov){
			currentPair=assemblyPairs[pos];
			return;
		}
		pos++;
	}

}

/**
*
* Given a jQuery object and a string, returns the first child of the given element with
* a tag equivalent to the given string.
*
* @method dir_grab
* @for  directionConfirmGlobal
* @param {jQuery Object} theTree The jQuery object whose child is to be returned
* @param {String} theMember The name of the tag being searched
* @return {jQuery Object} The first child with the given tag. If such a child does not
* exist, null is returned.
*
*/
function dir_grab(theTree,theMember){

	if($(theTree).children(theMember).length!=0){
		return $(theTree).children(theMember)[0];
	}
	else{
		return null;
	}

}


var time=0;
var focusBox;
var focusPoint;


/**
*
* The dir_rendering function for the webpage
*
* @for directionConfirmGlobal
* @return {Void}
*
*/
var dir_render = function () {

	// The function that will manage frame requests
	requestAnimationFrame( dir_render );

	if(lastPair!==null){
		var holder=currentPair;
		currentPair=lastPair;
		dir_dehighlight(currentPair);
		currentPair=holder;
		dir_highlight(currentPair);
		lastPair=null;
	}

	currentPair.Ref.Mesh.geometry.computeBoundingBox();
	currentPair.Mov.Mesh.geometry.computeBoundingBox();
	focusBox=currentPair.Ref.Mesh.geometry.boundingBox.clone();
	focusBox.union(currentPair.Mov.Mesh.geometry.boundingBox);

	focusPoint= new THREE.Vector3(
								  (focusBox.min.x+focusBox.max.x)/2,
								  (focusBox.min.y+focusBox.max.y)/2,
								  (focusBox.min.z+focusBox.max.z)/2
								 );

	thePos.normalize();

	thePos.applyEuler(theEul);
	theEul.set(0,0,0,'XYZ');
	thePos.multiplyScalar(theDistance);
	camera.position.copy(thePos);
	camera.position.add(focusPoint);
	camera.lookAt(focusPoint);
	camera.updateMatrix();

	sunLight.position.set( (camera.position.x-focusPoint.x)*2+focusPoint.x,
						   (camera.position.y-focusPoint.y)*2+focusPoint.y,
						   (camera.position.z-focusPoint.z)*2+focusPoint.z );
	sunLight.target.position=focusPoint;


	time+=0.01;

	dir_updateAxisLines();

	// Call for the render
	renderer.render(scene, camera);
};




/**
*
* Accepts a string and outputs the string of all characters following the final '.' symbol
* in the string. This is used internally to extract file extensions from file names.
*
* @method dir_grabExtension
* @for directionConfirmGlobal
* @param {String} theName The file name to be processed
* @return {String} the extension in the given file name. If no extension is found, the
* 'undefined' value is returned.
*
*/
function dir_grabExtension(theName){
	return (/[.]/.exec(theName)) ? /[^.]+$/.exec(theName) : undefined;
}





// Returns from the given list of file readers those that have not completed loading
/**
*
* Outputs through the console the list of FileReaders in theReaders which have
* not yet completed their loading
*
* @method dir_whoIsLeft
* @for  directionConfirmGlobal
* @param {FileReader Object List} theReaders The list of FileReaders to be checked
* @return {Void}
*
*/
function dir_whoIsLeft(theReaders){

	var pos=0;
	var lim=fileReaders.length;
	var theList=[];
	while(pos<lim){
		if(theReaders[pos].Reader.readyState!=2){
			theList.push(theReaders[pos].Name);
		}
		pos++;
	}
	console.log(theList);

}




/**
*
* Accepts a fileinput event, presumably from a file upload event listener, and assigns
* functions to each file reader listed in the event to be called upon the full loading
* of that given reader's files
*
* @method dir_readMultipleFiles
* @for directionConfirmGlobal
* @param {Event} evt A fileinput event, to be given by a fileinput event listener
* @return {Void}
*
*/
function dir_readMultipleFiles(evt) {
	//Retrieve all the files from the FileList object
	var files = evt.target.files;

	if (files) {
		for (var i=0, f; f=files[i]; i++) {

			var r = new FileReader();
			var extension=dir_grabExtension(f.name)[0];
			//console.log(f.name);

			if(extension===undefined){
				continue;
			}
			if(extension.toLowerCase()==="stl"){
				r.onload = (function(f) {
					return function(e) {
					//console.log(f.name);
						var contents = e.target.result;
						if(r.result!=null){
							STLs.push(r.result);
						}
						dir_loadParts();
					};
				})(f);
				r.readAsArrayBuffer(f);
				fileReaders.push({Reader: r, Name: f.name});
			}
			else if(extension.toLowerCase()==="xml"){
				console.log(f.name);
				if(!(theXML===null)){
					console.log("Warning: More than one XML file provided");
				}
				r.onload = (function(f) {
					return function(e) {
						//console.log(f.name);
						var contents = e.target.result;
						theXML=e.target.result;
						dir_loadParts();
					};
				})(f);
				r.readAsText(f,"US-ASCII");
				fileReaders.push({Reader: r, Name: f.name});
			}

		}
		console.log(fileReaders);
	}
	else {
		  alert("Failed to load files");
	}
}




/**
*
* Called internally upon every recieved fileload event. Checks if every file reader in the
* array "fileReaders" has fully read each of their files. If so, then the function converts
* all recieved stl files into threeJS models and executes "dir_renderParts".
*
* @method dir_loadParts
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_loadParts (){


		// Looks for unloaded files
		var pos=0;
		var lim=fileReaders.length;
		while(pos<lim){
			if(!(fileReaders[pos].Reader.readyState===2)){
				//console.log(pos);
				//console.log(fileReaders[pos].Name);
				break;
			}
			pos++;
		}


	// Executes if all files are loaded
	if(pos===lim){
		//console.log("ALL DONE");
		parts.length=0;
		pos=0;
		var partGeom=null;
		var partMesh;
		var theCenter;
		var ext;
		while(pos<lim){
			ext=dir_grabExtension(fileReaders[pos].Name)[0];

			if(ext.toLowerCase()==="stl"){

				partGeom=parseStl(fileReaders[pos].Reader.result);
				if(partGeom===null){
					partGeom=parseStlBinary(fileReaders[pos].Reader.result);
				}

				//console.log(partGeom);

				partMesh=new THREE.Mesh(
						partGeom,
						new THREE.MeshLambertMaterial(wireSettings)
				);
				parts.push({
					Mesh: partMesh,
					Name: fileReaders[pos].Name
				})
				scene.add(partMesh);
			}

			pos++;
		}

		dir_renderParts();

	}


}


function dir_renderParts(){


	dir_parseData();
	dir_linkParts();
	console.log(assemblyPairs);
	dir_highlight(assemblyPairs[0]);
	lastPair=assemblyPairs[0];
	currentPair=assemblyPairs[0];
	dir_insertAssemblyPairs();
	dir_initAxisLines();
	dir_render();


}



/**
*
* Accepts two strings, a and b, and a vector, vec, and outputs a
* constructed part pair object if the two strings correspond to two
* extant parts
*
* @method dir_linkPair
* @for directionConfirmGlobal
* @param {String} a The first part name
* @param {String} b The second part name
* @param {Vector3} vec The vector to be added to the pair
* @return {Object} The resulting pair object
*
*/
function dir_linkPair(a,b,vec){

	var thePair={Ref: null,
				 Mov: null,
				 Vec: null,
				 Directed: null,
				 DoublyDirected: null,
				 InfiniteDirections: null};

	//console.log(parts);

	var pos=0;
	var lim=parts.length;
	while(pos<lim){

		if(parts[pos].Name===a+".STL" || parts[pos].Name===a){
			thePair.Ref=parts[pos];
		}
		if(parts[pos].Name===b+".STL" || parts[pos].Name===b){
			thePair.Mov=parts[pos];
		}
		if(thePair.Ref!==null && thePair.Mov!==null){
			thePair.Vec=vec;
			return thePair;
		}
		pos++;
	}
	//console.log(thePair);
	return null;

}



/**
*
* Links together the pairs of parts corresponding to the strings present in
* the namePairs array.
*
* @method dir_linkParts
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_linkParts(){

	var pos=0;
	var lim=namePairs.length;
	var thePair=null;

	while(pos<lim){
		thePair=dir_linkPair(namePairs[pos].Ref,namePairs[pos].Mov,namePairs[pos].Vec);

		if(thePair!=null){
			thePair.InfiniteDirections = namePairs[pos].InfiniteDirections;
			assemblyPairs.push(thePair);
		}
		pos++;
	}
	//console.log(assemblyPairs);
}


/**
*
* Populates the webpage with data stored int the global variable theSML
*
* @method dir_parseData
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_parseData(){

	//console.log(theXML);
	var doc = $.parseXML(theXML);
	//console.log(doc);
	doc = dir_grab(doc,"DirectionSaveStructure");
	var directions = dir_grab(doc,"Directions");
	directions = $(directions).children("ArrayOfDouble");
	var thePairs=dir_grab(doc,"arcs");
	//console.log(thePairs);

	thePairs=$(thePairs).children("arc");
	//console.log(thePairs);
	var pos=0;
	var lim=thePairs.length;
	var thePair;
	var theMov;
	var theRef;
	var theVec;
	var vecPos;
	var vecLim;
	var directed;
	var docDirs;
	var doublyDirected;
	var docDubDirs;
	var infiniteDirections;
	var docInfDirs;

	while(pos<lim){

		theRef=dir_grab(thePairs[pos],"To");
		theMov=dir_grab(thePairs[pos],"From");

		docDirs=dir_grab(thePairs[pos],"directed");
		directed=[];

		docDubDirs=dir_grab(thePairs[pos],"doublyDirected");
		doublyDirected=[];

		docInfDirs=dir_grab(thePairs[pos],"InfiniteDirections");
		infiniteDirections=[];

		docFinDirs=dir_grab(thePairs[pos],"FiniteDirections");
		finiteDirections=[];



		if($(docDirs[vecPos]).innerHTML != "false"){
			docDirs = $(docDirs).children("int");
			vecPos=0;
			vecLim=docDirs.length;
			while(vecPos<vecLim){
				theVec=parseInt(docDirs[vecPos].innerHTML);
				directed.push(theVec);
				vecPos++;
			}
		}


		if($(docDubDirs[vecPos]).innerHTML != "false"){
			docDubDirs = $(docDubDirs).children("int");
			vecPos=0;
			vecLim=docDubDirs.length;
			while(vecPos<vecLim){
				theVec=parseInt(docDubDirs[vecPos].innerHTML);
				doublyDirected.push(theVec);
				vecPos++;
			}
		}

		if($(docInfDirs[vecPos]).innerHTML != "false"){
			docInfDirs = $(docInfDirs).children("int");
			vecPos=0;
			vecLim=docInfDirs.length;
			while(vecPos<vecLim){
				theVec=parseInt(docInfDirs[vecPos].innerHTML);
				infiniteDirections.push(theVec);
				vecPos++;
			}
		}


		theVec=dir_grab(thePairs[pos],"vector");
		namePairs.push({
			name: dir_grab(thePairs[pos],"name").innerHTML,
			Ref: theRef.innerHTML,
			Mov: theMov.innerHTML,
			localLabels: dir_grab(thePairs[pos],"localLabels").innerHTML,
			localVariables: dir_grab(thePairs[pos],"localVariables").innerHTML,
			Directed: dir_grab(thePairs[pos],"Directed").innerHTML,
			DoublyDirected: dir_grab(thePairs[pos],"DoublyDirected").innerHTML,
			InfiniteDirections: infiniteDirections,
			FiniteDirections: dir_grab(thePairs[pos],"FiniteDirections").innerHTML,
			Fasteners: dir_grab(thePairs[pos],"Fasteners").innerHTML,
			Certainty: dir_grab(thePairs[pos],"Certainty").innerHTML,
			ConnectionType: dir_grab(thePairs[pos],"ConnectionType").innerHTML
		});
		pos++;
	}

}



/**
*
* Populates the webpage with graphical representations of the assembly pairs
* stored in the global variable assemblyPairs
*
* @method dir_insertAssemblyPairs
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_insertAssemblyPairs(){

	var pos=0;
	var lim=assemblyPairs.length;
	while(pos<lim){
		var theDiv = document.createElement("div");
		var theText = document.createElement("text");
		theText.innerHTML = assemblyPairs[pos].Ref.Name + " \n<---\n " + assemblyPairs[pos].Mov.Name;
		var theConfBut = document.createElement("button");
		theConfBut.innerHTML = "confirm";
		theConfBut.onclick = function (){
			dir_confirmPair(this);
		}
		var thedir_highlightBut = document.createElement("button");
		thedir_highlightBut.innerHTML = "focus";
		thedir_highlightBut.onclick = (function(position){
			return function(){
				lastPair=currentPair;
				console.log("assigning currentPair");
				console.log(position);
				console.log(assemblyPairs[position]);
				currentPair=assemblyPairs[position];
				console.log ("Doing the focus thing");
			}
		})(pos);
		theText.className="pairText";
		theConfBut.className="dirButton";
		thedir_highlightBut.className="dirButton";
		theDiv.appendChild(theText);
		theDiv.appendChild(document.createElement("br"));
		theDiv.appendChild(thedir_highlightBut);
		theDiv.appendChild(theConfBut);
		theDiv.className="dirPair";
		document.getElementById("unconfirmed").appendChild(theDiv);
		pos++;
	}
	pos--;

}





/**
*
* dir_dehighlights the given pair of parts
*
* @method dir_dehighlight
* @for directionConfirmGlobal
* @param {Object} thePair The pair object to be dir_dehighlighted
* @return {Void}
*
*/
function dir_dehighlight(thePair){
	console.log("The number of vectors is ",theVectors.length);
	dir_removeVectorView(document.getElementById("expandButton"));
	thePair.Ref.Mesh.material=new THREE.MeshLambertMaterial(wireSettings);
	thePair.Mov.Mesh.material=new THREE.MeshLambertMaterial(wireSettings);
}



/**
*
* dir_highlights the given pair of parts
*
* @method dir_highlight
* @for directionConfirmGlobal
* @param {Object} thePair The pair object to be dir_highlighted
* @return {Void}
*
*/

function dir_highlight(thePair){

	console.log(thePair);
	thePair.Ref.Mesh.material=new THREE.MeshLambertMaterial({color: 0x4444FF /*, transparent: true, opacity: 0.6, depthTest: false */});
	thePair.Mov.Mesh.material=new THREE.MeshLambertMaterial({color: 0xFF4444 /*, transparent: true, opacity: 0.6, depthTest: false */});
	thePair.Ref.Mesh.geometry.computeBoundingBox();
	thePair.Mov.Mesh.geometry.computeBoundingBox();
	var theBox=thePair.Mov.Mesh.geometry.boundingBox.clone();
	var distBox = thePair.Mov.Mesh.geometry.boundingBox.clone();
	distBox.union(thePair.Ref.Mesh.geometry.boundingBox);



	var pos=0;
	var lim=theVectors.length;
	while(pos<lim){
		scene.remove( theVectors[pos] );
		pos++;
	}


	theVectors.length=0;
	console.log("Just set the Vectors to 0");
	console.log("The pair is: ", thePair);
	var theVec;

	var theDist = Math.sqrt(Math.pow(distBox.max.x-distBox.min.x,2)+
							Math.pow(distBox.max.y-distBox.min.y,2)+
							Math.pow(distBox.max.y-distBox.min.y,2));


	pos=0;
	lim=thePair.InfiniteDirections.length;
	while(pos<lim){
		theVec = new THREE.Line(  new THREE.Geometry(),  new THREE.LineBasicMaterial({color: 0xff0000}));
		theVec.geometry.vertices[0]=new THREE.Vector3(
								  (theBox.min.x+theBox.max.x)/2,
								  (theBox.min.y+theBox.max.y)/2,
								  (theBox.min.z+theBox.max.z)/2
								 );
		theVec.geometry.vertices[1]=new THREE.Vector3(theDist*theDirections[thePair.InfiniteDirections[pos]].X,
													  theDist*theDirections[thePair.InfiniteDirections[pos]].Y,
													  theDist*theDirections[thePair.InfiniteDirections[pos]].Z);
		theVec.geometry.vertices[1].add(theVec.geometry.vertices[0]);
		theVec.geometry.verticesNeedUpdate=true;
		scene.add(theVec);
		theVectors.push(theVec);
		console.log("Vector List Size is: ",theVectors.length);
		pos++;
	}

	dir_insertVectorView(document.getElementById("expandButton"));

}




/**
*
* Sets the opacity of each (non-dir_highlighted) mesh object to the value of the
* slider element provided
*
* @method dir_fixOpacity
* @for directionConfirmGlobal
* @param {Object} theSlider The slider which is to be referenced when setting object opacity
* @return {Void}
*
*/
function dir_fixOpacity(theSlider){

	console.log("Changing Opacity");
	var val = theSlider.value;
	wireSettings.opacity=val;
	var pos=0;
	var lim=parts.length;
	while(pos<lim){
		if(parts[pos].Mesh!=currentPair.Ref.Mesh && parts[pos].Mesh!=currentPair.Mov.Mesh){
			parts[pos].Mesh.material=new THREE.MeshLambertMaterial(wireSettings);
		}
		pos++;
	}

}



/**
*
* Given a mouseup event, sets corresponding internal button states for mouse-related controls
*
* @method dir_doMouseUp
* @for directionConfirmGlobal
* @param {mouseup event} theEvent
* @return {Void}
*
*/
function dir_doMouseUp(theEvent){
	if(theEvent.button == 0){
		leftDrag = false;
	}
	else if(theEvent.button == 2){
		rightDrag = false;
	}
}


/**
*
* Given a mousedown event, sets corresponding internal button states for mouse-related controls
*
* @method dir_doMouseDown
* @for directionConfirmGlobal
* @param {mousedown event} theEvent
* @return {Void}
*
*/
function dir_doMouseDown(theEvent){
	if(theEvent.button == 0){
		leftDrag = true;
	}
	else if(theEvent.button == 2){
		rightDrag = true;
	}
}


/**
*
* Given a mouseleave event, sets corresponding internal button states for mouse-related controls
*
* @method dir_doMouseLeave
* @for directionConfirmGlobal
* @param {mouseup event} theEvent
* @return {Void}
*
*/
function dir_doMouseLeave(theEvent){
	leftDrag = false;
	rightDrag = false;
	lastMouse = null;
}


/**
*
* Prevents the default response of the given event (used to prevent dropdown menus when right
* clicking on the display).
*
* @method dir_justDont
* @for directionConfirmGlobal
* @param {Event Object} theEvent The event to suppress the default response of.
* @return {Void}
*
*/
function dir_justDont(theEvent){
	theEvent.preventDefault();
}


/**
*
* Given a mousedrag event, rotates the camera or adds a vector to the currently displayed pair,
* depending upon whether or not the left or right mouse button is depressed
*
* @method dir_doDrag
* @for directionConfirmGlobal
* @param {mouseup event} theEvent
* @return {Void}
*
*/
function dir_doDrag(theEvent){


	if(theAddAxis !== null){

		var theBox=currentPair.Mov.Mesh.geometry.boundingBox.clone();
		var theArea = document.getElementById("display");
		var areaW = theArea.clientWidth;
		var areaH = theArea.clientHeight;
		var areaT = theArea.offsetTop;
		var areaL = theArea.offsetLeft;
		var mouseX = theEvent.clientX;
		var mouseY = theEvent.clientY;
		//console.log("aW: "+areaW+" aH: "+areaH+" aT: "+areaT+" aL: "+areaL);
		//console.log("mX: "+(((mouseX-areaL)-areaW/2)/(areaW/2))+" mY: "+((areaH/2-(mouseY-areaT))/(areaH/2)));
		var theDir = dir_getDirectionFromMouse( ((mouseX-areaL)-areaW/2)/(areaW/2), (areaH/2-(mouseY-areaT))/(areaH/2) );

		theAddAxis.geometry.vertices[0].set((theBox.min.x+theBox.max.x)/2,(theBox.min.y+theBox.max.y)/2,(theBox.min.z+theBox.max.z)/2);
		theAddAxis.geometry.vertices[1].set((theBox.min.x+theBox.max.x)/2+theDirections[theDir].X*theDistance*0.6,
											(theBox.min.y+theBox.max.y)/2+theDirections[theDir].Y*theDistance*0.6,
											(theBox.min.z+theBox.max.z)/2+theDirections[theDir].Z*theDistance*0.6 );

		console.log( "X: "+(theBox.min.x+theBox.max.x)/2+
					" Y: "+(theBox.min.y+theBox.max.y)/2+
					" Z: "+(theBox.min.z+theBox.max.z)/2 );

		console.log(" X: "+theDirections[theDir].X +
					" Y: "+theDirections[theDir].Y +
					" Z: "+theDirections[theDir].Z  );

		theAddAxis.geometry.verticesNeedUpdate=true;

	}


	if(leftDrag==true){
		thePos.normalize();
		theEul.set(theEvent.movementY*(-0.02)*Math.cos(Math.atan2(thePos.x,thePos.z)),
				   theEvent.movementX*(-0.02),
				   theEvent.movementY*(0.02)*Math.sin(Math.atan2(thePos.x,thePos.z)),
				   'ZYX');
	}
	if(rightDrag==true){
		dir_addVectorFromMouse(theEvent.clientX, theEvent.clientY);
	}
}


/**
*
* Given a mousewheel event, changes the distance of the camera from the center of the scene
*
* @method dir_doMouseUp
* @for directionConfirmGlobal
* @param {mouseup event} theEvent
* @return {Void}
*
*/
function dir_doZoom(theEvent){
	var theDelta = theEvent.deltaY == 0 ? 0 : ( theEvent.deltaY > 0 ? 1 : -1 );
	theDistance=theDistance*Math.pow(1.001,theDelta*(-40));
}





/**
*
* Inserts the vector view into the webpage
*
* @method dir_insertVectorView
* @for directionConfirmGlobal
* @param {HTML Element} theButton The vector viewing button
* @return {Void}
*
*/
function dir_insertVectorView(theButton){

	console.log("doing dir_insertVectorView");

	if(currentPair==null){
		return;
	}

	currentPair.Ref.Mesh.geometry.computeBoundingBox();
	currentPair.Mov.Mesh.geometry.computeBoundingBox();
	var theBox=currentPair.Mov.Mesh.geometry.boundingBox.clone();
	var distBox = currentPair.Mov.Mesh.geometry.boundingBox.clone()
	distBox.union(currentPair.Ref.Mesh.geometry.boundingBox);

	var theDist = Math.sqrt(Math.pow(distBox.max.x-distBox.min.x,2)+
							Math.pow(distBox.max.y-distBox.min.y,2)+
							Math.pow(distBox.max.y-distBox.min.y,2));

	var theDiv=theButton.parentElement;
	console.log(theDiv);
	theButton.onclick=function () {dir_removeVectorView(this);};
	var theVecList=document.createElement("div");
	theVecList.id="vecList";
	var addButton=document.createElement("button");
	addButton.innerHTML="Add Vector";
	addButton.id="addButton";
	addButton.onclick=function () {dir_addVectorToPair(this);};

	var pos=0;
	var lim=theVectors.length;
	var theEntry;
	var remBut;
	var xLab;
	var xInp;
	var yLab;
	var yInp;
	var zLabl;
	var zInp;
	while(pos<lim){
		theEntry=document.createElement("div");
		remBut=document.createElement("button");
		remBut.innerHTML="Remove";
		remBut.onclick=function () {dir_remVectorFromPair(this);};
		xLab=document.createElement("text");
		xLab.innerHTML="X";
		xInp=document.createElement("input");
		xInp.type="number";
		xInp.step=0.01;
		xInp.value=(theVectors[pos].geometry.vertices[1].x-theVectors[pos].geometry.vertices[0].x)/theDist;
		xInp.onchange=function () {dir_vecEntryUpdate(this);};
		yLab=document.createElement("text");
		yLab.innerHTML="Y";
		yInp=document.createElement("input");
		yInp.type="number";
		yInp.step=0.01;
		yInp.value=(theVectors[pos].geometry.vertices[1].y-theVectors[pos].geometry.vertices[0].y)/theDist;
		yInp.onchange=function () {dir_vecEntryUpdate(this);};
		zLab=document.createElement("text");
		zLab.innerHTML="Z";
		zInp=document.createElement("input");
		zInp.type="number";
		zInp.step=0.01;
		zInp.value=(theVectors[pos].geometry.vertices[1].z-theVectors[pos].geometry.vertices[0].z)/theDist;
		zInp.onchange=function () {dir_vecEntryUpdate(this);};

		theEntry.appendChild(xLab);
		theEntry.appendChild(xInp);
		theEntry.appendChild(document.createElement("br"));
		theEntry.appendChild(yLab);
		theEntry.appendChild(yInp);
		theEntry.appendChild(document.createElement("br"));
		theEntry.appendChild(zLab);
		theEntry.appendChild(zInp);
		theEntry.appendChild(document.createElement("br"));
		theEntry.appendChild(remBut);

		theEntry.counterPart=theVectors[pos];
		theEntry.className="vecEntry";

		theVecList.appendChild(theEntry);
		pos++;
	}

	theDiv.appendChild(addButton);
	theDiv.appendChild(theVecList);

}





/**
*
* Removes the vector view from the webpage
*
* @method dir_removeVectorView
* @for directionConfirmGlobal
* @param {HTML Element} theButton The vector viewing button
* @return {Void}
*
*/
function dir_removeVectorView(theButton){

	console.log("doing dir_removeVectorView");

	var theDiv=theButton.parentElement;
	var vecListHolder=document.getElementById("vecList");



	if(vecListHolder!=null){
		var vecPos=0;
		var vecLim=theVectors.length;
		console.log(theVectors);

		var best;
		var ang;
		var testVector;
		currentPair.InfiniteDirections.length=0;
		while(vecPos<vecLim){
			testVector=new THREE.Vector3(1,1,1);
			//
			testVector.copy(theVectors[vecPos].geometry.vertices[1]);
			testVector.sub(theVectors[vecPos].geometry.vertices[0]);
			testVector.normalize();
			//console.log(testVector);
			pos=dir_getDir(testVector);
			console.log(theVectors[vecPos]);
			if(theVectors[vecPos].material.color.r===1){
				currentPair.InfiniteDirections.push(pos);
				console.log("<--->");
			}

			console.log("Vector List Size is: ",theVectors.length);
			console.log("InfDir List Size is: ",currentPair.InfiniteDirections.length);
			vecPos++;
		}

		theDiv.removeChild(vecListHolder);
		theDiv.removeChild(document.getElementById("addButton"));
	}

	theButton.onclick=function () {dir_insertVectorView(this);};

}


/**
*
* Inserts a blank vector widget into the vector view element
*
* @method dir_addVectorToPair
* @for directionConfirmGlobal
* @param {HTML Element} theButton The "add vector" button
* @return {Void}
*
*/
function dir_addVectorToPair(theButton){

	console.log("doing dir_addVectorToPair");

	var theDiv=theButton.parentElement;
	var theVecList=document.getElementById("vecList");
	//console.log(theVecList);

	var theEntry=document.createElement("div");
	var remBut=document.createElement("button");
	remBut.innerHTML="Remove";
	remBut.onclick=function () {dir_remVectorFromPair(this);};
	var xLab=document.createElement("text");
	xLab.innerHTML="X";
	var xInp=document.createElement("input");
	xInp.type="number";
	xInp.step=0.01;
	xInp.onchange=function () {dir_vecEntryUpdate(this);};
	var yLab=document.createElement("text");
	yLab.innerHTML="Y";
	var yInp=document.createElement("input");
	yInp.type="number";
	yInp.step=0.01;
	yInp.onchange=function () {dir_vecEntryUpdate(this);};
	var zLab=document.createElement("text");
	zLab.innerHTML="Z";
	var zInp=document.createElement("input");
	zInp.type="number";
	zInp.step=0.01;
	zInp.onchange=function () {dir_vecEntryUpdate(this);};

	theEntry.appendChild(xLab);
	theEntry.appendChild(xInp);
	theEntry.appendChild(document.createElement("br"));
	theEntry.appendChild(yLab);
	theEntry.appendChild(yInp);
	theEntry.appendChild(document.createElement("br"));
	theEntry.appendChild(zLab);
	theEntry.appendChild(zInp);
	theEntry.appendChild(document.createElement("br"));
	theEntry.appendChild(remBut);

	theEntry.counterPart=null;
	theEntry.className="vecEntry";

	theVecList.appendChild(theEntry);
	return theEntry;

}




/**
*
* Removes a vector widget from the vector view element
*
* @method dir_remVectorFromPair
* @for directionConfirmGlobal
* @param {HTML Element} theButton The "remove" button of the widget to be removed
* @return {Void}
*
*/
function dir_remVectorFromPair(theButton){

	console.log("doing dir_remVectorFromPair");
	if(theButton.parentElement.counterPart!=null){
		scene.remove(theButton.parentElement.counterPart);
	}

	console.log("The vector length before splice: ",theVectors.lenth);
	theVectors.splice(theVectors.indexOf(theButton.parentElement.counterPart),1);
	console.log("The vector length after splice: ",theVectors.lenth);

	theButton.parentElement.parentElement.removeChild(theButton.parentElement);

}


/**
*
* Updates a vector to match the values in its corresponding widget
* @method dir_vecEntryUpdate
* @for directionConfirmGlobal
* @param {HTML Element} theInput An input element of the vector's widget
* @return {Void}
*
*/
function dir_vecEntryUpdate(theInput){

	console.log("doing dir_vecEntryUpdate");

	var theBox=currentPair.Mov.Mesh.geometry.boundingBox.clone();

	currentPair.Ref.Mesh.geometry.computeBoundingBox();
	currentPair.Mov.Mesh.geometry.computeBoundingBox();
	var theBox=currentPair.Mov.Mesh.geometry.boundingBox.clone();
	var distBox = currentPair.Mov.Mesh.geometry.boundingBox.clone();
	distBox.union(currentPair.Ref.Mesh.geometry.boundingBox);

	var theDist = Math.sqrt(Math.pow(distBox.max.x-distBox.min.x,2)+
							Math.pow(distBox.max.y-distBox.min.y,2)+
							Math.pow(distBox.max.y-distBox.min.y,2));


	var theEntry=theInput.parentElement;
	var theInputs=theEntry.getElementsByTagName("INPUT");
	var pos=0;
	var lim=theInputs.length;
	var current;
	while(pos<lim){
		current=theInputs[pos];
		if(theInputs[pos].value===""){
			return;
		}
		pos++;
	}

	var theMag = Math.sqrt( Math.pow(parseFloat(theInputs[0].value),2)+
							Math.pow(parseFloat(theInputs[1].value),2)+
							Math.pow(parseFloat(theInputs[2].value),2));
	theInputs[0].value = theInputs[0].value/theMag;
	theInputs[1].value = theInputs[1].value/theMag;
	theInputs[2].value = theInputs[2].value/theMag;

	console.log(theInputs);
	if(theEntry.counterPart===null){
		var theVec = new THREE.Line(  new THREE.Geometry(),  new THREE.LineBasicMaterial({color: 0xff0000}));
		theVec.geometry.vertices[0]=new THREE.Vector3(
								  (theBox.min.x+theBox.max.x)/2,
								  (theBox.min.y+theBox.max.y)/2,
								  (theBox.min.z+theBox.max.z)/2
								 );
		theVec.geometry.vertices[1]=new THREE.Vector3(theVec.geometry.vertices[0].x+parseFloat(theInputs[0].value)*theDist,
													  theVec.geometry.vertices[0].y+parseFloat(theInputs[1].value)*theDist,
													  theVec.geometry.vertices[0].z+parseFloat(theInputs[2].value)*theDist);



		scene.add(theVec);
		theVectors.push(theVec);
		console.log("theVectors Updated. New length is: ",theVectors.length);
		theVec.geometry.verticesNeedUpdate=true;
		theEntry.counterPart=theVec;
		theEntry.counterPart.geometry.verticesNeedUpdate=true;
	}
	else{
		var theVerts=theEntry.counterPart.geometry.vertices;
		theVerts[1].x=theVerts[0].x+parseFloat(theInputs[0].value)*theDist;
		theVerts[1].y=theVerts[0].y+parseFloat(theInputs[1].value)*theDist;
		theVerts[1].z=theVerts[0].z+parseFloat(theInputs[2].value)*theDist;
		theEntry.counterPart.geometry.verticesNeedUpdate=true;
	}
	console.log(theEntry.counterPart.geometry.vertices);

}



/**
*
* Finds and returns the index of the direction in the list of usable vector directions
* which best matches the given vector
*
* @method dir_getDir
* @for directionConfirmGlobal
* @param {Vector3} theVec The vector to be searched with
* @return {Int} The index of the best matching direction in the list of usable vector directions
*
*/
function dir_getDir(theVec){

	var maxDot=-1;
	var theDot;
	var best=-1;
	var pos=0;
	var lim=theDirections.length;
	while(pos<lim){
		theDot=theDirections[pos].X*theVec.x+theDirections[pos].Y*theVec.y+theDirections[pos].Z*theVec.z;
		if(theDot>maxDot){
			maxDot=theDot;
			best=pos;
		}
		pos++;
	}
	return best;

}



/**
*
* Processes the information in the webpage into an XML string and inserts a download link
* for the data into the top of the page
*
* @method dir_renderXML
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_renderXML(){


	var start= "<?xml version='1.0' encoding='utf-8'?>\n"+
				"<DirectionSaveStructure xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>\n";
	var end= "</DirectionSaveStructure>\n";

	var arcContent = "<arcs>\n";
	var idxPos;
	var idxLim;
	pos=0;
	lim=namePairs.length;
	while(pos<lim){
		arcContent = arcContent+"<arc xsi:type='Connection'>\n";
		arcContent = arcContent+"<name>"+namePairs[pos].name+"</name>\n";
		arcContent = arcContent+"<localLabels>"+namePairs[pos].localLabels+"</localLabels>\n";
		arcContent = arcContent+"<localVariables>"+namePairs[pos].localVariables+"</localVariables>\n";
		arcContent = arcContent+"<From>"+namePairs[pos].Mov+"</From>\n";
		arcContent = arcContent+"<To>"+namePairs[pos].Ref+"</To>\n";
		arcContent = arcContent+"<directed>"+namePairs[pos].Directed+"</directed>\n";
		arcContent = arcContent+"<doublyDirected>"+namePairs[pos].DoublyDirected+"</doublyDirected>\n";
		arcContent = arcContent+"<InfiniteDirections> \n";
		idxPos=0;
		idxLim=namePairs[pos].InfiniteDirections.length;
		while(idxPos<idxLim){
			arcContent = arcContent+"<int>"+namePairs[pos].InfiniteDirections[idxPos].toString()+"</int>\n";
			idxPos++;
		}
		arcContent = arcContent+"</InfiniteDirections>\n";
		arcContent = arcContent+"<FiniteDirections>"+namePairs[pos].FiniteDirections+"</FiniteDirections>\n";
		arcContent = arcContent+"<Fasteners>"+namePairs[pos].Fasteners+"</Fasteners>\n";
		arcContent = arcContent+"<Certainty>"+namePairs[pos].Certainty+"</Certainty>\n";
		arcContent = arcContent+"<ConnectionType>"+namePairs[pos].ConnectionType+"</ConnectionType>\n";

		arcContent = arcContent+"</arc>\n";
		pos++;
	}
	arcContent= arcContent + "</arcs>\n";

	var result = start + arcContent + end;

	outText = result;
	requestAdvance(5);

}



/**
*
* Initializes the lines for the XYZ compass in the display
*
* @method dir_initAxisLines
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_initAxisLines(){

	theXAxis = new THREE.Line(  new THREE.Geometry(),  new THREE.LineBasicMaterial({color: 0xff0000, depthTest: false }));
	theXAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theXAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theXAxis.frustumCulled = false;

	theYAxis = new THREE.Line(  new THREE.Geometry(),  new THREE.LineBasicMaterial({color: 0x00ff00, depthTest: false }));
	theYAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theYAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theYAxis.frustumCulled = false;

	theZAxis = new THREE.Line(  new THREE.Geometry(),  new THREE.LineBasicMaterial({color: 0x0000ff, depthTest: false }));
	theZAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theZAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theZAxis.frustumCulled = false;

	theAddAxis = new THREE.Line(  new THREE.Geometry(),  new THREE.LineBasicMaterial({color: 0x00ff00, depthTest: true }));
	theAddAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theAddAxis.geometry.vertices.push(new THREE.Vector3(0,0,0));
	theAddAxis.frustumCulled = false;


	scene.add(theXAxis);
	scene.add(theYAxis);
	scene.add(theZAxis);
	scene.add(theAddAxis);


}


/**
*
* Updates the lines for the XYZ compass in the display
*
* @method dir_updateAxisLines
* @for directionConfirmGlobal
* @return {Void}
*
*/
function dir_updateAxisLines(){

	var theRot= new THREE.Quaternion(0,0,0,0);
	theRot.setFromEuler(camera.rotation);
	var theDir= new THREE.Vector3(-3,-3,-5);

	theDir.applyQuaternion(theRot);


	var thePosition = camera.position.clone();

	thePosition.add(theDir);

	theXAxis.geometry.vertices[0].copy(thePosition);
	theXAxis.geometry.vertices[0].x-=0.5;
	theXAxis.geometry.vertices[1].copy(thePosition);
	theXAxis.geometry.vertices[1].x+=1;
	theXAxis.geometry.verticesNeedUpdate=true;

	theYAxis.geometry.vertices[0].copy(thePosition);
	theYAxis.geometry.vertices[0].y-=0.5;
	theYAxis.geometry.vertices[1].copy(thePosition);
	theYAxis.geometry.vertices[1].y+=1;
	theYAxis.geometry.verticesNeedUpdate=true;

	theZAxis.geometry.vertices[0].copy(thePosition);
	theZAxis.geometry.vertices[0].z-=0.5;
	theZAxis.geometry.vertices[1].copy(thePosition);
	theZAxis.geometry.vertices[1].z+=1;
	theZAxis.geometry.verticesNeedUpdate=true;

}




/**
*
* Maps a given mouse X position and mouse Y position to a point on a unit hemisphere facing
* towards the user then returns the index of the closest valid direction
*
* @method dir_getDirectionFromMouse
* @for directionConfirmGlobal
* @param {Float} mouseX
* @param {Float} mouseY
* @return {Int}
*
*/
function dir_getDirectionFromMouse( mouseX, mouseY ){

	var mouseZ;
	mouseZ = Math.pow(1-((mouseX*mouseX)+(mouseY*mouseY)),0.5);

	var theVec = new THREE.Vector3(mouseX,mouseY,mouseZ);
	var theRot = new THREE.Euler( 	0-Math.atan2(thePos.y,Math.sqrt(Math.pow(thePos.z,2)+Math.pow(thePos.x,2))),
									Math.atan2(thePos.x,thePos.z),
									0,
									'ZYX' );
	theVec.applyEuler(theRot);

	var theDir = dir_getDir(theVec);
	return theDir;

}




/**
*
* Adds a vector to the currently displayed pair based off of camera position, mouse X and mouse Y
*
* @method dir_addVectorFromMouse
* @for directionConfirmGlobal
* @param {Float} mouseX The X position of the mouse
* @param {Float} mouseY The Y position of the mouse
* @return {Void}
*
*/
function dir_addVectorFromMouse ( mouseX, mouseY ){

	var theButton = document.getElementById("addButton");
	var theArea = document.getElementById("display");
	var areaW = theArea.clientWidth;
	var areaH = theArea.clientHeight;
	var areaT = theArea.offsetTop;
	var areaL = theArea.offsetLeft;
	console.log("aW: "+areaW+" aH: "+areaH+" aT: "+areaT+" aL: "+areaL);
	console.log("mX: "+(((mouseX-areaL)-areaW/2)/(areaW/2))+" mY: "+((areaH/2-(mouseY-areaT))/(areaH/2)));
	var theDir = dir_getDirectionFromMouse( ((mouseX-areaL)-areaW/2)/(areaW/2), (areaH/2-(mouseY-areaT))/(areaH/2) );


	var theVecList=document.getElementById("vecList");
	var theVecs = theVecList.childNodes;
	var pos = 0;
	var lim = theVecs.length;
	var testVec = new THREE.Vector3(theDirections[theDir].X,theDirections[theDir].Y,theDirections[theDir].Z);
	var otherVec = new THREE.Vector3(0,0,0);
	while(pos<lim){
		if(theVecs[pos]!==null){
			otherVec.copy(theVecs[pos].counterPart.geometry.vertices[1]);
			otherVec.sub(theVecs[pos].counterPart.geometry.vertices[0]);
			if(testVec.angleTo(otherVec) < 0.15){
				return;
			}
		}
		pos++;
	}
	delete testVec;
	delete otherVec;
	var theElem = dir_addVectorToPair(theButton);
	var theInputs = theElem.getElementsByTagName("input");
	theInputs[0].value = theDirections[theDir].X;
	theInputs[1].value = theDirections[theDir].Y;
	theInputs[2].value = theDirections[theDir].Z;
	theInputs[0].onchange();

}










startupScripts["4"] = function() {


	lastPair=null;
	currentPair=null;


	theWidth=document.getElementById("display").clientWidth;
	theHeight= document.getElementById("display").clientHeight;

	// The scene of the assembly animation
	//scene = new THREE.Scene();

	// The camera
	//camera = new THREE.PerspectiveCamera( 75, theWidth/theHeight, 1, 16000 );


	document.getElementById("display").appendChild( renderer.domElement );



	// Inserts the file loading manager into the document
	//document.getElementById('fileinput').addEventListener('change', dir_readMultipleFiles, false);
	document.getElementById("display").addEventListener("mousemove", dir_doDrag);
	document.getElementById("display").addEventListener("wheel", dir_doZoom);

	theXML = inText;

	var i = 0;
	var lim = directionList.length;
	theDirections = [];
	while( i < lim ){
		theDirections.push({
			X: directionList[i][0],
			Y: directionList[i][1],
			Z: directionList[i][2]
		});
		i++;
	}

	dir_renderParts();

}
//</script>