boundary_conditions.cpp 4.7 KB

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