/*========================================================================= Program: Visualization Toolkit Module: vtkDataArrayTemplate.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 __vtkDataArrayTemplate_txx #define __vtkDataArrayTemplate_txx #include "vtkDataArrayTemplate.h" #include "vtkArrayIteratorTemplate.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationDoubleVectorKey.h" #include "vtkInformationInformationVectorKey.h" #include "vtkInformationVector.h" #include "vtkSortDataArray.h" #include "vtkTypeTraits.h" #include #include #include #include #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 class vtkDataArrayTemplateLookup { public: vtkDataArrayTemplateLookup() : Rebuild(true) { this->SortedArray = NULL; this->IndexArray = NULL; } ~vtkDataArrayTemplateLookup() { if (this->SortedArray) { this->SortedArray->Delete(); this->SortedArray = NULL; } if (this->IndexArray) { this->IndexArray->Delete(); this->IndexArray = NULL; } } vtkAbstractArray* SortedArray; vtkIdList* IndexArray; vtkstd::multimap CachedUpdates; bool Rebuild; }; //---------------------------------------------------------------------------- template vtkDataArrayTemplate::vtkDataArrayTemplate(vtkIdType numComp): vtkDataArray(numComp) { this->Array = 0; this->Tuple = 0; this->TupleSize = 0; this->SaveUserArray = 0; this->DeleteMethod = VTK_DATA_ARRAY_FREE; this->Lookup = 0; this->ValueRange[0] = 0; this->ValueRange[1] = 1; } //---------------------------------------------------------------------------- template vtkDataArrayTemplate::~vtkDataArrayTemplate() { this->DeleteArray(); if(this->Tuple) { free(this->Tuple); } if(this->Lookup) { delete this->Lookup; } } //---------------------------------------------------------------------------- // 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, int deleteMethod) { this->DeleteArray(); vtkDebugMacro(<<"Setting array to: " << static_cast(array)); this->Array = array; this->Size = size; this->MaxId = size-1; this->SaveUserArray = save; this->DeleteMethod = deleteMethod; this->DataChanged(); } //---------------------------------------------------------------------------- // 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) { this->DeleteArray(); this->Size = 0; vtkIdType newSize = (sz > 0 ? sz : 1); this->Array = static_cast(malloc(static_cast(newSize) * sizeof(T))); if(this->Array==0) { vtkErrorMacro("Unable to allocate " << newSize << " elements of size " << sizeof(T) << " 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 vtkstd::bad_alloc(); #else // We indicate that malloc failed by return return 0; #endif } this->Size = newSize; } this->DataChanged(); return 1; } //---------------------------------------------------------------------------- // Release storage and reset array to initial state. template void vtkDataArrayTemplate::Initialize() { this->DeleteArray(); this->Array = 0; this->Size = 0; this->MaxId = -1; this->DataChanged(); } //---------------------------------------------------------------------------- // 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); this->DataChanged(); return; } // Free our previous memory. this->DeleteArray(); // Copy the given array into new memory. this->NumberOfComponents = fa->GetNumberOfComponents(); this->MaxId = fa->GetMaxId(); this->Size = fa->GetSize(); this->Size = (this->Size > 0 ? this->Size : 1); this->Array = static_cast( malloc(static_cast(this->Size) * sizeof(T))); if(this->Array==0) { vtkErrorMacro("Unable to allocate " << this->Size << " elements of size " << sizeof(T) << " 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 vtkstd::bad_alloc(); #else // We indicate that malloc failed by return this->Size = 0; this->NumberOfComponents = 0; this->MaxId = -1; return; #endif } if (fa->GetSize() > 0) { memcpy(this->Array, fa->GetVoidPointer(0), static_cast(this->Size)*sizeof(T)); } this->vtkAbstractArray::DeepCopy( fa ); this->DataChanged(); } //---------------------------------------------------------------------------- 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"; } } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::DeleteArray() { if ((this->Array) && (!this->SaveUserArray)) { if (this->DeleteMethod == VTK_DATA_ARRAY_FREE) { free(this->Array); } else { delete[] this->Array; } } this->SaveUserArray = 0; this->DeleteMethod = VTK_DATA_ARRAY_FREE; this->Array = 0; } //---------------------------------------------------------------------------- template T* vtkDataArrayTemplate::ResizeAndExtend(vtkIdType sz, bool useExactSize) { 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 = sz + (useExactSize ? 0 : this->Size); } 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; this->DataChanged(); } // Wipe out the array completely if new size is zero. if(newSize <= 0) { this->Initialize(); return 0; } // OS X's realloc does not free memory if the new block is smaller. This // is a very serious problem and causes huge amount of memory to be // wasted. Do not use realloc on the Mac. bool dontUseRealloc=false; #if defined __APPLE__ dontUseRealloc=true; #endif // Allocate the new array or reallocate the old. if (this->Array && (this->SaveUserArray || this->DeleteMethod==VTK_DATA_ARRAY_DELETE || dontUseRealloc )) { newArray = static_cast(malloc(static_cast(newSize)*sizeof(T))); if(!newArray) { vtkErrorMacro("Unable to allocate " << newSize << " elements of size " << sizeof(T) << " 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 vtkstd::bad_alloc(); #else // We indicate that malloc failed by return return 0; #endif } // Copy the data from the old array. memcpy(newArray, this->Array, static_cast(newSize < this->Size ? newSize : this->Size) * sizeof(T)); // Realease old array if we own this->DeleteArray(); } else { // Try to reallocate with minimal memory usage and possibly avoid // copying. newArray = static_cast( realloc(this->Array,static_cast(newSize)*sizeof(T))); if(!newArray) { vtkErrorMacro("Unable to allocate " << newSize << " elements of size " << sizeof(T) << " 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 vtkstd::bad_alloc(); #else // We indicate that malloc failed by return return 0; #endif } } // Allocation was successful. Save it. if((newSize-1) < this->MaxId) { this->MaxId = newSize-1; } this->Size = newSize; this->Array = newArray; return this->Array; } //---------------------------------------------------------------------------- template int vtkDataArrayTemplate::Resize(vtkIdType sz) { this->DataChanged(); T *newArray = this->ResizeAndExtend(sz*this->NumberOfComponents, true); if( newArray!=0 || 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); this->DataChanged(); } //---------------------------------------------------------------------------- // Set the tuple at the ith location using the jth tuple in the source array. // This method assumes that the two arrays have the same type // and structure. Note that range checking and memory allocation is not // performed; use in conjunction with SetNumberOfTuples() to allocate space. template void vtkDataArrayTemplate::SetTuple(vtkIdType i, vtkIdType j, vtkAbstractArray* source) { if (source->GetDataType() != this->GetDataType()) { vtkWarningMacro("Input and output array data types do not match."); return; } if (this->NumberOfComponents != source->GetNumberOfComponents()) { vtkWarningMacro("Input and output component sizes do not match."); return; } vtkIdType loci = i * this->NumberOfComponents; vtkIdType locj = j * source->GetNumberOfComponents(); T* data = static_cast(source->GetVoidPointer(0)); for (vtkIdType cur = 0; cur < this->NumberOfComponents; cur++) { this->Array[loci + cur] = data[locj + cur]; } this->DataChanged(); } //---------------------------------------------------------------------------- // Insert the jth tuple in the source array, at ith location in this array. // Note that memory allocation is performed as necessary to hold the data. template void vtkDataArrayTemplate::InsertTuple(vtkIdType i, vtkIdType j, vtkAbstractArray* source) { if (source->GetDataType() != this->GetDataType()) { vtkWarningMacro("Input and output array data types do not match."); return; } int inNumComp = source->GetNumberOfComponents(); if (this->NumberOfComponents != inNumComp) { vtkWarningMacro("Input and output component sizes do not match."); return; } vtkIdType locOut = i * inNumComp; vtkIdType maxSize = locOut + inNumComp; if (maxSize > this->Size) { if (this->ResizeAndExtend(maxSize,false)==0) { return; } } vtkIdType locIn = j * inNumComp; T* outPtr = this->GetPointer(locOut); T* inPtr = static_cast(source->GetVoidPointer(locIn)); size_t s=static_cast(inNumComp); memcpy(outPtr, inPtr, s*sizeof(T)); vtkIdType maxId = maxSize-1; if ( maxId > this->MaxId ) { this->MaxId = maxId; } this->DataChanged(); } //---------------------------------------------------------------------------- // Insert the jth tuple in the source array, at the end in this array. // Note that memory allocation is performed as necessary to hold the data. // Returns the location at which the data was inserted. template vtkIdType vtkDataArrayTemplate::InsertNextTuple(vtkIdType j, vtkAbstractArray* source) { if (source->GetDataType() != this->GetDataType()) { vtkWarningMacro("Input and output array data types do not match."); return -1; } if (this->NumberOfComponents != source->GetNumberOfComponents()) { vtkWarningMacro("Input and output component sizes do not match."); return -1; } // If this and source are the same, we need to make sure that // the array grows before we get the pointer. Growing the array // after getting the pointer may make it invalid. if (this == source) { if (this->ResizeAndExtend(this->Size+1,false)==0) { return -1; } } T* data = static_cast(source->GetVoidPointer(0)); vtkIdType locj = j * source->GetNumberOfComponents(); for (vtkIdType cur = 0; cur < this->NumberOfComponents; cur++) { this->InsertNextValue(data[locj + cur]); } return (this->GetNumberOfTuples()-1); } //---------------------------------------------------------------------------- // 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 1 // Allocate a larger tuple buffer if needed. if(this->TupleSize < this->NumberOfComponents) { this->TupleSize = this->NumberOfComponents; free(this->Tuple); size_t s=static_cast(this->TupleSize); this->Tuple = static_cast(malloc(s*sizeof(double))); } // Make sure tuple allocation succeeded. if(!this->Tuple) { vtkErrorMacro("Unable to allocate " << this->TupleSize << " elements of size " << sizeof(double) << " 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 vtkstd::bad_alloc(); #else // We indicate that malloc failed by return return 0; #endif } // 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. "); #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 vtkstd::bad_alloc(); #else // We indicate that malloc failed by return return 0; #endif } // 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]); } this->DataChanged(); } 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]); } this->DataChanged(); } 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]; } this->DataChanged(); } //---------------------------------------------------------------------------- // 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); if (t==0) { return; } for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } this->DataChanged(); } template void vtkDataArrayTemplate::InsertTuple(vtkIdType i, const double* tuple) { T* t = this->WritePointer(i*this->NumberOfComponents, this->NumberOfComponents); if (t==0) { return; } for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } this->DataChanged(); } template void vtkDataArrayTemplate::InsertTupleValue(vtkIdType i, const T* tuple) { T* t = this->WritePointer(i*this->NumberOfComponents, this->NumberOfComponents); if (t==0) { return; } for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = *tuple++; } this->DataChanged(); } //---------------------------------------------------------------------------- // 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); if (t==0) { return -1; } for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } this->DataChanged(); return this->MaxId / this->NumberOfComponents; } template vtkIdType vtkDataArrayTemplate::InsertNextTuple(const double* tuple) { T* t = this->WritePointer(this->MaxId + 1,this->NumberOfComponents); if (t==0) { return -1; } for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = static_cast(*tuple++); } this->DataChanged(); return this->MaxId / this->NumberOfComponents; } template vtkIdType vtkDataArrayTemplate::InsertNextTupleValue(const T* tuple) { T* t = this->WritePointer(this->MaxId + 1,this->NumberOfComponents); if (t==0) { return -1; } for(int j=0; j < this->NumberOfComponents; ++j) { *t++ = *tuple++; } this->DataChanged(); return this->MaxId / this->NumberOfComponents; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::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; } // Remove the element by moving those after it over by one. We must // use memmove instead of memcpy because the memory areas overlap. vtkIdType len = (this->GetNumberOfTuples() - id) - 1; len *= this->GetNumberOfComponents(); vtkIdType from = (id+1) * this->GetNumberOfComponents(); vtkIdType to = id * this->GetNumberOfComponents(); memmove(this->Array + to, this->Array + from, static_cast(len) * sizeof(T)); this->Resize(this->GetNumberOfTuples() - 1); this->DataChanged(); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::RemoveFirstTuple() { this->RemoveTuple(0); this->DataChanged(); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::RemoveLastTuple() { this->Resize(this->GetNumberOfTuples()- 1); this->DataChanged(); } //---------------------------------------------------------------------------- // 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; } this->DataChanged(); } //---------------------------------------------------------------------------- template T* vtkDataArrayTemplate::WritePointer(vtkIdType id, vtkIdType number) { vtkIdType newSize=id+number; if ( newSize > this->Size ) { if (this->ResizeAndExtend(newSize,false)==0) { return 0; } } if ( (--newSize) > this->MaxId ) { this->MaxId = newSize; } this->DataChanged(); return this->Array + id; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::InsertValue(vtkIdType id, T f) { if ( id >= this->Size ) { if (this->ResizeAndExtend(id+1,false)==0) { return; } } this->Array[id] = f; if ( id > this->MaxId ) { this->MaxId = id; } this->DataElementChanged(id); } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::SetVariantValue(vtkIdType id, vtkVariant value) { T* dummyPtr = 0; bool valid; T toInsert = value.ToNumeric(&valid, dummyPtr); if (valid) { this->SetValue(id, toInsert); } else { vtkErrorMacro("unable to set value of type " << value.GetType()); } } //---------------------------------------------------------------------------- template vtkIdType vtkDataArrayTemplate::InsertNextValue(T f) { this->InsertValue (++this->MaxId,f); return this->MaxId; } //---------------------------------------------------------------------------- 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] = {vtkTypeTraits::Max(), vtkTypeTraits::Min()}; for(T* i = begin; i != end; i += numComp) { T s = *i; if(s < range[0]) { range[0] = s; } if(s > range[1]) { range[1] = s; } } // Store the range. this->ValueRange[0] = range[0]; this->ValueRange[1] = range[1]; this->Range[0] = static_cast(range[0]); this->Range[1] = static_cast(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 = static_cast(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, static_cast(this->MaxId + 1)*sizeof(T)); } } //---------------------------------------------------------------------------- template vtkArrayIterator* vtkDataArrayTemplate::NewIterator() { vtkArrayIteratorTemplate* iter = vtkArrayIteratorTemplate::New(); iter->Initialize(this); return iter; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::UpdateLookup() { if (!this->Lookup) { this->Lookup = new vtkDataArrayTemplateLookup(); this->Lookup->SortedArray = vtkAbstractArray::CreateArray(this->GetDataType()); this->Lookup->IndexArray = vtkIdList::New(); this->Lookup->Rebuild = true; } if (this->Lookup->Rebuild) { int numComps = this->GetNumberOfComponents(); vtkIdType numTuples = this->GetNumberOfTuples(); this->Lookup->SortedArray->DeepCopy(this); this->Lookup->IndexArray->SetNumberOfIds(numComps*numTuples); for (vtkIdType i = 0; i < numComps*numTuples; i++) { this->Lookup->IndexArray->SetId(i, i); } vtkSortDataArray::Sort(this->Lookup->SortedArray, this->Lookup->IndexArray); this->Lookup->Rebuild = false; this->Lookup->CachedUpdates.clear(); } } //---------------------------------------------------------------------------- template vtkIdType vtkDataArrayTemplate::LookupValue(vtkVariant var) { T* dummyPtr = 0; bool valid = true; T value = var.ToNumeric(&valid, dummyPtr); if (valid) { return this->LookupValue(value); } return -1; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::LookupValue(vtkVariant var, vtkIdList* ids) { T* dummyPtr = 0; bool valid = true; T value = var.ToNumeric(&valid, dummyPtr); ids->Reset(); if (valid) { this->LookupValue(value, ids); } } //---------------------------------------------------------------------------- template vtkIdType vtkDataArrayTemplate::LookupValue(T value) { this->UpdateLookup(); // First look into the cached updates, to see if there were any // cached changes. Find an equivalent element in the set of cached // indices for this value. Some of the indices may have changed // values since the cache was built, so we need to do this equality // check. typedef typename vtkstd::multimap::iterator CacheIterator; CacheIterator cached = this->Lookup->CachedUpdates.lower_bound(value), cachedEnd = this->Lookup->CachedUpdates.end(); while (cached != cachedEnd) { // Check that we are still in the same equivalence class as the // value. if (value == cached->first) { // Check that the value in the original array hasn't changed. T currentValue = this->GetValue(cached->second); if (value == currentValue) { return cached->second; } } else { break; } ++cached; } // The index array can have size zero even when the // sorted array is of size 1, due to vtkDataArrayTemplate::DeepCopy's // refusal to allocate a 0-length array. if (this->Lookup->IndexArray->GetNumberOfIds() == 0) { return -1; } int numComps = this->Lookup->SortedArray->GetNumberOfComponents(); vtkIdType numTuples = this->Lookup->SortedArray->GetNumberOfTuples(); T* ptr = static_cast(this->Lookup->SortedArray->GetVoidPointer(0)); T* ptrEnd = ptr + numComps*numTuples; T* found = vtkstd::lower_bound(ptr, ptrEnd, value); // Find an index with a matching value. Non-matching values might // show up here when the underlying value at that index has been // changed (so the sorted array is out-of-date). vtkIdType offset = static_cast(found - ptr); while (found != ptrEnd) { // Check whether we still have a value equivalent to what we're // looking for. if (value == *found) { // Check that the value in the original array hasn't changed. vtkIdType index = this->Lookup->IndexArray->GetId(offset); T currentValue = this->GetValue(index); if (value == currentValue) { return index; } } else { break; } ++found; ++offset; } return -1; } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::LookupValue(T value, vtkIdList* ids) { this->UpdateLookup(); ids->Reset(); // First look into the cached updates, to see if there were any // cached changes. Find an equivalent element in the set of cached // indices for this value. Some of the indices may have changed // values since the cache was built, so we need to do this equality // check. typedef typename vtkstd::multimap::iterator CacheIterator; vtkstd::pair cached = this->Lookup->CachedUpdates.equal_range(value); while (cached.first != cached.second) { // Check that the value in the original array hasn't changed. T currentValue = this->GetValue(cached.first->second); if (cached.first->first == currentValue) { ids->InsertNextId(cached.first->second); } ++cached.first; } // The index array can have size zero even when the // sorted array is of size 1, due to vtkDataArrayTemplate::DeepCopy's // refusal to allocate a 0-length array. if (this->Lookup->IndexArray->GetNumberOfIds() == 0) { return; } // Perform a binary search of the sorted array using STL equal_range. int numComps = this->GetNumberOfComponents(); vtkIdType numTuples = this->GetNumberOfTuples(); T* ptr = static_cast(this->Lookup->SortedArray->GetVoidPointer(0)); vtkstd::pair found = vtkstd::equal_range(ptr, ptr + numComps*numTuples, value); // Add the indices of the found items to the ID list. vtkIdType offset = static_cast(found.first - ptr); while (found.first != found.second) { // Check that the value in the original array hasn't changed. vtkIdType index = this->Lookup->IndexArray->GetId(offset); T currentValue = this->GetValue(index); if (*found.first == currentValue) { ids->InsertNextId(index); } ++found.first; ++offset; } } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::DataChanged() { if (this->Lookup) { this->Lookup->Rebuild = true; } } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::DataElementChanged(vtkIdType id) { if (this->Lookup) { if (this->Lookup->Rebuild) { // We're already going to rebuild the lookup table. Do nothing. return; } if (this->Lookup->CachedUpdates.size() > static_cast(this->GetNumberOfTuples()/10)) { // At this point, just rebuild the full table. this->Lookup->Rebuild = true; } else { // Insert this change into the set of cached updates vtkstd::pair value(this->GetValue(id), id); this->Lookup->CachedUpdates.insert(value); } } } //---------------------------------------------------------------------------- template void vtkDataArrayTemplate::ClearLookup() { if (this->Lookup) { delete this->Lookup; this->Lookup = NULL; } } #endif