VTK  9.7.1
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
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 
600 VTK_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
603 class VTKFILTERSCORE_EXPORT vtkSurfaceNets3DNonManifoldCases
604 {
605 public:
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  {
631  NonManifoldCaseType NonManifoldCase = 0;
632  VoxelCaseType VoxelCase = 0;
633  bool IsHomogeneous = true;
634  std::array<int8_t, 12> PointIndices;
635  std::array<VoxelCaseType, 4> SubVoxelCases;
636  std::array<EdgeCaseType, 4> SubEdgeCases;
637  };
648  template <class T>
650  {
653  std::array<T, 8> Labels;
654  };
655 
656  enum TableIndexValues : int8_t
657  {
658  EmptyIndex = -3,
659  ManifoldIndex = -2,
660  NonManifoldIndexUnsolvable = -1,
661  NonManifoldIndex0 = 0,
662  NonManifoldIndex1 = 1,
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(
764  EdgeCaseType edgeCase, int8_t tableIndex) -> NonManifoldCaseType
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(
815  NonManifoldCaseType nonManifoldCase) -> 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(
853  EdgeCaseType edgeCase, int8_t tableIndex) -> 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(
897  EdgeCaseType edgeCase, int8_t tableIndex) -> 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(
937  uint8_t numPoints, int8_t tableIndex) -> 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 
964  struct StateInfo
965  {
966  // 0 (empty), 1 (manifold or unsolvable), 3, 4, or 5
967  uint8_t NumPoints;
968  // EmptyIndex, ManifoldIndex, NonManifoldIndexUnsolvable, or [0, MaxTableIndex]
969  int8_t TableIndex;
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)
989  { 3, NonManifoldIndex0 }, { 3, NonManifoldIndex1 }, { 3, NonManifoldIndex2 },
990  { 3, NonManifoldIndex3 }, { 3, NonManifoldIndex4 }, { 3, NonManifoldIndex5 },
991  { 3, NonManifoldIndex6 }, { 3, NonManifoldIndex7 }, { 3, NonManifoldIndex8 },
992  { 3, NonManifoldIndex9 },
993  // 13-14: 4-point solvable (tableIndex 0-1)
994  { 4, NonManifoldIndex0 }, { 4, NonManifoldIndex1 },
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)
1002  { 3, NonManifoldIndex0 }, { 3, NonManifoldIndex1 }, { 3, NonManifoldIndex2 },
1003  { 3, NonManifoldIndex3 }, { 3, NonManifoldIndex4 }, { 3, NonManifoldIndex5 },
1004  { 3, NonManifoldIndex6 }, { 3, NonManifoldIndex7 }, { 3, NonManifoldIndex8 },
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 
1013 private:
1027  static VTK_ALWAYS_INLINE auto GetManifoldSubVoxelCases(
1028  EdgeCaseType edgeCase, int8_t tableIndex) -> 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 };
1036 VTK_ABI_NAMESPACE_END
1037 
1038 #endif // vtkSurfaceNets3DNonManifoldCases_h
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 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 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...
VTKACCELERATORSVTKMDATAMODEL_EXPORT vtkIdType IsHomogeneous(vtkCellArray *cells)
Provides utilities to identify vtkSurfaceNets3D's edge-cases that can lead to non-manifold output geo...
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 singl...
static constexpr VTK_ALWAYS_INLINE auto GetNumberOfPoints(NonManifoldCaseType nonManifoldCase) -> uint8_t
Given the non-manifold case, returns the number of duplicate points.
Holds the local configuration of the 8 voxels surrounding a triad point in the grid.
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.
Decoded metadata for a state: number of points to generate and the corresponding non-manifold table i...
static VTK_ALWAYS_INLINE auto GetNumberOfNonManifoldCases(EdgeCaseType edgeCase) -> uint8_t
Returns the number of non-manifold metadata entries for the given edge case.
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...