Commit f14fbdf6 authored by Utkarsh Ayachit's avatar Utkarsh Ayachit Committed by Kitware Robot
Browse files

Merge topic 'new-field-list'

ded78d2b Fix handling of global cell ids.
45a5778f Simply `vtkAppendFilter` to use `FieldList`.
426fc1f7 Make vtkAppendFilter respect copy flags for attributes.
e3f9c88d Simplify vtkAppendPolyData.
f4662727

 Refactor vtkDataSetAttributes::FieldList
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Cory Quammen's avatarCory Quammen <cory.quammen@kitware.com>
Merge-request: !4469
parents b8ec9be1 ded78d2b
......@@ -40,6 +40,7 @@ set(Module_SRCS
vtkDataObjectTree.cxx
vtkDataObjectTreeIterator.cxx
vtkDataSetAttributes.cxx
vtkDataSetAttributesFieldList.cxx
vtkDataSetCollection.cxx
vtkDataSet.cxx
vtkDirectedAcyclicGraph.cxx
......
......@@ -12,6 +12,7 @@ vtk_add_test_cxx(vtkCommonDataModelCxxTests tests
TestDataArrayDispatcher.cxx
TestDataObject.cxx
TestDispatchers.cxx
TestFieldList.cxx
TestGenericCell.cxx
TestGraph.cxx
TestGraph2.cxx
......
#include "vtkDataSetAttributes.h"
#include "vtkDoubleArray.h"
#include "vtkIntArray.h"
#include "vtkNew.h"
#include "vtkSmartPointer.h"
#include <string>
namespace
{
template <typename T>
vtkSmartPointer<T> CreateArray(const char* aname, int num_comps, vtkIdType numTuples)
{
auto array = vtkSmartPointer<T>::New();
array->SetName(aname);
array->SetNumberOfComponents(num_comps);
array->SetNumberOfTuples(numTuples);
array->FillValue(typename T::ValueType());
return array;
}
#define EXPECT_THAT(v, m) \
if ((v) != (m)) \
{ \
cerr << "FAILED at line " << __LINE__ << ": \n " << #v << " must match " << #m << endl; \
return EXIT_FAILURE; \
}
}
int TestFieldList(int, char* [])
{
{
// For arrays without names, ensure we are doing a order-dependent matching.
// For attributes, the attribute flag is preserved if the same arrays is
// consistently flagged as an attribute on all DSA instances.
vtkNew<vtkDataSetAttributes> dsa0;
dsa0->SetScalars(CreateArray<vtkDoubleArray>(nullptr, 1, 20));
dsa0->AddArray(CreateArray<vtkDoubleArray>(nullptr, 2, 20));
dsa0->SetVectors(CreateArray<vtkDoubleArray>(nullptr, 3, 20));
EXPECT_THAT(dsa0->GetNumberOfArrays(), 3);
vtkNew<vtkDataSetAttributes> dsa1;
dsa1->SetScalars(CreateArray<vtkDoubleArray>(nullptr, 1, 20));
dsa1->AddArray(CreateArray<vtkDoubleArray>(nullptr, 3, 20));
dsa1->AddArray(CreateArray<vtkDoubleArray>(nullptr, 3, 20));
EXPECT_THAT(dsa1->GetNumberOfArrays(), 3);
vtkDataSetAttributes::FieldList fl;
fl.InitializeFieldList(dsa0);
fl.IntersectFieldList(dsa1);
vtkNew<vtkDataSetAttributes> output;
fl.CopyAllocate(output, vtkDataSetAttributes::COPYTUPLE, 0, 0);
EXPECT_THAT(output->GetNumberOfArrays(), 2);
EXPECT_THAT(output->GetArray(0)->GetNumberOfComponents(), 1);
EXPECT_THAT(output->GetArray(1)->GetNumberOfComponents(), 3);
EXPECT_THAT(output->GetVectors(), nullptr);
EXPECT_THAT(output->GetScalars() != nullptr, true);
fl.InitializeFieldList(dsa0);
fl.UnionFieldList(dsa1);
output->Initialize();
fl.CopyAllocate(output, vtkDataSetAttributes::COPYTUPLE, 0, 0);
EXPECT_THAT(output->GetNumberOfArrays(), 4);
EXPECT_THAT(output->GetArray(0)->GetNumberOfComponents(), 1);
EXPECT_THAT(output->GetArray(1)->GetNumberOfComponents(), 2);
EXPECT_THAT(output->GetArray(2)->GetNumberOfComponents(), 3);
EXPECT_THAT(output->GetArray(3)->GetNumberOfComponents(), 3);
EXPECT_THAT(output->GetVectors(), nullptr);
EXPECT_THAT(output->GetScalars() != nullptr, true);
// just to increase coverage.
fl.PrintSelf(cout, vtkIndent());
}
{
// If inputs arrays with different names for attributes,
// make sure output doesn't have either of the arrays flagged as attributes.
vtkNew<vtkDataSetAttributes> dsa0;
dsa0->SetScalars(CreateArray<vtkDoubleArray>("scalars", 1, 20));
dsa0->AddArray(CreateArray<vtkDoubleArray>("vectors", 3, 20));
dsa0->AddArray(CreateArray<vtkDoubleArray>("common", 1, 20));
dsa0->AddArray(CreateArray<vtkDoubleArray>("uncommon0", 1, 20));
vtkNew<vtkDataSetAttributes> dsa1;
dsa1->AddArray(CreateArray<vtkDoubleArray>("scalars", 1, 20));
dsa1->SetVectors(CreateArray<vtkDoubleArray>("vectors", 3, 20));
dsa1->AddArray(CreateArray<vtkDoubleArray>("common", 1, 20));
dsa0->AddArray(CreateArray<vtkDoubleArray>("uncommon1", 1, 20));
vtkDataSetAttributes::FieldList fl;
fl.InitializeFieldList(dsa0);
fl.IntersectFieldList(dsa1);
vtkNew<vtkDataSetAttributes> output;
fl.CopyAllocate(output, vtkDataSetAttributes::COPYTUPLE, 0, 0);
EXPECT_THAT(output->GetNumberOfArrays(), 3);
EXPECT_THAT(output->GetArray("uncommon0"), nullptr);
EXPECT_THAT(output->GetArray("uncommon1"), nullptr);
EXPECT_THAT(output->GetScalars(), nullptr);
EXPECT_THAT(output->GetVectors(), nullptr);
EXPECT_THAT(output->GetArray("scalars") != nullptr, true);
EXPECT_THAT(output->GetArray("vectors") != nullptr, true);
fl.InitializeFieldList(dsa0);
fl.UnionFieldList(dsa1);
output->Initialize();
fl.CopyAllocate(output, vtkDataSetAttributes::COPYTUPLE, 0, 0);
EXPECT_THAT(output->GetNumberOfArrays(), 5);
EXPECT_THAT(output->GetScalars(), nullptr);
EXPECT_THAT(output->GetVectors(), nullptr);
}
return EXIT_SUCCESS;
}
......@@ -36,16 +36,7 @@
#include "vtkUnsignedShortArray.h"
#include <vector>
namespace
{
// pair.first it used to indicate if pair.second is valid.
typedef std::vector<std::pair<bool, vtkStdString> > vtkInternalComponentNameBase;
}
class vtkDataSetAttributes::vtkInternalComponentNames : public vtkInternalComponentNameBase {};
vtkStandardNewMacro(vtkDataSetAttributes);
//--------------------------------------------------------------------------
const char vtkDataSetAttributes
::AttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][12] =
......@@ -1636,7 +1627,7 @@ void vtkDataSetAttributes::CopyAllocate(
vtkDataSetAttributes::FieldList& list,
vtkIdType sze, vtkIdType ext)
{
this->InternalCopyAllocate(list, COPYTUPLE, sze, ext);
list.CopyAllocate(this, COPYTUPLE, sze, ext);
}
//--------------------------------------------------------------------------
......@@ -1644,88 +1635,7 @@ void vtkDataSetAttributes::InterpolateAllocate(
vtkDataSetAttributes::FieldList& list, vtkIdType sze,
vtkIdType ext)
{
this->InternalCopyAllocate(list, INTERPOLATE, sze, ext);
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::InternalCopyAllocate(
vtkDataSetAttributes::FieldList& list,
int ctype,
vtkIdType sze, vtkIdType ext)
{
vtkAbstractArray* newAA=nullptr;
vtkDataArray* newDA=nullptr;
int i;
// Allocate attributes if any
for (i=0; i < list.NumberOfFields; i++)
{
if ( list.FieldIndices[i] >= 0 )
{
newAA = vtkAbstractArray::CreateArray(list.FieldTypes[i]);
newAA->SetName(list.Fields[i]);
newAA->SetNumberOfComponents(list.FieldComponents[i]);
if ( list.FieldComponentsNames[i] )
{
for (unsigned int j=0; j < list.FieldComponentsNames[i]->size(); ++j)
{
if (list.FieldComponentsNames[i]->at(j).first)
{
newAA->SetComponentName(j,
list.FieldComponentsNames[i]->at(j).second.c_str());
}
}
}
if (list.FieldInformation[i])
{
newAA->CopyInformation(list.FieldInformation[i],/*deep=*/1);
}
if ( sze > 0 )
{
newAA->Allocate(sze,ext);
}
else
{
newAA->Allocate(list.NumberOfTuples,ext);
}
if ( (newDA = vtkArrayDownCast<vtkDataArray>(newAA)) )
{
newDA->SetLookupTable(list.LUT[i]);
}
// If attribute data, do something extra
if ( i < NUM_ATTRIBUTES )
{
// since attributes can only be DataArray, newDA must be non-null.
if ( this->CopyAttributeFlags[ctype][i] && newDA)
{
list.FieldIndices[i] = this->AddArray(newDA);
this->SetActiveAttribute(list.FieldIndices[i], i);
}
else
{
list.FieldIndices[i] = -1;
}
}
else //check if this field is to be copied
{
if ( (this->GetFlag(list.Fields[i]) != 0) &&
!(this->DoCopyAllOff && (this->GetFlag(list.Fields[i]) != 1)) )
{
list.FieldIndices[i] = this->AddArray(newAA);
}
else
{
list.FieldIndices[i] = -1;
}
}
newAA->Delete(); //okay, reference counting
}//data array defined
}
list.CopyAllocate(this, INTERPOLATE, sze, ext);
}
//--------------------------------------------------------------------------
......@@ -1737,16 +1647,7 @@ void vtkDataSetAttributes::CopyData(vtkDataSetAttributes::FieldList& list,
vtkDataSetAttributes* fromDSA,
int idx, vtkIdType fromId, vtkIdType toId)
{
for (int i=0; i < list.NumberOfFields; i++)
{
if ( list.FieldIndices[i] >= 0 && list.DSAIndices[idx][i] >= 0 )
{
vtkAbstractArray *toDA = this->GetAbstractArray(list.FieldIndices[i]);
vtkAbstractArray *fromDA = fromDSA->GetAbstractArray(list.DSAIndices[idx][i]);
this->CopyTuple(fromDA, toDA, fromId, toId);
}
}
list.CopyData(idx, fromDSA, fromId, this, toId);
}
//--------------------------------------------------------------------------
......@@ -1759,15 +1660,7 @@ void vtkDataSetAttributes::CopyData(vtkDataSetAttributes::FieldList& list,
int idx, vtkIdType dstStart, vtkIdType n,
vtkIdType srcStart)
{
for (int i=0; i < list.NumberOfFields; i++)
{
if ( list.FieldIndices[i] >= 0 && list.DSAIndices[idx][i] >= 0 )
{
vtkAbstractArray *toDA = this->GetAbstractArray(list.FieldIndices[i]);
vtkAbstractArray *fromDA = fromDSA->GetAbstractArray(list.DSAIndices[idx][i]);
this->CopyTuples(fromDA, toDA, dstStart, n, srcStart);
}
}
list.CopyData(idx, fromDSA, srcStart, n, this, dstStart);
}
//--------------------------------------------------------------------------
......@@ -1780,41 +1673,7 @@ void vtkDataSetAttributes::InterpolatePoint(
vtkIdType toId, vtkIdList *ptIds,
double *weights)
{
vtkAbstractArray *fromArray;
vtkAbstractArray *toArray;
for (int i=0; i < list.NumberOfFields; i++)
{
if ( list.FieldIndices[i] >= 0 && list.DSAIndices[idx][i] >= 0 )
{
toArray = this->GetAbstractArray(list.FieldIndices[i]);
fromArray = fromPd->GetAbstractArray(list.DSAIndices[idx][i]);
//check if the destination array needs nearest neighbor interpolation
int attributeIndex = this->IsArrayAnAttribute(list.DSAIndices[idx][i]);
if (attributeIndex != -1
&&
this->CopyAttributeFlags[INTERPOLATE][attributeIndex]==2)
{
vtkIdType numIds = ptIds->GetNumberOfIds();
vtkIdType maxId = ptIds->GetId(0);
vtkIdType maxWeight = 0.;
for (int j=0;j<numIds;j++)
{
if (weights[j] > maxWeight)
{
maxWeight = weights[j];
maxId = ptIds->GetId(j);
}
}
toArray->InsertTuple(toId, maxId, fromArray);
}
else
{
toArray->InterpolateTuple(toId, ptIds, fromArray, weights);
}
}
}
list.InterpolatePoint(idx, fromPd, ptIds, weights, this, toId);
}
//--------------------------------------------------------------------------
......@@ -1838,548 +1697,3 @@ const char* vtkDataSetAttributes::GetLongAttributeTypeAsString(int attributeType
}
return vtkDataSetAttributes::LongAttributeNames[attributeType];
}
//=============================================================================
vtkDataSetAttributes::FieldList::FieldList(int numInputs)
{
this->Fields = nullptr;
this->FieldTypes = nullptr;
this->FieldComponents = nullptr;
this->FieldComponentsNames = nullptr;
this->FieldIndices = nullptr;
this->NumberOfFields = 0;
this->LUT = nullptr;
this->FieldInformation = nullptr;
this->DSAIndices = nullptr;
this->NumberOfDSAIndices = 0;
//
if (numInputs)
{
this->NumberOfDSAIndices = numInputs;
this->DSAIndices = new int*[numInputs];
int i;
for (i=0; i<numInputs; i++)
{
this->DSAIndices[i] = nullptr;
}
}
}
//--------------------------------------------------------------------------
vtkDataSetAttributes::FieldList::~FieldList()
{
this->ClearFields();
delete [] this->DSAIndices;
this->DSAIndices = nullptr;
}
//----------------------------------------------------------------------------
// To perform intersection of attribute data, use InitializeFieldList() to grab
// an initial vtkDataSetAttributes. Then use IntersectFieldList() to add (and
// intersect) additional vtkDataSetAttributes.
void vtkDataSetAttributes::FieldList::InitializeFieldList(
vtkDataSetAttributes* dsa)
{
int i;
this->ClearFields();
// Allocate space for the arrays plus five attributes
this->NumberOfFields = dsa->GetNumberOfArrays() + NUM_ATTRIBUTES;
this->Fields = new char*[this->NumberOfFields];
this->FieldTypes = new int [this->NumberOfFields];
this->FieldComponents = new int [this->NumberOfFields];
this->FieldComponentsNames =
new vtkDataSetAttributes::vtkInternalComponentNames*[this->NumberOfFields];
this->FieldIndices = new int [this->NumberOfFields];
this->LUT = new vtkLookupTable* [this->NumberOfFields];
this->FieldInformation = new vtkInformation* [this->NumberOfFields];
for(i=0; i < this->NumberOfFields; i++)
{
this->Fields[i] = nullptr;
this->FieldTypes[i] = -1;
this->FieldComponents[i] = 0;
this->FieldComponentsNames[i] = nullptr;
this->FieldIndices[i] = -1;
this->LUT[i] = nullptr;
this->FieldInformation[i] = nullptr;
}
this->CurrentInput = 0;
this->NumberOfTuples = 0;
//there may be no data hence dsa->Data
for(i=0; dsa->Data && i < dsa->GetNumberOfArrays(); i++)
{
int attrType = dsa->IsArrayAnAttribute(i);
if ( attrType != -1 ) //it's an attribute
{
this->FieldIndices[attrType] = i;
this->SetField(attrType, dsa->Data[i]);
}
else
{
this->FieldIndices[NUM_ATTRIBUTES+i] = i;
this->SetField(NUM_ATTRIBUTES+i, dsa->Data[i]);
}
}
// The first dataset is added to the field list
this->IntersectFieldList(dsa);
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::UnionFieldList(vtkDataSetAttributes* dsa)
{
vtkAbstractArray* aa;
vtkDataArray* da;
// Keep a running total of the number of tuples...might be useful
// for later allocation.
if ( (aa=dsa->GetAbstractArray(0)) )
{
this->NumberOfTuples += aa->GetNumberOfTuples();
}
// unlike Intersection, with Union the total number of fields may change,
// so we have to be careful with that.
std::vector<int> dsaIndices;
dsaIndices.resize(this->NumberOfFields, -1);
// Intersect the active attributes. (Even though we are taking a union, we
// intersect the active attributes).
int attributeIndices[NUM_ATTRIBUTES];
dsa->GetAttributeIndices(attributeIndices);
for (int i=0; i < NUM_ATTRIBUTES; i++)
{
if (this->FieldIndices[i] >= 0)
{
da = dsa->GetAttribute(i);
if ((da) && (da->GetDataType() == this->FieldTypes[i]) &&
(da->GetNumberOfComponents() == this->FieldComponents[i]))
{
dsaIndices[i] = attributeIndices[i];
}
else
{
// doh! A attribute is not available in this new dsa. But it was
// available until now.
// In InitializeFieldList(), if an array is an active attribute, its
// information is noted only in the first "set". Now since we are
// marking it as not-an-attribute, we still don't want to lose the
// array. So we enable it in the second "set". But all DSAIndices until
// the CurrentInput referred to this array in it's location in the
// first "set" so we have to move those as well. That's what's
// happening here.
int offset = this->FieldIndices[i];
this->FieldIndices[NUM_ATTRIBUTES + offset] = this->FieldIndices[i];
this->Fields[offset+NUM_ATTRIBUTES] = this->Fields[i];
this->FieldTypes[offset+NUM_ATTRIBUTES] = this->FieldTypes[i];
this->FieldComponents[offset+NUM_ATTRIBUTES] = this->FieldComponents[i];
this->FieldComponentsNames[offset+NUM_ATTRIBUTES] = this->FieldComponentsNames[i];
this->LUT[offset+NUM_ATTRIBUTES] = this->LUT[i];
this->FieldInformation[offset+NUM_ATTRIBUTES] = this->FieldInformation[i];
this->FieldIndices[i] = -1; //Attribute not present
this->Fields[i] = nullptr;
this->FieldTypes[i] = -1;
this->FieldComponents[i] = 0;
this->FieldComponentsNames[i] = nullptr;
this->LUT[i] = nullptr;
this->FieldInformation[i] = nullptr;
for (int cc=0; cc < this->CurrentInput && cc < this->NumberOfDSAIndices;
cc++)
{
this->DSAIndices[cc][offset+NUM_ATTRIBUTES] = this->DSAIndices[cc][i];
this->DSAIndices[cc][i] = -1;
}
}
}
}
std::vector<bool> dsaMarkedArrays;
dsaMarkedArrays.resize(dsa->GetNumberOfArrays(), false);
// * Try to match the existing fields with those in dsa.
for (int i = NUM_ATTRIBUTES; i < this->NumberOfFields; i++)
{
// FieldIndices should really be a bool.
if (this->FieldIndices[i] < 0)
{
continue;
}
int index;
aa = dsa->GetAbstractArray(this->Fields[i], index);
if ((aa) && (aa->GetDataType() == this->FieldTypes[i]) &&
(aa->GetNumberOfComponents() == this->FieldComponents[i]))
{
dsaIndices[i] = index;
dsaMarkedArrays[index] = true;
}
}
// * Now every array in dsaMarkedArrays that has a false, implies that it did not
// match with any of the existing fields. So those will be appended to the
// end of the field list.
std::vector<int> dsaPendingIndices;
for (size_t cc=0; cc < dsaMarkedArrays.size(); cc++)
{
if (dsaMarkedArrays[cc] == false)
{
dsaPendingIndices.push_back(static_cast<int>(cc));
}
}
if (!dsaPendingIndices.empty())
{
size_t old_size = dsaIndices.size();
size_t new_size = old_size + dsaPendingIndices.size();
// * If dsaPendingIndices != empty, then we need to grow the num of fields.
this->GrowBy(static_cast<unsigned int>(dsaPendingIndices.size()));
dsaIndices.resize(new_size, -1);
for (size_t cc=0; cc < dsaPendingIndices.size(); cc++)
{
this->FieldIndices[old_size+cc] =
static_cast<int>((old_size+cc) - NUM_ATTRIBUTES);
this->SetField(static_cast<int>(old_size+cc),
dsa->GetAbstractArray(dsaPendingIndices[cc]));
dsaIndices[old_size + cc] = dsaPendingIndices[cc];
}
}
this->DSAIndices[this->CurrentInput] = new int [this->NumberOfFields];
memcpy(this->DSAIndices[this->CurrentInput], &dsaIndices[0],
sizeof(int)*this->NumberOfFields);
this->CurrentInput++;
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::GrowBy(unsigned int delta)
{
if (delta == 0)
{
return;
}
int old_size = this->NumberOfFields;
int new_size = this->NumberOfFields + delta;
char** newFields = new char*[new_size];
int* newFieldTypes = new int[new_size];
int* newFieldComponents = new int [new_size];
vtkDataSetAttributes::vtkInternalComponentNames** newFieldComponentsNames
= new vtkDataSetAttributes::vtkInternalComponentNames* [ new_size ];
int* newFieldIndices = new int [new_size];
vtkLookupTable** newLUT = new vtkLookupTable* [new_size];
vtkInformation** newFieldInformation = new vtkInformation* [new_size];
// copy the old fields.
for(int i=0; i < old_size; i++)
{
if (this->Fields[i])
{
newFields[i] = strdup(this->Fields[i]);
}
else
{
newFields[i] = nullptr;
}
if ( this->FieldComponentsNames[i] )
{
newFieldComponentsNames[i] =
new vtkDataSetAttributes::vtkInternalComponentNames(