Can't display model from C++

Hi,

Here is my first attempt to add a model but I can’t display scalars on 3D view:

  vtkNew<vtkPoints> pts;
  vtkNew<vtkDoubleArray> derivs;
  ...
  vtkNew<vtkPolyData> polyData;
  polyData->SetPoints(pts);
  polyData->GetPointData()->SetScalars(derivs);

  vtkNew<vtkMRMLModelNode> modelNode;
  modelNode->SetAndObservePolyData(polyData);

  GetMRMLScene()->AddNode(modelNode.GetPointer());
  modelNode->CreateDefaultDisplayNodes();

I can see that the node is added to the scene and the scalars present but I can’t find a node on the view:

You can use the Models module logic’s convenience method for this:

1 Like

Thank you for the answer

I noticed that my data has nan values and thus the scalar range is useless. Did you have an experience of displaying models with nan?

It is practically impossible to prepare a software to properly deal with nan values everywhere. It would have enormous performance impact and would complicate algorithms and display pipelines at an unreasonable level. Also, meaning of “properly deal with nan” depends on the use case. Points/cells with nan values could be removed, skipped (interpolated using nearby valid values), displayed with a transparent value or special color, …?

I would recommend to get rid of the nan values as soon as you can (right after importing the mesh). For example by converting them to a value that makes sense for your application and maybe by applying further processing (e.g., remove regions with nan valued scalar by using threshold filter).

1 Like

I still can’t make scalar visualization work.

For example what is wrong with this pretty simple snippet of code:

// preparing rectangular grid
  ptrdiff_t nX = 10;
  ptrdiff_t nY = 10;

  vtkNew<vtkPoints> pts;
  pts->SetNumberOfPoints(nX*nY);

  vtkNew<vtkDoubleArray> scalars;
  scalars->SetName("my_scalars");
  scalars->SetNumberOfTuples(nX*nY);

  double vals[3];
  for (ptrdiff_t y = 0; y < nY; y++){
    for (ptrdiff_t x = 0; x < nX; x++){
      vals[0] = x;
      vals[1] = y;
      vals[2] = 0;
      pts->SetPoint(x + y*nX, vals);
      scalars->SetValue(x + y*nX, x+y);
    }
  }

// creating polydata and adding it to the scene
  vtkNew<vtkPolyData> polyData;
  polyData->SetPoints(pts);
  polyData->GetPointData()->SetScalars(scalars);

  qSlicerApplication* app = qSlicerApplication::application();
  vtkSlicerModelsLogic* modelsLogic =
    vtkSlicerModelsLogic::SafeDownCast(app->moduleLogic("Models"));
  vtkMRMLModelNode* modelNode =
    modelsLogic->AddModel(polyData);

I’m trying to represent rectangular grid and set scalars to points.
After running the app I can see that the model is added but no any coloring applied

Could you please share Python code that generates the mesh or upload the generated mesh somewhere and post the link here?

Here is the code I use to test it in python.
The mesh (mesh and points I guess share the same meaning) is named vpoints and varray is scalars (any random numbers):

# variable prefixed with `v` is treated as `vtk` object

import numpy as np

nx = 10
ny = 10

rng = np.random.default_rng(12345)
array = rng.random((nx*ny))

vpoints = vtk.vtkPoints()
vpoints.SetNumberOfPoints(nx*ny)

varray = vtk.vtkDoubleArray()
varray.SetNumberOfComponents(1)
varray.SetName("my_scalar")
varray.SetNumberOfTuples(nx*ny)

for y in range(0, ny):
    for x in range(0, nx):
        ind = x + y*nx
        vpoints.SetPoint(ind, [x,y,0])
        varray.SetValue(ind, array[ind])

vpoly = vtk.vtkPolyData()
vpoly.SetPoints(vpoints)
vpoly.GetPointData().SetScalars(varray) # this returns 0 - is it ok?

modelNode = slicer.modules.models.logic().AddModel(vpoly)

This code generates a pointset and puts it into a polydata object, but there is nothing displayable here (there are no cells, just points). If you want to display some shape at each point position then you can use vpoly as input to a vtkGlyph3D filter (along with some glyph source, source as a sphere source). The output of that filter will be displayable.

1 Like

Thank you very much!

Just in case here is the Exponential Cosine VTK example converted to Slicer API:

import math

plane = vtk.vtkPlaneSource()
plane.SetResolution(300, 300)

transform = vtk.vtkTransform()
transform.Scale(10.0, 10.0, 1.0)

transF = vtk.vtkTransformPolyDataFilter()
transF.SetInputConnection(plane.GetOutputPort())
transF.SetTransform(transform)
transF.Update()

input = transF.GetOutput()
numPts = input.GetNumberOfPoints()

newPts = vtk.vtkPoints()
newPts.SetNumberOfPoints(numPts)

derivs = vtk.vtkDoubleArray()
derivs.SetName("my_scalar")
derivs.SetNumberOfTuples(numPts)

bessel = vtk.vtkPolyData()
bessel.CopyStructure(input)
bessel.SetPoints(newPts)
bessel.GetPointData().SetScalars(derivs)

x = [0,0,0]

for i in range(0, numPts):
    input.GetPoint(i, x)
    r = math.sqrt(x[0] * x[0] + x[1] * x[1])
    x[2] = math.exp(-r) * math.cos(10.0 * r)
    newPts.SetPoint(i, x)
    deriv = -math.exp(-r) * (math.cos(10.0 * r) + 10.0 * math.sin(10.0 * r))
    derivs.SetValue(i, deriv)

warp = vtk.vtkWarpScalar()
warp.SetInputData(bessel)
warp.XYPlaneOn()
warp.SetScaleFactor(0.5)

modelNode = slicer.modules.models.logic().AddModel(warp.GetOutputPort())
1 Like

Thank you for the example, looks nice!

1 Like