export function decodeRawChunk(chunk: VolumeChunk, response: ArrayBuffer) { let {spec} = chunk.source!; let {dataType} = spec; let numElements = prod3(chunk.chunkDataSize!); let bytesPerElement = DATA_TYPE_BYTES[dataType]; let expectedBytes = numElements * bytesPerElement * spec.numChannels; if (expectedBytes !== response.byteLength) { throw new Error( `Raw-format chunk is ${response.byteLength} bytes, but ${numElements} * ${bytesPerElement} = ${expectedBytes} bytes are expected.`); } let data: ArrayBufferView; switch (dataType) { case DataType.UINT8: data = new Uint8Array(response); break; case DataType.UINT16: data = new Uint16Array(response); break; case DataType.UINT32: case DataType.UINT64: data = new Uint32Array(response); break; case DataType.FLOAT32: data = new Float32Array(response); break; default: throw new Error(`Unexpected data type: ${dataType}.`); } postProcessRawData(chunk, data); }
constructor(options: VolumeChunkSpecificationOptions) { let { lowerVoxelBound = kZeroVec, upperVoxelBound, chunkDataSize, voxelSize, transform, baseVoxelOffset = kZeroVec } = options; let { lowerClipBound = vec3.multiply(vec3.create(), voxelSize, lowerVoxelBound), upperClipBound = vec3.multiply(vec3.create(), voxelSize, upperVoxelBound) } = options; const chunkSize = vec3.multiply(vec3.create(), chunkDataSize, voxelSize); let lowerChunkBound = vec3.create(); let upperChunkBound = vec3.create(); for (let i = 0; i < 3; ++i) { lowerChunkBound[i] = Math.floor(lowerVoxelBound[i] / chunkDataSize[i]); upperChunkBound[i] = Math.floor((upperVoxelBound[i] - 1) / chunkDataSize[i] + 1); } super({voxelSize, transform, lowerChunkBound, upperChunkBound, chunkSize}); this.baseVoxelOffset = baseVoxelOffset; this.lowerClipBound = lowerClipBound; this.upperClipBound = upperClipBound; this.lowerVoxelBound = lowerVoxelBound; this.upperVoxelBound = upperVoxelBound; this.chunkDataSize = chunkDataSize; let dataType = this.dataType = options.dataType; let numChannels = this.numChannels = options.numChannels; this.chunkBytes = prod3(chunkDataSize) * DATA_TYPE_BYTES[dataType] * numChannels; this.compressedSegmentationBlockSize = options.compressedSegmentationBlockSize; }
it(`round trip ${volumeSize.join(',')}`, () => { const numPossibleValues = 15; const input = makeRandomUint32Array(prod3(volumeSize), numPossibleValues); const blockSize = [2, 2, 2]; const output = new Uint32ArrayBuilder(); encodeChannel(output, blockSize, input, volumeSize); const decoded = new Uint32Array(input.length); decodeChannel(decoded, output.view, 0, volumeSize, blockSize); expect(decoded).toEqual(input); });
export function formatBoundingBoxVolume(pointA: vec3, pointB: vec3, transform: mat4) { let dimensionText = ''; const vector = vec3.create(); for (let axis = 0; axis < 3; ++axis) { vec3.set(vector, 0, 0, 0); vector[axis] = pointB[axis] - pointA[axis]; const spatialVector = transformVectorByMat4(vector, vector, transform); const length = vec3.length(spatialVector); if (axis !== 0) { dimensionText += ' × '; } dimensionText += formatLength(length); } const preTransformVolume = Math.abs(prod3(vec3.subtract(vector, pointB, pointA))); const det = mat3.determinant(mat3.fromMat4(mat3.create(), transform)); const postTransformVolume = det * preTransformVolume; return `${dimensionText} [${formatVolume(postTransformVolume)}]`; }