diff --git a/io/loader.js b/io/loader.js index 5c96b8551..535c40019 100644 --- a/io/loader.js +++ b/io/loader.js @@ -239,10 +239,9 @@ X.loader.prototype.load = function(container, object) { // configure the URL request.open('GET', filepath, true); request.responseType = 'arraybuffer'; - + // .. and GO! request.send(null); - }; @@ -293,6 +292,11 @@ X.loader.prototype.parse = function(request, container, object) { // call the parse function and pass in the container, the object and the // data stream and some additional value _parser.parse(container, object, _data, flags); + + var event = document.createEvent("HTMLEvents"); + event.initEvent("parsingComplete", true, true); + event.eventName = "parsingComplete"; + document.documentElement.dispatchEvent(event); }.bind(this), 100); @@ -323,12 +327,14 @@ X.loader.prototype.complete = function(event) { // .. but mark the container as dirty since its content changed container._dirty = true; - - // fire the modified event on the object - object.modified(); - + // mark the loading job as completed this._jobs.set(container._id, true); + + // fire the modified event on the object if all loading jobs complete + if (this.completed()) { + object.modified(); + } }.bind(this), 100); diff --git a/io/parser.js b/io/parser.js index af3020fb6..d8fe9fbb7 100644 --- a/io/parser.js +++ b/io/parser.js @@ -755,11 +755,12 @@ X.parser.xyBBox = function(_solutionsXY){ * @param {!X.object} object The X.volume. * @param {!boolean} hasLabelMap Volume has labelmap attached. * @param {goog.structs.Map} colorTable Associated color table. + * @param {Function} colormap Function mapping from labelmap pixel intensity to rgba. * * @return The target slice. * @static */ -X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color, _bbox, _IJKVolume, object, hasLabelMap, colorTable){ +X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color, _bbox, _IJKVolume, object, hasLabelMap, colorTable, colormap){ var sliceXY = new X.slice(); @@ -913,7 +914,7 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color // check for out of range and use the last label value in this case if (!lookupValue) { - lookupValue = [ 0, .61, 0, 0, 1 ]; + lookupValue = [ 0, 0.61, 0, 0, 1 ]; } @@ -923,6 +924,14 @@ X.parser.reslice2 = function(_sliceOrigin, _sliceXYSpacing, _sliceNormal, _color pixelValue_a = 255 * lookupValue[4]; } +// else if (colormap) { +// // colormap should be function taking value between 0 and 1 and returning rgba values [0,255] +// var mapColor = colormap((pixval - object._min) / (object._max - object._min)); +// pixelValue_r = mapColor[0]; +// pixelValue_g = mapColor[1]; +// pixelValue_b = mapColor[2]; +// pixelValue_a = mapColor[3]; +// } else { // normalization should not happen here, only in the shaders/canvas?? pixelValue_r = pixelValue_g = pixelValue_b = 255 * ((pixval - object._min )/ (object._max - object._min)); @@ -1155,7 +1164,8 @@ X.parser.prototype.reslice = function(object) { // ------------------------------------------ // SETUP LABEL MAPS AND COLOR TABLES // ------------------------------------------ - object.hasLabelMap = object._labelmap != null; + object.hasLabelMap = object._labelmap != null && !goog.isArray(object._labelmap); + object.hasLabelMapArray = object._labelmap != null && goog.isArray(object._labelmap); if (object._colortable) { object._colorTable = object._colortable._map; } @@ -1214,13 +1224,18 @@ X.parser.prototype.reslice = function(object) { _sliceOrigin[1] = object._childrenInfo[0]._solutionsLine[0][0][1] + object._childrenInfo[0]._sliceDirection[1]*Math.floor(object._childrenInfo[0]._nb/2); _sliceOrigin[2] = object._childrenInfo[0]._solutionsLine[0][0][2] + object._childrenInfo[0]._sliceDirection[2]*Math.floor(object._childrenInfo[0]._nb/2); - var _slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[0]._sliceXYSpacing, object._childrenInfo[0]._sliceNormal, object._childrenInfo[0]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable); + var _slice = X.parser.reslice2(_sliceOrigin, object._childrenInfo[0]._sliceXYSpacing, object._childrenInfo[0]._sliceNormal, object._childrenInfo[0]._color, object._BBox, object._IJKVolume, object, object.hasLabelMap, object._colorTable, object._colormap); if (object.hasLabelMap) { // if this object has a labelmap, // we have it loaded at this point (for sure) // ..so we can attach it as the second texture to this slice _slice._labelmap = object._labelmap._children[0]._children[Math.floor(object._childrenInfo[0]._nb/2)]._texture; + } else if (object.hasLabelMapArray) { + _slice._labelmap = []; + for (var i=0; i + * + * The X Toolkit (XTK) is licensed under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * "Free software" is a matter of liberty, not price. + * "Free" as in "free speech", not as in "free beer". + * - Richard M. Stallman + * + * + */ +// provides +goog.provide('X.vector4'); + +// requires +goog.require('goog.vec.Vec4'); + + +// expose the following goog.math.Vec3 functionality +/** + * @constructor + * @see goog.math.Vec3 + */ +X.vector4 = goog.vec.Vec4; + + +// /** +// * @see goog.math.Vec3.prototype.clone +// */ +// X.vector.prototype.clone = goog.math.Vec3.prototype.clone; +// +// +// /** +// * @see goog.math.Vec3.prototype.magnitude +// */ +// X.vector.prototype.magnitude = goog.math.Vec3.prototype.magnitude; +// +// +// /** +// * @see goog.math.Vec3.prototype.scale +// */ +// X.vector.prototype.scale = goog.math.Vec3.prototype.scale; +// +// +// /** +// * @see goog.math.Vec3.prototype.invert +// */ +// X.vector.prototype.invert = goog.math.Vec3.prototype.invert; +// +// +// /** +// * @see goog.math.Vec3.prototype.add +// */ +// X.vector.prototype.add = goog.math.Vec3.prototype.add; +// +// +// /** +// * @see goog.math.Vec3.prototype.subtract +// */ +// X.vector.prototype.subtract = goog.math.Vec3.prototype.subtract; +// +// +// /** +// * Normalize the vector. The goog.math.Vec3.prototype.normalize +// * did not check on a magnitude of 0 resulting in an error. +// * +// * @return {!X.vector|!goog.math.Vec3} The normalized vector. +// */ +// X.vector.prototype.normalize = function() { +// // add a special check if the magnitude is 0 +// var _magnitude = this.magnitude(); +// if (_magnitude == 0) { +// return this.scale(0); +// } +// return this.scale(1 / _magnitude); +// }; +// +// +// /** +// * @see goog.math.Vec3.dot +// */ +// X.vector.dot = goog.math.Vec3.dot; +// +// +// /** +// * @see goog.math.Vec3.cross +// */ +// X.vector.cross = goog.math.Vec3.cross; +// +// +// /** +// * @see goog.math.Vec3.distance +// */ +// X.vector.distance = goog.math.Vec3.distance; +// +// +// /** +// * @see goog.math.Vec3.lerp +// */ +// X.vector.lerp = goog.math.Vec3.lerp; + +// // now we need to make sure we can access the x,y,z +// // components of a goog.math.Vec3 which might be renamed +// // during the compilation. we don't want to modify the goog.math.Vec3 +// // class so this is the easiest workaround. +// /** +// * Get the x component of this vector. +// * +// * @return {number} The x component of this vector. +// * @public +// */ +// X.vector4.prototype.__defineGetter__('xx', function() { +// +// return this.x; +// +// }); +// +// +// /** +// * Get the y component of this vector. +// * +// * @return {number} The y component of this vector. +// * @public +// */ +// X.vector4.prototype.__defineGetter__('yy', function() { +// +// return this.y; +// +// }); +// +// +// /** +// * Get the z component of this vector. +// * +// * @return {number} The z component of this vector. +// * @public +// */ +// X.vector4.prototype.__defineGetter__('zz', function() { +// +// return this.z; +// +// }); + + +goog.exportSymbol('X.vector4', X.vector4); +goog.exportSymbol('X.vector4.createFloat32FromValues', X.vector4.createFloat32FromValues); +goog.exportSymbol('X.vector4.createFloat32', X.vector4.createFloat32); +// goog.exportSymbol('X.vector.prototype.clone', X.vector.prototype.clone); +// goog.exportSymbol('X.vector.prototype.magnitude', X.vector.prototype.magnitude); +// goog.exportSymbol('X.vector.prototype.scale', X.vector.prototype.scale); +// goog.exportSymbol('X.vector.prototype.invert', X.vector.prototype.invert); +// goog.exportSymbol('X.vector.prototype.normalize', X.vector.prototype.normalize); +// goog.exportSymbol('X.vector.prototype.add', X.vector.prototype.add); +// goog.exportSymbol('X.vector.prototype.subtract', X.vector.prototype.subtract); +// goog.exportSymbol('X.vector.dot', X.vector.dot); +// goog.exportSymbol('X.vector.cross', X.vector.cross); +// goog.exportSymbol('X.vector.distance', X.vector.distance); +// goog.exportSymbol('X.vector.lerp', X.vector.lerp); \ No newline at end of file diff --git a/objects/labelmap.js b/objects/labelmap.js index c1cec8fe4..93e2a9e21 100644 --- a/objects/labelmap.js +++ b/objects/labelmap.js @@ -97,7 +97,6 @@ X.labelmap.prototype.modified = function() { }; - /** * Show only the label with the given value or color (RGBA 0..1). If null is passed, * show all labels. diff --git a/objects/object.js b/objects/object.js index 8dfe7b567..70f119477 100755 --- a/objects/object.js +++ b/objects/object.js @@ -72,6 +72,14 @@ X.object = function(object) { * @protected */ this._children = new Array(); + + /** + * The colormap Function associated with this object. + * + * @type {Function} + * @protected + */ + this._colormap = null; /** * The color table of this object. @@ -179,6 +187,36 @@ X.object.prototype.copy_ = function(object) { }; +/** + * Associate a function with the _colormap property which can be used to color + * the labelmap based on normalized voxel values. + * + * @param {Function} A Function object taking a single argument between 0 and 1 and returning a + * length 4 Array containing rgba values between 0 and 255. + * @throws {Error} + * @public + */ +X.object.prototype.__defineSetter__('colormap', function(func) { + + if (!goog.isDefAndNotNull(func) || !goog.isFunction(func)) { + throw new Error('No function defined for colormap.'); + } + if (func.length != 1) { + throw new Error('Invalid number of arguments required for colormap function.'); + } else { + var rgba = func(1); + if (!goog.isArray(rgba) || rgba.length != 4) { + throw new Error('Return value of colormap is not a length 4 Array.'); + } else { + for (var i=0; i<4; i++) { + if (!goog.isNumber(rgba[i]) || rgba[i] < 0 || rgba[i] > 255) { + throw new Error('Return Array of colormap function contains one or more invalid rgba values.'); + } + } + } + } + this._colormap = func; +}); /** * The color table associated with this object. @@ -228,6 +266,17 @@ X.object.prototype.__defineGetter__('children', function() { }); +/** + * Set the children of this object. + * + * @return {!Array} The children of this object which are again objects. + */ +X.object.prototype.__defineSetter__('children', function(newChildren) { + + this._children = newChildren; + +}); + /** * Fire a modified event for this object. * diff --git a/objects/slice.js b/objects/slice.js index bb1bc085c..6f87bbd71 100644 --- a/objects/slice.js +++ b/objects/slice.js @@ -221,6 +221,13 @@ X.slice.prototype.__defineGetter__('right', function() { }); +/** + * Get the labelmap of this slice. + */ +X.slice.prototype.__defineGetter__('labelmap', function() { + return this._labelmap +}); + /** * Setup this X.slice and create it. diff --git a/objects/volume.js b/objects/volume.js index f89753908..4df31632b 100644 --- a/objects/volume.js +++ b/objects/volume.js @@ -555,17 +555,30 @@ X.volume.prototype.slicing_ = function() { //attach labelmap if(this.hasLabelMap){ - var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[xyz]._sliceXYSpacing, this._childrenInfo[xyz]._sliceNormal, this._childrenInfo[xyz]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, this._labelmap._colortable._map); + var colortable = this._labelmap._colortable ? this._labelmap._colortable._map : null; + var _sliceLabel = X.parser.reslice2(_sliceOrigin, this._childrenInfo[xyz]._sliceXYSpacing, this._childrenInfo[xyz]._sliceNormal, this._childrenInfo[xyz]._color, this._BBox, this._labelmap._IJKVolume, this._labelmap, this._labelmap.hasLabelMap, colortable, this._labelmap._colormap); this._labelmap._children[xyz]._children[parseInt(currentIndex, 10)] = _sliceLabel; // add it to create the texture this._labelmap._children[xyz].modified(true); + } else if (this.hasLabelMapArray) { + for (var i=0; i