UNPKG

three-stdlib

Version:

stand-alone library of threejs examples

116 lines (115 loc) 4.43 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); class VolumeSlice { constructor(volume, index, axis) { const slice = this; this.volume = volume; index = index || 0; Object.defineProperty(this, "index", { get: function() { return index; }, set: function(value) { index = value; slice.geometryNeedsUpdate = true; return index; } }); this.axis = axis || "z"; this.canvas = document.createElement("canvas"); this.canvasBuffer = document.createElement("canvas"); this.updateGeometry(); const canvasMap = new THREE.Texture(this.canvas); canvasMap.minFilter = THREE.LinearFilter; canvasMap.wrapS = canvasMap.wrapT = THREE.ClampToEdgeWrapping; if ("colorSpace" in canvasMap) canvasMap.colorSpace = "srgb"; else canvasMap.encoding = 3001; const material = new THREE.MeshBasicMaterial({ map: canvasMap, side: THREE.DoubleSide, transparent: true }); this.mesh = new THREE.Mesh(this.geometry, material); this.mesh.matrixAutoUpdate = false; this.geometryNeedsUpdate = true; this.repaint(); } /** * @member {Function} repaint Refresh the texture and the geometry if geometryNeedsUpdate is set to true * @memberof VolumeSlice */ repaint() { if (this.geometryNeedsUpdate) { this.updateGeometry(); } const iLength = this.iLength, jLength = this.jLength, sliceAccess = this.sliceAccess, volume = this.volume, canvas = this.canvasBuffer, ctx = this.ctxBuffer; const imgData = ctx.getImageData(0, 0, iLength, jLength); const data = imgData.data; const volumeData = volume.data; const upperThreshold = volume.upperThreshold; const lowerThreshold = volume.lowerThreshold; const windowLow = volume.windowLow; const windowHigh = volume.windowHigh; let pixelCount = 0; if (volume.dataType === "label") { for (let j = 0; j < jLength; j++) { for (let i = 0; i < iLength; i++) { let label = volumeData[sliceAccess(i, j)]; label = label >= this.colorMap.length ? label % this.colorMap.length + 1 : label; const color = this.colorMap[label]; data[4 * pixelCount] = color >> 24 & 255; data[4 * pixelCount + 1] = color >> 16 & 255; data[4 * pixelCount + 2] = color >> 8 & 255; data[4 * pixelCount + 3] = color & 255; pixelCount++; } } } else { for (let j = 0; j < jLength; j++) { for (let i = 0; i < iLength; i++) { let value = volumeData[sliceAccess(i, j)]; let alpha = 255; alpha = upperThreshold >= value ? lowerThreshold <= value ? alpha : 0 : 0; value = Math.floor(255 * (value - windowLow) / (windowHigh - windowLow)); value = value > 255 ? 255 : value < 0 ? 0 : value | 0; data[4 * pixelCount] = value; data[4 * pixelCount + 1] = value; data[4 * pixelCount + 2] = value; data[4 * pixelCount + 3] = alpha; pixelCount++; } } } ctx.putImageData(imgData, 0, 0); this.ctx.drawImage(canvas, 0, 0, iLength, jLength, 0, 0, this.canvas.width, this.canvas.height); this.mesh.material.map.needsUpdate = true; } /** * @member {Function} Refresh the geometry according to axis and index * @see Volume.extractPerpendicularPlane * @memberof VolumeSlice */ updateGeometry() { const extracted = this.volume.extractPerpendicularPlane(this.axis, this.index); this.sliceAccess = extracted.sliceAccess; this.jLength = extracted.jLength; this.iLength = extracted.iLength; this.matrix = extracted.matrix; this.canvas.width = extracted.planeWidth; this.canvas.height = extracted.planeHeight; this.canvasBuffer.width = this.iLength; this.canvasBuffer.height = this.jLength; this.ctx = this.canvas.getContext("2d"); this.ctxBuffer = this.canvasBuffer.getContext("2d"); if (this.geometry) this.geometry.dispose(); this.geometry = new THREE.PlaneGeometry(extracted.planeWidth, extracted.planeHeight); if (this.mesh) { this.mesh.geometry = this.geometry; this.mesh.matrix.identity(); this.mesh.applyMatrix4(this.matrix); } this.geometryNeedsUpdate = false; } } exports.VolumeSlice = VolumeSlice; //# sourceMappingURL=VolumeSlice.cjs.map