VTK  9.7.20260828
vtkVoronoiCore.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
18
19#ifndef vtkVoronoiCore_h
20#define vtkVoronoiCore_h
21
22#include "vtkAlgorithm.h" // check abort status if embedded in filter
23#include "vtkIntArray.h" // for representing segmented region ids
24#include "vtkSMPTools.h" // SMP parallel processing
25
26#include <algorithm> // for std::sort
27#include <iostream>
28#include <random> // random generation of colors
29#include <vector>
30
31VTK_ABI_NAMESPACE_BEGIN
32
45
52{
53 BACKWARD_SPOKE = 0, // Bit 0: Backward spoke
54 FORWARD_SPOKE = 1, // Bit 0: Forward spoke
55 REGION_BOUNDARY = 2, // Bit 1: Region boundary spoke
56 DOMAIN_BOUNDARY = 4, // Bit 2: Domain boundary spoke
57 PRUNED = 8, // Bit 3: Spoke is pruned (deleted)
58};
59
64{
65 vtkIdType NeiId; // Id of the wheel that the spoke is connected to (wheelId,NeiId)
66 unsigned char Classification; // Indicate the classification of this spoke
68 : NeiId(-1)
70 {
71 }
72 vtkVoronoiSpoke(vtkIdType neiId, unsigned char classification)
73 : NeiId(neiId)
74 , Classification(classification)
75 {
76 }
77}; // vtkVoronoiSpoke
78
86using vtkVoronoiSpokesType = std::vector<vtkVoronoiSpoke>;
87using vtkVoronoiSpokesIterator = vtkVoronoiSpokesType::iterator;
88using vtkVoronoiWheelsType = std::vector<vtkIdType>;
89
90// Gather spokes into a wheel. Define some basic operators. Note that every
91// wheel is associated with an input (tile/hull generating) point. So access
92// to the wheel and its associated spokes is via point id.
94{
95 vtkVoronoiWheelsType& Wheels; // The composited array of wheels
96 vtkVoronoiSpokesType& Spokes; // The composited array of spokes
97 vtkIdType Id; // The associated point/tile id: with wheelId == pointId
98 int NumSpokes; // The number of emanating spokes
99 vtkVoronoiSpoke* LocalSpokes; // The array of spokes connected to this wheel
100
101 // Default instantiation.
103 : Wheels(wheels)
104 , Spokes(spokes)
105 , Id(-1)
106 , NumSpokes(0)
107 , LocalSpokes(nullptr)
108 {
109 }
110
111 // Setup the wheel for queries: an efficient form that does not require
112 // repeated wheel instantiation.
114 {
115 this->Id = id;
116 this->NumSpokes = numSpokes = (this->Wheels[id + 1] - this->Wheels[id]);
117 this->LocalSpokes =
118 ((size_t)this->Wheels[id] < this->Spokes.size() ? &(this->Spokes[this->Wheels[id]])
119 : nullptr);
120 return this->LocalSpokes;
121 }
122}; // vtkVoronoiWheel
123
132{
133 vtkVoronoiWheelsType Wheels; // Wheel/spokes data structure: offset array into spokes
134 vtkVoronoiSpokesType Spokes; // Spokes / edges with classification
135
136 void Initialize(vtkIdType numWheels, vtkIdType numSpokes);
137 vtkVoronoiWheelsType& GetWheels() { return this->Wheels; }
138 vtkVoronoiSpokesType& GetSpokes() { return this->Spokes; }
139 vtkIdType GetNumberOfWheels() { return (this->Wheels.size() - 1); }
140 vtkIdType GetNumberOfSpokes() { return this->Spokes.size(); }
142 vtkIdType GetNumberOfSpokes(vtkIdType ptId); // #spokes for a specified wheel
144 vtkIdType GetWheelOffset(vtkIdType ptId) { return this->Wheels[ptId]; }
145 static void CountFaces(const vtkVoronoiSpoke* spokes, int numSpokes, int& numDomainBoundaryFaces,
146 int& numRegionBoundaryFaces, int& numForwardFaces);
147
155 bool Validate();
156
161 {
164
166 : Graph(graph)
167 , NumInvalid(0)
168 {
169 }
170
171 // Keep track whether threads are non-degenerate.
173
174 // vtkSMPTools threaded interface
176 void operator()(vtkIdType wheelId, vtkIdType endWheelId);
177 void Reduce();
178 }; // ValidateAdjacencyGraph
179}; // vtkVoronoiAdjacencyGraph
180
185struct vtkVoronoiHullVertex // 3D hull vertices
186{
187 double X[3];
188 vtkVoronoiHullVertex(double x, double y, double z)
189 : X{ x, y, z }
190 {
191 }
192 vtkVoronoiHullVertex(const double x[3])
193 : X{ x[0], x[1], x[2] }
194 {
195 }
196};
197using vtkVoronoiHullVertexType = std::vector<vtkVoronoiHullVertex>;
198
199struct vtkVoronoiTileVertex // 2D tile vertices
200{
201 double X[2];
202 vtkVoronoiTileVertex(double x, double y)
203 : X{ x, y }
204 {
205 }
206 vtkVoronoiTileVertex(const double x[2])
207 : X{ x[0], x[1] }
208 {
209 }
210};
211using vtkVoronoiTileVertexType = std::vector<vtkVoronoiTileVertex>;
212
224{
229 std::array<vtkIdType, 4> Ids;
230
235 : Ids{ 0 }
236 {
237 }
238
243 : Ids{ p0, p1, p2, ptId }
244 {
245 std::sort(this->Ids.data(), this->Ids.data() + this->Ids.size());
246 }
247
250 vtkVoronoiTopoCoord3D(const vtkVoronoiTopoCoord3D& tt) { this->Ids = tt.Ids; }
251
257 bool operator<(const vtkVoronoiTopoCoord3D& tuple) const { return this->Ids < tuple.Ids; }
258};
259using vtkVoronoiTopoCoords3DType = std::vector<vtkVoronoiTopoCoord3D>;
260
262{
267 std::array<vtkIdType, 3> Ids;
268
273 : Ids{ 0 }
274 {
275 }
276
281 : Ids{ p0, p1, ptId }
282 {
283 std::sort(this->Ids.data(), this->Ids.data() + this->Ids.size());
284 }
285
288 vtkVoronoiTopoCoord2D(const vtkVoronoiTopoCoord2D& tt) { this->Ids = tt.Ids; }
289
295 bool operator<(const vtkVoronoiTopoCoord2D& tuple) const { return this->Ids < tuple.Ids; }
296};
297using vtkVoronoiTopoCoords2DType = std::vector<vtkVoronoiTopoCoord2D>;
298
307{
308 vtkIdType PtId; // the id of the hull vertex
309
311 : PtId(-1)
312 {
313 }
314 bool operator!=(const vtkVoronoiMergeTuple3D& mt) const { return (this->Ids != mt.Ids); }
315}; // vtkVoronoiMergeTuple3D
316
318{
319 vtkIdType PtId; // the id of the tile vertex
320
322 : PtId(-1)
323 {
324 }
325 bool operator!=(const vtkVoronoiMergeTuple2D& mt) const { return (this->Ids != mt.Ids); }
326}; // vtkVoronoiMergeTuple2D
327
334using vtkMergeTupleOffsets = std::vector<vtkIdType>; // offsets into merged tuples
335using vtkMergeTuples3DType = std::vector<vtkVoronoiMergeTuple3D>;
336using vtkMergeTuples2DType = std::vector<vtkVoronoiMergeTuple2D>;
337
343using vtkMergeMapType = std::vector<vtkIdType>;
344
348using vtkVoronoiCellConnType = std::vector<vtkIdType>;
349
355{
356 vtkIdType Num; // Number of total items (e.g., points) to process
357 vtkIdType BatchSize; // The desired batch size (clamped by Num)
358 vtkIdType NumBatches; // The total number of batches to process
360 : Num(num)
361 , BatchSize(batchSize)
362 {
363 this->NumBatches = static_cast<vtkIdType>(ceil(static_cast<double>(num) / batchSize));
364 }
365 vtkIdType GetNumberOfBatches() const { return this->NumBatches; }
366 vtkIdType GetBatchItemRange(vtkIdType batchNum, vtkIdType& startId, vtkIdType& endId) const
367 {
368 startId = batchNum * this->BatchSize;
369 endId = startId + this->BatchSize;
370 endId = (endId > this->Num ? this->Num : endId);
371 return (endId - startId);
372 }
373}; // vtkVoronoiBatchManager
374
379using vtkBatchIdsType = std::vector<vtkIdType>;
380
381// Convenience function: convert input labels/region ids/scalars to signed int.
382// The Voronoi classes expect signed int region labels.
384{
386 rIds->SetNumberOfTuples(inScalars->GetNumberOfTuples());
387 rIds->DeepCopy(inScalars);
388
389 return rIds;
390}
391
397{
401
403 : Filter(filter)
404 {
405 this->IsFirst = vtkSMPTools::GetSingleThread();
406 this->CheckAbortInterval = std::min((end - start) / 10 + 1, (vtkIdType)1000);
407 }
408
410 {
411 if (this->Filter && this->IsFirst && !(id % this->CheckAbortInterval))
412 {
413 this->Filter->CheckAbort();
414 return (this->Filter->GetAbortOutput() ? true : false);
415 }
416 return false;
417 }
418}; // vtkVoronoiAbortCheck
419
420// Use system <random> - create a simple convenience class. This generates
421// random color indices [0,64).
423{
424 std::mt19937 RNG;
425 std::uniform_int_distribution<int> Dist;
426 vtkVoronoiRandomColors() { this->Dist.param(decltype(this->Dist)::param_type(0, 64)); }
427 void Seed(vtkIdType s) { this->RNG.seed(s); }
428 vtkIdType Next() { return this->Dist(RNG); }
429};
430
431// Use system <random> - create a simple convenience class. This generates
432// random real values [0,1).
434{
435 std::mt19937 RNG;
436 std::uniform_real_distribution<double> Dist;
437 vtkVoronoiRandom01Range() { this->Dist.param(decltype(this->Dist)::param_type(0.0, 1.0)); }
438 void Seed(vtkIdType s) { this->RNG.seed(s); }
439 double Next() { return this->Dist(RNG); }
440};
441
442// A convenience class and methods to randomly perturb (alternatively:
443// joggle, jitter, or jiggle) point positions. Such jittering (even if very
444// small) significantly improves the numerical stability of Voronoi and
445// Delaunay computations. Terminology note: while joggle is not a widely used
446// term (typically in computer graphics the words perturb, jitter, and jiggle
447// are found more frequently), it is used by the popular QuickHull (and
448// associated implementation QHull qhull.org)--so the terminology was
449// adopted by this work. Implementation note: these methods might be better
450// added to vtkMath since they can be used by other classes. Once they are
451// demonstrated to be stable, they may be moved.
453{
454 // Joggle a single point at input position xIn to produce the output position
455 // xOut (xIn and xOut may be computed in-place). The radius is the allowable
456 // range of joggle in the sphere. A sequence is provided, assumed properly
457 // initialized, to produce random (0,1) values. Note that if this method is
458 // invoked in a thread, separate sequence instantiations (one per thread)
459 // should be provided.
460 static void JoggleXYZ(
461 double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range& sequence)
462 {
463 double cosphi = 1 - 2 * sequence.Next();
464 double sinphi = sqrt(1 - cosphi * cosphi);
465 double rho = radius * pow(sequence.Next(), 0.33333333);
466 double R = rho * sinphi;
467 double theta = 2.0 * vtkMath::Pi() * sequence.Next();
468 xOut[0] = xIn[0] + R * cos(theta);
469 xOut[1] = xIn[1] + R * sin(theta);
470 xOut[2] = xIn[2] + rho * cosphi;
471 }
472
473 // Joggle a single point at input position xIn to produce the output
474 // position xOut (xIn and xOut may be computed in-place). The radius is the
475 // allowable range of joggle in the circle in the x-y plane. A sequence is
476 // provided, assumed properly initialized, to produce random (0,1) values.
477 // Note that if this method is invoked in a thread, separate sequence
478 // instantiations (one per thread) should be provided.
479 static void JoggleXY(
480 double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range& sequence)
481 {
482 double R = radius * sequence.Next();
483 double theta = 2.0 * vtkMath::Pi() * sequence.Next();
484 xOut[0] = xIn[0] + R * cos(theta);
485 xOut[1] = xIn[1] + R * sin(theta);
486 xOut[2] = xIn[2];
487 }
488
489 // Joggle a single point at input position xIn to produce the output
490 // position xOut (xIn and xOut may be computed in-place). The radius is the
491 // allowable range of joggle in the circle in the x-z plane. A sequence is
492 // provided, assumed properly initialized, to produce random (0,1) values.
493 // Note that if this method is invoked in a thread, separate sequence
494 // instantiations (one per thread) should be provided.
495 static void JoggleXZ(
496 double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range& sequence)
497 {
498 double R = radius * sequence.Next();
499 double theta = 2.0 * vtkMath::Pi() * sequence.Next();
500 xOut[0] = xIn[0] + R * cos(theta);
501 xOut[1] = xIn[1];
502 xOut[2] = xIn[2] + R * sin(theta);
503 }
504
505 // Joggle a single point at input position xIn to produce the output
506 // position xOut (xIn and xOut may be computed in-place). The radius is the
507 // allowable range of joggle in the circle in the y-z plane. A sequence is
508 // provided, assumed properly initialized, to produce random (0,1) values.
509 // Note that if this method is invoked in a thread, separate sequence
510 // instantiations (one per thread) should be provided.
511 static void JoggleYZ(
512 double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range& sequence)
513 {
514 double R = radius * sequence.Next();
515 double theta = 2.0 * vtkMath::Pi() * sequence.Next();
516 xOut[0] = xIn[0];
517 xOut[1] = xIn[1] + R * cos(theta);
518 xOut[2] = xIn[2] + R * sin(theta);
519 }
520
521 // Joggle a 3D vector. Specify an input normalized vector (vecIn), a angle
522 // of rotation theta (in radians, 0<theta<Pi/2), and a random
523 // sequence. Produce on output a normalized vector (vecOut) -- vecIn and
524 // vecOut may be computed in place. Note that if this method is invoked in
525 // a thread, separate sequence instantiations (one per thread) should be
526 // provided. The approach used here is to define a disk located at the tip
527 // of the (normalized) vecIn (the disc is normal to vecIn), and randomly
528 // select a vector from the edge/along the perimeter of the disc.
529 static void JoggleNormal(
530 double vecIn[3], double vecOut[3], double theta, vtkVoronoiRandom01Range& sequence)
531 {
532 // Find a vector orthogonal to the input vector.
533 double perp[3];
534 int iMax = (std::fabs(vecIn[0]) > std::fabs(vecIn[1]) ? 0 : 1);
535 iMax = (std::fabs(vecIn[iMax]) > std::fabs(vecIn[2]) ? iMax : 2);
536 perp[(iMax + 1) % 3] = 1.0;
537 perp[(iMax + 2) % 3] = 0.0;
538 perp[iMax] = -(vecIn[(iMax + 1) % 3] / vecIn[iMax]);
539 vtkMath::Normalize(perp);
540
541 // Now find third orthogonal vector. Since vecIn and perp are normalized and
542 // orthogonal, the resultant cross also a unit vector.
543 double cross[3];
544 vtkMath::Cross(vecIn, perp, cross);
545
546 // Compute a random vector
547 double radius = theta / (2.0 * vtkMath::Pi()); // small angle approximation
548 double t = 2.0 * vtkMath::Pi() * sequence.Next();
549 double x = radius * cos(t);
550 double y = radius * sin(t);
551
552 // Construct a vector along the disc/cone edge
553 vecOut[0] = vecIn[0] + x * perp[0] + y * cross[0];
554 vecOut[1] = vecIn[1] + x * perp[1] + y * cross[1];
555 vecOut[2] = vecIn[2] + x * perp[2] + y * cross[2];
556 vtkMath::Normalize(vecOut);
557 }
558}; // vtkVoronoiJoggle
559
560VTK_ABI_NAMESPACE_END
561#include "vtkVoronoiCore.txx"
562
563#endif
564// VTK-HeaderTest-Exclude: vtkVoronoiCore.h
RealT mt
Definition PyrC2Basis.h:39
vtkIdType GetNumberOfTuples() const
Get the number of complete tuples (a component group) in the array.
bool CheckAbort()
Check to see if an input's ABORTED flag is set or if an upstream algorithm's AbortExecute is set.
virtual bool GetAbortOutput()
Set/Get an internal variable used to communicate between the algorithm and executive.
static constexpr double Pi()
A mathematical constant.
Definition vtkMath.h:227
static float Normalize(float v[3])
Normalize (in place) a 3-vector.
Definition vtkMath.h:1972
static void Cross(VectorT1 &&a, VectorT2 &&b, VectorT3 &c)
Cross product of two 3-vectors.
Definition vtkMath.h:2079
Allocate and hold a VTK object.
Definition vtkNew.h:168
Thread local storage for VTK objects.
static bool GetSingleThread()
Returns true if the given thread is specified thread for single scope.
Hold a reference to a vtkObjectBase instance.
vtkVoronoiAbortCheck(vtkIdType start, vtkIdType end, vtkAlgorithm *filter)
bool operator()(vtkIdType id)
vtkAlgorithm * Filter
ValidateAdjacencyGraph(vtkVoronoiAdjacencyGraph &graph)
void operator()(vtkIdType wheelId, vtkIdType endWheelId)
vtkSMPThreadLocal< vtkIdType > ThreadNumInvalid
The adjacency graph, a collection of wheels and spokes, is a topological construct that connects Voro...
vtkVoronoiWheelsType Wheels
vtkIdType GetNumberOfSpokes(vtkIdType ptId)
vtkVoronoiSpoke * GetSpokes(vtkIdType ptId, vtkIdType &numSpokes)
bool Validate()
Return true if the graph meets the conditions necessary to form a valid Voronoi tessellation.
vtkVoronoiWheelsType & GetWheels()
static void CountFaces(const vtkVoronoiSpoke *spokes, int numSpokes, int &numDomainBoundaryFaces, int &numRegionBoundaryFaces, int &numForwardFaces)
void Initialize(vtkIdType numWheels, vtkIdType numSpokes)
vtkVoronoiSpokesType Spokes
bool IsSpoke(vtkIdType pt0, vtkIdType pt1)
vtkIdType GetWheelOffset(vtkIdType ptId)
vtkVoronoiSpokesType & GetSpokes()
vtkIdType GetBatchItemRange(vtkIdType batchNum, vtkIdType &startId, vtkIdType &endId) const
vtkVoronoiBatchManager(vtkIdType num, vtkIdType batchSize)
vtkIdType GetNumberOfBatches() const
vtkVoronoiHullVertex(const double x[3])
vtkVoronoiHullVertex(double x, double y, double z)
static void JoggleNormal(double vecIn[3], double vecOut[3], double theta, vtkVoronoiRandom01Range &sequence)
static void JoggleXY(double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range &sequence)
static void JoggleXZ(double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range &sequence)
static void JoggleYZ(double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range &sequence)
static void JoggleXYZ(double xIn[3], double xOut[3], double radius, vtkVoronoiRandom01Range &sequence)
bool operator!=(const vtkVoronoiMergeTuple2D &mt) const
bool operator!=(const vtkVoronoiMergeTuple3D &mt) const
std::uniform_real_distribution< double > Dist
void Seed(vtkIdType s)
std::uniform_int_distribution< int > Dist
void Seed(vtkIdType s)
Typedefs and classes in support of the adjacency graph.
unsigned char Classification
vtkVoronoiSpoke(vtkIdType neiId, unsigned char classification)
vtkVoronoiTileVertex(double x, double y)
vtkVoronoiTileVertex(const double x[2])
vtkVoronoiTopoCoord2D(vtkIdType p0, vtkIdType p1, vtkIdType ptId)
Define with the N+1 point generators: the N generators producing the hull vertex, plus the current po...
vtkVoronoiTopoCoord2D()
Various flavors of constructors.
vtkVoronoiTopoCoord2D(const vtkVoronoiTopoCoord2D &tt)
Copy constructor assumes that tuple ids are already sorted.
bool operator<(const vtkVoronoiTopoCoord2D &tuple) const
Operator< used to support a subsequent sort operation of the n-tuples (used for uniquely identifying ...
std::array< vtkIdType, 3 > Ids
Points defining a topological coord tuple / Delaunay simplex.
vtkVoronoiTopoCoord3D()
Various flavors of constructors.
bool operator<(const vtkVoronoiTopoCoord3D &tuple) const
Operator< used to support a subsequent sort operation of the n-tuples (used for uniquely identifying ...
std::array< vtkIdType, 4 > Ids
Points defining a topological coord tuple / Delaunay simplex.
vtkVoronoiTopoCoord3D(vtkIdType p0, vtkIdType p1, vtkIdType p2, vtkIdType ptId)
Define with the N+1 point generators: the N generators producing the hull vertex, plus the current po...
vtkVoronoiTopoCoord3D(const vtkVoronoiTopoCoord3D &tt)
Copy constructor assumes that tuple ids are already sorted.
vtkVoronoiSpoke * LocalSpokes
vtkVoronoiSpokesType & Spokes
vtkVoronoiWheel(vtkVoronoiWheelsType &wheels, vtkVoronoiSpokesType &spokes)
vtkVoronoiSpoke * Initialize(vtkIdType id, int &numSpokes)
vtkVoronoiWheelsType & Wheels
#define vtkDataArray
int vtkIdType
Definition vtkType.h:363
std::vector< vtkVoronoiTopoCoord2D > vtkVoronoiTopoCoords2DType
std::vector< vtkIdType > vtkVoronoiCellConnType
Convenience type for representing cell connectivity during compositing.
std::vector< vtkIdType > vtkBatchIdsType
Keep track of batches of generating points.
std::vector< vtkIdType > vtkMergeMapType
When merging points, the merge map is a vector that maps global tile/hull vertex ids (which contain d...
std::vector< vtkIdType > vtkVoronoiWheelsType
std::vector< vtkVoronoiSpoke > vtkVoronoiSpokesType
The vtkVoronoiWheelsType vector is used to keep track of the number of spokes (and equivalently,...
ClipIntersectionStatus
Classes, structs, and typedefs in support of Voronoi processing.
vtkSmartPointer< vtkIntArray > ConvertRegionLabels(vtkDataArray *inScalars)
vtkVoronoiSpokesType::iterator vtkVoronoiSpokesIterator
std::vector< vtkVoronoiHullVertex > vtkVoronoiHullVertexType
std::vector< vtkVoronoiMergeTuple3D > vtkMergeTuples3DType
vtkSpokeClassification
Classification for Voronoi spokes (and associated faces).
@ BACKWARD_SPOKE
@ PRUNED
@ DOMAIN_BOUNDARY
@ FORWARD_SPOKE
@ REGION_BOUNDARY
std::vector< vtkVoronoiMergeTuple2D > vtkMergeTuples2DType
std::vector< vtkVoronoiTopoCoord3D > vtkVoronoiTopoCoords3DType
std::vector< vtkIdType > vtkMergeTupleOffsets
Global tile/hull vertices, with duplicates, that are assigned a global id (if point merging is perfor...
std::vector< vtkVoronoiTileVertex > vtkVoronoiTileVertexType
#define vtkAlgorithm