You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1231 lines
40 KiB
Plaintext

/*=========================================================================
Program: Visualization Toolkit
Module: vtkGenericDataArray.txx
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.
=========================================================================*/
#ifndef vtkGenericDataArray_txx
#define vtkGenericDataArray_txx
#include "vtkGenericDataArray.h"
#include "vtkIdList.h"
#include "vtkMath.h"
#include "vtkVariantCast.h"
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
double* vtkGenericDataArray<DerivedT, ValueTypeT>::GetTuple(vtkIdType tupleIdx)
{
assert(!this->LegacyTuple.empty() && "Number of components is nonzero.");
this->GetTuple(tupleIdx, &this->LegacyTuple[0]);
return &this->LegacyTuple[0];
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::GetTuple(vtkIdType tupleIdx, double* tuple)
{
for (int c = 0; c < this->NumberOfComponents; ++c)
{
tuple[c] = static_cast<double>(this->GetTypedComponent(tupleIdx, c));
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InterpolateTuple(
vtkIdType dstTupleIdx, vtkIdList* ptIndices, vtkAbstractArray* source, double* weights)
{
// First, check for the common case of typeid(source) == typeid(this). This
// way we don't waste time redoing the other checks in the superclass, and
// can avoid doing a dispatch for the most common usage of this method.
DerivedT* other = vtkArrayDownCast<DerivedT>(source);
if (!other)
{
// Let the superclass handle dispatch/fallback.
this->Superclass::InterpolateTuple(dstTupleIdx, ptIndices, source, weights);
return;
}
int numComps = this->GetNumberOfComponents();
if (other->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components do not match: Source: "
<< other->GetNumberOfComponents() << " Dest: " << this->GetNumberOfComponents());
return;
}
vtkIdType numIds = ptIndices->GetNumberOfIds();
vtkIdType* ids = ptIndices->GetPointer(0);
for (int c = 0; c < numComps; ++c)
{
double val = 0.;
for (vtkIdType tupleId = 0; tupleId < numIds; ++tupleId)
{
vtkIdType t = ids[tupleId];
double weight = weights[tupleId];
val += weight * static_cast<double>(other->GetTypedComponent(t, c));
}
ValueType valT;
vtkMath::RoundDoubleToIntegralIfNecessary(val, &valT);
this->InsertTypedComponent(dstTupleIdx, c, valT);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InterpolateTuple(vtkIdType dstTupleIdx,
vtkIdType srcTupleIdx1, vtkAbstractArray* source1, vtkIdType srcTupleIdx2,
vtkAbstractArray* source2, double t)
{
// First, check for the common case of typeid(source) == typeid(this). This
// way we don't waste time redoing the other checks in the superclass, and
// can avoid doing a dispatch for the most common usage of this method.
DerivedT* other1 = vtkArrayDownCast<DerivedT>(source1);
DerivedT* other2 = other1 ? vtkArrayDownCast<DerivedT>(source2) : nullptr;
if (!other1 || !other2)
{
// Let the superclass handle dispatch/fallback.
this->Superclass::InterpolateTuple(
dstTupleIdx, srcTupleIdx1, source1, srcTupleIdx2, source2, t);
return;
}
if (srcTupleIdx1 >= source1->GetNumberOfTuples())
{
vtkErrorMacro("Tuple 1 out of range for provided array. "
"Requested tuple: "
<< srcTupleIdx1
<< " "
"Tuples: "
<< source1->GetNumberOfTuples());
return;
}
if (srcTupleIdx2 >= source2->GetNumberOfTuples())
{
vtkErrorMacro("Tuple 2 out of range for provided array. "
"Requested tuple: "
<< srcTupleIdx2
<< " "
"Tuples: "
<< source2->GetNumberOfTuples());
return;
}
int numComps = this->GetNumberOfComponents();
if (other1->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components do not match: Source: "
<< other1->GetNumberOfComponents() << " Dest: " << this->GetNumberOfComponents());
return;
}
if (other2->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components do not match: Source: "
<< other2->GetNumberOfComponents() << " Dest: " << this->GetNumberOfComponents());
return;
}
const double oneMinusT = 1. - t;
double val;
ValueType valT;
for (int c = 0; c < numComps; ++c)
{
val = other1->GetTypedComponent(srcTupleIdx1, c) * oneMinusT +
other2->GetTypedComponent(srcTupleIdx2, c) * t;
vtkMath::RoundDoubleToIntegralIfNecessary(val, &valT);
this->InsertTypedComponent(dstTupleIdx, c, valT);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetComponent(
vtkIdType tupleIdx, int compIdx, double value)
{
// Reimplemented for efficiency (base impl allocates heap memory)
this->SetTypedComponent(tupleIdx, compIdx, static_cast<ValueType>(value));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
double vtkGenericDataArray<DerivedT, ValueTypeT>::GetComponent(vtkIdType tupleIdx, int compIdx)
{
// Reimplemented for efficiency (base impl allocates heap memory)
return static_cast<double>(this->GetTypedComponent(tupleIdx, compIdx));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::RemoveTuple(vtkIdType id)
{
if (id < 0 || id >= this->GetNumberOfTuples())
{
// Nothing to be done
return;
}
if (id == (this->GetNumberOfTuples() - 1))
{
// To remove last item, just decrease the size by one
this->RemoveLastTuple();
return;
}
// This is a very slow implementation since it uses generic API. Subclasses
// are encouraged to provide a faster implementation.
assert(((this->GetNumberOfTuples() - id) - 1) /* (length) */ > 0);
int numComps = this->GetNumberOfComponents();
vtkIdType fromTuple = id + 1;
vtkIdType toTuple = id;
vtkIdType endTuple = this->GetNumberOfTuples();
for (; fromTuple != endTuple; ++toTuple, ++fromTuple)
{
for (int comp = 0; comp < numComps; ++comp)
{
this->SetTypedComponent(toTuple, comp, this->GetTypedComponent(fromTuple, comp));
}
}
this->SetNumberOfTuples(this->GetNumberOfTuples() - 1);
this->DataChanged();
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetVoidArray(void*, vtkIdType, int)
{
vtkErrorMacro("SetVoidArray is not supported by this class.");
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetVoidArray(void*, vtkIdType, int, int)
{
vtkErrorMacro("SetVoidArray is not supported by this class.");
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetArrayFreeFunction(void (*)(void*))
{
vtkErrorMacro("SetArrayFreeFunction is not supported by this class.");
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void* vtkGenericDataArray<DerivedT, ValueTypeT>::WriteVoidPointer(vtkIdType, vtkIdType)
{
vtkErrorMacro("WriteVoidPointer is not supported by this class.");
return nullptr;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
typename vtkGenericDataArray<DerivedT, ValueTypeT>::ValueType*
vtkGenericDataArray<DerivedT, ValueTypeT>::WritePointer(vtkIdType id, vtkIdType number)
{
return static_cast<ValueType*>(this->WriteVoidPointer(id, number));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
int vtkGenericDataArray<DerivedT, ValueTypeT>::GetDataType() const
{
return vtkTypeTraits<ValueType>::VTK_TYPE_ID;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
int vtkGenericDataArray<DerivedT, ValueTypeT>::GetDataTypeSize() const
{
return static_cast<int>(sizeof(ValueType));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
bool vtkGenericDataArray<DerivedT, ValueTypeT>::HasStandardMemoryLayout() const
{
// False by default, AoS should set true.
return false;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void* vtkGenericDataArray<DerivedT, ValueTypeT>::GetVoidPointer(vtkIdType)
{
vtkErrorMacro("GetVoidPointer is not supported by this class.");
return nullptr;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
typename vtkGenericDataArray<DerivedT, ValueTypeT>::ValueType*
vtkGenericDataArray<DerivedT, ValueTypeT>::GetPointer(vtkIdType id)
{
return static_cast<ValueType*>(this->GetVoidPointer(id));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::LookupValue(vtkVariant valueVariant)
{
bool valid = true;
ValueType value = vtkVariantCast<ValueType>(valueVariant, &valid);
if (valid)
{
return this->LookupTypedValue(value);
}
return -1;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::LookupTypedValue(ValueType value)
{
return this->Lookup.LookupValue(value);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::LookupValue(vtkVariant valueVariant, vtkIdList* ids)
{
ids->Reset();
bool valid = true;
ValueType value = vtkVariantCast<ValueType>(valueVariant, &valid);
if (valid)
{
this->LookupTypedValue(value, ids);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::LookupTypedValue(ValueType value, vtkIdList* ids)
{
ids->Reset();
this->Lookup.LookupValue(value, ids);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::ClearLookup()
{
this->Lookup.ClearLookup();
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::DataChanged()
{
this->Lookup.ClearLookup();
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetVariantValue(
vtkIdType valueIdx, vtkVariant valueVariant)
{
bool valid = true;
ValueType value = vtkVariantCast<ValueType>(valueVariant, &valid);
if (valid)
{
this->SetValue(valueIdx, value);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkVariant vtkGenericDataArray<DerivedT, ValueTypeT>::GetVariantValue(vtkIdType valueIdx)
{
return vtkVariant(this->GetValue(valueIdx));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertVariantValue(
vtkIdType valueIdx, vtkVariant valueVariant)
{
bool valid = true;
ValueType value = vtkVariantCast<ValueType>(valueVariant, &valid);
if (valid)
{
this->InsertValue(valueIdx, value);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkTypeBool vtkGenericDataArray<DerivedT, ValueTypeT>::Allocate(
vtkIdType size, vtkIdType vtkNotUsed(ext))
{
// Allocator must updated this->Size and this->MaxId properly.
this->MaxId = -1;
if (size > this->Size || size == 0)
{
this->Size = 0;
// let's keep the size an integral multiple of the number of components.
size = size < 0 ? 0 : size;
int numComps = this->GetNumberOfComponents() > 0 ? this->GetNumberOfComponents() : 1;
double ceilNum = ceil(static_cast<double>(size) / static_cast<double>(numComps));
vtkIdType numTuples = static_cast<vtkIdType>(ceilNum);
// NOTE: if numTuples is 0, AllocateTuples is expected to release the
// memory.
if (this->AllocateTuples(numTuples) == false)
{
vtkErrorMacro(
"Unable to allocate " << size << " elements of size " << sizeof(ValueType) << " bytes. ");
#if !defined NDEBUG
// We're debugging, crash here preserving the stack
abort();
#elif !defined VTK_DONT_THROW_BAD_ALLOC
// We can throw something that has universal meaning
throw std::bad_alloc();
#else
// We indicate that alloc failed by return
return 0;
#endif
}
this->Size = numTuples * numComps;
}
this->DataChanged();
return 1;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkTypeBool vtkGenericDataArray<DerivedT, ValueTypeT>::Resize(vtkIdType numTuples)
{
int numComps = this->GetNumberOfComponents();
vtkIdType curNumTuples = this->Size / (numComps > 0 ? numComps : 1);
if (numTuples > curNumTuples)
{
// Requested size is bigger than current size. Allocate enough
// memory to fit the requested size and be more than double the
// currently allocated memory.
numTuples = curNumTuples + numTuples;
}
else if (numTuples == curNumTuples)
{
return 1;
}
else
{
// Requested size is smaller than current size. Squeeze the
// memory.
this->DataChanged();
}
assert(numTuples >= 0);
if (!this->ReallocateTuples(numTuples))
{
vtkErrorMacro("Unable to allocate " << numTuples * numComps << " elements of size "
<< sizeof(ValueType) << " bytes. ");
#if !defined NDEBUG
// We're debugging, crash here preserving the stack
abort();
#elif !defined VTK_DONT_THROW_BAD_ALLOC
// We can throw something that has universal meaning
throw std::bad_alloc();
#else
// We indicate that malloc failed by return
return 0;
#endif
}
// Allocation was successful. Save it.
this->Size = numTuples * numComps;
// Update MaxId if we truncated:
if ((this->Size - 1) < this->MaxId)
{
this->MaxId = (this->Size - 1);
}
return 1;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetNumberOfComponents(int num)
{
this->vtkDataArray::SetNumberOfComponents(num);
this->LegacyTuple.resize(num);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetNumberOfTuples(vtkIdType number)
{
vtkIdType newSize = number * this->NumberOfComponents;
if (this->Allocate(newSize, 0))
{
this->MaxId = newSize - 1;
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::Initialize()
{
this->Resize(0);
this->DataChanged();
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::Squeeze()
{
this->Resize(this->GetNumberOfTuples());
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::SetTuple(
vtkIdType dstTupleIdx, vtkIdType srcTupleIdx, vtkAbstractArray* source)
{
// First, check for the common case of typeid(source) == typeid(this). This
// way we don't waste time redoing the other checks in the superclass, and
// can avoid doing a dispatch for the most common usage of this method.
DerivedT* other = vtkArrayDownCast<DerivedT>(source);
if (!other)
{
// Let the superclass handle dispatch/fallback.
this->Superclass::SetTuple(dstTupleIdx, srcTupleIdx, source);
return;
}
int numComps = this->GetNumberOfComponents();
if (source->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components do not match: Source: "
<< source->GetNumberOfComponents() << " Dest: " << this->GetNumberOfComponents());
return;
}
for (int c = 0; c < numComps; ++c)
{
this->SetTypedComponent(dstTupleIdx, c, other->GetTypedComponent(srcTupleIdx, c));
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertTuples(
vtkIdList* dstIds, vtkIdList* srcIds, vtkAbstractArray* source)
{
// First, check for the common case of typeid(source) == typeid(this). This
// way we don't waste time redoing the other checks in the superclass, and
// can avoid doing a dispatch for the most common usage of this method.
DerivedT* other = vtkArrayDownCast<DerivedT>(source);
if (!other)
{
// Let the superclass handle dispatch/fallback.
this->Superclass::InsertTuples(dstIds, srcIds, source);
return;
}
if (dstIds->GetNumberOfIds() == 0)
{
return;
}
if (dstIds->GetNumberOfIds() != srcIds->GetNumberOfIds())
{
vtkErrorMacro("Mismatched number of tuples ids. Source: "
<< srcIds->GetNumberOfIds() << " Dest: " << dstIds->GetNumberOfIds());
return;
}
int numComps = this->GetNumberOfComponents();
if (other->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components do not match: Source: "
<< other->GetNumberOfComponents() << " Dest: " << this->GetNumberOfComponents());
return;
}
vtkIdType maxSrcTupleId = srcIds->GetId(0);
vtkIdType maxDstTupleId = dstIds->GetId(0);
for (int i = 0; i < dstIds->GetNumberOfIds(); ++i)
{
// parenthesis around std::max prevent MSVC macro replacement when
// inlined:
maxSrcTupleId = (std::max)(maxSrcTupleId, srcIds->GetId(i));
maxDstTupleId = (std::max)(maxDstTupleId, dstIds->GetId(i));
}
if (maxSrcTupleId >= other->GetNumberOfTuples())
{
vtkErrorMacro("Source array too small, requested tuple at index "
<< maxSrcTupleId << ", but there are only " << other->GetNumberOfTuples()
<< " tuples in the array.");
return;
}
vtkIdType newSize = (maxDstTupleId + 1) * this->NumberOfComponents;
if (this->Size < newSize)
{
if (!this->Resize(maxDstTupleId + 1))
{
vtkErrorMacro("Resize failed.");
return;
}
}
// parenthesis around std::max prevent MSVC macro replacement when
// inlined:
this->MaxId = (std::max)(this->MaxId, newSize - 1);
vtkIdType numTuples = srcIds->GetNumberOfIds();
for (vtkIdType t = 0; t < numTuples; ++t)
{
vtkIdType srcT = srcIds->GetId(t);
vtkIdType dstT = dstIds->GetId(t);
for (int c = 0; c < numComps; ++c)
{
this->SetTypedComponent(dstT, c, other->GetTypedComponent(srcT, c));
}
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertTuple(
vtkIdType i, vtkIdType j, vtkAbstractArray* source)
{
this->EnsureAccessToTuple(i);
this->SetTuple(i, j, source);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertTuple(vtkIdType i, const float* source)
{
this->EnsureAccessToTuple(i);
this->SetTuple(i, source);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertTuple(vtkIdType i, const double* source)
{
this->EnsureAccessToTuple(i);
this->SetTuple(i, source);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertComponent(
vtkIdType tupleIdx, int compIdx, double value)
{
// Update MaxId to the inserted component (not the complete tuple) for
// compatibility with InsertNextValue.
vtkIdType newMaxId = tupleIdx * this->NumberOfComponents + compIdx;
if (newMaxId < this->MaxId)
{
newMaxId = this->MaxId;
}
this->EnsureAccessToTuple(tupleIdx);
assert("Sufficient space allocated." && this->MaxId >= newMaxId);
this->MaxId = newMaxId;
this->SetComponent(tupleIdx, compIdx, value);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::InsertNextTuple(
vtkIdType srcTupleIdx, vtkAbstractArray* source)
{
vtkIdType nextTuple = this->GetNumberOfTuples();
this->InsertTuple(nextTuple, srcTupleIdx, source);
return nextTuple;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::InsertNextTuple(const float* tuple)
{
vtkIdType nextTuple = this->GetNumberOfTuples();
this->InsertTuple(nextTuple, tuple);
return nextTuple;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::InsertNextTuple(const double* tuple)
{
vtkIdType nextTuple = this->GetNumberOfTuples();
this->InsertTuple(nextTuple, tuple);
return nextTuple;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::GetTuples(
vtkIdList* tupleIds, vtkAbstractArray* output)
{
// First, check for the common case of typeid(source) == typeid(this). This
// way we don't waste time redoing the other checks in the superclass, and
// can avoid doing a dispatch for the most common usage of this method.
DerivedT* other = vtkArrayDownCast<DerivedT>(output);
if (!other)
{
// Let the superclass handle dispatch/fallback.
this->Superclass::GetTuples(tupleIds, output);
return;
}
int numComps = this->GetNumberOfComponents();
if (other->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components for input and output do not match.\n"
"Source: "
<< this->GetNumberOfComponents()
<< "\n"
"Destination: "
<< other->GetNumberOfComponents());
return;
}
vtkIdType* srcTuple = tupleIds->GetPointer(0);
vtkIdType* srcTupleEnd = tupleIds->GetPointer(tupleIds->GetNumberOfIds());
vtkIdType dstTuple = 0;
while (srcTuple != srcTupleEnd)
{
for (int c = 0; c < numComps; ++c)
{
other->SetTypedComponent(dstTuple, c, this->GetTypedComponent(*srcTuple, c));
}
++srcTuple;
++dstTuple;
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::GetTuples(
vtkIdType p1, vtkIdType p2, vtkAbstractArray* output)
{
// First, check for the common case of typeid(source) == typeid(this). This
// way we don't waste time redoing the other checks in the superclass, and
// can avoid doing a dispatch for the most common usage of this method.
DerivedT* other = vtkArrayDownCast<DerivedT>(output);
if (!other)
{
// Let the superclass handle dispatch/fallback.
this->Superclass::GetTuples(p1, p2, output);
return;
}
int numComps = this->GetNumberOfComponents();
if (other->GetNumberOfComponents() != numComps)
{
vtkErrorMacro("Number of components for input and output do not match.\n"
"Source: "
<< this->GetNumberOfComponents()
<< "\n"
"Destination: "
<< other->GetNumberOfComponents());
return;
}
// p1-p2 are inclusive
for (vtkIdType srcT = p1, dstT = 0; srcT <= p2; ++srcT, ++dstT)
{
for (int c = 0; c < numComps; ++c)
{
other->SetTypedComponent(dstT, c, this->GetTypedComponent(srcT, c));
}
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkArrayIterator* vtkGenericDataArray<DerivedT, ValueTypeT>::NewIterator()
{
vtkWarningMacro(<< "No vtkArrayIterator defined for " << this->GetClassName() << " arrays.");
return nullptr;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::InsertNextValue(ValueType value)
{
vtkIdType nextValueIdx = this->MaxId + 1;
if (nextValueIdx >= this->Size)
{
vtkIdType tuple = nextValueIdx / this->NumberOfComponents;
this->EnsureAccessToTuple(tuple);
// Since EnsureAccessToTuple will update the MaxId to point to the last
// component in the last tuple, we move it back to support this method on
// multi-component arrays.
this->MaxId = nextValueIdx;
}
// Extending array without needing to reallocate:
if (this->MaxId < nextValueIdx)
{
this->MaxId = nextValueIdx;
}
this->SetValue(nextValueIdx, value);
return nextValueIdx;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertValue(vtkIdType valueIdx, ValueType value)
{
vtkIdType tuple = valueIdx / this->NumberOfComponents;
// Update MaxId to the inserted component (not the complete tuple) for
// compatibility with InsertNextValue.
vtkIdType newMaxId = valueIdx > this->MaxId ? valueIdx : this->MaxId;
if (this->EnsureAccessToTuple(tuple))
{
assert("Sufficient space allocated." && this->MaxId >= newMaxId);
this->MaxId = newMaxId;
this->SetValue(valueIdx, value);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertTypedTuple(
vtkIdType tupleIdx, const ValueType* t)
{
if (this->EnsureAccessToTuple(tupleIdx))
{
this->SetTypedTuple(tupleIdx, t);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkIdType vtkGenericDataArray<DerivedT, ValueTypeT>::InsertNextTypedTuple(const ValueType* t)
{
vtkIdType nextTuple = this->GetNumberOfTuples();
this->InsertTypedTuple(nextTuple, t);
return nextTuple;
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::InsertTypedComponent(
vtkIdType tupleIdx, int compIdx, ValueType val)
{
// Update MaxId to the inserted component (not the complete tuple) for
// compatibility with InsertNextValue.
vtkIdType newMaxId = tupleIdx * this->NumberOfComponents + compIdx;
if (this->MaxId > newMaxId)
{
newMaxId = this->MaxId;
}
this->EnsureAccessToTuple(tupleIdx);
assert("Sufficient space allocated." && this->MaxId >= newMaxId);
this->MaxId = newMaxId;
this->SetTypedComponent(tupleIdx, compIdx, val);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::GetValueRange(ValueType range[2], int comp)
{
this->ComputeValueRange(range, comp);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
typename vtkGenericDataArray<DerivedT, ValueTypeT>::ValueType*
vtkGenericDataArray<DerivedT, ValueTypeT>::GetValueRange(int comp)
{
this->LegacyValueRange.resize(2);
this->GetValueRange(this->LegacyValueRange.data(), comp);
return &this->LegacyValueRange[0];
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::GetFiniteValueRange(ValueType range[2], int comp)
{
this->ComputeFiniteValueRange(range, comp);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
typename vtkGenericDataArray<DerivedT, ValueTypeT>::ValueType*
vtkGenericDataArray<DerivedT, ValueTypeT>::GetFiniteValueRange(int comp)
{
this->LegacyValueRange.resize(2);
this->GetFiniteValueRange(this->LegacyValueRange.data(), comp);
return &this->LegacyValueRange[0];
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::FillTypedComponent(int compIdx, ValueType value)
{
if (compIdx < 0 || compIdx >= this->NumberOfComponents)
{
vtkErrorMacro(<< "Specified component " << compIdx << " is not in [0, "
<< this->NumberOfComponents << ")");
return;
}
for (vtkIdType i = 0; i < this->GetNumberOfTuples(); ++i)
{
this->SetTypedComponent(i, compIdx, value);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::FillValue(ValueType value)
{
for (int i = 0; i < this->NumberOfComponents; ++i)
{
this->FillTypedComponent(i, value);
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::FillComponent(int compIdx, double value)
{
this->FillTypedComponent(compIdx, static_cast<ValueType>(value));
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkGenericDataArray<DerivedT, ValueTypeT>::vtkGenericDataArray()
{
// Initialize internal data structures:
this->Lookup.SetArray(this);
this->SetNumberOfComponents(this->NumberOfComponents);
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
vtkGenericDataArray<DerivedT, ValueTypeT>::~vtkGenericDataArray()
{
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
bool vtkGenericDataArray<DerivedT, ValueTypeT>::EnsureAccessToTuple(vtkIdType tupleIdx)
{
if (tupleIdx < 0)
{
return false;
}
vtkIdType minSize = (1 + tupleIdx) * this->NumberOfComponents;
vtkIdType expectedMaxId = minSize - 1;
if (this->MaxId < expectedMaxId)
{
if (this->Size < minSize)
{
if (!this->Resize(tupleIdx + 1))
{
return false;
}
}
this->MaxId = expectedMaxId;
}
return true;
}
// The following introduces a layer of indirection that allows us to use the
// optimized range computation logic in vtkDataArrayPrivate.txx for common
// arrays, but fallback to computing the range at double precision and then
// converting to the valuetype for unknown array types, or for types where
// the conversion from double->ValueType doesn't lose precision.
template <typename ValueType>
class vtkAOSDataArrayTemplate;
template <typename ValueType>
class vtkSOADataArrayTemplate;
#ifdef VTK_USE_SCALED_SOA_ARRAYS
template <typename ValueType>
class vtkScaledSOADataArrayTemplate;
#endif
namespace vtk_GDA_detail
{
// Arrays templates with compiled-in support for value ranges in
// vtkGenericDataArray.cxx
template <typename ArrayType>
struct ATIsSupported : public std::false_type
{
};
template <typename ValueType>
struct ATIsSupported<vtkAOSDataArrayTemplate<ValueType> > : public std::true_type
{
};
template <typename ValueType>
struct ATIsSupported<vtkSOADataArrayTemplate<ValueType> > : public std::true_type
{
};
#ifdef VTK_USE_SCALED_SOA_ARRAYS
template <typename ValueType>
struct ATIsSupported<vtkScaledSOADataArrayTemplate<ValueType> > : public std::true_type
{
};
#endif
// ValueTypes with compiled-in support for value ranges in
// vtkGenericDataArray.cxx
template <typename ValueType>
struct VTIsSupported : public std::false_type
{
};
template <>
struct VTIsSupported<long> : public std::true_type
{
};
template <>
struct VTIsSupported<unsigned long> : public std::true_type
{
};
template <>
struct VTIsSupported<long long> : public std::true_type
{
};
template <>
struct VTIsSupported<unsigned long long> : public std::true_type
{
};
// Full array types with compiled-in support for value ranges in
// vtkGenericDataArray.cxx
template <typename ArrayType, typename ValueType>
struct IsSupported
: public std::integral_constant<bool,
(ATIsSupported<ArrayType>::value && VTIsSupported<ValueType>::value)>
{
};
} // end namespace vtk_GDA_detail
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::ComputeValueRange(ValueType range[2], int comp)
{
using namespace vtk_GDA_detail;
using Supported = IsSupported<DerivedT, ValueTypeT>;
// For array / value types without specific implementations compiled into
// vtkGenericDataArray.cxx, fall back to the GetRange computations in
// vtkDataArray. In these cases, either a) the ValueType's full range is
// expressable as a double, or b) we aren't aware of the array type.
// This reduces the number of specialized range implementations we need to
// compile, and is also faster since we're able to cache the GetValue
// computation (See #17666).
if (!Supported::value)
{
double tmpRange[2];
this->ComputeRange(tmpRange, comp);
range[0] = static_cast<ValueType>(tmpRange[0]);
range[1] = static_cast<ValueType>(tmpRange[1]);
return;
}
range[0] = vtkTypeTraits<ValueType>::Max();
range[1] = vtkTypeTraits<ValueType>::Min();
if (comp > this->NumberOfComponents)
{
return;
}
if (comp < 0 && this->NumberOfComponents == 1)
{
comp = 0;
}
// TODO this should eventually cache the results, but we do not have support
// for all of the information keys we need to cover all possible value types.
if (comp < 0)
{
this->ComputeVectorValueRange(range);
}
else
{
this->LegacyValueRangeFull.resize(this->NumberOfComponents * 2);
if (this->ComputeScalarValueRange(this->LegacyValueRangeFull.data()))
{
range[0] = this->LegacyValueRangeFull[comp * 2];
range[1] = this->LegacyValueRangeFull[comp * 2 + 1];
}
}
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
void vtkGenericDataArray<DerivedT, ValueTypeT>::ComputeFiniteValueRange(
ValueType range[2], int comp)
{
using namespace vtk_GDA_detail;
using Supported = IsSupported<DerivedT, ValueTypeT>;
// For array / value types without specific implementations compiled into
// vtkGenericDataArray.cxx, fall back to the GetRange computations in
// vtkDataArray. In these cases, either a) the ValueType's full range is
// expressable as a double, or b) we aren't aware of the array type.
// This reduces the number of specialized range implementations we need to
// compile, and is also faster since we're able to cache the GetValue
// computation (See #17666).
if (!Supported::value)
{
double tmpRange[2];
this->ComputeFiniteRange(tmpRange, comp);
range[0] = static_cast<ValueType>(tmpRange[0]);
range[1] = static_cast<ValueType>(tmpRange[1]);
return;
}
range[0] = vtkTypeTraits<ValueType>::Max();
range[1] = vtkTypeTraits<ValueType>::Min();
if (comp > this->NumberOfComponents)
{
return;
}
if (comp < 0 && this->NumberOfComponents == 1)
{
comp = 0;
}
// TODO this should eventually cache the results, but we do not have support
// for all of the information keys we need to cover all possible value types.
if (comp < 0)
{
this->ComputeFiniteVectorValueRange(range);
}
else
{
this->LegacyValueRangeFull.resize(this->NumberOfComponents * 2);
if (this->ComputeFiniteScalarValueRange(this->LegacyValueRangeFull.data()))
{
range[0] = this->LegacyValueRangeFull[comp * 2];
range[1] = this->LegacyValueRangeFull[comp * 2 + 1];
}
}
}
namespace vtk_GDA_detail
{
template <typename ArrayType, typename ValueType, typename Tag>
bool ComputeScalarValueRangeImpl(ArrayType* array, ValueType* range, Tag tag, std::true_type)
{
return ::vtkDataArrayPrivate::DoComputeScalarRange(array, range, tag);
}
template <typename ArrayType, typename ValueType, typename Tag>
bool ComputeScalarValueRangeImpl(ArrayType* array, ValueType* range, Tag tag, std::false_type)
{
// Compute the range at double precision.
std::size_t numComps = static_cast<size_t>(array->GetNumberOfComponents());
std::vector<double> tmpRange(numComps * 2);
if (!::vtkDataArrayPrivate::DoComputeScalarRange(
static_cast<vtkDataArray*>(array), tmpRange.data(), tag))
{
return false;
}
for (std::size_t i = 0; i < numComps * 2; ++i)
{
range[i] = static_cast<ValueType>(tmpRange[i]);
}
return true;
}
template <typename ArrayType, typename ValueType, typename Tag>
bool ComputeVectorValueRangeImpl(ArrayType* array, ValueType range[2], Tag tag, std::true_type)
{
return ::vtkDataArrayPrivate::DoComputeVectorRange(array, range, tag);
}
template <typename ArrayType, typename ValueType, typename Tag>
bool ComputeVectorValueRangeImpl(ArrayType* array, ValueType range[2], Tag tag, std::false_type)
{
// Compute the range at double precision.
double tmpRange[2];
if (!::vtkDataArrayPrivate::DoComputeVectorRange(
static_cast<vtkDataArray*>(array), tmpRange, tag))
{
return false;
}
range[0] = static_cast<ValueType>(tmpRange[0]);
range[1] = static_cast<ValueType>(tmpRange[1]);
return true;
}
} // namespace vtk_GDA_detail
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
bool vtkGenericDataArray<DerivedT, ValueTypeT>::ComputeScalarValueRange(ValueType* ranges)
{
using namespace vtk_GDA_detail;
using Supported = IsSupported<DerivedT, ValueTypeT>;
return ComputeScalarValueRangeImpl(
static_cast<DerivedT*>(this), ranges, vtkDataArrayPrivate::AllValues{}, Supported{});
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
bool vtkGenericDataArray<DerivedT, ValueTypeT>::ComputeVectorValueRange(ValueType range[2])
{
using namespace vtk_GDA_detail;
using Supported = IsSupported<DerivedT, ValueTypeT>;
return ComputeVectorValueRangeImpl(
static_cast<DerivedT*>(this), range, vtkDataArrayPrivate::AllValues{}, Supported{});
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
bool vtkGenericDataArray<DerivedT, ValueTypeT>::ComputeFiniteScalarValueRange(ValueType* range)
{
using namespace vtk_GDA_detail;
using Supported = IsSupported<DerivedT, ValueTypeT>;
return ComputeScalarValueRangeImpl(
static_cast<DerivedT*>(this), range, vtkDataArrayPrivate::FiniteValues{}, Supported{});
}
//-----------------------------------------------------------------------------
template <class DerivedT, class ValueTypeT>
bool vtkGenericDataArray<DerivedT, ValueTypeT>::ComputeFiniteVectorValueRange(ValueType range[2])
{
using namespace vtk_GDA_detail;
using Supported = IsSupported<DerivedT, ValueTypeT>;
return ComputeVectorValueRangeImpl(
static_cast<DerivedT*>(this), range, vtkDataArrayPrivate::FiniteValues{}, Supported{});
}
#undef vtkGenericDataArrayT
#endif // header guard