diff --git a/js/bin.js b/js/bin.js new file mode 100755 index 0000000000000000000000000000000000000000..ace3a8bac7f415e5de7f82df9dfddd92bb65406b --- /dev/null +++ b/js/bin.js @@ -0,0 +1,29 @@ +/*jslint browser: true */ +define( function() { + 'use strict'; + + return { + + /** + * @param {string} name + * @param {function()} require + * @param {function()} onload + * @param {Object} config + */ + load: function( name, require, onload, config ) { + + var xhr = new XMLHttpRequest(); + + if (config.paths[name]) name = config.paths[name]; + + xhr.open( 'GET', name, true ); + xhr.responseType = 'arraybuffer'; + + xhr.onload = function( evt ) { + onload( this.response ); + }; + + xhr.send(); + } + }; +} ); diff --git a/js/cells/DMACell.js b/js/cells/DMACell.js index c2d6351310b5f15f2220321689eff2b483fc6e5c..06bcd1399e70c739c6365e34539683041615a3ac 100644 --- a/js/cells/DMACell.js +++ b/js/cells/DMACell.js @@ -226,36 +226,45 @@ define(['underscore', 'three', 'threeModel', 'lattice', 'appState', 'globals'], DMACell.prototype.setMode = function(mode){ if (mode === undefined) mode = appState.get("cellMode"); + var self = this; switch(mode) { case "supercell": if (!this.superCell) mode = "cell";//top level item + setVisiblity(); break; case "cell": + setVisiblity(); break; case "part": if (!this.parts) { - this.parts = this._initParts(); - var self = this; - _.each(this.parts, function(part){ - self.addChildren(part.getMesh()); + this._initParts(function(parts){ + self.parts = parts; + _.each(this.parts, function(part){ + self.addChildren(part.getMesh()); + }); + setVisiblity(); }); } break; case "beam": // if (!this.beams) this.beams = this._initBeams(); + setVisiblity(); break; case "node": // if (!this.nodes) this.nodes = this._initNodes(); + setVisiblity(); break; } - var visible = !(this.superCell && this.cells);//middle layers are always hidden + function setVisiblity(){ + var visible = !(self.superCell && self.cells);//middle layers are always hidden - _.each(this.object3D.children, function(child){ - if (child.name == "object3D") return; - child.visible = visible && (child.name == mode); - }); + _.each(self.object3D.children, function(child){ + if (child.name == "object3D") return; + child.visible = visible && (child.name == mode); + }); + }; }; diff --git a/js/cells/OctaFaceCell.js b/js/cells/OctaFaceCell.js index 0b6fe3245fa62764b231d3c41882a50495a51d18..b1b021661bbf0ed9a7aeaf091af309436fb5e6da 100644 --- a/js/cells/OctaFaceCell.js +++ b/js/cells/OctaFaceCell.js @@ -25,12 +25,15 @@ define(['underscore', 'three', 'threeModel', 'lattice', 'appState', 'cell'], return object3D; }; - OctaFaceCell.prototype._initParts = function(){ - var parts = []; - for (var i=0;i<3;i++){ - parts.push(new OctaFaceTriPart(i, this)); - } - return parts; + OctaFaceCell.prototype._initParts = function(callback){ + var self = this; + require(['octaFaceTriPart'], function(OctaFaceTriPart){ + var parts = []; + for (var i=0;i<3;i++){ + parts.push(new OctaFaceTriPart(i, self)); + } + callback(parts); + }); }; OctaFaceCell.prototype.calcHighlighterParams = function(face){ diff --git a/js/main.js b/js/main.js index f64da74feb3fd98b16de6ba18f15d9f93b723087..747616d71cfc64331f5b2fc88a02f0f60d40b792 100644 --- a/js/main.js +++ b/js/main.js @@ -16,6 +16,7 @@ require.config({ //three three: 'dependencies/three', orbitControls: 'dependencies/OrbitControls', + stlLoader: 'dependencies/loaders/STLLoader', threeModel: 'three/ThreeModel', threeView: 'three/ThreeView', @@ -67,6 +68,10 @@ require.config({ superCell: 'cells/supercells/DMASupercell', gikSuperCell: 'cells/supercells/GIKSuperCell', + //parts + part: 'parts/DMAPart', + octaFaceTriPart: 'parts/OctaFaceTriPart', + //materials materials: 'materials/DMAMaterials', electronicMaterials: 'materials/ElectronicMaterials', @@ -88,7 +93,10 @@ require.config({ assemblerMenu: 'menus/AssemblerMenuView', camMenu: 'menus/CamMenuView', animateMenu: 'menus/AnimationMenuView', - sendMenu: 'menus/SendMenuView' + sendMenu: 'menus/SendMenuView', + + //stls + octaFaceTrianglePart: '../assets/stls/parts/trianglePart.stl' }, @@ -100,6 +108,10 @@ require.config({ deps: ['three'], exports: 'THREE' }, + stlLoader: { + deps: ['three'], + exports: 'THREE' + }, fileSaverLib: { exports: 'saveAs' }, diff --git a/js/parts/DMAPart.js b/js/parts/DMAPart.js index 2eb06073e5e4a74ef7ac690d5e8456504056e675..35f559618b70092c18fdb628f9caa0ec80400277 100644 --- a/js/parts/DMAPart.js +++ b/js/parts/DMAPart.js @@ -3,55 +3,48 @@ */ -var partMaterial = new THREE.MeshLambertMaterial({ color:0xffffff, shading: THREE.FlatShading }); - partMaterial.color.setRGB( 0.9619657144369509, 0.6625466032079207, 0.20799727886007258 ); - -function DMAPart(index, parent) { - this.parentCell = parent; - this.index = index;//todo need this? - this.mesh = this._buildMesh(index); -} - -DMAPart.prototype._buildMesh = function(index){ - var geometry = this._getGeometry(index); - var mesh = new THREE.Mesh(geometry, this.getMaterial()); - mesh.name = "part"; - return mesh; -}; - -DMAPart.prototype.highlight = function(){ -// this.mesh.material.color.setRGB(1,0,0); -}; - -DMAPart.prototype.unhighlight = function(){ -// if (this.mesh) this.mesh.material.color.setRGB(0.9619657144369509, 0.6625466032079207, 0.20799727886007258); -}; - -//DMAPart.prototype.removeFromCell = function(){//send message back to parent cell to destroy this -// if (this.parentCell) { -// this.parentCell.removePart(this.index); -// globals.three.render(); -// } else console.warn("part has no parent cell"); -//}; - -DMAPart.prototype.getMesh = function(){//only call by parent cell - return this.mesh; -}; - -DMAPart.prototype.getMaterial = function(){ - return partMaterial; -}; - -DMAPart.prototype.destroy = function(){ - if (this.mesh) { - this.mesh.parent.remove(this.mesh); - this.mesh = null; - } - this.parentCell = null; - this.index = null; -}; -DMAPart.prototype.toJSON = function(){ - return { +define(['underscore', 'three'], function(_, THREE){ + + function DMAPart(index, parent) { + this.parentCell = parent; + this.index = index; + this.mesh = this._buildMesh(); + this.parentCell.addChildren(this.mesh);//add itself as child of parent cell } -}; + + DMAPart.prototype._buildMesh = function(){ + var mesh = this._translatePart(this._rotatePart(new THREE.Mesh(this._getGeometry(), this.getMaterial()))); + mesh.name = "part"; + return mesh; + }; + + DMAPart.prototype._rotatePart = function(mesh){ + return mesh; + }; + + DMAPart.prototype._translatePart = function(mesh){ + return mesh; + }; + + DMAPart.prototype.getMaterial = function(){ + return this.parentCell.getMaterial(); + }; + + DMAPart.prototype.destroy = function(){ + if (this.mesh) { + this.mesh.parent.remove(this.mesh); + this.mesh = null; + } + this.parentCell = null; + this.index = null; + }; + + DMAPart.prototype.toJSON = function(){ + return { + } + }; + + return DMAPart; +}); + diff --git a/js/parts/OctaFaceTriPart.js b/js/parts/OctaFaceTriPart.js index d3f7612afc79ed26b357e16f294d2b7e5cd38842..339f49ada0846a0149b536933d4653ee9d4ad3e8 100644 --- a/js/parts/OctaFaceTriPart.js +++ b/js/parts/OctaFaceTriPart.js @@ -3,45 +3,39 @@ */ -(function () { - -var unitPartGeo1, unitPartGeo2, unitPartGeo3; - -//import part geometry -var loader = new THREE.STLLoader(); -loader.load("assets/stls/parts/trianglePart.stl", function(geometry){ - - unitPartGeo1 = geometry; - unitPartGeo1.computeBoundingBox(); - var unitScale = 1.2/unitPartGeo1.boundingBox.max.y; - unitPartGeo1.applyMatrix(new THREE.Matrix4().makeScale(unitScale, unitScale, unitScale)); - unitPartGeo1.applyMatrix(new THREE.Matrix4().makeTranslation(0.25,-0.6, -0.45)); - unitPartGeo1.applyMatrix(new THREE.Matrix4().makeRotationZ(-Math.PI/6)); - - unitPartGeo2 = unitPartGeo1.clone(); - unitPartGeo2.applyMatrix(new THREE.Matrix4().makeRotationZ(2*Math.PI/3)); - - unitPartGeo3 = unitPartGeo1.clone(); - unitPartGeo3.applyMatrix(new THREE.Matrix4().makeRotationZ(-2*Math.PI/3)); -}); - -function OctaFaceTriPart(type, parent){ - DMAPart.call(this, type, parent); -} -OctaFaceTriPart.prototype = Object.create(DMAPart.prototype); - -OctaFaceTriPart.prototype._getGeometry = function(index){ - switch(index){ - case 0: - return unitPartGeo1; - case 1: - return unitPartGeo2; - case 2: - return unitPartGeo3; +define(['underscore', 'three', 'part', 'bin!octaFaceTrianglePart', 'stlLoader'], function(_, THREE, DMAPart, trianglePart){ + + var loader = new THREE.STLLoader(); + var unitGeo = loader.parse(trianglePart); + unitGeo.computeBoundingBox(); + var unitScale = 1.2/unitGeo.boundingBox.max.y; + unitGeo.applyMatrix(new THREE.Matrix4().makeScale(unitScale, unitScale, unitScale)); + unitGeo.applyMatrix(new THREE.Matrix4().makeTranslation(0.25,-0.6, -0.45)); + unitGeo.applyMatrix(new THREE.Matrix4().makeRotationZ(-Math.PI/6)); + + function OctaFaceTriPart(type, parent){ + DMAPart.call(this, type, parent); } - console.warn("no geometry for index " + index); - return null; -}; - -self.OctaFaceTriPart = OctaFaceTriPart; -})(); \ No newline at end of file + OctaFaceTriPart.prototype = Object.create(DMAPart.prototype); + + OctaFaceTriPart.prototype._getGeometry = function(){ + if (!unitGeo || unitGeo === undefined) console.warn("geo not loaded yet"); + return unitGeo; + }; + + OctaFaceTriPart.prototype._rotatePart = function(mesh){ + switch(this.index){ + case 0: + return mesh; + case 1: + return mesh.rotateZ(2*Math.PI/3); + case 2: + return mesh.rotateZ(-2*Math.PI/3); + default: + console.warn("uknown index " + this.index + " for part") + return null; + } + }; + + return OctaFaceTriPart; +}); \ No newline at end of file diff --git a/js/text.js b/js/text.js new file mode 100644 index 0000000000000000000000000000000000000000..17921b6e5e0e49f9da54e1635010b3e68ccab061 --- /dev/null +++ b/js/text.js @@ -0,0 +1,390 @@ +/** + * @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/text for details + */ +/*jslint regexp: true */ +/*global require, XMLHttpRequest, ActiveXObject, + define, window, process, Packages, + java, location, Components, FileUtils */ + +define(['module'], function (module) { + 'use strict'; + + var text, fs, Cc, Ci, xpcIsWindows, + progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], + xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, + bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im, + hasLocation = typeof location !== 'undefined' && location.href, + defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), + defaultHostName = hasLocation && location.hostname, + defaultPort = hasLocation && (location.port || undefined), + buildMap = {}, + masterConfig = (module.config && module.config()) || {}; + + text = { + version: '2.0.12', + + strip: function (content) { + //Strips <?xml ...?> declarations so that external SVG and XML + //documents can be added to a document without worry. Also, if the string + //is an HTML document, only the part inside the body tag is returned. + if (content) { + content = content.replace(xmlRegExp, ""); + var matches = content.match(bodyRegExp); + if (matches) { + content = matches[1]; + } + } else { + content = ""; + } + return content; + }, + + jsEscape: function (content) { + return content.replace(/(['\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r") + .replace(/[\u2028]/g, "\\u2028") + .replace(/[\u2029]/g, "\\u2029"); + }, + + createXhr: masterConfig.createXhr || function () { + //Would love to dump the ActiveX crap in here. Need IE 6 to die first. + var xhr, i, progId; + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } else if (typeof ActiveXObject !== "undefined") { + for (i = 0; i < 3; i += 1) { + progId = progIds[i]; + try { + xhr = new ActiveXObject(progId); + } catch (e) {} + + if (xhr) { + progIds = [progId]; // so faster next time + break; + } + } + } + + return xhr; + }, + + /** + * Parses a resource name into its component parts. Resource names + * look like: module/name.ext!strip, where the !strip part is + * optional. + * @param {String} name the resource name + * @returns {Object} with properties "moduleName", "ext" and "strip" + * where strip is a boolean. + */ + parseName: function (name) { + var modName, ext, temp, + strip = false, + index = name.indexOf("."), + isRelative = name.indexOf('./') === 0 || + name.indexOf('../') === 0; + + if (index !== -1 && (!isRelative || index > 1)) { + modName = name.substring(0, index); + ext = name.substring(index + 1, name.length); + } else { + modName = name; + } + + temp = ext || modName; + index = temp.indexOf("!"); + if (index !== -1) { + //Pull off the strip arg. + strip = temp.substring(index + 1) === "strip"; + temp = temp.substring(0, index); + if (ext) { + ext = temp; + } else { + modName = temp; + } + } + + return { + moduleName: modName, + ext: ext, + strip: strip + }; + }, + + xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + + /** + * Is an URL on another domain. Only works for browser use, returns + * false in non-browser environments. Only used to know if an + * optimized .js version of a text resource should be loaded + * instead. + * @param {String} url + * @returns Boolean + */ + useXhr: function (url, protocol, hostname, port) { + var uProtocol, uHostName, uPort, + match = text.xdRegExp.exec(url); + if (!match) { + return true; + } + uProtocol = match[2]; + uHostName = match[3]; + + uHostName = uHostName.split(':'); + uPort = uHostName[1]; + uHostName = uHostName[0]; + + return (!uProtocol || uProtocol === protocol) && + (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && + ((!uPort && !uHostName) || uPort === port); + }, + + finishLoad: function (name, strip, content, onLoad) { + content = strip ? text.strip(content) : content; + if (masterConfig.isBuild) { + buildMap[name] = content; + } + onLoad(content); + }, + + load: function (name, req, onLoad, config) { + //Name has format: some.module.filext!strip + //The strip part is optional. + //if strip is present, then that means only get the string contents + //inside a body tag in an HTML string. For XML/SVG content it means + //removing the <?xml ...?> declarations so the content can be inserted + //into the current doc without problems. + + // Do not bother with the work if a build and text will + // not be inlined. + if (config && config.isBuild && !config.inlineText) { + onLoad(); + return; + } + + masterConfig.isBuild = config && config.isBuild; + + var parsed = text.parseName(name), + nonStripName = parsed.moduleName + + (parsed.ext ? '.' + parsed.ext : ''), + url = req.toUrl(nonStripName), + useXhr = (masterConfig.useXhr) || + text.useXhr; + + // Do not load if it is an empty: url + if (url.indexOf('empty:') === 0) { + onLoad(); + return; + } + + //Load the text. Use XHR if possible and in a browser. + if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { + text.get(url, function (content) { + text.finishLoad(name, parsed.strip, content, onLoad); + }, function (err) { + if (onLoad.error) { + onLoad.error(err); + } + }); + } else { + //Need to fetch the resource across domains. Assume + //the resource has been optimized into a JS module. Fetch + //by the module name + extension, but do not include the + //!strip part to avoid file system issues. + req([nonStripName], function (content) { + text.finishLoad(parsed.moduleName + '.' + parsed.ext, + parsed.strip, content, onLoad); + }); + } + }, + + write: function (pluginName, moduleName, write, config) { + if (buildMap.hasOwnProperty(moduleName)) { + var content = text.jsEscape(buildMap[moduleName]); + write.asModule(pluginName + "!" + moduleName, + "define(function () { return '" + + content + + "';});\n"); + } + }, + + writeFile: function (pluginName, moduleName, req, write, config) { + var parsed = text.parseName(moduleName), + extPart = parsed.ext ? '.' + parsed.ext : '', + nonStripName = parsed.moduleName + extPart, + //Use a '.js' file name so that it indicates it is a + //script that can be loaded across domains. + fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; + + //Leverage own load() method to load plugin value, but only + //write out values that do not have the strip argument, + //to avoid any potential issues with ! in file names. + text.load(nonStripName, req, function (value) { + //Use own write() method to construct full module value. + //But need to create shell that translates writeFile's + //write() to the right interface. + var textWrite = function (contents) { + return write(fileName, contents); + }; + textWrite.asModule = function (moduleName, contents) { + return write.asModule(moduleName, fileName, contents); + }; + + text.write(pluginName, nonStripName, textWrite, config); + }, config); + } + }; + + if (masterConfig.env === 'node' || (!masterConfig.env && + typeof process !== "undefined" && + process.versions && + !!process.versions.node && + !process.versions['node-webkit'])) { + //Using special require.nodeRequire, something added by r.js. + fs = require.nodeRequire('fs'); + + text.get = function (url, callback, errback) { + try { + var file = fs.readFileSync(url, 'utf8'); + //Remove BOM (Byte Mark Order) from utf8 files if it is there. + if (file.indexOf('\uFEFF') === 0) { + file = file.substring(1); + } + callback(file); + } catch (e) { + if (errback) { + errback(e); + } + } + }; + } else if (masterConfig.env === 'xhr' || (!masterConfig.env && + text.createXhr())) { + text.get = function (url, callback, errback, headers) { + var xhr = text.createXhr(), header; + xhr.open('GET', url, true); + + //Allow plugins direct access to xhr headers + if (headers) { + for (header in headers) { + if (headers.hasOwnProperty(header)) { + xhr.setRequestHeader(header.toLowerCase(), headers[header]); + } + } + } + + //Allow overrides specified in config + if (masterConfig.onXhr) { + masterConfig.onXhr(xhr, url); + } + + xhr.onreadystatechange = function (evt) { + var status, err; + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + status = xhr.status || 0; + if (status > 399 && status < 600) { + //An http 4xx or 5xx error. Signal an error. + err = new Error(url + ' HTTP status: ' + status); + err.xhr = xhr; + if (errback) { + errback(err); + } + } else { + callback(xhr.responseText); + } + + if (masterConfig.onXhrComplete) { + masterConfig.onXhrComplete(xhr, url); + } + } + }; + xhr.send(null); + }; + } else if (masterConfig.env === 'rhino' || (!masterConfig.env && + typeof Packages !== 'undefined' && typeof java !== 'undefined')) { + //Why Java, why is this so awkward? + text.get = function (url, callback) { + var stringBuffer, line, + encoding = "utf-8", + file = new java.io.File(url), + lineSeparator = java.lang.System.getProperty("line.separator"), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), + content = ''; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + + if (line !== null) { + stringBuffer.append(line); + } + + while ((line = input.readLine()) !== null) { + stringBuffer.append(lineSeparator); + stringBuffer.append(line); + } + //Make sure we return a JavaScript string and not a Java string. + content = String(stringBuffer.toString()); //String + } finally { + input.close(); + } + callback(content); + }; + } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && + typeof Components !== 'undefined' && Components.classes && + Components.interfaces)) { + //Avert your gaze! + Cc = Components.classes; + Ci = Components.interfaces; + Components.utils['import']('resource://gre/modules/FileUtils.jsm'); + xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); + + text.get = function (url, callback) { + var inStream, convertStream, fileObj, + readData = {}; + + if (xpcIsWindows) { + url = url.replace(/\//g, '\\'); + } + + fileObj = new FileUtils.File(url); + + //XPCOM, you so crazy + try { + inStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + inStream.init(fileObj, 1, 0, false); + + convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] + .createInstance(Ci.nsIConverterInputStream); + convertStream.init(inStream, "utf-8", inStream.available(), + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + + convertStream.readString(inStream.available(), readData); + convertStream.close(); + inStream.close(); + callback(readData.value); + } catch (e) { + throw new Error((fileObj && fileObj.path || '') + ': ' + e); + } + }; + } + return text; +});