In vtk.js because we mostly focus on Rendering we only have 2 types of data structures. We have a vtkPolyData
that can be used for geometry rendering and a vtkImageData
that can be used for volume rendering. In proper VTK, we have more types of DataSets and we have several filters that help you convert from one type to another.
Here we explain some of the foundation of those data structures so you could create them by hand if you wanted to.
An ImageData is an implicit grid that is axis aligned as shown in the picture below.
The set of properties that can be given to vtk_imagedata
are as follow:
- origin: location of the bottom left corner of the grid in the 3D world
- dimensions: how many points we have along each axis
- spacing: what is the uniform spacing along each axis between the points
A concrete example would be a grid of 5 points or 4 cells along each axis which will go from [-2, 2]
along each axis.
vtk_imagedata(
dimension=[5,5,5],
origin=[-2,-2,-2],
spacing=[1,1,1],
)
View full code
using DashHtmlComponents, DashVtk
html_div([vtk_view([
vtk_volumerepresentation([
# GUI to control Volume Rendering
# + Setup good default at startup
vtk_volumecontroller(),
# Actual Imagedata
vtk_imagedata(
dimensions=[5, 5, 5],
origin=[-2, -2, -2],
spacing=[1, 1, 1],
children=[
vtk_pointdata([
vtk_dataarray(
registration="setScalars",
values=collect(0:1:124),
)
])
],
),
]),
])], style=Dict("width" => "100%", "height" => "400px"))
A vtk_polydata is a surface mesh composed of points
and cells
. The cells can be:
- verts: Vertex or point to show as a tiny square on the screen
- lines: Lines that connect points into a one segment or multi segment line
- polys: Polygons which are convex surfaces such as triangles, rectangles, circles…
- strips: Triangle strips efficiently combine triangles together with no repeated points just for connectivity
The way cells are defined is via an index-based array that maps to a given point index. For example let’s pretend you want to create a line with 2 segments, you will need at least 3 points defined in the points
array. If those points are defined first in your points
array, then the lines
array should be filled as follows:
nb_points = 3
lines = [nb_points, 0, 1, 2]
To create 2 lines independent of each other, you can do it as follows:
lines = [
3, 0, 1, 2, # First line of 2 segments / 3 points
2, 3, 4, # Second line of 1 segment / 2 points
4, 10, 11, 12, 14 # Third line of 3 segments / 4 points
]
You can see a concrete example in the image below.
View full code
using DashHtmlComponents, DashVtk
html_div([vtk_view([
vtk_geometryrepresentation(
children=[
vtk_polydata(
points=[
0,0,0,
1,0,0,
0,1,0,
1,1,0,
],
lines=[3, 1, 3, 2],
polys=[3, 0, 1, 2],
children=[
vtk_pointdata([
vtk_dataarray(
#registration="setScalars", # To activate field
name="onPoints",
values=[0, 0.33, 0.66, 1],
)
]),
vtk_celldata([
vtk_dataarray(
# registration="setScalars", # To activate field
name="onCells",
values=[0, 1],
)
])
],
),
],
),
])], style=Dict("width" => "100%", "height" => "400px"))
The vtk_polydata
element has an additional property to automatically generate cells based on some assumption of the order of the points defined in the points
array. That property is named connectivity and defaults to manual
, meaning no automatic action is taken. But that property can be set to points
to automatically set the vertex to actually see the points provided or triangles
which uses each set of 3 consecutive points to create a triangle and finally strips
which consumes all the points in a single strip of triangles.
Having a grid is a good start, but most likely you would want to attach a field to a given mesh so you can start looking at it in a 3D context.
Fields are arrays that map to either Points or Cells. They could be scalars or vectors of different size.
The diagram below tries to explain the difference between fields located on points vs cells in term of rendering, but it also truly has a different meaning based on the type of data that you have.
Caution: By convention, we always attach data to points in an vtk_imagedata for doing VolumeRendering and the array must be registered as scalars.