VTK  9.6.20260529
vtkSurfaceNets3DNonManifoldCases.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
589
590#ifndef vtkSurfaceNets3DNonManifoldCases_h
591#define vtkSurfaceNets3DNonManifoldCases_h
592
593#include "vtkFiltersCoreModule.h"
594#include "vtkSetGet.h"
595
596#include <array>
597#include <cstddef>
598#include <cstdint>
599
600VTK_ABI_NAMESPACE_BEGIN
601#define VTK_SURFACE_NETS_3D_ALWAYS_SPLIT_CASES_1_3
602// #define VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8
603class VTKFILTERSCORE_EXPORT vtkSurfaceNets3DNonManifoldCases
604{
605public:
606#ifdef VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8
607 static constexpr uint8_t MaxTableIndex = 9;
608#else
609 static constexpr uint8_t MaxTableIndex = 8;
610#endif
611 using NonManifoldCaseType = unsigned char;
612 using EdgeCaseType = unsigned short;
613 using VoxelCaseType = unsigned char;
614
630 {
633 bool IsHomogeneous = true;
634 std::array<int8_t, 12> PointIndices;
635 std::array<VoxelCaseType, 4> SubVoxelCases;
636 std::array<EdgeCaseType, 4> SubEdgeCases;
637 };
638
648 template <class T>
655
656 enum TableIndexValues : int8_t
657 {
663 NonManifoldIndex2 = 2, // Used only by NonManifoldCase 8
664 NonManifoldIndex3 = 3, // Used only by NonManifoldCase 8
665 NonManifoldIndex4 = 4, // Used only by NonManifoldCase 8
666 NonManifoldIndex5 = 5, // Used only by NonManifoldCase 8
667 NonManifoldIndex6 = 6, // Used only by NonManifoldCase 8
668 NonManifoldIndex7 = 7, // Used only by NonManifoldCase 8
669 NonManifoldIndex8 = 8, // Used only by NonManifoldCase 8
670#ifdef VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8
671 NonManifoldIndex9 = 9, // Used only by NonManifoldCase 8
672#endif
673 };
674
738 template <class T>
739 static auto GetNonManifoldTableIndex(const VoxelNeighborhood<T>& voxelNeighborhood) -> int8_t;
740
750 static VTK_ALWAYS_INLINE auto GetNumberOfNonManifoldCases(EdgeCaseType edgeCase) -> uint8_t
751 {
752 return EdgeCaseOffsets[edgeCase + 1] - EdgeCaseOffsets[edgeCase];
753 }
754
763 static VTK_ALWAYS_INLINE auto GetNonManifoldCase(EdgeCaseType edgeCase, int8_t tableIndex)
765 {
766 if (tableIndex < 0 || tableIndex >= GetNumberOfNonManifoldCases(edgeCase))
767 {
768 return 0; // manifold case
769 }
770 return NonManifoldMetadata[EdgeCaseOffsets[edgeCase] + tableIndex].NonManifoldCase;
771 }
772
783 static VTK_ALWAYS_INLINE auto GetNonManifoldBasicVoxelCase(
784 EdgeCaseType edgeCase, int8_t tableIndex) -> VoxelCaseType
785 {
786 return NonManifoldMetadata[EdgeCaseOffsets[edgeCase] + tableIndex].VoxelCase;
787 }
788
799 static VTK_ALWAYS_INLINE auto IsNonManifoldCaseHomogeneous(
800 EdgeCaseType edgeCase, int8_t tableIndex) -> NonManifoldCaseType
801 {
802 return NonManifoldMetadata[EdgeCaseOffsets[edgeCase] + tableIndex].IsHomogeneous;
803 }
804
814 static constexpr VTK_ALWAYS_INLINE auto GetNumberOfPoints(NonManifoldCaseType nonManifoldCase)
815 -> uint8_t
816 {
817 constexpr uint8_t pointsPerNonManifoldCase[12] = {
818 1, // case 0 is manifold, so 1 point (the center vertex) is generated
819 2 + 1, // case 1 has 1 duplicate point, so 2 points + 1 center point = 3 total
820 2 + 1, // case 2 has 1 duplicate point, so 2 points + 1 center point = 3 total
821 2 + 1, // case 3 has 1 duplicate point, so 2 points + 1 center point = 3 total
822 3 + 1, // case 4 has 2 duplicate points, so 3 points + 1 center point = 4 total
823 2 + 1, // case 5 has 1 duplicate point, so 2 points + 1 center point = 3 total
824 2 + 1, // case 6 has 1 duplicate point, so 2 points + 1 center point = 3 total
825 4 + 1, // case 7 has 3 duplicate points, so 4 points + 1 center point = 5 total
826 2 + 1, // case 8 has 1 duplicate point, so 2 points + 1 center point = 3 total
827 2 + 1, // case 9 has 1 duplicate point, so 2 points + 1 center point = 3 total
828 2 + 1, // case 10 has 1 duplicate point, so 2 points + 1 center point = 3 total
829 2 + 1, // case 11 has 1 duplicate point, so 2 points + 1 center point = 3 total
830 };
831 return pointsPerNonManifoldCase[nonManifoldCase];
832 }
833
851 template <uint8_t QuadId>
852 static VTK_ALWAYS_INLINE auto GetNonManiFoldPointIndex(EdgeCaseType edgeCase, int8_t tableIndex)
853 -> int8_t
854 {
855 static_assert(QuadId < 12, "QuadId must be between 0 and 11 (inclusive)");
856 return NonManifoldMetadata[EdgeCaseOffsets[edgeCase] + tableIndex].PointIndices[QuadId];
857 }
858
867 static constexpr VTK_ALWAYS_INLINE auto GetNumberOfManifoldSubCases(
868 NonManifoldCaseType nonManifoldCase) -> uint8_t
869 {
870 constexpr uint8_t subCasesPerNonManifoldCase[12] = {
871 1, // case 0 is manifold, so 1 point (the center vertex) is generated
872 2, // case 1 has 1 duplicate point, so 2 sub cases
873 2, // case 2 has 1 duplicate point, so 2 sub cases
874 2, // case 3 has 1 duplicate point, so 2 sub cases
875 3, // case 4 has 2 duplicate points, so 3 sub cases
876 2, // case 5 has 1 duplicate point, so 2 sub cases
877 2, // case 6 has 1 duplicate point, so 2 sub cases
878 4, // case 7 has 3 duplicate points, so 4 sub cases
879 2, // case 8 has 1 duplicate point, so 2 sub cases
880 2, // case 9 has 1 duplicate point, so 2 sub cases
881 2, // case 10 has 1 duplicate point, so 2 sub cases
882 2 // case 11 has 1 duplicate point, so 2 sub cases
883 };
884 return subCasesPerNonManifoldCase[nonManifoldCase];
885 }
886
896 static VTK_ALWAYS_INLINE auto GetManifoldSubEdgeCases(EdgeCaseType edgeCase, int8_t tableIndex)
897 -> const std::array<EdgeCaseType, 4>&
898 {
899 static constexpr std::array<EdgeCaseType, 4> Empty{};
900 if (tableIndex < 0)
901 {
902 return Empty;
903 }
904 return NonManifoldMetadata[EdgeCaseOffsets[edgeCase] + tableIndex].SubEdgeCases;
905 }
906
936 static constexpr VTK_ALWAYS_INLINE auto ComputeState(uint8_t numPoints, int8_t tableIndex)
937 -> uint8_t
938 {
939 switch (numPoints)
940 {
941 case 0:
942 return 0;
943 case 1:
944 return tableIndex == ManifoldIndex ? 1 : 2;
945 case 3:
946 return 3 + tableIndex; // Indices 0-MaxTableIndex map to 3...
947 case 4:
948 // If MaxTableIndex is 9, offset is 3 + 10 = 13
949 // If MaxTableIndex is 8, offset is 3 + 9 = 12
950 return 3 + (MaxTableIndex + 1) + tableIndex;
951 case 5:
952 // If MaxTableIndex is 9, offset is 13 + 2 = 15
953 // If MaxTableIndex is 8, offset is 12 + 2 = 14
954 return 3 + (MaxTableIndex + 1) + 2 + tableIndex;
955 default:
956 return 1;
957 }
958 }
959
965 {
966 // 0 (empty), 1 (manifold or unsolvable), 3, 4, or 5
967 uint8_t NumPoints;
968 // EmptyIndex, ManifoldIndex, NonManifoldIndexUnsolvable, or [0, MaxTableIndex]
970 };
971
982 static constexpr VTK_ALWAYS_INLINE auto GetStateInfo(uint8_t state) -> StateInfo
983 {
984#ifdef VTK_SURFACE_NETS_3D_SUPPORT_ALL_SOLVABLE_VARIATIONS_FOR_CASE_8
985 constexpr StateInfo InfoTable[17] = { { 0, EmptyIndex }, // 0: Empty
986 { 1, ManifoldIndex }, // 1: Manifold
987 { 1, NonManifoldIndexUnsolvable }, // 2: Non-Manifold (Unsolvable)
988 // 3-12: 3-point solvable (tableIndex 0-9)
992 { 3, NonManifoldIndex9 },
993 // 13-14: 4-point solvable (tableIndex 0-1)
995 // 15-16: 5-point solvable (tableIndex 0-1)
996 { 5, NonManifoldIndex0 }, { 5, NonManifoldIndex1 } };
997#else
998 constexpr StateInfo InfoTable[16] = { { 0, EmptyIndex }, // 0: Empty
999 { 1, ManifoldIndex }, // 1: Manifold
1000 { 1, NonManifoldIndexUnsolvable }, // 2: Non-Manifold (Unsolvable)
1001 // 3-11: 3-point solvable (tableIndex 0-8)
1005 // 12-13: 4-point solvable (tableIndex 0-1)
1006 { 4, NonManifoldIndex0 }, { 4, NonManifoldIndex1 },
1007 // 14-15: 5-point solvable (tableIndex 0-1)
1008 { 5, NonManifoldIndex0 }, { 5, NonManifoldIndex1 } };
1009#endif
1010 return InfoTable[state];
1011 }
1012
1013private:
1027 static VTK_ALWAYS_INLINE auto GetManifoldSubVoxelCases(EdgeCaseType edgeCase, int8_t tableIndex)
1028 -> const std::array<VoxelCaseType, 4>&
1029 {
1030 return NonManifoldMetadata[EdgeCaseOffsets[edgeCase] + tableIndex].SubVoxelCases;
1031 }
1032
1033 static const std::array<uint16_t, 4097>& EdgeCaseOffsets;
1034 static const std::array<NonManifoldCaseMetadata, 3736>& NonManifoldMetadata;
1035};
1036VTK_ABI_NAMESPACE_END
1037
1038#endif // vtkSurfaceNets3DNonManifoldCases_h
Provides utilities to identify vtkSurfaceNets3D's edge-cases that can lead to non-manifold output geo...
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 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...
static auto GetNonManifoldTableIndex(const VoxelNeighborhood< T > &voxelNeighborhood) -> int8_t
Returns the index into the non-manifold metadata table for the given voxel neighborhood,...
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),...
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 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 GetStateInfo(uint8_t state) -> StateInfo
Decodes both the number of duplicate points and the metadata table index from a state code in a singl...
static constexpr VTK_ALWAYS_INLINE auto GetNumberOfPoints(NonManifoldCaseType nonManifoldCase) -> uint8_t
Given the non-manifold case, returns the number of duplicate points.
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-manif...
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 GetNonManifoldBasicVoxelCase(EdgeCaseType edgeCase, int8_t tableIndex) -> VoxelCaseType
Given an edge case and the table index for the non-manifold case, returns the corresponding basic vox...
Decoded metadata for a state: number of points to generate and the corresponding non-manifold table i...
Holds the local configuration of the 8 voxels surrounding a triad point in the grid.