|
VTK
9.6.20260529
|
Provides utilities to identify vtkSurfaceNets3D's edge-cases that can lead to non-manifold output geometry, and to resolve them by creating duplicate points. More...
#include <vtkSurfaceNets3DNonManifoldCases.h>
Classes | |
| struct | NonManifoldCaseMetadata |
| For non-manifold edge cases: More... | |
| struct | StateInfo |
| Decoded metadata for a state: number of points to generate and the corresponding non-manifold table index. More... | |
| struct | VoxelNeighborhood |
| Holds the local configuration of the 8 voxels surrounding a triad point in the grid. More... | |
Public Types | |
| enum | TableIndexValues : int8_t { EmptyIndex = -3 , ManifoldIndex = -2 , NonManifoldIndexUnsolvable = -1 , NonManifoldIndex0 = 0 , NonManifoldIndex1 = 1 , NonManifoldIndex2 = 2 , NonManifoldIndex3 = 3 , NonManifoldIndex4 = 4 , NonManifoldIndex5 = 5 , NonManifoldIndex6 = 6 , NonManifoldIndex7 = 7 , NonManifoldIndex8 = 8 } |
| using | NonManifoldCaseType = unsigned char |
| using | EdgeCaseType = unsigned short |
| using | VoxelCaseType = unsigned char |
Static Public Member Functions | |
| template<class T> | |
| static auto | GetNonManifoldTableIndex (const VoxelNeighborhood< T > &voxelNeighborhood) -> int8_t |
| Returns the index into the non-manifold metadata table for the given voxel neighborhood, or a special sentinel value if the neighborhood is manifold or unresolvable. | |
| static VTK_ALWAYS_INLINE auto | GetNumberOfNonManifoldCases (EdgeCaseType edgeCase) -> uint8_t |
| Returns the number of non-manifold metadata entries for the given edge case. | |
| static VTK_ALWAYS_INLINE auto | GetNonManifoldCase (EdgeCaseType edgeCase, int8_t tableIndex) -> NonManifoldCaseType |
| Given an edge case and the table index for the non-manifold case, returns the corresponding non-manifold case index, where 0 means manifold. | |
| static VTK_ALWAYS_INLINE auto | GetNonManifoldBasicVoxelCase (EdgeCaseType edgeCase, int8_t tableIndex) -> VoxelCaseType |
| Given an edge case and the table index for the non-manifold case, returns the corresponding basic voxel case bitmask for the corresponding non-manifold configuration. | |
| static VTK_ALWAYS_INLINE auto | IsNonManifoldCaseHomogeneous (EdgeCaseType edgeCase, int8_t tableIndex) -> NonManifoldCaseType |
| Given an edge case and the table index for the non-manifold case, returns whether it's homogeneous or not. | |
| static constexpr VTK_ALWAYS_INLINE auto | GetNumberOfPoints (NonManifoldCaseType nonManifoldCase) -> uint8_t |
| Given the non-manifold case, returns the number of duplicate points. | |
| template<uint8_t QuadId> | |
| static VTK_ALWAYS_INLINE auto | GetNonManiFoldPointIndex (EdgeCaseType edgeCase, int8_t tableIndex) -> int8_t |
| Given a quad id (bits 0–3 for yz-plane quads, 4–7 for xz-plane, 8–11 for xy-plane), and the table index for the non-manifold case, returns the duplicate point index for that quad in the current non-manifold configuration. | |
| static constexpr VTK_ALWAYS_INLINE auto | GetNumberOfManifoldSubCases (NonManifoldCaseType nonManifoldCase) -> uint8_t |
| Given the non-manifold case, returns the number of manifold sub-cases. | |
| static VTK_ALWAYS_INLINE auto | GetManifoldSubEdgeCases (EdgeCaseType edgeCase, int8_t tableIndex) -> const std::array< EdgeCaseType, 4 > & |
| Returns the manifold sub-edge cases for a given edge case and table index. | |
| static constexpr VTK_ALWAYS_INLINE auto | ComputeState (uint8_t numPoints, int8_t tableIndex) -> uint8_t |
| Computes a state code from a point count and table index using a variable-width linear mapping. | |
| static constexpr VTK_ALWAYS_INLINE auto | GetStateInfo (uint8_t state) -> StateInfo |
| Decodes both the number of duplicate points and the metadata table index from a state code in a single table lookup. | |
Static Public Attributes | |
| static constexpr uint8_t | MaxTableIndex = 8 |
Provides utilities to identify vtkSurfaceNets3D's edge-cases that can lead to non-manifold output geometry, and to resolve them by creating duplicate points.
vtkSurfaceNets3D performs dual contouring on a 3D segmented multi-material image to generate a surface mesh using the Flying Edges approach. As the name implies, the Flying Edges approach goes through the edges of the input grid, instead of the voxels, to determine how the output geometry should be generated.
Assuming you are at the center of a 2x2x2 grid of voxels, an edge case has 12 bits describing which of the 12 possible faces between the voxels will be generated or not. A face is generated if a voxel either does not have a neighboring voxel in a particular direction (i.e., it has a voxel with a background label), or if it has a neighboring voxel with a different label. In the latter case, the generated face is shared by the two voxels, and is generated only once.
In contrast, the more traditional Marching Cubes performs contouring (not dual) and goes through the voxels of the input grid. As the name implies, it generates voxel cases, instead of edge cases, to determine how to generate the output geometry.
Assuming you are at the center of a 2x2x2 grid of voxels, a voxel case has 8 bits describing which of the 8 voxels are present in the case (i.e., have a non-background label).
Both the flying edges approach used by SurfaceNets and the marching cubes approach can lead to non-manifold output geometry for certain configurations of voxels.
A manifold surface mesh is one where every edge is shared by exactly two faces and every vertex has a single connected ring of faces around it, meaning the mesh locally resembles a flat disk at every point, with no holes, gaps, or self-intersections.
An open-manifold surface mesh relaxes this definition by allowing boundary edges — edges shared by only one face. It locally resembles a flat disk at interior vertices and a half-disk at boundary vertices.
Since vtkSurfaceNets3D does not cap boundary faces, voxels at the image boundary generate boundary edges, so the resulting surface mesh cannot be strictly manifold. The best we can do is attempt to improve local topology (towards open-manifold behavior) in regions where the local voxel/material configuration is solvable.
Furthermore, since vtkSurfaceNets3D generates faces shared between voxels of different non-background labels, any open-manifold objective is meaningful only per label region: if you extract the faces corresponding to a single label from the output mesh, that sub-mesh is what we try to keep open-manifold where possible. When a configuration cannot be resolved, this class reports it as such and vtkSurfaceNets3D may still produce non-manifold output.
In "Parallel hexahedral meshing from volume fractions", Steven J. Owen, Matthew L. Staten, Marguerite C. Sorensen (https://doi.org/10.1007/s00366-012-0292-8), seven canonical voxel configurations (ignoring different orientations) are described for a 2×2×2 grid of voxels, which can lead to generating a non-manifold surface mesh.
Before describing these cases, let's first provide some mathematical background necessary to understand them and compute all their various rotated/reflected variants.
We work in a 3D binary grid: {0,1}^3 → There are exactly 8 possible coordinates: (x,y,z) with x,y,z ∈ {0,1}. → Each coordinate triple represents the position of a voxel in a 2×2×2 cube.
Hamming distance definition: d_H(a,b) = number of coordinates where a != b.
For k chosen voxels:
The sorted distance signature is permutation-invariant and acts as a shape descriptor in the binary cube space. Each non-manifold case (case1...case11) is defined by a unique signature:
Case 1: Two voxels are at opposite corners (body diagonal). Example: voxels at (0,0,0) and (1,1,1).
Pseudo-3D view: · · · ■ (back layer z=1) ■ · (front layer z=0) · ·
Case 2: Two voxels are diagonally adjacent across a face (no shared edge). Example: voxels at (0,0,0) and (1,0,1).
Pseudo-3D view: · · ■ · ■ · · ·
Case 3: Three voxels where, one pair shares a face, one pair shares only a vertex, and one pair is opposite corners. Shape looks like an "L" but spans entire cube. Example: voxels at (0,0,0), (1,0,0), and (1,1,1).
Pseudo-3D view: · · · ■ ■ ■ · ·
Case 4: Three voxels arranged so that all three share a common edge, but no common face, i.e. Forms an equilateral triangle in the cube. Example: voxels at (0,0,1), (1,0,0), and (0,1,0).
Pseudo-3D view: ■ · · · · ■ ■ ·
Case 5: Four voxels with two face-adjacent pairs, two vertex-adjacent pairs, and two body diagonals. Shape is like a bent rectangle spanning the cube. Example: voxels at (0,0,0), (0,0,1), (1,1,0), and (1,1,1).
Pseudo-3D view: ■ · · ■ ■ · · ■
Case 6: Four voxels where three lie in the same horizontal layer and are face-adjacent in an L-shape, and the fourth is above one corner, touching the others only along edges. Example: voxels at (0,0,1), (1,0,0), (0,1,0), and (1,1,0).
Pseudo-3D view: ■ · · · · ■ ■ ■
Case 7: Four voxels placed so each shares exactly three edges with the others, forming a twisted diagonal pattern through the grid. Example: voxels at (0,0,1), (1,0,0), (0,1,0), and (1,1,1).
Pseudo-3D view: ■ · · ■ · ■ ■ ·
We also have the complementary cases of non-manifold cases 1-4, which are not mentioned in the paper but can be derived by inverting the binary grid (i.e., swapping filled and empty voxels).
Case 8: Complement of Case 4. Five voxels fill the cube leaving three empty voxels that form an equilateral triangle (all pairwise distances equal 2). The three empty voxels each touch only diagonally, creating non-manifold edges throughout the surface. Example: all voxels except (0,0,1),(1,0,0),(0,1,0), i.e. (0,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1).
Pseudo-3D view: ■ ■ · ■ (back layer z=1) · ■ (front layer z=0) ■ ·
Case 9: Complement of Case 3. Five voxels fill the cube leaving three empty voxels whose distances are [1,2,3] — one face-adjacent pair, one edge-diagonal pair, and one body-diagonal pair. The empty region spans the full cube, creating a non-manifold edge. Example: all voxels except (0,0,0),(1,0,0),(1,1,1), i.e. (0,0,1),(0,1,0),(0,1,1),(1,0,1),(1,1,0).
Pseudo-3D view: ■ · ■ ■ (back layer z=1) ■ ■ (front layer z=0) · ·
Case 10: Complement of Case 2. Six voxels fill the cube leaving two face-diagonal voxels empty. The two empty voxels touch only at an edge, creating a non-manifold edge where four faces meet. Example: all voxels except (0,0,0) and (1,0,1), i.e. (0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,1,0),(1,1,1).
Pseudo-3D view: ■ ■ ■ · (back layer z=1) ■ ■ (front layer z=0) · ■
Case 11: Complement of Case 1. Six voxels fill the cube leaving two opposite corners (body diagonal) empty. The two empty voxels are at opposite corners, so the surface pinches at two vertices forming a non-manifold bowtie through the solid. Example: all voxels except (0,0,0) and (1,1,1), i.e. (0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0).
Pseudo-3D view: ■ · ■ ■ (back layer z=1) ■ ■ (front layer z=0) · ■
Beyond the 11 non-manifold cases above, there exist 10 additional voxel configurations that are geometrically manifold when all active voxels share the same material, but can produce non-manifold edge cases when two or more active voxels carry different material labels. These are referred to as manifold cases 12-21.
Case 12: Single voxel — only one active voxel in the cube. Example: voxel at (0,0,0).
Pseudo-3D view: · · · · (back layer z=1) ■ · (front layer z=0) · ·
Case 13: Two face-adjacent voxels. Example: voxels at (0,0,0) and (1,0,0).
Pseudo-3D view: · · · · (back layer z=1) ■ ■ (front layer z=0) · ·
Case 14: Three voxels in a gamma (L) shape — two face-adjacent pairs sharing a common voxel, with the two end voxels edge-adjacent. Example: voxels at (0,0,0), (1,0,0), and (0,1,0).
Pseudo-3D view: · · · · (back layer z=1) ■ ■ (front layer z=0) ■ ·
Case 15: Four voxels forming a 2x2 square in one plane. Example: voxels at (0,0,0), (1,0,0), (0,1,0), and (1,1,0).
Pseudo-3D view: · · · · (back layer z=1) ■ ■ (front layer z=0) ■ ■
Case 16: Four voxels in a T-shape — three face-adjacent in a row, with the fourth attached face-adjacent to the middle one. Example: voxels at (0,0,0), (1,0,0), (0,1,0), and (0,0,1).
Pseudo-3D view: ■ · · · (back layer z=1) ■ ■ (front layer z=0) ■ ·
Case 17: Four voxels in a zigzag chain — three sequential face-adjacent pairs forming a 3D chain. Example: voxels at (0,0,0), (1,0,0), (1,1,0), and (1,1,1).
Pseudo-3D view: · · · ■ (back layer z=1) ■ ■ (front layer z=0) · ■
Case 18: Five voxels — four forming a 2x2 square in one plane, with the fifth attached face-adjacent to one corner of the square. Example: voxels at (0,0,0),(1,0,0),(0,1,0),(1,1,0),(0,0,1).
Pseudo-3D view: ■ · · · (back layer z=1) ■ ■ (front layer z=0) ■ ■
Case 19: Six voxels forming an L-shape spanning two layers. Example: voxels at (0,0,0),(1,0,0),(0,1,0),(1,1,0),(0,0,1),(1,0,1).
Pseudo-3D view: ■ ■ · · (back layer z=1) ■ ■ (front layer z=0) ■ ■
Case 20: Seven voxels — all eight corners of the cube except one. Example: all voxels except (1,1,1).
Pseudo-3D view: ■ ■ ■ · (back layer z=1) ■ ■ (front layer z=0) ■ ■
Case 21: Eight voxels — all eight corners of the cube active. Example: all voxels at (0,0,0) through (1,1,1).
Pseudo-3D view: ■ ■ ■ ■ (back layer z=1) ■ ■ (front layer z=0) ■ ■
Non-manifold cases 1-11 can produce non-manifold configurations in two ways:
The same applies to manifold cases 12-21: even though they are geometrically manifold, non-homogeneous material assignments can create sub-voxel configurations that match one of the 11 non-manifold cases, producing a non-manifold edge case.
This class resolves non-manifold output by duplicating the point generated at a triad and assigning the faces around that triad to different duplicate points. The key question is: for a given local configuration, which faces should be grouped together (share the same point) to improve local topology (ideally open-manifold per label region) when the configuration is solvable?
We use the following terminology:
Normal/Primary split: the split pattern obtained from a given basic voxel configuration by grouping its active voxels into face-connected components (Hamming distance 1) and assigning each generated face to the component that produced it.
Not every case has a normal/primary split:
Complementary split: some non-manifold situations have a complementary split via its complementary voxel configuration (the occupancy complement inside the 2×2×2 cube).
Complementary splits are not always available:
Important: a voxel configuration and its paired complementary configuration can map to the same 12-bit edge case. Since the lookup table is keyed by edge case, both split patterns may appear in the same metadata span for that edge case as separate entries. In practice, such pairs are usually stored as the first two entries for the edge case (table indices 0 and 1), and the complementary split is selected by swapping between them.
The complementary split matters mainly for homogeneous material assignments: if all active voxels belong to the same label region, using the complementary split can avoid creating artificial separations inside that region while still resolving the non-manifold topology.
vtkSurfaceNets3D’s “flying edges” traversal produces, at each triad point, a compact local description of the 2×2×2 voxel neighborhood:
The same edge case can arise from many different voxel cases and many different material assignments, and only some of those assignments are actually non-manifold. To make runtime resolution fast, this class precomputes a sparse lookup table that, for each edge case that can be non-manifold, provides one or more candidate entries.
Conceptually, each candidate entry corresponds to a basic voxel configuration (and possibly a material-driven variation) and provides a split pattern: how to assign generated faces to duplicate point indices, plus per-component sub-configurations used for manifold processing and smoothing.
Table generation (high level):
The result is sparse: most of the 4096 theoretical 12-bit edge cases are either geometrically unreachable or always manifold, and therefore have no metadata entries.
Sparsity statistics (informational):
Table-index outcome statistics (informational):
At runtime, GetNonManifoldTableIndex() decides whether the neighborhood is:
ManifoldIndex) → no point duplication is needed.NonManifoldIndexUnsolvable) → the material assignment creates a non-manifold junction that cannot be eliminated using the available split patterns.The returned table index is a local indicator for a single triad neighborhood. Whether the final surface contains an observable non-manifold edge/vertex can depend on how neighboring triads are resolved. In particular, a neighborhood that is marked as unresolvable may still not create a non-manifold artifact in the final mesh if adjacent neighborhoods introduce compatible point duplications that avoid the problematic connectivity.
A practical sufficient condition for full resolvability is local homogeneity: if, for every triad neighborhood, all active voxels share the same label (for example, a single-material segmentation, or multiple materials that never meet at a triad), then GetNonManifoldTableIndex() will never return NonManifoldIndexUnsolvable. In that scenario, all detected non-manifold situations are handled through the geometric split patterns, and the resulting surface for each label region is guaranteed to be open-manifold. If label regions are disjoint (do not share faces), the full output mesh is likewise open-manifold as a disjoint union of those regions.
Conceptually, the runtime decision has three stages:
In terms of “when is a configuration solvable?”, the implementation applies these rules:
IsSplitSufficientForColorEncodedVoxelCase().Note: when VTK_SURFACE_NETS_3D_ALWAYS_SPLIT_CASES_1_3 is enabled, cases 1–3 are treated as non-manifold and are always split regardless of material labels (these patterns are typically interpreted as sampling artifacts without a meaningful continuous analogue).
Once a non-negative table index has been selected, the corresponding metadata entry provides:
PointIndices[12].SubVoxelCases / SubEdgeCases) for processing each component independently.Only points are duplicated (faces are not): the intent is to improve local topology per label region without duplicating geometry across labels. Duplicating faces would replicate the same geometric face into multiple label regions. By duplicating points instead, label regions can be separated topologically while shared faces between different labels remain geometrically coincident.
Given that we can resolve a subset of non-manifold neighborhoods by splitting them into manifold sub-configurations, the next step is to apply smoothing to improve the geometric quality of the output surface. For each point in the output mesh, a smoothing stencil defines which neighboring points it should be averaged with to compute its smoothed position.
To resolve a non-manifold edge case, we split its voxel configuration into face-connected groups, yielding sub-configurations each with their own sub edge case and sub voxel case. Since each sub-configuration is manifold, it can be processed independently to generate a well-defined smoothing stencil for its corresponding duplicate point.
For non-manifold edge cases, we generate stencils for two kinds of points:
The stencil for the non-manifold point is needed because, when a neighboring point's stencil needs to connect to a duplicated point, rather than arbitrarily choosing one duplicate, it connects to the non-manifold point whose position is averaged by points included in all sub-configurations. This ensures that the smoothing operation is consistent across groups and keeps all duplicate points geometrically close to each other after smoothing.
(Material-aware split selection is part of the GetNonManifoldTableIndex() decision: when the labels for the basic voxel case are homogeneous and an alternate grouping exists in the metadata table, the lookup can flip to that alternate split to avoid introducing artificial separations inside a single material region.)
Definition at line 603 of file vtkSurfaceNets3DNonManifoldCases.h.
| using vtkSurfaceNets3DNonManifoldCases::NonManifoldCaseType = unsigned char |
Definition at line 611 of file vtkSurfaceNets3DNonManifoldCases.h.
| using vtkSurfaceNets3DNonManifoldCases::EdgeCaseType = unsigned short |
Definition at line 612 of file vtkSurfaceNets3DNonManifoldCases.h.
| using vtkSurfaceNets3DNonManifoldCases::VoxelCaseType = unsigned char |
Definition at line 613 of file vtkSurfaceNets3DNonManifoldCases.h.
| enum vtkSurfaceNets3DNonManifoldCases::TableIndexValues : int8_t |
Definition at line 656 of file vtkSurfaceNets3DNonManifoldCases.h.
|
static |
Returns the index into the non-manifold metadata table for the given voxel neighborhood, or a special sentinel value if the neighborhood is manifold or unresolvable.
The lookup proceeds as follows:
If the voxel config matches one of the 11 non-manifold cases: a. If cases 1-3 (VTK_SURFACE_NETS_3D_ALWAYS_SPLIT_CASES_1_3): → always return table index 0 which represents the normal/primary split. b. If the configuration is homogeneous (all active voxels share the same material): i. If a complementary split exists (cases 4-11): → return the complementary split (swap between the paired entries, typically table indices 0 and 1) to support contiguous same-material flow. ii. Else if a normal/primary split exists (cases 1-8): → return the normal/primary split for the basic voxel case. c. Else if a sub-voxel non-manifold configuration exists: i. If the sub-voxel edge case equals the current edge case: → if a complementary split of the sub-voxel exists (cases 4-11): return the complementary split of the sub-voxel case. ii. Else if the sub-voxel edge case is a subset of the current edge case: → if normal splits exist for both sub-voxel (cases 1-8) and basic (cases 1-8):
Notes:
| T | The type of the material labels (e.g., uint8_t). |
| voxelNeighborhood | The voxel neighborhood containing the edge case, voxel case bitmask, and material labels at the 8 cube corners. |
|
inlinestatic |
Returns the number of non-manifold metadata entries for the given edge case.
Returns 0 if the edge case has no non-manifold configurations.
| edgeCase | The 12-bit edge case to query. |
Definition at line 750 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestatic |
Given an edge case and the table index for the non-manifold case, returns the corresponding non-manifold case index, where 0 means manifold.
| edgeCase | A 12-bit edge case bitmask. |
| tableIndex | The index in the non-manifold cases table for the given edge case |
Definition at line 763 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestatic |
Given an edge case and the table index for the non-manifold case, returns the corresponding basic voxel case bitmask for the corresponding non-manifold configuration.
The basic voxel case is an 8-bit bitmask where each bit indicates whether the corresponding voxel corner is present in the non-manifold configuration.
| edgeCase | A 12-bit edge case bitmask. |
| tableIndex | The index in the non-manifold cases table for the given edge case |
Definition at line 783 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestatic |
Given an edge case and the table index for the non-manifold case, returns whether it's homogeneous or not.
Homogeneous means that all active corners of the basic voxel case share the same material label.
| edgeCase | A 12-bit edge case bitmask. |
| tableIndex | The index in the non-manifold cases table for the given edge case |
Definition at line 799 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestaticconstexpr |
Given the non-manifold case, returns the number of duplicate points.
This is equal to the number of face-connected groups plus one additional point used as a stencil point for smoothing. For manifold cases (index 0), this is 1 (no duplicate points, no smoothing stencil needed).
| nonManifoldCase | The non-manifold case index in [0, 11], where 0 means manifold. |
Definition at line 814 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestatic |
Given a quad id (bits 0–3 for yz-plane quads, 4–7 for xz-plane, 8–11 for xy-plane), and the table index for the non-manifold case, returns the duplicate point index for that quad in the current non-manifold configuration.
The duplicate point index identifies which connected component the voxels generating that face belong to. Components are formed by splitting all populated voxels in the 2x2x2 grid into connected components where two voxels are directly connected if their Hamming distance is exactly 1. Note that voxels within the same component do not need to be directly connected to each other — they only need to be reachable through a path of direct connections.
| QuadId | Index of the quad (face-bit position) in [0, 11]. |
| edgeCase | A 12-bit edge case bitmask. |
| tableIndex | The index in the non-manifold cases table for the given edge case of a non-manifold case, false otherwise. |
Definition at line 852 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestaticconstexpr |
Given the non-manifold case, returns the number of manifold sub-cases.
Each sub-case corresponds to one face-connected group of voxels that needs to be processed independently to resolve the non-manifold configuration. For manifold cases (index 0), this is 1.
| nonManifoldCase | The non-manifold case index in [0, 11], where 0 means manifold. |
Definition at line 867 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestatic |
Returns the manifold sub-edge cases for a given edge case and table index.
Each sub-edge case is a 12-bit mask representing the faces belonging to one face-connected group of voxels. Unused sub-cases are zero.
| edgeCase | A 12-bit edge case bitmask. |
| tableIndex | The index into the non-manifold metadata table for this edge case. |
Definition at line 896 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestaticconstexpr |
Computes a state code from a point count and table index using a variable-width linear mapping.
The state space is partitioned by point count, with offsets for the 4-point and 5-point groups calculated dynamically using MaxTableIndex to ensure the 3-point group is fully utilized.
State space layout (without VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8): State 0: Empty voxel (numPoints=0, EmptyIndex) State 1: Manifold point (numPoints=1, ManifoldIndex) State 2: Unsolvable non-manifold point (numPoints=1, NonManifoldIndexUnsolvable) States 3-11: 3-point solvable non-manifold (tableIndex 0-8, MaxTableIndex=8) States 12-13: 4-point solvable non-manifold (tableIndex 0-1) States 14-15: 5-point solvable non-manifold (tableIndex 0-1) Maximum state: 15
State space layout (with VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8): State 0: Empty voxel (numPoints=0, EmptyIndex) State 1: Manifold point (numPoints=1, ManifoldIndex) State 2: Unsolvable non-manifold point (numPoints=1, NonManifoldIndexUnsolvable) States 3-12: 3-point solvable non-manifold (tableIndex 0-9, MaxTableIndex=9) States 13-14: 4-point solvable non-manifold (tableIndex 0-1) States 15-16: 5-point solvable non-manifold (tableIndex 0-1) Maximum state: 16
| numPoints | The number of duplicate points to generate (0, 1, 3, 4, or 5). |
| tableIndex | The metadata table index (EmptyIndex, ManifoldIndex, NonManifoldIndexUnsolvable, or 0 to MaxTableIndex). |
Definition at line 936 of file vtkSurfaceNets3DNonManifoldCases.h.
|
inlinestaticconstexpr |
Decodes both the number of duplicate points and the metadata table index from a state code in a single table lookup.
| state | The state code computed via ComputeState. Valid range: [0, 15] without VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8, or [0, 16] with it. |
Definition at line 982 of file vtkSurfaceNets3DNonManifoldCases.h.
|
staticconstexpr |
Definition at line 609 of file vtkSurfaceNets3DNonManifoldCases.h.