1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkSortDataArray.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm 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 /*
17 * Copyright 2003 Sandia Corporation.
18 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
19 * license for use of this work by or on behalf of the
20 * U.S. Government. Redistribution and use in source and binary forms, with
21 * or without modification, are permitted provided that this Notice and any
22 * statement of authorship are reproduced on all copies.
23 */
24
25 #include "vtkSortDataArray.h"
26
27 #include "vtkAbstractArray.h"
28 #include "vtkIdList.h"
29 #include "vtkMath.h"
30 #include "vtkObjectFactory.h"
31 #include "vtkSMPTools.h"
32 #include "vtkStdString.h"
33 #include "vtkStringArray.h"
34 #include "vtkVariant.h"
35 #include "vtkVariantArray.h"
36 #include <functional> //std::greater
37
38 //------------------------------------------------------------------------------
39
40 vtkStandardNewMacro(vtkSortDataArray);
41
42 //------------------------------------------------------------------------------
43 vtkSortDataArray::vtkSortDataArray() = default;
44
45 //------------------------------------------------------------------------------
46 vtkSortDataArray::~vtkSortDataArray() = default;
47
48 //------------------------------------------------------------------------------
Sort(vtkIdList * keys,int dir)49 void vtkSortDataArray::Sort(vtkIdList* keys, int dir)
50 {
51 if (keys == nullptr)
52 {
53 return;
54 }
55 vtkIdType* data = keys->GetPointer(0);
56 vtkIdType numKeys = keys->GetNumberOfIds();
57 if (dir == 0)
58 {
59 vtkSMPTools::Sort(data, data + numKeys);
60 }
61 else
62 {
63 vtkSMPTools::Sort(data, data + numKeys, std::greater<vtkIdType>());
64 }
65 }
66
67 //------------------------------------------------------------------------------
Sort(vtkAbstractArray * keys,int dir)68 void vtkSortDataArray::Sort(vtkAbstractArray* keys, int dir)
69 {
70 if (keys == nullptr)
71 {
72 return;
73 }
74
75 if (keys->GetNumberOfComponents() != 1)
76 {
77 vtkGenericWarningMacro("Can only sort keys that are 1-tuples.");
78 return;
79 }
80
81 void* data = keys->GetVoidPointer(0);
82 vtkIdType numKeys = keys->GetNumberOfTuples();
83
84 if (dir == 0)
85 {
86 switch (keys->GetDataType())
87 {
88 vtkExtendedTemplateMacro(
89 vtkSMPTools::Sort(static_cast<VTK_TT*>(data), static_cast<VTK_TT*>(data) + numKeys));
90 }
91 }
92 else
93 {
94 switch (keys->GetDataType())
95 {
96 vtkExtendedTemplateMacro(vtkSMPTools::Sort(
97 static_cast<VTK_TT*>(data), static_cast<VTK_TT*>(data) + numKeys, std::greater<VTK_TT>()));
98 }
99 }
100 }
101
102 //------------------------------------------------------------------------------
103 // Hide some stuff; mostly things plugged into templated functions
104 namespace
105 {
106
107 //------------------------------------------------------------------------------
108 // We sort the indices based on a key value in another array. Produces sort
109 // in ascending direction. Note that sort comparison operator is for single
110 // component arrays.
111 template <typename T>
112 struct KeyComp
113 {
114 const T* Array;
KeyComp__anon7d4c914e0111::KeyComp115 KeyComp(T* array)
116 : Array(array)
117 {
118 }
operator ()__anon7d4c914e0111::KeyComp119 bool operator()(vtkIdType idx0, vtkIdType idx1) const { return (Array[idx0] < Array[idx1]); }
120 };
121
122 //------------------------------------------------------------------------------
123 // Special comparison functor using tuple component as a key. Note that this
124 // comparison function is for general arrays of n components.
125 template <typename T>
126 struct TupleComp
127 {
128 const T* Array;
129 int NumComp;
130 int K;
TupleComp__anon7d4c914e0111::TupleComp131 TupleComp(T* array, int n, int k)
132 : Array(array)
133 , NumComp(n)
134 , K(k)
135 {
136 }
operator ()__anon7d4c914e0111::TupleComp137 bool operator()(vtkIdType idx0, vtkIdType idx1) const
138 {
139 return Array[idx0 * NumComp + K] < Array[idx1 * NumComp + K];
140 }
141 };
142
143 //------------------------------------------------------------------------------
144 // Given a set of indices (after sorting), copy the data from a pre-sorted
145 // array to a final, post-sorted array, Implementation note: the direction of
146 // sort (dir) is treated here rather than in the std::sort() function to
147 // reduce object file .obj size; e.g., running std::sort with a different
148 // comporator function causes inline expansion to produce very large object
149 // files.
150 template <typename T>
Shuffle1Tuples(vtkIdType * idx,vtkIdType sze,vtkAbstractArray * arrayIn,T * preSort,int dir)151 void Shuffle1Tuples(vtkIdType* idx, vtkIdType sze, vtkAbstractArray* arrayIn, T* preSort, int dir)
152 {
153 T* postSort = new T[sze];
154
155 if (dir == 0) // ascending
156 {
157 for (vtkIdType i = 0; i < sze; ++i)
158 {
159 postSort[i] = preSort[idx[i]];
160 }
161 }
162 else
163 {
164 vtkIdType end = sze - 1;
165 for (vtkIdType i = 0; i < sze; ++i)
166 {
167 postSort[i] = preSort[idx[end - i]];
168 }
169 }
170
171 arrayIn->SetVoidArray(postSort, sze, 0, vtkAbstractArray::VTK_DATA_ARRAY_DELETE);
172 }
173
174 //------------------------------------------------------------------------------
175 // Given a set of indices (after sorting), copy the data from a pre-sorted
176 // data array to a final, post-sorted array. Note that the data array is
177 // assumed to have arbitrary sized components.
178 template <typename T>
ShuffleTuples(vtkIdType * idx,vtkIdType sze,int numComp,vtkAbstractArray * arrayIn,T * preSort,int dir)179 void ShuffleTuples(
180 vtkIdType* idx, vtkIdType sze, int numComp, vtkAbstractArray* arrayIn, T* preSort, int dir)
181 {
182 T* postSort = new T[sze * numComp];
183
184 int k;
185 vtkIdType i;
186 if (dir == 0) // ascending
187 {
188 for (i = 0; i < sze; ++i)
189 {
190 for (k = 0; k < numComp; ++k)
191 {
192 postSort[i * numComp + k] = preSort[idx[i] * numComp + k];
193 }
194 }
195 }
196 else
197 {
198 vtkIdType end = sze - 1;
199 for (i = 0; i < sze; ++i)
200 {
201 for (k = 0; k < numComp; ++k)
202 {
203 postSort[i * numComp + k] = preSort[idx[end - i] * numComp + k];
204 }
205 }
206 }
207
208 arrayIn->SetVoidArray(postSort, sze * numComp, 0, vtkAbstractArray::VTK_DATA_ARRAY_DELETE);
209 }
210
211 } // anonymous namespace
212
213 //------------------------------------------------------------------------------
214 // Allocate and initialize sort indices
InitializeSortIndices(vtkIdType num)215 vtkIdType* vtkSortDataArray::InitializeSortIndices(vtkIdType num)
216 {
217 vtkIdType* idx = new vtkIdType[num];
218 for (vtkIdType i = 0; i < num; ++i)
219 {
220 idx[i] = i;
221 }
222 return idx;
223 }
224
225 //------------------------------------------------------------------------------
226 // Efficient function for generating sort ordering specialized to single
227 // component arrays.
GenerateSort1Indices(int dataType,void * dataIn,vtkIdType numKeys,vtkIdType * idx)228 void vtkSortDataArray::GenerateSort1Indices(
229 int dataType, void* dataIn, vtkIdType numKeys, vtkIdType* idx)
230 {
231 if (dataType == VTK_VARIANT)
232 {
233 vtkSMPTools::Sort(idx, idx + numKeys, KeyComp<vtkVariant>(static_cast<vtkVariant*>(dataIn)));
234 }
235 else
236 {
237 switch (dataType)
238 {
239 vtkExtendedTemplateMacro(
240 vtkSMPTools::Sort(idx, idx + numKeys, KeyComp<VTK_TT>(static_cast<VTK_TT*>(dataIn))));
241 }
242 }
243 }
244
245 //------------------------------------------------------------------------------
246 // Function for generating sort ordering for general arrays.
GenerateSortIndices(int dataType,void * dataIn,vtkIdType numKeys,int numComp,int k,vtkIdType * idx)247 void vtkSortDataArray::GenerateSortIndices(
248 int dataType, void* dataIn, vtkIdType numKeys, int numComp, int k, vtkIdType* idx)
249 {
250 // Specialized and faster for single component arrays
251 if (numComp == 1)
252 {
253 return vtkSortDataArray::GenerateSort1Indices(dataType, dataIn, numKeys, idx);
254 }
255
256 if (dataType == VTK_VARIANT)
257 {
258 vtkSMPTools::Sort(
259 idx, idx + numKeys, TupleComp<vtkVariant>(static_cast<vtkVariant*>(dataIn), numComp, k));
260 }
261 else
262 {
263 switch (dataType)
264 {
265 vtkExtendedTemplateMacro(vtkSMPTools::Sort(
266 idx, idx + numKeys, TupleComp<VTK_TT>(static_cast<VTK_TT*>(dataIn), numComp, k)));
267 }
268 }
269 }
270
271 //------------------------------------------------------------------------------
272 // Set up the actual templated shuffling operation. This method is for
273 // VTK arrays that are precsisely one component.
Shuffle1Array(vtkIdType * idx,int dataType,vtkIdType numKeys,vtkAbstractArray * arr,void * dataIn,int dir)274 void vtkSortDataArray::Shuffle1Array(
275 vtkIdType* idx, int dataType, vtkIdType numKeys, vtkAbstractArray* arr, void* dataIn, int dir)
276 {
277 if (dataType == VTK_VARIANT)
278 {
279 Shuffle1Tuples(idx, numKeys, arr, static_cast<vtkVariant*>(dataIn), dir);
280 }
281 else
282 {
283 switch (arr->GetDataType())
284 {
285 vtkExtendedTemplateMacro(
286 Shuffle1Tuples(idx, numKeys, arr, static_cast<VTK_TT*>(dataIn), dir));
287 }
288 }
289 }
290
291 //------------------------------------------------------------------------------
292 // Set up the actual templated shuffling operation
ShuffleArray(vtkIdType * idx,int dataType,vtkIdType numKeys,int numComp,vtkAbstractArray * arr,void * dataIn,int dir)293 void vtkSortDataArray::ShuffleArray(vtkIdType* idx, int dataType, vtkIdType numKeys, int numComp,
294 vtkAbstractArray* arr, void* dataIn, int dir)
295 {
296 // Specialized for single component arrays
297 if (numComp == 1)
298 {
299 return vtkSortDataArray::Shuffle1Array(idx, dataType, numKeys, arr, dataIn, dir);
300 }
301
302 if (dataType == VTK_VARIANT)
303 {
304 ShuffleTuples(idx, numKeys, numComp, arr, static_cast<vtkVariant*>(dataIn), dir);
305 }
306 else
307 {
308 switch (arr->GetDataType())
309 {
310 vtkExtendedTemplateMacro(
311 ShuffleTuples(idx, numKeys, numComp, arr, static_cast<VTK_TT*>(dataIn), dir));
312 }
313 }
314 }
315
316 //------------------------------------------------------------------------------
317 // Given a set of indices (after sorting), copy the ids from a pre-sorted
318 // id array to a final, post-sorted array.
ShuffleIdList(vtkIdType * idx,vtkIdType sze,vtkIdList * arrayIn,vtkIdType * preSort,int dir)319 void vtkSortDataArray::ShuffleIdList(
320 vtkIdType* idx, vtkIdType sze, vtkIdList* arrayIn, vtkIdType* preSort, int dir)
321 {
322 vtkIdType* postSort = new vtkIdType[sze];
323
324 if (dir == 0) // ascending
325 {
326 for (vtkIdType i = 0; i < sze; ++i)
327 {
328 postSort[i] = preSort[idx[i]];
329 }
330 }
331 else
332 {
333 vtkIdType end = sze - 1;
334 for (vtkIdType i = 0; i < sze; ++i)
335 {
336 postSort[i] = preSort[idx[end - i]];
337 }
338 }
339
340 arrayIn->SetArray(postSort, sze);
341 }
342
343 //------------------------------------------------------------------------------
344 // Sort a position index based on the values in the abstract array. Once
345 // sorted, then shuffle the keys and values around into new arrays.
Sort(vtkAbstractArray * keys,vtkAbstractArray * values,int dir)346 void vtkSortDataArray::Sort(vtkAbstractArray* keys, vtkAbstractArray* values, int dir)
347 {
348 // Check input
349 if (keys == nullptr || values == nullptr)
350 {
351 return;
352 }
353 if (keys->GetNumberOfComponents() != 1)
354 {
355 vtkGenericWarningMacro("Can only sort keys that are 1-tuples.");
356 return;
357 }
358 vtkIdType numKeys = keys->GetNumberOfTuples();
359 vtkIdType numValues = values->GetNumberOfTuples();
360 if (numKeys != numValues)
361 {
362 vtkGenericWarningMacro("Could not sort arrays. Key and value arrays have different sizes.");
363 return;
364 }
365
366 // Sort the index array
367 vtkIdType* idx = vtkSortDataArray::InitializeSortIndices(numKeys);
368
369 // Generate the sorting index array
370 void* dataIn = keys->GetVoidPointer(0);
371 int numComp = 1;
372 int dataType = keys->GetDataType();
373 vtkSortDataArray::GenerateSortIndices(dataType, dataIn, numKeys, numComp, 0, idx);
374
375 // Now shuffle data around based on sorted indices
376 vtkSortDataArray::ShuffleArray(idx, dataType, numKeys, numComp, keys, dataIn, dir);
377
378 dataIn = values->GetVoidPointer(0);
379 numComp = values->GetNumberOfComponents();
380 dataType = values->GetDataType();
381 vtkSortDataArray::ShuffleArray(idx, dataType, numKeys, numComp, values, dataIn, dir);
382
383 // Clean up
384 delete[] idx;
385 }
386
387 //------------------------------------------------------------------------------
Sort(vtkAbstractArray * keys,vtkIdList * values,int dir)388 void vtkSortDataArray::Sort(vtkAbstractArray* keys, vtkIdList* values, int dir)
389 {
390 // Check input
391 if (keys == nullptr || values == nullptr)
392 {
393 return;
394 }
395 if (keys->GetNumberOfComponents() != 1)
396 {
397 vtkGenericWarningMacro("Can only sort keys that are 1-tuples.");
398 return;
399 }
400 vtkIdType numKeys = keys->GetNumberOfTuples();
401 vtkIdType numIds = values->GetNumberOfIds();
402 if (numKeys != numIds)
403 {
404 vtkGenericWarningMacro("Could not sort arrays. Key and id arrays have different sizes.");
405 return;
406 }
407
408 // Sort the index array
409 vtkIdType* idx = vtkSortDataArray::InitializeSortIndices(numKeys);
410
411 // Generate the sorting index array
412 void* dataIn = keys->GetVoidPointer(0);
413 int numComp = 1;
414 int dataType = keys->GetDataType();
415 vtkSortDataArray::GenerateSortIndices(dataType, dataIn, numKeys, numComp, 0, idx);
416
417 // Shuffle the keys
418 vtkSortDataArray::ShuffleArray(idx, dataType, numKeys, numComp, keys, dataIn, dir);
419
420 // Now shuffle the ids to match the sort
421 vtkIdType* ids = values->GetPointer(0);
422 ShuffleIdList(idx, numKeys, values, ids, dir);
423
424 // Clean up
425 delete[] idx;
426 }
427
428 //------------------------------------------------------------------------------
SortArrayByComponent(vtkAbstractArray * arr,int k,int dir)429 void vtkSortDataArray::SortArrayByComponent(vtkAbstractArray* arr, int k, int dir)
430 {
431 // Check input
432 if (arr == nullptr)
433 {
434 return;
435 }
436 vtkIdType numKeys = arr->GetNumberOfTuples();
437 int nc = arr->GetNumberOfComponents();
438
439 if (k < 0 || k >= nc)
440 {
441 vtkGenericWarningMacro(
442 "Cannot sort by column " << k << " since the array only has columns 0 through " << (nc - 1));
443 return;
444 }
445
446 // Perform the sort
447 vtkIdType* idx = vtkSortDataArray::InitializeSortIndices(numKeys);
448
449 void* dataIn = arr->GetVoidPointer(0);
450 int dataType = arr->GetDataType();
451 vtkSortDataArray::GenerateSortIndices(dataType, dataIn, numKeys, nc, k, idx);
452
453 vtkSortDataArray::ShuffleArray(idx, dataType, numKeys, nc, arr, dataIn, dir);
454
455 // Clean up
456 delete[] idx;
457 }
458
459 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)460 void vtkSortDataArray::PrintSelf(ostream& os, vtkIndent indent)
461 {
462 this->Superclass::PrintSelf(os, indent);
463 }
464
465 // vtkSortDataArray methods -------------------------------------------------------
466