1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkExtractCells.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  Copyright (c) Sandia Corporation
17  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19 
20 #include "vtkExtractCells.h"
21 
22 #include "vtkCell.h"
23 #include "vtkCellArray.h"
24 #include "vtkCellArrayIterator.h"
25 #include "vtkCellData.h"
26 #include "vtkDoubleArray.h"
27 #include "vtkIdTypeArray.h"
28 #include "vtkInformation.h"
29 #include "vtkNew.h"
30 #include "vtkObjectFactory.h"
31 #include "vtkPointData.h"
32 #include "vtkPointSet.h"
33 #include "vtkPoints.h"
34 #include "vtkSMPThreadLocalObject.h"
35 #include "vtkSMPTools.h"
36 #include "vtkTimeStamp.h"
37 #include "vtkUnsignedCharArray.h"
38 #include "vtkUnstructuredGrid.h"
39 
40 #include <algorithm>
41 #include <iterator>
42 #include <numeric>
43 #include <vector>
44 
45 namespace
46 {
47 
48 struct ExtractedCellsT
49 {
50   vtkSmartPointer<vtkCellArray> Connectivity;
51   vtkSmartPointer<vtkUnsignedCharArray> CellTypes;
52   vtkSmartPointer<vtkIdTypeArray> Faces;
53   vtkSmartPointer<vtkIdTypeArray> FaceLocations;
54 };
55 
56 //=============================================================================
57 /*
58  * These work types help us reuse the same code for extracting elements
59  * when a smaller subset is being extracted or everything is being extracted
60  * with ease.
61  */
62 struct AllElementsWork
63 {
64   vtkIdType NumberOfPoints;
65   vtkIdType NumberOfCells;
66 
67   // PointWork API
GetNumberOfPoints__anon984874830111::AllElementsWork68   inline vtkIdType GetNumberOfPoints() const { return this->NumberOfPoints; }
GetPointId__anon984874830111::AllElementsWork69   inline vtkIdType GetPointId(vtkIdType index) const { return index; }
70 
71   // CellWork API
GetNumberOfCells__anon984874830111::AllElementsWork72   inline vtkIdType GetNumberOfCells() const { return this->NumberOfCells; }
GetCellId__anon984874830111::AllElementsWork73   inline vtkIdType GetCellId(vtkIdType index) const { return index; }
MapPointIds__anon984874830111::AllElementsWork74   inline void MapPointIds(vtkIdList*) const {};
75 };
76 
77 struct SubsetCellsWork
78 {
79   const std::vector<vtkIdType>::const_iterator Begin;
80   const std::vector<vtkIdType>::const_iterator End;
81   const std::vector<vtkIdType>& PointMap;
82   vtkIdType NumberOfCells;
83 
GetNumberOfCells__anon984874830111::SubsetCellsWork84   inline vtkIdType GetNumberOfCells() const { return this->NumberOfCells; }
GetCellId__anon984874830111::SubsetCellsWork85   inline vtkIdType GetCellId(vtkIdType index) const { return *std::next(this->Begin, index); }
MapPointId__anon984874830111::SubsetCellsWork86   inline vtkIdType MapPointId(vtkIdType id) const
87   {
88     assert(id >= 0 && id < static_cast<vtkIdType>(this->PointMap.size()));
89     return this->PointMap[id];
90   }
MapPointIds__anon984874830111::SubsetCellsWork91   inline void MapPointIds(vtkIdList* ids) const
92   {
93     for (vtkIdType ptid = 0, max = ids->GetNumberOfIds(); ptid < max; ++ptid)
94     {
95       ids->SetId(ptid, this->MapPointId(ids->GetId(ptid)));
96     }
97   };
98 };
99 
100 struct SubsetPointsWork
101 {
102   const vtkSmartPointer<vtkIdList>& PointIdsToExtract;
GetNumberOfPoints__anon984874830111::SubsetPointsWork103   inline vtkIdType GetNumberOfPoints() const { return this->PointIdsToExtract->GetNumberOfIds(); }
GetPointId__anon984874830111::SubsetPointsWork104   inline vtkIdType GetPointId(vtkIdType index) const
105   {
106     return this->PointIdsToExtract->GetId(index);
107   }
108 };
109 //=============================================================================
110 
111 //------------------------------------------------------------------------------
112 /* This function returns a new vtkPoints extracted from the `input`.
113  * The points to extract are identified by the `PointWork`:
114  *  `PointWork::GetNumberOfPoints`: total number of points to extract
115  *  `PointWork::GetPointId(idx)`: original pt id for extracted point at the `idx`
116  */
117 template <typename PointWorkT>
DoExtractPoints(vtkDataSet * input,const PointWorkT & work)118 static vtkSmartPointer<vtkPoints> DoExtractPoints(vtkDataSet* input, const PointWorkT& work)
119 {
120   vtkNew<vtkPoints> pts;
121   pts->SetDataTypeToDouble();
122   pts->SetNumberOfPoints(work.GetNumberOfPoints());
123   auto array = vtkDoubleArray::SafeDownCast(pts->GetData());
124 
125   vtkSMPTools::For(
126     0, work.GetNumberOfPoints(), [&work, &array, &input](vtkIdType first, vtkIdType last) {
127       double coords[3];
128       for (vtkIdType cc = first; cc < last; ++cc)
129       {
130         input->GetPoint(work.GetPointId(cc), coords);
131         array->SetTypedTuple(cc, coords);
132       }
133     });
134   return pts;
135 }
136 
137 //------------------------------------------------------------------------------
138 /**
139  * Adds `vtkOriginalCellIds` array, if not already present in `outCD`.
140  * `CellWorkT::GetNumberOfCells`: total number of cells being extracted.
141  * `CellWorkT::GetCellId(idx)`: original cell id for extracted cell at index `idx`.
142  */
143 template <typename CellWorkT>
AddOriginalCellIds(vtkCellData * outCD,const CellWorkT & work)144 static void AddOriginalCellIds(vtkCellData* outCD, const CellWorkT& work)
145 {
146   // add vtkOriginalCellIds array, if needed.
147   if (outCD->GetArray("vtkOriginalCellIds") == nullptr)
148   {
149     const auto numCells = work.GetNumberOfCells();
150     vtkNew<vtkIdTypeArray> ids;
151     ids->SetName("vtkOriginalCellIds");
152     ids->SetNumberOfTuples(numCells);
153     vtkSMPTools::For(0, numCells, [&ids, &work](vtkIdType start, vtkIdType end) {
154       for (vtkIdType cc = start; cc < end; ++cc)
155       {
156         ids->SetTypedComponent(cc, 0, work.GetCellId(cc));
157       }
158     });
159     outCD->AddArray(ids);
160   }
161 }
162 
163 //------------------------------------------------------------------------------
164 /* Extracts cells identified by `work` from the input.
165  * Returns ExtractedCellsT with connectivity and cell-types array set.
166  */
167 template <typename CellWorkT>
DoExtractCells(vtkDataSet * input,const CellWorkT & work)168 static ExtractedCellsT DoExtractCells(vtkDataSet* input, const CellWorkT& work)
169 {
170   const auto numCells = work.GetNumberOfCells();
171 
172   ExtractedCellsT result;
173   result.Connectivity.TakeReference(vtkCellArray::New());
174   result.Connectivity->AllocateEstimate(numCells, input->GetMaxCellSize());
175   result.CellTypes.TakeReference(vtkUnsignedCharArray::New());
176   result.CellTypes->Allocate(numCells);
177 
178   vtkNew<vtkIdList> ptIds;
179   for (vtkIdType cc = 0; cc < numCells; ++cc)
180   {
181     const auto in_cellid = work.GetCellId(cc);
182     input->GetCellPoints(in_cellid, ptIds);
183     work.MapPointIds(ptIds);
184     result.Connectivity->InsertNextCell(ptIds);
185     result.CellTypes->InsertNextValue(input->GetCellType(in_cellid));
186   }
187   result.Connectivity->Squeeze();
188   result.CellTypes->Squeeze();
189   return result;
190 }
191 
192 //------------------------------------------------------------------------------
193 /**
194  * Extract polyhedral cell-face information form input. Adds `Faces` and
195  * `FaceLocations` to `result`.
196  */
197 template <typename CellWorkT>
DoExtractPolyhedralFaces(ExtractedCellsT & result,vtkUnstructuredGrid * input,const CellWorkT & work)198 static void DoExtractPolyhedralFaces(
199   ExtractedCellsT& result, vtkUnstructuredGrid* input, const CellWorkT& work)
200 {
201   const auto numCells = work.GetNumberOfCells();
202   auto inFaceLocations = input->GetFaceLocations();
203   auto inFaces = input->GetFaces();
204 
205   result.FaceLocations.TakeReference(vtkIdTypeArray::New());
206   result.FaceLocations->SetNumberOfTuples(numCells);
207 
208   vtkIdType outFacesSize = 0;
209   for (vtkIdType cc = 0; cc < numCells; ++cc)
210   {
211     const auto loc = inFaceLocations->GetValue(work.GetCellId(cc));
212     if (loc == -1)
213     {
214       // not a polyhedral cell
215       result.FaceLocations->SetTypedComponent(cc, 0, -1);
216     }
217     else
218     {
219       result.FaceLocations->SetTypedComponent(cc, 0, outFacesSize);
220       vtkIdType* pfaces_start = inFaces->GetPointer(loc);
221       vtkIdType* pfaces = pfaces_start;
222       const auto nfaces = (*pfaces++);
223       for (vtkIdType face = 0; face < nfaces; ++face)
224       {
225         const auto npts = (*pfaces++);
226         pfaces += npts;
227       }
228       outFacesSize += static_cast<vtkIdType>(std::distance(pfaces_start, pfaces));
229     }
230   }
231 
232   // Now copy polyhedron Faces.
233   result.Faces.TakeReference(vtkIdTypeArray::New());
234   result.Faces->SetNumberOfTuples(outFacesSize);
235 
236   vtkSMPTools::For(0, numCells, [&](vtkIdType start, vtkIdType end) {
237     for (vtkIdType cc = start; cc < end; ++cc)
238     {
239       const auto inLoc = inFaceLocations->GetValue(work.GetCellId(cc));
240       if (inLoc == -1)
241       {
242         continue;
243       }
244       const auto outLoc = result.FaceLocations->GetValue(cc);
245 
246       auto iptr = inFaces->GetPointer(inLoc);
247       auto optr = result.Faces->GetPointer(outLoc);
248       const auto nfaces = *iptr++;
249       *optr++ = nfaces;
250       for (vtkIdType face = 0; face < nfaces; ++face)
251       {
252         const auto npts = (*iptr++);
253         *optr++ = npts;
254         std::transform(
255           iptr, iptr + npts, optr, [&work](vtkIdType id) { return work.MapPointId(id); });
256         optr += npts;
257         iptr += npts;
258       }
259     }
260   });
261 }
262 
263 //------------------------------------------------------------------------------
264 template <typename IteratorType>
FlagChosenPoints(vtkDataSet * input,const IteratorType & start,const IteratorType & end)265 static std::vector<vtkIdType> FlagChosenPoints(
266   vtkDataSet* input, const IteratorType& start, const IteratorType& end)
267 {
268   std::vector<vtkIdType> chosen_points(input->GetNumberOfPoints(), 0);
269   const vtkIdType num_cells = static_cast<vtkIdType>(std::distance(start, end));
270 
271   vtkSMPThreadLocalObject<vtkIdList> ptIds;
272 
273   // make input API threadsafe by calling it once in a single thread.
274   input->GetCellType(0);
275   input->GetCellPoints(0, ptIds.Local());
276 
277   // flag each point used by all of the selected cells.
278   vtkSMPTools::For(0, num_cells, [&](vtkIdType first, vtkIdType last) {
279     auto& lptIds = ptIds.Local();
280     auto celliditer = std::next(start, first);
281     for (vtkIdType cc = first; cc < last; ++cc, ++celliditer)
282     {
283       const auto id = *(celliditer);
284       input->GetCellPoints(id, lptIds);
285       for (vtkIdType i = 0, max = lptIds->GetNumberOfIds(); i < max; ++i)
286       {
287         chosen_points[lptIds->GetId(i)] = 1;
288       }
289     }
290   });
291   return chosen_points;
292 }
293 
294 //------------------------------------------------------------------------------
295 // Faster overload for vtkUnstructuredGrid
296 template <typename IteratorType>
FlagChosenPoints(vtkUnstructuredGrid * input,const IteratorType & start,const IteratorType & end)297 static std::vector<vtkIdType> FlagChosenPoints(
298   vtkUnstructuredGrid* input, const IteratorType& start, const IteratorType& end)
299 {
300   std::vector<vtkIdType> chosen_points(input->GetNumberOfPoints(), 0);
301   const vtkIdType num_cells = static_cast<vtkIdType>(std::distance(start, end));
302   auto cellArray = input->GetCells();
303 
304   // flag each point used by all of the selected cells.
305   vtkSMPThreadLocal<vtkSmartPointer<vtkCellArrayIterator>> storage;
306 
307   vtkSMPTools::For(0, num_cells, [&](vtkIdType first, vtkIdType last) {
308     auto celliditer = std::next(start, first);
309     auto& caIter = storage.Local();
310     if (caIter.GetPointer() == nullptr)
311     {
312       caIter.TakeReference(cellArray->NewIterator());
313     }
314     vtkIdType npts;
315     const vtkIdType* ptids;
316     for (vtkIdType cc = first; cc < last; ++cc, ++celliditer)
317     {
318       const auto id = *(celliditer);
319       caIter->GetCellAtId(id, npts, ptids);
320       for (vtkIdType i = 0; i < npts; ++i)
321       {
322         chosen_points[ptids[i]] = 1;
323       }
324     }
325   });
326   return chosen_points;
327 }
328 
329 //------------------------------------------------------------------------------
330 template <typename IteratorType>
GeneratePointMap(vtkDataSet * input,const IteratorType & start,const IteratorType & end,vtkIdType & outNumPoints)331 static std::vector<vtkIdType> GeneratePointMap(
332   vtkDataSet* input, const IteratorType& start, const IteratorType& end, vtkIdType& outNumPoints)
333 {
334   auto ugInput = vtkUnstructuredGrid::SafeDownCast(input);
335   std::vector<vtkIdType> chosen_points = ugInput != nullptr ? FlagChosenPoints(ugInput, start, end)
336                                                             : FlagChosenPoints(input, start, end);
337   // convert flags to  map where index is old id, value is new id and -1 means
338   // the point is to be discarded.
339   vtkIdType nextid = 0;
340   for (auto& pt : chosen_points)
341   {
342     pt = pt ? nextid++ : -1;
343   }
344   outNumPoints = nextid;
345   return chosen_points;
346 }
347 
348 //------------------------------------------------------------------------------
349 template <typename CellWorkT>
CopyCellData(vtkCellData * input,vtkCellData * output,const CellWorkT & work)350 static void CopyCellData(vtkCellData* input, vtkCellData* output, const CellWorkT& work)
351 {
352   const auto numValues = work.GetNumberOfCells();
353   output->CopyAllocate(input, numValues);
354 
355   vtkNew<vtkIdList> srcIds;
356   srcIds->SetNumberOfIds(numValues);
357 
358   vtkIdType next = 0;
359   std::generate_n(
360     srcIds->GetPointer(0), numValues, [&work, &next]() { return work.GetCellId(next++); });
361 
362   vtkNew<vtkIdList> dstIds;
363   dstIds->SetNumberOfIds(numValues);
364   std::iota(dstIds->GetPointer(0), dstIds->GetPointer(numValues), 0);
365 
366   output->CopyData(input, srcIds, dstIds);
367 }
368 
369 //------------------------------------------------------------------------------
CopyPointData(vtkPointData * inPD,vtkPointData * outPD,vtkIdList * srcIds)370 void CopyPointData(vtkPointData* inPD, vtkPointData* outPD, vtkIdList* srcIds)
371 {
372   const auto numValues = srcIds->GetNumberOfIds();
373   outPD->CopyAllocate(inPD, numValues);
374   vtkNew<vtkIdList> dstIds;
375   dstIds->SetNumberOfIds(numValues);
376   std::iota(dstIds->GetPointer(0), dstIds->GetPointer(numValues), 0);
377   outPD->CopyData(inPD, srcIds, dstIds);
378 }
379 
380 //------------------------------------------------------------------------------
ConvertToPointIdsToExtract(const std::vector<vtkIdType> & pointMap,const vtkIdType numValues)381 vtkSmartPointer<vtkIdList> ConvertToPointIdsToExtract(
382   const std::vector<vtkIdType>& pointMap, const vtkIdType numValues)
383 {
384   vtkNew<vtkIdList> srcIds;
385   srcIds->Allocate(numValues);
386   for (vtkIdType cc = 0; cc < static_cast<vtkIdType>(pointMap.size()); ++cc)
387   {
388     if (pointMap[cc] != -1)
389     {
390       srcIds->InsertNextId(cc);
391     }
392   }
393   srcIds->Squeeze();
394   assert(numValues == srcIds->GetNumberOfIds());
395   return srcIds;
396 }
397 
398 } // end anonymous namespace
399 
400 //=============================================================================
401 class vtkExtractCellsSTLCloak
402 {
403   vtkTimeStamp SortTime;
404 
405 public:
406   std::vector<vtkIdType> CellIds;
407   std::pair<typename std::vector<vtkIdType>::const_iterator,
408     typename std::vector<vtkIdType>::const_iterator>
409     CellIdsRange;
410 
Prepare(vtkIdType numInputCells,vtkExtractCells * self)411   vtkIdType Prepare(vtkIdType numInputCells, vtkExtractCells* self)
412   {
413     assert(numInputCells > 0);
414 
415     if (self->GetAssumeSortedAndUniqueIds() == false && (self->GetMTime() > this->SortTime))
416     {
417       vtkSMPTools::Sort(this->CellIds.begin(), this->CellIds.end());
418       auto last = std::unique(this->CellIds.begin(), this->CellIds.end());
419       this->CellIds.erase(last, this->CellIds.end());
420       this->SortTime.Modified();
421     }
422 
423     this->CellIdsRange =
424       std::make_pair(std::lower_bound(this->CellIds.begin(), this->CellIds.end(), 0),
425         std::upper_bound(this->CellIds.begin(), this->CellIds.end(), (numInputCells - 1)));
426     return static_cast<vtkIdType>(
427       std::distance(this->CellIdsRange.first, this->CellIdsRange.second));
428   }
429 };
430 
431 vtkStandardNewMacro(vtkExtractCells);
432 //------------------------------------------------------------------------------
vtkExtractCells()433 vtkExtractCells::vtkExtractCells()
434 {
435   this->CellList = new vtkExtractCellsSTLCloak;
436 }
437 
438 //------------------------------------------------------------------------------
~vtkExtractCells()439 vtkExtractCells::~vtkExtractCells()
440 {
441   delete this->CellList;
442 }
443 
444 //------------------------------------------------------------------------------
SetCellList(vtkIdList * l)445 void vtkExtractCells::SetCellList(vtkIdList* l)
446 {
447   delete this->CellList;
448   this->CellList = new vtkExtractCellsSTLCloak;
449   if (l != nullptr)
450   {
451     this->AddCellList(l);
452   }
453   this->Modified();
454 }
455 
456 //------------------------------------------------------------------------------
AddCellList(vtkIdList * l)457 void vtkExtractCells::AddCellList(vtkIdList* l)
458 {
459   const vtkIdType inputSize = l ? l->GetNumberOfIds() : 0;
460   if (inputSize == 0)
461   {
462     return;
463   }
464 
465   auto& cellIds = this->CellList->CellIds;
466   const vtkIdType* inputBegin = l->GetPointer(0);
467   const vtkIdType* inputEnd = inputBegin + inputSize;
468   std::copy(inputBegin, inputEnd, std::back_inserter(cellIds));
469   this->Modified();
470 }
471 
472 //------------------------------------------------------------------------------
SetCellIds(const vtkIdType * ptr,vtkIdType numValues)473 void vtkExtractCells::SetCellIds(const vtkIdType* ptr, vtkIdType numValues)
474 {
475   delete this->CellList;
476   this->CellList = new vtkExtractCellsSTLCloak;
477   if (ptr != nullptr && numValues > 0)
478   {
479     this->AddCellIds(ptr, numValues);
480   }
481   this->Modified();
482 }
483 
484 //------------------------------------------------------------------------------
AddCellIds(const vtkIdType * ptr,vtkIdType numValues)485 void vtkExtractCells::AddCellIds(const vtkIdType* ptr, vtkIdType numValues)
486 {
487   auto& cellIds = this->CellList->CellIds;
488   std::copy(ptr, ptr + numValues, std::back_inserter(cellIds));
489   this->Modified();
490 }
491 
492 //------------------------------------------------------------------------------
AddCellRange(vtkIdType from,vtkIdType to)493 void vtkExtractCells::AddCellRange(vtkIdType from, vtkIdType to)
494 {
495   if (to < from || to < 0)
496   {
497     vtkWarningMacro("Bad cell range: (" << to << "," << from << ")");
498     return;
499   }
500 
501   // This range specification is inconsistent with C++. Left for backward
502   // compatibility reasons.  Add 1 to `to` to make it consistent.
503   ++to;
504 
505   auto& cellIds = this->CellList->CellIds;
506   std::generate_n(std::back_inserter(cellIds), (to - from), [&from]() { return from++; });
507   this->Modified();
508 }
509 
510 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)511 int vtkExtractCells::RequestData(vtkInformation* vtkNotUsed(request),
512   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
513 {
514   // get the input and output
515   vtkDataSet* input = vtkDataSet::GetData(inputVector[0]);
516   vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
517 
518   auto inPD = input->GetPointData();
519   auto inCD = input->GetCellData();
520   auto outPD = output->GetPointData();
521   auto outCD = output->GetCellData();
522 
523   // copy all arrays, including global ids etc.
524   outPD->CopyAllOn();
525   outCD->CopyAllOn();
526 
527   const vtkIdType numCellsInput = input->GetNumberOfCells();
528   const vtkIdType numCells =
529     this->ExtractAllCells ? numCellsInput : this->CellList->Prepare(numCellsInput, this);
530 
531   // Handle simple cases, first.
532   // Check if no cells are to be extracted
533   if (numCells == 0)
534   {
535     // set up a ugrid with same data arrays as input, but
536     // no points, cells or data.
537     output->Allocate(1);
538     outPD->CopyAllocate(inPD, 1);
539     outCD->CopyAllocate(inCD, 1);
540     vtkNew<vtkPoints> pts;
541     pts->SetNumberOfPoints(0);
542     output->SetPoints(pts);
543     return 1;
544   }
545   else if (numCellsInput == numCells)
546   {
547     // Check if all cells are to be extracted.
548     // `Copy` will ShallowCopy input if input is vtkUnstructuredGrid, else
549     // convert it to an unstructured grid.
550     return this->Copy(input, output) ? 1 : 0;
551   }
552 
553   // Build point map for selected cells.
554   const auto& cellids_range = this->CellList->CellIdsRange;
555   assert(cellids_range.first != cellids_range.second);
556 
557   vtkIdType numPoints;
558   const auto pointMap =
559     ::GeneratePointMap(input, cellids_range.first, cellids_range.second, numPoints);
560   auto chosenPtIds = ::ConvertToPointIdsToExtract(pointMap, numPoints);
561   this->UpdateProgress(0.25);
562 
563   const SubsetCellsWork work{ cellids_range.first, cellids_range.second, pointMap, numCells };
564 
565   // Copy cell and point data first, since that's easy enough.
566   ::CopyCellData(inCD, outCD, work);
567   ::AddOriginalCellIds(outCD, work);
568   ::CopyPointData(inPD, outPD, chosenPtIds);
569   this->UpdateProgress(0.5);
570 
571   // Get new points
572   auto pts = ::DoExtractPoints(input, SubsetPointsWork{ chosenPtIds });
573   output->SetPoints(pts);
574   this->UpdateProgress(0.75);
575 
576   // Extract cells
577   auto cells = ::DoExtractCells(input, work);
578   this->UpdateProgress(0.85);
579 
580   // Handle polyhedral cells
581   auto inputUG = vtkUnstructuredGrid::SafeDownCast(input);
582   if (inputUG && inputUG->GetFaces() && inputUG->GetFaceLocations() &&
583     inputUG->GetFaceLocations()->GetRange(0)[1] != -1)
584   {
585     ::DoExtractPolyhedralFaces(cells, inputUG, work);
586   }
587   output->SetCells(cells.CellTypes, cells.Connectivity, cells.FaceLocations, cells.Faces);
588   return 1;
589 }
590 
591 //------------------------------------------------------------------------------
Copy(vtkDataSet * input,vtkUnstructuredGrid * output)592 bool vtkExtractCells::Copy(vtkDataSet* input, vtkUnstructuredGrid* output)
593 {
594   if (vtkUnstructuredGrid::SafeDownCast(input))
595   {
596     output->ShallowCopy(input);
597     return true;
598   }
599 
600   if (vtkPointSet::SafeDownCast(input))
601   {
602     // pass points along.
603     output->vtkPointSet::ShallowCopy(input);
604   }
605   else
606   {
607     // copy points manually.
608     const vtkIdType numPoints = input->GetNumberOfPoints();
609     auto pts = ::DoExtractPoints(input, AllElementsWork{ numPoints, 0 });
610     output->SetPoints(pts);
611   }
612 
613   const auto numCells = input->GetNumberOfCells();
614   auto cells = ::DoExtractCells(input, AllElementsWork{ 0, numCells });
615   output->SetCells(cells.CellTypes, cells.Connectivity, nullptr, nullptr);
616 
617   // copy cell/point arrays.
618   output->GetPointData()->ShallowCopy(input->GetPointData());
619   output->GetCellData()->ShallowCopy(input->GetCellData());
620   ::AddOriginalCellIds(output->GetCellData(), AllElementsWork{ 0, numCells });
621   return true;
622 }
623 
624 //------------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)625 int vtkExtractCells::FillInputPortInformation(int, vtkInformation* info)
626 {
627   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
628   return 1;
629 }
630 
631 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)632 void vtkExtractCells::PrintSelf(ostream& os, vtkIndent indent)
633 {
634   this->Superclass::PrintSelf(os, indent);
635   os << indent << "ExtractAllCells: " << this->ExtractAllCells << endl;
636   os << indent << "AssumeSortedAndUniqueIds: " << this->AssumeSortedAndUniqueIds << endl;
637 }
638