Commit 0e88f8c9 authored by David C. Lonie's avatar David C. Lonie

Refactor vtkDataArrayIteratorMacro usages to use vtkArrayDispatch.

Also remove vtkGenericDataArrayMacros.
parent 62e146bf
Pipeline #8773 passed with stage
This diff is collapsed.
......@@ -292,7 +292,6 @@ set(${vtk-module}_HDRS
vtkDataArrayIteratorMacro.h
vtkGenericDataArray.h
vtkGenericDataArrayLookupHelper.h
vtkGenericDataArrayMacros.h
vtkGenericDataArray.txx
vtkIOStream.h
vtkIOStreamFwd.h
......
......@@ -17,6 +17,7 @@
// Helpers:
#include "vtkAoSDataArrayTemplate.h"
#include "vtkArrayDispatch.h"
#include "vtkIdList.h"
#include "vtkMath.h"
#include "vtkNew.h"
......@@ -1477,9 +1478,6 @@ int Test_int_IsNumeric()
// vtkArrayIterator* NewIterator()
// Just test that the returned iterator is non-NULL and the data types match.
// The base vtkArrayIterator API doesn't really have much utility.
// TODO should we allow this to return NULL and deprecate? This mechanism is
// an inferior version of vtkGenericDataArrayMacro.
template <typename ScalarT, typename ArrayT>
int Test_vtkArrayIteratorPtr_NewIterator()
{
......@@ -2924,11 +2922,31 @@ int Test_GetRange_all_overloads()
//------------------------------------------------------------------------------
//-----------Unit Test Function Caller------------------------------------------
//------------------------------------------------------------------------------
struct CanDispatch // Dummy for testing if we can dispatch an array type.
{
template <typename ArrayT> void operator()(ArrayT *) {}
};
template <typename ScalarT, typename ArrayT>
int ExerciseDataArray()
{
int errors = 0;
// Check to see if ArrayT is supported by the dispatch mechanism (this is
// controlled by the VTK_DISPATCH_* CMake settings). If not, skip testing it
// as many internal methods in vtkDataArray use it.
vtkNew<ArrayT> testArray;
CanDispatch testWorker;
if (!vtkArrayDispatch::Dispatch::Execute(testArray.GetPointer(), testWorker))
{
std::cerr << "Skipping tests for '" << typeid(ArrayT).name()
<< "' with data type '" << vtkTypeTraits<ScalarT>::Name()
<< "', as dispatch is disabled for this array. Modify the "
"VTK_DISPATCH_* CMake settings to enable tests for this "
"class." << std::endl;
return errors;
}
// vtkAbstractArray API:
errors += Test_int_Allocate_numValues_ext<ScalarT, ArrayT>();
errors += Test_void_Initialize<ScalarT, ArrayT>();
......@@ -3041,6 +3059,17 @@ int ExerciseGetRange()
{
int errors = 0;
// Check to see if ArrayT is supported by the dispatch mechanism (this is
// controlled by the VTK_DISPATCH_* CMake settings). If not, skip testing it
// as many internal methods in vtkDataArray use it.
vtkNew<ArrayT> testArray;
CanDispatch testWorker;
if (!vtkArrayDispatch::Dispatch::Execute(testArray.GetPointer(), testWorker))
{
// A warning is printed when this test fails in ExerciseDataArray.
return errors;
}
errors += Test_GetRange_all_overloads<ScalarT, ArrayT>();
return errors;
......
......@@ -14,6 +14,23 @@
#include "vtkSoADataArrayTemplate.h"
#include "vtkAoSDataArrayTemplate.h"
#include "vtkArrayDispatch.h"
struct TestWorker
{
template <typename Array1T>
void operator()(Array1T *array)
{
for (vtkIdType tupleIdx = 0, max = array->GetNumberOfTuples();
tupleIdx < max;
++tupleIdx)
{
array->SetComponentValue(tupleIdx, 0, 1);
array->SetComponentValue(tupleIdx, 1, 2);
array->SetComponentValue(tupleIdx, 2, 3);
}
}
};
template <class T>
void Test()
......@@ -21,16 +38,18 @@ void Test()
T* array = T::New();
array->SetNumberOfComponents(3);
array->SetNumberOfTuples(100);
vtkGenericDataArrayMacro(array,
for (vtkIdType tupleIdx=0, max=ARRAY->GetNumberOfTuples(); tupleIdx < max;
++tupleIdx)
TestWorker worker;
if (!vtkArrayDispatch::Dispatch::Execute(array, worker))
{
ARRAY->SetComponentValue(tupleIdx, 0, 1);
ARRAY->SetComponentValue(tupleIdx, 1, 2);
ARRAY->SetComponentValue(tupleIdx, 2, 3);
std::cerr << "Dispatch failed! Array: " << array->GetClassName()
<< std::endl;
}
);
array->Print(cout);
else
{
array->Print(cout);
}
array->Delete();
}
......
......@@ -17,6 +17,7 @@
// Helpers:
#include "vtkAoSDataArrayTemplate.h"
#include "vtkArrayDispatch.h"
#include "vtkNew.h"
#include "vtkSmartPointer.h"
#include "vtkTypeTraits.h"
......@@ -863,11 +864,31 @@ int Test_GetValueRange_all_overloads()
//------------------------------------------------------------------------------
//-----------Unit Test Function Caller------------------------------------------
//------------------------------------------------------------------------------
struct CanDispatch // Dummy for testing if we can dispatch an array type.
{
template <typename ArrayT> void operator()(ArrayT *) {}
};
template <typename ScalarT, typename ArrayT>
int ExerciseGenericDataArray()
{
int errors = 0;
// Check to see if ArrayT is supported by the dispatch mechanism (this is
// controlled by the VTK_DISPATCH_* CMake settings). If not, skip testing it
// as many internal methods in vtkDataArray use it.
vtkNew<ArrayT> testArray;
CanDispatch testWorker;
if (!vtkArrayDispatch::Dispatch::Execute(testArray.GetPointer(), testWorker))
{
std::cerr << "Skipping tests for '" << typeid(ArrayT).name()
<< "' with data type '" << vtkTypeTraits<ScalarT>::Name()
<< "', as dispatch is disabled for this array. Modify the "
"VTK_DISPATCH_* CMake settings to enable tests for this "
"class." << std::endl;
return errors;
}
errors += Test_constRefT_GetValue_valueIdx_const<ScalarT, ArrayT>();
errors += Test_void_GetTupleValue_tupleIdx_tuple<ScalarT, ArrayT>();
errors += Test_constRefT_GetComponentValue_tupleIdx_comp_const<ScalarT, ArrayT>();
......
This diff is collapsed.
......@@ -112,6 +112,7 @@ public:
// interpolation weights.
// This method assumes that the two arrays are of the same type
// and strcuture.
// This array will be resized to contain tuple i, if needed.
virtual void InterpolateTuple(vtkIdType i, vtkIdList *ptIndices,
vtkAbstractArray* source, double* weights);
......@@ -122,6 +123,7 @@ public:
// with t=0 located at p1. This method assumes that the three arrays are of
// the same type. p1 is value at index id1 in source1, while, p2 is
// value at index id2 in source2.
// This array will be resized to contain tuple i, if needed.
virtual void InterpolateTuple(vtkIdType i,
vtkIdType id1, vtkAbstractArray* source1,
vtkIdType id2, vtkAbstractArray* source2, double t);
......
......@@ -16,6 +16,11 @@
// vtkDataArray data when the array implementation and type are unknown.
//
// .SECTION Description
//
// NOTE: This macro is deprecated and should not be used any longer. Use
// vtkArrayDispatch and the vtkGenericDataArray API instead of
// vtkDataArrayIteratorMacro and vtkTypedDataArrayIterator.
//
// See vtkTemplateMacro.
// This macro is similar, but defines several additional typedefs and variables
// for safely iterating through data in a vtkAbstractArray container:
......
......@@ -63,9 +63,8 @@ using std::max;
template <class ValueType, int NumComps, int RangeSize>
struct ComputeScalarRange
{
template<class InputIteratorType>
bool operator()(InputIteratorType begin, InputIteratorType end,
double* ranges)
template<class ArrayT>
bool operator()(ArrayT *array, double *ranges)
{
ValueType tempRange[RangeSize];
for(int i = 0, j = 0; i < NumComps; ++i, j+=2)
......@@ -75,12 +74,15 @@ struct ComputeScalarRange
}
//compute the range for each component of the data array at the same time
for(InputIteratorType value = begin; value != end; value+=NumComps)
const int numTuples = array->GetNumberOfTuples();
for(vtkIdType tupleIdx = 0; tupleIdx < numTuples; ++tupleIdx)
{
for(int i = 0, j = 0; i < NumComps; ++i, j+=2)
for(int compIdx = 0, j = 0; compIdx < NumComps; ++compIdx, j+=2)
{
tempRange[j] = detail::min(tempRange[j], value[i]);
tempRange[j+1] = detail::max(tempRange[j+1], value[i]);
tempRange[j] = detail::min(tempRange[j],
array->GetComponentValue(tupleIdx, compIdx));
tempRange[j+1] = detail::max(tempRange[j+1],
array->GetComponentValue(tupleIdx, compIdx));
}
}
......@@ -95,10 +97,13 @@ struct ComputeScalarRange
};
//----------------------------------------------------------------------------
template <class ValueType, class InputIteratorType>
bool DoComputeScalarRange(InputIteratorType begin, InputIteratorType end,
const int numComp, double* ranges)
template <typename ArrayT>
bool DoComputeScalarRange(ArrayT *array, double *ranges)
{
typedef typename ArrayT::ValueType ValueType;
const int numTuples = array->GetNumberOfTuples();
const int numComp = array->GetNumberOfComponents();
//setup the initial ranges to be the max,min for double
for (int i = 0, j = 0; i < numComp; ++i, j+=2)
{
......@@ -107,52 +112,48 @@ bool DoComputeScalarRange(InputIteratorType begin, InputIteratorType end,
}
//do this after we make sure range is max to min
if (begin == end)
if (numTuples == 0)
{
return false;
}
//verify that length of the array is divisible by the number of components
//this will make sure we don't walk off the end
assert((end-begin) % numComp == 0);
//Special case for single value scalar range. This is done to help the
//compiler detect it can perform loop optimizations.
if (numComp == 1)
{
return ComputeScalarRange<ValueType,1,2>()(begin, end, ranges);
return ComputeScalarRange<ValueType,1,2>()(array, ranges);
}
else if (numComp == 2)
{
return ComputeScalarRange<ValueType,2,4>()(begin, end, ranges);
return ComputeScalarRange<ValueType,2,4>()(array, ranges);
}
else if (numComp == 3)
{
return ComputeScalarRange<ValueType,3,6>()(begin, end, ranges);
return ComputeScalarRange<ValueType,3,6>()(array, ranges);
}
else if (numComp == 4)
{
return ComputeScalarRange<ValueType,4,8>()(begin, end, ranges);
return ComputeScalarRange<ValueType,4,8>()(array, ranges);
}
else if (numComp == 5)
{
return ComputeScalarRange<ValueType,5,10>()(begin, end, ranges);
return ComputeScalarRange<ValueType,5,10>()(array, ranges);
}
else if (numComp == 6)
{
return ComputeScalarRange<ValueType,6,12>()(begin, end, ranges);
return ComputeScalarRange<ValueType,6,12>()(array, ranges);
}
else if (numComp == 7)
{
return ComputeScalarRange<ValueType,7,14>()(begin, end, ranges);
return ComputeScalarRange<ValueType,7,14>()(array, ranges);
}
else if (numComp == 8)
{
return ComputeScalarRange<ValueType,8,16>()(begin, end, ranges);
return ComputeScalarRange<ValueType,8,16>()(array, ranges);
}
else if (numComp == 9)
{
return ComputeScalarRange<ValueType,9,18>()(begin, end, ranges);
return ComputeScalarRange<ValueType,9,18>()(array, ranges);
}
else
{
......@@ -165,12 +166,14 @@ bool DoComputeScalarRange(InputIteratorType begin, InputIteratorType end,
}
//compute the range for each component of the data array at the same time
for (InputIteratorType value = begin; value != end; value+=numComp)
for (vtkIdType tupleIdx; tupleIdx < numTuples; ++tupleIdx)
{
for(int i = 0, j = 0; i < numComp; ++i, j+=2)
for(int compIdx = 0, j = 0; compIdx < numComp; ++compIdx, j+=2)
{
tempRange[j] = detail::min(tempRange[j], value[i]);
tempRange[j+1] = detail::max(tempRange[j+1], value[i]);
tempRange[j] = detail::min(tempRange[j],
array->GetComponentValue(tupleIdx, compIdx));
tempRange[j+1] = detail::max(tempRange[j+1],
array->GetComponentValue(tupleIdx, compIdx));
}
}
......@@ -189,30 +192,28 @@ bool DoComputeScalarRange(InputIteratorType begin, InputIteratorType end,
}
//----------------------------------------------------------------------------
template <class ValueType, class InputIteratorType>
bool DoComputeVectorRange(InputIteratorType begin, InputIteratorType end,
int numComp, double range[2])
template <typename ArrayT>
bool DoComputeVectorRange(ArrayT *array, double range[2])
{
const int numTuples = array->GetNumberOfTuples();
const int numComps = array->GetNumberOfComponents();
range[0] = vtkTypeTraits<double>::Max();
range[1] = vtkTypeTraits<double>::Min();
//do this after we make sure range is max to min
if (begin == end)
if (numTuples == 0)
{
return false;
}
//verify that length of the array is divisible by the number of components
//this will make sure we don't walk off the end
assert((end-begin) % numComp == 0);
//iterate over all the tuples
for (InputIteratorType value = begin; value != end; value+=numComp)
for (vtkIdType tupleIdx; tupleIdx < numTuples; ++tupleIdx)
{
double squaredSum = 0.0;
for (int i = 0; i < numComp; ++i)
for (int compIdx = 0; compIdx < numComps; ++compIdx)
{
const double t = static_cast<double>(value[i]);
const double t = array->GetComponent(tupleIdx, compIdx);
squaredSum += t * t;
}
range[0] = detail::min(range[0], squaredSum);
......
......@@ -507,5 +507,4 @@ private:
};
#include "vtkGenericDataArray.txx"
#include "vtkGenericDataArrayMacros.h"
#endif
......@@ -14,6 +14,7 @@
=========================================================================*/
#include "vtkGenericDataArrayHelper.h"
#include "vtkArrayDispatch.h"
#include "vtkObjectFactory.h"
#include "vtkSoADataArrayTemplate.h"
#include "vtkAoSDataArrayTemplate.h"
......@@ -21,29 +22,51 @@
//============================================================================
namespace
{
//--------------------------------------------------------------------------
template <class ArrayDestType, class ArraySourceType>
void vtkSetTuple(ArrayDestType* dest, vtkIdType destTuple,
ArraySourceType* source, vtkIdType sourceTuple)
//--------------------------------------------------------------------------
struct SetTupleWorker
{
vtkIdType SourceTuple;
vtkIdType DestTuple;
SetTupleWorker(vtkIdType sourceTuple, vtkIdType destTuple)
: SourceTuple(sourceTuple),
DestTuple(destTuple)
{}
template <typename ArrayIn, typename ArrayOut>
void operator()(ArrayIn *source, ArrayOut *dest)
{
for (int cc = 0, max = dest->GetNumberOfComponents(); cc < max; ++cc)
{
for (int cc=0, max=dest->GetNumberOfComponents(); cc < max; ++cc)
{
dest->SetComponentValue(destTuple, cc,
static_cast<typename ArrayDestType::ValueType>(
source->GetComponentValue(sourceTuple, cc)));
}
dest->SetComponentValue(this->DestTuple, cc,
static_cast<typename ArrayOut::ValueType>(
source->GetComponentValue(this->SourceTuple, cc)));
}
}
};
//-------------------------------------------------------------------------
template <class ArraySourceType>
void vtkGetTuple(ArraySourceType* source, vtkIdType tuple, double* buffer)
//--------------------------------------------------------------------------
struct GetTupleWorker
{
vtkIdType Tuple;
double *Buffer;
GetTupleWorker(vtkIdType tuple, double *buffer) : Tuple(tuple), Buffer(buffer)
{}
template <typename ArrayT>
void operator()(ArrayT *source)
{
for (int cc = 0, max = source->GetNumberOfComponents(); cc < max; ++cc)
{
for (int cc=0, max=source->GetNumberOfComponents(); cc < max; ++cc)
{
buffer[cc] = static_cast<double>(source->GetComponentValue(tuple, cc));
}
this->Buffer[cc] =
static_cast<double>(source->GetComponentValue(this->Tuple, cc));
}
}
}
};
} // end anon namespace
//============================================================================
......@@ -73,15 +96,33 @@ void vtkGenericDataArrayHelper::SetTuple(
return;
}
vtkGenericDataArrayMacro2(dest, source,
vtkSetTuple(ARRAY1, destTuple, ARRAY2, sourceTuple));
vtkDataArray *srcDA = vtkDataArray::SafeDownCast(source);
vtkDataArray *dstDA = vtkDataArray::SafeDownCast(dest);
if (!srcDA || !dstDA)
{
vtkGenericWarningMacro("This method expects both arrays to be vtkDataArray "
"subclasses.");
return;
}
SetTupleWorker worker(sourceTuple, destTuple);
vtkArrayDispatch::Dispatch2SameValueType::Execute(srcDA, dstDA, worker);
}
//----------------------------------------------------------------------------
void vtkGenericDataArrayHelper::GetTuple(vtkAbstractArray* source,
vtkIdType tuple, double* buffer)
{
vtkGenericDataArrayMacro(source, vtkGetTuple(ARRAY, tuple, buffer));
vtkDataArray *srcDA = vtkDataArray::SafeDownCast(source);
if (!srcDA)
{
vtkGenericWarningMacro("This method expects source to be a vtkDataArray "
"subclass.");
return;
}
GetTupleWorker worker(tuple, buffer);
vtkArrayDispatch::Dispatch::Execute(srcDA, worker);
}
//----------------------------------------------------------------------------
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkGenericDataArrayMacros.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.
=========================================================================*/
// .NAME vtkGenericDataArrayMacros
// .SECTION Description
#ifndef vtkGenericDataArrayMacros_h
#define vtkGenericDataArrayMacros_h
#include "vtkGenericDataArray.h"
#include "vtkSoADataArrayTemplate.h"
#include "vtkAoSDataArrayTemplate.h"
#include <typeinfo>
// TODO the dynamic_cast is needed instead of:
// if (typeid(*array) == typeid(arrayT<scalarT>))
// so that e.g. vtkFloatArray will match vtkAoSDataArrayTemplate<float>
// Might be slower, need to find the more performant way to do this that
// covers all usecases. Then again...this should never be called in a tight
// loop, so dynamic_cast'ing might be fine?
#define vtkGenericDataArrayMacroCase(arrayT, scalarT, array, call) \
if (dynamic_cast<arrayT<scalarT>*>(array)) \
{ \
typedef arrayT<scalarT> ARRAY_TYPE; \
ARRAY_TYPE* ARRAY = reinterpret_cast<ARRAY_TYPE*>(array); \
call; \
}
// vtkIdType is at the end just in case it's definied to a non-default type.
#define vtkGenericDataArrayMacroTemplateCases(arrayT, array, call) \
vtkGenericDataArrayMacroCase(arrayT, char, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, double, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, float, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, int, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, long long, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, long, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, short, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, signed char, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, unsigned char, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, unsigned int, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, unsigned long long, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, unsigned long, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, unsigned short, array, call) \
else vtkGenericDataArrayMacroCase(arrayT, vtkIdType, array, call)
#define vtkGenericDataArrayMacro(array, call) \
vtkGenericDataArrayMacroTemplateCases(vtkSoADataArrayTemplate, array, call) \
else vtkGenericDataArrayMacroTemplateCases(vtkAoSDataArrayTemplate, array, call) \
else \
{ \
vtkGenericWarningMacro("Unknown type " << typeid(*array).name()); \
abort(); \
}
#define vtkGenericDataArrayMacro2(array1, array2, call) \
vtkGenericDataArrayMacro(array1, \
typedef ARRAY_TYPE ARRAY_TYPE1; \
ARRAY_TYPE1* ARRAY1 = ARRAY; \
vtkGenericDataArrayMacro(array2, \
typedef ARRAY_TYPE ARRAY_TYPE2; \
ARRAY_TYPE2* ARRAY2 = ARRAY; \
call; \
)\
)
#endif
......@@ -186,7 +186,7 @@ void *vtkSoADataArrayTemplate<ValueType>::GetVoidPointer(vtkIdType id)
vtkWarningMacro(<<"GetVoidPointer called. This is very expensive for "
"non-array-of-structs subclasses, as the scalar array "
"must be generated for each call. Using the "
"vtkGenericDataArray API vtkGenericDataArrayMacro are "
"vtkGenericDataArray API with vtkArrayDispatch are "
"preferred. Define the environment variable "
"VTK_SILENCE_GET_VOID_POINTER_WARNINGS to silence "
"this warning.");
......
......@@ -14,12 +14,12 @@
=========================================================================*/
#include "vtkDataSetAttributes.h"
#include "vtkArrayDispatch.h"
#include "vtkArrayIteratorIncludes.h"
#include "vtkCell.h"
#include "vtkCharArray.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"
#include "vtkGenericDataArrayMacros.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkIntArray.h"
......@@ -436,46 +436,59 @@ void vtkDataSetAttributes::PassData(vtkFieldData* fd)
}
//----------------------------------------------------------------------------
template <class OutGenericArrayT, class InGenericArrayT>
void vtkDataSetAttributesCopyValuesForGenericArrays(
OutGenericArrayT* dest, const int* outExt,
InGenericArrayT* src, const int* 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] = {
outExt[0] - inExt[0],
outExt[1] - inExt[0],
outExt[2] - inExt[2],
outExt[3] - inExt[2],
outExt[4] - inExt[4],
outExt[5] - inExt[4]
};
const int dims[3] = { inExt[1] - inExt[0] + 1,
inExt[3] - inExt[2] + 1,
inExt[5] - inExt[4] + 1};
vtkIdType outTupleIdx = 0;
for (int outz = relOutExt[4]; outz <= relOutExt[5]; ++outz)
{
const vtkIdType zfactor = static_cast<vtkIdType>(outz) * dims[1];
for (int outy = relOutExt[2]; outy <= relOutExt[3]; ++outy)
namespace {
struct CopyStructuredDataWorker
{
const int *OutExt;
const int *InExt;
CopyStructuredDataWorker(const int *outExt, const int *inExt)
: OutExt(outExt), InExt(inExt)
{}
template <typename Array1T, typename Array2T>
void operator()(Array1T *dest, Array2T *src)
{
// 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]
};
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 yfactor = (zfactor + outy) * dims[0];
for (int outx = relOutExt[0]; outx <= relOutExt[1]; ++outx)
const vtkIdType zfactor = static_cast<vtkIdType>(outz) * dims[1];
for (int outy = relOutExt[2]; outy <= relOutExt[3]; ++outy)
{
const vtkIdType inTupleIdx = yfactor + outx;
for (int comp=0, max=dest->GetNumberOfComponents(); comp < max; ++comp)
const vtkIdType yfactor = (zfactor + outy) * dims[0];
for (int outx = relOutExt[0]; outx <= relOutExt[1]; ++outx)
{
dest->SetComponentValue(outTupleIdx, comp, src->GetComponentValue(inTupleIdx, comp));
const vtkIdType inTupleIdx = yfactor + outx;
for (int comp = 0, max = dest->GetNumberOfComponents();
comp < max; ++comp)
{
dest->SetComponentValue(outTupleIdx, comp,
src->GetComponentValue(inTupleIdx, comp));
}
outTupleIdx++;
}
outTupleIdx++;
}
}
}
dest->DataChanged();
}
dest->DataChanged();
}
};
} // end anon namespace
//----------------------------------------------------------------------------
template <class iterT>
......@@ -597,7 +610,11 @@ void vtkDataSetAttributes::CopyStructuredData(vtkDataSetAttributes *fromPd,
// We get very little performance improvement from this, but we'll leave the
// legacy code around until we've done through benchmarking.
if (inArray->HasStandardMemoryLayout() && outArray->HasStandardMemoryLayout())
vtkDataArray *inDA = vtkDataArray::SafeDownCast(inArray);
vtkDataArray *outDA = vtkDataArray::SafeDownCast(outArray);
if ((inArray->HasStandardMemoryLayout() &&
outArray->HasStandardMemoryLayout()) ||
(!inDA || !outDA))
{
vtkArrayIterator* srcIter = inArray->NewIterator();
vtkArrayIterator* destIter = outArray->NewIterator();
......@@ -613,8 +630,12 @@ void vtkDataSetAttributes::CopyStructuredData(vtkDataSetAttributes *fromPd,
}
else
{
vtkGenericDataArrayMacro2(outArray, inArray,
vtkDataSetAttributesCopyValuesForGenericArrays(ARRAY1, outExt, ARRAY2, inExt));
CopyStructuredDataWorker worker(outExt, inExt);
if (!vtkArrayDispatch::Dispatch2SameValueType::Execute(outDA, inDA,
worker))
{
vtkWarningMacro("Dispatch failed for array " << inArray->GetName());
}
}
}
}
......
......@@ -14,10 +14,10 @@
=========================================================================*/
#include "vtkAppendPolyData.h"
#include "vtkArrayDispatch.h"
#include "vtkAlgorithmOutput.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkDataArrayIteratorMacro.h"
#include "vtkDataSetAttributes.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
......@@ -27,6 +27,9 @@