march_cube.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2021 Alec Jacobson <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "march_cube.h"
  9. #include <cstdint>
  10. // Something bad is happening when I made this a function. Maybe
  11. // something is not inlining? It ends up 1.25× slower than if the code is pasted
  12. // into the respective functions in igl::marching_cubes
  13. //
  14. // Even if I make it a lambda with no arguments (all capture by reference [&])
  15. // and call it immediately I get a 1.25× slow-down.
  16. //
  17. // Maybe keeping it out of a function allows the compiler to optimize with the
  18. // loop? But then I guess that measn this function is not getting inlined? Or
  19. // that it's not getting optimized after inlining?
  20. //
  21. template <
  22. typename DerivedGV,
  23. typename Scalar,
  24. typename Index,
  25. typename DerivedV,
  26. typename DerivedF>
  27. IGL_INLINE void igl::march_cube(
  28. const DerivedGV & GV,
  29. const Eigen::Matrix<Scalar,8,1> & cS,
  30. const Eigen::Matrix<Index,8,1> & cI,
  31. const Scalar & isovalue,
  32. Eigen::PlainObjectBase<DerivedV> &V,
  33. Index & n,
  34. Eigen::PlainObjectBase<DerivedF> &F,
  35. Index & m,
  36. std::unordered_map<std::int64_t,int> & E2V)
  37. {
  38. // These consts get stored reasonably
  39. #include "marching_cubes_tables.h"
  40. // Seems this is also successfully inlined
  41. //
  42. // Returns whether the vertex is new
  43. const auto ij2vertex =
  44. [&E2V,&V,&n]
  45. (const Index & i, const Index & j, Index & v)->bool
  46. {
  47. // Seems this is successfully inlined.
  48. const auto ij2key = [](std::int32_t i,std::int32_t j)
  49. {
  50. if(i>j){ std::swap(i,j); }
  51. std::int64_t ret = 0;
  52. ret |= i;
  53. ret |= static_cast<std::int64_t>(j) << 32;
  54. return ret;
  55. };
  56. const auto key = ij2key(i,j);
  57. const auto it = E2V.find(key);
  58. if(it == E2V.end())
  59. {
  60. // new vertex
  61. if(n==V.rows()){ V.conservativeResize(V.rows()*2+1,V.cols()); }
  62. v = n;
  63. E2V[key] = v;
  64. n++;
  65. return true;
  66. }else
  67. {
  68. v = it->second;
  69. return false;
  70. }
  71. };
  72. int c_flags = 0;
  73. for(int c = 0; c < 8; c++)
  74. {
  75. if(cS(c) > isovalue){ c_flags |= 1<<c; }
  76. }
  77. //Find which edges are intersected by the surface
  78. int e_flags = aiCubeEdgeFlags[c_flags];
  79. //If the cube is entirely inside or outside of the surface, then there will be no intersections
  80. if(e_flags == 0) { return; }
  81. //Find the point of intersection of the surface with each edge
  82. //Then find the normal to the surface at those points
  83. Eigen::Matrix<Index,12,1> edge_vertices;
  84. for(int e = 0; e < 12; e++)
  85. {
  86. #ifndef NDEBUG
  87. edge_vertices[e] = -1;
  88. #endif
  89. //if there is an intersection on this edge
  90. if(e_flags & (1<<e))
  91. {
  92. // record global index into local table
  93. const Index & i = cI(a2eConnection[e][0]);
  94. const Index & j = cI(a2eConnection[e][1]);
  95. Index & v = edge_vertices[e];
  96. if(ij2vertex(i,j,v))
  97. {
  98. // find crossing point assuming linear interpolation along edges
  99. const Scalar & a = cS(a2eConnection[e][0]);
  100. const Scalar & b = cS(a2eConnection[e][1]);
  101. // This t is being recomputed each time an edge is seen.
  102. Scalar t;
  103. const Scalar delta = b-a;
  104. if(delta == 0) { t = 0.5; }
  105. t = (isovalue - a)/delta;
  106. V.row(v) = GV.row(i) + t*(GV.row(j) - GV.row(i));
  107. }
  108. assert(v >= 0);
  109. assert(v < n);
  110. }
  111. }
  112. // Insert the triangles that were found. There can be up to five per cube
  113. for(int f = 0; f < 5; f++)
  114. {
  115. if(a2fConnectionTable[c_flags][3*f] < 0) break;
  116. if(m==F.rows()){ F.conservativeResize(F.rows()*2+1,F.cols()); }
  117. assert(edge_vertices[a2fConnectionTable[c_flags][3*f+0]]>=0);
  118. assert(edge_vertices[a2fConnectionTable[c_flags][3*f+1]]>=0);
  119. assert(edge_vertices[a2fConnectionTable[c_flags][3*f+2]]>=0);
  120. F.row(m) <<
  121. edge_vertices[a2fConnectionTable[c_flags][3*f+0]],
  122. edge_vertices[a2fConnectionTable[c_flags][3*f+1]],
  123. edge_vertices[a2fConnectionTable[c_flags][3*f+2]];
  124. m++;
  125. }
  126. }
  127. #ifdef IGL_STATIC_LIBRARY
  128. // Explicit template instantiation
  129. // generated by autoexplicit.sh
  130. template void igl::march_cube<Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>, double, long, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>> const&, Eigen::Matrix<double, 8, 1, 0, 8, 1> const&, Eigen::Matrix<long, 8, 1, 0, 8, 1> const&, double const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>>&, long&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3>>&, long&, std::unordered_map<std::int64_t, int, std::hash<std::int64_t>, std::equal_to<std::int64_t>, std::allocator<std::pair<std::int64_t const, int>>>&);
  131. template void igl::march_cube<Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >, float, unsigned int, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<float, 8, 1, 0, 8, 1> const&, Eigen::Matrix<unsigned int, 8, 1, 0, 8, 1> const&, float const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, unsigned int&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, unsigned int&, std::unordered_map<std::int64_t, int, std::hash<std::int64_t>, std::equal_to<std::int64_t>, std::allocator<std::pair<std::int64_t const, int> > >&);
  132. template void igl::march_cube<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, double, unsigned int, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 8, 1, 0, 8, 1> const&, Eigen::Matrix<unsigned int, 8, 1, 0, 8, 1> const&, double const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, unsigned int&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, unsigned int&, std::unordered_map<std::int64_t, int, std::hash<std::int64_t>, std::equal_to<std::int64_t>, std::allocator<std::pair<std::int64_t const, int> > >&);
  133. template void igl::march_cube<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, double, long, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 8, 1, 0, 8, 1> const&, Eigen::Matrix<long, 8, 1, 0, 8, 1> const&, double const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, long&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, long&, std::unordered_map<std::int64_t, int, std::hash<std::int64_t>, std::equal_to<std::int64_t>, std::allocator<std::pair<std::int64_t const, int> > >&);
  134. template void igl::march_cube<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, double, unsigned int, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 8, 1, 0, 8, 1> const&, Eigen::Matrix<unsigned int, 8, 1, 0, 8, 1> const&, double const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, unsigned int&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, unsigned int&, std::unordered_map<std::int64_t, int, std::hash<std::int64_t>, std::equal_to<std::int64_t>, std::allocator<std::pair<std::int64_t const, int> > >&);
  135. #ifdef WIN32
  136. template void __cdecl igl::march_cube<class Eigen::MatrixBase<class Eigen::Matrix<double,-1,3,1,-1,3> >,double,__int64,class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,3,0,-1,3> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,3,1,-1,3> > const &,class Eigen::Matrix<double,8,1,0,8,1> const &,class Eigen::Matrix<__int64,8,1,0,8,1> const &,double const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &,__int64 &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,3,0,-1,3> > &,__int64 &,class std::unordered_map<__int64,int,struct std::hash<__int64>,struct std::equal_to<__int64>,class std::allocator<struct std::pair<__int64 const ,int> > > &);
  137. template void __cdecl igl::march_cube<class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> >,double,__int64,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::Matrix<double,8,1,0,8,1> const &,class Eigen::Matrix<__int64,8,1,0,8,1> const &,double const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > &,__int64 &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > &,__int64 &,class std::unordered_map<__int64,int,struct std::hash<__int64>,struct std::equal_to<__int64>,class std::allocator<struct std::pair<__int64 const ,int> > > &);
  138. #endif
  139. #endif