/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkDataArrayTemplate.txx,v $ 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 __vtkDataArrayTemplate_txx #define __vtkDataArrayTemplate_txx #include "vtkDataArrayTemplate.h" #include // We do not provide a definition for the copy constructor or // operator=. Block the warning. #ifdef _MSC_VER # pragma warning (disable: 4661) #endif //---------------------------------------------------------------------------- template vtkDataArrayTemplate::vtkDataArrayTemplate(vtkIdType numComp): vtkDataArray(numComp) { this->Array = 0; this->Tuple = 0; this->TupleSize = 0; this->SaveUserArray = 0; } //---------------------------------------------------------------------------- template vtkDataArrayTemplate::~vtkDataArrayTemplate() { if ((this->Array) && (!this->SaveUserArray)) { free(this->Array); } if(this->Tuple) { free(this->Tuple); } } //---------------------------------------------------------------------------- // This method lets the user specify data to be held by the array. The // array argument is a pointer to the data. size is the size of // the array supplied by the user. Set save to 1 to keep the class // from deleting the array when it cleans up or reallocates memory. // The class uses the actual array provided; it does not copy the data // from the suppled array. template void vtkDataArrayTemplate::SetArray(T* array, vtkIdType size, int save) { if ((this->Array) && (!this->SaveUserArray)) { vtkDebugMacro (<< "Deleting the array..."); free(this->Array); } else { vtkDebugMacro (<<"Warning, array not deleted, but will point to new array."); } vtkDebugMacro(<<"Setting array to: " << static_cast(array)); this->Array = array; this->Size = size; this->MaxId = size-1; this->SaveUserArray = save; } //---------------------------------------------------------------------------- // Allocate memory for this array. Delete old storage only if necessary. template int vtkDataArrayTemplate::Allocate(vtkIdType sz, vtkIdType) { this->MaxId = -1; if(sz > this->Size) { if(this->Array && !this->SaveUserArray) { free(this->Array); } this->Array = 0; this->Size = 0; this->SaveUserArray = 0; int newSize = (sz > 0 ? sz : 1); this->Array = (T*)malloc(newSize * sizeof(T)); if(!this->Array) { vtkErrorMacro("Unable to allocate " << newSize << " elements of size " << sizeof(T) << " bytes. "); return 0; } this->Size = newSize; } return 1; } //---------------------------------------------------------------------------- // Release storage and reset array to initial state. template void vtkDataArrayTemplate::Initialize() { if(this->Array && !this->SaveUserArray) { free(this->Array); } this->Array = 0; this->Size = 0; this->MaxId = -1; this->SaveUserArray = 0; } //---------------------------------------------------------------------------- // Deep copy of another double array. template void vtkDataArrayTemplate::DeepCopy(vtkDataArray* fa) { // Do nothing on a NULL input. if(!fa) { return; } // Avoid self-copy. if(this == fa) { return; } // If data type does not match, do copy with conversion. if(fa->GetDataType() != this->GetDataType()) { this->Superclass::DeepCopy(fa); return; } // Free our previous memory. if(this->Array && !this->SaveUserArray) { free(this->Array); } // Copy the given array into new memory. this->NumberOfComponents = fa->GetNumberOfComponents(); this->MaxId = fa->GetMaxId(); this->Size = fa->GetSize(); this->SaveUserArray = 0; this->Array = (T*)malloc(this->Size * sizeof(T)); if(!this->Array) { vtkErrorMacro("Unable to allocate " << this->Size << " elements of size " << sizeof(T) << " bytes. "); this->Size = 0; this->NumberOfComponents = 0; this->MaxId = -1; return; } memcpy(this->Array, fa->GetVoidPointer(0), this->Size*sizeof(T)); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); vtkOStreamWrapper osw(os); if(this->Array) { osw << indent << "Array: " << static_cast(this->Array) << "\n"; } else { osw << indent << "Array: (null)\n"; } } //---------------------------------------------------------------------------- // Protected function does "reallocate" template T* vtkDataArrayTemplate::ResizeAndExtend(vtkIdType sz) { T* newArray; vtkIdType newSize; if(sz > this->Size) { // Requested size is bigger than current size. Allocate enough // memory to fit the requested size and be more than double the // currently allocated memory. newSize = this->Size + sz; } else if (sz == this->Size) { // Requested size is equal to current size. Do nothing. return this->Array; } else { // Requested size is smaller than current size. Squeeze the // memory. newSize = sz; } // Wipe out the array completely if new size is zero. if(newSize <= 0) { this->Initialize(); return 0; } // Allocate the new array or reallocate the old. if(this->Array && this->SaveUserArray) { // The old array is owned by the user so we cannot try to // reallocate it. Just allocate new memory that we will own. newArray = (T*)malloc(newSize*sizeof(T)); if(!newArray) { vtkErrorMacro("Unable to allocate " << newSize << " elements of size " << sizeof(T) << " bytes. "); return 0; } // Copy the data from the old array. memcpy(newArray, this->Array, (newSize < this->Size ? newSize : this->Size) * sizeof(T)); } else { // Try to reallocate with minimal memory usage and possibly avoid // copying. newArray = (T*)realloc(this->Array, newSize*sizeof(T)); if(!newArray) { vtkErrorMacro("Unable to allocate " << newSize << " elements of size " << sizeof(T) << " bytes. "); return 0; } } // Allocation was successful. Save it. if((newSize-1) < this->MaxId) { this->MaxId = newSize-1; } this->Size = newSize; this->Array = newArray; // This object has now allocated its memory and owns it. this->SaveUserArray = 0; return this->Array; } //---------------------------------------------------------------------------- template int vtkDataArrayTemplate::Resize(vtkIdType sz) { if(this->ResizeAndExtend(sz*this->NumberOfComponents) || sz <= 0) { return 1; } else { return 0; } } //---------------------------------------------------------------------------- // Set the number of n-tuples in the array. template void vtkDataArrayTemplate::SetNumberOfTuples(vtkIdType number) { this->SetNumberOfValues(number*this->NumberOfComponents); } //---------------------------------------------------------------------------- // Get a pointer to a tuple at the ith location. This is a dangerous method // (it is not thread safe since a pointer is returned). template double* vtkDataArrayTemplate::GetTuple(vtkIdType i) { // If the small Tuple array fails to allocate we need something to // return. This will avoid an immediate crash for arrays that do // not have too many components. static double sentryTuple[6] = {0,0,0,0,0,0}; #if 1 // Allocate a larger tuple buffer if needed. if(this->TupleSize < this->NumberOfComponents) { this->TupleSize = this->NumberOfComponents; free(this->Tuple); this->Tuple = (double*)malloc(this->TupleSize * sizeof(double)); } // Make sure tuple allocation succeeded. if(!this->Tuple) { vtkErrorMacro("Unable to allocate " << this->TupleSize << " elements of size " << sizeof(double) << " bytes. "); return sentryTuple; } // Copy the data into the tuple. T* t = this->Array + this->NumberOfComponents*i; for(int j=0; j < this->NumberOfComponents; ++j) { this->Tuple[j] = static_cast(t[j]); } return this->Tuple; #else // Use this version along with purify or valgrind to detect code // that saves the pointer returned by GetTuple. By always // allocating a new tuple and freeing the old one code that keeps // the pointer will do invalid reads or writes. double* newTuple; newTuple = (double*)malloc(this->NumberOfComponents * sizeof(double)); if(!newTuple) { vtkErrorMacro("Unable to allocate " << this->NumberOfComponents << " elements of size " << sizeof(double) << " bytes. "); return sentryTuple; } // Copy the data into the new tuple. T* t = this->Array + this->NumberOfComponents*i; for(int j=0; j < this->NumberOfComponents; ++j) { newTuple[j] = static_cast(t[j]); } // Replace the old tuple with the new one. free(this->Tuple); this->Tuple = newTuple; return this->Tuple; #endif } //---------------------------------------------------------------------------- // Copy the tuple value into a user-provided array. template void vtkDataArrayTemplate::GetTuple(vtkIdType i, double* tuple) { T* t = this->Array + this->NumberOfComponents*i; for(int j=0; j < this->NumberOfComponents; ++j) { tuple[j] = static_cast(t[j]); } } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::GetTupleValue(vtkIdType i, T* tuple) { T* t = this->Array + this->NumberOfComponents*i; for(int j=0; j < this->NumberOfComponents; ++j) { tuple[j] = t[j]; } } //---------------------------------------------------------------------------- // Set the tuple value at the ith location in the array. template void vtkDataArrayTemplate::SetTuple(vtkIdType i, const float* tuple) { vtkIdType loc = i * this->NumberOfComponents; for(int j=0; j < this->NumberOfComponents; ++j) { this->Array[loc+j] = static_cast(tuple[j]); } } template void vtkDataArrayTemplate::SetTuple(vtkIdType i, const double* tuple) { vtkIdType loc = i * this->NumberOfComponents; for(int j=0; j < this->NumberOfComponents; ++j) { this->Array[loc+j] = static_cast(tuple[j]); } } template void vtkDataArrayTemplate::SetTupleValue(vtkIdType i, const T* tuple) { vtkIdType loc = i * this->NumberOfComponents; for(int j=0; j < this->NumberOfComponents; ++j) { this->Array[loc+j] = tuple[j]; } } //---------------------------------------------------------------------------- // Insert (memory allocation performed) the tuple into the ith location // in the array. template void vtkDataArrayTemplate::InsertTuple(vtkIdType i, const float* tuple) { T* t = this->WritePointer(i*this->NumberOfComponents, this->NumberOfComponents); for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } } template void vtkDataArrayTemplate::InsertTuple(vtkIdType i, const double* tuple) { T* t = this->WritePointer(i*this->NumberOfComponents, this->NumberOfComponents); for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } } template void vtkDataArrayTemplate::InsertTupleValue(vtkIdType i, const T* tuple) { T* t = this->WritePointer(i*this->NumberOfComponents, this->NumberOfComponents); for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = *tuple++; } } //---------------------------------------------------------------------------- // Insert (memory allocation performed) the tuple onto the end of the array. template vtkIdType vtkDataArrayTemplate::InsertNextTuple(const float* tuple) { T* t = this->WritePointer(this->MaxId + 1, this->NumberOfComponents); for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } return this->MaxId / this->NumberOfComponents; } template vtkIdType vtkDataArrayTemplate::InsertNextTuple(const double* tuple) { T* t = this->WritePointer(this->MaxId + 1,this->NumberOfComponents); for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } return this->MaxId / this->NumberOfComponents; } template vtkIdType vtkDataArrayTemplate::InsertNextTupleValue(const T* tuple) { T* t = this->WritePointer(this->MaxId + 1,this->NumberOfComponents); for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = *tuple++; } return this->MaxId / this->NumberOfComponents; } //---------------------------------------------------------------------------- // Return the data component at the ith tuple and jth component location. // Note that i double vtkDataArrayTemplate::GetComponent(vtkIdType i, int j) { return static_cast(this->GetValue(i*this->NumberOfComponents + j)); } //---------------------------------------------------------------------------- // Set the data component at the ith tuple and jth component location. // Note that i void vtkDataArrayTemplate::SetComponent(vtkIdType i, int j, double c) { this->SetValue(i*this->NumberOfComponents + j, static_cast(c)); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::InsertComponent(vtkIdType i, int j, double c) { this->InsertValue(i*this->NumberOfComponents + j, static_cast(c)); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::SetNumberOfValues(vtkIdType number) { if(this->Allocate(number)) { this->MaxId = number - 1; } } //---------------------------------------------------------------------------- template T* vtkDataArrayTemplate::WritePointer(vtkIdType id, vtkIdType number) { vtkIdType newSize=id+number; if ( newSize > this->Size ) { this->ResizeAndExtend(newSize); } if ( (--newSize) > this->MaxId ) { this->MaxId = newSize; } return this->Array + id; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::InsertValue(vtkIdType id, T f) { if ( id >= this->Size ) { this->ResizeAndExtend(id+1); } this->Array[id] = f; if ( id > this->MaxId ) { this->MaxId = id; } } //---------------------------------------------------------------------------- template vtkIdType vtkDataArrayTemplate::InsertNextValue(T f) { this->InsertValue (++this->MaxId,f); return this->MaxId; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::ComputeRange(int comp) { // If we got component -1 on a vector array, compute vector magnitude. if(comp < 0 && this->NumberOfComponents == 1) { comp = 0; } // Choose index into component range cache. int index = (comp<0)? this->NumberOfComponents : comp; if(index >= VTK_MAXIMUM_NUMBER_OF_CACHED_COMPONENT_RANGES || (this->GetMTime() > this->ComponentRangeComputeTime[index])) { // We need to compute the range. this->Range[0] = VTK_DOUBLE_MAX; this->Range[1] = VTK_DOUBLE_MIN; if(comp >= 0) { this->ComputeScalarRange(comp); } else { this->ComputeVectorRange(); } // Store the result in the range cache if there is room. if(index < VTK_MAXIMUM_NUMBER_OF_CACHED_COMPONENT_RANGES) { this->ComponentRangeComputeTime[index].Modified(); this->ComponentRange[index][0] = this->Range[0]; this->ComponentRange[index][1] = this->Range[1]; } } else { // Copy value from range cache entry for this component. this->Range[0] = this->ComponentRange[index][0]; this->Range[1] = this->ComponentRange[index][1]; } } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::ComputeScalarRange(int comp) { // Compute range only if there are data. T* begin = this->Array+comp; T* end = this->Array+comp+this->MaxId+1; if(begin == end) { return; } // Compute the range of scalar values. int numComp = this->NumberOfComponents; T range[2] = {*begin, *begin}; for(T* i = begin+numComp; i != end; i += numComp) { T s = *i; if(s < range[0]) { range[0] = s; } else if(s > range[1]) { range[1] = s; } } // Store the range. this->Range[0] = range[0]; this->Range[1] = range[1]; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::ComputeVectorRange() { // Compute range only if there are data. T* begin = this->Array; T* end = this->Array+this->MaxId+1; if(begin == end) { return; } // Compute the range of vector magnitude squared. int numComp = this->NumberOfComponents; double range[2] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MIN}; for(T* i = begin; i != end; i += numComp) { double s = 0.0; for(int j=0; j < numComp; ++j) { double t = i[j]; s += t*t; } if(s < range[0]) { range[0] = s; } // this cannot be an elseif because there may be only one vector in which // case the range[1] would be left at a bad value if(s > range[1]) { range[1] = s; } } // Store the range of vector magnitude. this->Range[0] = sqrt(range[0]); this->Range[1] = sqrt(range[1]); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::ExportToVoidPointer(void *out_ptr) { if(out_ptr && this->Array) { memcpy(static_cast(out_ptr), this->Array, (this->MaxId + 1)*sizeof(T)); } } #endif