VTK  9.7.20261112
vtkStaticPointLocator2DPrivate.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 vtkStaticPointLocator2DPrivate_h
14#define vtkStaticPointLocator2DPrivate_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"
26#include "vtkSMPTools.h"
28#include "vtkStructuredData.h"
29
30VTK_ABI_NAMESPACE_BEGIN
31
32#define Distance2BetweenPoints2D(p1, p2) \
33 ((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]))
34
40inline bool IntersectsCircle(
41 const double min[2], const double max[2], const double center[2], double r2)
42{
43 double d2 = 0.0;
44 for (int i = 0; i < 2; ++i)
45 {
46 if (center[i] < min[i])
47 {
48 d2 += (center[i] - min[i]) * (center[i] - min[i]);
49 }
50 else if (center[i] > max[i])
51 {
52 d2 += (center[i] - max[i]) * (center[i] - max[i]);
53 }
54 }
55 return (d2 <= r2);
56}
57
63inline bool InsideCircle(
64 const double min[2], const double max[2], const double center[2], double r2)
65{
66 double dmin = 0.0, dmax = 0.0;
67 for (int i = 0; i < 2; ++i)
68 {
69 double a = (center[i] - min[i]) * (center[i] - min[i]);
70 double b = (center[i] - max[i]) * (center[i] - max[i]);
71 dmax += std::max(a, b);
72 if (min[i] <= center[i] && center[i] <= max[i])
73 {
74 dmin += std::min(a, b);
75 }
76 }
77 return (!(dmin <= r2 && r2 <= dmax));
78}
79
80//------------------------------------------------------------------------------
81// The following code supports threaded point locator construction. The locator
82// is assumed to be constructed once (i.e., it does not allow incremental point
83// insertion). The algorithm proceeds in three steps:
84// 1) All points are assigned a bucket index (combined i-j bucket location).
85// The index is computed in parallel. This requires a one time allocation of an
86// index array (which is also associated with the originating point ids).
87// 2) vtkSMPTools::Sort() is used to sort the index array. Note that the sort
88// carries along the point ids as well. This creates contiguous runs of points
89// all resident in the same bucket.
90// 3) The bucket offsets are updated to refer to the right entry location into
91// the sorted point ids array. This enables quick access, and an indirect count
92// of the number of points in each bucket.
93
94struct NeighborBuckets2D;
95
96//------------------------------------------------------------------------------
97// The bucketed points, including the sorted map. This is just a PIMPLd
98// wrapper around the classes that do the real work.
100{
102 vtkIdType NumPts; // the number of points to bucket
105
106 // These are internal data members used for performance reasons
108 int Divisions[3];
109 double Bounds[6];
110 double H[3];
111 double hX, hY, hX2, hY2;
112 double fX, fY, bX, bY;
114
115 // Used for accelerated performance for certain methods
116 double* FastPoints; // fast path for accessing points
117 double BinRadius; // circumradius of a single bin/bucket
118 int MaxLevel; // the maximum possible level searches can proceed
119
120 // Construction
122 {
123 this->Locator = loc;
124 this->NumPts = numPts;
125 this->NumBuckets = numBuckets;
126 this->BatchSize = 10000; // building the offset array
127 this->DataSet = loc->GetDataSet();
128
129 // Setup internal data members for more efficient processing. Remember this is
130 // a 2D locator so just processing (x,y) points.
131 double spacing[3], bounds[6];
132 loc->GetDivisions(this->Divisions);
133 loc->GetSpacing(spacing);
134 loc->GetBounds(bounds);
135 this->hX = this->H[0] = spacing[0];
136 this->hY = this->H[1] = spacing[1];
137 this->hX2 = this->hX / 2.0;
138 this->hY2 = this->hY / 2.0;
139 this->fX = 1.0 / spacing[0];
140 this->fY = 1.0 / spacing[1];
141 this->bX = this->Bounds[0] = bounds[0];
142 this->Bounds[1] = bounds[1];
143 this->bY = this->Bounds[2] = bounds[2];
144 this->Bounds[3] = bounds[3];
145 this->xD = this->Divisions[0];
146 this->yD = this->Divisions[1];
147 this->zD = 1;
148
149 this->FastPoints = nullptr;
150 this->BinRadius = sqrt(hX * hX + hY * hY) / 2.0;
151 this->MaxLevel = std::max({ this->xD, this->yD, this->zD });
152 }
153
154 // Virtuals for templated subclasses
155 virtual ~vtkBucketList2D() = default;
156 virtual void BuildLocator() = 0;
157
158 // place points in appropriate buckets
160 NeighborBuckets2D* buckets, const int ij[2], const int ndivs[2], int level);
161 void GenerateFace(int face, int i, int j, int k, vtkPoints* pts, vtkCellArray* polys);
162 double Distance2ToBucket(const double x[3], const int nei[3]);
163 double Distance2ToBounds(const double x[3], const double bounds[6]);
164
165 //-----------------------------------------------------------------------------
166 // Inlined for performance. These function invocations must be called after
167 // BuildLocator() is invoked, otherwise the output is indeterminate.
168 void GetBucketIndices(const double* x, int ij[2]) const
169 {
170 // Compute point index. SafeCastFromDouble clamps to the integer type limits
171 // (mapping NaN to 0) so casting a coordinate far outside the locator bounds
172 // (e.g. VTK_DOUBLE_MAX) is not undefined behavior. Make sure it then lies
173 // within the range of the locator.
176
177 ij[0] = std::min(std::max<vtkIdType>(tmp0, 0), xD - 1);
178 ij[1] = std::min(std::max<vtkIdType>(tmp1, 0), yD - 1);
179 }
180
181 //-----------------------------------------------------------------------------
182 vtkIdType GetBucketIndex(const double* x) const
183 {
184 int ij[2];
185 this->GetBucketIndices(x, ij);
186 return ij[0] + ij[1] * xD;
187 }
188
189 //-----------------------------------------------------------------------------
190 // Return the center of the bucket/bin at (i,j). Note, returns a 2D point
191 // center[2].
192 void GetBucketCenter(int i, int j, double center[3])
193 {
194 center[0] = this->bX + this->hX2 + i * this->hX;
195 center[1] = this->bY + this->hY2 + j * this->hY;
196 center[2] = 0.0;
197 }
198
199 //-----------------------------------------------------------------------------
200 // Return the bounding box (min,max) of a specified bucket (i,j,k).
201 void GetBucketBounds(int i, int j, double min[3], double max[3])
202 {
203 min[0] = this->bX + i * this->hX;
204 min[1] = this->bY + j * this->hY;
205 min[2] = 0.0;
206 max[0] = min[0] + this->hX;
207 max[1] = min[1] + this->hY;
208 max[2] = 0.0;
209 }
210
211 //-----------------------------------------------------------------------------
212 // Determine whether a bin/bucket specified by i,j is completely contained
213 // inside the circle (center,r2). Return true if contained; false otherwise.
214 bool BucketInsideCircle(int i, int j, const double center[3], double r2)
215 {
216 double xMin = this->bX + i * this->hX;
217 double xMax = xMin + this->hX;
218 double yMin = this->bY + j * this->hY;
219 double yMax = yMin + this->hY;
220 double dx0 = center[0] - xMin, dx1 = center[0] - xMax;
221 double dy0 = center[1] - yMin, dy1 = center[1] - yMax;
222 double dmax2 = std::max(dx0 * dx0, dx1 * dx1) + std::max(dy0 * dy0, dy1 * dy1);
223 return dmax2 <= r2;
224 }
225}; // vtkBucketList2D
226
227//------------------------------------------------------------------------------
228// This templated class manages the creation of the static locator
229// structures. It also implements the operator() functors which are supplied
230// to vtkSMPTools for threaded processesing.
231template <typename TIds>
233{
234 // Okay the various ivars
235 vtkLocatorTuple<TIds>* Map; // the map to be sorted
236 TIds* Offsets; // offsets for each bucket into the map
237
238 // Construction
239 BucketList2D(vtkStaticPointLocator2D* loc, vtkIdType numPts, int numBuckets)
240 : vtkBucketList2D(loc, numPts, numBuckets)
241 {
242 // one extra to simplify traversal
243 this->Map = new vtkLocatorTuple<TIds>[numPts + 1];
244 this->Map[numPts].Bucket = numBuckets;
245 this->Offsets = new TIds[numBuckets + 1];
246 this->Offsets[numBuckets] = numPts;
247 }
248
249 // Release allocated memory
250 ~BucketList2D() override
251 {
252 delete[] this->Map;
253 delete[] this->Offsets;
254 }
255
256 // The number of point ids in a bucket is determined by computing the
257 // difference between the offsets into the sorted points array.
259 {
260 if (bucketNum < 0 || bucketNum >= this->NumBuckets)
261 {
262 return 0;
263 }
264 return (this->Offsets[bucketNum + 1] - this->Offsets[bucketNum]);
265 }
266
267 // Given a bucket number, return the point ids in that bucket.
269 {
270 return this->Map + this->Offsets[bucketNum];
271 }
272
273 // Given a bucket number, return the point ids in that bucket.
274 void GetIds(vtkIdType bucketNum, vtkIdList* bList)
275 {
276 const vtkLocatorTuple<TIds>* ids = this->GetIds(bucketNum);
277 vtkIdType numIds = this->GetNumberOfIds(bucketNum);
278 bList->SetNumberOfIds(numIds);
279 for (int i = 0; i < numIds; i++)
280 {
281 bList->SetId(i, ids[i].PtId);
282 }
283 }
284
285 // Templated implementations of the locator
286 vtkIdType FindClosestPoint(const double x[3]);
288 double radius, const double x[3], double inputDataLength, double& dist2);
289 void FindClosestNPoints(int N, const double x[3], vtkIdList* result);
290 double FindNPointsInShell(int N, const double x[3], vtkDist2TupleArray& results,
291 double minDist2 = (-0.1), bool sort = true, vtkDoubleArray* petals = nullptr);
292 void FindPointsInShell(const double x[3], vtkDist2TupleArray& results, double minDist2,
293 double maxDist2, bool sort, vtkDoubleArray* petals);
294 void FindPointsWithinRadius(double R, const double x[3], vtkIdList* result);
295 int IntersectWithLine(double a0[3], double a1[3], double tol, double& t, double lineX[3],
296 double ptX[3], vtkIdType& ptId);
297 double FindCloseNBoundedPoints(int N, const double x[3], vtkIdList* result);
298
299 void MergePoints(double tol, vtkIdType* pointMap);
300 void GenerateRepresentation(int vtkNotUsed(level), vtkPolyData* pd);
301
302 // Internal methods
303 bool BucketIntersectsCircle(int i, int j, const double center[3], double R2);
305 NeighborBuckets2D* buckets, const double x[3], const int ij[2], double dist, int level);
306 void GetOverlappingBuckets(NeighborBuckets2D* buckets, const double x[3], double dist,
307 int prevMinLevel[2], int prevMaxLevel[2]);
308
309 // Implicit point representation, slower path
310 template <typename T>
312 {
315
317 : BList(blist)
318 , DataSet(ds)
319 {
320 }
321
323 {
324 double p[3];
325 vtkLocatorTuple<T>* t = this->BList->Map + ptId;
326 for (; ptId < end; ++ptId, ++t)
327 {
328 this->DataSet->GetPoint(ptId, p);
329 t->PtId = ptId;
330 t->Bucket = this->BList->GetBucketIndex(p);
331 } // for all points in this batch
332 }
333 };
334
335 template <typename T, typename TPointsArray>
337 {
339 TPointsArray* Points;
340
341 MapPointsArray(BucketList2D<T>* blist, TPointsArray* pts)
342 : BList(blist)
343 , Points(pts)
344 {
345 }
346
348 {
349 double p[3];
350 auto x = vtk::DataArrayTupleRange<3>(this->Points, ptId, end).begin();
351 vtkLocatorTuple<T>* t = this->BList->Map + ptId;
352 for (; ptId < end; ++ptId, ++x, ++t)
353 {
354 x->GetTuple(p);
355 t->PtId = ptId;
356 t->Bucket = this->BList->GetBucketIndex(p);
357 } // for all points in this batch
358 }
359 };
360
362 {
363 template <typename TPointsArray>
364 void operator()(TPointsArray* points, BucketList2D* blist)
365 {
366 MapPointsArray<TIds, TPointsArray> mapper(blist, points);
367 vtkSMPTools::For(0, blist->NumPts, mapper);
368 }
369 };
370
371 // A clever way to build offsets in parallel. Basically each thread builds
372 // offsets across a range of the sorted map. Recall that offsets are an
373 // integral value referring to the locations of the sorted points that
374 // reside in each bucket.
375 template <typename T>
377 {
381
383 : BList(blist)
384 {
385 this->NumPts = this->BList->NumPts;
386 this->NumBuckets = this->BList->NumBuckets;
387 }
388
389 // Traverse sorted points (i.e., tuples) and update bucket offsets.
390 void operator()(vtkIdType batch, vtkIdType batchEnd)
391 {
392 T* offsets = this->BList->Offsets;
393 const vtkLocatorTuple<T>* curPt = this->BList->Map + batch * this->BList->BatchSize;
394 const vtkLocatorTuple<T>* endBatchPt = this->BList->Map + batchEnd * this->BList->BatchSize;
395 const vtkLocatorTuple<T>* endPt = this->BList->Map + this->NumPts;
396 const vtkLocatorTuple<T>* prevPt;
397 endBatchPt = (endBatchPt > endPt ? endPt : endBatchPt);
398
399 // Special case at the very beginning of the mapped points array. If
400 // the first point is in bucket# N, then all buckets up and including
401 // N must refer to the first point.
402 if (curPt == this->BList->Map)
403 {
404 prevPt = this->BList->Map;
405 std::fill_n(offsets, curPt->Bucket + 1, 0); // point to the first points
406 } // at the very beginning of the map (sorted points array)
407
408 // We are entering this functor somewhere in the interior of the
409 // mapped points array. All we need to do is point to the entry
410 // position because we are interested only in prevPt->Bucket.
411 else
412 {
413 prevPt = curPt;
414 } // else in the middle of a batch
415
416 // Okay we have a starting point for a bucket run. Now we can begin
417 // filling in the offsets in this batch. A previous thread should
418 // have/will have completed the previous and subsequent runs outside
419 // of the [batch,batchEnd) range
420 for (curPt = prevPt; curPt < endBatchPt;)
421 {
422 for (; curPt->Bucket == prevPt->Bucket && curPt <= endBatchPt; ++curPt)
423 {
424 // advance
425 }
426 // Fill in any gaps in the offset array
427 std::fill_n(
428 offsets + prevPt->Bucket + 1, curPt->Bucket - prevPt->Bucket, curPt - this->BList->Map);
429 prevPt = curPt;
430 } // for all batches in this range
431 } // operator()
432 };
433
434 // Merge points that are pecisely coincident. Operates in parallel on
435 // locator buckets. Does not need to check neighbor buckets.
436 template <typename T>
438 {
442
444 : BList(blist)
445 , MergeMap(mergeMap)
446 {
447 this->DataSet = blist->DataSet;
448 }
449
450 void operator()(vtkIdType bucket, vtkIdType endBucket)
451 {
452 BucketList2D<T>* bList = this->BList;
453 vtkIdType* mergeMap = this->MergeMap;
454 int i, j;
455 const vtkLocatorTuple<TIds>* ids;
456 double p[3], p2[3];
457 vtkIdType ptId, ptId2, numIds;
458
459 for (; bucket < endBucket; ++bucket)
460 {
461 if ((numIds = bList->GetNumberOfIds(bucket)) > 0)
462 {
463 ids = bList->GetIds(bucket);
464 for (i = 0; i < numIds; i++)
465 {
466 ptId = ids[i].PtId;
467 if (mergeMap[ptId] < 0)
468 {
469 mergeMap[ptId] = ptId;
470 this->DataSet->GetPoint(ptId, p);
471 for (j = i + 1; j < numIds; j++)
472 {
473 ptId2 = ids[j].PtId;
474 if (mergeMap[ptId2] < 0)
475 {
476 this->DataSet->GetPoint(ptId2, p2);
477 if (p[0] == p2[0] && p[1] == p2[1])
478 {
479 mergeMap[ptId2] = ptId;
480 }
481 }
482 }
483 } // if point not yet visited
484 }
485 }
486 }
487 }
488 };
489
490 // Merge points that are coincident within a tolerance. Operates in
491 // parallel on points. Needs to check neighbor buckets which slows it down
492 // considerably. Note that merging is one direction: larger ids are merged
493 // to lower.
494 template <typename T>
496 {
500 double Tol;
501
503
504 MergeClose(BucketList2D<T>* blist, double tol, vtkIdType* mergeMap)
505 : BList(blist)
506 , MergeMap(mergeMap)
507 , Tol(tol)
508 {
509 this->DataSet = blist->DataSet;
510 }
511
512 // Just allocate a little bit of memory to get started.
514 {
515 vtkIdList*& pIds = this->PIds.Local();
516 pIds->Reserve(128); // allocate some memory
517 }
518
519 void operator()(vtkIdType ptId, vtkIdType endPtId)
520 {
521 BucketList2D<T>* bList = this->BList;
522 vtkIdType* mergeMap = this->MergeMap;
523 int i;
524 double p[3];
525 vtkIdType nearId, numIds;
526 vtkIdList*& nearby = this->PIds.Local();
527
528 for (; ptId < endPtId; ++ptId)
529 {
530 if (mergeMap[ptId] < 0)
531 {
532 mergeMap[ptId] = ptId;
533 this->DataSet->GetPoint(ptId, p);
534 bList->FindPointsWithinRadius(this->Tol, p, nearby);
535 if ((numIds = nearby->GetNumberOfIds()) > 0)
536 {
537 for (i = 0; i < numIds; i++)
538 {
539 nearId = nearby->GetId(i);
540 if (ptId < nearId && (mergeMap[nearId] < 0 || ptId < mergeMap[nearId]))
541 {
542 mergeMap[nearId] = ptId;
543 }
544 }
545 }
546 } // if point not yet processed
547 } // for all points in this batch
548 }
549
550 void Reduce() {}
551 };
552
553 // Build the map and other structures to support locator operations
554 void BuildLocator() override
555 {
556 // Place each point in a bucket
557 auto points = this->DataSet->GetPoints()->GetData();
560 points, worker, this))
561 {
562 worker(points, this);
563 }
564
565 // Provide accelerated access to points. Needed for Voronoi bin iterators.
567 {
568 this->FastPoints = static_cast<double*>(vtkDoubleArray::SafeDownCast(points)->GetPointer(0));
569 }
570
571 // Now gather the points into contiguous runs in buckets
572 //
573 vtkSMPTools::Sort(this->Map, this->Map + this->NumPts);
574
575 // Build the offsets into the Map. The offsets are the positions of
576 // each bucket into the sorted list. They mark the beginning of the
577 // list of points in each bucket. Amazingly, this can be done in
578 // parallel.
579 //
580 int numBatches = static_cast<int>(ceil(static_cast<double>(this->NumPts) / this->BatchSize));
581 MapOffsets<TIds> offMapper(this);
582 vtkSMPTools::For(0, numBatches, offMapper);
583 }
584}; // BucketList2D
585
586//------------------------------------------------------------------------------
587// Iteration over the bins of a vtkStaticPointLocator2D in patches of
588// increasing levels around a center bin: the patch of level L is the square
589// of bins (2L+1)^2 around the center bin, and only its boundary bins (the bins
590// not in the patch of level L-1) are visited, each once. Used by
591// vtkStaticPointLocator2D::FindPointsInShell() and vtkAnnularBinIterator.
592//------------------------------------------------------------------------------
593// Hard coded bin iteration traversals for lower levels. Note the ping-pong
594// order (traversal of opposite bins).
595inline constexpr int vtkBucketPatchLevel1[8][2] = {
596 { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 }, // four edge centers, ping pong style
597 { -1, -1 }, { 1, 1 }, { 1, -1 }, { -1, 1 } // four patch corners, ping ponged
598}; // Level1
599
600inline constexpr int vtkBucketPatchLevel2[16][2] = {
601 { -2, 0 }, { 2, 0 }, { 0, -2 }, { 0, 2 }, // edge centers
602 { -1, -2 }, { 1, 2 }, { -2, -1 }, { 2, 1 }, // along edges
603 { 1, -2 }, { -1, 2 }, { -2, 1 }, { 2, -1 }, { -2, -2 }, { 2, 2 }, { 2, -2 }, { -2, 2 } // corners
604}; // Level2
605
606inline constexpr int vtkBucketPatchLevel3[24][2] = { { -3, 0 }, { 3, 0 }, { 0, -3 }, { 0, 3 },
607 { -1, -3 }, { 1, 3 }, { 3, -1 }, { -3, 1 }, { 1, -3 }, { -1, 3 }, { 3, 1 }, { -3, -1 },
608 { -2, -3 }, { 2, 3 }, { 3, -2 }, { -3, 2 }, { 2, -3 }, { -2, 3 }, { 3, 2 }, { -3, -2 },
609 { -3, -3 }, { 3, 3 }, { 3, -3 }, { -3, 3 } }; // Level3
610
611inline constexpr int vtkBucketPatchLevel4[32][2] = { { -4, 0 }, { 4, 0 }, { 0, -4 }, { 0, 4 },
612 { -1, -4 }, { 1, 4 }, { 4, -1 }, { -4, 1 }, { 1, -4 }, { -1, 4 }, { 4, 1 }, { -4, -1 },
613 { -2, -4 }, { 2, 4 }, { 4, -2 }, { -4, 2 }, { 2, -4 }, { -2, 4 }, { 4, 2 }, { -4, -2 },
614 { -3, -4 }, { 3, 4 }, { 4, -3 }, { -4, 3 }, { 3, -4 }, { -3, 4 }, { 4, 3 }, { -4, -3 },
615 { -4, -4 }, { 4, 4 }, { 4, -4 }, { -4, 4 } }; // Level4
616
617inline constexpr int vtkBucketPatchLevel5[40][2] = { { -5, 0 }, { 5, 0 }, { 0, -5 }, { 0, 5 },
618 { -1, -5 }, { 1, 5 }, { 5, -1 }, { -5, 1 }, { 1, -5 }, { -1, 5 }, { 5, 1 }, { -5, -1 },
619 { -2, -5 }, { 2, 5 }, { 5, -2 }, { -5, 2 }, { 2, -5 }, { -2, 5 }, { 5, 2 }, { -5, -2 },
620 { -3, -5 }, { 3, 5 }, { 5, -3 }, { -5, 3 }, { 3, -5 }, { -3, 5 }, { 5, 3 }, { -5, -3 },
621 { -4, -5 }, { 4, 5 }, { 5, -4 }, { -5, 4 }, { 4, -5 }, { -4, 5 }, { 5, 4 }, { -5, -4 },
622 { -5, -5 }, { 5, 5 }, { 5, -5 }, { -5, 5 } }; // Level5
623
624//------------------------------------------------------------------------------
625// Iterate over a specified level of an i-j patch (i.e., a hollow square of bins,
626// iteration occurs over the perimeter of the patch at a specified level).
628{
629 int Divs[2]; // the topology of a regular (2D locator) binning
630 int MaxLevel; // the maximum level of iteration based on locator
631
632 // The current state of iteration.
633 int Level; // the current level over which we are iterating
634 int Center[2]; // the center of iteration of the current patch
635 int Span; // the topological width of the patch at the current patch level
636 int NumBins; // the number of bins to process at the current level
637 int BinNum; // the current iteration position at the current level
638 int Interior; // indicate whether (center+level) is interior to the patch
639 int IJ[2]; // the current IJ index of iteration
640
641 // Constructor
643
644 // Initialize the patch iterator.
645 void Initialize(int divs[3], int maxLevel)
646 {
647 this->Divs[0] = divs[0];
648 this->Divs[1] = divs[1];
649 this->MaxLevel = maxLevel;
650 }
651
652 // Determine if the current bin is within the locator binning.
653 bool IsValid()
654 {
655 if (this->Interior)
656 {
657 return true;
658 }
659
660 if (this->IJ[0] < 0 || this->IJ[0] >= this->Divs[0] || this->IJ[1] < 0 ||
661 this->IJ[1] >= this->Divs[1])
662 {
663 return false;
664 }
665 return true;
666 }
667
668 // Return the current bin id.
669 vtkIdType GetBinId() { return (this->IJ[0] + this->IJ[1] * this->Divs[0]); }
670
671 // Update the IJ index.
672 void GetIJ(int ij[2])
673 {
674 ij[0] = this->IJ[0];
675 ij[1] = this->IJ[1];
676 }
677
678 // Initialize the patch iteration process. Indicate the center of the
679 // patch. This is used to specify the patch center of iteration.
680 vtkIdType Begin(int level, int center[2])
681 {
682 this->Level = level;
683 this->Center[0] = center[0];
684 this->Center[1] = center[1];
685 this->BinNum = 0; // starting iteration bin
686
687 if (level == 0)
688 {
689 this->IJ[0] = this->Center[0];
690 this->IJ[1] = this->Center[1];
691 this->NumBins = 1;
692 return this->GetBinId();
693 }
694
695 // For levels>0, further iteration will occur via repeated invocations
696 // of Next().
697
698 // The span: the number of bins spanning a face edge.
699 this->Span = 2 * level + 1;
700
701 // The total number of bins to process.
702 this->NumBins =
703 (level == 0 ? 1
704 : (this->Span * this->Span) - ((2 * (level - 1) + 1) * (2 * (level - 1) + 1)));
705
706 // Determine whether the iteration region is inside of the locator. If the iteration
707 // region overlaps the locator boundary (i.e., is not interior), then bin validity checks
708 // have to be performed.
709 this->Interior = true;
710 if ((this->Center[0] - level) < 0 || (this->Center[0] + level) >= this->Divs[0] ||
711 (this->Center[1] - level) < 0 || (this->Center[1] + level) >= this->Divs[1])
712 {
713 this->Interior = false;
714 }
715
716 // Special case for levels 1-5. The bins are traversed in ping-pong order
717 // in increasing distance from center: first -/+ edge centers, then along edges,
718 // and finally corner points,
719 if (level == 1)
720 {
721 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel1[0][0];
722 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel1[0][1];
723 }
724 else if (level == 2)
725 {
726 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel2[0][0];
727 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel2[0][1];
728 }
729 else if (level == 3)
730 {
731 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel3[0][0];
732 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel3[0][1];
733 }
734 else if (level == 4)
735 {
736 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel4[0][0];
737 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel4[0][1];
738 }
739 else if (level == 5)
740 {
741 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel5[0][0];
742 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel5[0][1];
743 }
744 else // general case for larger levels
745 {
746 this->IJ[0] = this->Center[0];
747 this->IJ[1] = this->Center[1] - level;
748 }
749
750 // Make sure that the starting bin is valid
751 if (!this->IsValid())
752 {
753 return this->Next();
754 }
755
756 return this->GetBinId();
757 }
758
759 // Return binId<0 when iteration over the entirety of the current face patch
760 // completes.
762 {
763 // Loop until valid bin found, or bin traversal for this level is complete.
764 while (true)
765 {
766 // Advance the current bin number
767 this->BinNum++;
768
769 // Special case for level 0, or if visited all bins in the current level
770 int level = this->Level;
771 if (level == 0 || this->BinNum >= this->NumBins || level > this->MaxLevel)
772 {
773 return (-1);
774 }
775
776 // Special cases for levels 1-5
777 if (level == 1)
778 {
779 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel1[this->BinNum][0];
780 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel1[this->BinNum][1];
781 }
782 else if (level == 2)
783 {
784 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel2[this->BinNum][0];
785 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel2[this->BinNum][1];
786 }
787 else if (level == 3)
788 {
789 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel3[this->BinNum][0];
790 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel3[this->BinNum][1];
791 }
792 else if (level == 4)
793 {
794 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel4[this->BinNum][0];
795 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel4[this->BinNum][1];
796 }
797 else if (level == 5)
798 {
799 this->IJ[0] = this->Center[0] + vtkBucketPatchLevel5[this->BinNum][0];
800 this->IJ[1] = this->Center[1] + vtkBucketPatchLevel5[this->BinNum][1];
801 }
802 else // general iteration case - ping-pong rotation around patch
803 {
804 // four edge centers - recall that Begin() processed BinNum==0.
805 if (this->BinNum < 4)
806 {
807 if (this->BinNum == 1)
808 {
809 this->IJ[0] = this->Center[0];
810 this->IJ[1] = this->Center[1] + level;
811 }
812 else if (this->BinNum == 2)
813 {
814 this->IJ[0] = this->Center[0] - level;
815 this->IJ[1] = this->Center[1];
816 }
817 else // if ( this->BinNum == 3 )
818 {
819 this->IJ[0] = this->Center[0] + level;
820 this->IJ[1] = this->Center[1];
821 }
822 }
823
824 // four patch corners
825 else if (this->BinNum >= (this->NumBins - 4))
826 {
827 if (this->BinNum == (this->NumBins - 4))
828 {
829 this->IJ[0] = this->Center[0] - level;
830 this->IJ[1] = this->Center[1] - level;
831 }
832 else if (this->BinNum == (this->NumBins - 3))
833 {
834 this->IJ[0] = this->Center[0] + level;
835 this->IJ[1] = this->Center[1] + level;
836 }
837 else if (this->BinNum == (this->NumBins - 2))
838 {
839 this->IJ[0] = this->Center[0] + level;
840 this->IJ[1] = this->Center[1] - level;
841 }
842 else // if ( this->BinNum == (this->NumBins-1) )
843 {
844 this->IJ[0] = this->Center[0] - level;
845 this->IJ[1] = this->Center[1] + level;
846 }
847 }
848
849 // ping-pong rotation
850 else
851 {
852 int idx = (this->BinNum - 4) % 8;
853 int offset = ((this->BinNum - 4) / 8) + 1;
854 if (idx == 0)
855 {
856 this->IJ[0] = this->Center[0] - offset;
857 this->IJ[1] = this->Center[1] - level;
858 }
859 else if (idx == 1)
860 {
861 this->IJ[0] = this->Center[0] + offset;
862 this->IJ[1] = this->Center[1] + level;
863 }
864 else if (idx == 2)
865 {
866 this->IJ[0] = this->Center[0] - level;
867 this->IJ[1] = this->Center[1] - offset;
868 }
869 else if (idx == 3)
870 {
871 this->IJ[0] = this->Center[0] + level;
872 this->IJ[1] = this->Center[1] + offset;
873 }
874 else if (idx == 4)
875 {
876 this->IJ[0] = this->Center[0] + offset;
877 this->IJ[1] = this->Center[1] - level;
878 }
879 else if (idx == 5)
880 {
881 this->IJ[0] = this->Center[0] - offset;
882 this->IJ[1] = this->Center[1] + level;
883 }
884 else if (idx == 6)
885 {
886 this->IJ[0] = this->Center[0] - level;
887 this->IJ[1] = this->Center[1] + offset;
888 }
889 else // if ( idx == 7 )
890 {
891 this->IJ[0] = this->Center[0] + level;
892 this->IJ[1] = this->Center[1] - offset;
893 }
894 }
895 }
896
897 // Return when valid bin is found
898 if (this->IsValid())
899 {
900 return this->GetBinId();
901 }
902 } // while iterating over patch at current level
903 } // Next()
904
905}; // vtkBucketPatchIterator
906
907VTK_ABI_NAMESPACE_END
908#endif // vtkStaticPointLocator2DPrivate_h
909// VTK-HeaderTest-Exclude: vtkStaticPointLocator2DPrivate.h
int idx
Definition HexCnBasis.h:79
RealT r2
Definition PyrC2Basis.h:20
ValueType * GetPointer(vtkIdType valueIdx)
Get the address of a particular data index.
object to represent cell connectivity
abstract class to specify dataset behavior
Definition vtkDataSet.h:165
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.
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.
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 2-space
void GetBounds(double *bounds) override
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 directions.
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(BucketList2D< T > *blist, vtkDataSet *ds)
void operator()(vtkIdType ptId, vtkIdType end)
void operator()(vtkIdType batch, vtkIdType batchEnd)
void operator()(TPointsArray *points, BucketList2D *blist)
void operator()(vtkIdType ptId, vtkIdType end)
MapPointsArray(BucketList2D< T > *blist, TPointsArray *pts)
MergeClose(BucketList2D< T > *blist, double tol, vtkIdType *mergeMap)
vtkSMPThreadLocalObject< vtkIdList > PIds
void operator()(vtkIdType ptId, vtkIdType endPtId)
void operator()(vtkIdType bucket, vtkIdType endBucket)
MergePrecise(BucketList2D< T > *blist, vtkIdType *mergeMap)
void FindClosestNPoints(int N, const double x[3], vtkIdList *result)
double FindCloseNBoundedPoints(int N, const double x[3], vtkIdList *result)
const vtkLocatorTuple< TIds > * GetIds(vtkIdType bucketNum)
void FindPointsInShell(const double x[3], vtkDist2TupleArray &results, double minDist2, double maxDist2, bool sort, vtkDoubleArray *petals)
BucketList2D(vtkStaticPointLocator2D *loc, vtkIdType numPts, int numBuckets)
void MergePoints(double tol, vtkIdType *pointMap)
void GetOverlappingBuckets(NeighborBuckets2D *buckets, const double x[3], const int ij[2], double dist, int level)
void GetOverlappingBuckets(NeighborBuckets2D *buckets, const double x[3], double dist, int prevMinLevel[2], int prevMaxLevel[2])
vtkLocatorTuple< TIds > * Map
void FindPointsWithinRadius(double R, const double x[3], vtkIdList *result)
int IntersectWithLine(double a0[3], double a1[3], double tol, double &t, double lineX[3], double ptX[3], vtkIdType &ptId)
vtkIdType GetNumberOfIds(vtkIdType bucketNum)
bool BucketIntersectsCircle(int i, int j, const double center[3], double R2)
void GetIds(vtkIdType bucketNum, vtkIdList *bList)
vtkIdType FindClosestPointWithinRadius(double radius, const double x[3], double inputDataLength, double &dist2)
vtkIdType FindClosestPoint(const double x[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)
Dispatch a single array against all array types mentioned in the ArrayList template parameter.
double Distance2ToBucket(const double x[3], const int nei[3])
void GetBucketBounds(int i, int j, double min[3], double max[3])
double Distance2ToBounds(const double x[3], const double bounds[6])
void GetBucketIndices(const double *x, int ij[2]) const
void GenerateFace(int face, int i, int j, int k, vtkPoints *pts, vtkCellArray *polys)
vtkIdType GetBucketIndex(const double *x) const
bool BucketInsideCircle(int i, int j, const double center[3], double r2)
virtual ~vtkBucketList2D()=default
vtkStaticPointLocator2D * Locator
virtual void BuildLocator()=0
void GetBucketCenter(int i, int j, double center[3])
void GetBucketNeighbors(NeighborBuckets2D *buckets, const int ij[2], const int ndivs[2], int level)
vtkBucketList2D(vtkStaticPointLocator2D *loc, vtkIdType numPts, int numBuckets)
void Initialize(int divs[3], int maxLevel)
vtkBucketPatchIterator()=default
vtkIdType Begin(int level, int center[2])
Represent an array of vtkDist2Tuples.
STL-compatible iterable ranges that provide access to vtkDataArray elements.
constexpr int vtkBucketPatchLevel3[24][2]
bool InsideCircle(const double min[2], const double max[2], const double center[2], double r2)
Performant method to determine if a box if fully inside a circle.
constexpr int vtkBucketPatchLevel4[32][2]
constexpr int vtkBucketPatchLevel2[16][2]
constexpr int vtkBucketPatchLevel1[8][2]
bool IntersectsCircle(const double min[2], const double max[2], const double center[2], double r2)
Performant method to intersect a box with a circle.
constexpr int vtkBucketPatchLevel5[40][2]
int vtkIdType
Definition vtkType.h:366
#define max(a, b)