From 5a3c2898d520c7a1ab53b4e51e42f8af9490ed6c Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Mon, 2 Dec 2024 16:16:56 -0800 Subject: [PATCH 1/3] actually remove the volume --- src/View3d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/View3d.ts b/src/View3d.ts index 5ea76089..91b96cda 100644 --- a/src/View3d.ts +++ b/src/View3d.ts @@ -226,6 +226,7 @@ export class View3d { if (this.image) { this.removeVolume(this.image.volume); } + this.image = undefined; } /** From 2f97c8701ba15ea0b66b9d5fc8a2a18538d0ba3b Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Tue, 3 Dec 2024 13:51:30 -0800 Subject: [PATCH 2/3] fix channel bug in jsonimageinfoloader --- src/Atlas2DSlice.ts | 1 - src/VolumeDrawable.ts | 7 ++++--- src/loaders/JsonImageInfoLoader.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Atlas2DSlice.ts b/src/Atlas2DSlice.ts index 18ce9208..ae03a739 100644 --- a/src/Atlas2DSlice.ts +++ b/src/Atlas2DSlice.ts @@ -96,7 +96,6 @@ export default class Atlas2DSlice implements VolumeRenderImpl { public updateVolumeDimensions(): void { const volumeScale = this.volume.normPhysicalSize.clone().multiply(this.settings.scale); const regionScale = volumeScale.clone().multiply(this.volume.normRegionSize); - console.log(regionScale); const volumeOffset = this.volume.getContentCenter().clone().multiply(this.settings.scale); this.geometryMesh.position.copy(volumeOffset); // set scale diff --git a/src/VolumeDrawable.ts b/src/VolumeDrawable.ts index 2a74e983..39713fe3 100644 --- a/src/VolumeDrawable.ts +++ b/src/VolumeDrawable.ts @@ -118,7 +118,8 @@ export default class VolumeDrawable { } /** - * Updates whether a channel's data must be loaded for rendering, based on if its volume or isosurface is enabled. + * Updates whether a channel's data must be loaded for rendering, + * based on if its volume or isosurface is enabled, or whether it is needed for masking. * Calls `Volume.updateRequiredData` to update the list of required channels if necessary. */ private updateChannelDataRequired(channelIndex: number): void { @@ -128,12 +129,12 @@ export default class VolumeDrawable { if (requiredChannels.includes(channelIndex)) { if (!channelIsRequired) { - // This channel is currently marked required, but both its volume and isosurface are off. Remove it! + // This channel is currently marked required, but both its volume and isosurface are off, and it's not a mask. Remove it! this.volume.updateRequiredData({ channels: requiredChannels.filter((i) => i !== channelIndex) }); } } else { if (channelIsRequired) { - // This channel is not marked required, but either its volume or isosurface is on. Add it! + // This channel is not marked required, but either its volume or isosurface is on, or it is a mask. Add it! this.volume.updateRequiredData({ channels: [...requiredChannels, channelIndex] }); } } diff --git a/src/loaders/JsonImageInfoLoader.ts b/src/loaders/JsonImageInfoLoader.ts index 76359c0e..cdd59ed4 100644 --- a/src/loaders/JsonImageInfoLoader.ts +++ b/src/loaders/JsonImageInfoLoader.ts @@ -192,7 +192,7 @@ class JsonImageInfoLoader extends ThreadableVolumeLoader { const requestedChannels = loadSpec.channels; if (requestedChannels) { // If only some channels are requested, load only images which contain at least one requested channel - images = images.filter(({ channels }) => channels.some((ch) => ch in requestedChannels)); + images = images.filter(({ channels }) => channels.some((ch) => requestedChannels.includes(ch))); } // This regex removes everything after the last slash, so the url had better be simple. From 225e8e2ea82327a4c9114c50d9880a28d90b0f2d Mon Sep 17 00:00:00 2001 From: toloudis Date: Tue, 3 Dec 2024 15:48:21 -0800 Subject: [PATCH 3/3] fix json time series playback by respecting syncChannels --- src/loaders/JsonImageInfoLoader.ts | 37 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/loaders/JsonImageInfoLoader.ts b/src/loaders/JsonImageInfoLoader.ts index cdd59ed4..2fde3051 100644 --- a/src/loaders/JsonImageInfoLoader.ts +++ b/src/loaders/JsonImageInfoLoader.ts @@ -121,6 +121,7 @@ const convertImageInfo = (json: JsonImageInfo): ImageInfo => { class JsonImageInfoLoader extends ThreadableVolumeLoader { urls: string[]; jsonInfo: (JsonImageInfo | undefined)[]; + syncChannels = false; cache?: VolumeCache; @@ -152,6 +153,10 @@ class JsonImageInfoLoader extends ThreadableVolumeLoader { return imageInfo; } + syncMultichannelLoading(sync: boolean): void { + this.syncChannels = sync; + } + async loadDims(loadSpec: LoadSpec): Promise { const jsonInfo = await this.getJsonImageInfo(loadSpec.time); @@ -217,7 +222,7 @@ class JsonImageInfoLoader extends ThreadableVolumeLoader { data: TypedArray[], ranges: [number, number][] ) => onData(ch, dtype, data, ranges, [w, h]); - await JsonImageInfoLoader.loadVolumeAtlasData(images, wrappedOnData, this.cache); + await JsonImageInfoLoader.loadVolumeAtlasData(images, wrappedOnData, this.cache, this.syncChannels); } /** @@ -239,8 +244,14 @@ class JsonImageInfoLoader extends ThreadableVolumeLoader { static async loadVolumeAtlasData( imageArray: PackedChannelsImage[], onData: RawChannelDataCallback, - cache?: VolumeCache + cache?: VolumeCache, + syncChannels = false ): Promise { + const resultChannelIndices: number[] = []; + const resultChannelDtype: NumberType[] = []; + const resultChannelData: TypedArray[] = []; + const resultChannelRanges: [number, number][] = []; + const imagePromises = imageArray.map(async (image) => { // Because the data is fetched such that one fetch returns a whole batch, // if any in batch is cached then they all should be. So if any in batch is NOT cached, @@ -251,7 +262,15 @@ class JsonImageInfoLoader extends ThreadableVolumeLoader { const cacheResult = cache?.get(`${image.name}/${chindex}`); if (cacheResult) { // all data coming from this loader is natively 8-bit - onData([chindex], ["uint8"], [new Uint8Array(cacheResult)], [DATARANGE_UINT8]); + if (syncChannels) { + // if we are synchronizing channels, we need to keep track of the data + resultChannelIndices.push(chindex); + resultChannelDtype.push("uint8"); + resultChannelData.push(new Uint8Array(cacheResult)); + resultChannelRanges.push(DATARANGE_UINT8); + } else { + onData([chindex], ["uint8"], [new Uint8Array(cacheResult)], [DATARANGE_UINT8]); + } } else { cacheHit = false; // we can stop checking because we know we are going to have to fetch the whole batch @@ -302,11 +321,21 @@ class JsonImageInfoLoader extends ThreadableVolumeLoader { cache?.insert(`${image.name}/${chindex}`, channelsBits[ch]); // NOTE: the atlas dimensions passed in here are currently unused by `JSONImageInfoLoader` // all data coming from this loader is natively 8-bit - onData([chindex], ["uint8"], [channelsBits[ch]], [DATARANGE_UINT8], [bitmap.width, bitmap.height]); + if (syncChannels) { + resultChannelIndices.push(chindex); + resultChannelDtype.push("uint8"); + resultChannelData.push(channelsBits[ch]); + resultChannelRanges.push(DATARANGE_UINT8); + } else { + onData([chindex], ["uint8"], [channelsBits[ch]], [DATARANGE_UINT8], [bitmap.width, bitmap.height]); + } } }); await Promise.all(imagePromises); + if (syncChannels) { + onData(resultChannelIndices, resultChannelDtype, resultChannelData, resultChannelRanges); + } } }