Skip to content

Commit ceaff34

Browse files
authored
Merge pull request #48 from sankhesh/geometry2d
feat(Rendering): Introduce Geometry2DRepresentation
2 parents d8a4b02 + 87b5ad0 commit ceaff34

File tree

5 files changed

+304
-24
lines changed

5 files changed

+304
-24
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@
2727
"semantic-release": "semantic-release"
2828
},
2929
"peerDependencies": {
30-
"@kitware/vtk.js": "^20.1.3",
30+
"@kitware/vtk.js": "^21.3.0",
3131
"react": "^16.0.0"
3232
},
3333
"devDependencies": {
3434
"@babel/core": "^7.12.10",
3535
"@babel/plugin-transform-runtime": "^7.12.10",
3636
"@babel/preset-env": "^7.12.11",
3737
"@babel/preset-react": "^7.12.10",
38-
"@kitware/vtk.js": "^20.1.3",
38+
"@kitware/vtk.js": "^21.3.0",
3939
"@rollup/plugin-babel": "^5.2.2",
4040
"@rollup/plugin-commonjs": "17.0.0",
4141
"@rollup/plugin-eslint": "^8.0.1",
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
import { ViewContext, RepresentationContext, DownstreamContext } from './View';
5+
import { vec2Equals } from '../utils';
6+
7+
import vtkActor2D from '@kitware/vtk.js/Rendering/Core/Actor2D.js';
8+
import vtkMapper2D from '@kitware/vtk.js/Rendering/Core/Mapper2D.js';
9+
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps.js';
10+
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction.js';
11+
import vtkCoordinate from '@kitware/vtk.js/Rendering/Core/Coordinate.js';
12+
import { Coordinate } from '@kitware/vtk.js/Rendering/Core/Coordinate/Constants.js';
13+
14+
/**
15+
* Geometry2DRepresentation is useful for rendering polydata in 2D screen space.
16+
* It takes the following set of properties:
17+
* - representation: ['POINTS', 'WIREFRAME', 'SURFACE'],
18+
* - pointSize: 1,
19+
* - color: [1,1,1],
20+
* - opacity: 1,
21+
*/
22+
export default class Geometry2DRepresentation extends Component {
23+
constructor(props) {
24+
super(props);
25+
26+
// Guard to prevent rendering if no data
27+
this.validData = false;
28+
this.currentVisibility = true;
29+
30+
// Create vtk.js actor/mapper
31+
this.actor = vtkActor2D.newInstance({
32+
visibility: false,
33+
representationId: props.id,
34+
});
35+
this.lookupTable = vtkColorTransferFunction.newInstance();
36+
this.transformCoordinate = vtkCoordinate.newInstance({
37+
coordinateSystem: Coordinate.DISPLAY,
38+
});
39+
this.mapper = vtkMapper2D.newInstance({
40+
lookupTable: this.lookupTable,
41+
useLookupTableScalarRange: false,
42+
scalarVisibility: false,
43+
transformCoordinate: this.transformCoordinate,
44+
});
45+
this.actor.setMapper(this.mapper);
46+
47+
this.subscriptions = [];
48+
}
49+
50+
render() {
51+
return (
52+
<ViewContext.Consumer>
53+
{(view) => {
54+
if (!this.view) {
55+
view.renderer.addActor2D(this.actor);
56+
this.view = view;
57+
}
58+
return (
59+
<RepresentationContext.Provider value={this}>
60+
<DownstreamContext.Provider value={this.mapper}>
61+
<div key={this.props.id} id={this.props.id}>
62+
{this.props.children}
63+
</div>
64+
</DownstreamContext.Provider>
65+
</RepresentationContext.Provider>
66+
);
67+
}}
68+
</ViewContext.Consumer>
69+
);
70+
}
71+
72+
componentDidMount() {
73+
this.update(this.props);
74+
}
75+
76+
componentDidUpdate(prevProps, prevState, snapshot) {
77+
this.update(this.props, prevProps);
78+
}
79+
80+
componentWillUnmount() {
81+
while (this.subscriptions.length) {
82+
this.subscriptions.pop().unsubscribe();
83+
}
84+
85+
if (this.view && this.view.renderer) {
86+
this.view.renderer.removeActor(this.actor);
87+
}
88+
89+
this.actor.delete();
90+
this.actor = null;
91+
92+
this.mapper.delete();
93+
this.mapper = null;
94+
95+
this.lookupTable.delete();
96+
this.lookupTable = null;
97+
98+
this.transformCoordinate.delete();
99+
this.transformCoordinate = null;
100+
}
101+
102+
update(props, previous) {
103+
const {
104+
actor,
105+
mapper,
106+
property,
107+
colorMapPreset,
108+
colorDataRange,
109+
transformCoordinate,
110+
} = props;
111+
let changed = false;
112+
113+
if (actor && (!previous || actor !== previous.actor)) {
114+
changed = this.actor.set(actor) || changed;
115+
}
116+
if (mapper && (!previous || mapper !== previous.mapper)) {
117+
changed = this.mapper.set(mapper) || changed;
118+
}
119+
if (property && (!previous || property !== previous.property)) {
120+
changed = this.actor.getProperty().set(property) || changed;
121+
}
122+
123+
if (
124+
colorMapPreset &&
125+
this.lookupTable &&
126+
(!previous || colorMapPreset !== previous.colorMapPreset)
127+
) {
128+
changed = true;
129+
const preset = vtkColorMaps.getPresetByName(colorMapPreset);
130+
this.lookupTable.applyColorMap(preset);
131+
this.lookupTable.setMappingRange(...colorDataRange);
132+
this.lookupTable.updateRange();
133+
}
134+
135+
if (
136+
colorDataRange &&
137+
this.lookupTable &&
138+
(!previous || !vec2Equals(colorDataRange, previous.colorDataRange))
139+
) {
140+
changed = true;
141+
this.lookupTable.setMappingRange(...colorDataRange);
142+
this.lookupTable.updateRange();
143+
}
144+
145+
if (
146+
transformCoordinate &&
147+
this.transformCoordinate &&
148+
(!previous || transformCoordinate !== previous.transformCoordinate)
149+
) {
150+
changed = true;
151+
this.transformCoordinate.set(transformCoordinate);
152+
}
153+
154+
// actor visibility
155+
if (actor && actor.visibility !== undefined) {
156+
this.currentVisibility = actor.visibility;
157+
changed =
158+
this.actor.setVisibility(this.currentVisibility && this.validData) ||
159+
changed;
160+
}
161+
162+
if (changed) {
163+
// trigger render
164+
this.dataChanged();
165+
}
166+
}
167+
168+
dataAvailable() {
169+
if (!this.validData) {
170+
this.validData = true;
171+
this.actor.setVisibility(this.currentVisibility);
172+
173+
// trigger render
174+
this.dataChanged();
175+
}
176+
}
177+
178+
dataChanged() {
179+
if (this.view) {
180+
this.view.renderView();
181+
}
182+
}
183+
}
184+
185+
Geometry2DRepresentation.defaultProps = {
186+
colorMapPreset: 'erdc_rainbow_bright',
187+
colorDataRange: [0, 1],
188+
};
189+
190+
Geometry2DRepresentation.propTypes = {
191+
/**
192+
* The ID used to identify this component.
193+
*/
194+
id: PropTypes.string,
195+
196+
/**
197+
* Properties to set to the actor
198+
*/
199+
actor: PropTypes.object,
200+
201+
/**
202+
* Properties to set to the actor
203+
*/
204+
mapper: PropTypes.object,
205+
206+
/**
207+
* Properties to set to the actor.property
208+
*/
209+
property: PropTypes.object,
210+
211+
/**
212+
* Preset name for the lookup table color map
213+
*/
214+
colorMapPreset: PropTypes.string,
215+
216+
/**
217+
* Data range use for the colorMap
218+
*/
219+
colorDataRange: PropTypes.arrayOf(PropTypes.number),
220+
221+
/**
222+
* Coordinate system that the input dataset is in.
223+
*/
224+
transformCoordinate: PropTypes.object,
225+
226+
children: PropTypes.oneOfType([
227+
PropTypes.arrayOf(PropTypes.node),
228+
PropTypes.node,
229+
]),
230+
};

src/core/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import vtkReader from './Reader';
77
import vtkShareDataSet from './ShareDataSet';
88
import vtkView from './View';
99
import vtkGeometryRepresentation from './GeometryRepresentation';
10+
import vtkGeometry2DRepresentation from './Geometry2DRepresentation';
1011
import vtkGlyphRepresentation from './GlyphRepresentation';
1112
import vtkImageData from './ImageData';
1213
import vtkDataArray from './DataArray';
@@ -24,6 +25,7 @@ export const Reader = vtkReader;
2425
export const ShareDataSet = vtkShareDataSet;
2526
export const View = vtkView;
2627
export const GeometryRepresentation = vtkGeometryRepresentation;
28+
export const Geometry2DRepresentation = vtkGeometry2DRepresentation;
2729
export const GlyphRepresentation = vtkGlyphRepresentation;
2830
export const ImageData = vtkImageData;
2931
export const DataArray = vtkDataArray;
@@ -42,6 +44,7 @@ export default {
4244
ShareDataSet: vtkShareDataSet,
4345
View: vtkView,
4446
GeometryRepresentation: vtkGeometryRepresentation,
47+
Geometry2DRepresentation: vtkGeometry2DRepresentation,
4548
GlyphRepresentation: vtkGlyphRepresentation,
4649
ImageData: vtkImageData,
4750
DataArray: vtkDataArray,

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const Reader = Core.Reader;
2323
export const ShareDataSet = Core.ShareDataSet;
2424
export const View = Core.View;
2525
export const GeometryRepresentation = Core.GeometryRepresentation;
26+
export const Geometry2DRepresentation = Core.Geometry2DRepresentation;
2627
export const GlyphRepresentation = Core.GlyphRepresentation;
2728
export const ImageData = Core.ImageData;
2829
export const DataArray = Core.DataArray;

usage/Geometry/PolyDataViewer.js

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,92 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
33

4-
import { View, GeometryRepresentation, PolyData } from 'react-vtk-js';
4+
import {
5+
View,
6+
GeometryRepresentation,
7+
Geometry2DRepresentation,
8+
PolyData,
9+
} from 'react-vtk-js';
10+
11+
import { Representation } from '@kitware/vtk.js/Rendering/Core/Property/Constants';
12+
import { DisplayLocation } from '@kitware/vtk.js/Rendering/Core/Property2D/Constants';
13+
import { Coordinate } from '@kitware/vtk.js/Rendering/Core/Coordinate/Constants';
514

615
// React complains about unique key prop but I don't see why
716
function Example(props) {
817
return (
9-
<div style={{width: '100vw', height: '100vh'}}>
18+
<div style={{ width: '100vw', height: '100vh' }}>
1019
<View id="0" background={[0.1, 0.5, 0.9]}>
1120
<GeometryRepresentation
1221
id="1"
1322
property={{
14-
opacity: 0.5,
23+
opacity: 0.1,
1524
color: [0.7, 0, 0],
1625
}}
1726
>
1827
<PolyData
1928
id="2"
2029
points={[
21-
0, 0, 0,
22-
1, 0, 0,
23-
1, 1, 0,
24-
0, 1, 0,
25-
0, 0, 1,
26-
1, 0, 1,
27-
1, 1, 1,
28-
0, 1, 1,
30+
0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0,
31+
1, 1,
2932
]}
30-
lines={[
31-
2, 0, 6,
32-
2, 1, 7,
33-
2, 2, 4,
34-
2, 3, 5,
33+
lines={
34+
[
35+
// 2, 0, 6,
36+
// 2, 1, 7,
37+
// 2, 2, 4,
38+
// 2, 3, 5,
39+
]
40+
}
41+
polys={[4, 0, 3, 2, 1, 4, 4, 5, 6, 7, 4, 2, 3, 7, 6, 4, 0, 1, 5, 4]}
42+
/>
43+
</GeometryRepresentation>
44+
<Geometry2DRepresentation
45+
id="3"
46+
property={{
47+
opacity: 1.0,
48+
pointSize: 4.0,
49+
color: [0.7, 1, 0],
50+
representation: Representation.WIREFRAME,
51+
displayLocation: DisplayLocation.BACKGROUND,
52+
}}
53+
transformCoordinate={{
54+
coordinateSystem: Coordinate.WORLD,
55+
}}
56+
>
57+
<PolyData
58+
id="4"
59+
points={[
60+
0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0,
61+
1, 1,
3562
]}
36-
polys={[
37-
4, 0, 3, 2, 1,
38-
4, 4, 5, 6, 7,
39-
4, 2, 3, 7, 6,
40-
4, 0, 1, 5, 4,
63+
lines={[2, 0, 6, 2, 1, 7, 2, 2, 4, 2, 3, 5]}
64+
polys={[4, 0, 3, 2, 1, 4, 4, 5, 6, 7, 4, 2, 3, 7, 6, 4, 0, 1, 5, 4]}
65+
/>
66+
</Geometry2DRepresentation>
67+
<Geometry2DRepresentation
68+
id="5"
69+
property={{
70+
opacity: 0.8,
71+
pointSize: 15,
72+
color: [0.7, 0, 0],
73+
representation: Representation.POINTS,
74+
displayLocation: DisplayLocation.FOREGROUND,
75+
}}
76+
transformCoordinate={{
77+
coordinateSystem: Coordinate.WORLD,
78+
}}
79+
>
80+
<PolyData
81+
id="6"
82+
points={[
83+
0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0,
84+
1, 1,
4185
]}
86+
lines={[2, 0, 6, 2, 1, 7, 2, 2, 4, 2, 3, 5]}
87+
polys={[4, 0, 3, 2, 1, 4, 4, 5, 6, 7, 4, 2, 3, 7, 6, 4, 0, 1, 5, 4]}
4288
/>
43-
</GeometryRepresentation>
89+
</Geometry2DRepresentation>
4490
</View>
4591
</div>
4692
);

0 commit comments

Comments
 (0)