vtkExtractUnstructuredGrid does not return any points on Windows

The vtkExtractUnstructuredGrid class is awesome on Linux, where it successfully merges points for unstructured grids. However, on Windows, it returns 0 points with merging on. I have explicitly turned off all clipping so it should not be doing anything other than merging exactly coincident points (since I’m using the default point locator for this class). My code looks like the following:

  auto merge_filter = vtkSmartPointer<vtkExtractUnstructuredGrid>::New();
  merge_filter->MergingOn();
  merge_filter->PointClippingOff();
  merge_filter->CellClippingOff();
  merge_filter->ExtentClippingOff();
  merge_filter->SetInputData(ugrid);
  merge_filter->Update();
  return merge_filter->GetOutput();

Is this expected behavior? Thank you!

If your function returns a raw pointer to the vtkUnstructuredGrid, it will no longer valid when you access it.

In your function you create a vtkSmartPointer to your algorithm. The output vtkUnstructuredGrid is owned by the algorithm (or its executive), but this all is destroyed while exiting the function, and so is your output, assuming you return a raw pointer to it. You probably just got ‘lucky’ that on Linux you’re still able to access it.

If you return it as a vtkSmartPointer<vtkUnstructuredGrid> I expect your code will work properly.

Thanks Andreas.

So just to be clear you are suggesting that I should change the above code to be something like the following:

  merge_filter->Update();
  auto ptr = vtkSmartPointer<vtkUnstructuredGrid>::New(); 
  ptr->DeepCopy(merge_filter->GetOutput());
  return ptr;

?

I did just try this code sample above, but it unfortunately has the same behavior.

If you return it as a vtkSmartPointer<vtkUnstructuredGrid> I expect your code will work properly.

This refers to the function signature (which you didn’t specify).

What it boils down to is that you should make sure the reference counting of the object that you return from the function does not go to zero while returning. Assuming your function returns a raw pointer both the first and the second snippet will destroy your result.

  1. In the first snippet the filter holds the single reference to the output object. Because the filter gets destroyed on exit, the reference to the output will be decremented to zero, and the output object will be destroyed too before the caller can get hold of it.
  2. In the second snippet you create a smart pointer which holds the single reference to an unstructured grid. After deep-copying (note that ShallowCopy would be prefereable), on returning from the function ptr goes out of scope, decrements the refcount to zero and causes the pointed-to unstructured grid to be destroyed before you can get hold of it as a caller.

So you need to take care that the reference count does not go to zero when exiting which can be done with raw pointers or smart pointers.

With raw pointers (note that your caller is then responsible for destroying the returned object):

vtkUnstructuredGrid* foo() {
     auto merge_filter = vtkSmartPointer<vtkExtractUnstructuredGrid>::New();
      // ...
     auto result = vtkUnstructuredGrid::New();
     result->ShallowCopy( merge_filter->GetOutput() );
     return result;
}

or

vtkUnstructuredGrid* foo() {
     auto merge_filter = vtkSmartPointer<vtkExtractUnstructuredGrid>::New();
      // ...
     auto result = merge_filter->GetOutput();
     result->Register(nullptr); // increment the refcount
     return result;
}

alternative returning a smart pointer:

vtkSmartPointer<vtkUnstructuredGrid> foo() {
  auto merge_filter = vtkSmartPointer<vtkExtractUnstructuredGrid>::New();
  // ...
  auto result = vtkSmartPointer<vtkUnstructuredGrid>::New();
  result->ShallowCopy( merge_filter->GetOutput() );
  return result;
}

or:

vtkSmartPointer<vtkUnstructuredGrid> foo() {
  auto merge_filter = vtkSmartPointer<vtkExtractUnstructuredGrid>::New();
  // ...
  return merge_filter->GetOutput(); // constructs a smart pointer and increases the reference count to the filter output before exiting.
}

I see. The return type of the problematic function is vtkSmartPointer<vtkUnstructuredGrid>. Is there another possible explanation for why there’s a difference in behavior between Linux and Windows?

I don’t know. I’m not familiar with the algorithm itself, but glancing over the code I don’s see why that should behave differently.

Have you tried printing out the output object of the algorithm, the object’s pointer and its contents (using Print) just before you return from the function and the object just after you return?

The result of the above code on windows (after adding merge_filter->DebugOn(); and merge_filter->Print(std::cout); is:

         vtkExtractUnstructuredGrid (00000137704C59A0)
           Debug: On
           Modified Time: 617321
           Reference Count: 2
           Registered Events: (none)
           Executive: 00000137704C5A90
           ErrorCode: No error
           Information: 00000137701F2CB0
           AbortExecute: Off
           Progress: 1
           Progress Text: (None)
           Point Minimum : 0
           Point Maximum : 9223372036854775807
           Cell Minimum : 0
           Cell Maximum : 9223372036854775807
           Extent: 
             Xmin,Xmax: (-1e+299, 1e+299)
             Ymin,Ymax: (-1e+299, 1e+299)
             Zmin,Zmax: (-1e+299, 1e+299)
           PointClipping: Off
           CellClipping: Off
           ExtentClipping: Off
           Merging: On
           Locator: (none)

Then, the unstructured grid (before function return, even) prints:
    vtkUnstructuredGrid (0000023C0BAA5080)
       Debug: Off
       Modified Time: 2701
       Reference Count: 1
       Registered Events: (none)
       Information: 0000023C0BFB4470
       Data Released: False
       Global Release Data: Off
       UpdateTime: 2707
       Field Data:
         Debug: Off
         Modified Time: 2691
         Reference Count: 1
         Registered Events: (none)
         Number Of Arrays: 0
         Number Of Components: 0
         Number Of Tuples: 0
       Number Of Points: 0
       Number Of Cells: 0
       Cell Data:
         Debug: Off
         Modified Time: 2699
         Reference Count: 1
         Registered Events: 
           Registered Observers:
             vtkObserver (0000023C08774960)
               Event: 33
               EventName: ModifiedEvent
               Command: 0000023C0BFB46F0
               Priority: 0
               Tag: 1
         Number Of Arrays: 0
         Number Of Components: 0
         Number Of Tuples: 0
         Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 )
         Interpolate Flags: ( 1 1 1 1 1 0 0 1 )
         Pass Through Flags: ( 1 1 1 1 1 1 1 1 )
         Scalars: (none)
         Vectors: (none)
         Normals: (none)
         TCoords: (none)
         Tensors: (none)
         GlobalIds: (none)
         PedigreeIds: (none)
         EdgeFlag: (none)
       Point Data:
         Debug: Off
         Modified Time: 2701
         Reference Count: 1
         Registered Events: 
           Registered Observers:
             vtkObserver (0000023C08774AB0)
               Event: 33
               EventName: ModifiedEvent
               Command: 0000023C0BFB46F0
               Priority: 0
               Tag: 1
         Number Of Arrays: 0
         Number Of Components: 0
         Number Of Tuples: 0
         Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 )
         Interpolate Flags: ( 1 1 1 1 1 0 0 1 )
         Pass Through Flags: ( 1 1 1 1 1 1 1 1 )
         Scalars: (none)
         Vectors: (none)
         Normals: (none)
         TCoords: (none)
         Tensors: (none)
         GlobalIds: (none)
         PedigreeIds: (none)
         EdgeFlag: (none)
       Bounds: 
         Xmin,Xmax: (1, -1)
         Ymin,Ymax: (1, -1)
         Zmin,Zmax: (1, -1)
       Compute Time: 0
       Number Of Points: 0
       Point Coordinates: 0000000000000000
       Locator: 0000000000000000
       Number Of Pieces: 1
       Piece: 0
       Ghost Level: 0

Is it an issue that the vtkExtractUnstructuredGrid prints out that it has no locator?

Is it an issue that the vtkExtractUnstructuredGrid prints out that it has no locator?

Looking at the implementation (https://github.com/Kitware/VTK/blob/nightly-master/Filters/Extraction/vtkExtractUnstructuredGrid.cxx), a locator is created during execution when none is supplied. Does the debug output on Linux show that a locator has been created?

Did you print the debug output after the Update()?

And did you see the debug output vtkDebugMacro(<<"Executing extraction filter");
and
vtkDebugMacro(<<"Extracted " << output->GetNumberOfPoints() << " points," << output->GetNumberOfCells() << " cells.");
being printed?

You could also have a look at your input ugrid, print out its contents right before execution of the filter.

Hi Andreas,

Thanks for your support, by the way, I really appreciate it!

Here’s the grid before it goes into the ExtractUnstructuredGrid:

     vtkUnstructuredGrid (00000186E23E67F0)
       Debug: Off
       Modified Time: 2507
       Reference Count: 1
       Registered Events: (none)
       Information: 00000186E24D6510
       Data Released: False
       Global Release Data: Off
       UpdateTime: 0
       Field Data:
         Debug: Off
         Modified Time: 2462
         Reference Count: 1
         Registered Events: (none)
         Number Of Arrays: 0
         Number Of Components: 0
         Number Of Tuples: 0
       Number Of Points: 7551512
       Number Of Cells: 0
       Cell Data:
         Debug: Off
         Modified Time: 2506
         Reference Count: 1
         Registered Events: 
           Registered Observers:
             vtkObserver (00000186EECD8B90)
               Event: 33
               EventName: ModifiedEvent
               Command: 00000186E24D61A0
               Priority: 0
               Tag: 1
         Number Of Arrays: 1
         Array 0 name = density
         Number Of Components: 1
         Number Of Tuples: 943939
         Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 )
         Interpolate Flags: ( 1 1 1 1 1 0 0 1 )
         Pass Through Flags: ( 1 1 1 1 1 1 1 1 )
         Scalars: (none)
         Vectors: (none)
         Normals: (none)
         TCoords: (none)
         Tensors: (none)
         GlobalIds: (none)
         PedigreeIds: (none)
         EdgeFlag: (none)
       Point Data:
         Debug: Off
         Modified Time: 2464
         Reference Count: 1
         Registered Events: 
           Registered Observers:
             vtkObserver (00000186EECD8B30)
               Event: 33
               EventName: ModifiedEvent
               Command: 00000186E24D61A0
               Priority: 0
               Tag: 1
         Number Of Arrays: 0
         Number Of Components: 0
         Number Of Tuples: 0
         Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 )
         Interpolate Flags: ( 1 1 1 1 1 0 0 1 )
         Pass Through Flags: ( 1 1 1 1 1 1 1 1 )
         Scalars: (none)
         Vectors: (none)
         Normals: (none)
         TCoords: (none)
         Tensors: (none)
         GlobalIds: (none)
         PedigreeIds: (none)
         EdgeFlag: (none)
       Bounds: 
         Xmin,Xmax: (-0.02698, 85.028)
         Ymin,Ymax: (-0.073318, 24.311)
         Zmin,Zmax: (-0.061071, 80.059)
       Compute Time: 2509
       Number Of Points: 7551512
       Point Coordinates: 00000186E07370B0
       Locator: 0000000000000000
       Number Of Pieces: 1
       Piece: -1
       Ghost Level: 0

So there are points but no cells.

Here’s how I constructed the grid to begin with:

  auto ugrid = gridPointer::New();
  auto points = vtkSmartPointer<vtkPoints>::New();
  points->Allocate(voxels.size() * 8);
  ugrid->Allocate(voxels.size());
  int curr_id = 0;
  auto vtk_voxel = vtkSmartPointer<vtkVoxel>::New();
  for (auto const& voxel : voxels) {
    auto min_corner = voxel.min_corner;
    auto max_corner = voxel.max_corner;
    points->InsertNextPoint(min_corner[0], min_corner[1], min_corner[2]);
    points->InsertNextPoint(max_corner[0], min_corner[1], min_corner[2]);
    points->InsertNextPoint(min_corner[0], max_corner[1], min_corner[2]);
    points->InsertNextPoint(max_corner[0], max_corner[1], min_corner[2]);
    points->InsertNextPoint(min_corner[0], min_corner[1], max_corner[2]);
    points->InsertNextPoint(max_corner[0], min_corner[1], max_corner[2]);
    points->InsertNextPoint(min_corner[0], max_corner[1], max_corner[2]);
    points->InsertNextPoint(max_corner[0], max_corner[1], max_corner[2]);
    vtk_voxel->GetPointIds()->SetId(0, curr_id * 8 + 0);
    vtk_voxel->GetPointIds()->SetId(1, curr_id * 8 + 1);
    vtk_voxel->GetPointIds()->SetId(2, curr_id * 8 + 2);
    vtk_voxel->GetPointIds()->SetId(3, curr_id * 8 + 3);
    vtk_voxel->GetPointIds()->SetId(4, curr_id * 8 + 4);
    vtk_voxel->GetPointIds()->SetId(5, curr_id * 8 + 5);
    vtk_voxel->GetPointIds()->SetId(6, curr_id * 8 + 6);
    vtk_voxel->GetPointIds()->SetId(7, curr_id * 8 + 7);
    ugrid->InsertNextCell(VTK_VOXEL, vtk_voxel->GetPointIds());
    curr_id++;
  }
  ugrid->SetPoints(points);

So it appears there is some difference in behavior between Windows and Linux regarding the loop above where I fill out the voxel cell array.

I do not see output about “extract X number of cells/points”.

As you already noted yourself, there are no cells, so that is the reason the algorithm will return without extracting anything. With debugging turned on you should see a message No data to extract!.

From this snippet I don’t see why your ugrid should have no cells (I don’t know what gridPointer::New() does, it suggests that it returns a raw pointer. Is that passed properly to the merge_filter?). Did you check with debug output that the ugrid that goes into the merge filter is the same as the ugrid that is produced by this snippet?

Note that you don’t really use the vtkVoxel, only its point ids array. You could also create a vtkIdList and populate that with the point ids. Another suggestion is that the InsertNextPoint method returns the id of the inserted point so you could use its return value to populate the vtkIdList instead of calculating the ids.

Weirdly I do not see any debug output, on either Linux or Windows, even when I set merge_filter->DebugOn();.

gridPointer is just my typename alias for vtkSmartPointer<vtkUnstructuredGrid>.

I changed the code as you recommend (using vtkIdList directly), with no difference in behavior. Indeed, the ugrid that goes into the merge filter is this same ugrid that gets filled out.

However, when I change the code to be use a different version of InsertNextCell it does fix the issue!

Here is the working snippet:

  std::vector<vtkIdType> id_list(8);
  for (auto const& voxel : voxels) {
    vec3 const min = voxel.getMin(), max = voxel.getMax();

    // insert 8 points for each voxel
    points->InsertNextPoint(min[0], min[1], min[2]);
    points->InsertNextPoint(max[0], min[1], min[2]);
    points->InsertNextPoint(min[0], max[1], min[2]);
    points->InsertNextPoint(max[0], max[1], min[2]);
    points->InsertNextPoint(min[0], min[1], max[2]);
    points->InsertNextPoint(max[0], min[1], max[2]);
    points->InsertNextPoint(min[0], max[1], max[2]);
    points->InsertNextPoint(max[0], max[1], max[2]);
    id_list[0] = curr_id * 8 + 0;
    id_list[1] = curr_id * 8 + 1;
    id_list[2] = curr_id * 8 + 2;
    id_list[3] = curr_id * 8 + 3;
    id_list[4] = curr_id * 8 + 4;
    id_list[5] = curr_id * 8 + 5;
    id_list[6] = curr_id * 8 + 6;
    id_list[7] = curr_id * 8 + 7;
    ugrid->InsertNextCell(VTK_VOXEL, 8, id_list.data());
}

So while this solves my immediate problem, I’m a little confused as to why I needed to use this method versus the other one.

Well congratulations, you solved your issue by yourself. I like your solution with the std::vector even better, and like you I’m puzzled too by how the cell insertion could fail. You could try and make sure the idlist that you write into has 8 positions, as vtkIdList::SetId assumes that you’ve allocated enough memory to write into.

The reason you don’t see debug output could be that you’re running a release build? I think debug output is printed only when running a debug build.

Debug output is only available if you build vtk with a build type Debug.