point_cubic_squared_distance.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include "point_cubic_squared_distance.h"
  2. #include "../parallel_for.h"
  3. #include "../cubic.h"
  4. #include "../cubic_monomial_bases.h"
  5. #include <cyPolynomial.h>
  6. #include <limits>
  7. template <
  8. typename DerivedQ,
  9. typename DerivedC,
  10. typename DerivedsqrD,
  11. typename DerivedS,
  12. typename DerivedK>
  13. void igl::cycodebase::point_cubic_squared_distance(
  14. const Eigen::MatrixBase<DerivedQ>& Q,
  15. const Eigen::MatrixBase<DerivedC>& C,
  16. Eigen::PlainObjectBase<DerivedsqrD>& sqrD,
  17. Eigen::PlainObjectBase<DerivedS>& S,
  18. Eigen::PlainObjectBase<DerivedK>& K)
  19. {
  20. using Scalar = typename DerivedQ::Scalar;
  21. constexpr int ColsAtCompileTime = DerivedQ::ColsAtCompileTime;
  22. const int dim = C.cols();
  23. assert(C.rows() == 4 && "C should be 4 x dim.");
  24. assert(Q.cols() == dim && "Q and C should have the same number of columns.");
  25. // min_t ‖ Q - C(t) ‖^2
  26. //
  27. // Necessary condition for a minimum:
  28. //
  29. // d/dt ‖ Q - C(t) ‖^2 = 0
  30. // => d/dt (Q - C(t)) · (Q - C(t)) = 0
  31. // => -2 (dC/dt) · (Q - C(t)) = 0
  32. // => (dC/dt) · (C(t) - Q) = f(t) = 0
  33. //
  34. using RowVectorSD = Eigen::RowVector<Scalar,ColsAtCompileTime>;
  35. using MatrixS4D = Eigen::Matrix<Scalar,4,ColsAtCompileTime>;
  36. using MatrixS3D = Eigen::Matrix<Scalar,3,ColsAtCompileTime>;
  37. MatrixS4D M;
  38. MatrixS3D D;
  39. Eigen::RowVector<Scalar,6> B;
  40. cubic_monomial_bases(C, M, D, B);
  41. return point_cubic_squared_distance( Q, C, D, B, sqrD, S, K);
  42. }
  43. template <
  44. typename DerivedQ,
  45. typename DerivedC,
  46. typename DerivedD,
  47. typename DerivedB,
  48. typename DerivedsqrD,
  49. typename DerivedS,
  50. typename DerivedK>
  51. void igl::cycodebase::point_cubic_squared_distance(
  52. const Eigen::MatrixBase<DerivedQ>& Q,
  53. const Eigen::MatrixBase<DerivedC>& C,
  54. const Eigen::MatrixBase<DerivedD>& D,
  55. const Eigen::MatrixBase<DerivedB>& B,
  56. Eigen::PlainObjectBase<DerivedsqrD>& sqrD,
  57. Eigen::PlainObjectBase<DerivedS>& S,
  58. Eigen::PlainObjectBase<DerivedK>& K)
  59. {
  60. // static assert that C has 4 rows or Dynamic
  61. static_assert(
  62. DerivedC::RowsAtCompileTime == 4 ||
  63. DerivedC::RowsAtCompileTime == Eigen::Dynamic,
  64. "C must have 4 rows.");
  65. // runtime assert that C has 4 rows
  66. assert(C.rows() == 4 && "C must have 4 rows.");
  67. using Scalar = typename DerivedQ::Scalar;
  68. constexpr int ColsAtCompileTime = DerivedQ::ColsAtCompileTime;
  69. const int dim = C.cols();
  70. using RowVectorSD = Eigen::RowVector<Scalar,ColsAtCompileTime>;
  71. sqrD.setConstant(Q.rows(),1,std::numeric_limits<Scalar>::infinity());
  72. S.resize(Q.rows());
  73. K.resize(Q.rows(),dim);
  74. const int n = Q.rows();
  75. for(int i = 0;i<n;i++)
  76. igl::parallel_for(n,[&](const int i)
  77. {
  78. RowVectorSD k_i;
  79. const RowVectorSD q_i = Q.row(i);
  80. point_cubic_squared_distance( q_i, C, D, B, sqrD(i), S(i), k_i);
  81. K.row(i) = k_i;
  82. }
  83. ,1000);
  84. }
  85. template <
  86. typename Derivedq,
  87. typename DerivedC,
  88. typename DerivedD,
  89. typename DerivedB,
  90. typename Derivedk
  91. >
  92. void igl::cycodebase::point_cubic_squared_distance(
  93. const Eigen::MatrixBase<Derivedq>& q,
  94. const Eigen::MatrixBase<DerivedC>& C,
  95. const Eigen::MatrixBase<DerivedD>& D,
  96. const Eigen::MatrixBase<DerivedB>& B,
  97. typename Derivedq::Scalar& sqrD,
  98. typename Derivedq::Scalar& s,
  99. Eigen::PlainObjectBase<Derivedk>& k)
  100. {
  101. using cy::PolynomialRoots;
  102. using Scalar = typename Derivedq::Scalar;
  103. const int dim = C.cols();
  104. // static assert that C has 4 rows or Dynamic
  105. static_assert(
  106. DerivedC::RowsAtCompileTime == 4 ||
  107. DerivedC::RowsAtCompileTime == Eigen::Dynamic,
  108. "C must have 4 rows.");
  109. assert(C.rows() == 4 && "C should be 4 x dim.");
  110. assert(q.cols() == dim && "q and C should have the same number of columns.");
  111. typedef Eigen::Matrix<Scalar,1,Derivedq::ColsAtCompileTime> RowVectorSD;
  112. // Fill in coefficients using precomputed data and Q
  113. // => (dC/dt) · (C(t) - Q) = f(t) = 0
  114. //
  115. // C(t) = (1-t)^3 C0 + 3(1-t)^2 t C1 + 3(1-t) t^2 C2 + t^3 C3
  116. // C(t) = C0 + t⋅3(C1 - C0) + t^2⋅3(C0 - 2C1 + C2) + t^3⋅(C3 - C0 + 3(C1 - C2))
  117. // dC/dt = 3(C1 - C0) + t⋅6(C0 - 2C1 + C2) + t^2⋅3(C3 - C0 + 3(C1 - C2))
  118. Eigen::RowVector<Scalar,6> coef = B;
  119. for (int j = 0; j < 3; ++j)
  120. {
  121. coef(j) -= D.row(j).dot(q);
  122. }
  123. sqrD = std::numeric_limits<Scalar>::infinity();
  124. // f is a quintic polynomial:
  125. constexpr int N = 5;
  126. Scalar r[N];
  127. int nr = PolynomialRoots<N>(r, coef.data(),Scalar(0),Scalar(1));
  128. for(int j = 0;j<nr+2;j++)
  129. {
  130. Scalar t;
  131. if(j==nr)
  132. {
  133. t = Scalar(0);
  134. }
  135. else if(j==nr+1)
  136. {
  137. t = Scalar(1);
  138. }else
  139. {
  140. t = r[j];
  141. }
  142. RowVectorSD Ct;
  143. igl::cubic(C,t,Ct);
  144. const Scalar sqrD_j = (Ct - q).squaredNorm();
  145. if(sqrD_j < sqrD)
  146. {
  147. sqrD = sqrD_j;
  148. s = t;
  149. k = Ct;
  150. }
  151. }
  152. }
  153. template <
  154. typename Derivedq,
  155. typename DerivedC,
  156. typename Derivedk
  157. >
  158. void igl::cycodebase::point_cubic_squared_distance(
  159. const Eigen::MatrixBase<Derivedq>& q,
  160. const Eigen::MatrixBase<DerivedC>& C,
  161. typename Derivedq::Scalar& sqrD,
  162. typename Derivedq::Scalar& s,
  163. Eigen::PlainObjectBase<Derivedk>& k)
  164. {
  165. using Scalar = typename Derivedq::Scalar;
  166. constexpr int ColsAtCompileTime = Derivedq::ColsAtCompileTime;
  167. static_assert(
  168. DerivedC::RowsAtCompileTime == 4 ||
  169. DerivedC::RowsAtCompileTime == Eigen::Dynamic,
  170. "C must have 4 rows.");
  171. static_assert(
  172. int(Derivedq::ColsAtCompileTime) == int(DerivedC::ColsAtCompileTime),
  173. "q and C must have the same number of columns.");
  174. const int dim = C.cols();
  175. assert(C.rows() == 4 && "C should be 4 x dim.");
  176. assert(q.cols() == dim && "q and C should have the same number of columns.");
  177. using RowVectorSD = Eigen::RowVector<Scalar,ColsAtCompileTime>;
  178. using MatrixS4D = Eigen::Matrix<Scalar,4,ColsAtCompileTime>;
  179. using MatrixS3D = Eigen::Matrix<Scalar,3,ColsAtCompileTime>;
  180. MatrixS4D M;
  181. MatrixS3D D;
  182. Eigen::RowVector<Scalar,6> B;
  183. cubic_monomial_bases(C, M, D, B);
  184. return point_cubic_squared_distance( q, C, D, B, sqrD, s, k);
  185. }
  186. #ifdef IGL_STATIC_LIBRARY
  187. // Explicit template instantiation
  188. template void igl::cycodebase::point_cubic_squared_distance<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 3, -1, 0, 3, -1>, Eigen::Matrix<double, 6, 1, 0, 6, 1>, Eigen::Matrix<double, 1, -1, 1, 1, -1>>(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, -1, 0, 3, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, 6, 1, 0, 6, 1>> const&, Eigen::Matrix<double, 1, -1, 1, 1, -1>::Scalar&, Eigen::Matrix<double, 1, -1, 1, 1, -1>::Scalar&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1>>&);
  189. template void igl::cycodebase::point_cubic_squared_distance<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 4, -1, 0, 4, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1>>(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, 4, -1, 0, 4, -1>> const&, Eigen::Matrix<double, 1, -1, 1, 1, -1>::Scalar&, Eigen::Matrix<double, 1, -1, 1, 1, -1>::Scalar&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1>>&);
  190. template void igl::cycodebase::point_cubic_squared_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&);
  191. #endif