{"version":3,"file":"VolumeSlice.cjs","sources":["../../src/misc/VolumeSlice.js"],"sourcesContent":["import { ClampToEdgeWrapping, DoubleSide, LinearFilter, Mesh, MeshBasicMaterial, PlaneGeometry, Texture } from 'three'\n\n/**\n * This class has been made to hold a slice of a volume data\n * @class\n * @param {Volume} volume The associated volume\n * @param {number} [index=0] The index of the slice\n * @param {string} [axis='z'] For now only 'x', 'y' or 'z' but later it will change to a normal vector\n * @see Volume\n */\nclass VolumeSlice {\n constructor(volume, index, axis) {\n const slice = this\n /**\n * @member {Volume} volume The associated volume\n */\n this.volume = volume\n /**\n * @member {Number} index The index of the slice, if changed, will automatically call updateGeometry at the next repaint\n */\n index = index || 0\n Object.defineProperty(this, 'index', {\n get: function () {\n return index\n },\n set: function (value) {\n index = value\n slice.geometryNeedsUpdate = true\n return index\n },\n })\n /**\n * @member {String} axis The normal axis\n */\n this.axis = axis || 'z'\n\n /**\n * @member {HTMLCanvasElement} canvas The final canvas used for the texture\n */\n /**\n * @member {CanvasRenderingContext2D} ctx Context of the canvas\n */\n this.canvas = document.createElement('canvas')\n /**\n * @member {HTMLCanvasElement} canvasBuffer The intermediary canvas used to paint the data\n */\n /**\n * @member {CanvasRenderingContext2D} ctxBuffer Context of the canvas buffer\n */\n this.canvasBuffer = document.createElement('canvas')\n this.updateGeometry()\n\n const canvasMap = new Texture(this.canvas)\n canvasMap.minFilter = LinearFilter\n canvasMap.wrapS = canvasMap.wrapT = ClampToEdgeWrapping\n if ('colorSpace' in canvasMap) canvasMap.colorSpace = 'srgb'\n else canvasMap.encoding = 3001 // sRGBEncoding\n const material = new MeshBasicMaterial({ map: canvasMap, side: DoubleSide, transparent: true })\n /**\n * @member {Mesh} mesh The mesh ready to get used in the scene\n */\n this.mesh = new Mesh(this.geometry, material)\n this.mesh.matrixAutoUpdate = false\n /**\n * @member {Boolean} geometryNeedsUpdate If set to true, updateGeometry will be triggered at the next repaint\n */\n this.geometryNeedsUpdate = true\n this.repaint()\n\n /**\n * @member {Number} iLength Width of slice in the original coordinate system, corresponds to the width of the buffer canvas\n */\n\n /**\n * @member {Number} jLength Height of slice in the original coordinate system, corresponds to the height of the buffer canvas\n */\n\n /**\n * @member {Function} sliceAccess Function that allow the slice to access right data\n * @see Volume.extractPerpendicularPlane\n * @param {Number} i The first coordinate\n * @param {Number} j The second coordinate\n * @returns {Number} the index corresponding to the voxel in volume.data of the given position in the slice\n */\n }\n\n /**\n * @member {Function} repaint Refresh the texture and the geometry if geometryNeedsUpdate is set to true\n * @memberof VolumeSlice\n */\n repaint() {\n if (this.geometryNeedsUpdate) {\n this.updateGeometry()\n }\n\n const iLength = this.iLength,\n jLength = this.jLength,\n sliceAccess = this.sliceAccess,\n volume = this.volume,\n canvas = this.canvasBuffer,\n ctx = this.ctxBuffer\n\n // get the imageData and pixel array from the canvas\n const imgData = ctx.getImageData(0, 0, iLength, jLength)\n const data = imgData.data\n const volumeData = volume.data\n const upperThreshold = volume.upperThreshold\n const lowerThreshold = volume.lowerThreshold\n const windowLow = volume.windowLow\n const windowHigh = volume.windowHigh\n\n // manipulate some pixel elements\n let pixelCount = 0\n\n if (volume.dataType === 'label') {\n //this part is currently useless but will be used when colortables will be handled\n for (let j = 0; j < jLength; j++) {\n for (let i = 0; i < iLength; i++) {\n let label = volumeData[sliceAccess(i, j)]\n label = label >= this.colorMap.length ? (label % this.colorMap.length) + 1 : label\n const color = this.colorMap[label]\n data[4 * pixelCount] = (color >> 24) & 0xff\n data[4 * pixelCount + 1] = (color >> 16) & 0xff\n data[4 * pixelCount + 2] = (color >> 8) & 0xff\n data[4 * pixelCount + 3] = color & 0xff\n pixelCount++\n }\n }\n } else {\n for (let j = 0; j < jLength; j++) {\n for (let i = 0; i < iLength; i++) {\n let value = volumeData[sliceAccess(i, j)]\n let alpha = 0xff\n //apply threshold\n alpha = upperThreshold >= value ? (lowerThreshold <= value ? alpha : 0) : 0\n //apply window level\n value = Math.floor((255 * (value - windowLow)) / (windowHigh - windowLow))\n value = value > 255 ? 255 : value < 0 ? 0 : value | 0\n\n data[4 * pixelCount] = value\n data[4 * pixelCount + 1] = value\n data[4 * pixelCount + 2] = value\n data[4 * pixelCount + 3] = alpha\n pixelCount++\n }\n }\n }\n\n ctx.putImageData(imgData, 0, 0)\n this.ctx.drawImage(canvas, 0, 0, iLength, jLength, 0, 0, this.canvas.width, this.canvas.height)\n\n this.mesh.material.map.needsUpdate = true\n }\n\n /**\n * @member {Function} Refresh the geometry according to axis and index\n * @see Volume.extractPerpendicularPlane\n * @memberof VolumeSlice\n */\n updateGeometry() {\n const extracted = this.volume.extractPerpendicularPlane(this.axis, this.index)\n this.sliceAccess = extracted.sliceAccess\n this.jLength = extracted.jLength\n this.iLength = extracted.iLength\n this.matrix = extracted.matrix\n\n this.canvas.width = extracted.planeWidth\n this.canvas.height = extracted.planeHeight\n this.canvasBuffer.width = this.iLength\n this.canvasBuffer.height = this.jLength\n this.ctx = this.canvas.getContext('2d')\n this.ctxBuffer = this.canvasBuffer.getContext('2d')\n\n if (this.geometry) this.geometry.dispose() // dispose existing geometry\n\n this.geometry = new PlaneGeometry(extracted.planeWidth, extracted.planeHeight)\n\n if (this.mesh) {\n this.mesh.geometry = this.geometry\n //reset mesh matrix\n this.mesh.matrix.identity()\n this.mesh.applyMatrix4(this.matrix)\n }\n\n this.geometryNeedsUpdate = false\n }\n}\n\nexport { VolumeSlice }\n"],"names":["Texture","LinearFilter","ClampToEdgeWrapping","MeshBasicMaterial","DoubleSide","Mesh","PlaneGeometry"],"mappings":";;;AAUA,MAAM,YAAY;AAAA,EAChB,YAAY,QAAQ,OAAO,MAAM;AAC/B,UAAM,QAAQ;AAId,SAAK,SAAS;AAId,YAAQ,SAAS;AACjB,WAAO,eAAe,MAAM,SAAS;AAAA,MACnC,KAAK,WAAY;AACf,eAAO;AAAA,MACR;AAAA,MACD,KAAK,SAAU,OAAO;AACpB,gBAAQ;AACR,cAAM,sBAAsB;AAC5B,eAAO;AAAA,MACR;AAAA,IACP,CAAK;AAID,SAAK,OAAO,QAAQ;AAQpB,SAAK,SAAS,SAAS,cAAc,QAAQ;AAO7C,SAAK,eAAe,SAAS,cAAc,QAAQ;AACnD,SAAK,eAAgB;AAErB,UAAM,YAAY,IAAIA,cAAQ,KAAK,MAAM;AACzC,cAAU,YAAYC,MAAY;AAClC,cAAU,QAAQ,UAAU,QAAQC,MAAmB;AACvD,QAAI,gBAAgB;AAAW,gBAAU,aAAa;AAAA;AACjD,gBAAU,WAAW;AAC1B,UAAM,WAAW,IAAIC,MAAiB,kBAAC,EAAE,KAAK,WAAW,MAAMC,MAAU,YAAE,aAAa,MAAM;AAI9F,SAAK,OAAO,IAAIC,MAAAA,KAAK,KAAK,UAAU,QAAQ;AAC5C,SAAK,KAAK,mBAAmB;AAI7B,SAAK,sBAAsB;AAC3B,SAAK,QAAS;AAAA,EAiBf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMD,UAAU;AACR,QAAI,KAAK,qBAAqB;AAC5B,WAAK,eAAgB;AAAA,IACtB;AAED,UAAM,UAAU,KAAK,SACnB,UAAU,KAAK,SACf,cAAc,KAAK,aACnB,SAAS,KAAK,QACd,SAAS,KAAK,cACd,MAAM,KAAK;AAGb,UAAM,UAAU,IAAI,aAAa,GAAG,GAAG,SAAS,OAAO;AACvD,UAAM,OAAO,QAAQ;AACrB,UAAM,aAAa,OAAO;AAC1B,UAAM,iBAAiB,OAAO;AAC9B,UAAM,iBAAiB,OAAO;AAC9B,UAAM,YAAY,OAAO;AACzB,UAAM,aAAa,OAAO;AAG1B,QAAI,aAAa;AAEjB,QAAI,OAAO,aAAa,SAAS;AAE/B,eAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,iBAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,cAAI,QAAQ,WAAW,YAAY,GAAG,CAAC,CAAC;AACxC,kBAAQ,SAAS,KAAK,SAAS,SAAU,QAAQ,KAAK,SAAS,SAAU,IAAI;AAC7E,gBAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,eAAK,IAAI,UAAU,IAAK,SAAS,KAAM;AACvC,eAAK,IAAI,aAAa,CAAC,IAAK,SAAS,KAAM;AAC3C,eAAK,IAAI,aAAa,CAAC,IAAK,SAAS,IAAK;AAC1C,eAAK,IAAI,aAAa,CAAC,IAAI,QAAQ;AACnC;AAAA,QACD;AAAA,MACF;AAAA,IACP,OAAW;AACL,eAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,iBAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,cAAI,QAAQ,WAAW,YAAY,GAAG,CAAC,CAAC;AACxC,cAAI,QAAQ;AAEZ,kBAAQ,kBAAkB,QAAS,kBAAkB,QAAQ,QAAQ,IAAK;AAE1E,kBAAQ,KAAK,MAAO,OAAO,QAAQ,cAAe,aAAa,UAAU;AACzE,kBAAQ,QAAQ,MAAM,MAAM,QAAQ,IAAI,IAAI,QAAQ;AAEpD,eAAK,IAAI,UAAU,IAAI;AACvB,eAAK,IAAI,aAAa,CAAC,IAAI;AAC3B,eAAK,IAAI,aAAa,CAAC,IAAI;AAC3B,eAAK,IAAI,aAAa,CAAC,IAAI;AAC3B;AAAA,QACD;AAAA,MACF;AAAA,IACF;AAED,QAAI,aAAa,SAAS,GAAG,CAAC;AAC9B,SAAK,IAAI,UAAU,QAAQ,GAAG,GAAG,SAAS,SAAS,GAAG,GAAG,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AAE9F,SAAK,KAAK,SAAS,IAAI,cAAc;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOD,iBAAiB;AACf,UAAM,YAAY,KAAK,OAAO,0BAA0B,KAAK,MAAM,KAAK,KAAK;AAC7E,SAAK,cAAc,UAAU;AAC7B,SAAK,UAAU,UAAU;AACzB,SAAK,UAAU,UAAU;AACzB,SAAK,SAAS,UAAU;AAExB,SAAK,OAAO,QAAQ,UAAU;AAC9B,SAAK,OAAO,SAAS,UAAU;AAC/B,SAAK,aAAa,QAAQ,KAAK;AAC/B,SAAK,aAAa,SAAS,KAAK;AAChC,SAAK,MAAM,KAAK,OAAO,WAAW,IAAI;AACtC,SAAK,YAAY,KAAK,aAAa,WAAW,IAAI;AAElD,QAAI,KAAK;AAAU,WAAK,SAAS,QAAS;AAE1C,SAAK,WAAW,IAAIC,MAAa,cAAC,UAAU,YAAY,UAAU,WAAW;AAE7E,QAAI,KAAK,MAAM;AACb,WAAK,KAAK,WAAW,KAAK;AAE1B,WAAK,KAAK,OAAO,SAAU;AAC3B,WAAK,KAAK,aAAa,KAAK,MAAM;AAAA,IACnC;AAED,SAAK,sBAAsB;AAAA,EAC5B;AACH;;"}