minkowski_sum.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #include "minkowski_sum.h"
  2. #include "mesh_boolean.h"
  3. #include "../../slice_mask.h"
  4. #include "../../unique.h"
  5. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  6. template <
  7. typename DerivedV,
  8. typename DerivedF,
  9. typename Deriveds,
  10. typename Derivedd,
  11. typename DerivedW,
  12. typename DerivedG,
  13. typename DerivedJ>
  14. IGL_INLINE void igl::copyleft::boolean::minkowski_sum(
  15. const Eigen::PlainObjectBase<DerivedV> & V,
  16. const Eigen::PlainObjectBase<DerivedF> & F,
  17. const Eigen::PlainObjectBase<Deriveds> & s,
  18. const Eigen::PlainObjectBase<Derivedd> & d,
  19. const bool resolve_overlaps,
  20. Eigen::PlainObjectBase<DerivedW> & W,
  21. Eigen::PlainObjectBase<DerivedG> & G,
  22. Eigen::PlainObjectBase<DerivedJ> & J)
  23. {
  24. using namespace Eigen;
  25. using namespace std;
  26. // silly base case
  27. if(F.size() == 0)
  28. {
  29. W.resize(0,3);
  30. G.resize(0,3);
  31. return;
  32. }
  33. const int dim = V.cols();
  34. assert(dim == 3 && "dim must be 3D");
  35. assert(s.size() == 3 && "s must be 3D point");
  36. assert(d.size() == 3 && "d must be 3D point");
  37. // segment vector
  38. const CGAL::Vector_3<CGAL::Epeck> v(d(0)-s(0),d(1)-s(1),d(2)-s(2));
  39. // number of vertices
  40. const int n = V.rows();
  41. // duplicate vertices at s and d, we'll remove unreferernced later
  42. DerivedW WW(2*n,dim);
  43. for(int i = 0;i<n;i++)
  44. {
  45. for(int j = 0;j<dim;j++)
  46. {
  47. WW (i,j) = V(i,j) + s(j);
  48. WW(i+n,j) = V(i,j) + d(j);
  49. }
  50. }
  51. // number of faces
  52. const int m = F.rows();
  53. // Mask whether positive dot product, or negative: because of exactly zero,
  54. // these are not necessarily complementary
  55. Matrix<bool,Dynamic,1> P(m,1),N(m,1);
  56. // loop over faces
  57. int mp = 0,mn = 0;
  58. for(int f = 0;f<m;f++)
  59. {
  60. const CGAL::Plane_3<CGAL::Epeck> plane(
  61. CGAL::Point_3<CGAL::Epeck>(V(F(f,0),0),V(F(f,0),1),V(F(f,0),2)),
  62. CGAL::Point_3<CGAL::Epeck>(V(F(f,1),0),V(F(f,1),1),V(F(f,1),2)),
  63. CGAL::Point_3<CGAL::Epeck>(V(F(f,2),0),V(F(f,2),1),V(F(f,2),2)));
  64. const auto normal = plane.orthogonal_vector();
  65. const auto dt = normal * v;
  66. if(dt > 0)
  67. {
  68. P(f) = true;
  69. N(f) = false;
  70. mp++;
  71. }else if(dt < 0)
  72. {
  73. P(f) = false;
  74. N(f) = true;
  75. mn++;
  76. }else
  77. {
  78. P(f) = false;
  79. N(f) = false;
  80. }
  81. }
  82. typedef Matrix<typename DerivedG::Scalar,Dynamic,Dynamic> MatrixXI;
  83. typedef Matrix<typename DerivedG::Scalar,Dynamic,1> VectorXI;
  84. MatrixXI GT(mp+mn,3);
  85. GT<< slice_mask(F,N,1), slice_mask((F.array()+n).eval(),P,1);
  86. // J indexes F for parts at s and m+F for parts at d
  87. J = DerivedJ::LinSpaced(m,0,m-1);
  88. DerivedJ JT(mp+mn);
  89. JT << slice_mask(J,P,1), slice_mask(J,N,1);
  90. JT.block(mp,0,mn,1).array()+=m;
  91. // Original non-co-planar faces with positively oriented reversed
  92. MatrixXI BA(mp+mn,3);
  93. BA << slice_mask(F,P,1).rowwise().reverse(), slice_mask(F,N,1);
  94. // Quads along **all** sides
  95. MatrixXI GQ((mp+mn)*3,4);
  96. GQ<<
  97. BA.col(1), BA.col(0), BA.col(0).array()+n, BA.col(1).array()+n,
  98. BA.col(2), BA.col(1), BA.col(1).array()+n, BA.col(2).array()+n,
  99. BA.col(0), BA.col(2), BA.col(2).array()+n, BA.col(0).array()+n;
  100. MatrixXI uGQ;
  101. VectorXI S,sI,sJ;
  102. //const auto & total_signed_distance =
  103. [](
  104. const MatrixXI & F,
  105. VectorXI & S,
  106. MatrixXI & uF,
  107. VectorXI & I,
  108. VectorXI & J)
  109. {
  110. const int m = F.rows();
  111. const int d = F.cols();
  112. MatrixXI sF = F;
  113. const auto MN = sF.rowwise().minCoeff().eval();
  114. // rotate until smallest index is first
  115. for(int p = 0;p<d;p++)
  116. {
  117. for(int f = 0;f<m;f++)
  118. {
  119. if(sF(f,0) != MN(f))
  120. {
  121. for(int r = 0;r<d-1;r++)
  122. {
  123. std::swap(sF(f,r),sF(f,r+1));
  124. }
  125. }
  126. }
  127. }
  128. // swap orienation
  129. for(int f = 0;f<m;f++)
  130. {
  131. if(sF(f,d-1) < sF(f,1))
  132. {
  133. sF.block(f,1,1,d-1) = sF.block(f,1,1,d-1).reverse().eval();
  134. }
  135. }
  136. Matrix<bool,Dynamic,1> M = Matrix<bool,Dynamic,1>::Zero(m,1);
  137. {
  138. VectorXI P = VectorXI::LinSpaced(d,0,d-1);
  139. for(int p = 0;p<d;p++)
  140. {
  141. for(int f = 0;f<m;f++)
  142. {
  143. bool all = true;
  144. for(int r = 0;r<d;r++)
  145. {
  146. all = all && (sF(f,P(r)) == F(f,r));
  147. }
  148. M(f) = M(f) || all;
  149. }
  150. for(int r = 0;r<d-1;r++)
  151. {
  152. std::swap(P(r),P(r+1));
  153. }
  154. }
  155. }
  156. unique_rows(sF,uF,I,J);
  157. S = VectorXI::Zero(uF.rows(),1);
  158. assert(m == J.rows());
  159. for(int f = 0;f<m;f++)
  160. {
  161. S(J(f)) += M(f) ? 1 : -1;
  162. }
  163. }(MatrixXI(GQ),S,uGQ,sI,sJ);
  164. assert(S.rows() == uGQ.rows());
  165. const int nq = (S.array().abs()==2).count();
  166. GQ.resize(nq,4);
  167. {
  168. int k = 0;
  169. for(int q = 0;q<uGQ.rows();q++)
  170. {
  171. switch(S(q))
  172. {
  173. #warning "If (V,F) is non-manifold, does this handle all cases?"
  174. case -2:
  175. GQ.row(k++) = uGQ.row(q).reverse().eval();
  176. break;
  177. case 2:
  178. GQ.row(k++) = uGQ.row(q);
  179. break;
  180. default:
  181. // do not add
  182. break;
  183. }
  184. }
  185. assert(nq == k);
  186. }
  187. MatrixXI GG(GT.rows()+2*GQ.rows(),3);
  188. GG<<
  189. GT,
  190. GQ.col(0), GQ.col(1), GQ.col(2),
  191. GQ.col(0), GQ.col(2), GQ.col(3);
  192. J.resize(JT.rows()+2*GQ.rows(),1);
  193. J<<JT,DerivedJ::Constant(2*GQ.rows(),1,2*m+1);
  194. if(resolve_overlaps)
  195. {
  196. DerivedJ SJ;
  197. mesh_boolean(
  198. WW,GG,
  199. Matrix<typename DerivedV::Scalar,Dynamic,Dynamic>(),MatrixXI(),
  200. MESH_BOOLEAN_TYPE_UNION,
  201. W,G,SJ);
  202. J = slice(DerivedJ(J),SJ,1);
  203. }
  204. }
  205. template <
  206. typename DerivedV,
  207. typename DerivedF,
  208. typename Deriveds,
  209. typename Derivedd,
  210. typename DerivedW,
  211. typename DerivedG,
  212. typename DerivedJ>
  213. IGL_INLINE void igl::copyleft::boolean::minkowski_sum(
  214. const Eigen::PlainObjectBase<DerivedV> & V,
  215. const Eigen::PlainObjectBase<DerivedF> & F,
  216. const Eigen::PlainObjectBase<Deriveds> & s,
  217. const Eigen::PlainObjectBase<Derivedd> & d,
  218. Eigen::PlainObjectBase<DerivedW> & W,
  219. Eigen::PlainObjectBase<DerivedG> & G,
  220. Eigen::PlainObjectBase<DerivedJ> & J)
  221. {
  222. return minkowski_sum(V,F,s,d,true,W,G,J);
  223. }