VTK_POLYHEDRON difficulties

I am generating VTK_POLYHEDRON items programmatically and they do not show. If I save them to a vtu file, reload directly that file - and still do not see the polyhedra!

Reading docs and studying the vtu file I see that the “faces” and the “faceoffsets” arrays are not there. And if I go and add them manually with a text editor, I can load the vtu file and everything is fine!

In the program, the cells are generated with calls like this:

vtkIdType cellId = Grid->InsertNextCell(VTK_POLYHEDRON, numPoints, ptIndex, numFaces, facePtIds);

and the data that I added manually in the two arrays are exactly the same which I am adding also with the above call! (Actually I wrote some “logging” code that wrote the numbers for me.)

So the question is: How can I properly get VTK_POLYHEDRON items programmatically, not only by adding the correct code to the vtu file manually?

I must say that at some time in the past it has even worked for me “somehow”, but I do not have the EXACT same code any more - but I believe that I cannot be really far away…

Some more details: I do the entire thing inside Paraview, and the 10 polyhedron cells are still indicated in the “Information” panel as existing. Also I can see in a “spreadsheet view” that the 10 cells are of type “POLYHEDRON”. And in 3d I can see the correct corner points if I am using the “Points Gaussian” representation. So again: much cannot be missing…

Maybe it helps if I can post more detail what the software is actually doing and what is the result.

So this is a very much stripped down version of source code that is supposed to generate a hexahedron as a VTK_POLYHEDRON:

vtkSmartPointer<vtkAtgTableToSamplings> generateSampling =
        vtkSmartPointer<vtkAtgTableToSamplings>::New();
generateSampling->SetInputData(inTable);
generateSampling->Update();
vtkPolyData* dataItems = generateSampling->GetOutput();

// get and prepare the output grid
vtkUnstructuredGrid* outputItemsUGrid =
        vtkUnstructuredGrid::GetData(outputVector->GetInformationObject(0));
outputItemsUGrid->Allocate();
vtkSmartPointer<vtkPoints> outPoints = vtkSmartPointer<vtkPoints>::New();
outputItemsUGrid->SetPoints(outPoints);

vtkIdType pointIds[8] = {0, 1, 2, 3, 4, 5, 6, 7};

outPoints->InsertNextPoint(-1.0,-1.0,-1.0);
outPoints->InsertNextPoint( 1.0,-1.0,-1.0);
outPoints->InsertNextPoint( 1.0, 1.0,-1.0);
outPoints->InsertNextPoint(-1.0, 1.0,-1.0);
outPoints->InsertNextPoint(-1.0,-1.0, 1.0);
outPoints->InsertNextPoint( 1.0,-1.0, 1.0);
outPoints->InsertNextPoint( 1.0, 1.0, 1.0);
outPoints->InsertNextPoint(-1.0, 1.0, 1.0);

vtkIdType faces[] =
{
    4, 0, 3, 2, 1,
    4, 0, 4, 7, 3,
    4, 4, 5, 6, 7,
    4, 5, 1, 2, 6,
    4, 0, 1, 5, 4,
    4, 2, 3, 7, 6
};

outputItemsUGrid->InsertNextCell(VTK_POLYHEDRON, 8, pointIds, 6, faces);

The output 3D view (in ParaView) shows just NOTHING.

The “Information” panel tells me that I am having an “unstructured grid” with 1 cell and 8 points.

A “spreadsheet view” shows in “point data” the 8 point coordinates, and in “cell data” one cell of type POLYHEDRON.

Writing this “unstructured grid” of one cell to a vtu file generates the following output:

<VTKFile type="UnstructuredGrid" version="1.0" byte_order="LittleEndian" header_type="UInt64">
  <UnstructuredGrid>
    <Piece NumberOfPoints="8" NumberOfCells="1">
      <PointData>
      </PointData>
      <CellData>
      </CellData>
      <Points>
        <DataArray type="Float64" Name="Points" NumberOfComponents="3" format="ascii" RangeMin="1.7320508075688772" RangeMax="1.7320508075688772">
          -1 -1 -1 1 -1 -1
          1 1 -1 -1 1 -1
          -1 -1 1 1 -1 1
          1 1 1 -1 1 1
          <InformationKey name="L2_NORM_FINITE_RANGE" location="vtkDataArray" length="2">
            <Value index="0">
              1.7320508076
            </Value>
            <Value index="1">
              1.7320508076
            </Value>
          </InformationKey>
          <InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
            <Value index="0">
              1.7320508076
            </Value>
            <Value index="1">
              1.7320508076
            </Value>
          </InformationKey>
        </DataArray>
      </Points>
      <Cells>
        <DataArray type="Int64" Name="connectivity" format="ascii" RangeMin="0" RangeMax="7">
          0 1 2 3 4 5
          6 7
        </DataArray>
        <DataArray type="Int64" Name="offsets" format="ascii" RangeMin="8" RangeMax="8">
          8
        </DataArray>
        <DataArray type="UInt8" Name="types" format="ascii" RangeMin="42" RangeMax="42">
          42
        </DataArray>
      </Cells>
    </Piece>
  </UnstructuredGrid>
</VTKFile>

Reading this same file back in results in NOTHING again.

Manually inserting the following after the last seems to fix the vtu file:

    <DataArray type="Int64" Name="faces" format="ascii" RangeMin="0" RangeMax="7">
      6
      4 0 3 2 1
      4 0 4 7 3
      4 4 5 6 7
      4 5 1 2 6
      4 0 1 5 4
      4 2 3 7 6
    </DataArray>
    <DataArray type="Int64" Name="faceoffsets" format="ascii" RangeMin="31" RangeMax="31">
      31
    </DataArray>

Note that this is exactly the same thing that I had already also written in the source code above!

Finally inserted the following data dump code after the InsertNextCell above:

vtkIdTypeArray* farr = outputItemsUGrid->GetFaces();
if(nullptr == farr)
    std::cout << "- NO faces array" << std::endl;
else
{
    std::cout << "- faces array";
    for(vtkIdType i = 0; i < farr->GetNumberOfValues(); ++i)
        std::cout << " " << farr->GetValue(i);
    std::cout << std::endl;
}
vtkIdTypeArray* flarr = outputItemsUGrid->GetFaceLocations();
if(nullptr == flarr)
    std::cout << "- NO faces location array" << std::endl;
else
{
    std::cout << "- faces location array";
    for(vtkIdType i = 0; i < flarr->GetNumberOfValues(); ++i)
        std::cout << " " << flarr->GetValue(i);
    std::cout << std::endl;
}

generating the following output:

- faces array 6 4 0 3 2 1 4 0 4 7 3 4 4 5 6 7 4 5 1 2 6 4 0 1 5 4 4 2 3 7 6
- faces location array 0

So it looks like “faces” and “faces location” data are also generated correctly during the InsertNextCell call!

(It looks like the “faces location array” is not exactly the same as what is expected in the “faceoffsets” - which makes even sense for me if I think about how the code should handle this kind of “streaming data”)

Now I start running out of options what else I could check…

More findings:

First: Replacing the above code that generates a cube as a polyhedron by this code which simply reads the file that I fixed manually and which was correctly displayed if I just “open” it with ParaView:

auto usrdr = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New();
usrdr->SetFileName("/home/......./mini.vtu");
usrdr->Update();
outputItemsUGrid->DeepCopy(usrdr->GetOutput());

Result: NOTHING is shown, and the “Information” panel tells the same story as before: “1 cell with 8 points”

Second: The points in the above code are arranged in such a way that they are ready for procuding a cube much more easily by simply replacing the VTK_POLYHEDRON with a VTK_HEXAHEDRON.

Result: Now the cube is visible!

Things are not getting more understandable, only more and more possible problems are excluded…

Trying to debug the process of writing that non-showing unstructured grid to a file because also there the problem seems to show up (and I felt like I might be quicker to get through the complexities of writing into a file than the even more complex ways from an unstructured grid data object to showing it on the screen): the resulting vtu file will NOT have the “faces” and “faceoffsets” sections.

Finding: the input data object at vtkXMLUnstructuredGridWriter.cxx(109) [referring to the “official release” version of PV 5.8] does not have either Faces or FaceLocations data attached, while at the end of my own code the final unstructured grid has both. This is the line of code that I am referring:

if (vtkUnstructuredGrid* grid = vtkUnstructuredGrid::SafeDownCast(input))

So at some point from my own filter that generates the unstructured grid to the input of the vtkXMLUnstructuredGridWriter both the “Faces” and the “FaceLocations” data are getting lost!

So far I am not able to further detangle the logic of that pipeline code because in most places inside that pipeline the data is in the form of a generic pointer that my debugger cannot easily interpret any further.

Only thing I see is that while the vtkUnstructuredGrid class has these two data objects, the vtkUnstructuredGridBase class has not, so my guess is currently that at some point in the pipeline logic the unstructured grid is “copied as vtkUnstructuredGridBase”, thus losing all the additional data.

Solution found!

Looks like I found a possible bug in the vtkUnstructuredGrid class - but may be it’s also just a “tricky feature”!??

Actually my simplified code above includes one more step - which I did not consider really relevant, but it included the point where the Faces and FaceLocations actually got lost.

My filter that generated an unstructured grid internally called another filter which only included the above test code. The output of the “inner filter” was then simply copied to the output of the “outer filter” (calling filter) like this:

outputSampling->DeepCopy(tabToItemLab->GetOutput());

And this was the trap!

Sometimes I am a bit lazy: instead of thinking whether it is safe to go with a ShallowCopy() - always a bit afraid of pointers that may get invalid “somehow somewhere”, I am using DeepCopy() instead if I expect that the entire thing is always very small, so “deep copying” does not cost a lot. Like it is the case here.

(Actually I learned in the meantime that the VTK object system is pretty safe in this respect normally.)

But in this specific case I realized that vtkUnstructuredGrid is a bit more complicated in this respect! To make a long exploration story short, this is what I found out:

  • Either I go with ShallowCopy() and everything is nice and simple and expectable
  • Or I go with DeepCopy(), but in this case I need two additional calls before I do the actual copy:

.

outputSampling->Allocate();
outputSampling->InitializeFacesRepresentation(tabToItemLab->GetOutput()->GetNumberOfCells());
outputSampling->DeepCopy(tabToItemLab->GetOutput());

The point is that the DeepCopy() only copies faces if the target unstructured grid has already the arrays prepared: this is why the InitializeFacesRepresentation() call is required. But this call will crash if not also Allocate() was called before - in order to prepare the Types array internally!

Whether this is a bug or a feature - no idea! Maybe there is some reasoning behind. But in any case I realized that it is pretty much confusing - and really hard to find out!

In my very little experience with polyhedral elements, that sounds like a bug to me.

Ok, that’s a word - and to me it makes sense because it would not be very consistent otherwise.

Added an issue to VTK: Gitlab