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