Skip to content

Commit edc49ec

Browse files
committed
feat(ImageDataOutlineFilter): generate oriented outline for vtkImageData
1 parent 3b74187 commit edc49ec

File tree

6 files changed

+427
-51
lines changed

6 files changed

+427
-51
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { vtkAlgorithm, vtkObject } from "../../../interfaces";
2+
import vtkImageData from "../../../Common/DataModel/ImageData";
3+
import vtkPolyData from "../../../Common/DataModel/PolyData";
4+
5+
export const LINE_ARRAY: number[];
6+
7+
export interface IImageDataOutlineFilterInitialValues {
8+
}
9+
10+
type vtkImageDataOutlineFilterBase = vtkObject & vtkAlgorithm;
11+
12+
export interface vtkImageDataOutlineFilter extends vtkImageDataOutlineFilterBase {
13+
/**
14+
*
15+
* @param inData
16+
* @param outData
17+
*/
18+
requestData(inData: vtkImageData, outData: vtkPolyData): void;
19+
20+
/**
21+
* Flag to indicate that the output should generate triangulated faces of the outline.
22+
* @param {boolean} generateFaces
23+
*/
24+
setGenerateFaces(generateFaces: boolean): boolean;
25+
26+
/**
27+
* Flag that indicates whether the output will generate triangulated faces of the outline.
28+
* @returns {boolean}
29+
*/
30+
getGenerateFaces(): boolean;
31+
32+
/**
33+
* Flag to indicate that the output should generate wireframe of the outline.
34+
* @param {boolean} generateLines
35+
*/
36+
setGenerateLines(generateLines: boolean): boolean;
37+
38+
/**
39+
* Flag that indicates whether the output will generate wireframe lines of the outline.
40+
* @returns {boolean}
41+
*/
42+
getGenerateLines(): boolean;
43+
}
44+
45+
/**
46+
* Method used to decorate a given object (publicAPI+model) with
47+
* vtkImageDataOutlineFilter characteristics.
48+
*
49+
* @param publicAPI object on which methods will be bounds (public)
50+
* @param model object on which data structure will be bounds (protected)
51+
* @param {IImageDataOutlineFilterInitialValues} [initialValues] (default: {})
52+
*/
53+
export function extend(publicAPI: object, model: object, initialValues?: IImageDataOutlineFilterInitialValues): void;
54+
55+
/**
56+
* Method used to create a new instance of vtkImageDataOutlineFilter
57+
* @param {IImageDataOutlineFilterInitialValues} [initialValues] for pre-setting some of its content
58+
*/
59+
export function newInstance(initialValues?: IImageDataOutlineFilterInitialValues): vtkImageDataOutlineFilter;
60+
61+
62+
/**
63+
* vtkImageDataOutlineFilter - A filter that generates oriented outline for
64+
* vtkImageData.
65+
*
66+
* vtkImageDataOutlineFilter is a filter that generates a wireframe or
67+
* triangulated rectangular-cuboid as an outline of an input vtkImageData.
68+
* It takes into account the orientation / DirectionMatrix of the image, so the
69+
* output outline may not be axes aligned.
70+
*
71+
*/
72+
export declare const vtkImageDataOutlineFilter: {
73+
newInstance: typeof newInstance;
74+
extend: typeof extend;
75+
}
76+
export default vtkImageDataOutlineFilter;
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import macro from 'vtk.js/Sources/macros';
2+
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
3+
import vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray';
4+
import vtkCubeSource from 'vtk.js/Sources/Filters/Sources/CubeSource';
5+
import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData';
6+
import vtkTransform from 'vtk.js/Sources/Common/Transform/Transform';
7+
8+
const { vtkErrorMacro } = macro;
9+
10+
// prettier-ignore
11+
export const LINE_ARRAY = [
12+
2, 0, 1,
13+
2, 2, 3,
14+
2, 4, 5,
15+
2, 6, 7,
16+
2, 0, 2,
17+
2, 1, 3,
18+
2, 4, 6,
19+
2, 5, 7,
20+
2, 0, 4,
21+
2, 1, 5,
22+
2, 2, 6,
23+
2, 3, 7,
24+
];
25+
26+
// ----------------------------------------------------------------------------
27+
// vtkImageDataOutlineFilter methods
28+
// ----------------------------------------------------------------------------
29+
30+
function vtkImageDataOutlineFilter(publicAPI, model) {
31+
// Set our className
32+
model.classHierarchy.push('vtkImageDataOutlineFilter');
33+
34+
publicAPI.requestData = (inData, outData) => {
35+
// implement requestData
36+
const input = inData[0];
37+
38+
if (!input || !input.isA('vtkImageData')) {
39+
vtkErrorMacro('Invalid or missing input');
40+
return;
41+
}
42+
43+
if (!model._tmpOut) {
44+
// allocate output object if not done previously.
45+
model._tmpOut = vtkPolyData.newInstance();
46+
}
47+
48+
// First create a cube polydata in the index-space of the image.
49+
const spatialExt = input.getSpatialExtent();
50+
if (!spatialExt) {
51+
vtkErrorMacro('Unable to fetch spatial extents of input image.');
52+
return;
53+
}
54+
55+
model._boundingBox.setBounds(spatialExt);
56+
const lengths = model._boundingBox.getLengths();
57+
model._cubeSource.setXLength(lengths[0]);
58+
model._cubeSource.setYLength(lengths[1]);
59+
model._cubeSource.setZLength(lengths[2]);
60+
model._cubeSource.setCenter(model._boundingBox.getCenter());
61+
model._cubeSource.update();
62+
63+
const out = model._cubeSource.getOutputData();
64+
model._tmpOut.getPoints().deepCopy(out.getPoints());
65+
66+
// Now, transform the cube polydata points in-place
67+
// using the image's indexToWorld transformation.
68+
model._transform.setMatrix(input.getIndexToWorld());
69+
model._transform.transformPoints(
70+
model._tmpOut.getPoints().getData(),
71+
model._tmpOut.getPoints().getData()
72+
);
73+
74+
// Lastly, generate the necessary cell arrays.
75+
if (model.generateFaces) {
76+
model._tmpOut.getPolys().deepCopy(out.getPolys());
77+
} else {
78+
model._tmpOut.getPolys().initialize();
79+
}
80+
if (model.generateLines) {
81+
model._tmpOut.getLines().deepCopy(model._lineCells);
82+
} else {
83+
model._tmpOut.getLines().initialize();
84+
}
85+
86+
model._tmpOut.modified();
87+
outData[0] = model._tmpOut;
88+
};
89+
}
90+
91+
// ----------------------------------------------------------------------------
92+
// Object factory
93+
// ----------------------------------------------------------------------------
94+
95+
const DEFAULT_VALUES = {
96+
generateFaces: false,
97+
generateLines: true,
98+
};
99+
100+
// ----------------------------------------------------------------------------
101+
102+
export function extend(publicAPI, model, initialValues = {}) {
103+
Object.assign(model, DEFAULT_VALUES, initialValues);
104+
105+
// Make this a VTK object
106+
macro.obj(publicAPI, model);
107+
108+
macro.setGet(publicAPI, model, ['generateFaces', 'generateLines']);
109+
110+
// Also make it an algorithm with one input and one output
111+
macro.algo(publicAPI, model, 1, 1);
112+
113+
// Internal persistent objects
114+
model._boundingBox = vtkBoundingBox.newInstance();
115+
model._cubeSource = vtkCubeSource.newInstance();
116+
model._tmpOut = vtkPolyData.newInstance();
117+
model._lineCells = vtkCellArray.newInstance({
118+
values: Uint16Array.from(LINE_ARRAY),
119+
});
120+
model._transform = vtkTransform.newInstance();
121+
122+
macro.moveToProtected(publicAPI, model, [
123+
'boundingBox',
124+
'cubeSource',
125+
'tmpOut',
126+
'lineCells',
127+
'transform',
128+
]);
129+
130+
// Object specific methods
131+
vtkImageDataOutlineFilter(publicAPI, model);
132+
}
133+
134+
// ----------------------------------------------------------------------------
135+
136+
export const newInstance = macro.newInstance(
137+
extend,
138+
'vtkImageDataOutlineFilter'
139+
);
140+
141+
// ----------------------------------------------------------------------------
142+
143+
export default { newInstance, extend };

0 commit comments

Comments
 (0)