boundary_conditions.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
  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 "boundary_conditions.h"
  9. #include "verbose.h"
  10. #include "EPS.h"
  11. #include "project_to_line.h"
  12. #include <vector>
  13. #include <map>
  14. #include <iostream>
  15. IGL_INLINE bool igl::boundary_conditions(
  16. const Eigen::MatrixXd & V ,
  17. const Eigen::MatrixXi & /*Ele*/,
  18. const Eigen::MatrixXd & C ,
  19. const Eigen::VectorXi & P ,
  20. const Eigen::MatrixXi & BE ,
  21. const Eigen::MatrixXi & CE ,
  22. Eigen::VectorXi & b ,
  23. Eigen::MatrixXd & bc )
  24. {
  25. using namespace Eigen;
  26. using namespace std;
  27. if(P.size()+BE.rows() == 0)
  28. {
  29. verbose("^%s: Error: no handles found\n",__FUNCTION__);
  30. return false;
  31. }
  32. vector<int> bci;
  33. vector<int> bcj;
  34. vector<double> bcv;
  35. // loop over points
  36. for(int p = 0;p<P.size();p++)
  37. {
  38. VectorXd pos = C.row(P(p));
  39. // loop over domain vertices
  40. for(int i = 0;i<V.rows();i++)
  41. {
  42. // Find samples just on pos
  43. //Vec3 vi(V(i,0),V(i,1),V(i,2));
  44. // EIGEN GOTCHA:
  45. // double sqrd = (V.row(i)-pos).array().pow(2).sum();
  46. // Must first store in temporary
  47. VectorXd vi = V.row(i);
  48. double sqrd = (vi-pos).squaredNorm();
  49. if(sqrd <= FLOAT_EPS)
  50. {
  51. //cout<<"sum((["<<
  52. // V(i,0)<<" "<<
  53. // V(i,1)<<" "<<
  54. // V(i,2)<<"] - ["<<
  55. // pos(0)<<" "<<
  56. // pos(1)<<" "<<
  57. // pos(2)<<"]).^2) = "<<sqrd<<endl;
  58. bci.push_back(i);
  59. bcj.push_back(p);
  60. bcv.push_back(1.0);
  61. }
  62. }
  63. }
  64. // loop over bone edges
  65. for(int e = 0;e<BE.rows();e++)
  66. {
  67. // loop over domain vertices
  68. for(int i = 0;i<V.rows();i++)
  69. {
  70. // Find samples from tip up to tail
  71. VectorXd tip = C.row(BE(e,0));
  72. VectorXd tail = C.row(BE(e,1));
  73. // Compute parameter along bone and squared distance
  74. double t,sqrd;
  75. project_to_line(
  76. V(i,0),V(i,1),V(i,2),
  77. tip(0),tip(1),tip(2),
  78. tail(0),tail(1),tail(2),
  79. t,sqrd);
  80. if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
  81. {
  82. bci.push_back(i);
  83. bcj.push_back(P.size()+e);
  84. bcv.push_back(1.0);
  85. }
  86. }
  87. }
  88. // loop over cage edges
  89. for(int e = 0;e<CE.rows();e++)
  90. {
  91. // loop over domain vertices
  92. for(int i = 0;i<V.rows();i++)
  93. {
  94. // Find samples from tip up to tail
  95. VectorXd tip = C.row(P(CE(e,0)));
  96. VectorXd tail = C.row(P(CE(e,1)));
  97. // Compute parameter along bone and squared distance
  98. double t,sqrd;
  99. project_to_line(
  100. V(i,0),V(i,1),V(i,2),
  101. tip(0),tip(1),tip(2),
  102. tail(0),tail(1),tail(2),
  103. t,sqrd);
  104. if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
  105. {
  106. bci.push_back(i);
  107. bcj.push_back(CE(e,0));
  108. bcv.push_back(1.0-t);
  109. bci.push_back(i);
  110. bcj.push_back(CE(e,1));
  111. bcv.push_back(t);
  112. }
  113. }
  114. }
  115. // find unique boundary indices
  116. vector<int> vb = bci;
  117. sort(vb.begin(),vb.end());
  118. vb.erase(unique(vb.begin(), vb.end()), vb.end());
  119. b.resize(vb.size());
  120. bc = MatrixXd::Zero(vb.size(),P.size()+BE.rows());
  121. // Map from boundary index to index in boundary
  122. map<int,int> bim;
  123. int i = 0;
  124. // Also fill in b
  125. for(vector<int>::iterator bit = vb.begin();bit != vb.end();bit++)
  126. {
  127. b(i) = *bit;
  128. bim[*bit] = i;
  129. i++;
  130. }
  131. // Build BC
  132. for(i = 0;i < (int)bci.size();i++)
  133. {
  134. assert(bim.find(bci[i]) != bim.end());
  135. bc(bim[bci[i]],bcj[i]) = bcv[i];
  136. }
  137. // Normalize accross rows so that conditions sum to one
  138. for(i = 0;i<bc.rows();i++)
  139. {
  140. double sum = bc.row(i).sum();
  141. assert(sum != 0 && "Some boundary vertex getting all zero BCs");
  142. bc.row(i).array() /= sum;
  143. }
  144. if(bc.size() == 0)
  145. {
  146. verbose("^%s: Error: boundary conditions are empty.\n",__FUNCTION__);
  147. return false;
  148. }
  149. // If there's only a single boundary condition, the following tests
  150. // are overzealous.
  151. if(bc.cols() == 1)
  152. {
  153. // If there is only one weight function,
  154. // then we expect that there is only one handle.
  155. assert(P.rows() + BE.rows() == 1);
  156. return true;
  157. }
  158. // Check that every Weight function has at least one boundary value of 1 and
  159. // one value of 0
  160. for(i = 0;i<bc.cols();i++)
  161. {
  162. double min_abs_c = bc.col(i).array().abs().minCoeff();
  163. double max_c = bc.col(i).maxCoeff();
  164. if(min_abs_c > FLOAT_EPS)
  165. {
  166. verbose("^%s: Error: handle %d does not receive 0 weight\n",__FUNCTION__,i);
  167. return false;
  168. }
  169. if(max_c< (1-FLOAT_EPS))
  170. {
  171. verbose("^%s: Error: handle %d does not receive 1 weight\n",__FUNCTION__,i);
  172. return false;
  173. }
  174. }
  175. return true;
  176. }