variable_radius_offset.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2025 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 "variable_radius_offset.h"
  9. #include "SphereMeshWedge.h"
  10. #include "marching_cubes.h"
  11. #include "unique_sparse_voxel_corners.h"
  12. #include "lipschitz_octree.h"
  13. #include "eytzinger_aabb.h"
  14. #include "eytzinger_aabb_sdf.h"
  15. #include "get_seconds.h"
  16. #include "parallel_for.h"
  17. #include <cstdio>
  18. template <
  19. typename DerivedV,
  20. typename DerivedF,
  21. typename DerivedR,
  22. typename Derivedorigin,
  23. typename DerivedmV,
  24. typename DerivedmF>
  25. void igl::variable_radius_offset(
  26. const Eigen::MatrixBase<DerivedV> & V,
  27. const Eigen::MatrixBase<DerivedF> & F,
  28. const Eigen::MatrixBase<DerivedR> & R,
  29. const Eigen::MatrixBase<Derivedorigin> & origin,
  30. const typename Derivedorigin::Scalar h0,
  31. const int max_depth,
  32. Eigen::PlainObjectBase<DerivedmV> & mV,
  33. Eigen::PlainObjectBase<DerivedmF> & mF)
  34. {
  35. using Scalar = typename DerivedV::Scalar;
  36. Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> PB1,PB2;
  37. std::vector<igl::SphereMeshWedge<Scalar>> data;
  38. std::function<Scalar(const Eigen::Matrix<Scalar,1,3> &,const int i)> primitive;
  39. igl::variable_radius_offset(V,F,R,PB1,PB2,data,primitive);
  40. igl::variable_radius_offset(
  41. PB1,PB2,data,primitive,origin,h0,max_depth,mV,mF);
  42. }
  43. template <
  44. typename DerivedV,
  45. typename DerivedF,
  46. typename DerivedR,
  47. typename DerivedPB1,
  48. typename DerivedPB2,
  49. typename Scalar>
  50. void igl::variable_radius_offset(
  51. const Eigen::MatrixBase<DerivedV> & V,
  52. const Eigen::MatrixBase<DerivedF> & F,
  53. const Eigen::MatrixBase<DerivedR> & R,
  54. Eigen::PlainObjectBase<DerivedPB1> & PB1,
  55. Eigen::PlainObjectBase<DerivedPB2> & PB2,
  56. std::vector<igl::SphereMeshWedge<Scalar>> & data,
  57. std::function<Scalar(const Eigen::Matrix<Scalar,1,3> &,const int i)> &
  58. primitive)
  59. {
  60. // Bounds
  61. PB1.setConstant(F.rows(),3,std::numeric_limits<Scalar>::infinity());
  62. PB2.setConstant(F.rows(),3,-std::numeric_limits<Scalar>::infinity());
  63. for(int f = 0;f<F.rows();f++)
  64. {
  65. for(int c = 0;c<F.cols();c++)
  66. {
  67. for(int d = 0;d<V.cols();d++)
  68. {
  69. PB1(f,d) = std::min(PB1(f,d),V(F(f,c),d)-R(F(f,c)));
  70. PB2(f,d) = std::max(PB2(f,d),V(F(f,c),d)+R(F(f,c)));
  71. }
  72. }
  73. }
  74. // Precomputed data
  75. data.resize(F.rows());
  76. for(int f = 0;f<F.rows();f++)
  77. {
  78. data[f] = igl::SphereMeshWedge<Scalar>(
  79. V.row(F(f,0)),V.row(F(f,1)),V.row(F(f,2)),
  80. R(F(f,0)),R(F(f,1)),R(F(f,2)));
  81. }
  82. // I suppose primitive could just capture `data` by value. Then it owns the
  83. // data and we don't need to worry about `data` getting destroyed before its
  84. // called. I'm not sure how expensive that copy would be.
  85. primitive = [&](const Eigen::RowVector3d & p, const int i)
  86. {
  87. return data[i](p);
  88. };
  89. }
  90. template <
  91. typename DerivedPB1,
  92. typename DerivedPB2,
  93. typename Scalar,
  94. typename Derivedorigin,
  95. typename DerivedmV,
  96. typename DerivedmF>
  97. void igl::variable_radius_offset(
  98. const Eigen::MatrixBase<DerivedPB1> & PB1,
  99. const Eigen::MatrixBase<DerivedPB2> & PB2,
  100. const std::vector<igl::SphereMeshWedge<Scalar>> & data,
  101. const std::function<Scalar(const Eigen::Matrix<Scalar,1,3> &,const int i)> &
  102. primitive,
  103. const Eigen::MatrixBase<Derivedorigin> & origin,
  104. const Scalar h0,
  105. const int max_depth,
  106. Eigen::PlainObjectBase<DerivedmV> & mV,
  107. Eigen::PlainObjectBase<DerivedmF> & mF)
  108. {
  109. using RowVector3S = Eigen::Matrix<Scalar,1,3>;
  110. IGL_TICTOC_LAMBDA;
  111. tictoc();
  112. Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> B1,B2;
  113. Eigen::VectorXi leaf;
  114. igl::eytzinger_aabb(PB1,PB2,B1,B2,leaf);
  115. printf("%-20s: %g secs\n","eytzinger_aabb",tictoc());
  116. const std::function<Scalar(const RowVector3S &)>
  117. sdf = [&](const RowVector3S & p) -> Scalar
  118. {
  119. const std::function<Scalar(const int)> primitive_p = [&](const int j)
  120. {
  121. return primitive(p,j);
  122. };
  123. Scalar f;
  124. igl::eytzinger_aabb_sdf(p,primitive_p,B1,B2,leaf,f);
  125. return f;
  126. };
  127. const std::function<Scalar(const RowVector3S &)>
  128. udf = [&](const RowVector3S & p) -> Scalar
  129. {
  130. return std::abs(sdf(p));
  131. //// This made performance worse.
  132. //const std::function<Scalar(const int)> primitive_p = [&](const int j)
  133. //{
  134. // const Scalar d = udTriangle( V.row(F(j,0)), V.row(F(j,1)), V.row(F(j,2)), p);
  135. // const RowVector3S r(R(F(j,0)),R(F(j,1)),R(F(j,2)));
  136. // const Scalar min_r = r.minCoeff();
  137. // const Scalar max_r = r.maxCoeff();
  138. // if(d > max_r)
  139. // {
  140. // return d - max_r;
  141. // }else if(d < min_r)
  142. // {
  143. // return d - min_r;
  144. // }
  145. // return 0.0;
  146. //};
  147. //Scalar f;
  148. //igl::eytzinger_aabb_sdf(p,primitive_p,B1,B2,leaf,f);
  149. //return f;
  150. };
  151. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> ijk;
  152. igl::lipschitz_octree( origin,h0,max_depth,udf,ijk);
  153. printf("%-20s: %g secs\n","lipschitz_octree",tictoc());
  154. {
  155. tictoc();
  156. // Gather the corners of those leaf cells
  157. const Scalar h = h0 / (1 << max_depth);
  158. Eigen::Matrix<int,Eigen::Dynamic,8,Eigen::RowMajor> J;
  159. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> unique_ijk;
  160. Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> unique_corner_positions;
  161. igl::unique_sparse_voxel_corners(origin,h0,max_depth,ijk,unique_ijk,J,unique_corner_positions);
  162. //printf("unique_sparse_voxel_corners: %0.7f seconds\n",tictoc());
  163. printf("%-20s: %g secs\n","unique_sparse_vo...",tictoc());
  164. /// Evaluate the signed distance function at the corners
  165. Eigen::VectorXd S(unique_corner_positions.rows());
  166. //for(int u = 0;u<unique_corner_positions.rows();u++)
  167. igl::parallel_for(
  168. unique_corner_positions.rows(),
  169. [&](const int u)
  170. {
  171. // evaluate the function at the corner
  172. S(u) = sdf(unique_corner_positions.row(u));
  173. },1000);
  174. //printf(" sdf: %0.7f seconds\n",tictoc());
  175. printf("%-20s: %g secs\n","sdf",tictoc());
  176. // Run marching cubes on the sparse set of leaf cells
  177. igl::marching_cubes( S,unique_corner_positions,J, 0, mV,mF);
  178. //printf(" marching_cubes: %0.7f seconds\n",tictoc());
  179. printf("%-20s: %g secs\n","marching_cubes",tictoc());
  180. }
  181. }
  182. #ifdef IGL_STATIC_LIBRARY
  183. // Explicit template instantiation
  184. template void igl::variable_radius_offset<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&, std::vector<igl::SphereMeshWedge<double>, std::allocator<igl::SphereMeshWedge<double>>>&, std::function<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int)>&);
  185. template void igl::variable_radius_offset<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, 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::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3>> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3>::Scalar, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3>>&);
  186. #endif