1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkGeometryFilter.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 // Hide VTK_DEPRECATED_IN_9_0_0() warnings for this class.
17 #define VTK_DEPRECATION_LEVEL 0
18 
19 #include "vtkGeometryFilter.h"
20 
21 #include "vtkArrayDispatch.h"
22 #include "vtkArrayListTemplate.h" // For processing attribute data
23 #include "vtkCellArray.h"
24 #include "vtkCellData.h"
25 #include "vtkCellTypes.h"
26 #include "vtkDataArrayRange.h"
27 #include "vtkDataSetSurfaceFilter.h"
28 #include "vtkGenericCell.h"
29 #include "vtkHexagonalPrism.h"
30 #include "vtkHexahedron.h"
31 #include "vtkIncrementalPointLocator.h"
32 #include "vtkInformation.h"
33 #include "vtkInformationVector.h"
34 #include "vtkLogger.h"
35 #include "vtkMergePoints.h"
36 #include "vtkNew.h"
37 #include "vtkObjectFactory.h"
38 #include "vtkPentagonalPrism.h"
39 #include "vtkPointData.h"
40 #include "vtkPolyData.h"
41 #include "vtkPyramid.h"
42 #include "vtkRectilinearGrid.h"
43 #include "vtkRectilinearGridGeometryFilter.h"
44 #include "vtkSMPThreadLocalObject.h"
45 #include "vtkSMPTools.h"
46 #include "vtkStaticCellLinksTemplate.h"
47 #include "vtkStreamingDemandDrivenPipeline.h"
48 #include "vtkStructuredData.h"
49 #include "vtkStructuredGrid.h"
50 #include "vtkStructuredGridGeometryFilter.h"
51 #include "vtkStructuredPoints.h"
52 #include "vtkTetra.h"
53 #include "vtkUniformGrid.h"
54 #include "vtkUnsignedCharArray.h"
55 #include "vtkUnstructuredGrid.h"
56 #include "vtkUnstructuredGridCellIterator.h"
57 #include "vtkVoxel.h"
58 #include "vtkWedge.h"
59 
60 #include <memory>
61 
62 vtkStandardNewMacro(vtkGeometryFilter);
63 vtkCxxSetObjectMacro(vtkGeometryFilter, Locator, vtkIncrementalPointLocator);
64 
65 //------------------------------------------------------------------------------
66 // Construct with all types of clipping turned off.
vtkGeometryFilter()67 vtkGeometryFilter::vtkGeometryFilter()
68 {
69   this->PointMinimum = 0;
70   this->PointMaximum = VTK_ID_MAX;
71 
72   this->CellMinimum = 0;
73   this->CellMaximum = VTK_ID_MAX;
74 
75   this->Extent[0] = -VTK_DOUBLE_MAX;
76   this->Extent[1] = VTK_DOUBLE_MAX;
77   this->Extent[2] = -VTK_DOUBLE_MAX;
78   this->Extent[3] = VTK_DOUBLE_MAX;
79   this->Extent[4] = -VTK_DOUBLE_MAX;
80   this->Extent[5] = VTK_DOUBLE_MAX;
81 
82   this->PointClipping = false;
83   this->CellClipping = false;
84   this->ExtentClipping = false;
85 
86   this->Merging = true;
87   this->Locator = nullptr;
88   this->OutputPointsPrecision = DEFAULT_PRECISION;
89 
90   this->FastMode = false;
91   this->Degree = 4;
92 
93   this->PieceInvariant = 0;
94 
95   this->PassThroughCellIds = 0;
96   this->PassThroughPointIds = 0;
97   this->OriginalCellIdsName = nullptr;
98   this->OriginalPointIdsName = nullptr;
99 
100   // optional 2nd input
101   this->SetNumberOfInputPorts(2);
102 
103   // Compatibility with vtkDataSetSurfaceFilter
104   this->NonlinearSubdivisionLevel = 1;
105 
106   // Enable delegation to an internal vtkDataSetSurfaceFilter.
107   this->Delegation = true;
108 }
109 
110 //------------------------------------------------------------------------------
~vtkGeometryFilter()111 vtkGeometryFilter::~vtkGeometryFilter()
112 {
113   this->SetLocator(nullptr);
114 }
115 
116 //------------------------------------------------------------------------------
117 // Specify a (xmin,xmax, ymin,ymax, zmin,zmax) bounding box to clip data.
SetExtent(double xMin,double xMax,double yMin,double yMax,double zMin,double zMax)118 void vtkGeometryFilter::SetExtent(
119   double xMin, double xMax, double yMin, double yMax, double zMin, double zMax)
120 {
121   double extent[6];
122 
123   extent[0] = xMin;
124   extent[1] = xMax;
125   extent[2] = yMin;
126   extent[3] = yMax;
127   extent[4] = zMin;
128   extent[5] = zMax;
129 
130   this->SetExtent(extent);
131 }
132 
133 //------------------------------------------------------------------------------
134 // Specify a (xmin,xmax, ymin,ymax, zmin,zmax) bounding box to clip data.
SetExtent(double extent[6])135 void vtkGeometryFilter::SetExtent(double extent[6])
136 {
137   int i;
138 
139   if (extent[0] != this->Extent[0] || extent[1] != this->Extent[1] ||
140     extent[2] != this->Extent[2] || extent[3] != this->Extent[3] || extent[4] != this->Extent[4] ||
141     extent[5] != this->Extent[5])
142   {
143     this->Modified();
144     for (i = 0; i < 3; i++)
145     {
146       if (extent[2 * i + 1] < extent[2 * i])
147       {
148         extent[2 * i + 1] = extent[2 * i];
149       }
150       this->Extent[2 * i] = extent[2 * i];
151       this->Extent[2 * i + 1] = extent[2 * i + 1];
152     }
153   }
154 }
155 
156 //------------------------------------------------------------------------------
SetOutputPointsPrecision(int precision)157 void vtkGeometryFilter::SetOutputPointsPrecision(int precision)
158 {
159   if (this->OutputPointsPrecision != precision)
160   {
161     this->OutputPointsPrecision = precision;
162     this->Modified();
163   }
164 }
165 
166 //------------------------------------------------------------------------------
GetOutputPointsPrecision() const167 int vtkGeometryFilter::GetOutputPointsPrecision() const
168 {
169   return this->OutputPointsPrecision;
170 }
171 
172 //------------------------------------------------------------------------------
173 // Excluded faces are defined here.
174 struct vtkExcludedFaces
175 {
176   vtkStaticCellLinksTemplate<vtkIdType>* Links;
vtkExcludedFacesvtkExcludedFaces177   vtkExcludedFaces()
178     : Links(nullptr)
179   {
180   }
~vtkExcludedFacesvtkExcludedFaces181   ~vtkExcludedFaces() { delete this->Links; }
182 };
183 
184 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)185 int vtkGeometryFilter::RequestData(vtkInformation* vtkNotUsed(request),
186   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
187 {
188   // get the info objects
189   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
190   vtkInformation* excInfo = inputVector[1]->GetInformationObject(0);
191   vtkInformation* outInfo = outputVector->GetInformationObject(0);
192 
193   // get the input and output
194   vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
195   vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
196 
197   vtkIdType numPts = input->GetNumberOfPoints();
198   vtkIdType numCells = input->GetNumberOfCells();
199 
200   if (numPts == 0 || numCells == 0)
201   {
202     return 1;
203   }
204 
205   // Check to see if excluded faces have been provided, and is so prepare the data
206   // for use.
207   vtkExcludedFaces exc; // Will delete exc->Links when goes out of scope
208   if (excInfo)
209   {
210     vtkPolyData* excFaces = vtkPolyData::SafeDownCast(excInfo->Get(vtkDataObject::DATA_OBJECT()));
211     vtkCellArray* excPolys = excFaces->GetPolys();
212     if (excPolys->GetNumberOfCells() > 0)
213     {
214       exc.Links = new vtkStaticCellLinksTemplate<vtkIdType>;
215       exc.Links->ThreadedBuildLinks(numPts, excPolys->GetNumberOfCells(), excPolys);
216     }
217   }
218 
219   // Prepare to delegate based on dataset type and characteristics.
220   int dataDim = 0;
221   switch (input->GetDataObjectType())
222   {
223     case VTK_POLY_DATA:
224     {
225       return this->PolyDataExecute(input, output, &exc);
226     }
227     case VTK_UNSTRUCTURED_GRID:
228     {
229       return this->UnstructuredGridExecute(input, output, nullptr, &exc);
230     }
231 
232     // Structured dataset types
233     case VTK_RECTILINEAR_GRID:
234       dataDim = vtkRectilinearGrid::SafeDownCast(input)->GetDataDimension();
235       break;
236     case VTK_STRUCTURED_GRID:
237       dataDim = vtkStructuredGrid::SafeDownCast(input)->GetDataDimension();
238       break;
239     case VTK_UNIFORM_GRID:
240       dataDim = vtkUniformGrid::SafeDownCast(input)->GetDataDimension();
241       break;
242     case VTK_STRUCTURED_POINTS:
243       dataDim = vtkStructuredPoints::SafeDownCast(input)->GetDataDimension();
244       break;
245     case VTK_IMAGE_DATA:
246       dataDim = vtkImageData::SafeDownCast(input)->GetDataDimension();
247       break;
248 
249     default:
250       vtkErrorMacro("Data type " << input->GetDataObjectType() << "is not supported.");
251       return 0;
252   }
253 
254   // Delegate to the faster structured processing if possible. It simplifies
255   // things if we only consider 3D structured datasets. Otherwise the
256   // general DataSetExecute will handle it just fine.
257   if (dataDim == 3)
258   {
259     return this->StructuredExecute(input, output, inInfo, &exc);
260   }
261 
262   // Use the general case
263   return this->DataSetExecute(input, output, &exc);
264 }
265 
266 //------------------------------------------------------------------------------
267 // Specify a spatial locator for merging points. This method is now deprecated.
CreateDefaultLocator()268 void vtkGeometryFilter::CreateDefaultLocator() {}
269 
270 //------------------------------------------------------------------------------
SetExcludedFacesData(vtkPolyData * input)271 void vtkGeometryFilter::SetExcludedFacesData(vtkPolyData* input)
272 {
273   this->Superclass::SetInputData(1, input);
274 }
275 
276 //------------------------------------------------------------------------------
277 // Specify the input data or filter.
SetExcludedFacesConnection(vtkAlgorithmOutput * algOutput)278 void vtkGeometryFilter::SetExcludedFacesConnection(vtkAlgorithmOutput* algOutput)
279 {
280   this->Superclass::SetInputConnection(1, algOutput);
281 }
282 
283 //------------------------------------------------------------------------------
284 // Reutrn the input data or filter.
GetExcludedFaces()285 vtkPolyData* vtkGeometryFilter::GetExcludedFaces()
286 {
287   if (this->GetNumberOfInputConnections(1) < 1)
288   {
289     return nullptr;
290   }
291   return vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(1, 0));
292 }
293 
294 //------------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)295 int vtkGeometryFilter::FillInputPortInformation(int port, vtkInformation* info)
296 {
297   if (port == 0)
298   {
299     info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
300   }
301   else if (port == 1)
302   {
303     info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
304     info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
305   }
306   return 1;
307 }
308 
309 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)310 void vtkGeometryFilter::PrintSelf(ostream& os, vtkIndent indent)
311 {
312   this->Superclass::PrintSelf(os, indent);
313 
314   os << indent << "Precision of the output points: " << this->OutputPointsPrecision << "\n";
315 
316   os << indent << "Point Minimum : " << this->PointMinimum << "\n";
317   os << indent << "Point Maximum : " << this->PointMaximum << "\n";
318 
319   os << indent << "Cell Minimum : " << this->CellMinimum << "\n";
320   os << indent << "Cell Maximum : " << this->CellMaximum << "\n";
321 
322   os << indent << "Extent: \n";
323   os << indent << "  Xmin,Xmax: (" << this->Extent[0] << ", " << this->Extent[1] << ")\n";
324   os << indent << "  Ymin,Ymax: (" << this->Extent[2] << ", " << this->Extent[3] << ")\n";
325   os << indent << "  Zmin,Zmax: (" << this->Extent[4] << ", " << this->Extent[5] << ")\n";
326 
327   os << indent << "PointClipping: " << (this->PointClipping ? "On\n" : "Off\n");
328   os << indent << "CellClipping: " << (this->CellClipping ? "On\n" : "Off\n");
329   os << indent << "ExtentClipping: " << (this->ExtentClipping ? "On\n" : "Off\n");
330 
331   os << indent << "Merging: " << (this->Merging ? "On\n" : "Off\n");
332 
333   os << indent << "Fast Mode: " << (this->FastMode ? "On\n" : "Off\n");
334   os << indent << "Degree: " << this->Degree << "\n";
335 
336   os << indent << "PieceInvariant: " << this->GetPieceInvariant() << endl;
337   os << indent << "PassThroughCellIds: " << (this->GetPassThroughCellIds() ? "On\n" : "Off\n");
338   os << indent << "PassThroughPointIds: " << (this->GetPassThroughPointIds() ? "On\n" : "Off\n");
339 
340   os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl;
341   os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl;
342 
343   os << indent << "NonlinearSubdivisionLevel: " << this->GetNonlinearSubdivisionLevel() << endl;
344 }
345 
346 //------------------------------------------------------------------------------
347 // Acceleration methods and classes for unstructured grid geometry extraction.
348 namespace // anonymous
349 {
350 // Make things a little more expressive
351 typedef std::vector<vtkIdType> IdListType;
352 
353 // This class accumulates cell array-related information. Also marks points
354 // as used if a point map is provided.
355 struct CellArrayType
356 {
357   vtkIdType* PointMap;
358   IdListType Cells;
359   IdListType OrigCellIds;
360   vtkIdType* ConnPtr;
361   vtkIdType* OffsetsPtr;
362   vtkStaticCellLinksTemplate<vtkIdType>* ExcFaces;
363 
CellArrayType__anon3ebeb7f20111::CellArrayType364   CellArrayType()
365     : PointMap(nullptr)
366     , ConnPtr(nullptr)
367     , OffsetsPtr(nullptr)
368     , ExcFaces(nullptr)
369   {
370   }
371 
SetPointMap__anon3ebeb7f20111::CellArrayType372   void SetPointMap(vtkIdType* ptMap) { this->PointMap = ptMap; }
SetExcludedFaces__anon3ebeb7f20111::CellArrayType373   void SetExcludedFaces(vtkStaticCellLinksTemplate<vtkIdType>* exc) { this->ExcFaces = exc; }
GetNumberOfCells__anon3ebeb7f20111::CellArrayType374   vtkIdType GetNumberOfCells() { return static_cast<vtkIdType>(this->OrigCellIds.size()); }
GetNumberOfConnEntries__anon3ebeb7f20111::CellArrayType375   vtkIdType GetNumberOfConnEntries() { return static_cast<vtkIdType>(this->Cells.size()); }
376 
InsertNextCell__anon3ebeb7f20111::CellArrayType377   void InsertNextCell(vtkIdType npts, const vtkIdType* pts, vtkIdType cellId)
378   {
379     // Only insert the face cell if it's not excluded
380     if (this->ExcFaces && this->ExcFaces->MatchesCell(npts, pts))
381     {
382       return;
383     }
384 
385     // Okay insert the boundary face cell
386     Cells.emplace_back(npts);
387     if (!this->PointMap)
388     {
389       for (auto i = 0; i < npts; ++i)
390       {
391         Cells.emplace_back(pts[i]);
392       }
393     }
394     else
395     {
396       for (auto i = 0; i < npts; ++i)
397       {
398         Cells.emplace_back(pts[i]);
399         this->PointMap[pts[i]] = 1;
400       }
401     }
402     OrigCellIds.emplace_back(cellId);
403   }
404 };
405 
406 //--------------------------------------------------------------------------
407 // Functor/worklet interfaces VTK -> SMPTools threading. This class enables
408 // compositing the output threads into a final VTK output. The actual work
409 // is performed by by subclasses of ExtractCellBoundaries which implement
410 // their own operator() method (i.e., the subclasses specialize
411 // to a particular dataset type).
412 struct LocalDataType
413 {
414   // Later on (in Reduce()), a thread id is assigned to the thread.
415   int ThreadId;
416 
417   // If point merging is specified, then a non-null point map is provided.
418   vtkIdType* PointMap;
419 
420   // These collect the boundary entities from geometry extraction. Note also
421   // that these implicitly keep track of the number of cells inserted.
422   CellArrayType Verts;
423   CellArrayType Lines;
424   CellArrayType Polys;
425   CellArrayType Strips;
426 
427   // Later (in the Reduce() method) build an offset structure to support
428   // threaded compositing of output geometric entities.
429   vtkIdType VertsConnOffset;  // this thread's offset into the output vert connectivity
430   vtkIdType VertsOffset;      // this thread's offset into the output offsets
431   vtkIdType LinesConnOffset;  // this thread's offset into the output line connectivity
432   vtkIdType LinesOffset;      // offset into the output line cells
433   vtkIdType PolysConnOffset;  // this thread's offset into the output poly connectivity
434   vtkIdType PolysOffset;      // offset into the output poly cells
435   vtkIdType StripsConnOffset; // this thread's offset into the output strip connectivity
436   vtkIdType StripsOffset;     // offset into the output triangle strip cells
437 
438   // These are scratch arrays to avoid repeated allocations
439   vtkSmartPointer<vtkGenericCell> Cell;
440   vtkSmartPointer<vtkIdList> CellIds;
441   vtkSmartPointer<vtkIdList> IPts;
442   vtkSmartPointer<vtkIdList> ICellIds;
443   vtkSmartPointer<vtkPoints> Coords;
444 
LocalDataType__anon3ebeb7f20111::LocalDataType445   LocalDataType()
446   {
447     this->PointMap = nullptr;
448     this->Cell.TakeReference(vtkGenericCell::New());
449     this->CellIds.TakeReference(vtkIdList::New());
450     this->IPts.TakeReference(vtkIdList::New());
451     this->ICellIds.TakeReference(vtkIdList::New());
452     this->Coords.TakeReference(vtkPoints::New());
453   }
454 
LocalDataType__anon3ebeb7f20111::LocalDataType455   LocalDataType(const LocalDataType& other)
456   {
457     this->ThreadId = other.ThreadId;
458 
459     this->Verts = other.Verts;
460     this->Lines = other.Lines;
461     this->Polys = other.Polys;
462     this->Strips = other.Strips;
463 
464     this->VertsConnOffset = other.VertsConnOffset;
465     this->VertsOffset = other.VertsOffset;
466     this->LinesConnOffset = other.LinesConnOffset;
467     this->LinesOffset = other.LinesOffset;
468     this->PolysConnOffset = other.PolysConnOffset;
469     this->PolysOffset = other.PolysOffset;
470     this->StripsConnOffset = other.StripsConnOffset;
471     this->StripsOffset = other.StripsOffset;
472 
473     this->PointMap = other.PointMap;
474     // These are here to have a different allocation for each threads
475     this->Cell.TakeReference(vtkGenericCell::New());
476     this->CellIds.TakeReference(vtkIdList::New());
477     this->IPts.TakeReference(vtkIdList::New());
478     this->ICellIds.TakeReference(vtkIdList::New());
479     this->Coords.TakeReference(vtkPoints::New());
480   }
481 
operator =__anon3ebeb7f20111::LocalDataType482   LocalDataType& operator=(const LocalDataType& other)
483   {
484     if (this != &other)
485     {
486       LocalDataType tmp = LocalDataType(other);
487       this->Swap(tmp);
488     }
489     return *this;
490   }
491 
Swap__anon3ebeb7f20111::LocalDataType492   void Swap(LocalDataType& other)
493   {
494     using std::swap; // the compiler will use custom swap for members if it exists
495 
496     swap(this->Verts, other.Verts);
497     swap(this->Lines, other.Lines);
498     swap(this->Polys, other.Polys);
499     swap(this->Strips, other.Strips);
500 
501     swap(this->VertsConnOffset, other.VertsConnOffset);
502     swap(this->VertsOffset, other.VertsOffset);
503     swap(this->LinesConnOffset, other.LinesConnOffset);
504     swap(this->LinesOffset, other.LinesOffset);
505     swap(this->PolysConnOffset, other.PolysConnOffset);
506     swap(this->PolysOffset, other.PolysOffset);
507     swap(this->StripsConnOffset, other.StripsConnOffset);
508     swap(this->StripsOffset, other.StripsOffset);
509 
510     swap(this->PointMap, other.PointMap);
511     swap(this->Cell, other.Cell);
512     swap(this->CellIds, other.CellIds);
513     swap(this->IPts, other.IPts);
514     swap(this->ICellIds, other.ICellIds);
515     swap(this->Coords, other.Coords);
516   }
517 
SetPointMap__anon3ebeb7f20111::LocalDataType518   void SetPointMap(vtkIdType* ptMap)
519   {
520     this->PointMap = ptMap;
521     this->Verts.SetPointMap(ptMap);
522     this->Lines.SetPointMap(ptMap);
523     this->Polys.SetPointMap(ptMap);
524     this->Strips.SetPointMap(ptMap);
525   }
526 
SetExcludedFaces__anon3ebeb7f20111::LocalDataType527   void SetExcludedFaces(vtkStaticCellLinksTemplate<vtkIdType>* exc)
528   {
529     this->Verts.SetExcludedFaces(exc);
530     this->Lines.SetExcludedFaces(exc);
531     this->Polys.SetExcludedFaces(exc);
532     this->Strips.SetExcludedFaces(exc);
533   }
534 };
535 typedef vtkSMPThreadLocal<LocalDataType>::iterator ThreadIterType;
536 typedef std::vector<ThreadIterType> ThreadOutputType;
537 
538 //--------------------------------------------------------------------------
539 // Given a cell and a bunch of supporting objects (to support computing and
540 // minimize allocation/deallocation), extract boundary features from the cell.
541 // This method works with arbitrary datasets.
ExtractDSCellGeometry(vtkDataSet * input,vtkIdType cellId,const char * cellVis,LocalDataType * localData)542 void ExtractDSCellGeometry(
543   vtkDataSet* input, vtkIdType cellId, const char* cellVis, LocalDataType* localData)
544 {
545   static const int pixelConvert[4] = { 0, 1, 3, 2 };
546   vtkGenericCell* cell = localData->Cell;
547   input->GetCell(cellId, cell);
548   int cellType = cell->GetCellType();
549 
550   if (cellType != VTK_EMPTY_CELL)
551   {
552     CellArrayType& verts = localData->Verts;
553     CellArrayType& lines = localData->Lines;
554     CellArrayType& polys = localData->Polys;
555     CellArrayType& strips = localData->Strips;
556     vtkIdList* cellIds = localData->CellIds.Get();
557     vtkIdList* ptIds = localData->IPts.Get();
558     ptIds->SetNumberOfIds(4);
559 
560     int cellDim = cell->GetCellDimension();
561     vtkIdType npts = cell->PointIds->GetNumberOfIds();
562     vtkIdType* pts = cell->PointIds->GetPointer(0);
563 
564     switch (cellDim)
565     {
566       // create new points and then cell
567       case 0:
568         verts.InsertNextCell(npts, pts, cellId);
569         break;
570 
571       case 1:
572         lines.InsertNextCell(npts, pts, cellId);
573         break;
574 
575       case 2:
576         if (cellType == VTK_TRIANGLE_STRIP)
577         {
578           strips.InsertNextCell(npts, pts, cellId);
579         }
580         else if (cellType == VTK_PIXEL)
581         {
582           ptIds->SetId(0, pts[pixelConvert[0]]);
583           ptIds->SetId(1, pts[pixelConvert[1]]);
584           ptIds->SetId(2, pts[pixelConvert[2]]);
585           ptIds->SetId(3, pts[pixelConvert[3]]);
586           polys.InsertNextCell(npts, ptIds->GetPointer(0), cellId);
587         }
588         else
589         {
590           polys.InsertNextCell(npts, pts, cellId);
591         }
592         break;
593 
594       case 3:
595         int numFaces = cell->GetNumberOfFaces();
596         for (auto j = 0; j < numFaces; j++)
597         {
598           vtkCell* face = cell->GetFace(j);
599           input->GetCellNeighbors(cellId, face->PointIds, cellIds);
600           if (cellIds->GetNumberOfIds() <= 0 || (cellVis && !cellVis[cellIds->GetId(0)]))
601           {
602             vtkIdType numFacePts = face->GetNumberOfPoints();
603             polys.InsertNextCell(numFacePts, face->PointIds->GetPointer(0), cellId);
604           }
605         }
606         break;
607     } // switch
608   }   // non-empty cell
609 } // extract dataset geometry
610 
611 //--------------------------------------------------------------------------
612 // Given a cell and a bunch of supporting objects (to support computing and
613 // minimize allocation/deallocation), extract boundary features from the cell.
614 // This method works with 3D structured data.
ExtractStructuredCellGeometry(vtkDataSet * input,vtkIdType cellId,int cellType,vtkIdType,const vtkIdType * pts,const char * cellVis,LocalDataType * localData)615 void ExtractStructuredCellGeometry(vtkDataSet* input, vtkIdType cellId, int cellType, vtkIdType,
616   const vtkIdType* pts, const char* cellVis, LocalDataType* localData)
617 {
618   CellArrayType& polys = localData->Polys;
619   vtkIdList* cellIds = localData->CellIds.Get();
620   vtkIdList* ptIds = localData->IPts.Get();
621   ptIds->SetNumberOfIds(4);
622 
623   int faceId, numFacePts;
624   const vtkIdType* faceVerts;
625   bool insertFace;
626   static const int pixelConvert[4] = { 0, 1, 3, 2 };
627 
628   switch (cellType)
629   {
630     case VTK_VOXEL:
631       numFacePts = 4;
632       for (faceId = 0; faceId < 6; faceId++)
633       {
634         faceVerts = vtkVoxel::GetFaceArray(faceId);
635         ptIds->SetId(0, pts[faceVerts[pixelConvert[0]]]);
636         ptIds->SetId(1, pts[faceVerts[pixelConvert[1]]]);
637         ptIds->SetId(2, pts[faceVerts[pixelConvert[2]]]);
638         ptIds->SetId(3, pts[faceVerts[pixelConvert[3]]]);
639         input->GetCellNeighbors(cellId, ptIds, cellIds);
640         insertFace = (cellIds->GetNumberOfIds() <= 0 || (cellVis && !cellVis[cellIds->GetId(0)]));
641         if (insertFace)
642         {
643           polys.InsertNextCell(numFacePts, ptIds->GetPointer(0), cellId);
644         }
645       }
646       break;
647 
648     case VTK_HEXAHEDRON:
649       numFacePts = 4;
650       for (faceId = 0; faceId < 6; faceId++)
651       {
652         faceVerts = vtkHexahedron::GetFaceArray(faceId);
653         ptIds->SetId(0, pts[faceVerts[0]]);
654         ptIds->SetId(1, pts[faceVerts[1]]);
655         ptIds->SetId(2, pts[faceVerts[2]]);
656         ptIds->SetId(3, pts[faceVerts[3]]);
657         input->GetCellNeighbors(cellId, ptIds, cellIds);
658         insertFace = (cellIds->GetNumberOfIds() <= 0 || (cellVis && !cellVis[cellIds->GetId(0)]));
659         if (insertFace)
660         {
661           polys.InsertNextCell(numFacePts, ptIds->GetPointer(0), cellId);
662         }
663       }
664       break;
665 
666   } // switch
667 } // ExtractStructuredCellGeometry()
668 
669 //--------------------------------------------------------------------------
670 // Given a cell and a bunch of supporting objects (to support computing and
671 // minimize allocation/deallocation), extract boundary features from the cell.
672 // This method works with unstructured grids.
ExtractCellGeometry(vtkUnstructuredGrid * input,vtkIdType cellId,int cellType,vtkIdType npts,const vtkIdType * pts,const char * cellVis,vtkUnstructuredGridCellIterator * cellIter,LocalDataType * localData)673 void ExtractCellGeometry(vtkUnstructuredGrid* input, vtkIdType cellId, int cellType, vtkIdType npts,
674   const vtkIdType* pts, const char* cellVis, vtkUnstructuredGridCellIterator* cellIter,
675   LocalDataType* localData)
676 {
677   CellArrayType& verts = localData->Verts;
678   CellArrayType& lines = localData->Lines;
679   CellArrayType& polys = localData->Polys;
680   CellArrayType& strips = localData->Strips;
681   vtkGenericCell* cell = localData->Cell.Get();
682   vtkIdList* cellIds = localData->CellIds.Get();
683 
684   int faceId, numFacePts;
685   const int MAX_FACE_POINTS = 32;
686   vtkIdType ptIds[MAX_FACE_POINTS]; // cell face point ids
687   const vtkIdType* faceVerts;
688   bool insertFace;
689   static const int pixelConvert[4] = { 0, 1, 3, 2 };
690 
691   switch (cellType)
692   {
693     case VTK_EMPTY_CELL:
694       break;
695 
696     case VTK_VERTEX:
697     case VTK_POLY_VERTEX:
698       verts.InsertNextCell(npts, pts, cellId);
699       break;
700 
701     case VTK_LINE:
702     case VTK_POLY_LINE:
703       lines.InsertNextCell(npts, pts, cellId);
704       break;
705 
706     case VTK_TRIANGLE:
707     case VTK_QUAD:
708     case VTK_POLYGON:
709       polys.InsertNextCell(npts, pts, cellId);
710       break;
711 
712     case VTK_TRIANGLE_STRIP:
713       strips.InsertNextCell(npts, pts, cellId);
714       break;
715 
716     case VTK_PIXEL:
717       // pixelConvert (in the following loop) is an int[4]. GCC 5.1.1
718       // warns about pixelConvert[4] being uninitialized due to loop
719       // unrolling -- forcibly restricting npts <= 4 prevents this warning.
720       ptIds[0] = pts[pixelConvert[0]];
721       ptIds[1] = pts[pixelConvert[1]];
722       ptIds[2] = pts[pixelConvert[2]];
723       ptIds[3] = pts[pixelConvert[3]];
724       polys.InsertNextCell(npts, ptIds, cellId);
725       break;
726 
727     case VTK_TETRA:
728       numFacePts = 3;
729       for (faceId = 0; faceId < 4; faceId++)
730       {
731         faceVerts = vtkTetra::GetFaceArray(faceId);
732         ptIds[0] = pts[faceVerts[0]];
733         ptIds[1] = pts[faceVerts[1]];
734         ptIds[2] = pts[faceVerts[2]];
735         if (!cellVis) // most common, fastpath: geometry not cropped
736         {
737           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
738         }
739         else // slower path, geometry cropped via point id, cell id, and/or extent
740         {
741           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
742           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
743         }
744         if (insertFace)
745         {
746           polys.InsertNextCell(numFacePts, ptIds, cellId);
747         }
748       }
749       break;
750 
751     case VTK_VOXEL:
752       numFacePts = 4;
753       for (faceId = 0; faceId < 6; faceId++)
754       {
755         faceVerts = vtkVoxel::GetFaceArray(faceId);
756         ptIds[0] = pts[faceVerts[pixelConvert[0]]];
757         ptIds[1] = pts[faceVerts[pixelConvert[1]]];
758         ptIds[2] = pts[faceVerts[pixelConvert[2]]];
759         ptIds[3] = pts[faceVerts[pixelConvert[3]]];
760         if (!cellVis) // most common, fastpath: geometry not cropped
761         {
762           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
763         }
764         else // slower path, geometry cropped via point id, cell id, and/or extent
765         {
766           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
767           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
768         }
769         if (insertFace)
770         {
771           polys.InsertNextCell(numFacePts, ptIds, cellId);
772         }
773       }
774       break;
775 
776     case VTK_HEXAHEDRON:
777       numFacePts = 4;
778       for (faceId = 0; faceId < 6; faceId++)
779       {
780         faceVerts = vtkHexahedron::GetFaceArray(faceId);
781         ptIds[0] = pts[faceVerts[0]];
782         ptIds[1] = pts[faceVerts[1]];
783         ptIds[2] = pts[faceVerts[2]];
784         ptIds[3] = pts[faceVerts[3]];
785         if (!cellVis) // most common, fastpath: geometry not cropped
786         {
787           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
788         }
789         else // slower path, geometry cropped via point id, cell id, and/or extent
790         {
791           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
792           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
793         }
794         if (insertFace)
795         {
796           polys.InsertNextCell(numFacePts, ptIds, cellId);
797         }
798       }
799       break;
800 
801     case VTK_WEDGE:
802       for (faceId = 0; faceId < 5; faceId++)
803       {
804         faceVerts = vtkWedge::GetFaceArray(faceId);
805         ptIds[0] = pts[faceVerts[0]];
806         ptIds[1] = pts[faceVerts[1]];
807         ptIds[2] = pts[faceVerts[2]];
808         numFacePts = 3;
809         if (faceVerts[3] >= 0)
810         {
811           ptIds[3] = pts[faceVerts[3]];
812           numFacePts = 4;
813         }
814         if (!cellVis) // most common, fastpath: geometry not cropped
815         {
816           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
817         }
818         else // slower path, geometry cropped via point id, cell id, and/or extent
819         {
820           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
821           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
822         }
823         if (insertFace)
824         {
825           polys.InsertNextCell(numFacePts, ptIds, cellId);
826         }
827       }
828       break;
829 
830     case VTK_PYRAMID:
831       for (faceId = 0; faceId < 5; faceId++)
832       {
833         faceVerts = vtkPyramid::GetFaceArray(faceId);
834         ptIds[0] = pts[faceVerts[0]];
835         ptIds[1] = pts[faceVerts[1]];
836         ptIds[2] = pts[faceVerts[2]];
837         numFacePts = 3;
838         if (faceVerts[3] >= 0)
839         {
840           ptIds[3] = pts[faceVerts[3]];
841           numFacePts = 4;
842         }
843         if (!cellVis) // most common, fastpath: geometry not cropped
844         {
845           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
846         }
847         else // slower path, geometry cropped via point id, cell id, and/or extent
848         {
849           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
850           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
851         }
852         if (insertFace)
853         {
854           polys.InsertNextCell(numFacePts, ptIds, cellId);
855         }
856       }
857       break;
858 
859     case VTK_HEXAGONAL_PRISM:
860       for (faceId = 0; faceId < 8; faceId++)
861       {
862         faceVerts = vtkHexagonalPrism::GetFaceArray(faceId);
863         ptIds[0] = pts[faceVerts[0]];
864         ptIds[1] = pts[faceVerts[1]];
865         ptIds[2] = pts[faceVerts[2]];
866         ptIds[3] = pts[faceVerts[3]];
867         numFacePts = 4;
868         if (faceVerts[4] >= 0)
869         {
870           ptIds[4] = pts[faceVerts[4]];
871           ptIds[5] = pts[faceVerts[5]];
872           numFacePts = 6;
873         }
874         if (!cellVis) // most common, fastpath: geometry not cropped
875         {
876           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
877         }
878         else // slower path, geometry cropped via point id, cell id, and/or extent
879         {
880           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
881           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
882         }
883         if (insertFace)
884         {
885           polys.InsertNextCell(numFacePts, ptIds, cellId);
886         }
887       }
888       break;
889 
890     case VTK_PENTAGONAL_PRISM:
891       for (faceId = 0; faceId < 7; faceId++)
892       {
893         faceVerts = vtkPentagonalPrism::GetFaceArray(faceId);
894         ptIds[0] = pts[faceVerts[0]];
895         ptIds[1] = pts[faceVerts[1]];
896         ptIds[2] = pts[faceVerts[2]];
897         ptIds[3] = pts[faceVerts[3]];
898         numFacePts = 4;
899         if (faceVerts[4] >= 0)
900         {
901           ptIds[4] = pts[faceVerts[4]];
902           numFacePts = 5;
903         }
904         if (!cellVis) // most common, fastpath: geometry not cropped
905         {
906           insertFace = input->IsCellBoundary(cellId, numFacePts, ptIds);
907         }
908         else // slower path, geometry cropped via point id, cell id, and/or extent
909         {
910           input->GetCellNeighbors(cellId, numFacePts, ptIds, cellIds);
911           insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
912         }
913         if (insertFace)
914         {
915           polys.InsertNextCell(numFacePts, ptIds, cellId);
916         }
917       }
918       break;
919 
920     default:
921       // Other types of 3D linear cells handled by vtkGeometryFilter. Exactly what
922       // is a linear cell is defined by vtkCellTypes::IsLinear().
923       cellIter->GetCell(cell);
924       if (cell->GetCellDimension() == 3)
925       {
926         int numFaces = cell->GetNumberOfFaces();
927         for (auto j = 0; j < numFaces; j++)
928         {
929           vtkCell* face = cell->GetFace(j);
930           numFacePts = face->PointIds->GetNumberOfIds();
931           if (!cellVis) // most common, fastpath: geometry not cropped
932           {
933             insertFace = input->IsCellBoundary(cellId, numFacePts, face->PointIds->GetPointer(0));
934           }
935           else // slower path, geometry cropped via point id, cell id, and/or extent
936           {
937             input->GetCellNeighbors(cellId, numFacePts, face->PointIds->GetPointer(0), cellIds);
938             insertFace = (cellIds->GetNumberOfIds() <= 0 || !cellVis[cellIds->GetId(0)]);
939           }
940           if (insertFace)
941           {
942             polys.InsertNextCell(numFacePts, face->PointIds->GetPointer(0), cellId);
943           }
944         } // for all cell faces
945       }   // if 3D
946       else
947       {
948         vtkLog(ERROR, "Unknown cell type.");
949       }
950   } // switch
951 } // ExtractCellGeometry()
952 
953 // Base class to extract boundary entities. Derived by all dataset extraction
954 // types -- the operator() method needs to be implemented by subclasses.
955 struct ExtractCellBoundaries
956 {
957   // If point merging is specified, then a point map is created.
958   vtkIdType* PointMap;
959 
960   // Cell visibility and cell ghost levels
961   const char* CellVis;
962   const unsigned char* CellGhosts;
963 
964   // These are the final composited output cell arrays
965   vtkCellArray* Verts;       // output verts
966   vtkIdType* VertsConnPtr;   // output connectivity array
967   vtkIdType* VertsOffsetPtr; // output offsets array
968 
969   vtkCellArray* Lines; // output lines
970   vtkIdType* LinesConnPtr;
971   vtkIdType* LinesOffsetPtr;
972 
973   vtkCellArray* Polys; // output polys
974   vtkIdType* PolysConnPtr;
975   vtkIdType* PolysOffsetPtr;
976 
977   vtkCellArray* Strips; // output triangle strips
978   vtkIdType* StripsConnPtr;
979   vtkIdType* StripsOffsetPtr;
980 
981   // Thread-related output data
982   vtkSMPThreadLocal<LocalDataType> LocalData;
983   vtkIdType VertsCellIdOffset;
984   vtkIdType LinesCellIdOffset;
985   vtkIdType PolysCellIdOffset;
986   vtkIdType StripsCellIdOffset;
987   vtkIdType NumPts;
988   vtkIdType NumCells;
989   ExtractCellBoundaries* Extract;
990   vtkStaticCellLinksTemplate<vtkIdType>* ExcFaces;
991   ThreadOutputType* Threads;
992 
ExtractCellBoundaries__anon3ebeb7f20111::ExtractCellBoundaries993   ExtractCellBoundaries(const char* cellVis, const unsigned char* ghosts, vtkCellArray* verts,
994     vtkCellArray* lines, vtkCellArray* polys, vtkCellArray* strips, vtkExcludedFaces* exc,
995     ThreadOutputType* threads)
996     : PointMap(nullptr)
997     , CellVis(cellVis)
998     , CellGhosts(ghosts)
999     , Verts(verts)
1000     , Lines(lines)
1001     , Polys(polys)
1002     , Strips(strips)
1003     , Threads(threads)
1004   {
1005     this->ExcFaces = (exc == nullptr ? nullptr : exc->Links);
1006     this->VertsConnPtr = this->VertsOffsetPtr = nullptr;
1007     this->LinesConnPtr = this->LinesOffsetPtr = nullptr;
1008     this->PolysConnPtr = this->PolysOffsetPtr = nullptr;
1009     this->StripsConnPtr = this->StripsOffsetPtr = nullptr;
1010   }
1011 
~ExtractCellBoundaries__anon3ebeb7f20111::ExtractCellBoundaries1012   virtual ~ExtractCellBoundaries() { delete[] this->PointMap; }
1013 
1014   // If point merging is needed, create the point map (map from old points
1015   // to new points).
CreatePointMap__anon3ebeb7f20111::ExtractCellBoundaries1016   void CreatePointMap(vtkIdType numPts)
1017   {
1018     this->PointMap = new vtkIdType[numPts];
1019     std::fill_n(this->PointMap, numPts, (-1));
1020   }
1021 
1022   // Helper function supporting Reduce() to allocate and construct output cell arrays.
1023   // Also keep local information to facilitate compositing.
AllocateCellArray__anon3ebeb7f20111::ExtractCellBoundaries1024   void AllocateCellArray(vtkIdType connSize, vtkIdType numCells, vtkCellArray* ca,
1025     vtkIdType*& connPtr, vtkIdType*& offsetPtr)
1026   {
1027     vtkNew<vtkIdTypeArray> outConn;
1028     connPtr = outConn->WritePointer(0, connSize);
1029     vtkNew<vtkIdTypeArray> outOffsets;
1030     offsetPtr = outOffsets->WritePointer(0, numCells + 1);
1031     offsetPtr[numCells] = connSize;
1032     ca->SetData(outOffsets, outConn);
1033   }
1034 
1035   // Initialize thread data
Initialize__anon3ebeb7f20111::ExtractCellBoundaries1036   void Initialize()
1037   {
1038     // Make sure cells have been built
1039     auto& localData = this->LocalData.Local();
1040     localData.SetPointMap(this->PointMap);
1041     localData.SetExcludedFaces(this->ExcFaces);
1042   }
1043 
1044   // operator() implemented by dataset-specific subclasses
1045 
1046   // Composite local thread data; i.e., rather than linearly appending data from each
1047   // thread into the filter's output, this performs a parallel append.
Reduce__anon3ebeb7f20111::ExtractCellBoundaries1048   void Reduce()
1049   {
1050     // Determine offsets to partition work and perform memory allocations.
1051     vtkIdType numCells, numConnEntries;
1052     vtkIdType vertsNumPts = 0, vertsNumCells = 0;
1053     vtkIdType linesNumPts = 0, linesNumCells = 0;
1054     vtkIdType polysNumPts = 0, polysNumCells = 0;
1055     vtkIdType stripsNumPts = 0, stripsNumCells = 0;
1056     int threadId = 0;
1057 
1058     // Loop over the local data generated by each thread. Setup the
1059     // offsets and such to insert into the output cell arrays.
1060     auto tItr = this->LocalData.begin();
1061     auto tEnd = this->LocalData.end();
1062     for (; tItr != tEnd; ++tItr)
1063     {
1064       tItr->ThreadId = threadId++;
1065       this->Threads->emplace_back(tItr); // need pointers to local thread data
1066 
1067       tItr->VertsConnOffset = vertsNumPts;
1068       tItr->VertsOffset = vertsNumCells;
1069       numCells = tItr->Verts.GetNumberOfCells();
1070       numConnEntries = tItr->Verts.GetNumberOfConnEntries() - numCells;
1071       vertsNumCells += numCells;
1072       vertsNumPts += numConnEntries;
1073 
1074       tItr->LinesConnOffset = linesNumPts;
1075       tItr->LinesOffset = linesNumCells;
1076       numCells = tItr->Lines.GetNumberOfCells();
1077       numConnEntries = tItr->Lines.GetNumberOfConnEntries() - numCells;
1078       linesNumCells += numCells;
1079       linesNumPts += numConnEntries;
1080 
1081       tItr->PolysConnOffset = polysNumPts;
1082       tItr->PolysOffset = polysNumCells;
1083       numCells = tItr->Polys.GetNumberOfCells();
1084       numConnEntries = tItr->Polys.GetNumberOfConnEntries() - numCells;
1085       polysNumCells += numCells;
1086       polysNumPts += numConnEntries;
1087 
1088       tItr->StripsConnOffset = stripsNumPts;
1089       tItr->StripsOffset = stripsNumCells;
1090       numCells = tItr->Strips.GetNumberOfCells();
1091       numConnEntries = tItr->Strips.GetNumberOfConnEntries() - numCells;
1092       stripsNumCells += numCells;
1093       stripsNumPts += numConnEntries;
1094     }
1095     this->VertsCellIdOffset = 0;
1096     this->LinesCellIdOffset = vertsNumCells;
1097     this->PolysCellIdOffset = vertsNumCells + linesNumCells;
1098     this->StripsCellIdOffset = vertsNumCells + linesNumCells + polysNumCells;
1099     this->NumCells = vertsNumCells + linesNumCells + polysNumCells + stripsNumCells;
1100     this->NumPts = vertsNumPts + linesNumPts + polysNumPts + stripsNumPts;
1101 
1102     // Allocate data for the output cell arrays: connectivity and
1103     // offsets are required to construct a cell array. Later compositing
1104     // will fill them in.
1105     if (vertsNumPts > 0)
1106     {
1107       this->AllocateCellArray(
1108         vertsNumPts, vertsNumCells, this->Verts, this->VertsConnPtr, this->VertsOffsetPtr);
1109     }
1110     if (linesNumPts > 0)
1111     {
1112       this->AllocateCellArray(
1113         linesNumPts, linesNumCells, this->Lines, this->LinesConnPtr, this->LinesOffsetPtr);
1114     }
1115     if (polysNumPts > 0)
1116     {
1117       this->AllocateCellArray(
1118         polysNumPts, polysNumCells, this->Polys, this->PolysConnPtr, this->PolysOffsetPtr);
1119     }
1120     if (stripsNumPts > 0)
1121     {
1122       this->AllocateCellArray(
1123         stripsNumPts, stripsNumCells, this->Strips, this->StripsConnPtr, this->StripsOffsetPtr);
1124     }
1125   }
1126 };
1127 
1128 // Extract unstructured grid boundary by visiting each cell and examining
1129 // cell features.
1130 struct ExtractUG : public ExtractCellBoundaries
1131 {
1132   // The unstructured grid to process
1133   vtkUnstructuredGrid* Grid;
1134   // Each thread has its own cell iterator.
1135   vtkSMPThreadLocal<vtkSmartPointer<vtkUnstructuredGridCellIterator>> CellIter;
1136 
ExtractUG__anon3ebeb7f20111::ExtractUG1137   ExtractUG(vtkUnstructuredGrid* grid, const char* cellVis, const unsigned char* ghosts,
1138     bool merging, vtkCellArray* verts, vtkCellArray* lines, vtkCellArray* polys,
1139     vtkCellArray* strips, vtkExcludedFaces* exc, ThreadOutputType* t)
1140     : ExtractCellBoundaries(cellVis, ghosts, verts, lines, polys, strips, exc, t)
1141     , Grid(grid)
1142     , CellIter(nullptr)
1143   {
1144     if (merging)
1145     {
1146       this->CreatePointMap(grid->GetNumberOfPoints());
1147     }
1148   }
1149 
1150   // Initialize thread data
Initialize__anon3ebeb7f20111::ExtractUG1151   void Initialize()
1152   {
1153     this->ExtractCellBoundaries::Initialize();
1154     this->CellIter.Local().TakeReference(
1155       static_cast<vtkUnstructuredGridCellIterator*>(this->Grid->NewCellIterator()));
1156   }
1157 
operator ()__anon3ebeb7f20111::ExtractUG1158   void operator()(vtkIdType cellId, vtkIdType endCellId)
1159   {
1160     auto& localData = this->LocalData.Local();
1161     auto& cellIter = this->CellIter.Local();
1162 
1163     for (cellIter->GoToCell(cellId); cellId < endCellId; ++cellId, cellIter->GoToNextCell())
1164     {
1165       // Handle ghost cells here.  Another option was used cellVis array.
1166       if (this->CellGhosts && this->CellGhosts[cellId] & vtkDataSetAttributes::DUPLICATECELL)
1167       { // Do not create surfaces in outer ghost cells.
1168         continue;
1169       }
1170 
1171       // If the cell is visible process it
1172       if (!this->CellVis || this->CellVis[cellId])
1173       {
1174         int type = cellIter->GetCellType();
1175         vtkIdList* pointIdList = cellIter->GetPointIds();
1176         vtkIdType npts = pointIdList->GetNumberOfIds();
1177         vtkIdType* pts = pointIdList->GetPointer(0);
1178 
1179         ExtractCellGeometry(
1180           this->Grid, cellId, type, npts, pts, this->CellVis, cellIter, &localData);
1181       } // if cell visible
1182     }   // for all cells in this batch
1183   }     // operator()
1184 
1185   // Composite local thread data
Reduce__anon3ebeb7f20111::ExtractUG1186   void Reduce() { this->ExtractCellBoundaries::Reduce(); }
1187 };
1188 
1189 // Extract unstructured grid boundary by visiting cells connected to points
1190 // with low point degree.
1191 struct FastExtractUG : public ExtractCellBoundaries
1192 {
1193   // The unstructured grid to process
1194   vtkUnstructuredGrid* Grid;
1195   // Each thread has its own cell iterator.
1196   vtkSMPThreadLocal<vtkSmartPointer<vtkUnstructuredGridCellIterator>> CellIter;
1197 
1198   // Specialized to the fast unstructured grid extraction process.
1199   vtkAbstractCellLinks* Links;
1200   vtkIdType Degree;
1201   std::vector<unsigned char> CellSelection;
1202 
FastExtractUG__anon3ebeb7f20111::FastExtractUG1203   FastExtractUG(vtkUnstructuredGrid* grid, const char* cellVis, const unsigned char* ghosts,
1204     bool merging, vtkCellArray* verts, vtkCellArray* lines, vtkCellArray* polys,
1205     vtkCellArray* strips, vtkIdType degree, vtkAbstractCellLinks* links, vtkExcludedFaces* exc,
1206     ThreadOutputType* t)
1207     : ExtractCellBoundaries(cellVis, ghosts, verts, lines, polys, strips, exc, t)
1208     , Grid(grid)
1209     , CellIter(nullptr)
1210     , Links(links)
1211     , Degree(degree)
1212   {
1213     vtkIdType minMaxDegree[2];
1214     minMaxDegree[0] = 0;
1215     minMaxDegree[1] = this->Degree + 1;
1216     this->CellSelection.resize(grid->GetNumberOfCells());
1217     this->Links->SelectCells(minMaxDegree, CellSelection.data());
1218     if (merging)
1219     {
1220       this->CreatePointMap(grid->GetNumberOfPoints());
1221     }
1222   }
1223 
1224   // Initialize thread data
Initialize__anon3ebeb7f20111::FastExtractUG1225   void Initialize()
1226   {
1227     this->ExtractCellBoundaries::Initialize();
1228     this->CellIter.Local().TakeReference(
1229       static_cast<vtkUnstructuredGridCellIterator*>(this->Grid->NewCellIterator()));
1230   }
1231 
operator ()__anon3ebeb7f20111::FastExtractUG1232   void operator()(vtkIdType cellId, vtkIdType endCellId)
1233   {
1234     auto& localData = this->LocalData.Local();
1235     auto& cellIter = this->CellIter.Local();
1236 
1237     for (cellIter->GoToCell(cellId); cellId < endCellId; ++cellId, cellIter->GoToNextCell())
1238     {
1239       // Handle ghost cells here.  Another option was used cellVis array.
1240       if (this->CellGhosts && this->CellGhosts[cellId] & vtkDataSetAttributes::DUPLICATECELL)
1241       { // Do not create surfaces in outer ghost cells.
1242         continue;
1243       }
1244 
1245       // If the cell is visible process it
1246       if (this->CellSelection[cellId] != 0 && (!this->CellVis || this->CellVis[cellId]))
1247       {
1248         int type = cellIter->GetCellType();
1249         vtkIdList* pointIdList = cellIter->GetPointIds();
1250         vtkIdType npts = pointIdList->GetNumberOfIds();
1251         vtkIdType* pts = pointIdList->GetPointer(0);
1252 
1253         ExtractCellGeometry(
1254           this->Grid, cellId, type, npts, pts, this->CellVis, cellIter, &localData);
1255 
1256       } // if cell visible and selected via fast mode (vertex degree)
1257     }   // for all cells in this batch
1258   }     // operator()
1259 
1260   // Composite local thread data
Reduce__anon3ebeb7f20111::FastExtractUG1261   void Reduce() { this->ExtractCellBoundaries::Reduce(); }
1262 }; // FastExtractUG
1263 
1264 // Extract structured 3D grid boundary by visiting each cell and examining
1265 // cell features.
1266 struct ExtractStructured : public ExtractCellBoundaries
1267 {
1268   vtkDataSet* Input; // Input data
1269   vtkIdType* Extent; // Data extent
1270   int Dims[3];       // Grid dimensions
1271 
ExtractStructured__anon3ebeb7f20111::ExtractStructured1272   ExtractStructured(vtkDataSet* ds, vtkIdType ext[6], const char* cellVis,
1273     const unsigned char* ghosts, bool merging, vtkCellArray* polys, vtkExcludedFaces* exc,
1274     ThreadOutputType* t)
1275     : ExtractCellBoundaries(cellVis, ghosts, nullptr, nullptr, polys, nullptr, exc, t)
1276     , Input(ds)
1277     , Extent(ext)
1278   {
1279     this->Dims[0] = this->Extent[1] - this->Extent[0] + 1;
1280     this->Dims[1] = this->Extent[3] - this->Extent[2] + 1;
1281     this->Dims[2] = this->Extent[5] - this->Extent[4] + 1;
1282     if (merging)
1283     {
1284       this->CreatePointMap(this->Dims[0] * this->Dims[1] * this->Dims[2]);
1285     }
1286   }
1287 
1288   // Determine whether to process the structured cell at location ijk[3]
1289   // and with cellId given for face extraction.
ProcessCell__anon3ebeb7f20111::ExtractStructured1290   bool ProcessCell(vtkIdType cellId, int ijk[3])
1291   {
1292     // Are we on the boundary of the structured dataset? Then the cell will
1293     // certainly produce a boundary face.
1294     if (ijk[0] == 0 || ijk[0] == (this->Dims[0] - 2) || ijk[1] == 0 ||
1295       ijk[1] == (this->Dims[1] - 2) || ijk[2] == 0 || ijk[2] == (this->Dims[2] - 2))
1296     {
1297       return true;
1298     }
1299 
1300     // If a cell visibility array is provided, then check neighbors.  If a
1301     // neighbor is not visible, then this cell will produce a boundary
1302     // face.  Note that since we've already checked the boundary cells (in
1303     // the if statement above) we don't need to worry about indexing beyond
1304     // the end of the cellVis array.
1305     if (this->CellVis)
1306     {
1307       int yInc = this->Dims[0] - 1;
1308       int zInc = (this->Dims[0] - 1) * (this->Dims[1] - 1);
1309       const char* cellVis = this->CellVis;
1310       if (!cellVis[cellId - 1] || !cellVis[cellId + 1] || !cellVis[cellId - yInc] ||
1311         !cellVis[cellId + yInc] || !cellVis[cellId - zInc] || !cellVis[cellId + zInc])
1312       {
1313         return true;
1314       }
1315     }
1316 
1317     return false;
1318   }
1319 
1320   // Initialize thread data
Initialize__anon3ebeb7f20111::ExtractStructured1321   void Initialize() { this->ExtractCellBoundaries::Initialize(); }
1322 
operator ()__anon3ebeb7f20111::ExtractStructured1323   void operator()(vtkIdType cellId, vtkIdType endCellId)
1324   {
1325     auto& localData = this->LocalData.Local();
1326 
1327     for (; cellId < endCellId; ++cellId)
1328     {
1329       // Handle ghost cells here.  Another option was used cellVis array.
1330       if (this->CellGhosts && this->CellGhosts[cellId] & vtkDataSetAttributes::DUPLICATECELL)
1331       { // Do not create surfaces in outer ghost cells.
1332         continue;
1333       }
1334 
1335       // If the cell is visible process it. This is far from optimized but simple.
1336       if (!this->CellVis || this->CellVis[cellId])
1337       {
1338         // Get the ijk to see if this cell is on the boundary of the structured data.
1339         int ijk[3];
1340         vtkStructuredData::ComputeCellStructuredCoords(cellId, this->Dims, ijk);
1341         if (this->ProcessCell(cellId, ijk))
1342         { // on boundary
1343           vtkGenericCell* cell = localData.Cell;
1344           this->Input->GetCell(cellId, cell);
1345           int cellType = cell->GetCellType();
1346           vtkIdType npts = cell->PointIds->GetNumberOfIds();
1347           vtkIdType* pts = cell->PointIds->GetPointer(0);
1348           ExtractStructuredCellGeometry(
1349             this->Input, cellId, cellType, npts, pts, this->CellVis, &localData);
1350         }
1351       } // if cell visible
1352     }   // for all cells in this batch
1353   }     // operator()
1354 
1355   // Composite local thread data
Reduce__anon3ebeb7f20111::ExtractStructured1356   void Reduce() { this->ExtractCellBoundaries::Reduce(); }
1357 };
1358 
1359 // Extract the boundaries of a general vtkDataSet by visiting each cell and
1360 // examining cell features. This is slower than specialized types and should be
1361 // avoided if possible.
1362 struct ExtractDS : public ExtractCellBoundaries
1363 {
1364   // The unstructured grid to process
1365   vtkDataSet* DataSet;
1366 
ExtractDS__anon3ebeb7f20111::ExtractDS1367   ExtractDS(vtkDataSet* ds, const char* cellVis, const unsigned char* ghosts, vtkCellArray* verts,
1368     vtkCellArray* lines, vtkCellArray* polys, vtkCellArray* strips, vtkExcludedFaces* exc,
1369     ThreadOutputType* t)
1370     : ExtractCellBoundaries(cellVis, ghosts, verts, lines, polys, strips, exc, t)
1371     , DataSet(ds)
1372   {
1373     // Point merging is always required since points are not explicitly
1374     // represented and cannot be passed through to the output.
1375     this->CreatePointMap(ds->GetNumberOfPoints());
1376   }
1377 
1378   // Initialize thread data
Initialize__anon3ebeb7f20111::ExtractDS1379   void Initialize()
1380   {
1381     this->ExtractCellBoundaries::Initialize();
1382     // Make sure any internal initialization methods which may not be thread
1383     // safe are built.
1384     this->DataSet->GetCell(0);
1385   }
1386 
operator ()__anon3ebeb7f20111::ExtractDS1387   void operator()(vtkIdType cellId, vtkIdType endCellId)
1388   {
1389     auto& localData = this->LocalData.Local();
1390 
1391     for (; cellId < endCellId; ++cellId)
1392     {
1393       // Handle ghost cells here.  Another option was used cellVis array.
1394       if (this->CellGhosts && this->CellGhosts[cellId] & vtkDataSetAttributes::DUPLICATECELL)
1395       { // Do not create surfaces in outer ghost cells.
1396         continue;
1397       }
1398 
1399       // If the cell is visible process it
1400       if (!this->CellVis || this->CellVis[cellId])
1401       {
1402         ExtractDSCellGeometry(this->DataSet, cellId, this->CellVis, &localData);
1403       } // if cell visible
1404 
1405     } // for all cells in this batch
1406   }   // operator()
1407 
1408   // Composite local thread data
Reduce__anon3ebeb7f20111::ExtractDS1409   void Reduce() { this->ExtractCellBoundaries::Reduce(); }
1410 };
1411 
1412 // Helper class to record original point and cell ids. This is for copying
1413 // cell data, and also to produce output arrays indicating where output
1414 // cells originated from (typically used in picking).
1415 struct IdRecorder
1416 {
1417   vtkSmartPointer<vtkIdTypeArray> Ids;
1418 
IdRecorder__anon3ebeb7f20111::IdRecorder1419   IdRecorder(
1420     vtkTypeBool passThru, const char* name, vtkDataSetAttributes* attrD, vtkIdType allocSize)
1421   {
1422     if (passThru)
1423     {
1424       this->Ids.TakeReference(vtkIdTypeArray::New());
1425       this->Ids->SetName(name);
1426       this->Ids->SetNumberOfComponents(1);
1427       this->Ids->Allocate(allocSize);
1428       attrD->AddArray(this->Ids.Get());
1429     }
1430   }
IdRecorder__anon3ebeb7f20111::IdRecorder1431   IdRecorder(vtkTypeBool passThru, const char* name, vtkDataSetAttributes* attrD)
1432   {
1433     if (passThru)
1434     {
1435       this->Ids.TakeReference(vtkIdTypeArray::New());
1436       this->Ids->SetName(name);
1437       this->Ids->SetNumberOfComponents(1);
1438       attrD->AddArray(this->Ids.Get());
1439     }
1440     else
1441     {
1442       this->Ids = nullptr;
1443     }
1444   }
Insert__anon3ebeb7f20111::IdRecorder1445   void Insert(vtkIdType destId, vtkIdType origId)
1446   {
1447     if (this->Ids.Get() != nullptr)
1448     {
1449       this->Ids->InsertValue(destId, origId);
1450     }
1451   }
GetPointer__anon3ebeb7f20111::IdRecorder1452   vtkIdType* GetPointer() { return this->Ids->GetPointer(0); }
PassThru__anon3ebeb7f20111::IdRecorder1453   vtkTypeBool PassThru() { return (this->Ids.Get() == nullptr ? false : true); }
Allocate__anon3ebeb7f20111::IdRecorder1454   void Allocate(vtkIdType num)
1455   {
1456     if (this->Ids.Get() != nullptr)
1457     {
1458       this->Ids->Allocate(num);
1459     }
1460   }
SetNumberOfValues__anon3ebeb7f20111::IdRecorder1461   void SetNumberOfValues(vtkIdType num)
1462   {
1463     if (this->Ids.Get() != nullptr)
1464     {
1465       this->Ids->SetNumberOfValues(num);
1466     }
1467   }
1468 }; // id recorder
1469 
1470 // Generate point map for explicit point representations.
1471 template <typename TIP, typename TOP>
1472 struct GenerateExpPoints
1473 {
1474   TIP* InPts;
1475   TOP* OutPts;
1476   vtkIdType* PointMap;
1477   ArrayList* PtArrays;
1478 
GenerateExpPoints__anon3ebeb7f20111::GenerateExpPoints1479   GenerateExpPoints(TIP* inPts, TOP* outPts, vtkIdType* ptMap, ArrayList* ptArrays)
1480     : InPts(inPts)
1481     , OutPts(outPts)
1482     , PointMap(ptMap)
1483     , PtArrays(ptArrays)
1484   {
1485   }
1486 
operator ()__anon3ebeb7f20111::GenerateExpPoints1487   void operator()(vtkIdType ptId, vtkIdType endPtId)
1488   {
1489     const auto inPts = vtk::DataArrayTupleRange<3>(this->InPts);
1490     auto outPts = vtk::DataArrayTupleRange<3>(this->OutPts);
1491     vtkIdType mapId;
1492 
1493     for (; ptId < endPtId; ++ptId)
1494     {
1495       if ((mapId = this->PointMap[ptId]) >= 0)
1496       {
1497         auto xIn = inPts[ptId];
1498         auto xOut = outPts[mapId];
1499         xOut[0] = xIn[0];
1500         xOut[1] = xIn[1];
1501         xOut[2] = xIn[2];
1502         this->PtArrays->Copy(ptId, mapId);
1503       }
1504     }
1505   }
1506 };
1507 
1508 // Generate point map for implicit point representations.
1509 template <typename TOP>
1510 struct GenerateImpPoints
1511 {
1512   vtkDataSet* InPts;
1513   TOP* OutPts;
1514   vtkIdType* PointMap;
1515   ArrayList* PtArrays;
1516 
GenerateImpPoints__anon3ebeb7f20111::GenerateImpPoints1517   GenerateImpPoints(vtkDataSet* inPts, TOP* outPts, vtkIdType* ptMap, ArrayList* ptArrays)
1518     : InPts(inPts)
1519     , OutPts(outPts)
1520     , PointMap(ptMap)
1521     , PtArrays(ptArrays)
1522   {
1523   }
1524 
operator ()__anon3ebeb7f20111::GenerateImpPoints1525   void operator()(vtkIdType ptId, vtkIdType endPtId)
1526   {
1527     auto outPts = vtk::DataArrayTupleRange<3>(this->OutPts);
1528     double xIn[3];
1529     vtkIdType mapId;
1530 
1531     for (; ptId < endPtId; ++ptId)
1532     {
1533       if ((mapId = this->PointMap[ptId]) >= 0)
1534       {
1535         this->InPts->GetPoint(ptId, xIn);
1536         auto xOut = outPts[mapId];
1537         xOut[0] = xIn[0];
1538         xOut[1] = xIn[1];
1539         xOut[2] = xIn[2];
1540         this->PtArrays->Copy(ptId, mapId);
1541       }
1542     }
1543   }
1544 };
1545 
1546 // Base class for point generation workers.
1547 struct GeneratePtsWorker
1548 {
1549   vtkIdType NumOutputPoints;
1550 
GeneratePtsWorker__anon3ebeb7f20111::GeneratePtsWorker1551   GeneratePtsWorker()
1552     : NumOutputPoints(0)
1553   {
1554   }
1555 
1556   // Create the final point map. This could be threaded (prefix_sum) but
1557   // performance gains are minimal.
GeneratePointMap__anon3ebeb7f20111::GeneratePtsWorker1558   vtkIdType* GeneratePointMap(vtkIdType numInputPts, ExtractCellBoundaries* extract)
1559   {
1560     // The PointMap has been marked as to which points are being used.
1561     // This needs to be updated to indicate the output point ids.
1562     vtkIdType* ptMap = extract->PointMap;
1563     for (auto ptId = 0; ptId < numInputPts; ++ptId)
1564     {
1565       if (ptMap[ptId] == 1)
1566       {
1567         ptMap[ptId] = this->NumOutputPoints++;
1568       }
1569     }
1570     return ptMap;
1571   }
1572 };
1573 
1574 // Dispatch to explicit, templated point types
1575 struct ExpPtsWorker : public GeneratePtsWorker
1576 {
1577   template <typename TIP, typename TOP>
operator ()__anon3ebeb7f20111::ExpPtsWorker1578   void operator()(TIP* inPts, TOP* outPts, vtkIdType numInputPts, vtkPointData* inPD,
1579     vtkPointData* outPD, ExtractCellBoundaries* extract)
1580   {
1581     // Finalize the point map
1582     vtkIdType* ptMap = this->GeneratePointMap(numInputPts, extract);
1583 
1584     // Now generate all of the points and point attribute data
1585     ArrayList ptArrays;
1586     outPD->CopyAllocate(inPD, this->NumOutputPoints);
1587     ptArrays.AddArrays(this->NumOutputPoints, inPD, outPD, 0.0, false);
1588 
1589     outPts->SetNumberOfTuples(this->NumOutputPoints);
1590     GenerateExpPoints<TIP, TOP> genPts(inPts, outPts, ptMap, &ptArrays);
1591     vtkSMPTools::For(0, numInputPts, genPts);
1592   }
1593 };
1594 
1595 // Dispatch to implicit input points, explicit output points
1596 struct ImpPtsWorker : public GeneratePtsWorker
1597 {
1598   template <typename TOP>
operator ()__anon3ebeb7f20111::ImpPtsWorker1599   void operator()(TOP* outPts, vtkDataSet* inPts, vtkIdType numInputPts, vtkPointData* inPD,
1600     vtkPointData* outPD, ExtractCellBoundaries* extract)
1601   {
1602     // Finalize the point map
1603     vtkIdType* ptMap = this->GeneratePointMap(numInputPts, extract);
1604 
1605     // Now generate all of the points and point attribute data
1606     ArrayList ptArrays;
1607     outPD->CopyAllocate(inPD, this->NumOutputPoints);
1608     ptArrays.AddArrays(this->NumOutputPoints, inPD, outPD, 0.0, false);
1609 
1610     outPts->SetNumberOfTuples(this->NumOutputPoints);
1611     GenerateImpPoints<TOP> genPts(inPts, outPts, ptMap, &ptArrays);
1612     vtkSMPTools::For(0, numInputPts, genPts);
1613   }
1614 };
1615 
1616 // Composite threads to produce output cell topology
1617 struct CompositeCells
1618 {
1619   const vtkIdType* PointMap;
1620   ArrayList* CellArrays;
1621   ExtractCellBoundaries* Extractor;
1622   ThreadOutputType* Threads;
1623 
CompositeCells__anon3ebeb7f20111::CompositeCells1624   CompositeCells(vtkIdType* ptMap, ArrayList* cellArrays, ExtractCellBoundaries* extract,
1625     ThreadOutputType* threads)
1626     : PointMap(ptMap)
1627     , CellArrays(cellArrays)
1628     , Extractor(extract)
1629     , Threads(threads)
1630   {
1631   }
1632 
CompositeCellArray__anon3ebeb7f20111::CompositeCells1633   void CompositeCellArray(CellArrayType* cat, vtkIdType connOffset, vtkIdType offset,
1634     vtkIdType cellIdOffset, vtkIdType* connPtr, vtkIdType* offsetPtr)
1635   {
1636     vtkIdType* cells = cat->Cells.data();
1637     vtkIdType numCells = cat->GetNumberOfCells();
1638     connPtr += connOffset;
1639     offsetPtr += offset;
1640     vtkIdType offsetVal = connOffset;
1641     vtkIdType globalCellId = cellIdOffset + offset;
1642 
1643     // If not merging points, we reuse input points and so do not need to
1644     // produce new points nor point data.
1645     if (!this->PointMap)
1646     {
1647       for (auto cellId = 0; cellId < numCells; ++cellId)
1648       {
1649         *offsetPtr++ = offsetVal;
1650         vtkIdType npts = *cells++;
1651         for (auto i = 0; i < npts; ++i)
1652         {
1653           *connPtr++ = *cells++;
1654         }
1655         offsetVal += npts;
1656         this->CellArrays->Copy(cat->OrigCellIds[cellId], globalCellId++);
1657       }
1658     }
1659     else // Merging - i.e., using a point map
1660     {
1661       for (auto cellId = 0; cellId < numCells; ++cellId)
1662       {
1663         *offsetPtr++ = offsetVal;
1664         vtkIdType npts = *cells++;
1665         for (auto i = 0; i < npts; ++i)
1666         {
1667           *connPtr++ = this->PointMap[*cells++];
1668         }
1669         offsetVal += npts;
1670         this->CellArrays->Copy(cat->OrigCellIds[cellId], globalCellId++);
1671       }
1672     }
1673   }
1674 
operator ()__anon3ebeb7f20111::CompositeCells1675   void operator()(vtkIdType thread, vtkIdType threadEnd)
1676   {
1677     ExtractCellBoundaries* extract = this->Extractor;
1678 
1679     for (; thread < threadEnd; ++thread)
1680     {
1681       ThreadIterType tItr = (*this->Threads)[thread];
1682 
1683       if (extract->VertsConnPtr)
1684       {
1685         this->CompositeCellArray(&tItr->Verts, tItr->VertsConnOffset, tItr->VertsOffset,
1686           extract->VertsCellIdOffset, extract->VertsConnPtr, extract->VertsOffsetPtr);
1687       }
1688       if (extract->LinesConnPtr)
1689       {
1690         this->CompositeCellArray(&tItr->Lines, tItr->LinesConnOffset, tItr->LinesOffset,
1691           extract->LinesCellIdOffset, extract->LinesConnPtr, extract->LinesOffsetPtr);
1692       }
1693       if (extract->PolysConnPtr)
1694       {
1695         this->CompositeCellArray(&tItr->Polys, tItr->PolysConnOffset, tItr->PolysOffset,
1696           extract->PolysCellIdOffset, extract->PolysConnPtr, extract->PolysOffsetPtr);
1697       }
1698       if (extract->StripsConnPtr)
1699       {
1700         this->CompositeCellArray(&tItr->Strips, tItr->StripsConnOffset, tItr->StripsOffset,
1701           extract->StripsCellIdOffset, extract->StripsConnPtr, extract->StripsOffsetPtr);
1702       }
1703     }
1704   }
1705 }; // CompositeCells
1706 
1707 // Composite threads to produce originating cell ids
1708 struct CompositeCellIds
1709 {
1710   ExtractCellBoundaries* Extractor;
1711   ThreadOutputType* Threads;
1712   vtkIdType* OrigIds;
1713 
CompositeCellIds__anon3ebeb7f20111::CompositeCellIds1714   CompositeCellIds(ExtractCellBoundaries* extract, ThreadOutputType* threads, vtkIdType* origIds)
1715     : Extractor(extract)
1716     , Threads(threads)
1717     , OrigIds(origIds)
1718   {
1719   }
1720 
CompositeIds__anon3ebeb7f20111::CompositeCellIds1721   void CompositeIds(CellArrayType* cat, vtkIdType offset, vtkIdType cellIdOffset)
1722   {
1723     vtkIdType numCells = cat->GetNumberOfCells();
1724     vtkIdType globalCellId = cellIdOffset + offset;
1725 
1726     for (auto cellId = 0; cellId < numCells; ++cellId)
1727     {
1728       this->OrigIds[globalCellId++] = cat->OrigCellIds[cellId];
1729     }
1730   }
1731 
operator ()__anon3ebeb7f20111::CompositeCellIds1732   void operator()(vtkIdType thread, vtkIdType threadEnd)
1733   {
1734     ExtractCellBoundaries* extract = this->Extractor;
1735 
1736     for (; thread < threadEnd; ++thread)
1737     {
1738       ThreadIterType tItr = (*this->Threads)[thread];
1739 
1740       if (extract->VertsConnPtr)
1741       {
1742         this->CompositeIds(&tItr->Verts, tItr->VertsOffset, extract->VertsCellIdOffset);
1743       }
1744       if (extract->LinesConnPtr)
1745       {
1746         this->CompositeIds(&tItr->Lines, tItr->LinesOffset, extract->LinesCellIdOffset);
1747       }
1748       if (extract->PolysConnPtr)
1749       {
1750         this->CompositeIds(&tItr->Polys, tItr->PolysOffset, extract->PolysCellIdOffset);
1751       }
1752       if (extract->StripsConnPtr)
1753       {
1754         this->CompositeIds(&tItr->Strips, tItr->StripsOffset, extract->StripsCellIdOffset);
1755       }
1756     }
1757   }
1758 }; // CompositeCellIds
1759 
1760 } // anonymous namespace
1761 
1762 //------------------------------------------------------------------------------
PolyDataExecute(vtkDataSet * dataSetInput,vtkPolyData * output)1763 int vtkGeometryFilter::PolyDataExecute(vtkDataSet* dataSetInput, vtkPolyData* output)
1764 {
1765   return this->PolyDataExecute(dataSetInput, output, nullptr);
1766 }
1767 
1768 //------------------------------------------------------------------------------
1769 // This is currently not threaded. Usually polydata extraction is only used to
1770 // setup originating cell or point ids - this part is threaded.
PolyDataExecute(vtkDataSet * dataSetInput,vtkPolyData * output,vtkExcludedFaces * exc)1771 int vtkGeometryFilter::PolyDataExecute(
1772   vtkDataSet* dataSetInput, vtkPolyData* output, vtkExcludedFaces* exc)
1773 {
1774   vtkPolyData* input = static_cast<vtkPolyData*>(dataSetInput);
1775   vtkIdType cellId;
1776   int i;
1777   int allVisible;
1778   vtkIdType npts;
1779   const vtkIdType* pts;
1780   vtkPoints* p = input->GetPoints();
1781   vtkIdType numCells = input->GetNumberOfCells();
1782   vtkIdType numPts = input->GetNumberOfPoints();
1783   vtkPointData* pd = input->GetPointData();
1784   vtkCellData* cd = input->GetCellData();
1785   vtkPointData* outputPD = output->GetPointData();
1786   vtkCellData* outputCD = output->GetCellData();
1787   vtkIdType newCellId, ptId;
1788   int visible, type;
1789   double x[3];
1790   unsigned char* cellGhosts = nullptr;
1791   vtkStaticCellLinksTemplate<vtkIdType>* links = (exc == nullptr ? nullptr : exc->Links);
1792 
1793   vtkDebugMacro(<< "Executing geometry filter for poly data input");
1794 
1795   vtkDataArray* temp = nullptr;
1796   if (cd)
1797   {
1798     temp = cd->GetArray(vtkDataSetAttributes::GhostArrayName());
1799   }
1800   if ((!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR) || (temp->GetNumberOfComponents() != 1))
1801   {
1802     vtkDebugMacro("No appropriate ghost levels field available.");
1803   }
1804   else
1805   {
1806     cellGhosts = static_cast<vtkUnsignedCharArray*>(temp)->GetPointer(0);
1807   }
1808 
1809   if ((!this->CellClipping) && (!this->PointClipping) && (!this->ExtentClipping))
1810   {
1811     allVisible = 1;
1812   }
1813   else
1814   {
1815     allVisible = 0;
1816   }
1817 
1818   IdRecorder origCellIds(
1819     this->PassThroughCellIds, this->GetOriginalCellIdsName(), output->GetCellData());
1820   IdRecorder origPointIds(
1821     this->PassThroughPointIds, this->GetOriginalPointIdsName(), output->GetPointData());
1822 
1823   // vtkPolyData points are not culled
1824   if (origPointIds.PassThru())
1825   {
1826     origPointIds.SetNumberOfValues(numPts);
1827     vtkIdType* origPointIdsPtr = origPointIds.GetPointer();
1828     vtkSMPTools::For(0, numPts, [&origPointIdsPtr](vtkIdType pId, vtkIdType endPId) {
1829       for (; pId < endPId; ++pId)
1830       {
1831         origPointIdsPtr[pId] = pId;
1832       }
1833     });
1834   }
1835 
1836   // Special case when data is just passed through
1837   if (allVisible && links == nullptr)
1838   {
1839     output->CopyStructure(input);
1840     outputPD->PassData(pd);
1841     outputCD->PassData(cd);
1842 
1843     if (origCellIds.PassThru())
1844     {
1845       origCellIds.SetNumberOfValues(numCells);
1846       vtkIdType* origCellIdsPtr = origCellIds.GetPointer();
1847       vtkSMPTools::For(0, numCells, [&origCellIdsPtr](vtkIdType cId, vtkIdType endCId) {
1848         for (; cId < endCId; ++cId)
1849         {
1850           origCellIdsPtr[cId] = cId;
1851         }
1852       });
1853     }
1854 
1855     return 1;
1856   }
1857 
1858   // Okay slower path, clipping by cells and/or point ids, or excluding
1859   // faces. Cells may be culled. Always pass point data (points are not
1860   // culled).
1861   output->SetPoints(p);
1862   outputPD->PassData(pd);
1863 
1864   // Allocate
1865   //
1866   origCellIds.Allocate(numCells);
1867   origPointIds.Allocate(numPts);
1868 
1869   output->AllocateEstimate(numCells, 1);
1870   outputCD->CopyAllocate(cd, numCells, numCells / 2);
1871   input->BuildCells(); // needed for GetCellPoints()
1872 
1873   vtkIdType progressInterval = numCells / 20 + 1;
1874   for (cellId = 0; cellId < numCells; cellId++)
1875   {
1876     // Progress and abort method support
1877     if (!(cellId % progressInterval))
1878     {
1879       vtkDebugMacro(<< "Process cell #" << cellId);
1880       this->UpdateProgress(static_cast<double>(cellId) / numCells);
1881     }
1882 
1883     // Handle ghost cells here.  Another option was used cellVis array.
1884     if (cellGhosts && cellGhosts[cellId] & vtkDataSetAttributes::DUPLICATECELL)
1885     { // Do not create surfaces in outer ghost cells.
1886       continue;
1887     }
1888 
1889     input->GetCellPoints(cellId, npts, pts);
1890 
1891     visible = 1;
1892     if (!allVisible)
1893     {
1894       if (this->CellClipping && (cellId < this->CellMinimum || cellId > this->CellMaximum))
1895       {
1896         visible = 0;
1897       }
1898       else
1899       {
1900         for (i = 0; i < npts; i++)
1901         {
1902           ptId = pts[i];
1903           input->GetPoint(ptId, x);
1904 
1905           if ((this->PointClipping && (ptId < this->PointMinimum || ptId > this->PointMaximum)) ||
1906             (this->ExtentClipping &&
1907               (x[0] < this->Extent[0] || x[0] > this->Extent[1] || x[1] < this->Extent[2] ||
1908                 x[1] > this->Extent[3] || x[2] < this->Extent[4] || x[2] > this->Extent[5])))
1909           {
1910             visible = 0;
1911             break;
1912           }
1913         }
1914       }
1915     }
1916 
1917     // now if visible extract geometry - i.e., cells may be culled
1918     if ((allVisible || visible) && (!links || !links->MatchesCell(npts, pts)))
1919     {
1920       type = input->GetCellType(cellId);
1921       newCellId = output->InsertNextCell(type, npts, pts);
1922       outputCD->CopyData(cd, cellId, newCellId);
1923       origCellIds.Insert(cellId, newCellId);
1924     } // if visible
1925   }   // for all cells
1926 
1927   // Update ourselves and release memory
1928   //
1929   output->Squeeze();
1930 
1931   vtkDebugMacro(<< "Extracted " << output->GetNumberOfPoints() << " points,"
1932                 << output->GetNumberOfCells() << " cells.");
1933 
1934   return 1;
1935 }
1936 
1937 namespace
1938 {
1939 struct CharacterizeGrid
1940 {
1941   vtkUnstructuredGrid* Grid;
1942   unsigned char* Types;
1943   unsigned char IsLinear;
1944   vtkSMPThreadLocal<unsigned char> LocalIsLinear;
1945 
CharacterizeGrid__anon3ebeb7f20411::CharacterizeGrid1946   CharacterizeGrid(vtkUnstructuredGrid* grid, vtkUnsignedCharArray* types)
1947     : Grid(grid)
1948   {
1949     this->Types = types->GetPointer(0);
1950   }
1951 
Initialize__anon3ebeb7f20411::CharacterizeGrid1952   void Initialize() { this->LocalIsLinear.Local() = 1; }
1953 
operator ()__anon3ebeb7f20411::CharacterizeGrid1954   void operator()(vtkIdType cellId, vtkIdType endCellId)
1955   {
1956     if (!this->LocalIsLinear.Local())
1957     {
1958       return;
1959     }
1960     // Check against linear cell types
1961     for (; cellId < endCellId; ++cellId)
1962     {
1963       if (!vtkCellTypes::IsLinear(this->Types[cellId]))
1964       {
1965         this->LocalIsLinear.Local() = 0;
1966         return;
1967       }
1968     }
1969   }
1970 
Reduce__anon3ebeb7f20411::CharacterizeGrid1971   void Reduce()
1972   {
1973     this->IsLinear = 1;
1974     auto tItr = this->LocalIsLinear.begin();
1975     auto tEnd = this->LocalIsLinear.end();
1976     for (; tItr != tEnd; ++tItr)
1977     {
1978       if (*tItr == 0)
1979       {
1980         this->IsLinear = 0;
1981         return;
1982       }
1983     }
1984   }
1985 };
1986 
1987 // Threaded creation to generate array of originating point ids.
PassPointIds(const char * name,vtkIdType numInputPts,vtkIdType numOutputPts,vtkIdType * ptMap,vtkPointData * outPD)1988 void PassPointIds(const char* name, vtkIdType numInputPts, vtkIdType numOutputPts, vtkIdType* ptMap,
1989   vtkPointData* outPD)
1990 {
1991   vtkNew<vtkIdTypeArray> origPtIds;
1992   origPtIds->SetName(name);
1993   origPtIds->SetNumberOfComponents(1);
1994   origPtIds->SetNumberOfTuples(numOutputPts);
1995   outPD->AddArray(origPtIds);
1996   vtkIdType* origIds = origPtIds->GetPointer(0);
1997 
1998   // Now threaded populate the array
1999   vtkSMPTools::For(0, numInputPts, [&origIds, &ptMap](vtkIdType ptId, vtkIdType endPtId) {
2000     for (; ptId < endPtId; ++ptId)
2001     {
2002       if (ptMap[ptId] >= 0)
2003       {
2004         origIds[ptMap[ptId]] = ptId;
2005       }
2006     }
2007   });
2008 }
2009 
2010 // Threaded compositing of originating cell ids.
PassCellIds(const char * name,ExtractCellBoundaries * extract,ThreadOutputType * threads,vtkCellData * outCD)2011 void PassCellIds(
2012   const char* name, ExtractCellBoundaries* extract, ThreadOutputType* threads, vtkCellData* outCD)
2013 {
2014   vtkIdType numOutputCells = extract->NumCells;
2015   vtkNew<vtkIdTypeArray> origCellIds;
2016   origCellIds->SetName(name);
2017   origCellIds->SetNumberOfComponents(1);
2018   origCellIds->SetNumberOfTuples(numOutputCells);
2019   outCD->AddArray(origCellIds);
2020   vtkIdType* origIds = origCellIds->GetPointer(0);
2021 
2022   // Now populate the original cell ids
2023   CompositeCellIds compIds(extract, threads, origIds);
2024   vtkSMPTools::For(0, static_cast<vtkIdType>(threads->size()), compIds);
2025 }
2026 
2027 } // anonymous
2028 
2029 //----------------------------------------------------------------------------
CharacterizeUnstructuredGrid(vtkUnstructuredGrid * input)2030 vtkGeometryFilterHelper* vtkGeometryFilterHelper::CharacterizeUnstructuredGrid(
2031   vtkUnstructuredGrid* input)
2032 {
2033   vtkGeometryFilterHelper* info = new vtkGeometryFilterHelper;
2034 
2035   // Check to see if the data actually has nonlinear cells.  Handling
2036   // nonlinear cells requires delegation to the appropriate filter.
2037   vtkIdType numCells = input->GetNumberOfCells();
2038   CharacterizeGrid characterize(input, input->GetCellTypesArray());
2039   vtkSMPTools::For(0, numCells, characterize);
2040 
2041   info->IsLinear = characterize.IsLinear;
2042 
2043   return info;
2044 }
2045 
2046 //----------------------------------------------------------------------------
CopyFilterParams(vtkGeometryFilter * gf,vtkDataSetSurfaceFilter * dssf)2047 void vtkGeometryFilterHelper::CopyFilterParams(vtkGeometryFilter* gf, vtkDataSetSurfaceFilter* dssf)
2048 {
2049   // Helper method to copy key parameters from this filter to an instance of
2050   // vtkDataSetSurfaceFilter. This is for delegation.
2051   dssf->SetPieceInvariant(gf->GetPieceInvariant());
2052   dssf->SetPassThroughCellIds(gf->GetPassThroughCellIds());
2053   dssf->SetPassThroughPointIds(gf->GetPassThroughPointIds());
2054   dssf->SetOriginalCellIdsName(gf->GetOriginalCellIdsName());
2055   dssf->SetOriginalPointIdsName(gf->GetOriginalPointIdsName());
2056   dssf->SetNonlinearSubdivisionLevel(gf->GetNonlinearSubdivisionLevel());
2057   dssf->SetFastMode(gf->GetFastMode());
2058 }
2059 
2060 //----------------------------------------------------------------------------
CopyFilterParams(vtkDataSetSurfaceFilter * dssf,vtkGeometryFilter * gf)2061 void vtkGeometryFilterHelper::CopyFilterParams(vtkDataSetSurfaceFilter* dssf, vtkGeometryFilter* gf)
2062 {
2063   // Helper method to copy key parameters from an instance of
2064   // vtkDataSetSurfaceFilter to vtkGeometryFilter. This is for delegation.
2065   gf->SetPieceInvariant(dssf->GetPieceInvariant());
2066   gf->SetPassThroughCellIds(dssf->GetPassThroughCellIds());
2067   gf->SetPassThroughPointIds(dssf->GetPassThroughPointIds());
2068   gf->SetOriginalCellIdsName(dssf->GetOriginalCellIdsName());
2069   gf->SetOriginalPointIdsName(dssf->GetOriginalPointIdsName());
2070   gf->SetNonlinearSubdivisionLevel(dssf->GetNonlinearSubdivisionLevel());
2071   gf->SetFastMode(dssf->GetFastMode());
2072 }
2073 
2074 //----------------------------------------------------------------------------
UnstructuredGridExecute(vtkDataSet * dataSetInput,vtkPolyData * output)2075 int vtkGeometryFilter::UnstructuredGridExecute(vtkDataSet* dataSetInput, vtkPolyData* output)
2076 {
2077   return this->UnstructuredGridExecute(dataSetInput, output, nullptr, nullptr);
2078 }
2079 
2080 //----------------------------------------------------------------------------
UnstructuredGridExecute(vtkDataSet * dataSetInput,vtkPolyData * output,vtkGeometryFilterHelper * info,vtkExcludedFaces * exc)2081 int vtkGeometryFilter::UnstructuredGridExecute(vtkDataSet* dataSetInput, vtkPolyData* output,
2082   vtkGeometryFilterHelper* info, vtkExcludedFaces* exc)
2083 {
2084   vtkUnstructuredGrid* input = static_cast<vtkUnstructuredGrid*>(dataSetInput);
2085   vtkCellArray* connectivity = input->GetCells();
2086   if (connectivity == nullptr)
2087   {
2088     vtkDebugMacro(<< "Nothing to extract");
2089     return 0;
2090   }
2091 
2092   // If no info, then compute information about the unstructured grid.
2093   // Depending on the outcome, we may process the data ourselves, or send over
2094   // to the faster vtkGeometryFilter.
2095   bool mayDelegate = (info == nullptr && this->Delegation);
2096   if (info == nullptr)
2097   {
2098     info = vtkGeometryFilterHelper::CharacterizeUnstructuredGrid(input);
2099   }
2100 
2101   // Nonlinear cells are handled by vtkDataSetSurfaceFilter
2102   // non-linear cells using sub-division.
2103   if (!info->IsLinear && mayDelegate)
2104   {
2105     vtkNew<vtkDataSetSurfaceFilter> dssf;
2106     vtkGeometryFilterHelper::CopyFilterParams(this, dssf.Get());
2107     dssf->UnstructuredGridExecute(dataSetInput, output, info);
2108     delete info;
2109     return 1;
2110   }
2111 
2112   auto cellIter = vtk::TakeSmartPointer(input->NewCellIterator());
2113   vtkIdType cellId;
2114   vtkIdType npts = 0;
2115   vtkIdList* pointIdList;
2116   const vtkIdType* pts = nullptr;
2117   vtkPoints* inPts = input->GetPoints();
2118   vtkIdType numInputPts = input->GetNumberOfPoints(), numOutputPts;
2119   vtkIdType numCells = input->GetNumberOfCells();
2120   vtkPointData* inPD = input->GetPointData();
2121   vtkCellData* inCD = input->GetCellData();
2122   vtkPointData* outPD = output->GetPointData();
2123   vtkCellData* outCD = output->GetCellData();
2124   std::unique_ptr<char[]> uCellVis; // reference count to prevent leakage
2125   char* cellVis;
2126   unsigned char* cellGhosts = nullptr;
2127 
2128   vtkDebugMacro(<< "Executing geometry filter for unstructured grid input");
2129 
2130   vtkDataArray* temp = nullptr;
2131   if (inCD)
2132   {
2133     temp = inCD->GetArray(vtkDataSetAttributes::GhostArrayName());
2134   }
2135   if ((!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR) || (temp->GetNumberOfComponents() != 1))
2136   {
2137     vtkDebugMacro("No appropriate ghost levels field available.");
2138   }
2139   else
2140   {
2141     cellGhosts = static_cast<vtkUnsignedCharArray*>(temp)->GetPointer(0);
2142   }
2143 
2144   // Determine nature of what we have to do
2145   if ((!this->CellClipping) && (!this->PointClipping) && (!this->ExtentClipping))
2146   {
2147     cellVis = nullptr;
2148   }
2149   else
2150   {
2151     uCellVis = std::unique_ptr<char[]>(new char[numCells]);
2152     cellVis = uCellVis.get();
2153   }
2154 
2155   outCD->CopyGlobalIdsOn();
2156 
2157   // Loop over the cells determining what's visible. This could be threaded
2158   // if necessary - for now it's not used very often so serial.
2159   if (cellVis)
2160   {
2161     double x[3];
2162     for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell())
2163     {
2164       cellId = cellIter->GetCellId();
2165       pointIdList = cellIter->GetPointIds();
2166       npts = pointIdList->GetNumberOfIds();
2167       pts = pointIdList->GetPointer(0);
2168       cellVis[cellId] = 1;
2169       if (this->CellClipping && (cellId < this->CellMinimum || cellId > this->CellMaximum))
2170       {
2171         cellVis[cellId] = 0;
2172       }
2173       else
2174       {
2175         for (int i = 0; i < npts; i++)
2176         {
2177           inPts->GetPoint(pts[i], x);
2178           if ((this->PointClipping &&
2179                 (pts[i] < this->PointMinimum || pts[i] > this->PointMaximum)) ||
2180             (this->ExtentClipping &&
2181               (x[0] < this->Extent[0] || x[0] > this->Extent[1] || x[1] < this->Extent[2] ||
2182                 x[1] > this->Extent[3] || x[2] < this->Extent[4] || x[2] > this->Extent[5])))
2183           {
2184             cellVis[cellId] = 0;
2185             break;
2186           } // point/extent clipping
2187         }   // for each point
2188       }     // if point clipping needs checking
2189     }       // for all cells
2190   }         // if not all visible
2191 
2192   // Prepare to generate the output. The cell arrays are of course the output vertex,
2193   // line, polygon, and triangle strip output. The four IdListType's capture the
2194   // generating cell ids (used later to copy cell attributes).
2195   vtkNew<vtkPoints> outPts;
2196   if (this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION)
2197   {
2198     outPts->SetDataType(inPts->GetDataType());
2199   }
2200   else if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION)
2201   {
2202     outPts->SetDataType(VTK_FLOAT);
2203   }
2204   else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
2205   {
2206     outPts->SetDataType(VTK_DOUBLE);
2207   }
2208   if (!this->Merging) // no merging, just use input points
2209   {
2210     output->SetPoints(inPts);
2211     outPD->PassData(inPD);
2212   }
2213   else
2214   {
2215     output->SetPoints(outPts);
2216   }
2217 
2218   vtkNew<vtkCellArray> verts;
2219   vtkNew<vtkCellArray> lines;
2220   vtkNew<vtkCellArray> polys;
2221   vtkNew<vtkCellArray> strips;
2222 
2223   output->SetVerts(verts);
2224   output->SetLines(lines);
2225   output->SetPolys(polys);
2226   output->SetStrips(strips);
2227 
2228   // Make sure links are built since link building is not thread safe
2229   input->BuildLinks();
2230 
2231   // Threaded visit of each cell to extract boundary features. Each thread gathers
2232   // output which is then composited into the final vtkPolyData.
2233   // Keep track of each thread's output, we'll need this later for compositing.
2234   ThreadOutputType threads;
2235 
2236   // Perform the threaded boundary cell extraction. This performs some
2237   // initial reduction and allocation of the output. It also computes offets
2238   // and sizes for allocation and writing of data.
2239   ExtractCellBoundaries* extract;
2240   if (this->FastMode)
2241   {
2242     FastExtractUG* ext = new FastExtractUG(input, cellVis, cellGhosts, this->Merging, verts, lines,
2243       polys, strips, this->Degree, input->GetCellLinks(), exc, &threads);
2244     vtkSMPTools::For(0, numCells, *ext);
2245     extract = ext;
2246   }
2247   else // the usual path
2248   {
2249     ExtractUG* ext = new ExtractUG(
2250       input, cellVis, cellGhosts, this->Merging, verts, lines, polys, strips, exc, &threads);
2251 
2252     vtkSMPTools::For(0, numCells, *ext);
2253     extract = ext;
2254   }
2255   numCells = extract->NumCells;
2256 
2257   // If merging points, then it's necessary to allocate the points array,
2258   // configure the point map, and generate the new points. Here we are using
2259   // an explicit point dispatch (i.e., the point representation is explicitly
2260   // represented by a data array as we are processing an unstructured grid).
2261   vtkIdType* ptMap = extract->PointMap;
2262   if (this->Merging)
2263   {
2264     using vtkArrayDispatch::Reals;
2265     using ExpPtsDispatch = vtkArrayDispatch::Dispatch2ByValueType<Reals, Reals>;
2266     ExpPtsWorker compWorker;
2267     if (!ExpPtsDispatch::Execute(
2268           inPts->GetData(), outPts->GetData(), compWorker, numInputPts, inPD, outPD, extract))
2269     { // Fallback to slowpath for other point types
2270       compWorker(inPts->GetData(), outPts->GetData(), numInputPts, inPD, outPD, extract);
2271     }
2272     numOutputPts = compWorker.NumOutputPoints;
2273 
2274     // Generate originating point ids if requested and merging is
2275     // on. (Generating these originating point ids only makes sense if the
2276     // points are merged.)
2277     if (this->PassThroughPointIds)
2278     {
2279       PassPointIds(this->GetOriginalPointIdsName(), numInputPts, numOutputPts, ptMap, outPD);
2280     }
2281   }
2282 
2283   // Finally we can composite the output topology.
2284   ArrayList cellArrays;
2285   outCD->CopyAllocate(inCD, numCells);
2286   cellArrays.AddArrays(numCells, inCD, outCD, 0.0, false);
2287 
2288   CompositeCells compCells(ptMap, &cellArrays, extract, &threads);
2289   vtkSMPTools::For(0, static_cast<vtkIdType>(threads.size()), compCells);
2290 
2291   // Generate originating cell ids if requested.
2292   if (this->PassThroughCellIds)
2293   {
2294     PassCellIds(this->GetOriginalCellIdsName(), extract, &threads, outCD);
2295   }
2296 
2297   vtkDebugMacro(<< "Extracted " << output->GetNumberOfPoints() << " points,"
2298                 << output->GetNumberOfCells() << " cells.");
2299 
2300   // Clean up and get out
2301   delete extract;
2302   return 1;
2303 }
2304 
2305 //------------------------------------------------------------------------------
2306 // Process various types of structured datasets.
StructuredExecute(vtkDataSet * input,vtkPolyData * output,vtkInformation *)2307 int vtkGeometryFilter::StructuredExecute(vtkDataSet* input, vtkPolyData* output, vtkInformation*)
2308 {
2309   return this->StructuredExecute(input, output, nullptr, nullptr);
2310 }
2311 
2312 //------------------------------------------------------------------------------
StructuredExecute(vtkDataSet * input,vtkPolyData * output,vtkInformation *,vtkExcludedFaces * exc)2313 int vtkGeometryFilter::StructuredExecute(
2314   vtkDataSet* input, vtkPolyData* output, vtkInformation*, vtkExcludedFaces* exc)
2315 {
2316   vtkIdType numCells = input->GetNumberOfCells();
2317   vtkIdType i, cellId, ptId;
2318   vtkPointData* inPD = input->GetPointData();
2319   vtkCellData* inCD = input->GetCellData();
2320   vtkPointData* outPD = output->GetPointData();
2321   vtkCellData* outCD = output->GetCellData();
2322 
2323   // Setup processing
2324   bool mergePts = true; // implicit point representations require merging
2325   vtkIdType ext[6];
2326   int* tmpext;
2327   vtkPoints* inPts = nullptr;
2328   switch (input->GetDataObjectType())
2329   {
2330     case VTK_STRUCTURED_GRID:
2331     {
2332       vtkStructuredGrid* grid = vtkStructuredGrid::SafeDownCast(input);
2333       tmpext = grid->GetExtent();
2334       inPts = vtkStructuredGrid::SafeDownCast(input)->GetPoints();
2335       mergePts = this->Merging; // may not be required for explicit
2336       break;
2337     }
2338     case VTK_RECTILINEAR_GRID:
2339     {
2340       vtkRectilinearGrid* grid = vtkRectilinearGrid::SafeDownCast(input);
2341       tmpext = grid->GetExtent();
2342       break;
2343     }
2344     case VTK_UNIFORM_GRID:
2345     case VTK_STRUCTURED_POINTS:
2346     case VTK_IMAGE_DATA:
2347     {
2348       vtkImageData* image = vtkImageData::SafeDownCast(input);
2349       tmpext = image->GetExtent();
2350       break;
2351     }
2352     default:
2353       return 0;
2354   }
2355 
2356   // Update the extent
2357   ext[0] = tmpext[0];
2358   ext[1] = tmpext[1];
2359   ext[2] = tmpext[2];
2360   ext[3] = tmpext[3];
2361   ext[4] = tmpext[4];
2362   ext[5] = tmpext[5];
2363 
2364   // Ghost cells and visibility if necessary
2365   std::unique_ptr<char[]> uCellVis; // reference count to prevent leakage
2366   char* cellVis;
2367   unsigned char* cellGhosts = nullptr;
2368   vtkDataArray* temp = inCD->GetArray(vtkDataSetAttributes::GhostArrayName());
2369   if (inCD)
2370   {
2371     temp = inCD->GetArray(vtkDataSetAttributes::GhostArrayName());
2372   }
2373   if ((!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR) || (temp->GetNumberOfComponents() != 1))
2374   {
2375     vtkDebugMacro("No appropriate ghost levels field available.");
2376   }
2377   else
2378   {
2379     cellGhosts = static_cast<vtkUnsignedCharArray*>(temp)->GetPointer(0);
2380   }
2381 
2382   // Determine nature of what we have to do
2383   if ((!this->CellClipping) && (!this->PointClipping) && (!this->ExtentClipping))
2384   {
2385     cellVis = nullptr;
2386   }
2387   else
2388   {
2389     uCellVis = std::unique_ptr<char[]>(new char[numCells]);
2390     cellVis = uCellVis.get();
2391   }
2392 
2393   // Mark cells as being visible or not
2394   //
2395   if (cellVis)
2396   {
2397     vtkNew<vtkGenericCell> cell;
2398     vtkIdList* ptIds;
2399     for (cellId = 0; cellId < numCells; cellId++)
2400     {
2401       if (this->CellClipping && (cellId < this->CellMinimum || cellId > this->CellMaximum))
2402       {
2403         cellVis[cellId] = 0;
2404       }
2405       else
2406       {
2407         double x[3];
2408         input->GetCell(cellId, cell);
2409         ptIds = cell->GetPointIds();
2410         vtkIdType ncells = ptIds->GetNumberOfIds();
2411         for (i = 0; i < ncells; i++)
2412         {
2413           ptId = ptIds->GetId(i);
2414           input->GetPoint(ptId, x);
2415 
2416           if ((this->PointClipping && (ptId < this->PointMinimum || ptId > this->PointMaximum)) ||
2417             (this->ExtentClipping &&
2418               (x[0] < this->Extent[0] || x[0] > this->Extent[1] || x[1] < this->Extent[2] ||
2419                 x[1] > this->Extent[3] || x[2] < this->Extent[4] || x[2] > this->Extent[5])))
2420           {
2421             cellVis[cellId] = 0;
2422             break;
2423           }
2424         }                // for all points defining the cell
2425         if (i >= ncells) // if no points are clipped
2426         {
2427           cellVis[cellId] = 1;
2428         }
2429       } // check cell clipping first, and then point clipping if necessary
2430     }   // for all cells
2431   }
2432 
2433   // We can now extract the boundary topology. This works for all structured
2434   // types. Here we are only dealing with 3D structured datasets. The 2D cells
2435   // are handled as a general dataset.
2436   vtkNew<vtkCellArray> polys;
2437   output->SetPolys(polys);
2438   ThreadOutputType threads;
2439 
2440   ExtractStructured extStr(input, ext, cellVis, cellGhosts, mergePts, polys, exc, &threads);
2441   vtkSMPTools::For(0, numCells, extStr);
2442   numCells = extStr.NumCells;
2443 
2444   // Generate the output points
2445   vtkIdType numInputPts = input->GetNumberOfPoints(), numOutputPts;
2446   vtkNew<vtkPoints> outPts;
2447   if (this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION && inPts != nullptr)
2448   {
2449     outPts->SetDataType(inPts->GetDataType());
2450   }
2451   else if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION)
2452   {
2453     outPts->SetDataType(VTK_FLOAT);
2454   }
2455   else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
2456   {
2457     outPts->SetDataType(VTK_DOUBLE);
2458   }
2459   if (!mergePts && inPts != nullptr) // no merging, just use input points
2460   {
2461     output->SetPoints(inPts);
2462     outPD->PassData(inPD);
2463   }
2464   else
2465   {
2466     output->SetPoints(outPts);
2467   }
2468 
2469   if (mergePts && inPts != nullptr) // are these explicit points with merging on?
2470   {
2471     using vtkArrayDispatch::Reals;
2472     using ExpPtsDispatch = vtkArrayDispatch::Dispatch2ByValueType<Reals, Reals>;
2473     ExpPtsWorker compWorker;
2474     if (!ExpPtsDispatch::Execute(
2475           inPts->GetData(), outPts->GetData(), compWorker, numInputPts, inPD, outPD, &extStr))
2476     { // Fallback to slowpath for other point types
2477       compWorker(inPts->GetData(), outPts->GetData(), numInputPts, inPD, outPD, &extStr);
2478     }
2479     numOutputPts = compWorker.NumOutputPoints;
2480   }
2481   else // implicit point representation
2482   {
2483     // Some of these datasets have explicit point representations, we'll generate
2484     // the geometry (i.e., points) now.
2485     using vtkArrayDispatch::Reals;
2486     using ImpPtsDispatch = vtkArrayDispatch::DispatchByValueType<Reals>;
2487     ImpPtsWorker compWorker;
2488     if (!ImpPtsDispatch::Execute(
2489           outPts->GetData(), compWorker, input, numInputPts, inPD, outPD, &extStr))
2490     { // Fallback to slowpath for other point types
2491       compWorker(outPts->GetData(), input, numInputPts, inPD, outPD, &extStr);
2492     }
2493     numOutputPts = compWorker.NumOutputPoints;
2494   }
2495 
2496   // Generate originating point ids if requested and merging is
2497   // on. (Generating these originating point ids only makes sense if the
2498   // points are merged.)
2499   vtkIdType* ptMap = extStr.PointMap;
2500   if (this->PassThroughPointIds && (inPts == nullptr || mergePts))
2501   {
2502     PassPointIds(this->GetOriginalPointIdsName(), numInputPts, numOutputPts, ptMap, outPD);
2503   }
2504 
2505   // Finally we can composite the output topology.
2506   ArrayList cellArrays;
2507   outCD->CopyAllocate(inCD, numCells);
2508   cellArrays.AddArrays(numCells, inCD, outCD, 0.0, false);
2509 
2510   CompositeCells compCells(ptMap, &cellArrays, &extStr, &threads);
2511   vtkSMPTools::For(0, static_cast<vtkIdType>(threads.size()), compCells);
2512 
2513   // Generate originating cell ids if requested.
2514   if (this->PassThroughCellIds)
2515   {
2516     PassCellIds(this->GetOriginalCellIdsName(), &extStr, &threads, outCD);
2517   }
2518 
2519   vtkDebugMacro(<< "Extracted " << output->GetNumberOfPoints() << " points,"
2520                 << output->GetNumberOfCells() << " cells.");
2521 
2522   return 1;
2523 }
2524 
2525 //------------------------------------------------------------------------------
DataSetExecute(vtkDataSet * input,vtkPolyData * output)2526 int vtkGeometryFilter::DataSetExecute(vtkDataSet* input, vtkPolyData* output)
2527 {
2528   return this->DataSetExecute(input, output, nullptr);
2529 }
2530 
2531 //------------------------------------------------------------------------------
DataSetExecute(vtkDataSet * input,vtkPolyData * output,vtkExcludedFaces * exc)2532 int vtkGeometryFilter::DataSetExecute(vtkDataSet* input, vtkPolyData* output, vtkExcludedFaces* exc)
2533 {
2534   vtkIdType cellId;
2535   int i;
2536   vtkIdType numCells = input->GetNumberOfCells();
2537   double x[3];
2538   vtkIdType ptId;
2539   vtkPointData* inPD = input->GetPointData();
2540   vtkCellData* inCD = input->GetCellData();
2541   vtkPointData* outPD = output->GetPointData();
2542   vtkCellData* outCD = output->GetCellData();
2543   std::unique_ptr<char[]> uCellVis; // reference count to prevent leakage
2544   char* cellVis;
2545   unsigned char* cellGhosts = nullptr;
2546 
2547   vtkDebugMacro(<< "Executing geometry filter");
2548 
2549   if (numCells == 0)
2550   {
2551     vtkDebugMacro(<< "Number of cells is zero, no data to process.");
2552     return 1;
2553   }
2554 
2555   // Ghost cells if necessary
2556   vtkDataArray* temp = inCD->GetArray(vtkDataSetAttributes::GhostArrayName());
2557   if (inCD)
2558   {
2559     temp = inCD->GetArray(vtkDataSetAttributes::GhostArrayName());
2560   }
2561   if ((!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR) || (temp->GetNumberOfComponents() != 1))
2562   {
2563     vtkDebugMacro("No appropriate ghost levels field available.");
2564   }
2565   else
2566   {
2567     cellGhosts = static_cast<vtkUnsignedCharArray*>(temp)->GetPointer(0);
2568   }
2569 
2570   // Determine nature of what we have to do
2571   if ((!this->CellClipping) && (!this->PointClipping) && (!this->ExtentClipping))
2572   {
2573     cellVis = nullptr;
2574   }
2575   else
2576   {
2577     uCellVis = std::unique_ptr<char[]>(new char[numCells]);
2578     cellVis = uCellVis.get();
2579   }
2580 
2581   // Mark cells as being visible or not
2582   //
2583   if (cellVis)
2584   {
2585     vtkNew<vtkGenericCell> cell;
2586     vtkIdList* ptIds;
2587     for (cellId = 0; cellId < numCells; cellId++)
2588     {
2589       if (this->CellClipping && (cellId < this->CellMinimum || cellId > this->CellMaximum))
2590       {
2591         cellVis[cellId] = 0;
2592       }
2593       else
2594       {
2595         input->GetCell(cellId, cell);
2596         ptIds = cell->GetPointIds();
2597         for (i = 0; i < ptIds->GetNumberOfIds(); i++)
2598         {
2599           ptId = ptIds->GetId(i);
2600           input->GetPoint(ptId, x);
2601 
2602           if ((this->PointClipping && (ptId < this->PointMinimum || ptId > this->PointMaximum)) ||
2603             (this->ExtentClipping &&
2604               (x[0] < this->Extent[0] || x[0] > this->Extent[1] || x[1] < this->Extent[2] ||
2605                 x[1] > this->Extent[3] || x[2] < this->Extent[4] || x[2] > this->Extent[5])))
2606           {
2607             cellVis[cellId] = 0;
2608             break;
2609           }
2610         }
2611         if (i >= ptIds->GetNumberOfIds())
2612         {
2613           cellVis[cellId] = 1;
2614         }
2615       }
2616     }
2617   }
2618 
2619   // Create new output points. In a dataset, points are assumed to be
2620   // implicitly represented, so merging must occur,
2621   vtkNew<vtkPoints> outPts;
2622   if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION ||
2623     this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION)
2624   {
2625     outPts->SetDataType(VTK_FLOAT);
2626   }
2627   else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
2628   {
2629     outPts->SetDataType(VTK_DOUBLE);
2630   }
2631   output->SetPoints(outPts);
2632 
2633   vtkNew<vtkCellArray> verts;
2634   vtkNew<vtkCellArray> lines;
2635   vtkNew<vtkCellArray> polys;
2636   vtkNew<vtkCellArray> strips;
2637 
2638   output->SetVerts(verts);
2639   output->SetLines(lines);
2640   output->SetPolys(polys);
2641   output->SetStrips(strips);
2642 
2643   outPD->CopyGlobalIdsOn();
2644   outCD->CopyGlobalIdsOn();
2645 
2646   // The extraction process for vtkDataSet
2647   ThreadOutputType threads;
2648   ExtractDS extract(input, cellVis, cellGhosts, verts, lines, polys, strips, exc, &threads);
2649 
2650   vtkSMPTools::For(0, numCells, extract);
2651   numCells = extract.NumCells;
2652 
2653   // If merging points, then it's necessary to allocate the points
2654   // array. This will be populated later when the final compositing
2655   // occurs.
2656   vtkIdType numInputPts = input->GetNumberOfPoints(), numOutputPts;
2657 
2658   // Generate the new points
2659   using vtkArrayDispatch::Reals;
2660   using ImpPtsDispatch = vtkArrayDispatch::DispatchByValueType<Reals>;
2661   ImpPtsWorker compWorker;
2662   if (!ImpPtsDispatch::Execute(
2663         outPts->GetData(), compWorker, input, numInputPts, inPD, outPD, &extract))
2664   { // Fallback to slowpath for other point types
2665     compWorker(outPts->GetData(), input, numInputPts, inPD, outPD, &extract);
2666   }
2667   numOutputPts = compWorker.NumOutputPoints;
2668 
2669   // Generate originating point ids if requested and merging is
2670   // on. (Generating these originating point ids only makes sense if the
2671   // points are merged.)
2672   vtkIdType* ptMap = extract.PointMap;
2673   if (this->PassThroughPointIds)
2674   {
2675     PassPointIds(this->GetOriginalPointIdsName(), numInputPts, numOutputPts, ptMap, outPD);
2676   }
2677 
2678   // Finally we can composite the output topology.
2679   ArrayList cellArrays;
2680   outCD->CopyAllocate(inCD, numCells);
2681   cellArrays.AddArrays(numCells, inCD, outCD, 0.0, false);
2682 
2683   CompositeCells compCells(ptMap, &cellArrays, &extract, &threads);
2684   vtkSMPTools::For(0, static_cast<vtkIdType>(threads.size()), compCells);
2685 
2686   // Generate originating cell ids if requested.
2687   if (this->PassThroughCellIds)
2688   {
2689     PassCellIds(this->GetOriginalCellIdsName(), &extract, &threads, outCD);
2690   }
2691 
2692   vtkDebugMacro(<< "Extracted " << output->GetNumberOfPoints() << " points,"
2693                 << output->GetNumberOfCells() << " cells.");
2694 
2695   return 1;
2696 }
2697 
2698 //------------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)2699 int vtkGeometryFilter::RequestUpdateExtent(vtkInformation* vtkNotUsed(request),
2700   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
2701 {
2702   // get the info objects
2703   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
2704   vtkInformation* outInfo = outputVector->GetInformationObject(0);
2705 
2706   int piece, numPieces, ghostLevels;
2707 
2708   piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
2709   numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
2710   ghostLevels = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS());
2711 
2712   if (numPieces > 1)
2713   {
2714     ++ghostLevels;
2715   }
2716 
2717   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), piece);
2718   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), numPieces);
2719   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), ghostLevels);
2720   inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
2721 
2722   return 1;
2723 }
2724