# \`vtkDataSetTriangleFilter\` changes connectivity ordering

**URL:** https://discourse.vtk.org/t/vtkdatasettrianglefilter-changes-connectivity-ordering/15928
**Category:** Support
**Tags:** python
**Created:** [August 6, 2025, 8:49pm UTC](https://discourse.vtk.org/t/vtkdatasettrianglefilter-changes-connectivity-ordering/15928 "2025-08-06T20:49:18Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![citronella3alain](https://discourse.vtk.org/user_avatar/discourse.vtk.org/citronella3alain/32/10080_2.png) [@citronella3alain](https://discourse.vtk.org/u/citronella3alain)
#### Post date: [August 6, 2025, 8:49pm UTC](https://discourse.vtk.org/t/vtkdatasettrianglefilter-changes-connectivity-ordering/15928/1 "2025-08-06T20:49:18Z")

</div>

tl;dr: `vtkDataSetTriangleFilter` causes cell connectivity ordering to change for pure vtk unstructured grid but not in a pyvista uns grid. Why? Does it matter? What am I missing to replicate the latter effect given that pyvista wraps vtk?

I have a pyvista fn that creates a tetrahedron unstructured grid and I translated it to pure vtk as such:

```python
from vtkmodules.vtkCommonDataModel import (
    VTK_HEXAHEDRON,
    VTK_TETRA,
    VTK_TRIANGLE,
    vtkDataSet,
    vtkPolyData,
    vtkUnstructuredGrid,
)
from vtkmodules.util import numpy_support
import numpy as np
import pyvista as pv
from vtkmodules.vtkCommonCore import vtkIdList, vtkPoints, vtkStringArray
from vtkmodules.vtkFiltersGeneral import vtkDataSetTriangleFilter

# pyvista:
def get_tetra(cell_num: int = 2):
    points_per_cell = 4
    points = np.empty((points_per_cell * cell_num, 3), dtype=np.float32)
    for i in range(cell_num):
        points[i*points_per_cell : (i+1)*points_per_cell] = \
            [[i, 0, 0],[i+0.5, 0, 0],[i+0.5, 0.5, 0.5],[i, 0, 0.5]] # fmt: skip
    cells = np.arange(len(points)).reshape([cell_num, points_per_cell])
    grid = pv.UnstructuredGrid({VTK_TETRA: cells}, points)
    return grid
pv_tetra = get_tetra()

# pure vtk:
def get_unstructured_grid(cell_num: int = 2):
    grid = vtkUnstructuredGrid()
    points = vtkPoints()
    point_idx = 0

    def insert_cell(cell_type_id, point_ids):
        id_list = vtkIdList()
        for pid in point_ids:
            id_list.InsertNextId(pid)
        grid.InsertNextCell(cell_type_id, id_list)

    for i in range(cell_num):
        cell_points = np.array(
            [
                [i, 0, 0],
                [i + 0.5, 0, 0],
                [i + 0.5, 0.5, 0.5],
                [i, 0, 0.5],
            ],
            dtype=np.float32,
        )
        ids = []
        for pt in cell_points:
            points.InsertNextPoint(pt)
            ids.append(point_idx)
            point_idx += 1

        id_list = vtkIdList()
        for pid in ids:
            id_list.InsertNextId(pid)
        grid.InsertNextCell(VTK_TETRA, id_list)

    grid.SetPoints(points)
    return grid
vtk_ugrid = get_unstructured_grid()

```

These two seem identical:

 ![image](https://discourse.vtk.org/uploads/default/original/2X/2/2db1d78edec9aadb460c5d9f936c185e67fb1dbd.png)

However, using the `vtkDataSetTriangleFilter` on them yields different results in connectivity ordering:

```python
print(numpy_support.vtk_to_numpy(pv_tetra.GetCells().GetData()))
print(numpy_support.vtk_to_numpy(vtk_ugrid.GetCells().GetData()))

trifilter = vtkDataSetTriangleFilter(input_data=pv_tetra)
trifilter.Update()
new_pv_tetra = trifilter.GetOutput()

trifilter1 = vtkDataSetTriangleFilter(input_data=vtk_ugrid)
trifilter1.Update()
new_vtk_ugrid = trifilter1.GetOutput()

print(numpy_support.vtk_to_numpy(new_pv_tetra.GetCells().GetData()))
print(numpy_support.vtk_to_numpy(new_vtk_ugrid.GetCells().GetData()))

```

yields

```auto
[4 0 1 2 3 4 4 5 6 7]
[4 0 1 2 3 4 4 5 6 7]
[4 0 1 2 3 4 4 5 6 7]
[4 1 2 0 3 4 5 6 4 7]

```

Why does the connectivity ordering change in the pure vtk implementation but not the pyvista implementation? What can I do to replicate the latter? What are the implications of the connectivity ordering changing?

Thanks!

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [August 11, 2025, 3:24pm UTC](https://discourse.vtk.org/t/vtkdatasettrianglefilter-changes-connectivity-ordering/15928/2 "2025-08-11T15:24:13Z")

</div>

I don’t have the answers to your questions about vtkDataSetTriangleFilter, but a comprehensive comparison of `pv_tetra` vs. `vtk_ugrid` can be done by saving both to ASCII files and then doing a diff,

```python
writer = vtkUnstructuredGridWriter()
writer.SetFileTypeToASCII()

```

---

<div class="post-metadata">

### Author: ![citronella3alain](https://discourse.vtk.org/user_avatar/discourse.vtk.org/citronella3alain/32/10080_2.png) [@citronella3alain](https://discourse.vtk.org/u/citronella3alain)
#### Post date: [August 11, 2025, 11:42pm UTC](https://discourse.vtk.org/t/vtkdatasettrianglefilter-changes-connectivity-ordering/15928/3 "2025-08-11T23:42:03Z")

</div>

Thanks for the suggestion @dgobbi  
It seems like that their ASCII representations are identical; the `diff` yields nothing.  
Just including the code as sanity check:

```python
import numpy as np
from vtkmodules.vtkCommonCore import vtkIdList, vtkPoints, vtkStringArray
from vtkmodules.vtkCommonDataModel import (
    VTK_HEXAHEDRON,
    VTK_TETRA,
    VTK_TRIANGLE,
    vtkDataSet,
    vtkPolyData,
    vtkUnstructuredGrid,
)
from vtkmodules.vtkFiltersCore import vtkCleanPolyData
from vtkmodules.vtkFiltersSources import vtkCubeSource
from vtkmodules.vtkIOLegacy import vtkUnstructuredGridWriter

grid = vtkUnstructuredGrid()
points = vtkPoints()
point_idx = 0

def insert_cell(cell_type_id, point_ids):
    id_list = vtkIdList()
    for pid in point_ids:
        id_list.InsertNextId(pid)
    grid.InsertNextCell(cell_type_id, id_list)
    
for i in range(2):
    cell_points = np.array(
        [
            [i, 0, 0],
            [i + 0.5, 0, 0],
            [i + 0.5, 0.5, 0.5],
            [i, 0, 0.5],
        ],
        dtype=np.float32,
    )
    ids = []
    for pt in cell_points:
        points.InsertNextPoint(pt)
        ids.append(point_idx)
        point_idx += 1
    insert_cell(VTK_TETRA, ids)

grid.SetPoints(points)
vtk_writer = vtkUnstructuredGridWriter(file_name="vtk_tetra.vtk", input_data=grid)
vtk_writer.SetFileTypeToASCII()
vtk_writer.Update()
vtk_writer.Write()

import pyvista as pv
points_per_cell = 4
cell_num = 2
pv_points = np.empty((points_per_cell * cell_num, 3), dtype=np.float32)
for i in range(cell_num):
    pv_points[i*points_per_cell : (i+1)*points_per_cell] = \
        [[i, 0, 0],[i+0.5, 0, 0],[i+0.5, 0.5, 0.5],[i, 0, 0.5]] # fmt: skip
cells = np.arange(len(pv_points)).reshape([cell_num, points_per_cell])
pv_grid = pv.UnstructuredGrid({VTK_TETRA: cells}, pv_points)
vtk_writer = vtkUnstructuredGridWriter(file_name="pv_tetra.vtk", input_data=pv_grid)
vtk_writer.SetFileTypeToASCII()
vtk_writer.Update()
vtk_writer.Write()

```

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [August 12, 2025, 12:03am UTC](https://discourse.vtk.org/t/vtkdatasettrianglefilter-changes-connectivity-ordering/15928/4 "2025-08-12T00:03:52Z")

</div>

I took a closer look and found a bug in vtkDataSetTriangleFilter, there is a place where it is looping over the reserved size of an array when it is supposed to be looping over the number of values actually stored in the array. That must be where `pv_tetra` and `vtk_ugrid` differ: pyvista probably pre-allocates the grid before storing data in it, whereas `vtk_ugrid` grows the arrays as needed, ending up with a reserved size that is larger than the number of values.

Here is a work-around until I fix the bug:

```python
    grid = vtkUnstructuredGrid()
    grid.AllocateExact(cell_num, 4*cell_num)

```

That’s it. Just pre-allocate the grid to exactly the size it will need once it is built. Then the bug in vtkDataSetTriangleFilter won’t be triggerred.
