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