1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: vtkArrayListTemplate.h 5 6 Copyright (c) Kitware, Inc. 7 All rights reserved. 8 See LICENSE file for details. 9 10 This software is distributed WITHOUT ANY WARRANTY; without even 11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 12 PURPOSE. See the above copyright notice for more information. 13 14 =========================================================================*/ 15 /** 16 * @class vtkArrayListTemplate 17 * @brief thread-safe and efficient data attribute processing 18 * 19 * 20 * vtkArrayListTemplate supplements the vtkDataSetAttributes class to provide 21 * threaded processing of data arrays. It is also more efficient for certain 22 * interpolation operations. The expectation is that it will be replaced one 23 * day once vtkPointData, vtkCellData, vtkDataSetAttributes, and vtkFieldData 24 * properly support multithreading and/or are redesigned. Note that this 25 * implementation does not support incremental operations (like InsertNext()). 26 * 27 * Generally the way this helper class is used is to first invoke 28 * vtkDataSetAttributes::CopyInterpolate() or InterpolateAllocate() which 29 * performs the initial magic of constructing input and output arrays. Then 30 * the input attributes, and output attributes, are passed to initialize the 31 * internal structures via the AddArrays() method. Essentially these internal 32 * structures are templated pairs of arrays of the same type, which can be 33 * efficiently accessed and assigned. The operations on these array pairs 34 * (e.g., interpolation) occur using a typeless, virtual dispatch base class. 35 * 36 * @warning 37 * vtkDataSetAttributes is not in general thread safe due to the use of its 38 * vtkFieldData::BasicIterator RequiredArrays data member. This class augments 39 * vtkDataSetAttributes for thread safety. 40 * 41 * @sa 42 * vtkFieldData vtkDataSetAttributes vtkPointData vtkCellData 43 */ 44 45 #ifndef vtkArrayListTemplate_h 46 #define vtkArrayListTemplate_h 47 48 #include "vtkDataArray.h" 49 #include "vtkDataSetAttributes.h" 50 #include "vtkSmartPointer.h" 51 #include "vtkStdString.h" 52 53 #include <algorithm> 54 #include <vector> 55 56 // Create a generic class supporting virtual dispatch to type-specific 57 // subclasses. 58 struct BaseArrayPair 59 { 60 vtkIdType Num; 61 int NumComp; 62 vtkSmartPointer<vtkDataArray> OutputArray; 63 BaseArrayPairBaseArrayPair64 BaseArrayPair(vtkIdType num, int numComp, vtkDataArray* outArray) 65 : Num(num) 66 , NumComp(numComp) 67 , OutputArray(outArray) 68 { 69 } 70 virtual ~BaseArrayPair() = default; 71 72 virtual void Copy(vtkIdType inId, vtkIdType outId) = 0; 73 virtual void Interpolate( 74 int numWeights, const vtkIdType* ids, const double* weights, vtkIdType outId) = 0; 75 virtual void Average(int numPts, const vtkIdType* ids, vtkIdType outId) = 0; 76 virtual void InterpolateEdge(vtkIdType v0, vtkIdType v1, double t, vtkIdType outId) = 0; 77 virtual void AssignNullValue(vtkIdType outId) = 0; 78 virtual void Realloc(vtkIdType sze) = 0; 79 }; 80 81 // Type specific interpolation on a matched pair of data arrays 82 template <typename T> 83 struct ArrayPair : public BaseArrayPair 84 { 85 T* Input; 86 T* Output; 87 T NullValue; 88 ArrayPairArrayPair89 ArrayPair(T* in, T* out, vtkIdType num, int numComp, vtkDataArray* outArray, T null) 90 : BaseArrayPair(num, numComp, outArray) 91 , Input(in) 92 , Output(out) 93 , NullValue(null) 94 { 95 } 96 ~ArrayPair() override = default; // calm down some finicky compilers 97 CopyArrayPair98 void Copy(vtkIdType inId, vtkIdType outId) override 99 { 100 for (int j = 0; j < this->NumComp; ++j) 101 { 102 this->Output[outId * this->NumComp + j] = this->Input[inId * this->NumComp + j]; 103 } 104 } 105 InterpolateArrayPair106 void Interpolate( 107 int numWeights, const vtkIdType* ids, const double* weights, vtkIdType outId) override 108 { 109 for (int j = 0; j < this->NumComp; ++j) 110 { 111 double v = 0.0; 112 for (vtkIdType i = 0; i < numWeights; ++i) 113 { 114 v += weights[i] * static_cast<double>(this->Input[ids[i] * this->NumComp + j]); 115 } 116 this->Output[outId * this->NumComp + j] = static_cast<T>(v); 117 } 118 } 119 AverageArrayPair120 void Average(int numPts, const vtkIdType* ids, vtkIdType outId) override 121 { 122 for (int j = 0; j < this->NumComp; ++j) 123 { 124 double v = 0.0; 125 for (vtkIdType i = 0; i < numPts; ++i) 126 { 127 v += static_cast<double>(this->Input[ids[i] * this->NumComp + j]); 128 } 129 v /= static_cast<double>(numPts); 130 this->Output[outId * this->NumComp + j] = static_cast<T>(v); 131 } 132 } 133 InterpolateEdgeArrayPair134 void InterpolateEdge(vtkIdType v0, vtkIdType v1, double t, vtkIdType outId) override 135 { 136 double v; 137 vtkIdType numComp = this->NumComp; 138 for (int j = 0; j < numComp; ++j) 139 { 140 v = this->Input[v0 * numComp + j] + 141 t * (this->Input[v1 * numComp + j] - this->Input[v0 * numComp + j]); 142 this->Output[outId * numComp + j] = static_cast<T>(v); 143 } 144 } 145 AssignNullValueArrayPair146 void AssignNullValue(vtkIdType outId) override 147 { 148 for (int j = 0; j < this->NumComp; ++j) 149 { 150 this->Output[outId * this->NumComp + j] = this->NullValue; 151 } 152 } 153 ReallocArrayPair154 void Realloc(vtkIdType sze) override 155 { 156 this->OutputArray->WriteVoidPointer(0, sze * this->NumComp); 157 this->Output = static_cast<T*>(this->OutputArray->GetVoidPointer(0)); 158 } 159 }; 160 161 // Type specific interpolation on a pair of data arrays with different types, where the 162 // output type is expected to be a real type (i.e., float or double). 163 template <typename TInput, typename TOutput> 164 struct RealArrayPair : public BaseArrayPair 165 { 166 TInput* Input; 167 TOutput* Output; 168 TOutput NullValue; 169 RealArrayPairRealArrayPair170 RealArrayPair( 171 TInput* in, TOutput* out, vtkIdType num, int numComp, vtkDataArray* outArray, TOutput null) 172 : BaseArrayPair(num, numComp, outArray) 173 , Input(in) 174 , Output(out) 175 , NullValue(null) 176 { 177 } 178 ~RealArrayPair() override = default; // calm down some finicky compilers 179 CopyRealArrayPair180 void Copy(vtkIdType inId, vtkIdType outId) override 181 { 182 for (int j = 0; j < this->NumComp; ++j) 183 { 184 this->Output[outId * this->NumComp + j] = 185 static_cast<TOutput>(this->Input[inId * this->NumComp + j]); 186 } 187 } 188 InterpolateRealArrayPair189 void Interpolate( 190 int numWeights, const vtkIdType* ids, const double* weights, vtkIdType outId) override 191 { 192 for (int j = 0; j < this->NumComp; ++j) 193 { 194 double v = 0.0; 195 for (vtkIdType i = 0; i < numWeights; ++i) 196 { 197 v += weights[i] * static_cast<double>(this->Input[ids[i] * this->NumComp + j]); 198 } 199 this->Output[outId * this->NumComp + j] = static_cast<TOutput>(v); 200 } 201 } 202 AverageRealArrayPair203 void Average(int numPts, const vtkIdType* ids, vtkIdType outId) override 204 { 205 for (int j = 0; j < this->NumComp; ++j) 206 { 207 double v = 0.0; 208 for (vtkIdType i = 0; i < numPts; ++i) 209 { 210 v += static_cast<double>(this->Input[ids[i] * this->NumComp + j]); 211 } 212 v /= static_cast<double>(numPts); 213 this->Output[outId * this->NumComp + j] = static_cast<TOutput>(v); 214 } 215 } 216 InterpolateEdgeRealArrayPair217 void InterpolateEdge(vtkIdType v0, vtkIdType v1, double t, vtkIdType outId) override 218 { 219 double v; 220 vtkIdType numComp = this->NumComp; 221 for (int j = 0; j < numComp; ++j) 222 { 223 v = this->Input[v0 * numComp + j] + 224 t * (this->Input[v1 * numComp + j] - this->Input[v0 * numComp + j]); 225 this->Output[outId * numComp + j] = static_cast<TOutput>(v); 226 } 227 } 228 AssignNullValueRealArrayPair229 void AssignNullValue(vtkIdType outId) override 230 { 231 for (int j = 0; j < this->NumComp; ++j) 232 { 233 this->Output[outId * this->NumComp + j] = this->NullValue; 234 } 235 } 236 ReallocRealArrayPair237 void Realloc(vtkIdType sze) override 238 { 239 this->OutputArray->WriteVoidPointer(0, sze * this->NumComp); 240 this->Output = static_cast<TOutput*>(this->OutputArray->GetVoidPointer(0)); 241 } 242 }; 243 244 // Forward declarations. This makes working with vtkTemplateMacro easier. 245 struct ArrayList; 246 247 template <typename T> 248 void CreateArrayPair( 249 ArrayList* list, T* inData, T* outData, vtkIdType numTuples, int numComp, T nullValue); 250 251 // A list of the arrays to interpolate, and a method to invoke interpolation on the list 252 struct ArrayList 253 { 254 // The list of arrays, and the arrays not to process 255 std::vector<BaseArrayPair*> Arrays; 256 std::vector<vtkDataArray*> ExcludedArrays; 257 258 // Add the arrays to interpolate here (from attribute data). Note that this method is 259 // not thread-safe due to its use of vtkDataSetAttributes. 260 void AddArrays(vtkIdType numOutPts, vtkDataSetAttributes* inPD, vtkDataSetAttributes* outPD, 261 double nullValue = 0.0, vtkTypeBool promote = true); 262 263 // Add an array that interpolates from its own attribute values 264 void AddSelfInterpolatingArrays( 265 vtkIdType numOutPts, vtkDataSetAttributes* attr, double nullValue = 0.0); 266 267 // Add a pair of arrays (manual insertion). Returns the output array created, 268 // if any. No array may be created if \c inArray was previously marked as 269 // excluded using ExcludeArray(). 270 vtkDataArray* AddArrayPair(vtkIdType numTuples, vtkDataArray* inArray, vtkStdString& outArrayName, 271 double nullValue, vtkTypeBool promote); 272 273 // Any array excluded here is not added by AddArrays() or AddArrayPair, hence not 274 // processed. Also check whether an array is excluded. 275 void ExcludeArray(vtkDataArray* da); 276 vtkTypeBool IsExcluded(vtkDataArray* da); 277 278 // Loop over the array pairs and copy data from one to another. This (and the following methods) 279 // can be used within threads. CopyArrayList280 void Copy(vtkIdType inId, vtkIdType outId) 281 { 282 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 283 { 284 (*it)->Copy(inId, outId); 285 } 286 } 287 288 // Loop over the arrays and have them interpolate themselves InterpolateArrayList289 void Interpolate(int numWeights, const vtkIdType* ids, const double* weights, vtkIdType outId) 290 { 291 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 292 { 293 (*it)->Interpolate(numWeights, ids, weights, outId); 294 } 295 } 296 297 // Loop over the arrays and have them averaged AverageArrayList298 void Average(int numPts, const vtkIdType* ids, vtkIdType outId) 299 { 300 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 301 { 302 (*it)->Average(numPts, ids, outId); 303 } 304 } 305 306 // Loop over the arrays perform edge interpolation InterpolateEdgeArrayList307 void InterpolateEdge(vtkIdType v0, vtkIdType v1, double t, vtkIdType outId) 308 { 309 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 310 { 311 (*it)->InterpolateEdge(v0, v1, t, outId); 312 } 313 } 314 315 // Loop over the arrays and assign the null value AssignNullValueArrayList316 void AssignNullValue(vtkIdType outId) 317 { 318 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 319 { 320 (*it)->AssignNullValue(outId); 321 } 322 } 323 324 // Extend (realloc) the arrays ReallocArrayList325 void Realloc(vtkIdType sze) 326 { 327 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 328 { 329 (*it)->Realloc(sze); 330 } 331 } 332 333 // Only you can prevent memory leaks! ~ArrayListArrayList334 ~ArrayList() 335 { 336 for (std::vector<BaseArrayPair*>::iterator it = Arrays.begin(); it != Arrays.end(); ++it) 337 { 338 delete (*it); 339 } 340 } 341 342 // Return the number of arrays GetNumberOfArraysArrayList343 vtkIdType GetNumberOfArrays() { return static_cast<vtkIdType>(Arrays.size()); } 344 }; 345 346 #include "vtkArrayListTemplate.txx" 347 348 #endif 349 // VTK-HeaderTest-Exclude: vtkArrayListTemplate.h 350