Multi geometry interaction

I have multiple geometries, each of which is stored in vtkunstructuredGrid/vtkPolyData. I hope that when the mouse clicks on a geometry during interaction, the geometry can be selected.
Of course, I also want to be able to select facets, points and so on in the geometry.
I used a vtkActor to display each geometry currently.
That is, there are as many vtkActors as there are geometry, so the mouse can select the actor.
But this operation is very inconvenient.
Is it possible to display only one vtkActor, but it is convenient to select geometry.

Hi Rockydut, what you’re trying sounds a bit like what I’m currently working on. For the selection part I had success with vtkMultiBlockDataSet and vtkCompositePolyDataMapper2. Then vtkHardwarePicker will return a blockId and a cellId which you can use to find out which geometry was selected and which cell of that geometry.

@tmnku could you please paste an example to me?
This problem has puzzled me for a long time.
Thanks a lot.

vtkNew<vtkMultiBlockDataSet> root;
root->SetNumberOfBlocks(2);
root->SetBlock(0, createPolyData());
root->SetBlock(1, createPolyData());

vtkNew<vtkCompositePolyDataMapper2> mapper;
mapper->SetInputDataObject(root);

vtkNew<vtkActor> actor;
actor->SetMapper(mapper);

createPolyData() is your custom function which returns the polydata you want to display. Then in the interactor use something like

void OnLeftButtonDown() {
    int* pos = this->GetInteractor()->GetEventPosition();
    vtkNew<vtkHardwarePicker> picker;
    int res = picker->Pick(pos[0], pos[1], 0, this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer());
    if (res == 1) {
      std::cout << "picked polydata " << picker->GetFlatBlockIndex() << ", cell " << picker->GetCellId() << std::endl;
    }
  }

Thank you very much. I’ll try it then give you a response.

I have a new problem.
How to set color for each geometry?

I actually had the same problem. SetBlockColor() of the mapper did not seem to have any effect neither did SetBlockVisibility(). I found an example in the unittests and it turns out that you have to set

vtkNew<vtkCompositeDataDisplayAttributes> cdsa;
mapper->SetCompositeDataDisplayAttributes(cdsa);

only then setting block attributes will work fine. When setting per block colors and visibility make sure to use its flat index which is not the same as the index when you use SetBlock(). In my case I had n polyDatas which I added to the root using SetBlock(0), SetBlock(1)... and then changed their color SetBlockColor(1), SetBlockColor(2),....

You can also set colors within each polyData object as an alternative.

  vtkNew<vtkUnsignedCharArray> colors;
  colors->SetNumberOfComponents(3);
  for (int i = 0; i < polyData->GetNumberOfCells(); ++i) {
    colors->InsertNextTuple3(255, 0, 0);
  }
  polyData->GetCellData()->SetScalars(colors);

I’m confuse for the color setting for each block.
The following code show the method for setting color of each block. However, the final color is not show as the setting.

vtkSmartPointer CreateSphereDataSet(const vtkVector3d& center,
double radius)
{
vtkNew leaf;
leaf->SetCenter(center.GetData());
leaf->SetRadius(radius);
leaf->Update();
return leaf->GetOutput();
}

int main(int, char*[])
{

vtkNew<vtkNamedColors> colors;
vtkNew<vtkMultiBlockDataSet> root;

root->SetBlock(0, CreateSphereDataSet({0, 0, 0}, 1.0));
root->SetBlock(1, CreateSphereDataSet({5, 0, 0}, 2));
root->SetBlock(3, CreateSphereDataSet({10, 0, 0.0}, 3));

vtkNew<vtkCompositePolyDataMapper2> mapper;
mapper->SetInputDataObject(root);
vtkNew<vtkCompositeDataDisplayAttributes> cdsa;
mapper->SetCompositeDataDisplayAttributes(cdsa);

double color[3];
color[0] = 1; color[1] = 0; color[2] = 0;
cdsa->SetBlockColor(root->GetBlock(0), color);
color[0] = 0; color[1] = 1; color[2] = 0;
cdsa->SetBlockColor(root->GetBlock(1), color);
color[0] = 0; color[1] = 0; color[2] = 1;
cdsa->SetBlockColor(root->GetBlock(2), color);

//Another method for color setting
// mapper->SetBlockColor(0, 1, 0, 0);
// mapper->SetBlockColor(1, 0, 1, 0);

// mapper->SetBlockColor(2, 0, 0, 1);

// display the data
vtkNew<vtkRenderer> aren;
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(aren);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);

vtkNew<vtkActor> actor;
actor->SetMapper(mapper);

aren->AddActor(actor);
aren->SetBackground(colors->GetColor3d("CornflowerBlue").GetData());

renWin->SetWindowName("MultiBLockDataSet");
renWin->Render();
iren->Start();
return 0;

}

P1
P2

The two method to color the ball is not same as that of the setting.

As I said before, you have to use the flat index in SetBlockColor() which starts at 1. Index 0 which you are using does not exist.

Do you test the vtkMultiBlockDataSet sorted the vtkUnstructuredGrid data and show it?
When I do it, the data can not display. I don’t know why.
When I transform ugrid to vtkPolyData, it can display correctly.
as the below showing an example.

#include <vtkActor.h>
#include <vtkCompositeDataGeometryFilter.h>
#include <vtkExtractEdges.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkVector.h>
#include <vtkCompositePolyDataMapper2.h>
#include <vtkSTLReader.h>
#include <vtkCompositeDataDisplayAttributes.h>
#include <vtkUnstructuredGrid.h>

vtkSmartPointer MakeHexahedron()
{
int numberOfVertices = 8;

// Create the points
vtkSmartPointer<vtkPoints> points =
        vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(0.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 1.0, 0.0);
points->InsertNextPoint(0.0, 1.0, 0.0);
points->InsertNextPoint(0.0, 0.0, 1.0);
points->InsertNextPoint(1.0, 0.0, 1.0);
points->InsertNextPoint(1.0, 1.0, 1.0);
points->InsertNextPoint(0.0, 1.0, 1.0);

// Create a hexahedron from the points
vtkSmartPointer<vtkHexahedron> hex =
        vtkSmartPointer<vtkHexahedron>::New();
for (int i = 0; i < numberOfVertices; ++i)
{
    hex->GetPointIds()->SetId(i, i);
}

// Add the points and hexahedron to an unstructured grid
vtkSmartPointer<vtkUnstructuredGrid> uGrid =
        vtkSmartPointer<vtkUnstructuredGrid>::New();
uGrid->SetPoints(points);
uGrid->InsertNextCell(hex->GetCellType(), hex->GetPointIds());

return uGrid;

}

int main(int, char*[])
{
vtkNew root;

vtkSmartPointer<vtkUnstructuredGrid> grid = MakeHexahedron();
vtkSmartPointer<vtkDataSetSurfaceFilter> surfaceFilter = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
surfaceFilter->SetInputData(grid);
surfaceFilter->Update();
vtkPolyData* poly = surfaceFilter->GetOutput();

//root->SetBlock(0, poly);
root->SetBlock(0, grid);

vtkNew<vtkCompositePolyDataMapper2> mapper;
mapper->SetInputDataObject(root);
vtkNew<vtkCompositeDataDisplayAttributes> cdsa;
mapper->SetCompositeDataDisplayAttributes(cdsa);

mapper->SetBlockColor(0, 1, 0, 0);

vtkNew<vtkRenderer> aren;
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(aren);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);

vtkNew<vtkActor> actor;
actor->SetMapper(mapper);

aren->AddActor(actor);
vtkNew<vtkNamedColors> colors;
aren->SetBackground(colors->GetColor3d("CornflowerBlue").GetData());

renWin->SetWindowName("MultiBLockDataSet");
renWin->Render();
iren->Start();
return 0;

}