/*========================================================================= 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 double* vtkGenericDataArray::GetTuple(vtkIdType tupleIdx) { assert(!this->LegacyTuple.empty() && "Number of components is nonzero."); this->GetTuple(tupleIdx, &this->LegacyTuple[0]); return &this->LegacyTuple[0]; } //----------------------------------------------------------------------------- template void vtkGenericDataArray::GetTuple(vtkIdType tupleIdx, double* tuple) { for (int c = 0; c < this->NumberOfComponents; ++c) { tuple[c] = static_cast(this->GetTypedComponent(tupleIdx, c)); } } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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(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(other->GetTypedComponent(t, c)); } ValueType valT; vtkMath::RoundDoubleToIntegralIfNecessary(val, &valT); this->InsertTypedComponent(dstTupleIdx, c, valT); } } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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(source1); DerivedT* other2 = other1 ? vtkArrayDownCast(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 void vtkGenericDataArray::SetComponent( vtkIdType tupleIdx, int compIdx, double value) { // Reimplemented for efficiency (base impl allocates heap memory) this->SetTypedComponent(tupleIdx, compIdx, static_cast(value)); } //----------------------------------------------------------------------------- template double vtkGenericDataArray::GetComponent(vtkIdType tupleIdx, int compIdx) { // Reimplemented for efficiency (base impl allocates heap memory) return static_cast(this->GetTypedComponent(tupleIdx, compIdx)); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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 void vtkGenericDataArray::SetVoidArray(void*, vtkIdType, int) { vtkErrorMacro("SetVoidArray is not supported by this class."); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::SetVoidArray(void*, vtkIdType, int, int) { vtkErrorMacro("SetVoidArray is not supported by this class."); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::SetArrayFreeFunction(void (*)(void*)) { vtkErrorMacro("SetArrayFreeFunction is not supported by this class."); } //----------------------------------------------------------------------------- template void* vtkGenericDataArray::WriteVoidPointer(vtkIdType, vtkIdType) { vtkErrorMacro("WriteVoidPointer is not supported by this class."); return nullptr; } //----------------------------------------------------------------------------- template typename vtkGenericDataArray::ValueType* vtkGenericDataArray::WritePointer(vtkIdType id, vtkIdType number) { return static_cast(this->WriteVoidPointer(id, number)); } //----------------------------------------------------------------------------- template int vtkGenericDataArray::GetDataType() const { return vtkTypeTraits::VTK_TYPE_ID; } //----------------------------------------------------------------------------- template int vtkGenericDataArray::GetDataTypeSize() const { return static_cast(sizeof(ValueType)); } //----------------------------------------------------------------------------- template bool vtkGenericDataArray::HasStandardMemoryLayout() const { // False by default, AoS should set true. return false; } //----------------------------------------------------------------------------- template void* vtkGenericDataArray::GetVoidPointer(vtkIdType) { vtkErrorMacro("GetVoidPointer is not supported by this class."); return nullptr; } //----------------------------------------------------------------------------- template typename vtkGenericDataArray::ValueType* vtkGenericDataArray::GetPointer(vtkIdType id) { return static_cast(this->GetVoidPointer(id)); } //----------------------------------------------------------------------------- template vtkIdType vtkGenericDataArray::LookupValue(vtkVariant valueVariant) { bool valid = true; ValueType value = vtkVariantCast(valueVariant, &valid); if (valid) { return this->LookupTypedValue(value); } return -1; } //----------------------------------------------------------------------------- template vtkIdType vtkGenericDataArray::LookupTypedValue(ValueType value) { return this->Lookup.LookupValue(value); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::LookupValue(vtkVariant valueVariant, vtkIdList* ids) { ids->Reset(); bool valid = true; ValueType value = vtkVariantCast(valueVariant, &valid); if (valid) { this->LookupTypedValue(value, ids); } } //----------------------------------------------------------------------------- template void vtkGenericDataArray::LookupTypedValue(ValueType value, vtkIdList* ids) { ids->Reset(); this->Lookup.LookupValue(value, ids); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::ClearLookup() { this->Lookup.ClearLookup(); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::DataChanged() { this->Lookup.ClearLookup(); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::SetVariantValue( vtkIdType valueIdx, vtkVariant valueVariant) { bool valid = true; ValueType value = vtkVariantCast(valueVariant, &valid); if (valid) { this->SetValue(valueIdx, value); } } //----------------------------------------------------------------------------- template vtkVariant vtkGenericDataArray::GetVariantValue(vtkIdType valueIdx) { return vtkVariant(this->GetValue(valueIdx)); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::InsertVariantValue( vtkIdType valueIdx, vtkVariant valueVariant) { bool valid = true; ValueType value = vtkVariantCast(valueVariant, &valid); if (valid) { this->InsertValue(valueIdx, value); } } //----------------------------------------------------------------------------- template vtkTypeBool vtkGenericDataArray::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(size) / static_cast(numComps)); vtkIdType numTuples = static_cast(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 vtkTypeBool vtkGenericDataArray::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 void vtkGenericDataArray::SetNumberOfComponents(int num) { this->vtkDataArray::SetNumberOfComponents(num); this->LegacyTuple.resize(num); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::SetNumberOfTuples(vtkIdType number) { vtkIdType newSize = number * this->NumberOfComponents; if (this->Allocate(newSize, 0)) { this->MaxId = newSize - 1; } } //----------------------------------------------------------------------------- template void vtkGenericDataArray::Initialize() { this->Resize(0); this->DataChanged(); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::Squeeze() { this->Resize(this->GetNumberOfTuples()); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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(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 void vtkGenericDataArray::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(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 void vtkGenericDataArray::InsertTuple( vtkIdType i, vtkIdType j, vtkAbstractArray* source) { this->EnsureAccessToTuple(i); this->SetTuple(i, j, source); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::InsertTuple(vtkIdType i, const float* source) { this->EnsureAccessToTuple(i); this->SetTuple(i, source); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::InsertTuple(vtkIdType i, const double* source) { this->EnsureAccessToTuple(i); this->SetTuple(i, source); } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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 vtkIdType vtkGenericDataArray::InsertNextTuple( vtkIdType srcTupleIdx, vtkAbstractArray* source) { vtkIdType nextTuple = this->GetNumberOfTuples(); this->InsertTuple(nextTuple, srcTupleIdx, source); return nextTuple; } //----------------------------------------------------------------------------- template vtkIdType vtkGenericDataArray::InsertNextTuple(const float* tuple) { vtkIdType nextTuple = this->GetNumberOfTuples(); this->InsertTuple(nextTuple, tuple); return nextTuple; } //----------------------------------------------------------------------------- template vtkIdType vtkGenericDataArray::InsertNextTuple(const double* tuple) { vtkIdType nextTuple = this->GetNumberOfTuples(); this->InsertTuple(nextTuple, tuple); return nextTuple; } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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(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 void vtkGenericDataArray::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(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 vtkArrayIterator* vtkGenericDataArray::NewIterator() { vtkWarningMacro(<< "No vtkArrayIterator defined for " << this->GetClassName() << " arrays."); return nullptr; } //----------------------------------------------------------------------------- template vtkIdType vtkGenericDataArray::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 void vtkGenericDataArray::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 void vtkGenericDataArray::InsertTypedTuple( vtkIdType tupleIdx, const ValueType* t) { if (this->EnsureAccessToTuple(tupleIdx)) { this->SetTypedTuple(tupleIdx, t); } } //----------------------------------------------------------------------------- template vtkIdType vtkGenericDataArray::InsertNextTypedTuple(const ValueType* t) { vtkIdType nextTuple = this->GetNumberOfTuples(); this->InsertTypedTuple(nextTuple, t); return nextTuple; } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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 void vtkGenericDataArray::GetValueRange(ValueType range[2], int comp) { this->ComputeValueRange(range, comp); } //----------------------------------------------------------------------------- template typename vtkGenericDataArray::ValueType* vtkGenericDataArray::GetValueRange(int comp) { this->LegacyValueRange.resize(2); this->GetValueRange(this->LegacyValueRange.data(), comp); return &this->LegacyValueRange[0]; } //----------------------------------------------------------------------------- template void vtkGenericDataArray::GetFiniteValueRange(ValueType range[2], int comp) { this->ComputeFiniteValueRange(range, comp); } //----------------------------------------------------------------------------- template typename vtkGenericDataArray::ValueType* vtkGenericDataArray::GetFiniteValueRange(int comp) { this->LegacyValueRange.resize(2); this->GetFiniteValueRange(this->LegacyValueRange.data(), comp); return &this->LegacyValueRange[0]; } //----------------------------------------------------------------------------- template void vtkGenericDataArray::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 void vtkGenericDataArray::FillValue(ValueType value) { for (int i = 0; i < this->NumberOfComponents; ++i) { this->FillTypedComponent(i, value); } } //----------------------------------------------------------------------------- template void vtkGenericDataArray::FillComponent(int compIdx, double value) { this->FillTypedComponent(compIdx, static_cast(value)); } //----------------------------------------------------------------------------- template vtkGenericDataArray::vtkGenericDataArray() { // Initialize internal data structures: this->Lookup.SetArray(this); this->SetNumberOfComponents(this->NumberOfComponents); } //----------------------------------------------------------------------------- template vtkGenericDataArray::~vtkGenericDataArray() { } //----------------------------------------------------------------------------- template bool vtkGenericDataArray::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 class vtkAOSDataArrayTemplate; template class vtkSOADataArrayTemplate; #ifdef VTK_USE_SCALED_SOA_ARRAYS template class vtkScaledSOADataArrayTemplate; #endif namespace vtk_GDA_detail { // Arrays templates with compiled-in support for value ranges in // vtkGenericDataArray.cxx template struct ATIsSupported : public std::false_type { }; template struct ATIsSupported > : public std::true_type { }; template struct ATIsSupported > : public std::true_type { }; #ifdef VTK_USE_SCALED_SOA_ARRAYS template struct ATIsSupported > : public std::true_type { }; #endif // ValueTypes with compiled-in support for value ranges in // vtkGenericDataArray.cxx template struct VTIsSupported : public std::false_type { }; template <> struct VTIsSupported : public std::true_type { }; template <> struct VTIsSupported : public std::true_type { }; template <> struct VTIsSupported : public std::true_type { }; template <> struct VTIsSupported : public std::true_type { }; // Full array types with compiled-in support for value ranges in // vtkGenericDataArray.cxx template struct IsSupported : public std::integral_constant::value && VTIsSupported::value)> { }; } // end namespace vtk_GDA_detail //----------------------------------------------------------------------------- template void vtkGenericDataArray::ComputeValueRange(ValueType range[2], int comp) { using namespace vtk_GDA_detail; using Supported = IsSupported; // 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(tmpRange[0]); range[1] = static_cast(tmpRange[1]); return; } range[0] = vtkTypeTraits::Max(); range[1] = vtkTypeTraits::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 void vtkGenericDataArray::ComputeFiniteValueRange( ValueType range[2], int comp) { using namespace vtk_GDA_detail; using Supported = IsSupported; // 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(tmpRange[0]); range[1] = static_cast(tmpRange[1]); return; } range[0] = vtkTypeTraits::Max(); range[1] = vtkTypeTraits::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 bool ComputeScalarValueRangeImpl(ArrayType* array, ValueType* range, Tag tag, std::true_type) { return ::vtkDataArrayPrivate::DoComputeScalarRange(array, range, tag); } template bool ComputeScalarValueRangeImpl(ArrayType* array, ValueType* range, Tag tag, std::false_type) { // Compute the range at double precision. std::size_t numComps = static_cast(array->GetNumberOfComponents()); std::vector tmpRange(numComps * 2); if (!::vtkDataArrayPrivate::DoComputeScalarRange( static_cast(array), tmpRange.data(), tag)) { return false; } for (std::size_t i = 0; i < numComps * 2; ++i) { range[i] = static_cast(tmpRange[i]); } return true; } template bool ComputeVectorValueRangeImpl(ArrayType* array, ValueType range[2], Tag tag, std::true_type) { return ::vtkDataArrayPrivate::DoComputeVectorRange(array, range, tag); } template 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(array), tmpRange, tag)) { return false; } range[0] = static_cast(tmpRange[0]); range[1] = static_cast(tmpRange[1]); return true; } } // namespace vtk_GDA_detail //----------------------------------------------------------------------------- template bool vtkGenericDataArray::ComputeScalarValueRange(ValueType* ranges) { using namespace vtk_GDA_detail; using Supported = IsSupported; return ComputeScalarValueRangeImpl( static_cast(this), ranges, vtkDataArrayPrivate::AllValues{}, Supported{}); } //----------------------------------------------------------------------------- template bool vtkGenericDataArray::ComputeVectorValueRange(ValueType range[2]) { using namespace vtk_GDA_detail; using Supported = IsSupported; return ComputeVectorValueRangeImpl( static_cast(this), range, vtkDataArrayPrivate::AllValues{}, Supported{}); } //----------------------------------------------------------------------------- template bool vtkGenericDataArray::ComputeFiniteScalarValueRange(ValueType* range) { using namespace vtk_GDA_detail; using Supported = IsSupported; return ComputeScalarValueRangeImpl( static_cast(this), range, vtkDataArrayPrivate::FiniteValues{}, Supported{}); } //----------------------------------------------------------------------------- template bool vtkGenericDataArray::ComputeFiniteVectorValueRange(ValueType range[2]) { using namespace vtk_GDA_detail; using Supported = IsSupported; return ComputeVectorValueRangeImpl( static_cast(this), range, vtkDataArrayPrivate::FiniteValues{}, Supported{}); } #undef vtkGenericDataArrayT #endif // header guard