Skip to content

Commit

Permalink
feat(ObliqueView): add colored outlines to oblique planes
Browse files Browse the repository at this point in the history
  • Loading branch information
jadh4v committed Aug 3, 2023
1 parent 1a40a6f commit c669bda
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 4 deletions.
25 changes: 23 additions & 2 deletions src/components/VtkObliqueView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ import type { Vector3 } from '@kitware/vtk.js/types';
import vtkMatrixBuilder from '@kitware/vtk.js/Common/Core/MatrixBuilder';
import { useResizeToFit } from '@src/composables/useResizeToFit';
import vtkLPSView2DProxy from '@src/vtk/LPSView2DProxy';
import vtkResliceRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/ResliceRepresentationProxy';
import vtkObliqueRepresentationProxy from '@/src/vtk/ObliqueRepresentationProxy';
import { SlabTypes } from '@kitware/vtk.js/Rendering/Core/ImageResliceMapper/Constants';
import { ViewTypes } from '@kitware/vtk.js/Widgets/Core/WidgetManager/Constants';
import { ResliceCursorWidgetState } from '@kitware/vtk.js/Widgets/Widgets3D/ResliceCursorWidget';
Expand Down Expand Up @@ -316,11 +316,32 @@ export default defineComponent({
});
const { baseImageRep } = useSceneBuilder<
vtkResliceRepresentationProxy
vtkObliqueRepresentationProxy
>(viewID, {
baseImage: curImageID
});
const obliqueRep = baseImageRep?.value;
if (obliqueRep) {
switch(viewDirection.value) {
case 'Left':
case 'Right':
obliqueRep.setOutlineColor([1, 0, 0]);
break;
case 'Posterior':
case 'Anterior':
obliqueRep.setOutlineColor([0, 1, 0]);
break;
case 'Superior':
case 'Inferior':
obliqueRep.setOutlineColor([0, 0, 1]);
break;
default:
obliqueRep.setOutlineColor([0, 0, 0]);
break;
};
}
onBeforeMount(() => {
// do this before mount, as the ManipulatorTools run onMounted
// before this component does.
Expand Down
12 changes: 12 additions & 0 deletions src/vtk/ObliqueRepresentationProxy/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { vec3 } from 'gl-matrix';
import vtkResliceRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/ResliceRepresentationProxy';

export interface vtkObliqueRepresentationProxy
extends vtkResliceRepresentationProxy {
setOutlineColor(color: vec3): boolean;
getOutlineColor(): vec3;
setOutlineVisibility(visibility: boolean): boolean;
getOutlineVisibility(): boolean;
}

export default vtkObliqueRepresentationProxy;
121 changes: 121 additions & 0 deletions src/vtk/ObliqueRepresentationProxy/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { vec3 } from 'gl-matrix';

import macro from '@kitware/vtk.js/macro';
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkCubeSource from '@kitware/vtk.js/Filters/Sources/CubeSource';
import vtkCutter from '@kitware/vtk.js/Filters/Core/Cutter';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData';
import vtkResliceRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/ResliceRepresentationProxy';

function vtkObliqueRepresentationProxy(publicAPI, model) {
model.classHierarchy.push('vtkObliqueRepresentationProxy');

function transformPoints(points, transform) {
const tmp = [0, 0, 0];
for (let i = 0; i < points.length; i += 3) {
const p = points.subarray(i, i + 3);
if (transform.length === 9) {
vec3.transformMat3(tmp, p, transform);
} else {
vec3.transformMat4(tmp, p, transform);
}
[p[0], p[1], p[2]] = tmp;
}
};

function imageToCubePolyData(image, outPD) {
// First create a cube polydata in the index-space of the image.
const sext = image?.getSpatialExtent();

if (sext) {
model.cubeSource.setXLength(sext[1] - sext[0]);
model.cubeSource.setYLength(sext[3] - sext[2]);
model.cubeSource.setZLength(sext[5] - sext[4]);
} else {
model.cubeSource.setXLength(1);
model.cubeSource.setYLength(1);
model.cubeSource.setZLength(1);
}

model.cubeSource.setCenter(
model.cubeSource.getXLength() / 2.0,
model.cubeSource.getYLength() / 2.0,
model.cubeSource.getZLength() / 2.0
);

model.cubeSource.update();
const out = model.cubeSource.getOutputData();
outPD.getPoints().setData(Float32Array.from(out.getPoints().getData()), 3);
outPD.getPolys().setData(Uint32Array.from(out.getPolys().getData()), 1);

// Now, transform the cube polydata points in-place
// using the image's indexToWorld transformation.
const points = outPD.getPoints().getData();
transformPoints(points, image.getIndexToWorld());
};

model.cubeSource = vtkCubeSource.newInstance();
model.cubePolyData = vtkPolyData.newInstance();
model.cutter = vtkCutter.newInstance();
model.cutter.setCutFunction(model.slicePlane);

model.outline = {
mapper: vtkMapper.newInstance(),
actor: vtkActor.newInstance(),
// property: this.actor.getProperty(),
};
model.outline.property = model.outline.actor.getProperty();
model.outline.property.setLineWidth(5.0);

model.outline.mapper.setInputConnection(model.cutter.getOutputPort());
model.outline.actor.setMapper(model.outline.mapper);
model.actors.push(model.outline.actor);

function setInputData(inputDataset) {
const inputImage = inputDataset;
if (inputImage) {// && inputImage.getMTime() > publicAPI.getMTime()) {
imageToCubePolyData(inputImage, model.cubePolyData);
model.cutter.setInputData(model.cubePolyData);
}
}

// Keep things updated
model.sourceDependencies.push({ setInputData });
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);

// Object methods
vtkResliceRepresentationProxy.extend(publicAPI, model);

// Object specific methods
vtkObliqueRepresentationProxy(publicAPI, model);

// Proxyfy
model.outlineProperty = model.outline.property;
macro.proxyPropertyMapping(publicAPI, model, {
outlineVisibility: { modelKey: 'outlineProperty', property: 'visibility' },
outlineColor: { modelKey: 'outlineProperty', property: 'color' },
});
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(
extend,
'vtkObliqueRepresentationProxy'
);

// ----------------------------------------------------------------------------

export default { newInstance, extend };
4 changes: 2 additions & 2 deletions src/vtk/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import vtkSourceProxy from '@kitware/vtk.js/Proxy/Core/SourceProxy';

import vtkVolumeRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/VolumeRepresentationProxy';
import vtkGeometryRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/GeometryRepresentationProxy';
import vtkResliceRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/ResliceRepresentationProxy';

import vtkLPSView3DProxy from '@/src/vtk/LPSView3DProxy';
import vtkLPSView2DProxy from '@/src/vtk/LPSView2DProxy';
import vtkIJKSliceRepresentationProxy from '@/src/vtk/IJKSliceRepresentationProxy';
import vtkObliqueRepresentationProxy from '@/src/vtk/ObliqueRepresentationProxy';
import vtkLabelMapSliceRepProxy from '@/src/vtk/LabelMapSliceRepProxy';

function createProxyDefinition(
Expand Down Expand Up @@ -44,7 +44,7 @@ export default {
TrivialProducer: createProxyDefinition(vtkSourceProxy),
},
Representations: {
ImageReslice: createProxyDefinition(vtkResliceRepresentationProxy),
ImageReslice: createProxyDefinition(vtkObliqueRepresentationProxy),
ImageSlice: createProxyDefinition(vtkIJKSliceRepresentationProxy),
LabelMapSlice: createProxyDefinition(vtkLabelMapSliceRepProxy),
Volume: createProxyDefinition(vtkVolumeRepresentationProxy),
Expand Down

0 comments on commit c669bda

Please sign in to comment.