1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCellArray.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 #include "vtkCellArray.h"
17 
18 #include "vtkArrayDispatch.h"
19 #include "vtkCellArrayIterator.h"
20 #include "vtkDataArrayRange.h"
21 #include "vtkIdTypeArray.h"
22 #include "vtkIntArray.h"
23 #include "vtkLongArray.h"
24 #include "vtkLongLongArray.h"
25 #include "vtkObjectFactory.h"
26 #include "vtkSMPThreadLocal.h"
27 #include "vtkSMPTools.h"
28 
29 #include <algorithm>
30 #include <array>
31 #include <iterator>
32 
33 namespace
34 {
35 
36 // These implementations are for methods that will be deprecated in the future:
37 namespace deprec
38 {
39 
40 struct GetSizeImpl
41 {
42   template <typename CellStateT>
operator ()__anon5799168e0111::deprec::GetSizeImpl43   vtkIdType operator()(CellStateT& cells) const
44   {
45     return (cells.GetOffsets()->GetSize() + cells.GetConnectivity()->GetSize());
46   }
47 };
48 
49 // Given a legacy Location, find the corresponding cellId. The location
50 // *must* refer to a [numPts] entry in the old connectivity array, or the
51 // returned CellId will be -1.
52 struct LocationToCellIdFunctor
53 {
54   template <typename CellStateT>
operator ()__anon5799168e0111::deprec::LocationToCellIdFunctor55   vtkIdType operator()(CellStateT& cells, vtkIdType location) const
56   {
57     using ValueType = typename CellStateT::ValueType;
58 
59     const auto offsets = vtk::DataArrayValueRange<1>(cells.GetOffsets());
60 
61     // Use a binary-search to find the location:
62     auto it = this->BinarySearchOffset(
63       offsets.begin(), offsets.end() - 1, static_cast<ValueType>(location));
64 
65     const vtkIdType cellId = std::distance(offsets.begin(), it);
66 
67     if (it == offsets.end() - 1 /* no match found */ ||
68       (*it + cellId) != location /* `location` not at cell head */)
69     { // Location invalid.
70       return -1;
71     }
72 
73     // return the cell id:
74     return cellId;
75   }
76 
77   template <typename IterT>
BinarySearchOffset__anon5799168e0111::deprec::LocationToCellIdFunctor78   IterT BinarySearchOffset(const IterT& beginIter, const IterT& endIter,
79     const typename std::iterator_traits<IterT>::value_type& targetLocation) const
80   {
81     using ValueType = typename std::iterator_traits<IterT>::value_type;
82     using DifferenceType = typename std::iterator_traits<IterT>::difference_type;
83 
84     DifferenceType roiSize = std::distance(beginIter, endIter);
85 
86     IterT roiBegin = beginIter;
87     while (roiSize > 0)
88     {
89       IterT it = roiBegin;
90       const DifferenceType step = roiSize / 2;
91       std::advance(it, step);
92       // This differs from a generic binary search in the following line:
93       // Adding the distance from the start of the array to the current
94       // iterator will account for the cellSize entries in the old cell array
95       // format, such that curLocation would be the offset in the old style
96       // connectivity array.
97       const ValueType curLocation = *it + std::distance(beginIter, it);
98       if (curLocation < targetLocation)
99       {
100         roiBegin = ++it;
101         roiSize -= step + 1;
102       }
103       else
104       {
105         roiSize = step;
106       }
107     }
108 
109     return roiBegin;
110   }
111 };
112 
113 struct CellIdToLocationFunctor
114 {
115   template <typename CellStateT>
operator ()__anon5799168e0111::deprec::CellIdToLocationFunctor116   vtkIdType operator()(CellStateT& cells, vtkIdType cellId) const
117   {
118     // Adding the cellId to the offset of that cell id gives us the cell
119     // location in the old-style vtkCellArray connectivity array.
120     return static_cast<vtkIdType>(cells.GetOffsets()->GetValue(cellId)) + cellId;
121   }
122 };
123 
124 struct GetInsertLocationImpl
125 {
126   template <typename CellStateT>
operator ()__anon5799168e0111::deprec::GetInsertLocationImpl127   vtkIdType operator()(CellStateT& cells) const
128   {
129     // The insert location used to just be the tail of the connectivity array.
130     // Compute the equivalent value:
131     return (
132       (cells.GetOffsets()->GetNumberOfValues() - 1) + cells.GetConnectivity()->GetNumberOfValues());
133   }
134 };
135 
136 } // end namespace deprec
137 
138 struct PrintDebugImpl
139 {
140   template <typename CellStateT>
operator ()__anon5799168e0111::PrintDebugImpl141   void operator()(CellStateT& state, std::ostream& os)
142   {
143     using ValueType = typename CellStateT::ValueType;
144 
145     const vtkIdType numCells = state.GetNumberOfCells();
146     for (vtkIdType cellId = 0; cellId < numCells; ++cellId)
147     {
148       os << "cell " << cellId << ": ";
149 
150       const auto cellRange = state.GetCellRange(cellId);
151       for (ValueType ptId : cellRange)
152       {
153         os << ptId << " ";
154       }
155 
156       os << "\n";
157     }
158   }
159 };
160 
161 struct InitializeImpl
162 {
163   template <typename CellStateT>
operator ()__anon5799168e0111::InitializeImpl164   void operator()(CellStateT& cells) const
165   {
166     cells.GetConnectivity()->Initialize();
167     cells.GetOffsets()->Initialize();
168     cells.GetOffsets()->InsertNextValue(0);
169   }
170 };
171 
172 struct SqueezeImpl
173 {
174   template <typename CellStateT>
operator ()__anon5799168e0111::SqueezeImpl175   void operator()(CellStateT& cells) const
176   {
177     cells.GetConnectivity()->Squeeze();
178     cells.GetOffsets()->Squeeze();
179   }
180 };
181 
182 struct IsValidImpl
183 {
184   template <typename CellStateT>
operator ()__anon5799168e0111::IsValidImpl185   bool operator()(CellStateT& state) const
186   {
187     using ValueType = typename CellStateT::ValueType;
188     auto* offsetArray = state.GetOffsets();
189     auto* connArray = state.GetConnectivity();
190 
191     // Both arrays must be single component
192     if (offsetArray->GetNumberOfComponents() != 1 || connArray->GetNumberOfComponents() != 1)
193     {
194       return false;
195     }
196 
197     auto offsets = vtk::DataArrayValueRange<1>(offsetArray);
198 
199     // Offsets must have at least one value, and the first value must be zero
200     if (offsets.size() == 0 || *offsets.cbegin() != 0)
201     {
202       return false;
203     }
204 
205     // Values in offsets must not decrease
206     auto it = std::adjacent_find(offsets.cbegin(), offsets.cend(),
207       [](const ValueType a, const ValueType b) -> bool { return a > b; });
208     if (it != offsets.cend())
209     {
210       return false;
211     }
212 
213     // The last value in offsets must be the size of the connectivity array.
214     if (connArray->GetNumberOfValues() != *(offsets.cend() - 1))
215     {
216       return false;
217     }
218 
219     return true;
220   }
221 };
222 
223 template <typename T>
224 struct CanConvert
225 {
226   template <typename CellStateT>
operator ()__anon5799168e0111::CanConvert227   bool operator()(CellStateT& state) const
228   {
229     using ArrayType = typename CellStateT::ArrayType;
230     using ValueType = typename CellStateT::ValueType;
231 
232     // offsets are sorted, so just check the last value, but we have to compute
233     // the full range of the connectivity array.
234     auto* off = state.GetOffsets();
235     if (off->GetNumberOfValues() > 0 && !this->CheckValue(off->GetValue(off->GetMaxId())))
236     {
237       return false;
238     }
239 
240     std::array<ValueType, 2> connRange;
241     auto* mutConn = const_cast<ArrayType*>(state.GetConnectivity());
242     if (mutConn->GetNumberOfValues() > 0)
243     {
244       mutConn->GetValueRange(connRange.data(), 0);
245       if (!this->CheckValue(connRange[0]) || !this->CheckValue(connRange[1]))
246       {
247         return false;
248       }
249     }
250 
251     return true;
252   }
253 
254   template <typename U>
CheckValue__anon5799168e0111::CanConvert255   bool CheckValue(const U& val) const
256   {
257     return val == static_cast<U>(static_cast<T>(val));
258   }
259 };
260 
261 struct ExtractAndInitialize
262 {
263   template <typename CellStateT, typename TargetArrayT>
operator ()__anon5799168e0111::ExtractAndInitialize264   bool operator()(CellStateT& state, TargetArrayT* offsets, TargetArrayT* conn) const
265   {
266     return (
267       this->Process(state.GetOffsets(), offsets) && this->Process(state.GetConnectivity(), conn));
268   }
269 
270   template <typename SourceArrayT, typename TargetArrayT>
Process__anon5799168e0111::ExtractAndInitialize271   bool Process(SourceArrayT* src, TargetArrayT* dst) const
272   {
273     // Check that allocation suceeds:
274     if (!dst->Resize(src->GetNumberOfTuples()))
275     {
276       return false;
277     }
278 
279     // Copy data:
280     dst->DeepCopy(src);
281 
282     // Free old memory:
283     src->Resize(0);
284 
285     return true;
286   }
287 };
288 
289 struct IsHomogeneousImpl
290 {
291   template <typename CellArraysT>
operator ()__anon5799168e0111::IsHomogeneousImpl292   vtkIdType operator()(CellArraysT& state) const
293   {
294     using ValueType = typename CellArraysT::ValueType;
295     auto* offsets = state.GetOffsets();
296 
297     const vtkIdType numCells = state.GetNumberOfCells();
298     if (numCells == 0)
299     {
300       return 0;
301     }
302 
303     // Initialize using the first cell:
304     const vtkIdType firstCellSize = state.GetCellSize(0);
305 
306     // Verify the rest:
307     auto offsetRange = vtk::DataArrayValueRange<1>(offsets);
308     auto it = std::adjacent_find(offsetRange.begin() + 1, offsetRange.end(),
309       [&](const ValueType a, const ValueType b) -> bool { return (b - a != firstCellSize); });
310 
311     if (it != offsetRange.end())
312     { // Found a cell that doesn't match the size of the first cell:
313       return -1;
314     }
315 
316     return firstCellSize;
317   }
318 };
319 
320 struct AllocateExactImpl
321 {
322   template <typename CellStateT>
operator ()__anon5799168e0111::AllocateExactImpl323   bool operator()(CellStateT& cells, vtkIdType numCells, vtkIdType connectivitySize) const
324   {
325     const bool result = (cells.GetOffsets()->Allocate(numCells + 1) &&
326       cells.GetConnectivity()->Allocate(connectivitySize));
327     if (result)
328     {
329       cells.GetOffsets()->InsertNextValue(0);
330     }
331 
332     return result;
333   }
334 };
335 
336 struct ResizeExactImpl
337 {
338   template <typename CellStateT>
operator ()__anon5799168e0111::ResizeExactImpl339   bool operator()(CellStateT& cells, vtkIdType numCells, vtkIdType connectivitySize) const
340   {
341     return (cells.GetOffsets()->SetNumberOfValues(numCells + 1) &&
342       cells.GetConnectivity()->SetNumberOfValues(connectivitySize));
343   }
344 };
345 
346 struct FindMaxCell // SMP functor
347 {
348   vtkCellArray* CellArray;
349   vtkIdType Result{ 0 };
350   vtkSMPThreadLocal<vtkIdType> LocalResult;
351 
FindMaxCell__anon5799168e0111::FindMaxCell352   FindMaxCell(vtkCellArray* array)
353     : CellArray{ array }
354   {
355   }
356 
Initialize__anon5799168e0111::FindMaxCell357   void Initialize() { this->LocalResult.Local() = 0; }
358 
359   struct Impl
360   {
361     template <typename CellStateT>
operator ()__anon5799168e0111::FindMaxCell::Impl362     vtkIdType operator()(CellStateT& cells, vtkIdType cellId, const vtkIdType endCellId) const
363     {
364       vtkIdType result = 0;
365       for (; cellId < endCellId; ++cellId)
366       {
367         result = std::max(result, cells.GetCellSize(cellId));
368       }
369       return result;
370     }
371   };
372 
operator ()__anon5799168e0111::FindMaxCell373   void operator()(vtkIdType cellId, vtkIdType endCellId)
374   {
375     vtkIdType& lval = this->LocalResult.Local();
376     lval = std::max(lval, this->CellArray->Visit(Impl{}, cellId, endCellId));
377   }
378 
Reduce__anon5799168e0111::FindMaxCell379   void Reduce()
380   {
381     for (const vtkIdType lResult : this->LocalResult)
382     {
383       this->Result = std::max(this->Result, lResult);
384     }
385   }
386 };
387 
388 struct GetActualMemorySizeImpl
389 {
390   template <typename CellStateT>
operator ()__anon5799168e0111::GetActualMemorySizeImpl391   unsigned long operator()(CellStateT& cells) const
392   {
393     return (
394       cells.GetOffsets()->GetActualMemorySize() + cells.GetConnectivity()->GetActualMemorySize());
395   }
396 };
397 
398 struct PrintSelfImpl
399 {
400   template <typename CellStateT>
operator ()__anon5799168e0111::PrintSelfImpl401   void operator()(CellStateT& cells, ostream& os, vtkIndent indent) const
402   {
403     os << indent << "Offsets:\n";
404     cells.GetOffsets()->PrintSelf(os, indent.GetNextIndent());
405     os << indent << "Connectivity:\n";
406     cells.GetConnectivity()->PrintSelf(os, indent.GetNextIndent());
407   }
408 };
409 
410 struct GetLegacyDataSizeImpl
411 {
412   template <typename CellStateT>
operator ()__anon5799168e0111::GetLegacyDataSizeImpl413   vtkIdType operator()(CellStateT& cells) const
414   {
415     return (
416       (cells.GetOffsets()->GetNumberOfValues() - 1) + cells.GetConnectivity()->GetNumberOfValues());
417   }
418 };
419 
420 struct ReverseCellAtIdImpl
421 {
422   template <typename CellStateT>
operator ()__anon5799168e0111::ReverseCellAtIdImpl423   void operator()(CellStateT& cells, vtkIdType cellId) const
424   {
425     auto cellRange = cells.GetCellRange(cellId);
426     std::reverse(cellRange.begin(), cellRange.end());
427   }
428 };
429 
430 struct ReplaceCellAtIdImpl
431 {
432   template <typename CellStateT>
operator ()__anon5799168e0111::ReplaceCellAtIdImpl433   void operator()(
434     CellStateT& cells, vtkIdType cellId, vtkIdType cellSize, const vtkIdType* cellPoints) const
435   {
436     using ValueType = typename CellStateT::ValueType;
437 
438     auto cellRange = cells.GetCellRange(cellId);
439 
440     assert(cellRange.size() == cellSize);
441     for (vtkIdType i = 0; i < cellSize; ++i)
442     {
443       cellRange[i] = static_cast<ValueType>(cellPoints[i]);
444     }
445   }
446 };
447 
448 struct AppendLegacyFormatImpl
449 {
450   template <typename CellStateT>
operator ()__anon5799168e0111::AppendLegacyFormatImpl451   void operator()(
452     CellStateT& cells, const vtkIdType* data, const vtkIdType len, const vtkIdType ptOffset) const
453   {
454     using ValueType = typename CellStateT::ValueType;
455 
456     ValueType offset = static_cast<ValueType>(cells.GetConnectivity()->GetNumberOfValues());
457 
458     const vtkIdType* const dataEnd = data + len;
459     while (data < dataEnd)
460     {
461       vtkIdType numPts = *data++;
462       offset += static_cast<ValueType>(numPts);
463       cells.GetOffsets()->InsertNextValue(offset);
464       while (numPts-- > 0)
465       {
466         cells.GetConnectivity()->InsertNextValue(static_cast<ValueType>(*data++ + ptOffset));
467       }
468     }
469   }
470 };
471 
472 struct AppendImpl
473 {
474   // Call this signature:
475   template <typename DstCellStateT>
operator ()__anon5799168e0111::AppendImpl476   void operator()(DstCellStateT& dstcells, vtkCellArray* src, vtkIdType pointOffset) const
477   { // dispatch on src:
478     src->Visit(*this, dstcells, pointOffset);
479   }
480 
481   // Above signature calls this operator in Visit:
482   template <typename SrcCellStateT, typename DstCellStateT>
operator ()__anon5799168e0111::AppendImpl483   void operator()(SrcCellStateT& src, DstCellStateT& dst, vtkIdType pointOffsets) const
484   {
485     this->AppendArrayWithOffset(
486       src.GetOffsets(), dst.GetOffsets(), dst.GetConnectivity()->GetNumberOfValues(), true);
487     this->AppendArrayWithOffset(src.GetConnectivity(), dst.GetConnectivity(), pointOffsets, false);
488   }
489 
490   // Assumes both arrays are 1 component. src's data is appended to dst with
491   // offset added to each value.
492   template <typename SrcArrayT, typename DstArrayT>
AppendArrayWithOffset__anon5799168e0111::AppendImpl493   void AppendArrayWithOffset(
494     SrcArrayT* srcArray, DstArrayT* dstArray, vtkIdType offset, bool skipFirst) const
495   {
496     VTK_ASSUME(srcArray->GetNumberOfComponents() == 1);
497     VTK_ASSUME(dstArray->GetNumberOfComponents() == 1);
498 
499     using SrcValueType = vtk::GetAPIType<SrcArrayT>;
500     using DstValueType = vtk::GetAPIType<DstArrayT>;
501 
502     const vtkIdType srcSize =
503       skipFirst ? srcArray->GetNumberOfValues() - 1 : srcArray->GetNumberOfValues();
504     const vtkIdType dstBegin = dstArray->GetNumberOfValues();
505     const vtkIdType dstEnd = dstBegin + srcSize;
506 
507     // This extends the allocation of dst to ensure we have enough space
508     // allocated:
509     dstArray->InsertValue(dstEnd - 1, 0);
510 
511     const auto srcRange = vtk::DataArrayValueRange<1>(srcArray, skipFirst ? 1 : 0);
512     auto dstRange = vtk::DataArrayValueRange<1>(dstArray, dstBegin, dstEnd);
513     assert(srcRange.size() == dstRange.size());
514 
515     const DstValueType dOffset = static_cast<DstValueType>(offset);
516 
517     std::transform(srcRange.cbegin(), srcRange.cend(), dstRange.begin(),
518       [&](SrcValueType x) -> DstValueType { return static_cast<DstValueType>(x) + dOffset; });
519   }
520 };
521 
522 } // end anon namespace
523 
524 vtkCellArray::vtkCellArray() = default;
525 vtkCellArray::~vtkCellArray() = default;
526 vtkStandardNewMacro(vtkCellArray);
527 
528 //=================== Begin Legacy Methods ===================================
529 // These should be deprecated at some point as they are confusing or very slow
530 
531 //------------------------------------------------------------------------------
GetSize()532 vtkIdType vtkCellArray::GetSize()
533 {
534   // We can still compute roughly the same result, so go ahead and do that.
535   return this->Visit(deprec::GetSizeImpl{});
536 }
537 
538 //------------------------------------------------------------------------------
GetNumberOfConnectivityEntries()539 vtkIdType vtkCellArray::GetNumberOfConnectivityEntries()
540 {
541   // We can still compute roughly the same result, so go ahead and do that.
542   return this->Visit(GetLegacyDataSizeImpl{});
543 }
544 
545 //------------------------------------------------------------------------------
GetCell(vtkIdType loc,vtkIdType & npts,const vtkIdType * & pts)546 void vtkCellArray::GetCell(vtkIdType loc, vtkIdType& npts, const vtkIdType*& pts)
547 {
548   const vtkIdType cellId = this->Visit(deprec::LocationToCellIdFunctor{}, loc);
549   if (cellId < 0)
550   {
551     vtkErrorMacro("Invalid location.");
552     npts = 0;
553     pts = nullptr;
554     return;
555   }
556 
557   this->GetCellAtId(cellId, this->TempCell);
558   npts = this->TempCell->GetNumberOfIds();
559   pts = this->TempCell->GetPointer(0);
560 }
561 
562 //------------------------------------------------------------------------------
GetCell(vtkIdType loc,vtkIdList * pts)563 void vtkCellArray::GetCell(vtkIdType loc, vtkIdList* pts)
564 {
565   const vtkIdType cellId = this->Visit(deprec::LocationToCellIdFunctor{}, loc);
566   if (cellId < 0)
567   {
568     vtkErrorMacro("Invalid location.");
569     pts->Reset();
570     return;
571   }
572 
573   this->GetCellAtId(cellId, pts);
574 }
575 
576 //------------------------------------------------------------------------------
GetInsertLocation(int npts)577 vtkIdType vtkCellArray::GetInsertLocation(int npts)
578 {
579   // It looks like the original implementation of this actually returned the
580   // location of the last cell (of size npts), not the current insert location.
581   return this->Visit(deprec::GetInsertLocationImpl{}) - npts - 1;
582 }
583 
584 //------------------------------------------------------------------------------
GetTraversalLocation()585 vtkIdType vtkCellArray::GetTraversalLocation()
586 {
587   return this->Visit(deprec::CellIdToLocationFunctor{}, this->GetTraversalCellId());
588 }
589 
590 //------------------------------------------------------------------------------
GetTraversalLocation(vtkIdType npts)591 vtkIdType vtkCellArray::GetTraversalLocation(vtkIdType npts)
592 {
593   return this->Visit(deprec::CellIdToLocationFunctor{}, this->GetTraversalCellId()) - npts - 1;
594 }
595 
596 //------------------------------------------------------------------------------
SetTraversalLocation(vtkIdType loc)597 void vtkCellArray::SetTraversalLocation(vtkIdType loc)
598 {
599   const vtkIdType cellId = this->Visit(deprec::LocationToCellIdFunctor{}, loc);
600   if (cellId < 0)
601   {
602     vtkErrorMacro("Invalid location, ignoring.");
603     return;
604   }
605 
606   this->SetTraversalCellId(cellId);
607 }
608 
609 //------------------------------------------------------------------------------
EstimateSize(vtkIdType numCells,int maxPtsPerCell)610 vtkIdType vtkCellArray::EstimateSize(vtkIdType numCells, int maxPtsPerCell)
611 {
612   return numCells * (1 + maxPtsPerCell);
613 }
614 
615 //------------------------------------------------------------------------------
SetNumberOfCells(vtkIdType)616 void vtkCellArray::SetNumberOfCells(vtkIdType)
617 {
618   // no-op
619 }
620 
621 //------------------------------------------------------------------------------
ReverseCell(vtkIdType loc)622 void vtkCellArray::ReverseCell(vtkIdType loc)
623 {
624   const vtkIdType cellId = this->Visit(deprec::LocationToCellIdFunctor{}, loc);
625   if (cellId < 0)
626   {
627     vtkErrorMacro("Invalid location, ignoring.");
628     return;
629   }
630 
631   this->ReverseCellAtId(cellId);
632 }
633 
634 //------------------------------------------------------------------------------
ReplaceCell(vtkIdType loc,int npts,const vtkIdType pts[])635 void vtkCellArray::ReplaceCell(vtkIdType loc, int npts, const vtkIdType pts[])
636 {
637   const vtkIdType cellId = this->Visit(deprec::LocationToCellIdFunctor{}, loc);
638   if (cellId < 0)
639   {
640     vtkErrorMacro("Invalid location, ignoring.");
641     return;
642   }
643 
644   this->ReplaceCellAtId(cellId, static_cast<vtkIdType>(npts), pts);
645 }
646 
647 //------------------------------------------------------------------------------
GetData()648 vtkIdTypeArray* vtkCellArray::GetData()
649 {
650   this->ExportLegacyFormat(this->LegacyData);
651 
652   return this->LegacyData;
653 }
654 
655 //------------------------------------------------------------------------------
656 // Specify a group of cells.
SetCells(vtkIdType ncells,vtkIdTypeArray * cells)657 void vtkCellArray::SetCells(vtkIdType ncells, vtkIdTypeArray* cells)
658 {
659   this->AllocateExact(ncells, cells->GetNumberOfValues() - ncells);
660   this->ImportLegacyFormat(cells);
661 }
662 
663 //=================== End Legacy Methods =====================================
664 
665 //------------------------------------------------------------------------------
DeepCopy(vtkCellArray * ca)666 void vtkCellArray::DeepCopy(vtkCellArray* ca)
667 {
668   if (ca == this)
669   {
670     return;
671   }
672 
673   if (ca->Storage.Is64Bit())
674   {
675     this->Storage.Use64BitStorage();
676     auto& srcStorage = ca->Storage.GetArrays64();
677     auto& dstStorage = this->Storage.GetArrays64();
678     dstStorage.Offsets->DeepCopy(srcStorage.Offsets);
679     dstStorage.Connectivity->DeepCopy(srcStorage.Connectivity);
680     this->Modified();
681   }
682   else
683   {
684     this->Storage.Use32BitStorage();
685     auto& srcStorage = ca->Storage.GetArrays32();
686     auto& dstStorage = this->Storage.GetArrays32();
687     dstStorage.Offsets->DeepCopy(srcStorage.Offsets);
688     dstStorage.Connectivity->DeepCopy(srcStorage.Connectivity);
689     this->Modified();
690   }
691 }
692 
693 //------------------------------------------------------------------------------
ShallowCopy(vtkCellArray * ca)694 void vtkCellArray::ShallowCopy(vtkCellArray* ca)
695 {
696   if (ca == this)
697   {
698     return;
699   }
700 
701   if (ca->Storage.Is64Bit())
702   {
703     auto& srcStorage = ca->Storage.GetArrays64();
704     this->SetData(srcStorage.GetOffsets(), srcStorage.GetConnectivity());
705   }
706   else
707   {
708     auto& srcStorage = ca->Storage.GetArrays32();
709     this->SetData(srcStorage.GetOffsets(), srcStorage.GetConnectivity());
710   }
711 }
712 
713 //------------------------------------------------------------------------------
Append(vtkCellArray * src,vtkIdType pointOffset)714 void vtkCellArray::Append(vtkCellArray* src, vtkIdType pointOffset)
715 {
716   if (src->GetNumberOfCells() > 0)
717   {
718     this->Visit(AppendImpl{}, src, pointOffset);
719   }
720 }
721 
722 //------------------------------------------------------------------------------
Initialize()723 void vtkCellArray::Initialize()
724 {
725   this->Visit(InitializeImpl{});
726 
727   this->LegacyData->Initialize();
728 }
729 
730 //------------------------------------------------------------------------------
NewIterator()731 vtkCellArrayIterator* vtkCellArray::NewIterator()
732 {
733   vtkCellArrayIterator* iter = vtkCellArrayIterator::New();
734   iter->SetCellArray(this);
735   iter->GoToFirstCell();
736   return iter;
737 }
738 
739 //------------------------------------------------------------------------------
SetData(vtkTypeInt32Array * offsets,vtkTypeInt32Array * connectivity)740 void vtkCellArray::SetData(vtkTypeInt32Array* offsets, vtkTypeInt32Array* connectivity)
741 {
742   if (offsets->GetNumberOfComponents() != 1 || connectivity->GetNumberOfComponents() != 1)
743   {
744     vtkErrorMacro("Only single component arrays may be used for vtkCellArray "
745                   "storage.");
746     return;
747   }
748 
749   this->Storage.Use32BitStorage();
750   auto& storage = this->Storage.GetArrays32();
751 
752   // vtkArrayDownCast to ensure this works when ArrayType32 is vtkIdTypeArray.
753   storage.Offsets = vtkArrayDownCast<ArrayType32>(offsets);
754   storage.Connectivity = vtkArrayDownCast<ArrayType32>(connectivity);
755   this->Modified();
756 }
757 
758 //------------------------------------------------------------------------------
SetData(vtkTypeInt64Array * offsets,vtkTypeInt64Array * connectivity)759 void vtkCellArray::SetData(vtkTypeInt64Array* offsets, vtkTypeInt64Array* connectivity)
760 {
761   if (offsets->GetNumberOfComponents() != 1 || connectivity->GetNumberOfComponents() != 1)
762   {
763     vtkErrorMacro("Only single component arrays may be used for vtkCellArray "
764                   "storage.");
765     return;
766   }
767 
768   this->Storage.Use64BitStorage();
769   auto& storage = this->Storage.GetArrays64();
770 
771   // vtkArrayDownCast to ensure this works when ArrayType64 is vtkIdTypeArray.
772   storage.Offsets = vtkArrayDownCast<ArrayType64>(offsets);
773   storage.Connectivity = vtkArrayDownCast<ArrayType64>(connectivity);
774   this->Modified();
775 }
776 
777 //------------------------------------------------------------------------------
SetData(vtkIdTypeArray * offsets,vtkIdTypeArray * connectivity)778 void vtkCellArray::SetData(vtkIdTypeArray* offsets, vtkIdTypeArray* connectivity)
779 {
780 #ifdef VTK_USE_64BIT_IDS
781   vtkNew<vtkTypeInt64Array> o;
782   vtkNew<vtkTypeInt64Array> c;
783   o->ShallowCopy(offsets);
784   c->ShallowCopy(connectivity);
785   this->SetData(o, c);
786 #else  // VTK_USE_64BIT_IDS
787   vtkNew<vtkTypeInt32Array> o;
788   vtkNew<vtkTypeInt32Array> c;
789   o->ShallowCopy(offsets);
790   c->ShallowCopy(connectivity);
791   this->SetData(o, c);
792 #endif // VTK_USE_64BIT_IDS
793 }
794 
795 //------------------------------------------------------------------------------
SetData(vtkAOSDataArrayTemplate<int> * offsets,vtkAOSDataArrayTemplate<int> * connectivity)796 void vtkCellArray::SetData(
797   vtkAOSDataArrayTemplate<int>* offsets, vtkAOSDataArrayTemplate<int>* connectivity)
798 {
799 #if VTK_SIZEOF_INT == 4
800   vtkNew<vtkTypeInt32Array> o;
801   vtkNew<vtkTypeInt32Array> c;
802   o->ShallowCopy(offsets);
803   c->ShallowCopy(connectivity);
804   this->SetData(o, c);
805 #elif VTK_SIZEOF_INT == 8
806   vtkNew<vtkTypeInt64Array> o;
807   vtkNew<vtkTypeInt64Array> c;
808   o->ShallowCopy(offsets);
809   c->ShallowCopy(connectivity);
810   this->SetData(o, c);
811 #else
812   vtkErrorMacro("`int` type is neither 32 nor 64 bits.");
813 #endif
814 }
815 
816 //------------------------------------------------------------------------------
SetData(vtkAOSDataArrayTemplate<long> * offsets,vtkAOSDataArrayTemplate<long> * connectivity)817 void vtkCellArray::SetData(
818   vtkAOSDataArrayTemplate<long>* offsets, vtkAOSDataArrayTemplate<long>* connectivity)
819 {
820 #if VTK_SIZEOF_LONG == 4
821   vtkNew<vtkTypeInt32Array> o;
822   vtkNew<vtkTypeInt32Array> c;
823   o->ShallowCopy(offsets);
824   c->ShallowCopy(connectivity);
825   this->SetData(o, c);
826 #elif VTK_SIZEOF_LONG == 8
827   vtkNew<vtkTypeInt64Array> o;
828   vtkNew<vtkTypeInt64Array> c;
829   o->ShallowCopy(offsets);
830   c->ShallowCopy(connectivity);
831   this->SetData(o, c);
832 #else
833   vtkErrorMacro("`long` type is neither 32 nor 64 bits.");
834 #endif
835 }
836 
837 //------------------------------------------------------------------------------
SetData(vtkAOSDataArrayTemplate<long long> * offsets,vtkAOSDataArrayTemplate<long long> * connectivity)838 void vtkCellArray::SetData(
839   vtkAOSDataArrayTemplate<long long>* offsets, vtkAOSDataArrayTemplate<long long>* connectivity)
840 {
841 #if VTK_SIZEOF_LONG_LONG == 4
842   vtkNew<vtkTypeInt32Array> o;
843   vtkNew<vtkTypeInt32Array> c;
844   o->ShallowCopy(offsets);
845   c->ShallowCopy(connectivity);
846   this->SetData(o, c);
847 #elif VTK_SIZEOF_LONG_LONG == 8
848   vtkNew<vtkTypeInt64Array> o;
849   vtkNew<vtkTypeInt64Array> c;
850   o->ShallowCopy(offsets);
851   c->ShallowCopy(connectivity);
852   this->SetData(o, c);
853 #else
854   vtkErrorMacro("`long long` type is neither 32 nor 64 bits.");
855 #endif
856 }
857 
858 namespace
859 {
860 
861 struct SetDataGenericImpl
862 {
863   vtkCellArray* CellArray;
864   vtkDataArray* ConnDA;
865   bool ArraysMatch;
866 
867   template <typename ArrayT>
operator ()__anon5799168e0511::SetDataGenericImpl868   void operator()(ArrayT* offsets)
869   {
870     ArrayT* conn = vtkArrayDownCast<ArrayT>(this->ConnDA);
871     if (!conn)
872     {
873       this->ArraysMatch = false;
874       return;
875     }
876     this->ArraysMatch = true;
877 
878     this->CellArray->SetData(offsets, conn);
879   }
880 };
881 
882 struct GenerateOffsetsImpl
883 {
884   vtkIdType CellSize;
885   vtkIdType ConnectivityArraySize;
886 
887   template <typename ArrayT>
operator ()__anon5799168e0511::GenerateOffsetsImpl888   void operator()(ArrayT* offsets)
889   {
890     for (vtkIdType cc = 0, max = (offsets->GetNumberOfTuples() - 1); cc < max; ++cc)
891     {
892       offsets->SetTypedComponent(cc, 0, cc * this->CellSize);
893     }
894     offsets->SetTypedComponent(offsets->GetNumberOfTuples() - 1, 0, this->ConnectivityArraySize);
895   }
896 };
897 
898 } // end anon namespace
899 
900 //------------------------------------------------------------------------------
SetData(vtkDataArray * offsets,vtkDataArray * connectivity)901 bool vtkCellArray::SetData(vtkDataArray* offsets, vtkDataArray* connectivity)
902 {
903   SetDataGenericImpl worker{ this, connectivity, false };
904   using SupportedArrays = vtkCellArray::InputArrayList;
905   using Dispatch = vtkArrayDispatch::DispatchByArray<SupportedArrays>;
906   if (!Dispatch::Execute(offsets, worker))
907   {
908     vtkErrorMacro("Invalid array types passed to SetData: "
909       << "offsets=" << offsets->GetClassName() << ", "
910       << "connectivity=" << connectivity->GetClassName());
911     return false;
912   }
913 
914   if (!worker.ArraysMatch)
915   {
916     vtkErrorMacro("Offsets and Connectivity arrays must have the same type.");
917     return false;
918   }
919 
920   return true;
921 }
922 
923 //------------------------------------------------------------------------------
SetData(vtkIdType cellSize,vtkDataArray * connectivity)924 bool vtkCellArray::SetData(vtkIdType cellSize, vtkDataArray* connectivity)
925 {
926   if (connectivity == nullptr || cellSize <= 0)
927   {
928     vtkErrorMacro("Invalid cellSize or connectivity array.");
929     return false;
930   }
931 
932   if ((connectivity->GetNumberOfTuples() % cellSize) != 0)
933   {
934     vtkErrorMacro("Connectivity array size is not suitable for chosen cellSize");
935     return false;
936   }
937 
938   vtkSmartPointer<vtkDataArray> offsets;
939   offsets.TakeReference(connectivity->NewInstance());
940   offsets->SetNumberOfTuples(1 + connectivity->GetNumberOfTuples() / cellSize);
941 
942   GenerateOffsetsImpl worker{ cellSize, connectivity->GetNumberOfTuples() };
943   using SupportedArrays = vtkCellArray::InputArrayList;
944   using Dispatch = vtkArrayDispatch::DispatchByArray<SupportedArrays>;
945   if (!Dispatch::Execute(offsets, worker))
946   {
947     vtkErrorMacro("Invalid array types passed to SetData: "
948       << "connectivity=" << connectivity->GetClassName());
949     return false;
950   }
951 
952   return this->SetData(offsets, connectivity);
953 }
954 
955 //------------------------------------------------------------------------------
Use32BitStorage()956 void vtkCellArray::Use32BitStorage()
957 {
958   if (!this->Storage.Is64Bit())
959   {
960     this->Initialize();
961     return;
962   }
963   this->Storage.Use32BitStorage();
964 }
965 
966 //------------------------------------------------------------------------------
Use64BitStorage()967 void vtkCellArray::Use64BitStorage()
968 {
969   if (this->Storage.Is64Bit())
970   {
971     this->Initialize();
972     return;
973   }
974   this->Storage.Use64BitStorage();
975 }
976 
977 //------------------------------------------------------------------------------
UseDefaultStorage()978 void vtkCellArray::UseDefaultStorage()
979 {
980 #ifdef VTK_USE_64BIT_IDS
981   this->Use64BitStorage();
982 #else  // VTK_USE_64BIT_IDS
983   this->Use32BitStorage();
984 #endif // VTK_USE_64BIT_IDS
985 }
986 
987 //------------------------------------------------------------------------------
CanConvertTo32BitStorage() const988 bool vtkCellArray::CanConvertTo32BitStorage() const
989 {
990   if (!this->Storage.Is64Bit())
991   {
992     return true;
993   }
994   return this->Visit(CanConvert<ArrayType32::ValueType>{});
995 }
996 
997 //------------------------------------------------------------------------------
CanConvertTo64BitStorage() const998 bool vtkCellArray::CanConvertTo64BitStorage() const
999 {
1000   return true;
1001 }
1002 
1003 //------------------------------------------------------------------------------
CanConvertToDefaultStorage() const1004 bool vtkCellArray::CanConvertToDefaultStorage() const
1005 {
1006 #ifdef VTK_USE_64BIT_IDS
1007   return this->CanConvertTo64BitStorage();
1008 #else  // VTK_USE_64BIT_IDS
1009   return this->CanConvertTo32BitStorage();
1010 #endif // VTK_USE_64BIT_IDS
1011 }
1012 
1013 //------------------------------------------------------------------------------
ConvertTo32BitStorage()1014 bool vtkCellArray::ConvertTo32BitStorage()
1015 {
1016   if (!this->IsStorage64Bit())
1017   {
1018     return true;
1019   }
1020   vtkNew<ArrayType32> offsets;
1021   vtkNew<ArrayType32> conn;
1022   if (!this->Visit(ExtractAndInitialize{}, offsets.Get(), conn.Get()))
1023   {
1024     return false;
1025   }
1026 
1027   this->SetData(offsets, conn);
1028   return true;
1029 }
1030 
1031 //------------------------------------------------------------------------------
ConvertTo64BitStorage()1032 bool vtkCellArray::ConvertTo64BitStorage()
1033 {
1034   if (this->IsStorage64Bit())
1035   {
1036     return true;
1037   }
1038   vtkNew<ArrayType64> offsets;
1039   vtkNew<ArrayType64> conn;
1040   if (!this->Visit(ExtractAndInitialize{}, offsets.Get(), conn.Get()))
1041   {
1042     return false;
1043   }
1044 
1045   this->SetData(offsets, conn);
1046   return true;
1047 }
1048 
1049 //------------------------------------------------------------------------------
ConvertToDefaultStorage()1050 bool vtkCellArray::ConvertToDefaultStorage()
1051 {
1052 #ifdef VTK_USE_64BIT_IDS
1053   return this->ConvertTo64BitStorage();
1054 #else  // VTK_USE_64BIT_IDS
1055   return this->ConvertTo32BitStorage();
1056 #endif // VTK_USE_64BIT_IDS
1057 }
1058 
1059 //------------------------------------------------------------------------------
ConvertToSmallestStorage()1060 bool vtkCellArray::ConvertToSmallestStorage()
1061 {
1062   if (this->IsStorage64Bit() && this->CanConvertTo32BitStorage())
1063   {
1064     return this->ConvertTo32BitStorage();
1065   }
1066   // Already at the smallest possible.
1067   return true;
1068 }
1069 
1070 //------------------------------------------------------------------------------
AllocateExact(vtkIdType numCells,vtkIdType connectivitySize)1071 bool vtkCellArray::AllocateExact(vtkIdType numCells, vtkIdType connectivitySize)
1072 {
1073   return this->Visit(AllocateExactImpl{}, numCells, connectivitySize);
1074 }
1075 
1076 //------------------------------------------------------------------------------
ResizeExact(vtkIdType numCells,vtkIdType connectivitySize)1077 bool vtkCellArray::ResizeExact(vtkIdType numCells, vtkIdType connectivitySize)
1078 {
1079   return this->Visit(ResizeExactImpl{}, numCells, connectivitySize);
1080 }
1081 
1082 //------------------------------------------------------------------------------
1083 // Returns the size of the largest cell. The size is the number of points
1084 // defining the cell.
GetMaxCellSize()1085 int vtkCellArray::GetMaxCellSize()
1086 {
1087   FindMaxCell finder{ this };
1088 
1089   // Grain size puts an even number of pages into each instance.
1090   vtkSMPTools::For(0, this->GetNumberOfCells(), finder);
1091 
1092   return static_cast<int>(finder.Result);
1093 }
1094 
1095 //------------------------------------------------------------------------------
GetActualMemorySize() const1096 unsigned long vtkCellArray::GetActualMemorySize() const
1097 {
1098   return this->Visit(GetActualMemorySizeImpl{});
1099 }
1100 
1101 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1102 void vtkCellArray::PrintSelf(ostream& os, vtkIndent indent)
1103 {
1104   this->Superclass::PrintSelf(os, indent);
1105 
1106   os << indent << "StorageIs64Bit: " << this->Storage.Is64Bit() << "\n";
1107 
1108   PrintSelfImpl functor;
1109   this->Visit(functor, os, indent);
1110 }
1111 
1112 //------------------------------------------------------------------------------
PrintDebug(std::ostream & os)1113 void vtkCellArray::PrintDebug(std::ostream& os)
1114 {
1115   this->Print(os);
1116   this->Visit(PrintDebugImpl{}, os);
1117 }
1118 
1119 //------------------------------------------------------------------------------
GetTraversalCellId()1120 vtkIdType vtkCellArray::GetTraversalCellId()
1121 {
1122   return this->TraversalCellId;
1123 }
1124 
1125 //------------------------------------------------------------------------------
SetTraversalCellId(vtkIdType cellId)1126 void vtkCellArray::SetTraversalCellId(vtkIdType cellId)
1127 {
1128   this->TraversalCellId = cellId;
1129 }
1130 
1131 //------------------------------------------------------------------------------
ReverseCellAtId(vtkIdType cellId)1132 void vtkCellArray::ReverseCellAtId(vtkIdType cellId)
1133 {
1134   this->Visit(ReverseCellAtIdImpl{}, cellId);
1135 }
1136 
1137 //------------------------------------------------------------------------------
ReplaceCellAtId(vtkIdType cellId,vtkIdList * list)1138 void vtkCellArray::ReplaceCellAtId(vtkIdType cellId, vtkIdList* list)
1139 {
1140   this->Visit(ReplaceCellAtIdImpl{}, cellId, list->GetNumberOfIds(), list->GetPointer(0));
1141 }
1142 
1143 //------------------------------------------------------------------------------
ReplaceCellAtId(vtkIdType cellId,vtkIdType cellSize,const vtkIdType cellPoints[])1144 void vtkCellArray::ReplaceCellAtId(
1145   vtkIdType cellId, vtkIdType cellSize, const vtkIdType cellPoints[])
1146 {
1147   this->Visit(ReplaceCellAtIdImpl{}, cellId, cellSize, cellPoints);
1148 }
1149 
1150 //------------------------------------------------------------------------------
ExportLegacyFormat(vtkIdTypeArray * data)1151 void vtkCellArray::ExportLegacyFormat(vtkIdTypeArray* data)
1152 {
1153   data->Allocate(this->Visit(GetLegacyDataSizeImpl{}));
1154 
1155   auto it = vtk::TakeSmartPointer(this->NewIterator());
1156 
1157   vtkIdType cellSize;
1158   const vtkIdType* cellPoints;
1159   for (it->GoToFirstCell(); !it->IsDoneWithTraversal(); it->GoToNextCell())
1160   {
1161     it->GetCurrentCell(cellSize, cellPoints);
1162     data->InsertNextValue(cellSize);
1163     for (vtkIdType i = 0; i < cellSize; ++i)
1164     {
1165       data->InsertNextValue(cellPoints[i]);
1166     }
1167   }
1168 }
1169 
1170 //------------------------------------------------------------------------------
ImportLegacyFormat(vtkIdTypeArray * data)1171 void vtkCellArray::ImportLegacyFormat(vtkIdTypeArray* data)
1172 {
1173   this->ImportLegacyFormat(data->GetPointer(0), data->GetNumberOfValues());
1174 }
1175 
1176 //------------------------------------------------------------------------------
ImportLegacyFormat(const vtkIdType * data,vtkIdType len)1177 void vtkCellArray::ImportLegacyFormat(const vtkIdType* data, vtkIdType len)
1178 {
1179   this->Reset();
1180   this->AppendLegacyFormat(data, len, 0);
1181 }
1182 
1183 //------------------------------------------------------------------------------
AppendLegacyFormat(vtkIdTypeArray * data,vtkIdType ptOffset)1184 void vtkCellArray::AppendLegacyFormat(vtkIdTypeArray* data, vtkIdType ptOffset)
1185 {
1186   this->AppendLegacyFormat(data->GetPointer(0), data->GetNumberOfValues(), ptOffset);
1187 }
1188 
1189 //------------------------------------------------------------------------------
AppendLegacyFormat(const vtkIdType * data,vtkIdType len,vtkIdType ptOffset)1190 void vtkCellArray::AppendLegacyFormat(const vtkIdType* data, vtkIdType len, vtkIdType ptOffset)
1191 {
1192   this->Visit(AppendLegacyFormatImpl{}, data, len, ptOffset);
1193 }
1194 
1195 //------------------------------------------------------------------------------
Squeeze()1196 void vtkCellArray::Squeeze()
1197 {
1198   this->Visit(SqueezeImpl{});
1199 
1200   // Just delete the legacy buffer.
1201   this->LegacyData->Initialize();
1202 }
1203 
1204 //------------------------------------------------------------------------------
IsValid()1205 bool vtkCellArray::IsValid()
1206 {
1207   return this->Visit(IsValidImpl{});
1208 }
1209 
1210 //------------------------------------------------------------------------------
IsHomogeneous()1211 vtkIdType vtkCellArray::IsHomogeneous()
1212 {
1213   return this->Visit(IsHomogeneousImpl{});
1214 }
1215