import { Vector3 } from "three"; import Channel from "./Channel.js"; import Histogram from "./Histogram.js"; import { Lut } from "./Lut.js"; import { type IVolumeLoader, LoadSpec, type PerChannelCallback } from "./loaders/IVolumeLoader.js"; import type { NumberType, TypedArray } from "./types.js"; import { type ImageInfo, CImageInfo } from "./ImageInfo.js"; interface VolumeDataObserver { onVolumeData: (vol: Volume, batch: number[]) => void; onVolumeChannelAdded: (vol: Volume, idx: number) => void; onVolumeLoadError: (vol: Volume, error: unknown) => void; } /** * A renderable multichannel volume image with 8-bits per channel intensity values. * @class * @param {ImageInfo} imageInfo */ export default class Volume { imageInfo: CImageInfo; loadSpec: Required; loader?: IVolumeLoader; /** `LoadSpec` representing the minimum data required to display what's in the viewer (subregion, channels, etc.). * Used to intelligently issue load requests whenever required by a state change. Modify with `updateRequiredData`. */ loadSpecRequired: Required; channelLoadCallback?: PerChannelCallback; imageMetadata: Record; name: string; channels: Channel[]; numChannels: number; channelNames: string[]; channelColorsDefault: [number, number, number][]; /** The maximum of the measurements of 3 axes in physical units (pixels*physicalSize) */ physicalScale: number; /** The physical size of a voxel in the original level 0 volume */ physicalPixelSize: Vector3; /** The physical dims of the whole volume (not accounting for subregion) */ physicalSize: Vector3; /** Normalized physical size of the whole volume (not accounting for subregion) */ normPhysicalSize: Vector3; normRegionSize: Vector3; normRegionOffset: Vector3; physicalUnitSymbol: string; tickMarkPhysicalLength: number; private volumeDataObservers; private loaded; constructor(imageInfo?: ImageInfo, loadSpec?: LoadSpec, loader?: IVolumeLoader); private setUnloaded; isLoaded(): boolean; updateDimensions(): void; /** Returns `true` iff differences between `loadSpec` and `loadSpecRequired` indicate new data *must* be loaded. */ private mustLoadNewData; /** * Returns `true` iff differences between `loadSpec` and `loadSpecRequired` indicate a new load *may* get a * different scale level than is currently loaded. * * This checks for changes in properties that *can*, but do not *always*, change the scale level the loader picks. * For example, a smaller `subregion` *may* mean a higher scale level will fit within memory constraints, or it may * not. A higher `scaleLevelBias` *may* nudge the volume into a higher scale level, or we may already be at the max * imposed by `multiscaleLevel`. */ private mayLoadNewScaleLevel; /** Call on any state update that may require new data to be loaded (subregion, enabled channels, time, etc.) */ updateRequiredData(required: Partial, onChannelLoaded?: PerChannelCallback): Promise; private loadScaleLevelDims; /** * Loads new data as specified in `this.loadSpecRequired`. Clones `loadSpecRequired` into `loadSpec` to indicate * that the data that *must* be loaded is now the data that *has* been loaded. */ private loadNewData; setVoxelSize(size: Vector3): void; setUnitSymbol(symbol: string): void; /** Computes the center of the volume subset */ getContentCenter(): Vector3; cleanup(): void; getChannel(channelIndex: number): Channel; onChannelLoaded(batch: number[]): void; /** * Assign volume data via a 2d array containing the z slices as tiles across it. Assumes that the incoming data is consistent with the image's pre-existing imageInfo tile metadata. * @param {number} channelIndex * @param {Uint8Array} atlasdata * @param {number} atlaswidth * @param {number} atlasheight */ setChannelDataFromAtlas(channelIndex: number, atlasdata: TypedArray, atlaswidth: number, atlasheight: number, range: [number, number], dtype?: NumberType): void; /** * Assign volume data as a 3d array ordered x,y,z. The xy size must be equal to tilewidth*tileheight from the imageInfo used to construct this Volume. Assumes that the incoming data is consistent with the image's pre-existing imageInfo tile metadata. * @param {number} channelIndex * @param {Uint8Array} volumeData */ setChannelDataFromVolume(channelIndex: number, volumeData: TypedArray, range: [number, number], dtype?: NumberType): void; /** * Add a new channel ready to receive data from one of the setChannelDataFrom* calls. * Name and color will be defaulted if not provided. For now, leave imageInfo alone as the "original" data * @param {string} name * @param {Array.} color [r,g,b] */ appendEmptyChannel(name: string, color?: [number, number, number]): number; /** * Get a value from the volume data * @return {number} the intensity value from the given channel at the given xyz location * @param {number} c The channel index * @param {number} x * @param {number} y * @param {number} z */ getIntensity(c: number, x: number, y: number, z: number): number; /** * Get the 256-bin histogram for the given channel * @return {Histogram} the histogram * @param {number} c The channel index */ getHistogram(c: number): Histogram; /** * Set the lut for the given channel * @param {number} c The channel index * @param {Array.} lut The lut as a 256 element array */ setLut(c: number, lut: Lut): void; /** * Set the color palette for the given channel * @param {number} c The channel index * @param {Array.} palette The colors as a 256 element array * RGBA */ setColorPalette(c: number, palette: Uint8Array): void; /** * Set the color palette alpha multiplier for the given channel. * This will blend between the ordinary color lut and this colorPalette lut. * @param {number} c The channel index * @param {number} alpha The alpha value as a number from 0 to 1 */ setColorPaletteAlpha(c: number, alpha: number): void; /** * Return the intrinsic rotation associated with this volume (radians) * @return {Array.} the xyz Euler angles (radians) */ getRotation(): [number, number, number]; /** * Return the intrinsic translation (pivot center delta) associated with this volume, in normalized volume units * @return {Array.} the xyz translation in normalized volume units */ getTranslation(): [number, number, number]; /** * Return a translation in normalized volume units, given a translation in image voxels * @return {Array.} the xyz translation in normalized volume units */ voxelsToWorldSpace(xyz: [number, number, number]): [number, number, number]; addVolumeDataObserver(o: VolumeDataObserver): void; removeVolumeDataObserver(o: VolumeDataObserver): void; removeAllVolumeDataObservers(): void; } export {};