Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* text=auto eol=lf
package-lock.json linguist-generated=true
patches/*.patch -whitespace
35 changes: 9 additions & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@itk-wasm/dicom": "^7.6.4",
"@itk-wasm/image-io": "1.6.1",
"@itk-wasm/morphological-contour-interpolation": "2.0.0",
"@kitware/vtk.js": "^36.2.0",
"@kitware/vtk.js": "^37.0.4",
"@netlify/edge-functions": "^3.0.2",
"@rollup/plugin-replace": "^6.0.3",
"@sentry/vite-plugin": "^4.6.1",
Expand Down
68 changes: 68 additions & 0 deletions patches/@kitware+vtk.js+37.0.4.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
diff --git a/node_modules/@kitware/vtk.js/Rendering/OpenGL/ImageMapper.js b/node_modules/@kitware/vtk.js/Rendering/OpenGL/ImageMapper.js
index 7defbee..70178df 100644
--- a/node_modules/@kitware/vtk.js/Rendering/OpenGL/ImageMapper.js
+++ b/node_modules/@kitware/vtk.js/Rendering/OpenGL/ImageMapper.js
@@ -32,11 +32,16 @@ function splitStringOnEnter(inputString) {
}
function vtkOpenGLImageMapper(publicAPI, model) {
model.classHierarchy.push("vtkOpenGLImageMapper");
+ function unregisterTextureResource(renderWindow, coreObject, texture) {
+ if (coreObject) renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI);
+ else texture?.releaseGraphicsResources(renderWindow);
+ }
function unregisterGraphicsResources(renderWindow) {
model.openGLTexture.releaseGraphicsResources(renderWindow);
+ model.tris.releaseGraphicsResources(renderWindow);
+ unregisterTextureResource(renderWindow, model._colorTransferFunc, model.colorTexture);
+ unregisterTextureResource(renderWindow, model._pwFunc, model.pwfTexture);
[
- model._colorTransferFunc,
- model._pwFunc,
model._labelOutlineThicknessArray,
model._labelOutlineOpacity
].forEach((coreObject) => renderWindow.unregisterGraphicsResourceUser(coreObject, publicAPI));
@@ -567,6 +572,11 @@ function vtkOpenGLImageMapper(publicAPI, model) {
const firstColorTransferFunc = actorProperty.getRGBTransferFunction();
const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
if (!cTex?.oglObject?.getHandle() || cTex?.hash !== cfunToString) {
+ if (!firstColorTransferFunc) {
+ if (model._colorTransferFunc) model._openGLRenderWindow.unregisterGraphicsResourceUser(model._colorTransferFunc, publicAPI);
+ else model.colorTexture?.releaseGraphicsResources(model._openGLRenderWindow);
+ model._colorTransferFunc = null;
+ }
model.colorTexture = Texture_default.newInstance({ resizable: true });
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
let cWidth = model.renderable.getColorTextureWidth();
@@ -629,6 +639,11 @@ function vtkOpenGLImageMapper(publicAPI, model) {
const firstPwFunc = actorProperty.getPiecewiseFunction();
const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
if (!pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== pwfunToString) {
+ if (!firstPwFunc) {
+ if (model._pwFunc) model._openGLRenderWindow.unregisterGraphicsResourceUser(model._pwFunc, publicAPI);
+ else model.pwfTexture?.releaseGraphicsResources(model._openGLRenderWindow);
+ model._pwFunc = null;
+ }
let pwfWidth = model.renderable.getOpacityTextureWidth();
if (pwfWidth <= 0) pwfWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
const pwfSize = pwfWidth * textureHeight;
diff --git a/node_modules/@kitware/vtk.js/Rendering/OpenGL/Texture.js b/node_modules/@kitware/vtk.js/Rendering/OpenGL/Texture.js
index 3563142..111214c 100644
--- a/node_modules/@kitware/vtk.js/Rendering/OpenGL/Texture.js
+++ b/node_modules/@kitware/vtk.js/Rendering/OpenGL/Texture.js
@@ -182,7 +182,7 @@ function vtkOpenGLTexture(publicAPI, model) {
publicAPI.deactivate = () => {
if (model._openGLRenderWindow) model._openGLRenderWindow.deactivateTexture(publicAPI);
};
- publicAPI.releaseGraphicsResources = (rwin) => {
+ publicAPI.releaseGraphicsResources = (rwin = model._openGLRenderWindow) => {
if (rwin && model.handle) {
rwin.activateTexture(publicAPI);
rwin.deactivateTexture(publicAPI);
@@ -863,6 +863,7 @@ function vtkOpenGLTexture(publicAPI, model) {
publicAPI.enableUseHalfFloat = (use) => {
model.enableUseHalfFloat = use;
};
+ publicAPI.delete = macros_exports.chain(() => publicAPI.releaseGraphicsResources(), publicAPI.delete);
}
var DEFAULT_VALUES = {
_openGLRenderWindow: null,
5 changes: 3 additions & 2 deletions src/components/RenderingModule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ export default defineComponent({
const activeView = viewStore.getView(viewStore.activeView);
if (
activeView?.type === '3D' &&
activeView.dataID === currentImageID.value
activeView.dataID === currentImageID.value &&
viewStore.visibleViews.includes(activeView)
) {
return activeView.id;
}

const any3DView = Object.values(viewStore.viewByID).find(
const any3DView = viewStore.visibleViews.find(
(v) => v.type === '3D' && v.dataID === currentImageID.value
);
return any3DView?.id;
Expand Down
12 changes: 2 additions & 10 deletions src/components/VolumeRendering.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
watchEffect,
} from 'vue';
import { onKeyDown, onKeyUp } from '@vueuse/core';
import { PresetNameList } from '@/src/vtk/ColorMaps';
import vtkPiecewiseWidget from '@/src/vtk/PiecewiseWidget';
import type { vtkSubscription } from '@kitware/vtk.js/interfaces';
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps';
Expand All @@ -25,11 +24,9 @@ import {
getColorFunctionRangeFromPreset,
getShiftedOpacityFromPreset,
} from '@/src/utils/vtk-helpers';
import { useVolumeThumbnailing } from '@/src/composables/useVolumeThumbnailing';

const WIDGET_WIDTH = 250;
const WIDGET_HEIGHT = 150;
const THUMBNAIL_SIZE = 80;

export default defineComponent({
name: 'VolumeRendering',
Expand Down Expand Up @@ -182,6 +179,8 @@ export default defineComponent({
onBeforeUnmount(() => {
pwfWidget.unbindMouseListeners();
pwfWidget.setContainer(null);
pwfWidget.delete();
colorTransferFunc.delete();
});

watch(
Expand Down Expand Up @@ -239,10 +238,6 @@ export default defineComponent({
{ immediate: true }
);

// -- thumbnailing -- //

const { currentThumbnails } = useVolumeThumbnailing(THUMBNAIL_SIZE);

// --- selection and updates --- //

const selectedPreset = computed(
Expand Down Expand Up @@ -335,7 +330,6 @@ export default defineComponent({
return {
editorContainerRef,
pwfEditorRef,
thumbnails: currentThumbnails,
hasCurrentImage,
preset: selectedPreset,
fullMappingRange,
Expand All @@ -348,8 +342,6 @@ export default defineComponent({
const step = Math.min(1, width / 256);
return step > 1 ? Math.round(step) : step;
}),
presetList: PresetNameList,
size: THUMBNAIL_SIZE,
rangeShiftMin: computed(() => -fullMappingRangeWidth.value / 2),
rangeShiftMax: computed(() => fullMappingRangeWidth.value / 2),
rangeShift,
Expand Down
3 changes: 2 additions & 1 deletion src/components/tools/ScalarProbe.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { inject, watch, computed, toRefs } from 'vue';
import { inject, watch, computed, toRefs, onScopeDispose } from 'vue';
import type { ReadonlyVec3 } from 'gl-matrix';
import { vec3 } from 'gl-matrix';
import { onVTKEvent } from '@/src/composables/onVTKEvent';
Expand Down Expand Up @@ -94,6 +94,7 @@ const sampleSet = computed(() => {

const pointPicker = vtkPointPicker.newInstance();
pointPicker.setPickFromList(true);
onScopeDispose(() => pointPicker.delete());

watch(
() => baseRep.value?.actor,
Expand Down
2 changes: 2 additions & 0 deletions src/components/tools/SelectTool.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ onVTKEvent(
// whatever its last tracked mouse move resolved, which can be a different
// position or, mid capture, nothing at all.
const selectedData = await view.widgetManager.getSelectedDataForXY(x, y);
// the pick spans a capture, which the view teardown can outrun
if (view.widgetManager.isDeleted()) return;
if ('widget' in selectedData) {
const widget =
selectedData.widget as Partial<vtkAnnotationToolWidget> | null;
Expand Down
1 change: 1 addition & 0 deletions src/components/tools/crop/Crop3D.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default defineComponent({

onBeforeUnmount(() => {
widgetManager.removeWidget(factory);
(factory as unknown as { delete(): void }).delete();
});

const { metadata: imageMetadata } = useImage(imageId);
Expand Down
1 change: 1 addition & 0 deletions src/components/tools/crosshairs/CrosshairsWidget2D.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export default defineComponent({

const manipulator = vtkPlaneManipulator.newInstance();
widget.setManipulator(manipulator);
onUnmounted(() => manipulator.delete());

const { metadata: imageMetadata } = useImage(imageId);
watchEffect(() => {
Expand Down
1 change: 1 addition & 0 deletions src/components/tools/paint/PaintWidget2D.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export default defineComponent({

const manipulator = vtkPlaneManipulator.newInstance();
widget.setManipulator(manipulator);
onUnmounted(() => manipulator.delete());

watchEffect(() => {
if (slice.value == null) return;
Expand Down
1 change: 1 addition & 0 deletions src/components/tools/polygon/PolygonWidget2D.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export default defineComponent({

const manipulator = vtkPlaneManipulator.newInstance();
widget.setManipulator(manipulator);
onUnmounted(() => manipulator.delete());

watchEffect(() => {
updatePlaneManipulatorFor2DView(
Expand Down
1 change: 1 addition & 0 deletions src/components/tools/rectangle/RectangleWidget2D.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export default defineComponent({

const manipulator = vtkPlaneManipulator.newInstance();
widget.setManipulator(manipulator);
onUnmounted(() => manipulator.delete());

watchEffect(() => {
updatePlaneManipulatorFor2DView(
Expand Down
1 change: 1 addition & 0 deletions src/components/tools/ruler/RulerWidget2D.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export default defineComponent({

const manipulator = vtkPlaneManipulator.newInstance();
widget.setManipulator(manipulator);
onUnmounted(() => manipulator.delete());

watchEffect(() => {
updatePlaneManipulatorFor2DView(
Expand Down
3 changes: 2 additions & 1 deletion src/components/vtk/VtkBaseObliqueSliceRepresentation.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { toRefs, watchEffect, inject } from 'vue';
import { toRefs, watchEffect, inject, onScopeDispose } from 'vue';
import { useImage } from '@/src/composables/useCurrentImage';
import { useResliceRepresentation } from '@/src/core/vtk/useResliceRepresentation';
import { useWindowingConfig } from '@/src/composables/useWindowingConfig';
Expand Down Expand Up @@ -42,6 +42,7 @@ sliceRep.mapper.setRelativeCoincidentTopologyPolygonOffsetParameters(1, 1);

// create slicing plane
const slicePlane = vtkPlane.newInstance();
onScopeDispose(() => slicePlane.delete());
sliceRep.mapper.setSlicePlane(slicePlane);

// initialize visual properties
Expand Down
5 changes: 5 additions & 0 deletions src/components/vtk/VtkBaseVolumeRepresentation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
watch,
shallowRef,
Ref,
onScopeDispose,
} from 'vue';
import { useImage } from '@/src/composables/useCurrentImage';
import { useVolumeRepresentation } from '@/src/core/vtk/useVolumeRepresentation';
Expand Down Expand Up @@ -67,6 +68,10 @@ const rep = useVolumeRepresentation(view, imageData);

const cfun = vtkColorTransferFunction.newInstance();
const ofun = vtkPiecewiseFunction.newInstance();
onScopeDispose(() => {
cfun.delete();
ofun.delete();
});
rep.property.setRGBTransferFunction(0, cfun);
rep.property.setScalarOpacity(0, ofun);
rep.property.setShade(true);
Expand Down
3 changes: 2 additions & 1 deletion src/components/vtk/VtkImageOutlineRepresentation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import type { Vector3 } from '@kitware/vtk.js/types';
import { syncRefs, watchImmediate } from '@vueuse/core';
import { inject, toRefs, watchEffect } from 'vue';
import { inject, onScopeDispose, toRefs, watchEffect } from 'vue';

interface Props {
viewId: string;
Expand All @@ -40,6 +40,7 @@ const outline = outlineFilter.getOutputData<vtkPolyData>(0);

// slicing plane
const slicePlane = vtkPlane.newInstance();
onScopeDispose(() => slicePlane.delete());
const cutterFilter = useVtkFilter(vtkCutter, outline);
(cutterFilter.filter as any).setCutFunction(slicePlane);

Expand Down
15 changes: 9 additions & 6 deletions src/components/vtk/VtkLayerSliceRepresentation.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { toRefs, watchEffect, inject, computed } from 'vue';
import { toRefs, watchEffect, inject, computed, onScopeDispose } from 'vue';
import { useImage } from '@/src/composables/useCurrentImage';
import { useSliceRepresentation } from '@/src/core/vtk/useSliceRepresentation';
import { LPSAxis } from '@/src/types/lps';
Expand Down Expand Up @@ -39,11 +39,14 @@ const imageData = computed(() =>
);
const sliceRep = useSliceRepresentation(view, imageData);

sliceRep.property.setRGBTransferFunction(
0,
vtkColorTransferFunction.newInstance()
);
sliceRep.property.setScalarOpacity(0, vtkPiecewiseFunction.newInstance());
const ownedColorTransferFunction = vtkColorTransferFunction.newInstance();
const ownedOpacityFunction = vtkPiecewiseFunction.newInstance();
sliceRep.property.setRGBTransferFunction(0, ownedColorTransferFunction);
sliceRep.property.setScalarOpacity(0, ownedOpacityFunction);
onScopeDispose(() => {
ownedColorTransferFunction.delete();
ownedOpacityFunction.delete();
});
sliceRep.property.setUseLookupTableScalarRange(false);

// set slice ordering to be in front of the segmentations
Expand Down
3 changes: 2 additions & 1 deletion src/components/vtk/VtkOrientationMarker.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { inject } from 'vue';
import { inject, onScopeDispose } from 'vue';
import { VtkViewContext } from '@/src/components/vtk/context';
import { useOrientationMarker } from '@/src/core/vtk/useOrientationMarker';
import vtkAnnotatedCubeActor from '@kitware/vtk.js/Rendering/Core/AnnotatedCubeActor';
Expand All @@ -13,6 +13,7 @@ AnnotatedCubePresets.applyPreset('default', actor); // applies color
AnnotatedCubePresets.applyPreset('lps', actor);

useOrientationMarker(actor, view.interactor);
onScopeDispose(() => actor.delete());
</script>

<template><slot></slot></template>
Loading
Loading