/*========================================================================= Program: Visualization Toolkit Module: vtkDataSetAttributes.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 "vtkDataSetAttributes.h" #include "vtkArrayDispatch.h" #include "vtkArrayIteratorIncludes.h" #include "vtkAssume.h" #include "vtkCell.h" #include "vtkCharArray.h" #include "vtkDataArrayAccessor.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkIntArray.h" #include "vtkLongArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkShortArray.h" #include "vtkStructuredExtent.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnsignedLongArray.h" #include "vtkUnsignedShortArray.h" #include namespace { // pair.first it used to indicate if pair.second is valid. typedef std::vector > vtkInternalComponentNameBase; } class vtkDataSetAttributes::vtkInternalComponentNames : public vtkInternalComponentNameBase {}; vtkStandardNewMacro(vtkDataSetAttributes); //-------------------------------------------------------------------------- const char vtkDataSetAttributes ::AttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][12] = { "Scalars", "Vectors", "Normals", "TCoords", "Tensors", "GlobalIds", "PedigreeIds", "EdgeFlag" }; const char vtkDataSetAttributes ::LongAttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][35] = { "vtkDataSetAttributes::SCALARS", "vtkDataSetAttributes::VECTORS", "vtkDataSetAttributes::NORMALS", "vtkDataSetAttributes::TCOORDS", "vtkDataSetAttributes::TENSORS", "vtkDataSetAttributes::GLOBALIDS", "vtkDataSetAttributes::PEDIGREEIDS", "vtkDataSetAttributes::EDGEFLAG" }; //-------------------------------------------------------------------------- // Construct object with copying turned on for all data. vtkDataSetAttributes::vtkDataSetAttributes() { int attributeType; for(attributeType=0; attributeTypeAttributeIndices[attributeType] = -1; this->CopyAttributeFlags[COPYTUPLE][attributeType] = 1; this->CopyAttributeFlags[INTERPOLATE][attributeType] = 1; this->CopyAttributeFlags[PASSDATA][attributeType] = 1; } //Global IDs should not be interpolated because they are labels, not "numbers" //Global IDs should not be copied either, unless doing so preserves meaning. //Passing through is ussually OK because it is 1:1. this->CopyAttributeFlags[COPYTUPLE][GLOBALIDS] = 0; this->CopyAttributeFlags[INTERPOLATE][GLOBALIDS] = 0; //Pedigree IDs should not be interpolated because they are labels, not "numbers" //Pedigree IDs may be copied since they do not require 1:1 mapping. this->CopyAttributeFlags[INTERPOLATE][PEDIGREEIDS] = 0; this->TargetIndices=nullptr; } //-------------------------------------------------------------------------- // Destructor for the vtkDataSetAttributes objects. vtkDataSetAttributes::~vtkDataSetAttributes() { this->Initialize(); delete[] this->TargetIndices; this->TargetIndices = nullptr; } //-------------------------------------------------------------------------- // Turn on copying of all data. void vtkDataSetAttributes::CopyAllOn(int ctype) { this->vtkFieldData::CopyAllOn(); this->SetCopyScalars(1, ctype); this->SetCopyVectors(1, ctype); this->SetCopyNormals(1, ctype); this->SetCopyTCoords(1, ctype); this->SetCopyTensors(1, ctype); this->SetCopyGlobalIds(1, ctype); this->SetCopyPedigreeIds(1, ctype); } //-------------------------------------------------------------------------- // Turn off copying of all data. void vtkDataSetAttributes::CopyAllOff(int ctype) { this->vtkFieldData::CopyAllOff(); this->SetCopyScalars(0, ctype); this->SetCopyVectors(0, ctype); this->SetCopyNormals(0, ctype); this->SetCopyTCoords(0, ctype); this->SetCopyTensors(0, ctype); this->SetCopyGlobalIds(0, ctype); this->SetCopyPedigreeIds(0, ctype); } //-------------------------------------------------------------------------- // Deep copy of data (i.e., create new data arrays and // copy from input data). Note that attribute data is // not copied. void vtkDataSetAttributes::DeepCopy(vtkFieldData *fd) { this->Initialize(); //free up memory vtkDataSetAttributes* dsa = vtkDataSetAttributes::SafeDownCast(fd); // If the source is a vtkDataSetAttributes if (dsa) { int numArrays = fd->GetNumberOfArrays(); int attributeType, i; vtkAbstractArray *data, *newData; // Allocate space for numArrays this->AllocateArrays(numArrays); for (i=0; i < numArrays; i++ ) { data = fd->GetAbstractArray(i); newData = data->NewInstance(); //instantiate same type of object newData->DeepCopy(data); newData->SetName(data->GetName()); this->AddArray(newData); newData->Delete(); } // Copy the copy flags for(attributeType=0; attributeTypeAttributeIndices[attributeType] = dsa->AttributeIndices[attributeType]; this->CopyAttributeFlags[COPYTUPLE][attributeType] = dsa->CopyAttributeFlags[COPYTUPLE][attributeType]; this->CopyAttributeFlags[INTERPOLATE][attributeType] = dsa->CopyAttributeFlags[INTERPOLATE][attributeType]; this->CopyAttributeFlags[PASSDATA][attributeType] = dsa->CopyAttributeFlags[PASSDATA][attributeType]; } this->CopyFlags(dsa); } // If the source is field data, do a field data copy else { this->vtkFieldData::DeepCopy(fd); } } //-------------------------------------------------------------------------- // Shallow copy of data (i.e., use reference counting). void vtkDataSetAttributes::ShallowCopy(vtkFieldData *fd) { this->Initialize(); //free up memory vtkDataSetAttributes* dsa = vtkDataSetAttributes::SafeDownCast(fd); // If the source is a vtkDataSetAttributes if (dsa) { int numArrays = fd->GetNumberOfArrays(); int attributeType, i; // Allocate space for numArrays this->AllocateArrays(numArrays); this->NumberOfActiveArrays = 0; for (i=0; i < numArrays; i++ ) { this->NumberOfActiveArrays++; this->SetArray(i, fd->GetAbstractArray(i)); } // Copy the copy flags for(attributeType=0; attributeTypeAttributeIndices[attributeType] = dsa->AttributeIndices[attributeType]; this->CopyAttributeFlags[COPYTUPLE][attributeType] = dsa->CopyAttributeFlags[COPYTUPLE][attributeType]; this->CopyAttributeFlags[INTERPOLATE][attributeType] = dsa->CopyAttributeFlags[INTERPOLATE][attributeType]; this->CopyAttributeFlags[PASSDATA][attributeType] = dsa->CopyAttributeFlags[PASSDATA][attributeType]; } this->CopyFlags(dsa); } // If the source is field data, do a field data copy else { this->vtkFieldData::ShallowCopy(fd); } } //-------------------------------------------------------------------------- // Initialize all of the object's data to nullptr void vtkDataSetAttributes::InitializeFields() { this->vtkFieldData::InitializeFields(); int attributeType; for(attributeType=0; attributeTypeAttributeIndices[attributeType] = -1; this->CopyAttributeFlags[COPYTUPLE][attributeType] = 1; this->CopyAttributeFlags[INTERPOLATE][attributeType] = 1; this->CopyAttributeFlags[PASSDATA][attributeType] = 1; } this->CopyAttributeFlags[COPYTUPLE][GLOBALIDS] = 0; this->CopyAttributeFlags[INTERPOLATE][GLOBALIDS] = 0; this->CopyAttributeFlags[INTERPOLATE][PEDIGREEIDS] = 0; } //-------------------------------------------------------------------------- // Initialize all of the object's data to nullptr void vtkDataSetAttributes::Initialize() { // // We don't modify ourselves because the "ReleaseData" methods depend upon // no modification when initialized. // // Call superclass' Initialize() this->vtkFieldData::Initialize(); // // Free up any memory // And don't forget to reset the attribute copy flags. int attributeType; for(attributeType=0; attributeTypeAttributeIndices[attributeType] = -1; this->CopyAttributeFlags[COPYTUPLE][attributeType] = 1; this->CopyAttributeFlags[INTERPOLATE][attributeType] = 1; this->CopyAttributeFlags[PASSDATA][attributeType] = 1; } this->CopyAttributeFlags[COPYTUPLE][GLOBALIDS] = 0; this->CopyAttributeFlags[INTERPOLATE][GLOBALIDS] = 0; this->CopyAttributeFlags[INTERPOLATE][PEDIGREEIDS] = 0; } //-------------------------------------------------------------------------- // This method is used to determine which arrays // will be copied to this object vtkFieldData::BasicIterator vtkDataSetAttributes::ComputeRequiredArrays( vtkDataSetAttributes* pd, int ctype) { if ((ctype < COPYTUPLE) || (ctype > PASSDATA)) { vtkErrorMacro("Must call compute required with COPYTUPLE, INTERPOLATE or PASSDATA"); ctype = COPYTUPLE; } // We need to do some juggling to find the number of arrays // which will be passed. // First, find the number of arrays to be copied because they // are in the list of _fields_ to be copied (and the actual data // pointer is non-nullptr). Also, we keep those indices in a list. int* copyFlags = new int[pd->GetNumberOfArrays()]; int index, i, numArrays = 0; for(i=0; iGetNumberOfArrays(); i++) { const char* arrayName = pd->GetArrayName(i); // If there is no blocker for the given array // and both CopyAllOff and CopyOn for that array are not true if ( (this->GetFlag(arrayName) != 0) && !(this->DoCopyAllOff && (this->GetFlag(arrayName) != 1)) && pd->GetAbstractArray(i)) { // Cannot interpolate idtype arrays if (ctype != INTERPOLATE || pd->GetAbstractArray(i)->GetDataType() != VTK_ID_TYPE) { copyFlags[numArrays] = i; numArrays++; } } } // Next, we check the arrays to be copied because they are one of // the _attributes_ to be copied (and the data array in non-nullptr). // We make sure that we don't count anything twice. int alreadyCopied; int attributeType, j; for(attributeType=0; attributeTypeAttributeIndices[attributeType]; int flag = this->GetFlag(pd->GetArrayName(index)); // If this attribute is to be copied if (this->CopyAttributeFlags[ctype][attributeType] && flag) { // Find out if it is also in the list of fields to be copied // Since attributes can only be vtkDataArray, we use GetArray() call. if (pd->GetArray(index)) { alreadyCopied = 0; for(i=0; iGetArray(index)->GetDataType() != VTK_ID_TYPE) { copyFlags[numArrays] = index; numArrays++; } } } } // If it is not to be copied and it is in the list (from the // previous pass), remove it else { for(i=0; i in the list of _fields_ to be copied or // 2> in the list of _attributes_ to be copied. // Note that nullptr data arrays are not copied vtkFieldData::BasicIterator it = this->ComputeRequiredArrays(dsa, PASSDATA); if ( it.GetListSize() > this->NumberOfArrays ) { this->AllocateArrays(it.GetListSize()); } if (it.GetListSize() == 0) { return; } // Since we are replacing, remove old attributes int attributeType; //will change// for(attributeType=0; attributeTypeCopyAttributeFlags[PASSDATA][attributeType]) { this->RemoveArray(this->AttributeIndices[attributeType]); this->AttributeIndices[attributeType] = -1; } } int i, arrayIndex; for(i=it.BeginIndex(); !it.End(); i=it.NextIndex()) { arrayIndex = this->AddArray(dsa->GetAbstractArray(i)); // If necessary, make the array an attribute if ( ((attributeType = dsa->IsArrayAnAttribute(i)) != -1 ) && this->CopyAttributeFlags[PASSDATA][attributeType] ) { this->SetActiveAttribute(arrayIndex, attributeType); } } } else { this->vtkFieldData::PassData(fd); } } //---------------------------------------------------------------------------- namespace { struct CopyStructuredDataWorker { const int *OutExt; const int *InExt; CopyStructuredDataWorker(const int *outExt, const int *inExt) : OutExt(outExt), InExt(inExt) {} template void operator()(Array1T *dest, Array2T *src) { if (vtkStructuredExtent::Smaller(this->OutExt, this->InExt)) { // get outExt relative to the inExt to keep the logic simple. This assumes // that outExt is a subset of the inExt. const int relOutExt[6] = { this->OutExt[0] - this->InExt[0], this->OutExt[1] - this->InExt[0], this->OutExt[2] - this->InExt[2], this->OutExt[3] - this->InExt[2], this->OutExt[4] - this->InExt[4], this->OutExt[5] - this->InExt[4] }; // Give the compiler a hand -- allow optimizations that require both arrays // to have the same stride. VTK_ASSUME(src->GetNumberOfComponents() == dest->GetNumberOfComponents()); vtkDataArrayAccessor d(dest); vtkDataArrayAccessor s(src); const int dims[3] = { this->InExt[1] - this->InExt[0] + 1, this->InExt[3] - this->InExt[2] + 1, this->InExt[5] - this->InExt[4] + 1}; vtkIdType outTupleIdx = 0; for (int outz = relOutExt[4]; outz <= relOutExt[5]; ++outz) { const vtkIdType zfactor = static_cast(outz) * dims[1]; for (int outy = relOutExt[2]; outy <= relOutExt[3]; ++outy) { const vtkIdType yfactor = (zfactor + outy) * dims[0]; for (int outx = relOutExt[0]; outx <= relOutExt[1]; ++outx) { const vtkIdType inTupleIdx = yfactor + outx; for (int comp = 0, max = dest->GetNumberOfComponents(); comp < max; ++comp) { d.Set(outTupleIdx, comp, s.Get(inTupleIdx, comp)); } outTupleIdx++; } } } } else { vtkDataArrayAccessor d(dest); vtkDataArrayAccessor s(src); int writeExt[6]; memcpy(writeExt, this->OutExt, 6*sizeof(int)); vtkStructuredExtent::Clamp(writeExt, this->InExt); vtkIdType inDims[3] = {this->InExt[1] - this->InExt[0] + 1, this->InExt[3] - this->InExt[2] + 1, this->InExt[5] - this->InExt[4] + 1}; vtkIdType outDims[3] = {this->OutExt[1] - this->OutExt[0] + 1, this->OutExt[3] - this->OutExt[2] + 1, this->OutExt[5] - this->OutExt[4] + 1}; for (int idz = writeExt[4]; idz <= writeExt[5]; ++idz) { vtkIdType inTupleId1 = (idz - this->InExt[4]) * inDims[0] * inDims[1]; vtkIdType outTupleId1 = (idz - this->OutExt[4]) * outDims[0] * outDims[1]; for (int idy = writeExt[2]; idy <= writeExt[3]; ++idy) { vtkIdType inTupleId2 = inTupleId1 + (idy - this->InExt[2]) * inDims[0]; vtkIdType outTupleId2 = outTupleId1 + (idy - this->OutExt[2]) * outDims[0]; for (int idx = writeExt[0]; idx <= writeExt[1]; ++idx) { vtkIdType inTupleIdx = inTupleId2 + idx - this->InExt[0]; vtkIdType outTupleIdx = outTupleId2 + idx - this->OutExt[0]; for (int comp = 0, max = dest->GetNumberOfComponents(); comp < max; ++comp) { d.Set(outTupleIdx, comp, s.Get(inTupleIdx, comp)); } } } } } dest->DataChanged(); } }; } // end anon namespace //---------------------------------------------------------------------------- template void vtkDataSetAttributesCopyValues( iterT* destIter, const int* outExt, vtkIdType outIncs[3], iterT* srcIter, const int* inExt, vtkIdType inIncs[3]) { // For vtkDataArray subclasses. int data_type_size = srcIter->GetArray()->GetDataTypeSize(); vtkIdType rowLength = outIncs[1]; unsigned char *inPtr; unsigned char *outPtr; unsigned char *inZPtr; unsigned char *outZPtr; // Get the starting input pointer. inZPtr = static_cast(srcIter->GetArray()->GetVoidPointer(0)); // Shift to the start of the subextent. inZPtr += (outExt[0] - inExt[0]) * inIncs[0] * data_type_size + (outExt[2] - inExt[2]) * inIncs[1] * data_type_size + (outExt[4] - inExt[4]) * inIncs[2] * data_type_size; // Get output pointer. outZPtr = static_cast(destIter->GetArray()->GetVoidPointer(0)); // Loop over z axis. for (int zIdx = outExt[4]; zIdx <= outExt[5]; ++zIdx) { inPtr = inZPtr; outPtr = outZPtr; for (int yIdx = outExt[2]; yIdx <= outExt[3]; ++yIdx) { memcpy(outPtr, inPtr, rowLength * data_type_size); inPtr += inIncs[1] * data_type_size; outPtr += outIncs[1] * data_type_size; } inZPtr += inIncs[2] * data_type_size; outZPtr += outIncs[2] * data_type_size; } } //---------------------------------------------------------------------------- template<> void vtkDataSetAttributesCopyValues( vtkArrayIteratorTemplate* destIter, const int* outExt, vtkIdType outIncs[3], vtkArrayIteratorTemplate* srcIter, const int* inExt, vtkIdType inIncs[3]) { vtkIdType inZIndex = (outExt[0] - inExt[0])*inIncs[0] + (outExt[2] - inExt[2])*inIncs[1] + (outExt[4] - inExt[4])*inIncs[2] ; vtkIdType outZIndex = 0; vtkIdType rowLength = outIncs[1]; for (int zIdx = outExt[4]; zIdx <= outExt[5]; ++zIdx) { vtkIdType inIndex = inZIndex; vtkIdType outIndex = outZIndex; for (int yIdx = outExt[2]; yIdx <= outExt[3]; ++yIdx) { for (int xIdx = 0; xIdx < rowLength; ++xIdx) { destIter->GetValue(outIndex + xIdx) = srcIter->GetValue(inIndex + xIdx); } inIndex += inIncs[1]; outIndex += outIncs[1]; } inZIndex += inIncs[2]; outZIndex += outIncs[2]; } } //---------------------------------------------------------------------------- // This is used in the imaging pipeline for copying arrays. // CopyAllocate needs to be called before this method. void vtkDataSetAttributes::CopyStructuredData(vtkDataSetAttributes *fromPd, const int *inExt, const int *outExt, bool setSize) { int i; for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { vtkAbstractArray *inArray = fromPd->Data[i]; vtkAbstractArray *outArray = this->Data[this->TargetIndices[i]]; vtkIdType inIncs[3]; vtkIdType outIncs[3]; vtkIdType zIdx; // Compute increments inIncs[0] = inArray->GetNumberOfComponents(); inIncs[1] = inIncs[0] * (inExt[1]-inExt[0]+1); inIncs[2] = inIncs[1] * (inExt[3]-inExt[2]+1); outIncs[0] = inIncs[0]; outIncs[1] = outIncs[0] * (outExt[1]-outExt[0]+1); outIncs[2] = outIncs[1] * (outExt[3]-outExt[2]+1); // Make sure the input extents match the actual array lengths. zIdx = inIncs[2]/inIncs[0]*(inExt[5]-inExt[4]+1); if (inArray->GetNumberOfTuples() != zIdx) { vtkErrorMacro("Input extent (" << inExt[0] << ", " << inExt[1] << ", " << inExt[2] << ", " << inExt[3] << ", " << inExt[4] << ", " << inExt[5] << ") does not match array length: " << zIdx); // Skip copying this array. continue; } // Make sure the output extents match the actual array lengths. zIdx = outIncs[2]/outIncs[0]*(outExt[5]-outExt[4]+1); if (outArray->GetNumberOfTuples() != zIdx && setSize) { // The "CopyAllocate" method only sets the size, not the number of tuples. outArray->SetNumberOfTuples(zIdx); } // We get very little performance improvement from this, but we'll leave the // legacy code around until we've done through benchmarking. vtkDataArray *inDA = vtkArrayDownCast(inArray); vtkDataArray *outDA = vtkArrayDownCast(outArray); if (!inDA || !outDA) // String array, etc { vtkArrayIterator* srcIter = inArray->NewIterator(); vtkArrayIterator* destIter = outArray->NewIterator(); switch (inArray->GetDataType()) { vtkArrayIteratorTemplateMacro( vtkDataSetAttributesCopyValues( static_cast(destIter), outExt, outIncs, static_cast(srcIter), inExt, inIncs)); } srcIter->Delete(); destIter->Delete(); } else { CopyStructuredDataWorker worker(outExt, inExt); if (!vtkArrayDispatch::Dispatch2SameValueType::Execute(outDA, inDA, worker)) { // Fallback to vtkDataArray API (e.g. vtkBitArray): worker(outDA, inDA); } } } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetupForCopy(vtkDataSetAttributes* pd) { this->InternalCopyAllocate(pd, COPYTUPLE, 0, 0, false, false); } //-------------------------------------------------------------------------- // Allocates point data for point-by-point (or cell-by-cell) copy operation. // If sze=0, then use the input DataSetAttributes to create (i.e., find // initial size of) new objects; otherwise use the sze variable. void vtkDataSetAttributes::InternalCopyAllocate(vtkDataSetAttributes* pd, int ctype, vtkIdType sze, vtkIdType ext, int shallowCopyArrays, bool createNewArrays) { vtkAbstractArray* newAA; int i; // Create various point data depending upon input // if ( !pd ) { return; } if ((ctype < COPYTUPLE) || (ctype > PASSDATA)) { return; } this->RequiredArrays = this->ComputeRequiredArrays(pd, ctype); if (this->RequiredArrays.GetListSize() == 0) { return; } delete[] this->TargetIndices; this->TargetIndices = new int[pd->GetNumberOfArrays()]; for(i=0; iGetNumberOfArrays(); i++) { this->TargetIndices[i] = -1; } vtkAbstractArray* aa=nullptr; // If we are not copying on self if ( (pd != this) && createNewArrays ) { int attributeType; for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { // Create all required arrays aa = pd->GetAbstractArray(i); if (shallowCopyArrays) { newAA = aa; } else { newAA = aa->NewInstance(); newAA->SetNumberOfComponents(aa->GetNumberOfComponents()); newAA->CopyComponentNames( aa ); newAA->SetName(aa->GetName()); if (aa->HasInformation()) { newAA->CopyInformation(aa->GetInformation(),/*deep=*/1); } if ( sze > 0 ) { newAA->Allocate(sze*aa->GetNumberOfComponents(),ext); } else { newAA->Allocate(aa->GetNumberOfTuples()); } vtkDataArray* newDA = vtkArrayDownCast(newAA); if (newDA) { vtkDataArray* da = vtkArrayDownCast(aa); newDA->SetLookupTable(da->GetLookupTable()); } } this->TargetIndices[i] = this->AddArray(newAA); // If necessary, make the array an attribute if ( ((attributeType = pd->IsArrayAnAttribute(i)) != -1 ) && this->CopyAttributeFlags[ctype][attributeType] ) { this->CopyAttributeFlags[ctype][attributeType] = pd->CopyAttributeFlags[ctype][attributeType]; this->SetActiveAttribute(this->TargetIndices[i], attributeType); } if (!shallowCopyArrays) { newAA->Delete(); } } } else if (pd == this) { // If copying on self, resize the arrays and initialize // TargetIndices for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { aa = pd->GetAbstractArray(i); aa->Resize(sze); this->TargetIndices[i] = i; } } else { // All we are asked to do is create a mapping. // Here we assume that arrays are the same and ordered // the same way. for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { this->TargetIndices[i] = i; } } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::RemoveArray(int index) { if ( (index<0) || (index>=this->NumberOfActiveArrays)) { return; } this->Superclass::RemoveArray(index); int attributeType; for(attributeType = 0; attributeType < NUM_ATTRIBUTES; attributeType++) { if (this->AttributeIndices[attributeType] == index) { this->AttributeIndices[attributeType] = -1; } else if (this->AttributeIndices[attributeType] > index) { this->AttributeIndices[attributeType]--; } } } //-------------------------------------------------------------------------- // Copy the attribute data from one id to another. Make sure CopyAllocate() has // been invoked before using this method. void vtkDataSetAttributes::CopyData(vtkDataSetAttributes* fromPd, vtkIdType fromId, vtkIdType toId) { int i; for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { this->CopyTuple(fromPd->Data[i], this->Data[this->TargetIndices[i]], fromId, toId); } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::CopyData(vtkDataSetAttributes *fromPd, vtkIdList *fromIds, vtkIdList *toIds) { int i; for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { this->CopyTuples(fromPd->Data[i], this->Data[this->TargetIndices[i]], fromIds, toIds); } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::CopyData(vtkDataSetAttributes *fromPd, vtkIdType dstStart, vtkIdType n, vtkIdType srcStart) { for (int i = this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i = this->RequiredArrays.NextIndex()) { this->CopyTuples(fromPd->Data[i], this->Data[this->TargetIndices[i]], dstStart, n, srcStart); } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::CopyAllocate(vtkDataSetAttributes* pd, vtkIdType sze, vtkIdType ext, int shallowCopyArrays) { this->InternalCopyAllocate(pd, COPYTUPLE, sze, ext, shallowCopyArrays); } // Initialize point interpolation method. void vtkDataSetAttributes::InterpolateAllocate(vtkDataSetAttributes* pd, vtkIdType sze, vtkIdType ext, int shallowCopyArrays) { this->InternalCopyAllocate(pd, INTERPOLATE, sze, ext, shallowCopyArrays); } //-------------------------------------------------------------------------- // Interpolate data from points and interpolation weights. Make sure that the // method InterpolateAllocate() has been invoked before using this method. void vtkDataSetAttributes::InterpolatePoint(vtkDataSetAttributes *fromPd, vtkIdType toId, vtkIdList *ptIds, double *weights) { for (int i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { vtkAbstractArray* fromArray = fromPd->Data[i]; vtkAbstractArray* toArray = this->Data[this->TargetIndices[i]]; //check if the destination array needs nearest neighbor interpolation int attributeIndex = this->IsArrayAnAttribute(this->TargetIndices[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 maxWeight) { maxWeight = weights[j]; maxId = ptIds->GetId(j); } } toArray->InsertTuple(toId, maxId, fromArray); } else { toArray->InterpolateTuple(toId, ptIds, fromArray, weights); } } } //-------------------------------------------------------------------------- // Interpolate data from the two points p1,p2 (forming an edge) and an // interpolation factor, t, along the edge. The weight ranges from (0,1), // with t=0 located at p1. Make sure that the method InterpolateAllocate() // has been invoked before using this method. void vtkDataSetAttributes::InterpolateEdge(vtkDataSetAttributes *fromPd, vtkIdType toId, vtkIdType p1, vtkIdType p2, double t) { for (int i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); i=this->RequiredArrays.NextIndex()) { vtkAbstractArray* fromArray = fromPd->Data[i]; vtkAbstractArray* toArray = this->Data[this->TargetIndices[i]]; //check if the destination array needs nearest neighbor interpolation int attributeIndex = this->IsArrayAnAttribute(this->TargetIndices[i]); if (attributeIndex != -1 && this->CopyAttributeFlags[INTERPOLATE][attributeIndex]==2) { if (t < .5) { toArray->InsertTuple(toId, p1, fromArray); } else { toArray->InsertTuple(toId, p2, fromArray); } } else { toArray->InterpolateTuple(toId, p1, fromArray, p2, fromArray, t); } } } //-------------------------------------------------------------------------- // Interpolate data from the two points p1,p2 (forming an edge) and an // interpolation factor, t, along the edge. The weight ranges from (0,1), // with t=0 located at p1. Make sure that the method InterpolateAllocate() // has been invoked before using this method. void vtkDataSetAttributes::InterpolateTime(vtkDataSetAttributes *from1, vtkDataSetAttributes *from2, vtkIdType id, double t) { for (int attributeType=0; attributeTypeCopyAttributeFlags[INTERPOLATE][attributeType]) { if (from1->GetAttribute(attributeType) && from2->GetAttribute(attributeType)) { vtkAbstractArray* toArray = this->GetAttribute(attributeType); //check if the destination array needs nearest neighbor interpolation if (this->CopyAttributeFlags[INTERPOLATE][attributeType]==2) { if (t < .5) { toArray->InsertTuple(id, id, from1->GetAttribute(attributeType)); } else { toArray->InsertTuple(id, id, from2->GetAttribute(attributeType)); } } else { toArray->InterpolateTuple(id, id, from1->GetAttribute(attributeType), id, from2->GetAttribute(attributeType), t); } } } } } //-------------------------------------------------------------------------- // Copy a tuple of data from one data array to another. This method (and // following ones) assume that the fromData and toData objects are of the // same type, and have the same number of components. This is true if you // invoke CopyAllocate() or InterpolateAllocate(). void vtkDataSetAttributes::CopyTuple(vtkAbstractArray *fromData, vtkAbstractArray *toData, vtkIdType fromId, vtkIdType toId) { toData->InsertTuple(toId, fromId, fromData); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::CopyTuples(vtkAbstractArray *fromData, vtkAbstractArray *toData, vtkIdList *fromIds, vtkIdList *toIds) { toData->InsertTuples(toIds, fromIds, fromData); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::CopyTuples(vtkAbstractArray *fromData, vtkAbstractArray *toData, vtkIdType dstStart, vtkIdType n, vtkIdType srcStart) { toData->InsertTuples(dstStart, n, srcStart, fromData); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetScalars(vtkDataArray* da) { return this->SetAttribute(da, SCALARS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveScalars(const char* name) { return this->SetActiveAttribute(name, SCALARS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveAttribute(const char* name, int attributeType) { int index; this->GetAbstractArray(name, index); return this->SetActiveAttribute(index, attributeType); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetScalars() { return this->GetAttribute(SCALARS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetVectors(vtkDataArray* da) { return this->SetAttribute(da, VECTORS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveVectors(const char* name) { return this->SetActiveAttribute(name, VECTORS); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetVectors() { return this->GetAttribute(VECTORS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetNormals(vtkDataArray* da) { return this->SetAttribute(da, NORMALS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveNormals(const char* name) { return this->SetActiveAttribute(name, NORMALS); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetNormals() { return this->GetAttribute(NORMALS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetTCoords(vtkDataArray* da) { return this->SetAttribute(da, TCOORDS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveTCoords(const char* name) { return this->SetActiveAttribute(name, TCOORDS); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetTCoords() { return this->GetAttribute(TCOORDS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetTensors(vtkDataArray* da) { return this->SetAttribute(da, TENSORS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveTensors(const char* name) { return this->SetActiveAttribute(name, TENSORS); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetTensors() { return this->GetAttribute(TENSORS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetGlobalIds(vtkDataArray* da) { return this->SetAttribute(da, GLOBALIDS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveGlobalIds(const char* name) { return this->SetActiveAttribute(name, GLOBALIDS); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetGlobalIds() { return this->GetAttribute(GLOBALIDS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetPedigreeIds(vtkAbstractArray* aa) { return this->SetAttribute(aa, PEDIGREEIDS); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActivePedigreeIds(const char* name) { return this->SetActiveAttribute(name, PEDIGREEIDS); } //-------------------------------------------------------------------------- vtkAbstractArray* vtkDataSetAttributes::GetPedigreeIds() { return this->GetAbstractAttribute(PEDIGREEIDS); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetScalars(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetScalars(); } return this->GetArray(name); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetVectors(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetVectors(); } return this->GetArray(name); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetNormals(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetNormals(); } return this->GetArray(name); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetTCoords(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetTCoords(); } return this->GetArray(name); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetTensors(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetTensors(); } return this->GetArray(name); } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetGlobalIds(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetGlobalIds(); } return this->GetArray(name); } //-------------------------------------------------------------------------- vtkAbstractArray* vtkDataSetAttributes::GetPedigreeIds(const char* name) { if (name == nullptr || name[0] == '\0') { return this->GetPedigreeIds(); } return this->GetAbstractArray(name); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::SetActiveAttribute(int index, int attributeType) { if ( (index >= 0) && (index < this->GetNumberOfArrays())) { if (attributeType != PEDIGREEIDS) { vtkDataArray* darray = vtkArrayDownCast( this->Data[index]); if (!darray) { vtkWarningMacro("Can not set attribute " << vtkDataSetAttributes::AttributeNames[attributeType] << ". Only vtkDataArray subclasses can be set as active attributes."); return -1; } if (!this->CheckNumberOfComponents(darray, attributeType)) { vtkWarningMacro("Can not set attribute " << vtkDataSetAttributes::AttributeNames[attributeType] << ". Incorrect number of components."); return -1; } } this->AttributeIndices[attributeType] = index; this->Modified(); return index; } else if (index == -1) { this->AttributeIndices[attributeType] = index; this->Modified(); } return -1; } //-------------------------------------------------------------------------- const int vtkDataSetAttributes ::NumberOfAttributeComponents[vtkDataSetAttributes::NUM_ATTRIBUTES] = { 0, 3, 3, 3, 9, 1, 1, 1}; //-------------------------------------------------------------------------- // Scalars set to NOLIMIT const int vtkDataSetAttributes ::AttributeLimits[vtkDataSetAttributes::NUM_ATTRIBUTES] = { NOLIMIT, EXACT, EXACT, MAX, EXACT, EXACT, EXACT, EXACT}; //-------------------------------------------------------------------------- int vtkDataSetAttributes::CheckNumberOfComponents(vtkAbstractArray* aa, int attributeType) { int numComp = aa->GetNumberOfComponents(); if ( vtkDataSetAttributes::AttributeLimits[attributeType] == MAX ) { if ( numComp > vtkDataSetAttributes::NumberOfAttributeComponents[attributeType] ) { return 0; } else { return 1; } } else if ( vtkDataSetAttributes::AttributeLimits[attributeType] == EXACT ) { if (numComp == vtkDataSetAttributes::NumberOfAttributeComponents[attributeType] || (numComp == 6 && attributeType == TENSORS)) // TENSORS6 support { return 1; } else { return 0; } } else if ( vtkDataSetAttributes::AttributeLimits[attributeType] == NOLIMIT ) { return 1; } else { return 0; } } //-------------------------------------------------------------------------- vtkDataArray* vtkDataSetAttributes::GetAttribute(int attributeType) { int index = this->AttributeIndices[attributeType]; if (index == -1) { return nullptr; } else { return vtkArrayDownCast(this->Data[index]); } } //-------------------------------------------------------------------------- vtkAbstractArray* vtkDataSetAttributes::GetAbstractAttribute(int attributeType) { int index = this->AttributeIndices[attributeType]; if (index == -1) { return nullptr; } else { return this->Data[index]; } } //-------------------------------------------------------------------------- // This method lets the user add an array and make it the current // scalars, vectors etc... (this is determined by the attribute type // which is an enum defined vtkDataSetAttributes) int vtkDataSetAttributes::SetAttribute(vtkAbstractArray* aa, int attributeType) { if (aa && attributeType != PEDIGREEIDS && !vtkArrayDownCast(aa)) { vtkWarningMacro("Can not set attribute " << vtkDataSetAttributes::AttributeNames[attributeType] << ". This attribute must be a subclass of vtkDataArray."); return -1; } if (aa && !this->CheckNumberOfComponents(aa, attributeType)) { vtkWarningMacro("Can not set attribute " << vtkDataSetAttributes::AttributeNames[attributeType] << ". Incorrect number of components."); return -1; } int currentAttribute = this->AttributeIndices[attributeType]; // If there is an existing attribute, replace it if ( (currentAttribute >= 0) && (currentAttribute < this->GetNumberOfArrays()) ) { if (this->GetAbstractArray(currentAttribute) == aa) { return currentAttribute; } this->RemoveArray(currentAttribute); } if (aa) { // Add the array currentAttribute = this->AddArray(aa); this->AttributeIndices[attributeType] = currentAttribute; } else { this->AttributeIndices[attributeType] = -1; //attribute of this type doesn't exist } this->Modified(); return this->AttributeIndices[attributeType]; } //-------------------------------------------------------------------------- void vtkDataSetAttributes::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); // Print the copy flags int i; os << indent << "Copy Tuple Flags: ( "; for (i=0; iCopyAttributeFlags[COPYTUPLE][i] << " "; } os << ")" << endl; os << indent << "Interpolate Flags: ( "; for (i=0; iCopyAttributeFlags[INTERPOLATE][i] << " "; } os << ")" << endl; os << indent << "Pass Through Flags: ( "; for (i=0; iCopyAttributeFlags[PASSDATA][i] << " "; } os << ")" << endl; // Now print the various attributes vtkAbstractArray* aa; int attributeType; for (attributeType=0; attributeTypeGetAbstractAttribute(attributeType)) ) { os << endl; aa->PrintSelf(os, indent.GetNextIndent()); } else { os << "(none)" << endl; } } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::GetAttributeIndices(int* indexArray) { int i; for(i=0; iAttributeIndices[i]; } } //-------------------------------------------------------------------------- int vtkDataSetAttributes::IsArrayAnAttribute(int idx) { int i; for (i=0; iAttributeIndices[i] ) { return i; } } return -1; } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyAttribute (int index, int value, int ctype) { if (index < 0 || ctype < 0 || index >= vtkDataSetAttributes::NUM_ATTRIBUTES || ctype > vtkDataSetAttributes::ALLCOPY) { vtkErrorMacro("Cannot set copy attribute for attribute type " << index << " and copy operation " << ctype << ". These values are out of range."); return; } if (ctype == vtkDataSetAttributes::ALLCOPY) { int t; for (t = COPYTUPLE; t < vtkDataSetAttributes::ALLCOPY; t++) { if (this->CopyAttributeFlags[t][ index ] != value) { this->CopyAttributeFlags[t][ index ] = value; this->Modified(); } } } else { if (this->CopyAttributeFlags[ctype][ index ] != value) { this->CopyAttributeFlags[ctype][ index ] = value; this->Modified(); } } } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyAttribute (int index, int ctype) { if (index < 0 || ctype < 0 || index >= vtkDataSetAttributes::NUM_ATTRIBUTES || ctype > vtkDataSetAttributes::ALLCOPY) { vtkWarningMacro("Cannot get copy attribute for attribute type " << index << " and copy operation " << ctype << ". These values are out of range."); return -1; } else if (ctype == vtkDataSetAttributes::ALLCOPY) { return (this->CopyAttributeFlags[COPYTUPLE][index] && this->CopyAttributeFlags[INTERPOLATE][index] && this->CopyAttributeFlags[PASSDATA][index]); } else { return this->CopyAttributeFlags[ctype][index]; } } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyScalars(int i, int ctype) { this->SetCopyAttribute(SCALARS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyScalars(int ctype) { return this->GetCopyAttribute(SCALARS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyVectors(int i, int ctype) { this->SetCopyAttribute(VECTORS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyVectors(int ctype) { return this->GetCopyAttribute(VECTORS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyNormals(int i, int ctype) { this->SetCopyAttribute(NORMALS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyNormals(int ctype) { return this->GetCopyAttribute(NORMALS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyTCoords(int i, int ctype) { this->SetCopyAttribute(TCOORDS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyTCoords(int ctype) { return this->GetCopyAttribute(TCOORDS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyTensors(int i, int ctype) { this->SetCopyAttribute(TENSORS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyTensors(int ctype) { return this->GetCopyAttribute(TENSORS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyGlobalIds(int i, int ctype) { this->SetCopyAttribute(GLOBALIDS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyGlobalIds(int ctype) { return this->GetCopyAttribute(GLOBALIDS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::SetCopyPedigreeIds(int i, int ctype) { this->SetCopyAttribute(PEDIGREEIDS, i, ctype); } //-------------------------------------------------------------------------- int vtkDataSetAttributes::GetCopyPedigreeIds(int ctype) { return this->GetCopyAttribute(PEDIGREEIDS, ctype); } //-------------------------------------------------------------------------- void vtkDataSetAttributes::CopyAllocate( vtkDataSetAttributes::FieldList& list, vtkIdType sze, vtkIdType ext) { this->InternalCopyAllocate(list, COPYTUPLE, sze, ext); } //-------------------------------------------------------------------------- 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(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 } } //-------------------------------------------------------------------------- // Description: // A special form of CopyData() to be used with FieldLists. Use it when you are // copying data from a set of vtkDataSetAttributes. Make sure that you have // called the special form of CopyAllocate that accepts FieldLists. 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); } } } //-------------------------------------------------------------------------- // Description: // A special form of CopyData() to be used with FieldLists. Use it when you are // copying data from a set of vtkDataSetAttributes. Make sure that you have // called the special form of CopyAllocate that accepts FieldLists. void vtkDataSetAttributes::CopyData(vtkDataSetAttributes::FieldList& list, vtkDataSetAttributes* fromDSA, 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); } } } //-------------------------------------------------------------------------- // Interpolate data from points and interpolation weights. Make sure that the // method InterpolateAllocate() has been invoked before using this method. void vtkDataSetAttributes::InterpolatePoint( vtkDataSetAttributes::FieldList& list, vtkDataSetAttributes *fromPd, int idx, 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 maxWeight) { maxWeight = weights[j]; maxId = ptIds->GetId(j); } } toArray->InsertTuple(toId, maxId, fromArray); } else { toArray->InterpolateTuple(toId, ptIds, fromArray, weights); } } } } //-------------------------------------------------------------------------- const char* vtkDataSetAttributes::GetAttributeTypeAsString(int attributeType) { if (attributeType < 0 || attributeType >= NUM_ATTRIBUTES) { vtkGenericWarningMacro("Bad attribute type: " << attributeType << "."); return nullptr; } return vtkDataSetAttributes::AttributeNames[attributeType]; } //-------------------------------------------------------------------------- const char* vtkDataSetAttributes::GetLongAttributeTypeAsString(int attributeType) { if (attributeType < 0 || attributeType >= NUM_ATTRIBUTES) { vtkGenericWarningMacro("Bad attribute type: " << attributeType << "."); return nullptr; } 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; iDSAIndices[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 the total number of fields may change, // so we have to be careful with that. std::vector 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 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 dsaPendingIndices; for (size_t cc=0; cc < dsaMarkedArrays.size(); cc++) { if (dsaMarkedArrays[cc] == false) { dsaPendingIndices.push_back(static_cast(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(dsaPendingIndices.size())); dsaIndices.resize(new_size, -1); for (size_t cc=0; cc < dsaPendingIndices.size(); cc++) { this->FieldIndices[old_size+cc] = static_cast((old_size+cc) - NUM_ATTRIBUTES); this->SetField(static_cast(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; iNumberOfFields; i++) { delete [] this->Fields[i]; this->Fields[i] = nullptr; } } if ( this->DSAIndices ) { for (i=0; iNumberOfDSAIndices; 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; iNumberOfFields; 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(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(false, vtkStdString())); name = nullptr; for ( vtkIdType i=0; i < numberOfComponents; ++i) { name = aa->GetComponentName(i); if ( name ) { this->FieldComponentsNames[index]->at(i) = std::pair(true, name); name = nullptr; } } } // Store the components this->FieldComponents[index] = numberOfComponents; // Store the lookup table this->LUT[index]=nullptr; if (vtkArrayDownCast(aa)) { this->LUT[index]= vtkArrayDownCast(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; iNumberOfFields; ++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; } }