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