Commits (27)
......@@ -50,8 +50,8 @@ public:
virtual void *GetGenericParentId() = 0;
virtual void *GetGenericContext() = 0;
virtual void *GetGenericDrawable() = 0;
virtual void SetWindowInfo(char *) = 0;
virtual void SetParentInfo(char *) = 0;
virtual void SetWindowInfo(const char *) = 0;
virtual void SetParentInfo(const char *) = 0;
//@}
//@{
......
......@@ -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(
*this->FieldComponentsNames[i]);
}
else
{
newFieldComponentsNames[i] = nullptr;
}
}
memcpy(newFieldTypes, this->FieldTypes, sizeof(int)*old_size);
memcpy(newFieldComponents, this->FieldComponents, sizeof(int)*old_size);
memcpy(newFieldIndices, this->FieldIndices, sizeof(int)*old_size);
memcpy(newLUT, this->LUT, sizeof(vtkLookupTable*)*old_size);
memcpy(newFieldInformation, this->FieldInformation,
sizeof(vtkInformation*)*old_size);
// initialize the rest.
for (int i=old_size; i < new_size; i++)
{
newFields[i] = nullptr;
newFieldTypes[i] = -1;
newFieldComponents[i] = 0;
newFieldIndices[i] = -1;
newLUT[i] = nullptr;
newFieldInformation[i] = nullptr;
newFieldComponentsNames[i] = nullptr;
}
int **newDSAIndices = new int*[this->NumberOfDSAIndices];
for (int cc=0; cc < this->NumberOfDSAIndices; cc++)
{
if (this->DSAIndices[cc] != nullptr)
{
newDSAIndices[cc] = new int[new_size];
memcpy(newDSAIndices[cc], this->DSAIndices[cc], sizeof(int)*old_size);
for (int kk=old_size; kk < new_size; kk++)
{
newDSAIndices[cc][kk] = -1;
}
}
else
{
newDSAIndices[cc] = nullptr;
}
}
int currentInput = this->CurrentInput;
int numberOfDSAIndices = this->NumberOfDSAIndices;
this->ClearFields();
this->NumberOfFields = new_size;
this->NumberOfDSAIndices = numberOfDSAIndices;
this->CurrentInput = currentInput;
this->Fields = newFields;
this->FieldTypes = newFieldTypes;
this->FieldComponents = newFieldComponents;
this->FieldComponentsNames = newFieldComponentsNames;
this->FieldIndices = newFieldIndices;
this->LUT = newLUT;
this->FieldInformation = newFieldInformation;
this->DSAIndices = newDSAIndices;
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::IntersectFieldList(vtkDataSetAttributes* dsa)
{
int i;
vtkDataArray *da;
vtkAbstractArray* aa;
// Initialize the indices for this dataset
this->DSAIndices[this->CurrentInput] = new int [this->NumberOfFields];
for (i=0; i < this->NumberOfFields; i++)
{
this->DSAIndices[this->CurrentInput][i]= -1;
}
// Keep a running total of the number of tuples...might be useful
// for later allocation.
if ( (da=dsa->GetArray(0)) )
{
this->NumberOfTuples += da->GetNumberOfTuples();
}
// Intersect the attributes
int attributeIndices[NUM_ATTRIBUTES];
dsa->GetAttributeIndices(attributeIndices);
for(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]))
{
this->DSAIndices[this->CurrentInput][i] = attributeIndices[i];
}
else
{
this->FieldIndices[i] = -1; //Attribute not present
}
}
}
// Intersect the fields
int index;
for(i=NUM_ATTRIBUTES; i < this->NumberOfFields; i++)
{
if (this->FieldIndices[i] >= 0)
{
aa = dsa->GetAbstractArray(this->Fields[i], index);
if ((aa) && (aa->GetDataType() == this->FieldTypes[i]) &&
(aa->GetNumberOfComponents() == this->FieldComponents[i]))
{
this->DSAIndices[this->CurrentInput][i] = index;
}
else
{
this->FieldIndices[i] = -1; //Field not present
}
}
}
this->CurrentInput++;
}
//--------------------------------------------------------------------------
int vtkDataSetAttributes::FieldList::IsAttributePresent(int attrType)
{
return this->FieldIndices[attrType];
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::ClearFields()
{
int i;
if ( this->Fields )
{
for (i=0; i<this->NumberOfFields; i++)
{
delete [] this->Fields[i];
this->Fields[i] = nullptr;
}
}
if ( this->DSAIndices )
{
for (i=0; i<this->NumberOfDSAIndices; i++)
{
delete[] this->DSAIndices[i];
this->DSAIndices[i] = nullptr;
}
}
//
delete [] this->Fields;
this->Fields = nullptr;
delete [] this->FieldInformation;
this->FieldInformation = nullptr;
delete [] this->LUT;
this->LUT = nullptr;
delete [] this->FieldTypes;
this->FieldTypes = nullptr;
delete [] this->FieldComponents;
this->FieldComponents = nullptr;
if ( this->FieldComponentsNames )
{
for (i=0; i<this->NumberOfFields; i++)
{
delete this->FieldComponentsNames[i];
}
delete [] this->FieldComponentsNames;
this->FieldComponentsNames = nullptr;
}
delete [] this->FieldIndices;
this->FieldIndices = nullptr;
this->NumberOfFields = 0;
this->CurrentInput = 0;
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::SetField(
int index,
vtkAbstractArray *aa)
{
// Store the field name
delete [] this->Fields[index];
this->Fields[index] = nullptr;
const char* name=aa->GetName();
if (name)
{
int len = static_cast<int>(strlen(name));
if (len > 0)
{
this->Fields[index] = new char[len+1];
strcpy(this->Fields[index], name);
}
}
// Store the data type
this->FieldTypes[index] = aa->GetDataType();
//we unallocate the names before we update the field components
//so we unallocate correctly
delete this->FieldComponentsNames[index];
this->FieldComponentsNames[index] = nullptr;
//store the components names
int numberOfComponents = aa->GetNumberOfComponents();
if ( aa->HasAComponentName() )
{
this->FieldComponentsNames[index] =
new vtkDataSetAttributes::vtkInternalComponentNames();
this->FieldComponentsNames[index]->resize(numberOfComponents,
std::pair<bool, vtkStdString>(false, vtkStdString()));
name = nullptr;
for ( vtkIdType i=0; i < numberOfComponents; ++i)
{
name = aa->GetComponentName(i);
if ( name )
{
this->FieldComponentsNames[index]->at(i) =
std::pair<bool, vtkStdString>(true, name);
name = nullptr;
}
}
}
// Store the components
this->FieldComponents[index] = numberOfComponents;
// Store the lookup table
this->LUT[index]=nullptr;
if (vtkArrayDownCast<vtkDataArray>(aa))
{
this->LUT[index]= vtkArrayDownCast<vtkDataArray>(aa)->GetLookupTable();
}
// Store the information
this->FieldInformation[index] = nullptr;
if (aa->HasInformation())
{
this->FieldInformation[index] = aa->GetInformation();
}
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::RemoveField(const char *name)
{
if ( !name )
{
return;
}
int i;
for (i=NUM_ATTRIBUTES; i < this->NumberOfFields; i++)
{
if ( this->Fields[i] && !strcmp(this->Fields[i],name) )
{
delete [] this->Fields[i];
this->Fields[i] = nullptr;
this->FieldTypes[i] = -1;
this->FieldComponents[i] = 0;
delete this->FieldComponentsNames[i];
this->FieldComponentsNames[i] = nullptr;
this->FieldIndices[i] = -1;
this->LUT[i] = nullptr;
this->FieldInformation[i] = nullptr;
return;
}
}
}
//--------------------------------------------------------------------------
void vtkDataSetAttributes::FieldList::PrintSelf(ostream &os, vtkIndent indent)
{
os << indent << "Number of Fields:" << this->NumberOfFields << endl;
vtkIndent nextIndent=indent.GetNextIndent();
for (int i=0; i<this->NumberOfFields; ++i)
{
os << indent << "Field " << i << " {" << endl
<< nextIndent
<< (this->Fields[i]==nullptr?"nullptr":this->Fields[i]) << ", "
<< this->FieldTypes[i] << ", "
<< this->FieldComponents[i] << ", "
<< this->FieldIndices[i] << ", "
<< this->FieldInformation[i]
<< "}" << endl;
}
}
......@@ -44,7 +44,8 @@
#ifndef vtkDataSetAttributes_h
#define vtkDataSetAttributes_h
#include "vtkCommonDataModelModule.h" // For export macro
#include "vtkCommonDataModelModule.h" // For export macro
#include "vtkDataSetAttributesFieldList.h" // for vtkDataSetAttributesFieldList
#include "vtkFieldData.h"
class vtkLookupTable;
......@@ -546,7 +547,7 @@ public:
vtkDataSetAttributes *from2,
vtkIdType id, double t);
class FieldList;
using FieldList = vtkDataSetAttributesFieldList;
// field list copy operations ------------------------------------------
......@@ -591,8 +592,6 @@ public:
int idx, vtkIdType toId,
vtkIdList *ids, double *weights);
friend class vtkDataSetAttributes::FieldList;
protected:
vtkDataSetAttributes();
~vtkDataSetAttributes() override;
......@@ -604,11 +603,6 @@ protected:
int shallowCopyArrays=0,
bool createNewArrays=true);
void InternalCopyAllocate(
vtkDataSetAttributes::FieldList& list,
int ctype,
vtkIdType sze, vtkIdType ext);
/**
* Initialize all of the object's data to nullptr
*/
......@@ -635,79 +629,7 @@ private:
vtkDataSetAttributes(const vtkDataSetAttributes&) = delete;
void operator=(const vtkDataSetAttributes&) = delete;
public:
// This public class is used to perform set operations, other misc.
// operations on fields. For example, vtkAppendFilter uses it to
// determine which attributes the input datasets share in common.
class vtkInternalComponentNames;
class VTKCOMMONDATAMODEL_EXPORT FieldList
{
public:
FieldList(int numInputs);
~FieldList();
void PrintSelf(ostream &os, vtkIndent indent);
void InitializeFieldList(vtkDataSetAttributes* dsa);
void IntersectFieldList(vtkDataSetAttributes* dsa);
/**
* Similar to IntersectFieldList() except that it builds a union of the
* array list. To determine the active attributes, it still, however, takes
* an intersection.
* WARNING!!!-IntersectFieldList() and UnionFieldList() should not be
* intermixed.
*/
void UnionFieldList(vtkDataSetAttributes* dsa);
//Determine whether data is available
int IsAttributePresent(int attrType); //true/false attributes specified
// Accessor methods.
int GetNumberOfFields() { return this->NumberOfFields; }
int GetFieldIndex(int i) { return this->FieldIndices[i]; }
const char* GetFieldName(int i) { return this->Fields[i]; }
int GetFieldComponents(int i) { return this->FieldComponents[i]; }
int GetDSAIndex(int index, int i) { return this->DSAIndices[index][i]; }
friend class vtkDataSetAttributes;
protected:
void SetFieldIndex(int i, int index)
{ this->FieldIndices[i] = index; }
private:
FieldList(const FieldList&) = delete;
void operator=(const FieldList&) = delete;
void SetField(int index, vtkAbstractArray *da);
void RemoveField(const char *name);
void ClearFields();
void GrowBy(unsigned int delta);
int NumberOfFields; //the number of fields (including five named attributes)
// These keep track of what is common across datasets. The first
// six items are always named attributes.
char** Fields; // the names of the fields
int *FieldTypes; // the types of the fields
int *FieldComponents; // the number of components in field
int *FieldIndices; // output data array index
vtkLookupTable **LUT; // luts associated with each array
vtkInformation **FieldInformation; // Information map associated with each array
vtkInternalComponentNames **FieldComponentsNames; // the name for each component in the field
vtkIdType NumberOfTuples; // a running total of values
//For every vtkDataSetAttributes that are processed, keep track of the
//indices into various things. The indices are organized so that the
//first NUM_ATTRIBUTES refer to attributes, the next refer to the
//non-attribute fields, for a total of NUM_ATTRIBUTES + NumberOfFields.
//CurrentInput is the current input being processed.
int **DSAIndices;
int NumberOfDSAIndices;
int CurrentInput;
};
friend class vtkDataSetAttributesFieldList;
};
#endif
/*=========================================================================
Program: Visualization Toolkit
Module: vtkDataSetAttributesFieldList.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkDataSetAttributesFieldList.h"
#include "vtkDataArray.h"
#include "vtkDataSetAttributes.h"
#include "vtkIdList.h"
#include "vtkInformation.h"
#include "vtkLookupTable.h"
#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"
#include <algorithm>
#include <array>
#include <functional>
#include <map>
#include <set>
#include <string>
#include <vector>
namespace detail
{
/**
* FieldInfo is used to store metadata about a field.
*/
struct FieldInfo
{
//@{
/**
* These attributes are used to compare two fields. If they match,
* then the fields can be treated as similar, hence can be merged.
*/
std::string Name;
int Type;
int NumberOfComponents;
//@}
//@{
/**
* These store metadata that may be present on any input field.
* These are passed to the output in `CopyAllocate`
*/
vtkSmartPointer<vtkLookupTable> LUT;
vtkSmartPointer<vtkInformation> Information;
std::vector<std::string> ComponentNames;
//@}
/**
* An array where `AttributeTypes[j][i]==true` if this field is marked
* as the i'th attribute type on the j'th input idx.
*/
std::vector<std::array<bool, vtkDataSetAttributes::NUM_ATTRIBUTES> > AttributeTypes;
/**
* Location of this field in the input vtkDataSetAttributes instance at the
* specific index, or -1 if not present in that input.
*/
std::vector<int> Location;
/**
* This is set in `CopyAllocate` to indicate the location of this field in the
* output vtkDataSetAttributes.
*/
mutable int OutputLocation;
FieldInfo()
: Name()
, Type(VTK_VOID)
, NumberOfComponents(0)
, LUT(nullptr)
, Information(nullptr)
, ComponentNames{}
, Location{}
, OutputLocation(-1)
{
}
void PrintSelf(ostream& os, vtkIndent indent) const
{
if (this->IsEmpty())
{
os << indent << "FieldInfo (" << this << "): Empty" << endl;
}
else
{
os << indent << "FieldInfo (" << this << ")\n";
os << indent.GetNextIndent() << "Name: " << this->Name << endl;
os << indent.GetNextIndent() << "Type: " << this->Type << endl;
os << indent.GetNextIndent() << "NumberOfComponents: " << this->NumberOfComponents << endl;
os << indent.GetNextIndent() << "LUT: " << this->LUT << endl;
os << indent.GetNextIndent() << "Information: " << this->Information << endl;
os << indent.GetNextIndent() << "Location: [ ";
for (const int& loc : this->Location)
{
os << loc << " ";
}
os << "]" << endl;
os << indent.GetNextIndent() << "OutputLocation: " << this->OutputLocation << endl;
}
}
bool IsEmpty() const { return this->Type == VTK_VOID; }
static FieldInfo Create(vtkAbstractArray* array, int loc)
{
FieldInfo info;
if (array)
{
info.Name = array->GetName() ? std::string(array->GetName()) : std::string();
info.Type = array->GetDataType();
info.NumberOfComponents = array->GetNumberOfComponents();
if (auto da = vtkDataArray::SafeDownCast(array))
{
info.LUT = da->GetLookupTable();
}
info.Information = array->GetInformation();
info.ComponentNames.resize(info.NumberOfComponents);
for (int cc = 0; cc < info.NumberOfComponents; ++cc)
{
if (auto name = array->GetComponentName(cc))
{
info.ComponentNames[cc] = name;
}
}
info.Location.push_back(loc);
}
return info;
}
void InitializeArray(vtkAbstractArray* array, vtkIdType sz, vtkIdType ext) const
{
if (array)
{
array->SetName(this->Name.empty() ? nullptr : this->Name.c_str());
array->SetNumberOfComponents(this->NumberOfComponents);
int cc = 0;
for (const auto& cname : this->ComponentNames)
{
if (cname.size())
{
array->SetComponentName(cc, cname.c_str());
}
++cc;
}
if (this->Information)
{
array->CopyInformation(this->Information, /*deep=*/1);
}
if (auto darray = vtkDataArray::SafeDownCast(array))
{
darray->SetLookupTable(this->LUT);
}
array->Allocate(sz, ext);
}
}
bool IsSimilar(const FieldInfo& other) const
{
return (this->Name == other.Name && this->Type == other.Type &&
this->NumberOfComponents == other.NumberOfComponents);
}
/**
* This method merges `this` and `other` to return a new FieldInfo.
*/
FieldInfo operator+(const FieldInfo& other) const
{
if (!this->IsEmpty() && this->IsSimilar(other))
{
FieldInfo result;
result = *this;
result.LUT = result.LUT ? result.LUT : other.LUT;
result.Information = result.Information ? result.Information : other.Information;
// merge component names.
assert(result.ComponentNames.size() == other.ComponentNames.size());
std::transform(result.ComponentNames.begin(), result.ComponentNames.end(),
other.ComponentNames.begin(), result.ComponentNames.begin(),
[](const std::string& in0, const std::string& in1) { return in0.empty() ? in1 : in0; });
assert(other.Location.size() == 1);
result.Location.insert(result.Location.end(), other.Location.begin(), other.Location.end());
result.AttributeTypes.insert(
result.AttributeTypes.end(), other.AttributeTypes.begin(), other.AttributeTypes.end());
return result;
}
else
{
return FieldInfo();
}
}
//@{
/**
* These methods are used by `UnionFieldList` to pad a FieldInfo instance.
* Calling these methods clears `AttributeTypes` since it indicates that this
* field is missing either in the inputs seen so far or in the current
* input and hence cannot be flagged as an attribute.
*/
void ExtendForUnion()
{
this->Location.push_back(-1);
std::array<bool, vtkDataSetAttributes::NUM_ATTRIBUTES> curattrs;
std::fill(curattrs.begin(), curattrs.end(), false);
this->AttributeTypes.push_back(std::move(curattrs));
}
void PreExtendForUnion(int count)
{
this->Location.insert(this->Location.begin(), count, -1);
std::array<bool, vtkDataSetAttributes::NUM_ATTRIBUTES> curattrs;
std::fill(curattrs.begin(), curattrs.end(), false);
this->AttributeTypes.insert(this->AttributeTypes.begin(), count, curattrs);
}
//@}
};
std::multimap<std::string, FieldInfo> GetFields(vtkDataSetAttributes* dsa)
{
std::array<int, vtkDataSetAttributes::NUM_ATTRIBUTES> attribute_indices;
dsa->GetAttributeIndices(attribute_indices.data());
std::multimap<std::string, FieldInfo> fields;
const auto num_of_arrays = dsa->GetNumberOfArrays();
for (int cc = 0; cc < num_of_arrays; ++cc)
{
auto finfo = FieldInfo::Create(dsa->GetAbstractArray(cc), cc);
// setup attributes info.
std::array<bool, vtkDataSetAttributes::NUM_ATTRIBUTES> curattrs;
std::transform(attribute_indices.begin(), attribute_indices.end(), curattrs.begin(),
[cc](int idx) { return idx == cc; });
finfo.AttributeTypes.push_back(std::move(curattrs));
fields.insert(std::make_pair(finfo.Name, std::move(finfo)));
}
return fields;
}
/**
* returns a vector of FieldInfo* where the index is the attribute type and
* value is the FieldInfo that will be flagged as that attribute type.
* To determine this, we look at the AttributeTypes information accumulated for
* inputs and mark an attribute as such only if its tagged as an attribute on
* all inputs consistently.
*/
std::array<const detail::FieldInfo*, vtkDataSetAttributes::NUM_ATTRIBUTES> GetAttributes(
const std::multimap<std::string, FieldInfo>& mmap)
{
std::array<const detail::