1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkCellArray.h
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 * @class vtkCellArray
17 * @brief object to represent cell connectivity
18 *
19 * vtkCellArray stores dataset topologies as an explicit connectivity table
20 * listing the point ids that make up each cell.
21 *
22 * Internally, the connectivity table is represented as two arrays: Offsets and
23 * Connectivity.
24 *
25 * Offsets is an array of [numCells+1] values indicating the index in the
26 * Connectivity array where each cell's points start. The last value is always
27 * the length of the Connectivity array.
28 *
29 * The Connectivity array stores the lists of point ids for each cell.
30 *
31 * Thus, for a dataset consisting of 2 triangles, a quad, and a line, the
32 * internal arrays will appear as follows:
33 *
34 * ```
35 * Topology:
36 * ---------
37 * Cell 0: Triangle | point ids: {0, 1, 2}
38 * Cell 1: Triangle | point ids: {5, 7, 2}
39 * Cell 2: Quad | point ids: {3, 4, 6, 7}
40 * Cell 4: Line | point ids: {5, 8}
41 *
42 * vtkCellArray (current):
43 * -----------------------
44 * Offsets: {0, 3, 6, 10, 12}
45 * Connectivity: {0, 1, 2, 5, 7, 2, 3, 4, 6, 7, 5, 8}
46 * ```
47 *
48 * While this class provides traversal methods (the legacy InitTraversal(),
49 * GetNextCell() methods, and the newer method GetCellAtId()) these are in
50 * general not thread-safe. Whenever possible it is preferrable to use a
51 * local thread-safe, vtkCellArrayIterator object, which can be obtained via:
52 *
53 * ```
54 * auto iter = vtk::TakeSmartPointer(cellArray->NewIterator());
55 * for (iter->GoToFirstCell(); !iter->IsDoneWithTraversal(); iter->GoToNextCell())
56 * {
57 * // do work with iter
58 * }
59 * ```
60 * (Note however that depending on the type and structure of internal
61 * storage, a cell array iterator may be significantly slower than direct
62 * traversal over the cell array due to extra data copying. Factors of 3-4X
63 * are not uncommon. See vtkCellArrayIterator for more information. Also note
64 * that an iterator may become invalid if the internal vtkCellArray storage
65 * is modified.)
66 *
67 * Other methods are also available for allocation and memory-related
68 * management; insertion of new cells into the vtkCellArray; and limited
69 * editing operations such as replacing one cell with a new cell of the
70 * same size.
71 *
72 * The internal arrays may store either 32- or 64-bit values, though most of
73 * the API will prefer to use vtkIdType to refer to items in these
74 * arrays. This enables significant memory savings when vtkIdType is 64-bit,
75 * but 32 bits are sufficient to store all of the values in the connectivity
76 * table. Using 64-bit storage with a 32-bit vtkIdType is permitted, but
77 * values too large to fit in a 32-bit signed integer will be truncated when
78 * accessed through the API. (The particular internal storage type has
79 * implications on performance depending on vtkIdType. If the internal
80 * storage is equivalent to vtkIdType, then methods that return pointers to
81 * arrays of point ids can share the internal storage; otherwise a copy of
82 * internal memory must be performed.)
83 *
84 * Methods for managing the storage type are:
85 *
86 * - `bool IsStorage64Bit()`
87 * - `bool IsStorageShareable() // Can pointers to internal storage be shared`
88 * - `void Use32BitStorage()`
89 * - `void Use64BitStorage()`
90 * - `void UseDefaultStorage() // Depends on vtkIdType`
91 * - `bool CanConvertTo32BitStorage()`
92 * - `bool CanConvertTo64BitStorage()`
93 * - `bool CanConvertToDefaultStorage() // Depends on vtkIdType`
94 * - `bool ConvertTo32BitStorage()`
95 * - `bool ConvertTo64BitStorage()`
96 * - `bool ConvertToDefaultStorage() // Depends on vtkIdType`
97 * - `bool ConvertToSmallestStorage() // Depends on current values in arrays`
98 *
99 * Note that some legacy methods are still available that reflect the
100 * previous storage format of this data, which embedded the cell sizes into
101 * the Connectivity array:
102 *
103 * ```
104 * vtkCellArray (legacy):
105 * ----------------------
106 * Connectivity: {3, 0, 1, 2, 3, 5, 7, 2, 4, 3, 4, 6, 7, 2, 5, 8}
107 * |--Cell 0--||--Cell 1--||----Cell 2---||--C3-|
108 * ```
109 *
110 * The methods require an external lookup table to allow random access, which
111 * was historically stored in the vtkCellTypes object. The following methods in
112 * vtkCellArray still support this style of indexing for compatibility
113 * purposes, but these are slow as they must perform some complex computations
114 * to convert the old "location" into the new "offset" and should be avoided.
115 * These methods (and their modern equivalents) are:
116 *
117 * - GetCell (Prefer GetCellAtId)
118 * - GetInsertLocation (Prefer GetNumberOfCells)
119 * - GetTraversalLocation (Prefer GetTraversalCellId, or better, NewIterator)
120 * - SetTraversalLocation (Prefer SetTraversalLocation, or better, NewIterator)
121 * - ReverseCell (Prefer ReverseCellAtId)
122 * - ReplaceCell (Prefer ReplaceCellAtId)
123 * - SetCells (Use ImportLegacyFormat, or SetData)
124 * - GetData (Use ExportLegacyFormat, or Get[Offsets|Connectivity]Array[|32|64])
125 *
126 * Some other legacy methods were completely removed, such as GetPointer() /
127 * WritePointer(), since they are cannot be effectively emulated under the
128 * current design. If external code needs to support both the old and new
129 * version of the vtkCellArray API, the VTK_CELL_ARRAY_V2 preprocessor
130 * definition may be used to detect which API is being compiled against.
131 *
132 * @sa vtkCellTypes vtkCellLinks
133 */
134
135 #ifndef vtkCellArray_h
136 #define vtkCellArray_h
137
138 #include "vtkCommonDataModelModule.h" // For export macro
139 #include "vtkObject.h"
140
141 #include "vtkAOSDataArrayTemplate.h" // Needed for inline methods
142 #include "vtkCell.h" // Needed for inline methods
143 #include "vtkDataArrayRange.h" // Needed for inline methods
144 #include "vtkFeatures.h" // for VTK_USE_MEMKIND
145 #include "vtkSmartPointer.h" // For vtkSmartPointer
146 #include "vtkTypeInt32Array.h" // Needed for inline methods
147 #include "vtkTypeInt64Array.h" // Needed for inline methods
148 #include "vtkTypeList.h" // Needed for ArrayList definition
149
150 #include <cassert> // for assert
151 #include <initializer_list> // for API
152 #include <type_traits> // for std::is_same
153 #include <utility> // for std::forward
154
155 /**
156 * @def VTK_CELL_ARRAY_V2
157 * @brief This preprocessor definition indicates that the updated vtkCellArray
158 * is being used. It may be used to conditionally switch between old and new
159 * API when both must be supported.
160 *
161 * For example:
162 *
163 * ```
164 * vtkIdType npts;
165 *
166 * #ifdef VTK_CELL_ARRAY_V2
167 * const vtkIdType *pts;
168 * #else // VTK_CELL_ARRAY_V2
169 * vtkIdType *pts'
170 * #endif // VTK_CELL_ARRAY_V2
171 *
172 * cellArray->GetCell(legacyLocation, npts, pts);
173 * ```
174 */
175 #define VTK_CELL_ARRAY_V2
176
177 class vtkCellArrayIterator;
178 class vtkIdTypeArray;
179
180 class VTKCOMMONDATAMODEL_EXPORT vtkCellArray : public vtkObject
181 {
182 public:
183 using ArrayType32 = vtkTypeInt32Array;
184 using ArrayType64 = vtkTypeInt64Array;
185
186 ///@{
187 /**
188 * Standard methods for instantiation, type information, and
189 * printing.
190 */
191 static vtkCellArray* New();
192 vtkTypeMacro(vtkCellArray, vtkObject);
193 void PrintSelf(ostream& os, vtkIndent indent) override;
194 void PrintDebug(ostream& os);
195 ///@}
196
197 /**
198 * List of possible array types used for storage. May be used with
199 * vtkArrayDispatch::Dispatch[2]ByArray to process internal arrays.
200 * Both the Connectivity and Offset arrays are guaranteed to have the same
201 * type.
202 *
203 * @sa vtkCellArray::Visit() for a simpler mechanism.
204 */
205 using StorageArrayList = vtkTypeList::Create<ArrayType32, ArrayType64>;
206
207 /**
208 * List of possible ArrayTypes that are compatible with internal storage.
209 * Single component AOS-layout arrays holding one of these types may be
210 * passed to the method SetData to setup the cell array state.
211 *
212 * This can be used with vtkArrayDispatch::DispatchByArray, etc to
213 * check input arrays before assigning them to a cell array.
214 */
215 using InputArrayList =
216 typename vtkTypeList::Unique<vtkTypeList::Create<vtkAOSDataArrayTemplate<int>,
217 vtkAOSDataArrayTemplate<long>, vtkAOSDataArrayTemplate<long long>>>::Result;
218
219 /**
220 * Allocate memory.
221 *
222 * This currently allocates both the offsets and connectivity arrays to @a sz.
223 *
224 * @note It is preferrable to use AllocateEstimate(numCells, maxCellSize)
225 * or AllocateExact(numCells, connectivitySize) instead.
226 */
227 vtkTypeBool Allocate(vtkIdType sz, vtkIdType vtkNotUsed(ext) = 1000)
228 {
229 return this->AllocateExact(sz, sz) ? 1 : 0;
230 }
231
232 /**
233 * @brief Pre-allocate memory in internal data structures. Does not change
234 * the number of cells, only the array capacities. Existing data is NOT
235 * preserved.
236 * @param numCells The number of expected cells in the dataset.
237 * @param maxCellSize The number of points per cell to allocate memory for.
238 * @return True if allocation succeeds.
239 * @sa Squeeze AllocateExact AllocateCopy
240 */
AllocateEstimate(vtkIdType numCells,vtkIdType maxCellSize)241 bool AllocateEstimate(vtkIdType numCells, vtkIdType maxCellSize)
242 {
243 return this->AllocateExact(numCells, numCells * maxCellSize);
244 }
245
246 /**
247 * @brief Pre-allocate memory in internal data structures. Does not change
248 * the number of cells, only the array capacities. Existing data is NOT
249 * preserved.
250 * @param numCells The number of expected cells in the dataset.
251 * @param connectivitySize The total number of pointIds stored for all cells.
252 * @return True if allocation succeeds.
253 * @sa Squeeze AllocateEstimate AllocateCopy
254 */
255 bool AllocateExact(vtkIdType numCells, vtkIdType connectivitySize);
256
257 /**
258 * @brief Pre-allocate memory in internal data structures to match the used
259 * size of the input vtkCellArray. Does not change
260 * the number of cells, only the array capacities. Existing data is NOT
261 * preserved.
262 * @param other The vtkCellArray to use as a reference.
263 * @return True if allocation succeeds.
264 * @sa Squeeze AllocateEstimate AllocateExact
265 */
AllocateCopy(vtkCellArray * other)266 bool AllocateCopy(vtkCellArray* other)
267 {
268 return this->AllocateExact(other->GetNumberOfCells(), other->GetNumberOfConnectivityIds());
269 }
270
271 /**
272 * @brief ResizeExact() resizes the internal structures to hold @a numCells
273 * total cell offsets and @a connectivitySize total pointIds. Old data is
274 * preserved, and newly-available memory is not initialized.
275 *
276 * @warning For advanced use only. You probably want an Allocate method.
277 *
278 * @return True if allocation succeeds.
279 */
280 bool ResizeExact(vtkIdType numCells, vtkIdType connectivitySize);
281
282 /**
283 * Free any memory and reset to an empty state.
284 */
285 void Initialize();
286
287 /**
288 * Reuse list. Reset to initial state without freeing memory.
289 */
290 void Reset();
291
292 /**
293 * Reclaim any extra memory while preserving data.
294 *
295 * @sa ConvertToSmallestStorage
296 */
297 void Squeeze();
298
299 /**
300 * Check that internal storage is consistent and in a valid state.
301 *
302 * Specifically, this function returns true if and only if:
303 * - The offset and connectivity arrays have exactly one component.
304 * - The offset array has at least one value and starts at 0.
305 * - The offset array values never decrease.
306 * - The connectivity array has as many entries as the last value in the
307 * offset array.
308 */
309 bool IsValid();
310
311 /**
312 * Get the number of cells in the array.
313 */
GetNumberOfCells()314 vtkIdType GetNumberOfCells() const
315 {
316 if (this->Storage.Is64Bit())
317 {
318 return this->Storage.GetArrays64().Offsets->GetNumberOfValues() - 1;
319 }
320 else
321 {
322 return this->Storage.GetArrays32().Offsets->GetNumberOfValues() - 1;
323 }
324 }
325
326 /**
327 * Get the number of elements in the offsets array. This will be the number of
328 * cells + 1.
329 */
GetNumberOfOffsets()330 vtkIdType GetNumberOfOffsets() const
331 {
332 if (this->Storage.Is64Bit())
333 {
334 return this->Storage.GetArrays64().Offsets->GetNumberOfValues();
335 }
336 else
337 {
338 return this->Storage.GetArrays32().Offsets->GetNumberOfValues();
339 }
340 }
341
342 /**
343 * Get the size of the connectivity array that stores the point ids.
344 * @note Do not confuse this with the deprecated
345 * GetNumberOfConnectivityEntries(), which refers to the legacy memory
346 * layout.
347 */
GetNumberOfConnectivityIds()348 vtkIdType GetNumberOfConnectivityIds() const
349 {
350 if (this->Storage.Is64Bit())
351 {
352 return this->Storage.GetArrays64().Connectivity->GetNumberOfValues();
353 }
354 else
355 {
356 return this->Storage.GetArrays32().Connectivity->GetNumberOfValues();
357 }
358 }
359
360 /**
361 * @brief NewIterator returns a new instance of vtkCellArrayIterator that
362 * is initialized to point at the first cell's data. The caller is responsible
363 * for Delete()'ing the object.
364 */
365 VTK_NEWINSTANCE vtkCellArrayIterator* NewIterator();
366
367 #ifndef __VTK_WRAP__ // The wrappers have issues with some of these templates
368 /**
369 * Set the internal data arrays to the supplied offsets and connectivity
370 * arrays.
371 *
372 * Note that the input arrays may be copied and not used directly. To avoid
373 * copying, use vtkIdTypeArray, vtkCellArray::ArrayType32, or
374 * vtkCellArray::ArrayType64.
375 *
376 * @{
377 */
378 void SetData(vtkTypeInt32Array* offsets, vtkTypeInt32Array* connectivity);
379 void SetData(vtkTypeInt64Array* offsets, vtkTypeInt64Array* connectivity);
380 void SetData(vtkIdTypeArray* offsets, vtkIdTypeArray* connectivity);
381 void SetData(vtkAOSDataArrayTemplate<int>* offsets, vtkAOSDataArrayTemplate<int>* connectivity);
382 void SetData(vtkAOSDataArrayTemplate<long>* offsets, vtkAOSDataArrayTemplate<long>* connectivity);
383 void SetData(
384 vtkAOSDataArrayTemplate<long long>* offsets, vtkAOSDataArrayTemplate<long long>* connectivity);
385 /**@}*/
386 #endif // __VTK_WRAP__
387
388 /**
389 * Sets the internal arrays to the supplied offsets and connectivity arrays.
390 *
391 * This is a convenience method, and may fail if the following conditions
392 * are not met:
393 *
394 * - Both arrays must be of the same type.
395 * - The array type must be one of the types in InputArrayList.
396 *
397 * If invalid arrays are passed in, an error is logged and the function
398 * will return false.
399 */
400 bool SetData(vtkDataArray* offsets, vtkDataArray* connectivity);
401
402 /**
403 * Sets the internal arrays to the supported connectivity array with an
404 * offsets array automatically generated given the fixed cells size.
405 *
406 * This is a convenience method, and may fail if the following conditions
407 * are not met:
408 *
409 * - The `connectivity` array must be one of the types in InputArrayList.
410 * - The `connectivity` array size must be a multiple of `cellSize`.
411 *
412 * If invalid arrays are passed in, an error is logged and the function
413 * will return false.
414 */
415 bool SetData(vtkIdType cellSize, vtkDataArray* connectivity);
416
417 /**
418 * @return True if the internal storage is using 64 bit arrays. If false,
419 * the storage is using 32 bit arrays.
420 */
IsStorage64Bit()421 bool IsStorage64Bit() const { return this->Storage.Is64Bit(); }
422
423 /**
424 * @return True if the internal storage can be shared as a
425 * pointer to vtkIdType, i.e., the type and organization of internal
426 * storage is such that copying of data can be avoided, and instead
427 * a pointer to vtkIdType can be used.
428 */
IsStorageShareable()429 bool IsStorageShareable() const
430 {
431 if (this->Storage.Is64Bit())
432 {
433 return this->Storage.GetArrays64().ValueTypeIsSameAsIdType;
434 }
435 else
436 {
437 return this->Storage.GetArrays32().ValueTypeIsSameAsIdType;
438 }
439 }
440
441 /**
442 * Initialize internal data structures to use 32- or 64-bit storage.
443 * If selecting default storage, the storage depends on the VTK_USE_64BIT_IDS
444 * setting.
445 *
446 * All existing data is erased.
447 * @{
448 */
449 void Use32BitStorage();
450 void Use64BitStorage();
451 void UseDefaultStorage();
452 /**@}*/
453
454 /**
455 * Check if the existing data can safely be converted to use 32- or 64- bit
456 * storage. Ensures that all values can be converted to the target storage
457 * without truncating.
458 * If selecting default storage, the storage depends on the VTK_USE_64BIT_IDS
459 * setting.
460 * @{
461 */
462 bool CanConvertTo32BitStorage() const;
463 bool CanConvertTo64BitStorage() const;
464 bool CanConvertToDefaultStorage() const;
465 /**@}*/
466
467 /**
468 * Convert internal data structures to use 32- or 64-bit storage.
469 *
470 * If selecting default storage, the storage depends on the VTK_USE_64BIT_IDS
471 * setting.
472 *
473 * If selecting smallest storage, the data is checked to see what the smallest
474 * safe storage for the existing data is, and then converts to it.
475 *
476 * Existing data is preserved.
477 *
478 * @return True on success, false on failure. If this algorithm fails, the
479 * cell array will be in an unspecified state.
480 *
481 * @{
482 */
483 bool ConvertTo32BitStorage();
484 bool ConvertTo64BitStorage();
485 bool ConvertToDefaultStorage();
486 bool ConvertToSmallestStorage();
487 /**@}*/
488
489 /**
490 * Return the array used to store cell offsets. The 32/64 variants are only
491 * valid when IsStorage64Bit() returns the appropriate value.
492 * @{
493 */
GetOffsetsArray()494 vtkDataArray* GetOffsetsArray()
495 {
496 if (this->Storage.Is64Bit())
497 {
498 return this->GetOffsetsArray64();
499 }
500 else
501 {
502 return this->GetOffsetsArray32();
503 }
504 }
GetOffsetsArray32()505 ArrayType32* GetOffsetsArray32() { return this->Storage.GetArrays32().Offsets; }
GetOffsetsArray64()506 ArrayType64* GetOffsetsArray64() { return this->Storage.GetArrays64().Offsets; }
507 /**@}*/
508
509 /**
510 * Return the array used to store the point ids that define the cells'
511 * connectivity. The 32/64 variants are only valid when IsStorage64Bit()
512 * returns the appropriate value.
513 * @{
514 */
GetConnectivityArray()515 vtkDataArray* GetConnectivityArray()
516 {
517 if (this->Storage.Is64Bit())
518 {
519 return this->GetConnectivityArray64();
520 }
521 else
522 {
523 return this->GetConnectivityArray32();
524 }
525 }
GetConnectivityArray32()526 ArrayType32* GetConnectivityArray32() { return this->Storage.GetArrays32().Connectivity; }
GetConnectivityArray64()527 ArrayType64* GetConnectivityArray64() { return this->Storage.GetArrays64().Connectivity; }
528 /**@}*/
529
530 /**
531 * Check if all cells have the same number of vertices.
532 *
533 * The return value is coded as:
534 * * -1 = heterogeneous
535 * * 0 = Cell array empty
536 * * n (positive integer) = homogeneous array of cell size n
537 */
538 vtkIdType IsHomogeneous();
539
540 /**
541 * @warning This method is not thread-safe. Consider using the NewIterator()
542 * iterator instead.
543 *
544 * InitTraversal() initializes the traversal of the list of cells.
545 *
546 * @note This method is not thread-safe and has tricky syntax to use
547 * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
548 */
549 void InitTraversal();
550
551 /**
552 * @warning This method is not thread-safe. Consider using the NewIterator()
553 * iterator instead.
554 *
555 * GetNextCell() gets the next cell in the list. If end of list
556 * is encountered, 0 is returned. A value of 1 is returned whenever
557 * npts and pts have been updated without error.
558 *
559 * Do not modify the returned @a pts pointer, as it may point to shared
560 * memory.
561 *
562 * @note This method is not thread-safe and has tricky syntax to use
563 * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
564 */
565 int GetNextCell(vtkIdType& npts, vtkIdType const*& pts) VTK_SIZEHINT(pts, npts);
566
567 /**
568 * @warning This method is not thread-safe. Consider using the NewIterator()
569 * iterator instead.
570 *
571 * GetNextCell() gets the next cell in the list. If end of list is
572 * encountered, 0 is returned.
573 *
574 * @note This method is not thread-safe and has tricky syntax to use
575 * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
576 */
577 int GetNextCell(vtkIdList* pts);
578
579 /**
580 * Return the point ids for the cell at @a cellId.
581 *
582 * @warning Subsequent calls to this method may invalidate previous call
583 * results if the internal storage type is not the same as vtkIdType and
584 * cannot be shared through the @a cellPoints pointer. In other words, the
585 * method may not be thread safe. Check if shareable (using
586 * IsStorageShareable()), or use a vtkCellArrayIterator to guarantee thread
587 * safety.
588 */
589 void GetCellAtId(vtkIdType cellId, vtkIdType& cellSize, vtkIdType const*& cellPoints)
590 VTK_SIZEHINT(cellPoints, cellSize) VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells());
591
592 /**
593 * Return the point ids for the cell at @a cellId. This always copies
594 * the cell ids (i.e., the list of points @a pts into the supplied
595 * vtkIdList). This method is thread safe.
596 */
597 void GetCellAtId(vtkIdType cellId, vtkIdList* pts)
598 VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells());
599
600 /**
601 * Return the size of the cell at @a cellId.
602 */
603 vtkIdType GetCellSize(const vtkIdType cellId) const;
604
605 /**
606 * Insert a cell object. Return the cell id of the cell.
607 */
608 vtkIdType InsertNextCell(vtkCell* cell);
609
610 /**
611 * Create a cell by specifying the number of points and an array of point
612 * id's. Return the cell id of the cell.
613 */
614 vtkIdType InsertNextCell(vtkIdType npts, const vtkIdType* pts) VTK_SIZEHINT(pts, npts);
615
616 /**
617 * Create a cell by specifying a list of point ids. Return the cell id of
618 * the cell.
619 */
620 vtkIdType InsertNextCell(vtkIdList* pts);
621
622 /**
623 * Overload that allows `InsertNextCell({0, 1, 2})` syntax.
624 *
625 * @warning This approach is useful for testing, but beware that trying to
626 * pass a single value (eg. `InsertNextCell({3})`) will call the
627 * `InsertNextCell(int)` overload instead.
628 */
InsertNextCell(const std::initializer_list<vtkIdType> & cell)629 vtkIdType InsertNextCell(const std::initializer_list<vtkIdType>& cell)
630 {
631 return this->InsertNextCell(static_cast<vtkIdType>(cell.size()), cell.begin());
632 }
633
634 /**
635 * Create cells by specifying a count of total points to be inserted, and
636 * then adding points one at a time using method InsertCellPoint(). If you
637 * don't know the count initially, use the method UpdateCellCount() to
638 * complete the cell. Return the cell id of the cell.
639 */
640 vtkIdType InsertNextCell(int npts);
641
642 /**
643 * Used in conjunction with InsertNextCell(npts) to add another point
644 * to the list of cells.
645 */
646 void InsertCellPoint(vtkIdType id);
647
648 /**
649 * Used in conjunction with InsertNextCell(int npts) and InsertCellPoint() to
650 * update the number of points defining the cell.
651 */
652 void UpdateCellCount(int npts);
653
654 /**
655 * Get/Set the current cellId for traversal.
656 *
657 * @note This method is not thread-safe and has tricky syntax to use
658 * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
659 * @{
660 */
661 vtkIdType GetTraversalCellId();
662 void SetTraversalCellId(vtkIdType cellId);
663 /**@}*/
664
665 /**
666 * Reverses the order of the point ids for the specified cell.
667 */
668 void ReverseCellAtId(vtkIdType cellId) VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells());
669
670 /**
671 * Replaces the point ids for the specified cell with the supplied list.
672 *
673 * @warning This can ONLY replace the cell if the size does not change.
674 * Attempting to change cell size through this method will have undefined
675 * results.
676 * @{
677 */
678 void ReplaceCellAtId(vtkIdType cellId, vtkIdList* list);
679 void ReplaceCellAtId(vtkIdType cellId, vtkIdType cellSize, const vtkIdType* cellPoints)
680 VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells()) VTK_SIZEHINT(cellPoints, cellSize);
681 /**@}*/
682
683 /**
684 * Overload that allows `ReplaceCellAtId(cellId, {0, 1, 2})` syntax.
685 *
686 * @warning This can ONLY replace the cell if the size does not change.
687 * Attempting to change cell size through this method will have undefined
688 * results.
689 */
ReplaceCellAtId(vtkIdType cellId,const std::initializer_list<vtkIdType> & cell)690 void ReplaceCellAtId(vtkIdType cellId, const std::initializer_list<vtkIdType>& cell)
691 {
692 return this->ReplaceCellAtId(cellId, static_cast<vtkIdType>(cell.size()), cell.begin());
693 }
694
695 /**
696 * Returns the size of the largest cell. The size is the number of points
697 * defining the cell.
698 */
699 int GetMaxCellSize();
700
701 /**
702 * Perform a deep copy (no reference counting) of the given cell array.
703 */
704 void DeepCopy(vtkCellArray* ca);
705
706 /**
707 * Shallow copy @a ca into this cell array.
708 */
709 void ShallowCopy(vtkCellArray* ca);
710
711 /**
712 * Append cells from src into this. Point ids are offset by @a pointOffset.
713 */
714 void Append(vtkCellArray* src, vtkIdType pointOffset = 0);
715
716 /**
717 * Fill @a data with the old-style vtkCellArray data layout, e.g.
718 *
719 * ```
720 * { n0, p0_0, p0_1, ..., p0_n, n1, p1_0, p1_1, ..., p1_n, ... }
721 * ```
722 *
723 * where `n0` is the number of points in cell 0, and `pX_Y` is the Y'th point
724 * in cell X.
725 */
726 void ExportLegacyFormat(vtkIdTypeArray* data);
727
728 /**
729 * Import an array of data with the legacy vtkCellArray layout, e.g.:
730 *
731 * ```
732 * { n0, p0_0, p0_1, ..., p0_n, n1, p1_0, p1_1, ..., p1_n, ... }
733 * ```
734 *
735 * where `n0` is the number of points in cell 0, and `pX_Y` is the Y'th point
736 * in cell X.
737 * @{
738 */
739 void ImportLegacyFormat(vtkIdTypeArray* data);
740 void ImportLegacyFormat(const vtkIdType* data, vtkIdType len) VTK_SIZEHINT(data, len);
741 /** @} */
742
743 /**
744 * Append an array of data with the legacy vtkCellArray layout, e.g.:
745 *
746 * ```
747 * { n0, p0_0, p0_1, ..., p0_n, n1, p1_0, p1_1, ..., p1_n, ... }
748 * ```
749 *
750 * where `n0` is the number of points in cell 0, and `pX_Y` is the Y'th point
751 * in cell X.
752 * @{
753 */
754 void AppendLegacyFormat(vtkIdTypeArray* data, vtkIdType ptOffset = 0);
755 void AppendLegacyFormat(const vtkIdType* data, vtkIdType len, vtkIdType ptOffset = 0)
756 VTK_SIZEHINT(data, len);
757 /** @} */
758
759 /**
760 * Return the memory in kibibytes (1024 bytes) consumed by this cell array. Used to
761 * support streaming and reading/writing data. The value returned is
762 * guaranteed to be greater than or equal to the memory required to
763 * actually represent the data represented by this object. The
764 * information returned is valid only after the pipeline has
765 * been updated.
766 */
767 unsigned long GetActualMemorySize() const;
768
769 // The following code is used to support
770
771 // The wrappers get understandably confused by some of the template code below
772 #ifndef __VTK_WRAP__
773
774 // Holds connectivity and offset arrays of the given ArrayType.
775 template <typename ArrayT>
776 struct VisitState
777 {
778 using ArrayType = ArrayT;
779 using ValueType = typename ArrayType::ValueType;
780 using CellRangeType = decltype(vtk::DataArrayValueRange<1>(std::declval<ArrayType>()));
781
782 // We can't just use is_same here, since binary compatible representations
783 // (e.g. int and long) are distinct types. Instead, ensure that ValueType
784 // is a signed integer the same size as vtkIdType.
785 // If this value is true, ValueType pointers may be safely converted to
786 // vtkIdType pointers via reinterpret cast.
787 static constexpr bool ValueTypeIsSameAsIdType = std::is_integral<ValueType>::value &&
788 std::is_signed<ValueType>::value && (sizeof(ValueType) == sizeof(vtkIdType));
789
GetOffsetsVisitState790 ArrayType* GetOffsets() { return this->Offsets; }
GetOffsetsVisitState791 const ArrayType* GetOffsets() const { return this->Offsets; }
792
GetConnectivityVisitState793 ArrayType* GetConnectivity() { return this->Connectivity; }
GetConnectivityVisitState794 const ArrayType* GetConnectivity() const { return this->Connectivity; }
795
796 vtkIdType GetNumberOfCells() const;
797
798 vtkIdType GetBeginOffset(vtkIdType cellId) const;
799
800 vtkIdType GetEndOffset(vtkIdType cellId) const;
801
802 vtkIdType GetCellSize(vtkIdType cellId) const;
803
804 CellRangeType GetCellRange(vtkIdType cellId);
805
806 friend class vtkCellArray;
807
808 protected:
VisitStateVisitState809 VisitState()
810 {
811 this->Connectivity = vtkSmartPointer<ArrayType>::New();
812 this->Offsets = vtkSmartPointer<ArrayType>::New();
813 this->Offsets->InsertNextValue(0);
814 if (vtkObjectBase::GetUsingMemkind())
815 {
816 this->IsInMemkind = true;
817 }
818 }
819 ~VisitState() = default;
newVisitState820 void* operator new(size_t nSize)
821 {
822 void* r;
823 #ifdef VTK_USE_MEMKIND
824 r = vtkObjectBase::GetCurrentMallocFunction()(nSize);
825 #else
826 r = malloc(nSize);
827 #endif
828 return r;
829 }
deleteVisitState830 void operator delete(void* p)
831 {
832 #ifdef VTK_USE_MEMKIND
833 VisitState* a = static_cast<VisitState*>(p);
834 if (a->IsInMemkind)
835 {
836 vtkObjectBase::GetAlternateFreeFunction()(p);
837 }
838 else
839 {
840 free(p);
841 }
842 #else
843 free(p);
844 #endif
845 }
846
847 vtkSmartPointer<ArrayType> Connectivity;
848 vtkSmartPointer<ArrayType> Offsets;
849
850 private:
851 VisitState(const VisitState&) = delete;
852 VisitState& operator=(const VisitState&) = delete;
853 bool IsInMemkind = false;
854 };
855
856 private: // Helpers that allow Visit to return a value:
857 template <typename Functor, typename... Args>
858 using GetReturnType = decltype(
859 std::declval<Functor>()(std::declval<VisitState<ArrayType32>&>(), std::declval<Args>()...));
860
861 template <typename Functor, typename... Args>
862 struct ReturnsVoid : std::is_same<GetReturnType<Functor, Args...>, void>
863 {
864 };
865
866 public:
867 /**
868 * @warning Advanced use only.
869 *
870 * The Visit methods allow efficient bulk modification of the vtkCellArray
871 * internal arrays by dispatching a functor with the current storage arrays.
872 * The simplest functor is of the form:
873 *
874 * ```
875 * // Functor definition:
876 * struct Worker
877 * {
878 * template <typename CellStateT>
879 * void operator()(CellStateT &state)
880 * {
881 * // Do work on state object
882 * }
883 * };
884 *
885 * // Functor usage:
886 * vtkCellArray *cellArray = ...;
887 * cellArray->Visit(Worker{});
888 * ```
889 *
890 * where `state` is an instance of the vtkCellArray::VisitState<ArrayT> class,
891 * instantiated for the current storage type of the cell array. See that
892 * class for usage details.
893 *
894 * The functor may also:
895 * - Return a value from `operator()`
896 * - Pass additional arguments to `operator()`
897 * - Hold state.
898 *
899 * A more advanced functor that does these things is shown below, along
900 * with its usage. This functor scans a range of cells and returns the largest
901 * cell's id:
902 *
903 * ```
904 * struct FindLargestCellInRange
905 * {
906 * template <typename CellStateT>
907 * vtkIdType operator()(CellStateT &state,
908 * vtkIdType rangeBegin,
909 * vtkIdType rangeEnd)
910 * {
911 * vtkIdType largest = rangeBegin;
912 * vtkIdType largestSize = state.GetCellSize(rangeBegin);
913 * ++rangeBegin;
914 * for (; rangeBegin < rangeEnd; ++rangeBegin)
915 * {
916 * const vtkIdType curSize = state.GetCellSize(rangeBegin);
917 * if (curSize > largestSize)
918 * {
919 * largest = rangeBegin;
920 * largestSize = curSize;
921 * }
922 * }
923 *
924 * return largest;
925 * }
926 * };
927 *
928 * // Usage:
929 * // Scan cells in range [128, 1024) and return the id of the largest.
930 * vtkCellArray cellArray = ...;
931 * vtkIdType largest = cellArray->Visit(FindLargestCellInRange{},
932 * 128, 1024);
933 * ```
934 * @{
935 */
936 template <typename Functor, typename... Args,
937 typename = typename std::enable_if<ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)938 void Visit(Functor&& functor, Args&&... args)
939 {
940 if (this->Storage.Is64Bit())
941 {
942 // If you get an error on the next line, a call to Visit(functor, Args...)
943 // is being called with arguments that do not match the functor's call
944 // signature. See the Visit documentation for details.
945 functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
946 }
947 else
948 {
949 // If you get an error on the next line, a call to Visit(functor, Args...)
950 // is being called with arguments that do not match the functor's call
951 // signature. See the Visit documentation for details.
952 functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
953 }
954 }
955
956 template <typename Functor, typename... Args,
957 typename = typename std::enable_if<ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)958 void Visit(Functor&& functor, Args&&... args) const
959 {
960 if (this->Storage.Is64Bit())
961 {
962 // If you get an error on the next line, a call to Visit(functor, Args...)
963 // is being called with arguments that do not match the functor's call
964 // signature. See the Visit documentation for details.
965 functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
966 }
967 else
968 {
969 // If you get an error on the next line, a call to Visit(functor, Args...)
970 // is being called with arguments that do not match the functor's call
971 // signature. See the Visit documentation for details.
972 functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
973 }
974 }
975
976 template <typename Functor, typename... Args,
977 typename = typename std::enable_if<!ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)978 GetReturnType<Functor, Args...> Visit(Functor&& functor, Args&&... args)
979 {
980 if (this->Storage.Is64Bit())
981 {
982 // If you get an error on the next line, a call to Visit(functor, Args...)
983 // is being called with arguments that do not match the functor's call
984 // signature. See the Visit documentation for details.
985 return functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
986 }
987 else
988 {
989 // If you get an error on the next line, a call to Visit(functor, Args...)
990 // is being called with arguments that do not match the functor's call
991 // signature. See the Visit documentation for details.
992 return functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
993 }
994 }
995 template <typename Functor, typename... Args,
996 typename = typename std::enable_if<!ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)997 GetReturnType<Functor, Args...> Visit(Functor&& functor, Args&&... args) const
998 {
999 if (this->Storage.Is64Bit())
1000 {
1001 // If you get an error on the next line, a call to Visit(functor, Args...)
1002 // is being called with arguments that do not match the functor's call
1003 // signature. See the Visit documentation for details.
1004 return functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
1005 }
1006 else
1007 {
1008 // If you get an error on the next line, a call to Visit(functor, Args...)
1009 // is being called with arguments that do not match the functor's call
1010 // signature. See the Visit documentation for details.
1011 return functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
1012 }
1013 }
1014
1015 /** @} */
1016
1017 #endif // __VTK_WRAP__
1018
1019 //=================== Begin Legacy Methods ===================================
1020 // These should be deprecated at some point as they are confusing or very slow
1021
1022 /**
1023 * Set the number of cells in the array.
1024 * DO NOT do any kind of allocation, advanced use only.
1025 *
1026 * @note This call has no effect.
1027 */
1028 virtual void SetNumberOfCells(vtkIdType);
1029
1030 /**
1031 * Utility routines help manage memory of cell array. EstimateSize()
1032 * returns a value used to initialize and allocate memory for array based
1033 * on number of cells and maximum number of points making up cell. If
1034 * every cell is the same size (in terms of number of points), then the
1035 * memory estimate is guaranteed exact. (If not exact, use Squeeze() to
1036 * reclaim any extra memory.)
1037 *
1038 * @note This method was often misused (e.g. called alone and then
1039 * discarding the result). Use AllocateEstimate directly instead.
1040 */
1041 vtkIdType EstimateSize(vtkIdType numCells, int maxPtsPerCell);
1042
1043 /**
1044 * Get the size of the allocated connectivity array.
1045 *
1046 * @warning This returns the allocated capacity of the internal arrays as a
1047 * number of elements, NOT the number of elements in use.
1048 *
1049 * @note Method incompatible with current internal storage.
1050 */
1051 vtkIdType GetSize();
1052
1053 /**
1054 * Return the size of the array that would be returned from
1055 * ExportLegacyFormat().
1056 *
1057 * @note Method incompatible with current internal storage.
1058 */
1059 vtkIdType GetNumberOfConnectivityEntries();
1060
1061 /**
1062 * Internal method used to retrieve a cell given a legacy offset location.
1063 *
1064 * @warning Subsequent calls to this method may invalidate previous call
1065 * results.
1066 *
1067 * @note The location-based API is now a super-slow compatibility layer.
1068 * Prefer GetCellAtId.
1069 */
1070 void GetCell(vtkIdType loc, vtkIdType& npts, const vtkIdType*& pts)
1071 VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries()) VTK_SIZEHINT(pts, npts);
1072
1073 /**
1074 * Internal method used to retrieve a cell given a legacy offset location.
1075 *
1076 * @note The location-based API is now a super-slow compatibility layer.
1077 * Prefer GetCellAtId.
1078 */
1079 void GetCell(vtkIdType loc, vtkIdList* pts)
1080 VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries());
1081
1082 /**
1083 * Computes the current legacy insertion location within the internal array.
1084 * Used in conjunction with GetCell(int loc,...).
1085 *
1086 * @note The location-based API is now a super-slow compatibility layer.
1087 */
1088 vtkIdType GetInsertLocation(int npts);
1089
1090 /**
1091 * Get/Set the current traversal legacy location.
1092 *
1093 * @note The location-based API is now a super-slow compatibility layer.
1094 * Prefer Get/SetTraversalCellId.
1095 * @{
1096 */
1097 vtkIdType GetTraversalLocation();
1098 vtkIdType GetTraversalLocation(vtkIdType npts);
1099 void SetTraversalLocation(vtkIdType loc);
1100 /**@}*/
1101
1102 /**
1103 * Special method inverts ordering of cell at the specified legacy location.
1104 * Must be called carefully or the cell topology may be corrupted.
1105 *
1106 * @note The location-based API is now a super-slow compatibility layer.
1107 * Prefer ReverseCellAtId;
1108 */
1109 void ReverseCell(vtkIdType loc) VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries());
1110
1111 /**
1112 * Replace the point ids of the cell at the legacy location with a different
1113 * list of point ids. Calling this method does not mark the vtkCellArray as
1114 * modified. This is the responsibility of the caller and may be done after
1115 * multiple calls to ReplaceCell. This call does not support changing the
1116 * number of points in the cell -- the caller must ensure that the target
1117 * cell has npts points.
1118 *
1119 * @note The location-based API is now a super-slow compatibility layer.
1120 * Prefer ReplaceCellAtId.
1121 */
1122 void ReplaceCell(vtkIdType loc, int npts, const vtkIdType pts[])
1123 VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries()) VTK_SIZEHINT(pts, npts);
1124
1125 /**
1126 * Define multiple cells by providing a connectivity list. The list is in
1127 * the form (npts,p0,p1,...p(npts-1), repeated for each cell). Be careful
1128 * using this method because it discards the old cells, and anything
1129 * referring these cells becomes invalid (for example, if BuildCells() has
1130 * been called see vtkPolyData). The traversal location is reset to the
1131 * beginning of the list; the insertion location is set to the end of the
1132 * list.
1133 *
1134 * @warning The vtkCellArray will not hold a reference to `cells`. This
1135 * function merely calls ImportLegacyFormat.
1136 *
1137 * @note Use ImportLegacyFormat or SetData instead.
1138 */
1139 void SetCells(vtkIdType ncells, vtkIdTypeArray* cells);
1140
1141 /**
1142 * Return the underlying data as a data array.
1143 *
1144 * @warning The returned array is not the actual internal representation used
1145 * by vtkCellArray. Modifications to the returned array will not change the
1146 * vtkCellArray's topology.
1147 *
1148 * @note Use ExportLegacyFormat, or GetOffsetsArray/GetConnectivityArray
1149 * instead.
1150 */
1151 vtkIdTypeArray* GetData();
1152
1153 //=================== End Legacy Methods =====================================
1154
1155 friend class vtkCellArrayIterator;
1156
1157 protected:
1158 vtkCellArray();
1159 ~vtkCellArray() override;
1160
1161 // Encapsulates storage of the internal arrays as a discriminated union
1162 // between 32-bit and 64-bit storage.
1163 struct Storage
1164 {
1165 // Union type that switches 32 and 64 bit array storage
1166 union ArraySwitch {
1167 ArraySwitch() = default; // handled by Storage
1168 ~ArraySwitch() = default; // handle by Storage
1169 VisitState<ArrayType32>* Int32;
1170 VisitState<ArrayType64>* Int64;
1171 };
1172
StorageStorage1173 Storage()
1174 {
1175 #ifdef VTK_USE_MEMKIND
1176 this->Arrays =
1177 static_cast<ArraySwitch*>(vtkObjectBase::GetCurrentMallocFunction()(sizeof(ArraySwitch)));
1178 #else
1179 this->Arrays = new ArraySwitch;
1180 #endif
1181
1182 // Default to the compile-time setting:
1183 #ifdef VTK_USE_64BIT_IDS
1184
1185 this->Arrays->Int64 = new VisitState<ArrayType64>;
1186 this->StorageIs64Bit = true;
1187
1188 #else // VTK_USE_64BIT_IDS
1189
1190 this->Arrays->Int32 = new VisitState<ArrayType32>;
1191 this->StorageIs64Bit = false;
1192
1193 #endif // VTK_USE_64BIT_IDS
1194 #ifdef VTK_USE_MEMKIND
1195 if (vtkObjectBase::GetUsingMemkind())
1196 {
1197 this->IsInMemkind = true;
1198 }
1199 #else
1200 (void)this->IsInMemkind; // comp warning workaround
1201 #endif
1202 }
1203
~StorageStorage1204 ~Storage()
1205 {
1206 if (this->StorageIs64Bit)
1207 {
1208 this->Arrays->Int64->~VisitState();
1209 delete this->Arrays->Int64;
1210 }
1211 else
1212 {
1213 this->Arrays->Int32->~VisitState();
1214 delete this->Arrays->Int32;
1215 }
1216 #ifdef VTK_USE_MEMKIND
1217 if (this->IsInMemkind)
1218 {
1219 vtkObjectBase::GetAlternateFreeFunction()(this->Arrays);
1220 }
1221 else
1222 {
1223 free(this->Arrays);
1224 }
1225 #else
1226 delete this->Arrays;
1227 #endif
1228 }
1229
1230 // Switch the internal arrays to be 32-bit. Any old data is lost. Returns
1231 // true if the storage changes.
Use32BitStorageStorage1232 bool Use32BitStorage()
1233 {
1234 if (!this->StorageIs64Bit)
1235 {
1236 return false;
1237 }
1238
1239 this->Arrays->Int64->~VisitState();
1240 delete this->Arrays->Int64;
1241 this->Arrays->Int32 = new VisitState<ArrayType32>;
1242 this->StorageIs64Bit = false;
1243
1244 return true;
1245 }
1246
1247 // Switch the internal arrays to be 64-bit. Any old data is lost. Returns
1248 // true if the storage changes.
Use64BitStorageStorage1249 bool Use64BitStorage()
1250 {
1251 if (this->StorageIs64Bit)
1252 {
1253 return false;
1254 }
1255
1256 this->Arrays->Int32->~VisitState();
1257 delete this->Arrays->Int32;
1258 this->Arrays->Int64 = new VisitState<ArrayType64>;
1259 this->StorageIs64Bit = true;
1260
1261 return true;
1262 }
1263
1264 // Returns true if the storage is currently configured to be 64 bit.
Is64BitStorage1265 bool Is64Bit() const { return this->StorageIs64Bit; }
1266
1267 // Get the VisitState for 32-bit arrays
GetArrays32Storage1268 VisitState<ArrayType32>& GetArrays32()
1269 {
1270 assert(!this->StorageIs64Bit);
1271 return *this->Arrays->Int32;
1272 }
1273
GetArrays32Storage1274 const VisitState<ArrayType32>& GetArrays32() const
1275 {
1276 assert(!this->StorageIs64Bit);
1277 return *this->Arrays->Int32;
1278 }
1279
1280 // Get the VisitState for 64-bit arrays
GetArrays64Storage1281 VisitState<ArrayType64>& GetArrays64()
1282 {
1283 assert(this->StorageIs64Bit);
1284 return *this->Arrays->Int64;
1285 }
1286
GetArrays64Storage1287 const VisitState<ArrayType64>& GetArrays64() const
1288 {
1289 assert(this->StorageIs64Bit);
1290 return *this->Arrays->Int64;
1291 }
1292
1293 private:
1294 // Access restricted to ensure proper union construction/destruction thru
1295 // API.
1296 ArraySwitch* Arrays;
1297 bool StorageIs64Bit;
1298 bool IsInMemkind = false;
1299 };
1300
1301 Storage Storage;
1302 vtkNew<vtkIdList> TempCell;
1303 vtkIdType TraversalCellId{ 0 };
1304
1305 vtkNew<vtkIdTypeArray> LegacyData; // For GetData().
1306
1307 private:
1308 vtkCellArray(const vtkCellArray&) = delete;
1309 void operator=(const vtkCellArray&) = delete;
1310 };
1311
1312 template <typename ArrayT>
GetNumberOfCells()1313 vtkIdType vtkCellArray::VisitState<ArrayT>::GetNumberOfCells() const
1314 {
1315 return this->Offsets->GetNumberOfValues() - 1;
1316 }
1317
1318 template <typename ArrayT>
GetBeginOffset(vtkIdType cellId)1319 vtkIdType vtkCellArray::VisitState<ArrayT>::GetBeginOffset(vtkIdType cellId) const
1320 {
1321 return static_cast<vtkIdType>(this->Offsets->GetValue(cellId));
1322 }
1323
1324 template <typename ArrayT>
GetEndOffset(vtkIdType cellId)1325 vtkIdType vtkCellArray::VisitState<ArrayT>::GetEndOffset(vtkIdType cellId) const
1326 {
1327 return static_cast<vtkIdType>(this->Offsets->GetValue(cellId + 1));
1328 }
1329
1330 template <typename ArrayT>
GetCellSize(vtkIdType cellId)1331 vtkIdType vtkCellArray::VisitState<ArrayT>::GetCellSize(vtkIdType cellId) const
1332 {
1333 return this->GetEndOffset(cellId) - this->GetBeginOffset(cellId);
1334 }
1335
1336 template <typename ArrayT>
1337 typename vtkCellArray::VisitState<ArrayT>::CellRangeType
GetCellRange(vtkIdType cellId)1338 vtkCellArray::VisitState<ArrayT>::GetCellRange(vtkIdType cellId)
1339 {
1340 return vtk::DataArrayValueRange<1>(
1341 this->GetConnectivity(), this->GetBeginOffset(cellId), this->GetEndOffset(cellId));
1342 }
1343
1344 namespace vtkCellArray_detail
1345 {
1346
1347 struct InsertNextCellImpl
1348 {
1349 // Insert full cell
1350 template <typename CellStateT>
operatorInsertNextCellImpl1351 vtkIdType operator()(CellStateT& state, const vtkIdType npts, const vtkIdType pts[])
1352 {
1353 using ValueType = typename CellStateT::ValueType;
1354 auto* conn = state.GetConnectivity();
1355 auto* offsets = state.GetOffsets();
1356
1357 const vtkIdType cellId = offsets->GetNumberOfValues() - 1;
1358
1359 offsets->InsertNextValue(static_cast<ValueType>(conn->GetNumberOfValues() + npts));
1360
1361 for (vtkIdType i = 0; i < npts; ++i)
1362 {
1363 conn->InsertNextValue(static_cast<ValueType>(pts[i]));
1364 }
1365
1366 return cellId;
1367 }
1368
1369 // Just update offset table (for incremental API)
1370 template <typename CellStateT>
operatorInsertNextCellImpl1371 vtkIdType operator()(CellStateT& state, const vtkIdType npts)
1372 {
1373 using ValueType = typename CellStateT::ValueType;
1374 auto* conn = state.GetConnectivity();
1375 auto* offsets = state.GetOffsets();
1376
1377 const vtkIdType cellId = offsets->GetNumberOfValues() - 1;
1378
1379 offsets->InsertNextValue(static_cast<ValueType>(conn->GetNumberOfValues() + npts));
1380
1381 return cellId;
1382 }
1383 };
1384
1385 // for incremental API:
1386 struct UpdateCellCountImpl
1387 {
1388 template <typename CellStateT>
operatorUpdateCellCountImpl1389 void operator()(CellStateT& state, const vtkIdType npts)
1390 {
1391 using ValueType = typename CellStateT::ValueType;
1392
1393 auto* offsets = state.GetOffsets();
1394 const ValueType cellBegin = offsets->GetValue(offsets->GetMaxId() - 1);
1395 offsets->SetValue(offsets->GetMaxId(), static_cast<ValueType>(cellBegin + npts));
1396 }
1397 };
1398
1399 struct GetCellSizeImpl
1400 {
1401 template <typename CellStateT>
operatorGetCellSizeImpl1402 vtkIdType operator()(CellStateT& state, const vtkIdType cellId)
1403 {
1404 return state.GetCellSize(cellId);
1405 }
1406 };
1407
1408 struct GetCellAtIdImpl
1409 {
1410 template <typename CellStateT>
operatorGetCellAtIdImpl1411 void operator()(CellStateT& state, const vtkIdType cellId, vtkIdList* ids)
1412 {
1413 using ValueType = typename CellStateT::ValueType;
1414
1415 const auto cellPts = state.GetCellRange(cellId);
1416
1417 ids->SetNumberOfIds(cellPts.size());
1418 vtkIdType* idPtr = ids->GetPointer(0);
1419
1420 for (ValueType ptId : cellPts)
1421 {
1422 *idPtr++ = static_cast<vtkIdType>(ptId);
1423 }
1424 }
1425
1426 // SFINAE helper to check if a VisitState's connectivity array's memory
1427 // can be used as a vtkIdType*.
1428 template <typename CellStateT>
1429 struct CanShareConnPtr
1430 {
1431 private:
1432 using ValueType = typename CellStateT::ValueType;
1433 using ArrayType = typename CellStateT::ArrayType;
1434 using AOSArrayType = vtkAOSDataArrayTemplate<ValueType>;
1435 static constexpr bool ValueTypeCompat = CellStateT::ValueTypeIsSameAsIdType;
1436 static constexpr bool ArrayTypeCompat = std::is_base_of<AOSArrayType, ArrayType>::value;
1437
1438 public:
1439 static constexpr bool value = ValueTypeCompat && ArrayTypeCompat;
1440 };
1441
1442 template <typename CellStateT>
operatorGetCellAtIdImpl1443 typename std::enable_if<CanShareConnPtr<CellStateT>::value, void>::type operator()(
1444 CellStateT& state, const vtkIdType cellId, vtkIdType& cellSize, vtkIdType const*& cellPoints,
1445 vtkIdList* vtkNotUsed(temp))
1446 {
1447 const vtkIdType beginOffset = state.GetBeginOffset(cellId);
1448 const vtkIdType endOffset = state.GetEndOffset(cellId);
1449 cellSize = endOffset - beginOffset;
1450 // This is safe, see CanShareConnPtr helper above.
1451 cellPoints = reinterpret_cast<vtkIdType*>(state.GetConnectivity()->GetPointer(beginOffset));
1452 }
1453
1454 template <typename CellStateT>
operatorGetCellAtIdImpl1455 typename std::enable_if<!CanShareConnPtr<CellStateT>::value, void>::type operator()(
1456 CellStateT& state, const vtkIdType cellId, vtkIdType& cellSize, vtkIdType const*& cellPoints,
1457 vtkIdList* temp)
1458 {
1459 using ValueType = typename CellStateT::ValueType;
1460
1461 const auto cellPts = state.GetCellRange(cellId);
1462 cellSize = cellPts.size();
1463
1464 // ValueType differs from vtkIdType, so we have to copy into a temporary
1465 // buffer:
1466 temp->SetNumberOfIds(cellSize);
1467 vtkIdType* tempPtr = temp->GetPointer(0);
1468 for (ValueType ptId : cellPts)
1469 {
1470 *tempPtr++ = static_cast<vtkIdType>(ptId);
1471 }
1472
1473 cellPoints = temp->GetPointer(0);
1474 }
1475 };
1476
1477 struct ResetImpl
1478 {
1479 template <typename CellStateT>
operatorResetImpl1480 void operator()(CellStateT& state)
1481 {
1482 state.GetOffsets()->Reset();
1483 state.GetConnectivity()->Reset();
1484 state.GetOffsets()->InsertNextValue(0);
1485 }
1486 };
1487
1488 } // end namespace vtkCellArray_detail
1489
1490 //----------------------------------------------------------------------------
InitTraversal()1491 inline void vtkCellArray::InitTraversal()
1492 {
1493 this->TraversalCellId = 0;
1494 }
1495
1496 //----------------------------------------------------------------------------
GetNextCell(vtkIdType & npts,vtkIdType const * & pts)1497 inline int vtkCellArray::GetNextCell(vtkIdType& npts, vtkIdType const*& pts) VTK_SIZEHINT(pts, npts)
1498 {
1499 if (this->TraversalCellId < this->GetNumberOfCells())
1500 {
1501 this->GetCellAtId(this->TraversalCellId, npts, pts);
1502 ++this->TraversalCellId;
1503 return 1;
1504 }
1505
1506 npts = 0;
1507 pts = nullptr;
1508 return 0;
1509 }
1510
1511 //----------------------------------------------------------------------------
GetNextCell(vtkIdList * pts)1512 inline int vtkCellArray::GetNextCell(vtkIdList* pts)
1513 {
1514 if (this->TraversalCellId < this->GetNumberOfCells())
1515 {
1516 this->GetCellAtId(this->TraversalCellId, pts);
1517 ++this->TraversalCellId;
1518 return 1;
1519 }
1520
1521 pts->Reset();
1522 return 0;
1523 }
1524 //----------------------------------------------------------------------------
GetCellSize(const vtkIdType cellId)1525 inline vtkIdType vtkCellArray::GetCellSize(const vtkIdType cellId) const
1526 {
1527 return this->Visit(vtkCellArray_detail::GetCellSizeImpl{}, cellId);
1528 }
1529
1530 //----------------------------------------------------------------------------
GetCellAtId(vtkIdType cellId,vtkIdType & cellSize,vtkIdType const * & cellPoints)1531 inline void vtkCellArray::GetCellAtId(vtkIdType cellId, vtkIdType& cellSize,
1532 vtkIdType const*& cellPoints) VTK_SIZEHINT(cellPoints, cellSize)
1533 {
1534 this->Visit(vtkCellArray_detail::GetCellAtIdImpl{}, cellId, cellSize, cellPoints, this->TempCell);
1535 }
1536
1537 //----------------------------------------------------------------------------
GetCellAtId(vtkIdType cellId,vtkIdList * pts)1538 inline void vtkCellArray::GetCellAtId(vtkIdType cellId, vtkIdList* pts)
1539 {
1540 this->Visit(vtkCellArray_detail::GetCellAtIdImpl{}, cellId, pts);
1541 }
1542
1543 //----------------------------------------------------------------------------
InsertNextCell(vtkIdType npts,const vtkIdType * pts)1544 inline vtkIdType vtkCellArray::InsertNextCell(vtkIdType npts, const vtkIdType* pts)
1545 VTK_SIZEHINT(pts, npts)
1546 {
1547 return this->Visit(vtkCellArray_detail::InsertNextCellImpl{}, npts, pts);
1548 }
1549
1550 //----------------------------------------------------------------------------
InsertNextCell(int npts)1551 inline vtkIdType vtkCellArray::InsertNextCell(int npts)
1552 {
1553 return this->Visit(vtkCellArray_detail::InsertNextCellImpl{}, npts);
1554 }
1555
1556 //----------------------------------------------------------------------------
InsertCellPoint(vtkIdType id)1557 inline void vtkCellArray::InsertCellPoint(vtkIdType id)
1558 {
1559 if (this->Storage.Is64Bit())
1560 {
1561 using ValueType = typename ArrayType64::ValueType;
1562 this->Storage.GetArrays64().Connectivity->InsertNextValue(static_cast<ValueType>(id));
1563 }
1564 else
1565 {
1566 using ValueType = typename ArrayType32::ValueType;
1567 this->Storage.GetArrays32().Connectivity->InsertNextValue(static_cast<ValueType>(id));
1568 }
1569 }
1570
1571 //----------------------------------------------------------------------------
UpdateCellCount(int npts)1572 inline void vtkCellArray::UpdateCellCount(int npts)
1573 {
1574 this->Visit(vtkCellArray_detail::UpdateCellCountImpl{}, npts);
1575 }
1576
1577 //----------------------------------------------------------------------------
InsertNextCell(vtkIdList * pts)1578 inline vtkIdType vtkCellArray::InsertNextCell(vtkIdList* pts)
1579 {
1580 return this->Visit(
1581 vtkCellArray_detail::InsertNextCellImpl{}, pts->GetNumberOfIds(), pts->GetPointer(0));
1582 }
1583
1584 //----------------------------------------------------------------------------
InsertNextCell(vtkCell * cell)1585 inline vtkIdType vtkCellArray::InsertNextCell(vtkCell* cell)
1586 {
1587 vtkIdList* pts = cell->GetPointIds();
1588 return this->Visit(
1589 vtkCellArray_detail::InsertNextCellImpl{}, pts->GetNumberOfIds(), pts->GetPointer(0));
1590 }
1591
1592 //----------------------------------------------------------------------------
Reset()1593 inline void vtkCellArray::Reset()
1594 {
1595 this->Visit(vtkCellArray_detail::ResetImpl{});
1596 }
1597
1598 #endif // vtkCellArray.h
1599