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