[vtk-developers] Active scalars and the behavior of vtkAppendFilter

Cory Quammen cory.quammen at kitware.com
Fri Apr 25 12:35:43 EDT 2014


Hi all,

There is some unexpected behavior (to me, anyway) in vtkAppendFilter.
Say I have two data sets D1 and D2, each of which has two
single-component scalar arrays named "A" and "B". Assume for
simplicity that each array has three elements as illustrated below:

D1:
"A" = [ 1, 1, 1 ]
"B" = [ 2, 2, 2 ]

D2:
"A" = [ 1, 1, 1 ]
"B" = [ 2, 2, 2 ]

I would expect that if I used vtkAppendFilter to merge these two
datasets that the values from the "A" arrays in each data set would be
merged into an "A" array in the result, with the same happening for
the "B" arrays. That is:

Appended result:
"A" = [ 1, 1, 1, 1, 1, 1 ]
"B" = [ 2, 2, 2, 2, 2, 2 ]

If no "active" scalars are set in the two data sets, then everything
works as I suspect.

"A" = [1, 1, 1, 1, 1, 1]
"B" = [2, 2, 2, 2, 2, 2]

However, if "A" is set as the active scalar in D1 and "B" is set as
the active scalar in D2, the result is that the merged array in the
result with the name "A" has the first half of its values from array
"A" in D1 and the second half of its values from array "B" in D2. The
"B" array in the output is all 2s as I would expect.

"A" = [ 1, 1, 1, 2, 2, 2 ]
"B" = [ 2, 2, 2, 2, 2, 2 ]

If you set "B" to be the active scalar in D1 and "A" as the active
scalar in D2, then the resulting merged array is named "B" and has
values from D1's "B" array followed by values from D2's "A" array. The
"A" array in the output is all 1s as I would expected.

"B" = [ 2, 2, 2, 1, 1, 1 ]
"A" = [ 1, 1, 1, 1, 1, 1 ]

If you set "A" to be the active scalars in both datasets, then "A" in
the output is all 1s and "B" is all 2s as I would expect.

"A" = [ 1, 1, 1, 1, 1, 1 ]
"B" = [ 2, 2, 2, 2, 2, 2 ]

What's happening is that the filter is merging the active scalars from
all the data sets into an array whose name comes from whichever
dataset happens to come first. Non-active arrays are merged by name.

Does this seem like sensible behavior? My guess is that most people
would expect arrays with the same name to be merged. The concern is
that some filter upstream may change which array is active, the user
has no idea that this has happened, and unexpected results occur.

Sure, you could get merging by name only by setting the active scalar
to the same array in each input data set for vtkAppendFilter prior to
updating it, but this is not at all obvious or well documented.

I've attached a self-contained code sample illustrating the problem.

Thanks for your thoughts,
Cory
-------------- next part --------------
cmake_minimum_required(VERSION 2.8)
project( AppendExample )

find_package( VTK )
include( ${VTK_USE_FILE} )

add_executable( AppendExample AppendExample.cxx )
target_link_libraries( AppendExample ${VTK_LIBRARIES} )
-------------- next part --------------
#include <iostream>

#include <vtkAppendFilter.h>
#include <vtkIntArray.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include <vtkUnstructuredGrid.h>

//////////////////////////////////////////////////////////////////////////////
void CreateDataset( vtkPolyData* dataset )
{
  vtkIntArray* a = vtkIntArray::New();
  a->SetName( "A" );
  a->SetNumberOfComponents( 1 );
  a->SetNumberOfTuples( 3 );
  a->FillComponent( 0, 1 );

  vtkIntArray* b = vtkIntArray::New();
  b->SetName( "B" );
  b->SetNumberOfComponents( 1 );
  b->SetNumberOfTuples( 3 );
  b->FillComponent( 0, 2 );

  vtkPoints* points = vtkPoints::New();
  for (int i = 0; i < 3; ++i)
    {
    points->InsertNextPoint( 0.0, 0.0, 0.0 );
    }
  dataset->SetPoints( points );
  points->Delete();
  dataset->GetPointData()->AddArray( a );
  a->Delete();
  dataset->GetPointData()->AddArray( b );
  b->Delete();
}

//////////////////////////////////////////////////////////////////////////////
void AppendDatasetsAndPrint( vtkPolyData* d1, vtkPolyData* d2 )
{
  vtkAppendFilter* append = vtkAppendFilter::New();
  append->AddInputData( d1 );
  append->AddInputData( d2 );
  append->Update();
  vtkUnstructuredGrid * grid = append->GetOutput();

  for ( int i = 0; i < grid->GetPointData()->GetNumberOfArrays(); ++i )
    {
    vtkIntArray* array = vtkIntArray::SafeDownCast( grid->GetPointData()->GetArray( i ) );
    std::cout << array->GetName() << ": [ ";
    for ( int j = 0; j < array->GetNumberOfTuples(); ++j )
      {
      std::cout << array->GetComponent( j, 0 );
      if ( j < array->GetNumberOfTuples() - 1 ) std::cout << ", ";
      }
    std::cout << " ]\n";
    }

  append->Delete();
}

//////////////////////////////////////////////////////////////////////////////
int main( int argc, char* argv[])
{
  // Set up d1 data object
  vtkPolyData* d1 = vtkPolyData::New();
  CreateDataset( d1 );

  // Set up d2 data object
  vtkPolyData* d2 = vtkPolyData::New();
  CreateDataset( d2 );

  // Now append these datasets and print the results
  std::cout << "Append result with no active scalars: " << std::endl;
  AppendDatasetsAndPrint( d1, d2 );

  // Set the active scalars in the first dataset to "A" and the active scalars in
  // the second dataset to "B".
  d1->GetPointData()->SetActiveScalars( "A" );
  d2->GetPointData()->SetActiveScalars( "B" );

  std::cout << "Append result with 'A' active scalar in D1, 'B' active scalar in D2: " << std::endl;
  AppendDatasetsAndPrint( d1, d2 );

  // Set the active scalars in the first dataset to "B" and the active scalars in
  // the second dataset to "A".
  d1->GetPointData()->SetActiveScalars( "B" );
  d2->GetPointData()->SetActiveScalars( "A" );

  std::cout << "Append result with 'B' active scalar in D1, 'A' active scalar in D2: " << std::endl;
  AppendDatasetsAndPrint( d1, d2 );
  
  // Set the active scalars in both datasets to "A"
  d1->GetPointData()->SetActiveScalars( "A" );
  d2->GetPointData()->SetActiveScalars( "A" );
  
  std::cout << "Append result with A active scalar in D1 and D2: " << std::endl;
  AppendDatasetsAndPrint( d1, d2 );
  
  d1->Delete();
  d2->Delete();

  return 0;
}


More information about the vtk-developers mailing list