/** * Created by aghassaei on 5/26/15. */ define(['underscore', 'three', 'threeModel', 'lattice', 'appState', 'globals', 'materials'], function(_, THREE, three, lattice, appState, globals, materials){ var wireframeMaterial = new THREE.MeshBasicMaterial({color:0x000000, wireframe:true}); function DMACell(json, superCell){ if (json.index) this.index = new THREE.Vector3(json.index.x, json.index.y, json.index.z); if (superCell) this.superCell = superCell; this.materialName = json.materialName || appState.get("materialType"); this.isTransparent = false; //object 3d is parent to all 3d elements owned by cell: cell mesh and wireframe, parts, beams, nodes, etc this.object3D = this._buildObject3D(); this.addChildren(this._buildMesh(), this.object3D);//build cell meshes if (this.superCell) this.superCell.addChildren(this.object3D);//add as child of supercell if (this.getAbsoluteIndex()){ if (!this.cells) lattice.getUItarget().addHighlightableCell(this.object3D.children[0]);//add mesh as highlightable object, only for lowest level of hierarchy if (!superCell || superCell === undefined) three.sceneAdd(this.object3D);//add object3d as child of scene if top level of hierarchy } else this.hide();//stock cell if (!this.cells) this.setMode(); } //make 3d stuff DMACell.prototype._buildObject3D = function(){ var object3D = this._translateCell(this._rotateCell(new THREE.Object3D())); if (!this.cells) object3D.myParent = this;//reference to get mouse raycasting back, only for lowest level of hierarchy object3D.name = "object3D"; return object3D; }; DMACell.prototype.getObject3D = function(){//careful, used for stock sim only for now todo need this? return this.object3D; }; DMACell.prototype._rotateCell = function(object3D){ return object3D;//by default, no mesh transformations }; DMACell.prototype._translateCell = function(object3D){ if (!this.index) return object3D; var position = lattice.getPositionForIndex(this.index); object3D.position.set(position.x, position.y, position.z); return object3D; }; DMACell.prototype._buildMesh = function(){ var geometry = this._getGeometry(); var meshes = []; var mesh = new THREE.Mesh(geometry, this.getMaterial(true)); mesh.name = this._getMeshName(); meshes.push(mesh); var wireframe = this._buildWireframe(mesh, geometry); if (!wireframe) return meshes; wireframe.name = this._getMeshName(); meshes.push(wireframe); return meshes; }; DMACell.prototype._getMeshName = function(){ if (this._isBottomLayer()) return "cell"; return "supercell"; }; DMACell.prototype._buildWireframe = function(mesh, geometry, isBeam){//for "cell" view if (isBeam) new THREE.Mesh(geometry, wireframeMaterial.clone());//todo fix this return new THREE.Mesh(geometry, wireframeMaterial); }; //position/index/rotation DMACell.prototype.getIndex = function(){ if (!this.index) { // console.warn("no index for this cell"); return null; } return this.index.clone(); }; DMACell.prototype.getAbsoluteIndex = function(){ if (!this.index) { // console.warn("no index for this cell"); return null; } if (!this.superCell) return this.getIndex(); var superCellIndex = this.superCell.getAbsoluteIndex(); if (!superCellIndex) return null; return superCellIndex.add(this.superCell.applyRotation(this.getIndex()).round()); }; DMACell.prototype.getPosition = function(){ return this.object3D.position.clone(); }; DMACell.prototype.getAbsolutePosition = function(){ if (!this.superCell) return this.getPosition(); return this.superCell.getAbsolutePosition().add(this.superCell.applyRotation(this.getPosition())); }; DMACell.prototype.getOrientation = function(){ return this.object3D.quaternion.clone(); }; DMACell.prototype.getAbsoluteOrientation = function(){ if (!this.superCell) return this.getOrientation(); return this.getOrientation().multiply(this.superCell.getAbsoluteOrientation());//order matters! }; DMACell.prototype.applyRotation = function(vector){//todo local rotation? vector.applyQuaternion(this.getOrientation()); return vector; }; DMACell.prototype.applyAbsoluteRotation = function(vector){ vector.applyQuaternion(this.getAbsoluteOrientation()); return vector; }; //highlighting DMACell.prototype.calcHighlighterParams = function(face, point){//this works for cells where addition happens orthogonal to all faces var direction = this.applyAbsoluteRotation(face.normal.clone());//todo local orientation? var position = this.getAbsolutePosition(); position.add(direction.clone().multiply(this.aspectRatio().divideScalar(2))); return {direction:direction, position:position}; }; DMACell.prototype.setDeleteMode = function(state){ var material; if (!state && !this.materialName) return;//cell may be deleted by now if (state) material = materials.list.deleteMaterial.threeMaterial; else material = this.getMaterial(true); if (!material) return;//no material object found if (this.object3D.children[0].material == material) return; if (this.cells){ this._loopCells(function(cell){ if (cell) cell.setDeleteMode(state); }); } if (this.parts){ _.each(this.parts, function(part){ if (part) part.setMaterial(material); }); } this.setMaterial(material); three.render(); }; DMACell.prototype.getParent = function(){ if (this.superCell) return this.superCell.getParent(); return this; }; //children DMACell.prototype.addChildren = function(children, object3D){//accepts an array or a single mesh this._addRemoveChildren(true, children, object3D); }; DMACell.prototype.removeChildren = function(children, object3D){//accepts an array or a single mesh this._addRemoveChildren(false, children, object3D); }; DMACell.prototype._addRemoveChildren = function(shouldAdd, children, object3D){//accepts an array or a single mesh if (object3D === undefined) object3D = this.object3D; if (children.constructor === Array){ _.each(children, function(child){ if (shouldAdd) object3D.add(child); else object3D.remove(child); }); } else if (shouldAdd) object3D.add(children); else object3D.remove(children); }; //visibility DMACell.prototype.hide = function(){ this.object3D.visible = false; }; DMACell.prototype.show = function(mode){ this.object3D.visible = true; this.setMode(mode); }; DMACell.prototype.getMaterialName = function(){ return this.materialName; }; DMACell.prototype.getMaterial = function(returnTHREEObject){ if (!this.materialName) { console.warn("no material type set for cell"); return null; } if (!materials.list[this.materialName]) { console.warn("no material object found of type "); console.warn(this.materialName); return null; } if (!returnTHREEObject) return materials.list[this.materialName]; if (!materials.list[this.materialName].threeMaterial){ console.warn("no three material object found for type "+ this.materialName); return null; } if (this.isTransparent) return materials.list[this.materialName].transparentMaterial; return materials.list[this.materialName].threeMaterial; }; DMACell.prototype.setMaterial = function(material){ this.object3D.children[0].material = material; }; DMACell.prototype.changeMaterial = function(materialName, materialObject){ this.materialName = materialName; if (materialObject === undefined) materialObject = materials.getMaterialForId(materialName).threeMaterial; this.object3D.children[0].material = materialObject; }; DMACell.prototype.setWireframeVisibility = function(visible, mode){ if (visible && mode === undefined) mode = this.getConditionalMode(appState.get("cellMode")); this.object3D.children[1].visible = visible && this.object3D.children[1].name == mode; }; DMACell.prototype.setTransparent = function(evalFunction){ var transparent = evalFunction(this); if (transparent == this.isTransparent) return; this.isTransparent = transparent; this.setMaterial(this.getMaterial(true)); this.setWireframeVisibility(!this.isTransparent); if (this.parts) { _.each(this.parts, function(part){ part.updateMaterial(); }); } }; DMACell.prototype.getConditionalMode = function(mode){ if (mode == "supercell" && this._isBottomLayer() && this._isTopLayer()) return "cell"; return mode; }; DMACell.prototype.setMode = function(mode, callback){ if (!mode || mode === undefined) mode = appState.get("cellMode"); var self = this; mode = this.getConditionalMode(mode); switch(mode) { case "supercell": setVisiblity(); break; case "cell": setVisiblity(); break; case "part": if (!this.cells && !this.parts) { this._initParts(function(parts){ self.parts = parts; setVisiblity(); }); } else setVisiblity(); break; case "beam": if (!this.cells && !this.beams) this.beams = this._initBeams(function(){ if (!this.nodes) this.nodes = self._initNodes(function(){ setVisiblity(); }); else setVisiblity(); }); else setVisiblity(); break; case "node": // if (!this.nodes) this.nodes = this._initNodes(); setVisiblity(); break; default: break; } function setVisiblity(){ var visible = true; if (mode == "supercell") visible = !self._isMiddleLayer();//middle layers are always hidden in supercell mode _.each(self.object3D.children, function(child){ if (child.name == "object3D") return; child.visible = visible && (child.name == mode); }); self.setWireframeVisibility(!self.isTransparent && visible, mode); if (callback) { callback(); return; } if (!self.superCell) three.conditionalRender(); } }; DMACell.prototype._isBottomLayer = function(){ return true; }; DMACell.prototype._isMiddleLayer = function(){ return false; }; DMACell.prototype._isTopLayer = function(){ return this.superCell === null || this.superCell === undefined; }; //subcomponents DMACell.prototype._initParts = function(callback){ if (callback) callback();//override in subclasses return []; }; DMACell.prototype._initNodes = function(callback){ // var PI2 = Math.PI * 2; // var material = new THREE.SpriteCanvasMaterial({ // color: 0xffffff, // program: function ( context ) { // context.beginPath(); // context.arc( 0, 0, 2, 0, PI2, true ); // context.fill(); // } // }); // // var particle = new THREE.Sprite(material); // particle.name = "beam"; // this.addChildren(particle); if (callback) callback(); return true; }; DMACell.prototype._initBeams = function(callback){ var wireframe = this._buildWireframe(this.object3D.children[0], this._getGeometry(), true); wireframe.name = "beam"; if (wireframe.material.wireframeLinewidth) wireframe.material.wireframeLinewidth = 5; else wireframe.material.linewidth = 5; wireframe.material.color = this.getMaterial(true).color; this.addChildren(wireframe); if (callback) callback(); return true; }; //scale DMACell.prototype.aspectRatio = function(){ return new THREE.Vector3(this.xScale(), this.yScale(), this.zScale()); }; DMACell.prototype.xScale = function(){ return lattice.xScale(0); }; DMACell.prototype.yScale = function(){ return lattice.yScale(0); }; DMACell.prototype.zScale = function(){ return lattice.zScale(0); }; //parse DMACell.prototype.addToDenseArray = function(cellsArray, min){ var index = this.getAbsoluteIndex().sub(min); if (cellsArray[index.x][index.y][index.z]) return true; cellsArray[index.x][index.y][index.z] = this; return false; }; DMACell.prototype.removeFromDenseArray = function(cellsArray, min){ var index = this.getAbsoluteIndex().sub(min); cellsArray[index.x][index.y][index.z] = null; }; //destroy DMACell.prototype.destroy = function(){//todo remove reference from lattice.cells this.destroyParts(); if (this.object3D) { if (this.superCell) this.superCell.removeChildren(this.object3D); else if (this.index) three.sceneRemove(this.object3D); if (!this.cells) lattice.getUItarget().removeHighlightableCell(this.object3D.children[0]);//remove mesh as highlightable object this.object3D.myParent = null; // this.object3D.dispose(); // geometry.dispose(); // material.dispose(); this.object3D = null; } this.nodes = null; this.beams = null; this.superCell = null; this.materialName = null; this.index = null; this.length = null; }; DMACell.prototype.destroyParts = function(){ if (!this.parts) return; _.each(this.parts, function(part){ if (part) part.destroy(); }); this.parts = null; }; DMACell.prototype.toJSON = function(){ var data = { materialName: this.materialName }; // if (materials.list[this.materialName].sparseCells) return data;//material definition in material composites // if (this.cells) data.cells = this.cells; return data; }; return DMACell; }); //DMACell.prototype.removePart = function(index){ // this.parts[index].destroy(); // this.parts[index] = null; // var hasAnyParts = false;//check if all parts have been deleted // _.each(this.parts, function(part){ // if (part) hasAnyParts = true; // }); // if (!hasAnyParts) lattice.removeCell(this);//if all parts are gone, remove cell //}; //DMACell.prototype._initNodes = function(vertices){ // var position = this.getPosition(); // var orientation = this.getOrientation(); // var nodes = []; // for (var i=0;i<vertices.length;i++){ // var vertex = vertices[i].clone(); // vertex.applyQuaternion(orientation); // vertex.add(position); // nodes.push(new DmaNode(vertex, i)); // } // return nodes; //}; // // //DMACell.prototype._initBeams = function(nodes, faces){ // var beams = []; // var self = this; // var addBeamFunc = function(index1, index2){ // var duplicate = false; // _.each(beams, function(beam){ // var index = beam.getIndex(); // if (index[0] == index1 && index[1] == index2) duplicate = true; // }); // if (duplicate) return; // var diff = nodes[index1].getPosition(); // diff.sub(nodes[index2].getPosition()); // if (diff.length() > self.getScale()*1.01) return; // if (index2>index1) { // beams.push(new DmaBeam(nodes[index1], nodes[index2], self)); // } // }; // for (var i=0;i<nodes.length;i++){ // _.each(faces, function(face){ // if (face.a == i) { // addBeamFunc(i, face.b); // addBeamFunc(i, face.c); // } else if (face.b == i){ // addBeamFunc(i, face.a); // addBeamFunc(i, face.c); // } else if (face.c == i){ // addBeamFunc(i, face.a); // addBeamFunc(i, face.b); // } // }) // } // return beams; //};