variable_radius_offset.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> B1,B2;
  111. Eigen::VectorXi leaf;
  112. igl::eytzinger_aabb(PB1,PB2,B1,B2,leaf);
  113. const std::function<Scalar(const RowVector3S &)>
  114. sdf = [&](const RowVector3S & p) -> Scalar
  115. {
  116. const std::function<Scalar(const int)> primitive_p = [&](const int j)
  117. {
  118. return primitive(p,j);
  119. };
  120. Scalar f;
  121. igl::eytzinger_aabb_sdf<false>(p,primitive_p,B1,B2,leaf,f);
  122. return f;
  123. };
  124. const std::function<Scalar(const RowVector3S &)>
  125. udf = [&](const RowVector3S & p) -> Scalar
  126. {
  127. return std::abs(sdf(p));
  128. //// This made performance worse.
  129. //const std::function<Scalar(const int)> primitive_p = [&](const int j)
  130. //{
  131. // const Scalar d = udTriangle( V.row(F(j,0)), V.row(F(j,1)), V.row(F(j,2)), p);
  132. // const RowVector3S r(R(F(j,0)),R(F(j,1)),R(F(j,2)));
  133. // const Scalar min_r = r.minCoeff();
  134. // const Scalar max_r = r.maxCoeff();
  135. // if(d > max_r)
  136. // {
  137. // return d - max_r;
  138. // }else if(d < min_r)
  139. // {
  140. // return d - min_r;
  141. // }
  142. // return 0.0;
  143. //};
  144. //Scalar f;
  145. //igl::eytzinger_aabb_sdf(p,primitive_p,B1,B2,leaf,f);
  146. //return f;
  147. };
  148. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> ijk;
  149. igl::lipschitz_octree( origin,h0,max_depth,udf,ijk);
  150. {
  151. // Gather the corners of those leaf cells
  152. const Scalar h = h0 / (1 << max_depth);
  153. Eigen::Matrix<int,Eigen::Dynamic,8,Eigen::RowMajor> J;
  154. Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor> unique_ijk;
  155. Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor> unique_corner_positions;
  156. igl::unique_sparse_voxel_corners(origin,h0,max_depth,ijk,unique_ijk,J,unique_corner_positions);
  157. /// Evaluate the signed distance function at the corners
  158. Eigen::VectorXd S(unique_corner_positions.rows());
  159. //for(int u = 0;u<unique_corner_positions.rows();u++)
  160. igl::parallel_for(
  161. unique_corner_positions.rows(),
  162. [&](const int u)
  163. {
  164. // evaluate the function at the corner
  165. S(u) = sdf(unique_corner_positions.row(u));
  166. },1000);
  167. // Run marching cubes on the sparse set of leaf cells
  168. igl::marching_cubes( S,unique_corner_positions,J, 0, mV,mF);
  169. }
  170. }
  171. #ifdef IGL_STATIC_LIBRARY
  172. // Explicit template instantiation
  173. 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)>&);
  174. 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>>&);
  175. #endif