1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkMergeCells.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 /*----------------------------------------------------------------------------
16 Copyright (c) Sandia Corporation
17 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19
20 #include "vtkMergeCells.h"
21
22 #include "vtkArrayDispatch.h"
23 #include "vtkCell.h"
24 #include "vtkCellArray.h"
25 #include "vtkCellData.h"
26 #include "vtkDataArray.h"
27 #include "vtkDataArrayRange.h"
28 #include "vtkIdTypeArray.h"
29 #include "vtkKdTree.h"
30 #include "vtkMergePoints.h"
31 #include "vtkNew.h"
32 #include "vtkObjectFactory.h"
33 #include "vtkPointData.h"
34 #include "vtkPoints.h"
35 #include "vtkSmartPointer.h"
36 #include "vtkUnsignedCharArray.h"
37 #include "vtkUnstructuredGrid.h"
38
39 #include <algorithm>
40 #include <cstdlib>
41 #include <map>
42
43 namespace
44 {
45
46 // use a fast path for 32/64 bit signed/unsigned ints as global ids:
47 using GIDFastTypes = vtkTypeList::Create<vtkTypeInt64, vtkTypeInt32, vtkTypeUInt64, vtkTypeUInt32>;
48 using IdDispatcher = vtkArrayDispatch::DispatchByValueType<GIDFastTypes>;
49
50 } // end anon namespace
51
52 vtkStandardNewMacro(vtkMergeCells);
53
54 vtkCxxSetObjectMacro(vtkMergeCells, UnstructuredGrid, vtkUnstructuredGrid);
55
56 class vtkMergeCellsSTLCloak
57 {
58 public:
59 std::map<vtkIdType, vtkIdType> IdTypeMap;
60 };
61
62 //------------------------------------------------------------------------------
vtkMergeCells()63 vtkMergeCells::vtkMergeCells()
64 {
65 this->TotalNumberOfDataSets = 0;
66 this->TotalNumberOfCells = 0;
67 this->TotalNumberOfPoints = 0;
68
69 this->NumberOfCells = 0;
70 this->NumberOfPoints = 0;
71
72 this->PointMergeTolerance = 10e-4;
73 this->MergeDuplicatePoints = true;
74
75 this->InputIsUGrid = false;
76 this->InputIsPointSet = false;
77
78 this->PointList = nullptr;
79 this->CellList = nullptr;
80
81 this->UnstructuredGrid = nullptr;
82
83 this->GlobalIdMap = new vtkMergeCellsSTLCloak;
84 this->GlobalCellIdMap = new vtkMergeCellsSTLCloak;
85
86 this->UseGlobalIds = 0;
87 this->UseGlobalCellIds = 0;
88
89 this->NextGrid = 0;
90 }
91
92 //------------------------------------------------------------------------------
~vtkMergeCells()93 vtkMergeCells::~vtkMergeCells()
94 {
95 this->FreeLists();
96
97 delete this->GlobalIdMap;
98 delete this->GlobalCellIdMap;
99
100 this->SetUnstructuredGrid(nullptr);
101 }
102
103 //------------------------------------------------------------------------------
FreeLists()104 void vtkMergeCells::FreeLists()
105 {
106 delete this->PointList;
107 this->PointList = nullptr;
108
109 delete this->CellList;
110 this->CellList = nullptr;
111 }
112
113 //------------------------------------------------------------------------------
MergeDataSet(vtkDataSet * set)114 int vtkMergeCells::MergeDataSet(vtkDataSet* set)
115 {
116 vtkUnstructuredGrid* grid = this->UnstructuredGrid;
117
118 if (!grid)
119 {
120 vtkErrorMacro(<< "SetUnstructuredGrid first");
121 return -1;
122 }
123
124 if (this->TotalNumberOfDataSets <= 0)
125 {
126 // TotalNumberOfCells and TotalNumberOfPoints may both be zero
127 // if all data sets to be merged are empty
128
129 vtkErrorMacro(<< "Must SetTotalNumberOfCells, SetTotalNumberOfPoints and "
130 "SetTotalNumberOfDataSets (upper bounds at least)"
131 " before starting to MergeDataSets");
132
133 return -1;
134 }
135
136 vtkPointData* pointArrays = set->GetPointData();
137 vtkCellData* cellArrays = set->GetCellData();
138
139 // Since vtkMergeCells is to be used only on distributed vtkDataSets,
140 // each DataSet should have the same field arrays. However the field arrays
141 // may get rearranged in the process of Marshalling/UnMarshalling.
142 // So we use a vtkDataSetAttributes::FieldList to ensure the field arrays are
143 // merged in the right order.
144 if (grid->GetNumberOfCells() == 0)
145 {
146 this->InputIsPointSet = vtkPointSet::SafeDownCast(set) ? 1 : 0;
147 this->InputIsUGrid = vtkUnstructuredGrid::SafeDownCast(set) ? 1 : 0;
148 this->StartUGrid(set);
149 }
150 else
151 {
152 this->PointList->IntersectFieldList(pointArrays);
153 this->CellList->IntersectFieldList(cellArrays);
154 }
155
156 vtkIdType numPoints = set->GetNumberOfPoints();
157 vtkIdType numCells = set->GetNumberOfCells();
158
159 if (numCells == 0)
160 {
161 return 0;
162 }
163
164 vtkIdType* idMap = nullptr;
165 if (this->MergeDuplicatePoints)
166 {
167 if (this->UseGlobalIds) // faster by far
168 {
169 // Note: It has been observed that an input dataset may
170 // have an invalid global ID array. Using the array to
171 // merge points results in bad geometry. It may be
172 // worthwhile to do a quick sanity check when merging
173 // points. Downside is that will slow down this filter.
174
175 idMap = this->MapPointsToIdsUsingGlobalIds(set);
176 }
177 else
178 {
179 idMap = this->MapPointsToIdsUsingLocator(set);
180 }
181 }
182
183 vtkIdType nextPt = this->NumberOfPoints;
184 vtkPoints* pts = grid->GetPoints();
185
186 for (vtkIdType oldPtId = 0; oldPtId < numPoints; oldPtId++)
187 {
188 vtkIdType newPtId = idMap ? idMap[oldPtId] : nextPt;
189
190 if (newPtId == nextPt)
191 {
192 pts->SetPoint(nextPt, set->GetPoint(oldPtId));
193 grid->GetPointData()->CopyData(
194 *this->PointList, pointArrays, this->NextGrid, oldPtId, nextPt);
195 nextPt++;
196 }
197 }
198
199 pts->Modified(); // so that subsequent GetBounds will be correct
200
201 vtkIdType newCellId = this->InputIsUGrid ? this->AddNewCellsUnstructuredGrid(set, idMap)
202 : this->AddNewCellsDataSet(set, idMap);
203
204 delete[] idMap;
205
206 this->NumberOfPoints = nextPt;
207 this->NumberOfCells = newCellId;
208
209 this->NextGrid++;
210
211 return 0;
212 }
213
214 namespace
215 {
216
217 struct ProcessCellGIDsDataSet
218 {
219 // Pass in the gids to do duplicate checking, otherwise use other overload:
220 template <typename GIDArrayT>
operator ()__anonff1779950211::ProcessCellGIDsDataSet221 void operator()(GIDArrayT* gidArray, std::map<vtkIdType, vtkIdType>& gidMap)
222 {
223 vtkIdType nextCellId = static_cast<vtkIdType>(gidMap.size());
224
225 const auto gids = vtk::DataArrayValueRange<1>(gidArray);
226 for (vtkIdType oldCellId = 0; oldCellId < gids.size(); oldCellId++)
227 {
228 vtkIdType globalId = static_cast<vtkIdType>(gids[oldCellId]);
229
230 auto inserted = gidMap.insert(std::make_pair(globalId, nextCellId));
231
232 if (inserted.second)
233 {
234 nextCellId++;
235 }
236 }
237 }
238 };
239
240 } // end anon namespace
241
242 //------------------------------------------------------------------------------
AddNewCellsDataSet(vtkDataSet * set,vtkIdType * idMap)243 vtkIdType vtkMergeCells::AddNewCellsDataSet(vtkDataSet* set, vtkIdType* idMap)
244 {
245 vtkUnstructuredGrid* grid = this->UnstructuredGrid;
246 const vtkIdType numCells = set->GetNumberOfCells();
247
248 vtkDataArray* gidArray = this->UseGlobalIds ? set->GetCellData()->GetGlobalIds() : nullptr;
249
250 if (gidArray)
251 { // Use duplicate matching:
252 ProcessCellGIDsDataSet worker;
253 if (!IdDispatcher::Execute(gidArray, worker, this->GlobalCellIdMap->IdTypeMap))
254 { // fallback for weird types:
255 worker(gidArray, this->GlobalCellIdMap->IdTypeMap);
256 }
257 }
258
259 vtkCellData* gridCD = grid->GetCellData();
260 vtkCellData* setCD = set->GetCellData();
261
262 vtkNew<vtkIdList> cellPoints;
263 cellPoints->Allocate(VTK_CELL_SIZE);
264
265 for (vtkIdType oldCellId = 0; oldCellId < numCells; oldCellId++)
266 {
267 set->GetCellPoints(oldCellId, cellPoints);
268 for (vtkIdType pid = 0; pid < cellPoints->GetNumberOfIds(); ++pid)
269 {
270 const vtkIdType oldPtId = cellPoints->GetId(pid);
271 const vtkIdType newPtId = idMap ? idMap[oldPtId] : this->NumberOfPoints + oldPtId;
272 cellPoints->SetId(pid, newPtId);
273 }
274
275 const vtkIdType newCellId = grid->InsertNextCell(set->GetCellType(oldCellId), cellPoints);
276
277 gridCD->CopyData(*this->CellList, setCD, this->NextGrid, oldCellId, newCellId);
278 }
279
280 return grid->GetNumberOfCells() - 1;
281 }
282
283 namespace
284 {
285
286 struct ProcessCellGIDsUG
287 {
288 template <typename GIDArrayT>
operator ()__anonff1779950311::ProcessCellGIDsUG289 void operator()(GIDArrayT* gidArray, vtkCellArray* newCells, vtkIdList*& duplicateCellIds,
290 vtkIdType& numDuplicateCells, vtkIdType& numDuplicateConnections,
291 std::map<vtkIdType, vtkIdType>& gidMap)
292 {
293 const auto gids = vtk::DataArrayValueRange<1>(gidArray);
294
295 vtkIdType nextLocalId = static_cast<vtkIdType>(gidMap.size());
296
297 duplicateCellIds = vtkIdList::New();
298
299 for (vtkIdType cid = 0; cid < gids.size(); cid++)
300 {
301 vtkIdType globalId = static_cast<vtkIdType>(gids[cid]);
302
303 auto inserted = gidMap.insert(std::make_pair(globalId, nextLocalId));
304 if (inserted.second)
305 {
306 nextLocalId++;
307 }
308 else
309 {
310 duplicateCellIds->InsertNextId(cid);
311 numDuplicateCells++;
312 numDuplicateConnections += newCells->GetCellSize(cid);
313 }
314 }
315
316 if (numDuplicateCells == 0)
317 {
318 duplicateCellIds->Delete();
319 duplicateCellIds = nullptr;
320 }
321 }
322 };
323
324 } // end anon namespace
325
326 //------------------------------------------------------------------------------
AddNewCellsUnstructuredGrid(vtkDataSet * set,vtkIdType * idMap)327 vtkIdType vtkMergeCells::AddNewCellsUnstructuredGrid(vtkDataSet* set, vtkIdType* idMap)
328 {
329 bool firstSet = (this->NextGrid == 0);
330
331 vtkUnstructuredGrid* newGrid = vtkUnstructuredGrid::SafeDownCast(set);
332 vtkUnstructuredGrid* grid = this->UnstructuredGrid;
333
334 // Connectivity information for the new data set
335 vtkCellArray* newCells = newGrid->GetCells();
336 vtkIdType newNumCells = newCells->GetNumberOfCells();
337 vtkIdType newNumConnections = newCells->GetNumberOfConnectivityIds();
338
339 // If we are checking for duplicate cells, create a list now of
340 // any cells in the new data set that we already have.
341 vtkIdList* duplicateCellIds = nullptr;
342 vtkIdType numDuplicateCells = 0;
343 vtkIdType numDuplicateConnections = 0;
344
345 if (this->UseGlobalCellIds)
346 {
347 vtkDataArray* gidArray = set->GetCellData()->GetGlobalIds();
348 if (gidArray)
349 {
350 ProcessCellGIDsUG worker;
351 if (!IdDispatcher::Execute(gidArray, worker, newCells, duplicateCellIds, numDuplicateCells,
352 numDuplicateConnections, this->GlobalCellIdMap->IdTypeMap))
353 { // fallback for weird types:
354 worker(gidArray, newCells, duplicateCellIds, numDuplicateCells, numDuplicateConnections,
355 this->GlobalCellIdMap->IdTypeMap);
356 }
357 }
358 }
359
360 // Connectivity for the merged grid so far
361
362 vtkCellArray* cellArray = nullptr;
363 vtkIdType* flocs = nullptr;
364 vtkIdType* faces = nullptr;
365 unsigned char* types = nullptr;
366
367 vtkIdType numCells = 0;
368 vtkIdType numConnections = 0;
369 vtkIdType numFacesConnections = 0;
370
371 if (!firstSet)
372 {
373 cellArray = grid->GetCells();
374 types = grid->GetCellTypesArray()->GetPointer(0);
375 flocs = grid->GetFaceLocations() ? grid->GetFaceLocations()->GetPointer(0) : nullptr;
376 faces = grid->GetFaces() ? grid->GetFaces()->GetPointer(0) : nullptr;
377
378 numCells = cellArray->GetNumberOfCells();
379 numConnections = cellArray->GetNumberOfConnectivityIds();
380 numFacesConnections = faces ? grid->GetFaces()->GetNumberOfValues() : 0;
381 }
382
383 // New output grid: merging of existing and incoming grids
384
385 // CELL ARRAY
386 vtkIdType totalNumCells = numCells + newNumCells - numDuplicateCells;
387 vtkIdType totalNumConnections = numConnections + newNumConnections - numDuplicateConnections;
388
389 vtkNew<vtkCellArray> finalCellArray;
390 finalCellArray->AllocateExact(totalNumCells, totalNumConnections);
391
392 if (!firstSet && cellArray)
393 {
394 finalCellArray->Append(cellArray, 0);
395 }
396
397 // TYPE ARRAY
398 vtkNew<vtkUnsignedCharArray> typeArray;
399 typeArray->SetNumberOfValues(totalNumCells);
400 if (!firstSet && types)
401 {
402 unsigned char* cptr = typeArray->GetPointer(0);
403 memcpy(cptr, types, numCells * sizeof(unsigned char));
404 }
405
406 // FACES LOCATION ARRAY
407 vtkNew<vtkIdTypeArray> facesLocationArray;
408 facesLocationArray->SetNumberOfValues(totalNumCells);
409 if (!firstSet && flocs)
410 {
411 vtkIdType* fiptr = facesLocationArray->GetPointer(0); // new output dataset
412 memcpy(fiptr, flocs, numCells * sizeof(vtkIdType)); // existing set
413 }
414 else if (!firstSet)
415 {
416 facesLocationArray->FillComponent(0, -1);
417 }
418
419 bool havePolyhedron = false;
420
421 // FACES ARRAY
422 vtkNew<vtkIdTypeArray> facesArray;
423 facesArray->SetNumberOfValues(numFacesConnections);
424 if (!firstSet && faces)
425 {
426 havePolyhedron = true;
427 vtkIdType* faptr = facesArray->GetPointer(0); // new output dataset
428 memcpy(faptr, faces, numFacesConnections * sizeof(vtkIdType)); // existing set
429 }
430
431 // set up new cell data
432
433 vtkIdType finalCellId = numCells;
434 vtkCellData* cellArrays = set->GetCellData();
435
436 vtkIdType oldPtId, finalPtId, nextDuplicateCellId = 0;
437
438 for (vtkIdType oldCellId = 0; oldCellId < newNumCells; oldCellId++)
439 {
440 if (duplicateCellIds && nextDuplicateCellId < duplicateCellIds->GetNumberOfIds())
441 {
442 vtkIdType skipId = duplicateCellIds->GetId(nextDuplicateCellId);
443 if (skipId == oldCellId)
444 {
445 nextDuplicateCellId++;
446 continue;
447 }
448 }
449
450 vtkIdType npts;
451 const vtkIdType* pts;
452 newGrid->GetCellPoints(oldCellId, npts, pts);
453
454 finalCellArray->InsertNextCell(static_cast<int>(npts));
455 unsigned char cellType = newGrid->GetCellType(oldCellId);
456 typeArray->SetValue(finalCellId, cellType);
457
458 for (vtkIdType i = 0; i < npts; i++)
459 {
460 oldPtId = pts[i];
461 finalPtId = idMap ? idMap[oldPtId] : this->NumberOfPoints + oldPtId;
462 finalCellArray->InsertCellPoint(finalPtId);
463 }
464
465 if (cellType == VTK_POLYHEDRON)
466 {
467 havePolyhedron = true;
468 vtkIdType nfaces;
469 const vtkIdType* ptIds;
470 newGrid->GetFaceStream(oldCellId, nfaces, ptIds);
471
472 facesLocationArray->SetValue(finalCellId, facesArray->GetNumberOfValues());
473 facesArray->InsertNextValue(nfaces);
474
475 for (vtkIdType i = 0; i < nfaces; i++)
476 {
477 vtkIdType nfpts = *ptIds++;
478 facesArray->InsertNextValue(nfpts);
479 for (vtkIdType j = 0; j < nfpts; j++)
480 {
481 oldPtId = *ptIds++;
482 finalPtId = idMap ? idMap[oldPtId] : this->NumberOfPoints + oldPtId;
483 facesArray->InsertNextValue(finalPtId);
484 }
485 }
486 }
487 else
488 {
489 facesLocationArray->SetValue(finalCellId, -1);
490 }
491
492 grid->GetCellData()->CopyData(
493 *(this->CellList), cellArrays, this->NextGrid, oldCellId, finalCellId);
494
495 finalCellId++;
496 }
497
498 if (havePolyhedron)
499 {
500 grid->SetCells(typeArray, finalCellArray, facesLocationArray, facesArray);
501 }
502 else
503 {
504 grid->SetCells(typeArray, finalCellArray, nullptr, nullptr);
505 }
506
507 if (duplicateCellIds)
508 {
509 duplicateCellIds->Delete();
510 }
511
512 return finalCellId;
513 }
514
515 //------------------------------------------------------------------------------
StartUGrid(vtkDataSet * set)516 void vtkMergeCells::StartUGrid(vtkDataSet* set)
517 {
518 vtkUnstructuredGrid* grid = this->UnstructuredGrid;
519
520 if (!this->InputIsUGrid)
521 {
522 grid->Allocate(this->TotalNumberOfCells);
523 }
524
525 vtkNew<vtkPoints> pts;
526 // If the input has a vtkPoints object, we'll make the merged output
527 // grid have a vtkPoints object of the same data type. Otherwise,
528 // the merged output grid will have the default of points of type float.
529 if (this->InputIsPointSet)
530 {
531 vtkPointSet* ps = vtkPointSet::SafeDownCast(set);
532 pts->SetDataType(ps->GetPoints()->GetDataType());
533 }
534 pts->SetNumberOfPoints(this->TotalNumberOfPoints); // allocate for upper bound
535 grid->SetPoints(pts);
536
537 // Order of field arrays may get changed when data sets are
538 // marshalled/sent/unmarshalled. So we need to re-index the
539 // field arrays before copying them using a FieldList
540 this->PointList = new vtkDataSetAttributes::FieldList(this->TotalNumberOfDataSets);
541 this->CellList = new vtkDataSetAttributes::FieldList(this->TotalNumberOfDataSets);
542
543 this->PointList->InitializeFieldList(set->GetPointData());
544 this->CellList->InitializeFieldList(set->GetCellData());
545
546 if (this->UseGlobalIds)
547 {
548 grid->GetPointData()->CopyGlobalIdsOn();
549 }
550 grid->GetPointData()->CopyAllocate(*this->PointList, this->TotalNumberOfPoints);
551
552 if (this->UseGlobalCellIds)
553 {
554 grid->GetCellData()->CopyGlobalIdsOn();
555 }
556 grid->GetCellData()->CopyAllocate(*this->CellList, this->TotalNumberOfCells);
557 }
558
559 //------------------------------------------------------------------------------
Finish()560 void vtkMergeCells::Finish()
561 {
562 this->FreeLists();
563
564 vtkUnstructuredGrid* grid = this->UnstructuredGrid;
565
566 if (this->NumberOfPoints < this->TotalNumberOfPoints)
567 {
568 // if we don't do this, grid->GetNumberOfPoints() gives the wrong value
569 grid->GetPoints()->GetData()->Resize(this->NumberOfPoints);
570 }
571
572 grid->Squeeze();
573 }
574
575 namespace
576 {
577
578 struct MapPointsUsingGIDsWorker
579 {
580 template <typename GIDArrayType>
operator ()__anonff1779950411::MapPointsUsingGIDsWorker581 void operator()(
582 GIDArrayType* gidArray, std::map<vtkIdType, vtkIdType>& globalIdMap, vtkIdType* idMap)
583 {
584 const auto gids = vtk::DataArrayValueRange<1>(gidArray);
585
586 vtkIdType nextNewLocalId = static_cast<vtkIdType>(globalIdMap.size());
587 for (vtkIdType oldId = 0; oldId < gids.size(); ++oldId)
588 {
589 vtkIdType globalId = static_cast<vtkIdType>(gids[oldId]);
590
591 auto inserted = globalIdMap.insert(std::make_pair(globalId, nextNewLocalId));
592
593 if (inserted.second)
594 { // This is a new global node id
595 idMap[oldId] = nextNewLocalId;
596 nextNewLocalId++;
597 }
598 else
599 { // A repeat; it was not inserted
600 idMap[oldId] = inserted.first->second;
601 }
602 }
603 }
604 };
605
606 } // end anon namespace
607
608 //------------------------------------------------------------------------------
609 // Use an array of global node ids to map all points to
610 // their new ids in the merged grid.
MapPointsToIdsUsingGlobalIds(vtkDataSet * set)611 vtkIdType* vtkMergeCells::MapPointsToIdsUsingGlobalIds(vtkDataSet* set)
612 {
613 vtkDataArray* globalIdArray = set->GetPointData()->GetGlobalIds();
614 if (!this->UseGlobalIds || !globalIdArray)
615 {
616 vtkErrorMacro("global id array is not available");
617 return nullptr;
618 }
619
620 vtkIdType npoints = set->GetNumberOfPoints();
621 vtkIdType* idMap = new vtkIdType[static_cast<std::size_t>(npoints)];
622 auto& gidMap = this->GlobalIdMap->IdTypeMap;
623
624 MapPointsUsingGIDsWorker worker;
625
626 if (!IdDispatcher::Execute(globalIdArray, worker, gidMap, idMap))
627 { // fallback to slow path for other value types:
628 worker(globalIdArray, gidMap, idMap);
629 }
630
631 return idMap;
632 }
633
634 //------------------------------------------------------------------------------
635 // Use a spatial locator to filter out duplicate points and map
636 // the new ids to their ids in the merged grid.
MapPointsToIdsUsingLocator(vtkDataSet * set)637 vtkIdType* vtkMergeCells::MapPointsToIdsUsingLocator(vtkDataSet* set)
638 {
639 vtkUnstructuredGrid* grid = this->UnstructuredGrid;
640 vtkPoints* points0 = grid->GetPoints();
641 vtkIdType npoints0 = this->NumberOfPoints;
642
643 vtkPointSet* ps = vtkPointSet::SafeDownCast(set);
644 vtkIdType npoints1 = set->GetNumberOfPoints();
645 vtkSmartPointer<vtkPoints> points1;
646
647 if (ps)
648 {
649 points1 = ps->GetPoints();
650 }
651 else
652 {
653 points1 = vtkSmartPointer<vtkPoints>::New();
654 points1->SetNumberOfPoints(npoints1);
655
656 for (vtkIdType ptId = 0; ptId < npoints1; ptId++)
657 {
658 points1->SetPoint(ptId, set->GetPoint(ptId));
659 }
660 }
661
662 vtkIdType* idMap = new vtkIdType[npoints1];
663
664 double bounds[6];
665 set->GetBounds(bounds);
666 if (npoints0 > 0)
667 {
668 double tmpBounds[6];
669
670 // Prior to MapPointsToIdsUsingLocator(), points0->SetNumberOfPoints()
671 // has been called to set the number of points to the upper bound on the
672 // points TO BE merged and now points0->GetNumberOfPoints() does not
673 // refer to the number of the points merged so far. Thus we need to
674 // temporarily set the number to the latter such that grid->GetBounds()
675 // is able to return the correct bounding information. This is a fix to
676 // bug #0009626.
677 points0->GetData()->SetNumberOfTuples(npoints0);
678 grid->GetBounds(tmpBounds); // safe to call GetBounds() for real info
679 points0->GetData()->SetNumberOfTuples(this->TotalNumberOfPoints);
680
681 bounds[0] = ((tmpBounds[0] < bounds[0]) ? tmpBounds[0] : bounds[0]);
682 bounds[2] = ((tmpBounds[2] < bounds[2]) ? tmpBounds[2] : bounds[2]);
683 bounds[4] = ((tmpBounds[4] < bounds[4]) ? tmpBounds[4] : bounds[4]);
684
685 bounds[1] = ((tmpBounds[1] > bounds[1]) ? tmpBounds[1] : bounds[1]);
686 bounds[3] = ((tmpBounds[3] > bounds[3]) ? tmpBounds[3] : bounds[3]);
687 bounds[5] = ((tmpBounds[5] > bounds[5]) ? tmpBounds[5] : bounds[5]);
688 }
689 if (!this->Locator)
690 {
691 vtkNew<vtkPoints> ptarray;
692 if (this->PointMergeTolerance == 0.0)
693 {
694 // testing shows vtkMergePoints is fastest when tolerance is 0
695 this->Locator = vtkSmartPointer<vtkMergePoints>::New();
696 }
697 else
698 {
699 // vtkPointLocator allows to merge duplicated points within a given tolerance
700 this->Locator = vtkSmartPointer<vtkPointLocator>::New();
701 this->Locator->SetTolerance(this->PointMergeTolerance);
702 }
703 // Set the desired precision for the points in the output.
704 if (this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION)
705 {
706 // The logical behaviour would be to use the data type from the input.
707 // However, input is a vtkDataSet, which has no point data type; only the
708 // derived class vtkPointSet has a vtkPoints attribute, so only for that
709 // the logical practice can be applied, while for others (currently
710 // vtkImageData and vtkRectilinearGrid) the data type is the default
711 // for vtkPoints - which is VTK_FLOAT.
712 if (ps)
713 {
714 ptarray->SetDataType(ps->GetPoints()->GetDataType());
715 }
716 }
717 else if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION)
718 {
719 ptarray->SetDataType(VTK_FLOAT);
720 }
721 else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
722 {
723 ptarray->SetDataType(VTK_DOUBLE);
724 }
725 // Init the vtkPointLocator object
726 this->Locator->InitPointInsertion(ptarray, bounds);
727 }
728
729 vtkIdType newId;
730 double x[3];
731
732 for (vtkIdType ptId = 0; ptId < npoints1; ptId++)
733 {
734 points1->GetPoint(ptId, x);
735 this->Locator->InsertUniquePoint(x, newId);
736 idMap[ptId] = newId;
737 }
738 return idMap;
739 }
740
741 //------------------------------------------------------------------------------
InvalidateCachedLocator()742 void vtkMergeCells::InvalidateCachedLocator()
743 {
744 this->Locator = nullptr;
745 }
746
747 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)748 void vtkMergeCells::PrintSelf(ostream& os, vtkIndent indent)
749 {
750 this->Superclass::PrintSelf(os, indent);
751
752 os << indent << "TotalNumberOfDataSets: " << this->TotalNumberOfDataSets << endl;
753 os << indent << "TotalNumberOfCells: " << this->TotalNumberOfCells << endl;
754 os << indent << "TotalNumberOfPoints: " << this->TotalNumberOfPoints << endl;
755
756 os << indent << "NumberOfCells: " << this->NumberOfCells << endl;
757 os << indent << "NumberOfPoints: " << this->NumberOfPoints << endl;
758
759 os << indent << "GlobalIdMap: " << this->GlobalIdMap->IdTypeMap.size() << endl;
760 os << indent << "GlobalCellIdMap: " << this->GlobalCellIdMap->IdTypeMap.size() << endl;
761
762 os << indent << "OutputPointsPrecision" << this->OutputPointsPrecision << endl;
763
764 os << indent << "PointMergeTolerance: " << this->PointMergeTolerance << endl;
765 os << indent << "MergeDuplicatePoints: " << this->MergeDuplicatePoints << endl;
766 os << indent << "InputIsUGrid: " << this->InputIsUGrid << endl;
767 os << indent << "InputIsPointSet: " << this->InputIsPointSet << endl;
768 os << indent << "UnstructuredGrid: " << this->UnstructuredGrid << endl;
769 os << indent << "PointList: " << this->PointList << endl;
770 os << indent << "CellList: " << this->CellList << endl;
771 os << indent << "UseGlobalIds: " << this->UseGlobalIds << endl;
772 os << indent << "UseGlobalCellIds: " << this->UseGlobalCellIds << endl;
773 os << indent << "Locator:";
774 if (this->Locator)
775 {
776 os << "\n";
777 this->Locator->PrintSelf(os, indent.GetNextIndent());
778 }
779 else
780 {
781 os << "(None)" << endl;
782 }
783 }
784