Commit f4662727 authored by Utkarsh Ayachit's avatar Utkarsh Ayachit
Browse files

Refactor vtkDataSetAttributes::FieldList

Refactoring vtkDataSetAttributes::FieldList to make the implementation
more readable and also better handle cases where attributes are not
named consistently across mutliple inputs.
parent 6edfd72d
......@@ -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;
}
This diff is collapsed.
......@@ -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
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkDataSetAttributesFieldList.h
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.
=========================================================================*/
/**
* @class vtkDataSetAttributesFieldList
* @brief helps manage arrays from multiple vtkDataSetAttributes.
*
* vtkDataSetAttributesFieldList, also called vtkDataSetAttributes::FieldList,
* is used to help with filters when dealing with arrays from multiple
* vtkDataSetAttributes instances, potentially from multiple inputs.
*
* Consider a filter that appends multiple inputs, e.g. vtkAppendPolyData.
* Besides appending mesh elements, such a filter also needs to combine field
* arrays (point, and cell data) from inputs to pass on to the output.
* Now if all the inputs had exactly the same set of arrays, we're all set.
* However, more often than not, the inputs will have different sets of arrays.
* The filter will need to match up from various inputs to combine together,
* potentially dropping arrays not in all inputs. Furthermore, it needs to
* ensure arrays in the output are flagged as attributes consistently. All of
* this can be done using vtkDataSetAttributesFieldList.
*
* @section Usage Usage
*
* Typical usage is as follows:
* 1. call `IntersectFieldList` or `UnionFieldList` for all input vtkDataSetAttributes
* instances,
* 2. allocate arrays for the output vtkDataSetAttributes by using `CopyAllocate`,
* 3. call `CopyData` per input (preserving the input order used in step 1) to
* copy tuple(s) from input to the output.
*
* `vtkDataSetAttributes::InitializeFieldList` is provided for API compatibility
* with previous implementation of this class and it not required to be called.
* Simply calling `UnionFieldList` or `IntersectFieldList` for the first
* vtkDataSetAttributes instance is sufficient.
*
* `CopyAllocate, `CopyData`, and `InterpolatePoint` methods on this class
* are called by similarly named variants on vtkDataSetAttributes that take in a
* FieldList instance as an argument. Hence, either forms may be used.
*
* Calls to `UnionFieldList` and `IntersectFieldList` cannot be mixed. Use
* `Reset` or `InitializeFieldList` to change mode and start reinitialization.
*/
#ifndef vtkDataSetAttributesFieldList_h
#define vtkDataSetAttributesFieldList_h
#include "vtkCommonDataModelModule.h" // For export macro
#include "vtkSystemIncludes.h"
#include "vtkSmartPointer.h" // for vtkSmartPointer
#include <memory> // for unique_ptr
class vtkAbstractArray;
class vtkDataSetAttributes;
class vtkIdList;
class VTKCOMMONDATAMODEL_EXPORT vtkDataSetAttributesFieldList
{
public:
/**
* `number_of_inputs` parameter is not required and only provided for
* backwards compatibility.
*/
vtkDataSetAttributesFieldList(int number_of_inputs = 0);
virtual ~vtkDataSetAttributesFieldList();
void PrintSelf(ostream& os, vtkIndent indent);
/**
* Initializes the field list to empty.
*/
void Reset();
/**
* Initialize the field list. This also adds the first input.
* Calling this method is optional. The first call to `IntersectFieldList` or
* `UnionFieldList` on a new instance or after calling `Reset()` will have the
* same effect.
*/
void InitializeFieldList(vtkDataSetAttributes* dsa);
/**
* Update the field list for an intersection of arrays registered so far and
* those in `dsa`.
*/
void IntersectFieldList(vtkDataSetAttributes* dsa);
/**
* Update the field list for an union of arrays registered so far and
* those in `dsa`.
*/
void UnionFieldList(vtkDataSetAttributes* dsa);
//@{
/**
* These methods can called to generate and update the output
* vtkDataSetAttributes. These match corresponding API on vtkDataSetAttributes
* and can be called via the output vtkDataSetAttributes instance
* instead as well.
*/
void CopyAllocate(vtkDataSetAttributes* output, int ctype, vtkIdType sz, vtkIdType ext) const;
void CopyData(int inputIndex, vtkDataSetAttributes* input, vtkIdType fromId,
vtkDataSetAttributes* output, vtkIdType toId) const;
void CopyData(int inputIdx, vtkDataSetAttributes* input, vtkIdType inputStart,
vtkIdType numValues, vtkDataSetAttributes* output, vtkIdType outStart) const;
void InterpolatePoint(int inputIdx, vtkDataSetAttributes* input, vtkIdList* inputIds,
double* weights, vtkDataSetAttributes* output, vtkIdType toId) const;
//@}
//@{
/**
* vtkDataSetAttributes::FieldList used a different internal data structure in
* older versions of VTK. This exposes that API for legacy applications.
* It may be deprecated in the future.
*
* Using these methods should be avoided in new code.
*/
int IsAttributePresent(int attrType) const;
int GetNumberOfFields() const;
int GetFieldIndex(int i) const;
const char* GetFieldName(int i) const;
int GetFieldComponents(int i) const;
int GetDSAIndex(int index, int i) const;
//@}
protected:
/**
* Called to create an output array for the given type.
* Default implementation calls `vtkAbstractArray::CreateArray()`.
*/
virtual vtkSmartPointer<vtkAbstractArray> CreateArray(int type) const;
private:
class vtkInternals;
std::unique_ptr<vtkInternals> Internals;
vtkDataSetAttributesFieldList(const vtkDataSetAttributesFieldList&) = delete;
void operator=(vtkDataSetAttributesFieldList&) = delete;
};
#endif
// VTK-HeaderTest-Exclude: vtkDataSetAttributesFieldList.h
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment