1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCellArrayIterator.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 /**
17  * @class   vtkCellArrayIterator
18  * @brief   Encapsulate traversal logic for vtkCellArray.
19  *
20  * This is iterator for thread-safe traversal of a vtkCellArray. It provides
21  * random access and forward iteration. Typical usage for forward iteration
22  * looks like:
23  *
24  * ```
25  * auto iter = vtk::TakeSmartPointer(cellArray->NewIterator());
26  * for (iter->GoToFirstCell(); !iter->IsDoneWithTraversal(); iter->GoToNextCell())
27  * {
28  *   // do work with iter
29  *   iter->GetCurrentCell(numCellPts, cellPts);
30  * }
31  * ```
32  *
33  * Typical usage for random access looks like:
34  *
35  * ```
36  * auto iter = vtk::TakeSmartPointer(cellArray->NewIterator());
37  * iter->GetCellAtId(cellId, numCellPts, cellPts);
38  * ```
39  *
40  * Here @a cellId is the id of the ith cell in the vtkCellArray;
41  * @a numCellPts is the number of points defining the cell represented
42  * as vtkIdType; and @a cellPts is a pointer to the point ids defined
43  * as vtkIdType const*&.
44  *
45  * Internally the iterator may copy data from the vtkCellArray, or reference
46  * the internal vtkCellArray storage. This depends on the relationship of
47  * vtkIdType to the type and structure of internal storage. If the type of
48  * storage is the same as vtkIdType, and the storage is a single-component
49  * AOS array (i.e., a 1D array), then shared access to the vtkCellArray
50  * storage is provided. Otherwise, the data from storage is copied into an
51  * internal iterator buffer. (Of course copying is slower and can result in
52  * 3-4x reduction in traversal performance. On the other hand, the
53  * vtkCellArray can use the appropriate storage to save memory, perform
54  * zero-copy, and/or efficiently represent the cell connectivity
55  * information.) Note that referencing internal vtkCellArray storage has
56  * implications on the validity of the iterator. If the underlying
57  * vtkCellArray storage changes while iterating, and the iterator is
58  * referencing this storage, unpredictable and catastrophic results are
59  * likely - hence do not modify the vtkCellArray while iterating.
60  *
61  * @sa
62  * vtkCellArray
63  */
64 
65 #ifndef vtkCellArrayIterator_h
66 #define vtkCellArrayIterator_h
67 
68 #include "vtkCommonDataModelModule.h" // For export macro
69 #include "vtkObject.h"
70 
71 #include "vtkCellArray.h"    // Needed for inline methods
72 #include "vtkIdList.h"       // Needed for inline methods
73 #include "vtkSmartPointer.h" // For vtkSmartPointer
74 
75 #include <cassert>     // for assert
76 #include <type_traits> // for std::enable_if
77 
78 class VTKCOMMONDATAMODEL_EXPORT vtkCellArrayIterator : public vtkObject
79 {
80 public:
81   ///@{
82   /**
83    * Standard methods for instantiation, type information, and printing.
84    */
85   vtkTypeMacro(vtkCellArrayIterator, vtkObject);
86   void PrintSelf(ostream& os, vtkIndent indent) override;
87   static vtkCellArrayIterator* New();
88   ///@}
89 
90   /**
91    * Return the vtkCellArray object over which iteration is occuring.
92    */
GetCellArray()93   vtkCellArray* GetCellArray() { return this->CellArray; }
94 
95   /**
96    * Intialize the iterator to a specific cell. This will revalidate the
97    * iterator if the underlying vtkCellArray has been modified. This method
98    * can always be used to set the starting location for forward iteration,
99    * and it is also used to support random access.
100    */
GoToCell(vtkIdType cellId)101   void GoToCell(vtkIdType cellId)
102   {
103     this->CurrentCellId = cellId;
104     this->NumberOfCells = this->CellArray->GetNumberOfCells();
105     assert(cellId <= this->NumberOfCells);
106   }
107 
108   /**
109    * The following are methods supporting random access iteration.
110    */
111 
112   ///@{
113   /**
114    * Initialize the iterator to a specific cell and return the cell. Note
115    * that methods passing vtkIdLists always copy data from the vtkCellArray
116    * storage buffer into the vtkIdList. Otherwise, a fastpath returning
117    * (numCellPts,cellPts) which may return a pointer to internal vtkCellArray
118    * storage is possible, if vtkIdType is the same as the vtkCellArray buffer
119    * (which is typical).
120    */
GetCellAtId(vtkIdType cellId,vtkIdType & numCellPts,vtkIdType const * & cellPts)121   void GetCellAtId(vtkIdType cellId, vtkIdType& numCellPts, vtkIdType const*& cellPts)
122   {
123     this->GoToCell(cellId);
124     this->GetCurrentCell(numCellPts, cellPts);
125   }
GetCellAtId(vtkIdType cellId,vtkIdList * cellIds)126   void GetCellAtId(vtkIdType cellId, vtkIdList* cellIds)
127   {
128     this->GoToCell(cellId);
129     this->GetCurrentCell(cellIds);
130   }
GetCellAtId(vtkIdType cellId)131   vtkIdList* GetCellAtId(vtkIdType cellId)
132   {
133     this->GoToCell(cellId);
134     return this->GetCurrentCell();
135   }
136   ///@}
137 
138   /**
139    * The following are methods supporting forward iteration.
140    */
141 
142   /**
143    * Initialize the iterator for forward iteration. This will revalidate the
144    * iterator if the underlying vtkCellArray has been modified.
145    */
GoToFirstCell()146   void GoToFirstCell()
147   {
148     this->CurrentCellId = 0;
149     this->NumberOfCells = this->CellArray->GetNumberOfCells();
150   }
151 
152   /**
153    * Advance the forward iterator to the next cell.
154    */
GoToNextCell()155   void GoToNextCell() { ++this->CurrentCellId; }
156 
157   /**
158    * Returns true if the iterator has completed the traversal.
159    */
IsDoneWithTraversal()160   bool IsDoneWithTraversal() { return this->CurrentCellId >= this->NumberOfCells; }
161 
162   /**
163    * Returns the id of the current cell during forward iteration.
164    */
GetCurrentCellId()165   vtkIdType GetCurrentCellId() const { return this->CurrentCellId; }
166 
167   ///@{
168   /**
169    * Returns the definition of the current cell during forward
170    * traversal. Note that methods passing vtkIdLists always copy data from
171    * the vtkCellArray storage buffer into the vtkIdList. Otherwise, a
172    * fastpath returning (numCellPts,cellPts) - which may return a pointer to
173    * internal vtkCellArray storage - is possible, if vtkIdType is the same as
174    * the vtkCellArray storage (which is typical).
175    */
GetCurrentCell(vtkIdType & cellSize,vtkIdType const * & cellPoints)176   void GetCurrentCell(vtkIdType& cellSize, vtkIdType const*& cellPoints)
177   {
178     assert(this->CurrentCellId < this->NumberOfCells);
179     // Either refer to vtkCellArray storage buffer, or copy into local buffer
180     if (this->CellArray->IsStorageShareable())
181     {
182       this->CellArray->GetCellAtId(this->CurrentCellId, cellSize, cellPoints);
183     }
184     else // or copy into local iterator buffer.
185     {
186       this->CellArray->GetCellAtId(this->CurrentCellId, this->TempCell);
187       cellSize = this->TempCell->GetNumberOfIds();
188       cellPoints = this->TempCell->GetPointer(0);
189     }
190   }
GetCurrentCell(vtkIdList * ids)191   void GetCurrentCell(vtkIdList* ids)
192   {
193     assert(this->CurrentCellId < this->NumberOfCells);
194     this->CellArray->GetCellAtId(this->CurrentCellId, ids);
195   }
GetCurrentCell()196   vtkIdList* GetCurrentCell()
197   {
198     assert(this->CurrentCellId < this->NumberOfCells);
199     this->CellArray->GetCellAtId(this->CurrentCellId, this->TempCell);
200     return this->TempCell;
201   }
202   ///@}
203 
204   /**
205    * Specialized methods for performing operations on the vtkCellArray.
206    */
207 
208   /**
209    * Replace the current cell with the ids in `list`. Note that this method
210    * CANNOT change the number of points in the cell, it can only redefine the
211    * ids (e.g. `list` must contain the same number of entries as the current
212    * cell's points).
213    */
ReplaceCurrentCell(vtkIdList * list)214   void ReplaceCurrentCell(vtkIdList* list)
215   {
216     assert(this->CurrentCellId < this->NumberOfCells);
217     this->CellArray->ReplaceCellAtId(this->CurrentCellId, list);
218   }
219 
220   /**
221    * Replace the current cell with the ids in `pts`. Note that this method
222    * CANNOT change the number of points in the cell, it can only redefine the
223    * ids (e.g. `npts` must equal the current cell's number of points).
224    */
ReplaceCurrentCell(vtkIdType npts,const vtkIdType * pts)225   void ReplaceCurrentCell(vtkIdType npts, const vtkIdType* pts)
226   {
227     assert(this->CurrentCellId < this->NumberOfCells);
228     this->CellArray->ReplaceCellAtId(this->CurrentCellId, npts, pts);
229   }
230 
231   /**
232    * Reverses the order of the point ids in the current cell.
233    */
ReverseCurrentCell()234   void ReverseCurrentCell()
235   {
236     assert(this->CurrentCellId < this->NumberOfCells);
237     this->CellArray->ReverseCellAtId(this->CurrentCellId);
238   }
239 
240   friend class vtkCellArray;
241 
242 protected:
243   vtkCellArrayIterator() = default;
244   ~vtkCellArrayIterator() override = default;
245 
246   vtkSetMacro(CellArray, vtkCellArray*);
247 
248   vtkSmartPointer<vtkCellArray> CellArray;
249   vtkNew<vtkIdList> TempCell;
250   vtkIdType CurrentCellId;
251   vtkIdType NumberOfCells;
252 
253 private:
254   vtkCellArrayIterator(const vtkCellArrayIterator&) = delete;
255   void operator=(const vtkCellArrayIterator&) = delete;
256 };
257 
258 #endif // vtkCellArrayIterator_h
259