VTK  9.6.20260102
vtkStaticPointLocatorPrivate.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-FileCopyrightText: Copyright 2011 Sandia Corporation
3// SPDX-License-Identifier: LicenseRef-BSD-3-Clause-Sandia-USGov
12
13#ifndef vtkStaticPointLocatorPrivate_h
14#define vtkStaticPointLocatorPrivate_h
15
16#include "vtkArrayDispatch.h"
18#include "vtkCellArray.h"
19#include "vtkDataArrayRange.h"
20#include "vtkDataSet.h"
21#include "vtkDoubleArray.h"
22#include "vtkMath.h"
23#include "vtkPoints.h"
24#include "vtkSMPThreadLocal.h"
26#include "vtkSMPTools.h"
28#include "vtkStructuredData.h"
29
30VTK_ABI_NAMESPACE_BEGIN
31
32//------------------------------------------------------------------------------
33// The following code supports threaded point locator construction. The locator
34// is assumed to be constructed once (i.e., it does not allow incremental point
35// insertion). The algorithm proceeds in three steps:
36// 1) All points are assigned a bucket index (combined i-j-k bucket location).
37// The index is computed in parallel. This requires a one time allocation of an
38// index array (which is also associated with the originating point ids).
39// 2) vtkSMPTools::Sort() is used to sort the index array. Note that the sort
40// carries along the point ids as well. This creates contiguous runs of points
41// all resident in the same bucket.
42// 3) The bucket offsets are updated to refer to the right entry location into
43// the sorted point ids array. This enables quick access, and an indirect count
44// of the number of points in each bucket.
45
46// Forward declaration of lists of neighboring buckets.
47struct NeighborBuckets;
48
49//------------------------------------------------------------------------------
50// The bucketed points, including the sorted map. This is just a PIMPLd
51// wrapper around the classes that do the real work.
53{
55 vtkIdType NumPts; // the number of points to bucket
58
59 // These are internal data members used for performance reasons
61 int Divisions[3];
62 double Bounds[6];
63 double H[3];
64 double hX, hY, hZ, hX2, hY2, hZ2;
65 double fX, fY, fZ, bX, bY, bZ;
67
68 // Used for accelerated performance for certain methods
69 double* FastPoints; // fast path for accessing points
70 double BinRadius; // circumradius of a single bin/bucket
71 int MaxLevel; // the maximum possible level searches can proceed
72
73 // Construction
74 vtkBucketList(vtkStaticPointLocator* loc, vtkIdType numPts, int numBuckets)
75 {
76 this->Locator = loc;
77 this->NumPts = numPts;
78 this->NumBuckets = numBuckets;
79 this->BatchSize = 10000; // building the offset array
80 this->DataSet = loc->GetDataSet();
81 loc->GetDivisions(this->Divisions);
82
83 // Setup internal data members for more efficient processing.
84 double spacing[3], bounds[6];
85 loc->GetDivisions(this->Divisions);
86 loc->GetSpacing(spacing);
87 loc->GetBounds(bounds);
88 this->hX = this->H[0] = spacing[0];
89 this->hY = this->H[1] = spacing[1];
90 this->hZ = this->H[2] = spacing[2];
91 this->hX2 = this->hX / 2.0;
92 this->hY2 = this->hY / 2.0;
93 this->hZ2 = this->hZ / 2.0;
94 this->fX = 1.0 / spacing[0];
95 this->fY = 1.0 / spacing[1];
96 this->fZ = 1.0 / spacing[2];
97 this->bX = this->Bounds[0] = bounds[0];
98 this->Bounds[1] = bounds[1];
99 this->bY = this->Bounds[2] = bounds[2];
100 this->Bounds[3] = bounds[3];
101 this->bZ = this->Bounds[4] = bounds[4];
102 this->Bounds[5] = bounds[5];
103 this->xD = this->Divisions[0];
104 this->yD = this->Divisions[1];
105 this->zD = this->Divisions[2];
106 this->xyD = this->Divisions[0] * this->Divisions[1];
107
108 this->FastPoints = nullptr;
109 this->BinRadius = sqrt(hX * hX + hY * hY + hZ * hZ) / 2.0;
110 this->MaxLevel = std::max({ this->xD, this->yD, this->zD });
111 }
112
113 // Virtuals for templated subclasses
114 virtual ~vtkBucketList() = default;
115 virtual void BuildLocator() = 0;
116
117 // place points in appropriate buckets
119 NeighborBuckets* buckets, const int ijk[3], const int ndivs[3], int level);
120 void GenerateFace(int face, int i, int j, int k, vtkPoints* pts, vtkCellArray* polys);
121 double Distance2ToBucket(const double x[3], const int nei[3]);
122 double Distance2ToBounds(const double x[3], const double bounds[6]);
123
124 //-----------------------------------------------------------------------------
125 // Inlined for performance. These function invocations must be called after
126 // BuildLocator() is invoked, otherwise the output is indeterminate.
127 void GetBucketIndices(const double* x, int ijk[3]) const
128 {
129 // Compute point index. Make sure it lies within range of locator.
130 vtkIdType tmp0 = static_cast<vtkIdType>(((x[0] - bX) * fX));
131 vtkIdType tmp1 = static_cast<vtkIdType>(((x[1] - bY) * fY));
132 vtkIdType tmp2 = static_cast<vtkIdType>(((x[2] - bZ) * fZ));
133
134 ijk[0] = tmp0 < 0 ? 0 : std::min(xD - 1, tmp0);
135 ijk[1] = tmp1 < 0 ? 0 : std::min(yD - 1, tmp1);
136 ijk[2] = tmp2 < 0 ? 0 : std::min(zD - 1, tmp2);
137 }
138
139 //-----------------------------------------------------------------------------
140 vtkIdType GetBucketIndex(const double* x) const
141 {
142 int ijk[3];
143 this->GetBucketIndices(x, ijk);
144 return ijk[0] + ijk[1] * xD + ijk[2] * xyD;
145 }
146
147 //-----------------------------------------------------------------------------
148 // Return the center of the bucket/bin at (i,j,k).
149 void GetBucketCenter(int i, int j, int k, double center[3])
150 {
151 center[0] = this->bX + this->hX2 + i * this->hX;
152 center[1] = this->bY + this->hY2 + j * this->hY;
153 center[2] = this->bZ + this->hZ2 + k * this->hZ;
154 }
155
156 //-----------------------------------------------------------------------------
157 // Return the bounding box (min,max) of a specified bucket (i,j,k).
158 void GetBucketBounds(int i, int j, int k, double min[3], double max[3])
159 {
160 min[0] = this->bX + i * this->hX;
161 min[1] = this->bY + j * this->hY;
162 min[2] = this->bZ + k * this->hZ;
163 max[0] = min[0] + this->hX;
164 max[1] = min[1] + this->hY;
165 max[2] = min[2] + this->hZ;
166 }
167
168 //-----------------------------------------------------------------------------
169 // Determine whether a bin/bucket specified by i,j,k is completely contained
170 // inside the sphere (center,r2). Return true if contained; false otherwise.
171 bool BucketInsideSphere(int i, int j, int k, double center[3], double r2)
172 {
173 double min[3], max[3];
174 min[0] = this->bX + i * this->hX;
175 min[1] = this->bY + j * this->hY;
176 min[2] = this->bZ + k * this->hZ;
177 max[0] += this->hX;
178 max[1] += this->hY;
179 max[2] += this->hZ;
180 return vtkBoundingBox::InsideSphere(min, max, center, r2);
181 }
182}; // vtkBucketList
183
184//------------------------------------------------------------------------------
185// This templates class manages the creation of the static locator
186// structures. It also implements the operator() functors which are supplied
187// to vtkSMPTools for threaded processesing.
188template <typename TIds>
190{
191 // Okay the various ivars
192 vtkLocatorTuple<TIds>* Map; // the map to be sorted
193 TIds* Offsets; // offsets for each bucket into the map
194
195 // Construction
196 BucketList(vtkStaticPointLocator* loc, vtkIdType numPts, int numBuckets)
197 : vtkBucketList(loc, numPts, numBuckets)
198 {
199 // one extra to simplify traversal
200 this->Map = new vtkLocatorTuple<TIds>[numPts + 1];
201 this->Map[numPts].Bucket = numBuckets;
202 this->Offsets = new TIds[numBuckets + 1];
203 this->Offsets[numBuckets] = numPts;
204 }
205
206 // Release allocated memory
207 ~BucketList() override
208 {
209 delete[] this->Map;
210 delete[] this->Offsets;
211 }
212
213 // The number of point ids in a bucket is determined by computing the
214 // difference between the offsets into the sorted points array.
216 {
217 return (this->Offsets[bucketNum + 1] - this->Offsets[bucketNum]);
218 }
219
220 // Given a bucket number, return the point ids in that bucket.
222 {
223 return this->Map + this->Offsets[bucketNum];
224 }
225
226 // Given a bucket number, return the point ids in that bucket.
227 void GetIds(vtkIdType bucketNum, vtkIdList* bList)
228 {
229 const vtkLocatorTuple<TIds>* ids = this->GetIds(bucketNum);
230 vtkIdType numIds = this->GetNumberOfIds(bucketNum);
231 bList->SetNumberOfIds(numIds);
232 for (int i = 0; i < numIds; i++)
233 {
234 bList->SetId(i, ids[i].PtId);
235 }
236 }
237
238 // Templated implementations of the locator
239 vtkIdType FindClosestPoint(const double x[3]);
241 double radius, const double x[3], double inputDataLength, double& dist2);
242 void FindClosestNPoints(int N, const double x[3], vtkIdList* result);
243 double FindNPointsInShell(int N, const double x[3], vtkDist2TupleArray& results,
244 double minDist2 = (-0.1), bool sort = true, vtkDoubleArray* petals = nullptr);
245 void FindPointsWithinRadius(double R, const double x[3], vtkIdList* result);
246 int IntersectWithLine(double a0[3], double a1[3], double tol, double& t, double lineX[3],
247 double ptX[3], vtkIdType& ptId);
248 void MergePoints(double tol, vtkIdType* pointMap, int orderingMode);
250 void GenerateRepresentation(int vtkNotUsed(level), vtkPolyData* pd);
251
252 // Internal methods
254 NeighborBuckets* buckets, const double x[3], const int ijk[3], double dist, int level);
255 void GetOverlappingBuckets(NeighborBuckets* buckets, const double x[3], double dist,
256 int prevMinLevel[3], int prevMaxLevel[3]);
257
258 // Implicit point representation, slower path
259 template <typename T>
261 {
264
266 : BList(blist)
267 , DataSet(ds)
268 {
269 }
270
272 {
273 double p[3];
274 vtkLocatorTuple<T>* t = this->BList->Map + ptId;
275
276 for (; ptId < end; ++ptId, ++t)
277 {
278 this->DataSet->GetPoint(ptId, p);
279 t->Bucket = this->BList->GetBucketIndex(p);
280 t->PtId = ptId;
281 } // for all points in this batch
282 }
283 };
284
285 template <typename T, typename TPointsArray>
287 {
289 TPointsArray* Points;
290
291 MapPointsArray(BucketList<T>* blist, TPointsArray* pts)
292 : BList(blist)
293 , Points(pts)
294 {
295 }
296
298 {
299 double p[3];
300 auto x = vtk::DataArrayTupleRange<3>(this->Points, ptId, end).begin();
301 vtkLocatorTuple<T>* t = this->BList->Map + ptId;
302
303 for (; ptId < end; ++ptId, ++x, ++t)
304 {
305 x->GetTuple(p);
306 t->Bucket = this->BList->GetBucketIndex(p);
307 t->PtId = ptId;
308 } // for all points in this batch
309 }
310 };
311
313 {
314 template <typename TPointsArray>
315 void operator()(TPointsArray* points, BucketList* blist)
316 {
317 MapPointsArray<TIds, TPointsArray> mapper(blist, points);
318 vtkSMPTools::For(0, blist->NumPts, mapper);
319 }
320 };
321
322 // A clever way to build offsets in parallel. Basically each thread builds
323 // offsets across a range of the sorted map. Recall that offsets are an
324 // integral value referring to the locations of the sorted points that
325 // reside in each bucket.
326 template <typename T>
328 {
332
334 : BList(blist)
335 {
336 this->NumBuckets = this->BList->NumBuckets;
337 this->NumPts = this->BList->NumPts;
338 }
339
340 // Traverse sorted points (i.e., tuples) and update bucket offsets.
341 void operator()(vtkIdType batch, vtkIdType batchEnd)
342 {
343 T* offsets = this->BList->Offsets;
344 const vtkLocatorTuple<T>* curPt = this->BList->Map + batch * this->BList->BatchSize;
345 const vtkLocatorTuple<T>* endBatchPt = this->BList->Map + batchEnd * this->BList->BatchSize;
346 const vtkLocatorTuple<T>* endPt = this->BList->Map + this->NumPts;
347 const vtkLocatorTuple<T>* prevPt;
348 endBatchPt = (endBatchPt > endPt ? endPt : endBatchPt);
349
350 // Special case at the very beginning of the mapped points array. If
351 // the first point is in bucket# N, then all buckets up and including
352 // N must refer to the first point.
353 if (curPt == this->BList->Map)
354 {
355 prevPt = this->BList->Map;
356 std::fill_n(offsets, curPt->Bucket + 1, 0); // point to the first points
357 } // at the very beginning of the map (sorted points array)
358
359 // We are entering this functor somewhere in the interior of the
360 // mapped points array. All we need to do is point to the entry
361 // position because we are interested only in prevPt->Bucket.
362 else
363 {
364 prevPt = curPt;
365 } // else in the middle of a batch
366
367 // Okay we have a starting point for a bucket run. Now we can begin
368 // filling in the offsets in this batch. A previous thread should
369 // have/will have completed the previous and subsequent runs outside
370 // of the [batch,batchEnd) range
371 for (curPt = prevPt; curPt < endBatchPt;)
372 {
373 for (; curPt->Bucket == prevPt->Bucket && curPt <= endBatchPt; ++curPt)
374 {
375 // advance
376 }
377 // Fill in any gaps in the offset array
378 std::fill_n(
379 offsets + prevPt->Bucket + 1, curPt->Bucket - prevPt->Bucket, curPt - this->BList->Map);
380 prevPt = curPt;
381 } // for all batches in this range
382 } // operator()
383 };
384
385 // Merge points that are pecisely coincident. Operates in parallel on
386 // locator buckets. Does not need to check neighbor buckets.
387 template <typename T>
389 {
393
395 : BList(blist)
396 , MergeMap(mergeMap)
397 {
398 this->DataSet = blist->DataSet;
399 }
400
401 void operator()(vtkIdType bucket, vtkIdType endBucket)
402 {
403 BucketList<T>* bList = this->BList;
404 vtkIdType* mergeMap = this->MergeMap;
405 int i, j;
406 const vtkLocatorTuple<TIds>* ids;
407 double p[3], p2[3];
408 vtkIdType ptId, ptId2, numIds;
409
410 for (; bucket < endBucket; ++bucket)
411 {
412 if ((numIds = bList->GetNumberOfIds(bucket)) > 0)
413 {
414 ids = bList->GetIds(bucket);
415 for (i = 0; i < numIds; i++)
416 {
417 ptId = ids[i].PtId;
418 if (mergeMap[ptId] < 0)
419 {
420 mergeMap[ptId] = ptId;
421 this->DataSet->GetPoint(ptId, p);
422 for (j = i + 1; j < numIds; j++)
423 {
424 ptId2 = ids[j].PtId;
425 if (mergeMap[ptId2] < 0)
426 {
427 this->DataSet->GetPoint(ptId2, p2);
428 if (p[0] == p2[0] && p[1] == p2[1] && p[2] == p2[2])
429 {
430 mergeMap[ptId2] = ptId;
431 }
432 }
433 }
434 } // if point not yet visited
435 }
436 }
437 }
438 }
439 };
440
441 // Merge points that are coincident within a specified tolerance. Depending
442 // on the orderingMode, either a serialized ordering process is used (i.e.,
443 // POINT_ORDER) or a threaded ordering process is used (i.e.,
444 // BIN_ORDER). Note that due to the tolerance, the merging tolerance
445 // needs to check neighbor buckets which slows the algorithm down
446 // considerably. Note that merging is in one direction: larger ids are
447 // merged to lower ids.
448 template <typename T>
450 {
454 double Tol;
455
457
458 MergeClose(BucketList<T>* blist, double tol, vtkIdType* mergeMap)
459 : BList(blist)
460 , MergeMap(mergeMap)
461 , Tol(tol)
462 {
463 this->DataSet = blist->DataSet;
464 }
465
466 // The core merging process around the point ptId.
467 void MergePoint(vtkIdType ptId, vtkIdList* nearby)
468 {
469 vtkIdType* mergeMap = this->MergeMap;
470
471 // Make sure the point is not already merged
472 if (mergeMap[ptId] < 0)
473 {
474 mergeMap[ptId] = ptId;
475 double p[3];
476 this->DataSet->GetPoint(ptId, p);
477 this->BList->FindPointsWithinRadius(this->Tol, p, nearby);
478 vtkIdType numIds = nearby->GetNumberOfIds();
479 if (numIds > 0)
480 {
481 for (auto i = 0; i < numIds; ++i)
482 {
483 vtkIdType nearId = nearby->GetId(i);
484 if (mergeMap[nearId] < 0)
485 {
486 mergeMap[nearId] = ptId;
487 } // if eligible for merging and not yet merged
488 } // for all nearby points
489 } // if nearby points exist
490 } // if point not yet merged
491 } // MergePoint
492
493 // Just allocate a little bit of memory to get started.
495 {
496 vtkIdList*& pIds = this->PIds.Local();
497 pIds->Allocate(128); // allocate some memory
498 }
499
500 void Reduce() {}
501 };
502
503 // Merge points with non-zero tolerance. Order of point merging guarantees
504 // that any two merged point ids (p0,p1) are such that p0<p1. Consequently
505 // this is a completely serial algorithm.
506 template <typename T>
507 struct MergePointOrder : public MergeClose<T>
508 {
509 MergePointOrder(BucketList<T>* blist, double tol, vtkIdType* mergeMap)
510 : MergeClose<T>(blist, tol, mergeMap)
511 {
512 }
513
515
516 // Process serially, point by point.
518 {
519 vtkIdList*& nearby = this->PIds.Local();
520
521 // Serial operation over all points in the locator.
522 for (vtkIdType ptId = 0; ptId < numPts; ++ptId)
523 {
524 this->MergePoint(ptId, nearby);
525 } // for all points in the locator
526 } // operator()
527
528 void Reduce() { this->MergeClose<T>::Reduce(); }
529 }; // Merge points in point ordering
530
531 // Merge points with non-zero tolerance. The order of point merging depends
532 // on the order in which the bins are traversed (using a checkerboard
533 // pattern). While the algorithm is threaded, the checkerboarding acts as
534 // a barrier to full threading so the performance is not optimal (but at
535 // least deterministic / reproducible).
536 //
537 // Checkerboarding works as follows. The locator bin volume of dimensions
538 // Divisions[3] is divided into a collection of "blocks" which are
539 // subvolumes of bins of dimensions d^3. The algorithm makes multiple,
540 // threaded passes over the blocks (a total of d^3 threaded traversals),
541 // choosing one of the bins in each block to process via the current
542 // checkerboard index. The dimension d of the blocks is determined by the
543 // tolerance and locator bin size, and is chosen in such a way as to
544 // separate the point merging computation so as to avoid threading data
545 // races / write contention.
546 template <typename T>
547 struct MergeBinOrder : public MergeClose<T>
548 {
549 int CheckerboardDimension; // the dimension of the checkerboard block/subvolume
550 int NumBlocks; // how many blocks/subvolumes are in the binned locator
551 int BlockDims[3]; // the number of blocks in each coordinate direction
552 int CheckerboardIndex[3]; // which bin is being processed in the blocks
553
554 // The main function of the constructor is the setup the checkerboard
555 // traversal. This means configuring the checkerboard subvolume, and
556 // set up the traversal indices.
557 MergeBinOrder(BucketList<T>* blist, double tol, vtkIdType* mergeMap)
558 : MergeClose<T>(blist, tol, mergeMap)
559 {
560 BucketList<T>* bl = this->BList;
561 double hMin = std::min({ bl->hX, bl->hY, bl->hZ });
562 this->CheckerboardDimension =
563 1 + (hMin == 0.0 ? 1 : (1 + vtkMath::Floor(tol / (hMin / 2.0))));
564
565 // Determine how many blocks there are in the locater, and determine the
566 // dimensions of the blocks.
567 this->NumBlocks = 1;
568 for (auto i = 0; i < 3; ++i)
569 {
570 double numBlocks =
571 static_cast<double>(bl->Divisions[i]) / static_cast<double>(this->CheckerboardDimension);
572 this->BlockDims[i] = (bl->Divisions[i] <= 1 ? 1 : vtkMath::Ceil(numBlocks));
573 this->NumBlocks *= this->BlockDims[i];
574 }
576 }
577
578 // Initialize the checkerboard traversal process. A pointer to the
579 // current traversal state (within the checkerboard region) is returned.
581 {
582 // Control checkerboard traversal
583 this->CheckerboardIndex[0] = 0;
584 this->CheckerboardIndex[1] = 0;
585 this->CheckerboardIndex[2] = 0;
586 return this->CheckerboardIndex;
587 }
588
589 // Given a blockId and the current checkerboard index, compute the
590 // current locator bin/bucket id. May return <0 if no bin exists.
591 vtkIdType GetCurrentBin(int blockId, int cIdx[3])
592 {
593 // Which checkerboard block are we in?
594 int ijk[3];
595 vtkStructuredData::ComputePointStructuredCoords(blockId, this->BlockDims, ijk);
596
597 // Combine the block index with the checkerboard index. Make sure that
598 // we are still inside the locator bins (partial blocks may exist at
599 // the boundary). Recall that the blocks are composed of d^3 bins.
600 for (auto i = 0; i < 3; ++i)
601 {
602 ijk[i] = ijk[i] * this->CheckerboardDimension + cIdx[i];
603 if (ijk[i] >= this->BList->Divisions[i])
604 {
605 return (-1);
606 }
607 }
608
609 // Okay return the bin index
610 return (ijk[0] + ijk[1] * this->BList->Divisions[0] +
611 ijk[2] * this->BList->Divisions[0] * this->BList->Divisions[1]);
612 }
613
615
616 // Process locator blocks/subvolumes.
617 void operator()(vtkIdType blockId, vtkIdType endBlockId)
618 {
619 vtkIdList*& nearby = this->PIds.Local();
620 for (; blockId < endBlockId; ++blockId)
621 {
622 vtkIdType bin = this->GetCurrentBin(blockId, this->CheckerboardIndex);
623 vtkIdType numIds;
624
625 if (bin >= 0 && (numIds = this->BList->GetNumberOfIds(bin)) > 0)
626 {
627 const vtkLocatorTuple<TIds>* ids = this->BList->GetIds(bin);
628 for (auto i = 0; i < numIds; ++i)
629 {
630 vtkIdType ptId = ids[i].PtId;
631 this->MergePoint(ptId, nearby);
632 } // for all points in bin/bucket
633 } // if points exist in bin/bucket
634 } // for all blocks
635 } // operator()
636
637 void Reduce() { this->MergeClose<T>::Reduce(); }
638
639 // Coordinate the checkerboard threading process. Checkerboarding simply
640 // processes a subset of the locator bins to avoid write contention. The
641 // checkerboard footprint (its subvolume size) is a function of the
642 // tolerance, and is effectively a d^3 subvolume that is traversed
643 // (across all subvolumes) in a synchronized fashion. Hence there are d^3
644 // separate SMP traversals - if d becomes too large, the fallback is
645 // simply a serial (MergePointOrder()) to avoid thread thrashing.
646 void Execute()
647 {
648 int cDim = this->CheckerboardDimension;
649 int* cIdx = this->InitializeCheckerboardIndex();
650
651 // Coordinate the checkerboarding by synchronized traversal of the
652 // the checkerboard subblocks.
653 for (cIdx[2] = 0; cIdx[2] < cDim; ++cIdx[2])
654 {
655 for (cIdx[1] = 0; cIdx[1] < cDim; ++cIdx[1])
656 {
657 for (cIdx[0] = 0; cIdx[0] < cDim; ++cIdx[0])
658 {
659 vtkSMPTools::For(0, this->NumBlocks, *this);
660 }
661 }
662 }
663 } // Execute()
664
665 }; // MergeBinOrder
666
667 // Merge points that are geometrically coincident and have matching data
668 // values. Operates in parallel on locator buckets. Does not need to check
669 // neighbor buckets.
670 template <typename T>
672 {
679
681 : BList(blist)
682 , DataArray(da)
683 , MergeMap(mergeMap)
684 {
685 this->DataSet = blist->DataSet;
686 }
687
688 bool TuplesEqual(int tupleSize, double* t1, double* t2)
689 {
690 for (auto i = 0; i < tupleSize; ++i)
691 {
692 if (t1[i] != t2[i])
693 {
694 return false;
695 }
696 }
697 return true;
698 }
699
701 {
702 vtkIdType numComp = this->DataArray->GetNumberOfComponents();
703 this->Tuple.Local().resize(numComp);
704 this->Tuple2.Local().resize(numComp);
705 }
706
707 void operator()(vtkIdType bucket, vtkIdType endBucket)
708 {
709 BucketList<T>* bList = this->BList;
710 vtkIdType* mergeMap = this->MergeMap;
711 int i, j;
712 const vtkLocatorTuple<TIds>* ids;
713 double p[3], p2[3];
714 vtkIdType ptId, ptId2, numIds;
715 int tupleSize = static_cast<int>(this->Tuple.Local().size());
716 double* t = this->Tuple.Local().data();
717 double* t2 = this->Tuple2.Local().data();
718
719 for (; bucket < endBucket; ++bucket)
720 {
721 if ((numIds = bList->GetNumberOfIds(bucket)) > 0)
722 {
723 ids = bList->GetIds(bucket);
724 for (i = 0; i < numIds; i++)
725 {
726 ptId = ids[i].PtId;
727 if (mergeMap[ptId] < 0)
728 {
729 mergeMap[ptId] = ptId;
730 this->DataSet->GetPoint(ptId, p);
731 this->DataArray->GetTuple(ptId, t);
732 for (j = i + 1; j < numIds; j++)
733 {
734 ptId2 = ids[j].PtId;
735 if (mergeMap[ptId2] < 0)
736 {
737 this->DataSet->GetPoint(ptId2, p2);
738 if (p[0] == p2[0] && p[1] == p2[1] && p[2] == p2[2])
739 {
740 this->DataArray->GetTuple(ptId2, t2);
741 if (this->TuplesEqual(tupleSize, t, t2))
742 {
743 mergeMap[ptId2] = ptId;
744 } // if point's data match
745 } // if points geometrically coincident
746 } // if point not yet visited
747 } // for the remaining points in the bin
748 } // if point not yet merged
749 } // for all points in bucket
750 } // if bucket contains points
751 } // for all buckets
752 } // operator()
753
754 void Reduce() {}
755 }; // MergePointsWithData
756
757 // Build the map and other structures to support locator operations
758 void BuildLocator() override
759 {
760 // Place each point in a bucket
761 auto points = this->DataSet->GetPoints()->GetData();
764 points, worker, this))
765 {
766 worker(points, this);
767 }
768
769 // Now group the points into contiguous runs within buckets (recall that
770 // sorting is occurring based on bin/bucket id).
771 vtkSMPTools::Sort(this->Map, this->Map + this->NumPts);
772
773 // Build the offsets into the Map. The offsets are the positions of
774 // each bucket into the sorted list. They mark the beginning of the
775 // list of points in each bucket. Amazingly, this can be done in
776 // parallel.
777 int numBatches = static_cast<int>(ceil(static_cast<double>(this->NumPts) / this->BatchSize));
778 MapOffsets<TIds> offMapper(this);
779 vtkSMPTools::For(0, numBatches, offMapper);
780 }
781};
782
783VTK_ABI_NAMESPACE_END
784#endif // vtkStaticPointLocatorPrivate_h
785// VTK-HeaderTest-Exclude: vtkStaticPointLocatorPrivate.h
RealT r2
Definition PyrC2Basis.h:20
RealT t2
Definition PyrC2Basis.h:22
int GetNumberOfComponents() const
Set/Get the dimension (n) of the components.
static bool InsideSphere(const double min[3], const double max[3], const double center[3], double r2)
Performant method to determine if box if fully inside a sphere.
object to represent cell connectivity
virtual double * GetTuple(vtkIdType tupleIdx)=0
Get the data tuple at tupleIdx.
abstract class to specify dataset behavior
Definition vtkDataSet.h:166
virtual double * GetPoint(vtkIdType ptId)=0
Get point coordinates with ptId such that: 0 <= ptId < NumberOfPoints.
dynamic, self-adjusting array of double
list of point or cell ids
Definition vtkIdList.h:133
void SetNumberOfIds(vtkIdType number)
Specify the number of ids for this object to hold.
int Allocate(vtkIdType sz, int strategy=0)
Allocate a capacity for sz ids in the list and set the number of stored ids in the list to 0.
vtkIdType GetNumberOfIds() const noexcept
Return the number of id's in the list.
Definition vtkIdList.h:159
void SetId(vtkIdType i, vtkIdType vtkid)
Set the id at location i.
Definition vtkIdList.h:188
vtkIdType GetId(vtkIdType i)
Return the id at location i.
Definition vtkIdList.h:164
virtual vtkDataSet * GetDataSet()
Build the locator from the points/cells defining this dataset.
static int Ceil(double x)
Rounds a double to the nearest integer not less than itself.
Definition vtkMath.h:1945
static int Floor(double x)
Rounds a double to the nearest integer not greater than itself.
Definition vtkMath.h:1936
represent and manipulate 3D points
Definition vtkPoints.h:139
concrete dataset represents vertices, lines, polygons, and triangle strips
Thread local storage for VTK objects.
T *& Local()
Returns an object local to the current thread.
Thread local storage for VTK objects.
T & Local()
This needs to be called mainly within a threaded execution path.
static void Sort(RandomAccessIterator begin, RandomAccessIterator end)
A convenience method for sorting data.
static void For(vtkIdType first, vtkIdType last, vtkIdType grain, Functor &f)
Execute a for operation in parallel.
quickly locate points in 3-space
virtual double * GetBounds()
Provide an accessor to the bounds.
virtual double * GetSpacing()
Provide an accessor to the bucket spacing.
virtual int * GetDivisions()
Set the number of divisions in x-y-z directions.
static void ComputePointStructuredCoords(vtkIdType ptId, const int dim[3], int ijk[3], int dataDescription=vtkStructuredData::VTK_STRUCTURED_EMPTY)
Given a pointId and grid dimensions 'dim', get the structured coordinates (i-j-k).
VTK_ITER_INLINE auto DataArrayTupleRange(const ArrayTypePtr &array, TupleIdType start=-1, TupleIdType end=-1) -> typename detail::SelectTupleRange< ArrayTypePtr, TupleSize >::type
Generate an stl and for-range compatible range of tuple iterators from a vtkDataArray.
MapDataSet(BucketList< T > *blist, vtkDataSet *ds)
void operator()(vtkIdType ptId, vtkIdType end)
void operator()(vtkIdType batch, vtkIdType batchEnd)
void operator()(TPointsArray *points, BucketList *blist)
void operator()(vtkIdType ptId, vtkIdType end)
MapPointsArray(BucketList< T > *blist, TPointsArray *pts)
void operator()(vtkIdType blockId, vtkIdType endBlockId)
MergeBinOrder(BucketList< T > *blist, double tol, vtkIdType *mergeMap)
vtkIdType GetCurrentBin(int blockId, int cIdx[3])
vtkSMPThreadLocalObject< vtkIdList > PIds
void MergePoint(vtkIdType ptId, vtkIdList *nearby)
MergeClose(BucketList< T > *blist, double tol, vtkIdType *mergeMap)
MergePointOrder(BucketList< T > *blist, double tol, vtkIdType *mergeMap)
MergePointsAndData(BucketList< T > *blist, vtkDataArray *da, vtkIdType *mergeMap)
bool TuplesEqual(int tupleSize, double *t1, double *t2)
vtkSMPThreadLocal< std::vector< double > > Tuple
void operator()(vtkIdType bucket, vtkIdType endBucket)
vtkSMPThreadLocal< std::vector< double > > Tuple2
MergePrecise(BucketList< T > *blist, vtkIdType *mergeMap)
void operator()(vtkIdType bucket, vtkIdType endBucket)
void GetIds(vtkIdType bucketNum, vtkIdList *bList)
BucketList(vtkStaticPointLocator *loc, vtkIdType numPts, int numBuckets)
void GetOverlappingBuckets(NeighborBuckets *buckets, const double x[3], double dist, int prevMinLevel[3], int prevMaxLevel[3])
double FindNPointsInShell(int N, const double x[3], vtkDist2TupleArray &results, double minDist2=(-0.1), bool sort=true, vtkDoubleArray *petals=nullptr)
void GenerateRepresentation(int level, vtkPolyData *pd)
void MergePointsWithData(vtkDataArray *data, vtkIdType *pointMap)
vtkIdType FindClosestPoint(const double x[3])
vtkIdType GetNumberOfIds(vtkIdType bucketNum)
void FindPointsWithinRadius(double R, const double x[3], vtkIdList *result)
vtkLocatorTuple< TIds > * Map
void BuildLocator() override
const vtkLocatorTuple< TIds > * GetIds(vtkIdType bucketNum)
vtkIdType FindClosestPointWithinRadius(double radius, const double x[3], double inputDataLength, double &dist2)
int IntersectWithLine(double a0[3], double a1[3], double tol, double &t, double lineX[3], double ptX[3], vtkIdType &ptId)
void GetOverlappingBuckets(NeighborBuckets *buckets, const double x[3], const int ijk[3], double dist, int level)
void MergePoints(double tol, vtkIdType *pointMap, int orderingMode)
void FindClosestNPoints(int N, const double x[3], vtkIdList *result)
Dispatch a single array against all array types mentioned in the ArrayList template parameter.
void GenerateFace(int face, int i, int j, int k, vtkPoints *pts, vtkCellArray *polys)
vtkIdType GetBucketIndex(const double *x) const
virtual void BuildLocator()=0
void GetBucketNeighbors(NeighborBuckets *buckets, const int ijk[3], const int ndivs[3], int level)
vtkBucketList(vtkStaticPointLocator *loc, vtkIdType numPts, int numBuckets)
double Distance2ToBucket(const double x[3], const int nei[3])
virtual ~vtkBucketList()=default
vtkStaticPointLocator * Locator
double Distance2ToBounds(const double x[3], const double bounds[6])
bool BucketInsideSphere(int i, int j, int k, double center[3], double r2)
void GetBucketIndices(const double *x, int ijk[3]) const
void GetBucketBounds(int i, int j, int k, double min[3], double max[3])
void GetBucketCenter(int i, int j, int k, double center[3])
Represent an array of vtkDist2Tuples.
#define vtkDataArray
STL-compatible iterable ranges that provide access to vtkDataArray elements.
int vtkIdType
Definition vtkType.h:368
#define max(a, b)