hausdorff.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 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 "hausdorff.h"
  9. #include "point_mesh_squared_distance.h"
  10. #include "AABB.h"
  11. #include "upsample.h"
  12. #include "slice_mask.h"
  13. #include "remove_unreferenced.h"
  14. #include "EPS.h"
  15. template <
  16. typename DerivedVA,
  17. typename DerivedFA,
  18. typename DerivedVB,
  19. typename DerivedFB,
  20. typename Scalar>
  21. IGL_INLINE void igl::hausdorff(
  22. const Eigen::PlainObjectBase<DerivedVA> & OVA,
  23. const Eigen::PlainObjectBase<DerivedFA> & OFA,
  24. const Eigen::PlainObjectBase<DerivedVB> & VB,
  25. const Eigen::PlainObjectBase<DerivedFB> & FB,
  26. const Scalar eps,
  27. Scalar & lower,
  28. Scalar & upper)
  29. {
  30. using namespace Eigen;
  31. using namespace igl;
  32. using namespace std;
  33. assert(OVA.cols() == 3 && "VA should contain 3d points");
  34. assert(OFA.cols() == 3 && "FA should contain triangles");
  35. assert(VB.cols() == 3 && "VB should contain 3d points");
  36. assert(FB.cols() == 3 && "FB should contain triangles");
  37. assert(eps>0 && "eps should be a strictly positive number");
  38. const auto inf = std::numeric_limits<Scalar>::infinity();
  39. DerivedVA VA = OVA;
  40. DerivedFA FA = OFA;
  41. // Precompute acceleration data structure for B
  42. AABB<DerivedVB,3> tree;
  43. tree.init(VB,FB);
  44. lower = 0;
  45. typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
  46. VectorXS DV;
  47. Eigen::Matrix<int,Eigen::Dynamic,1> DI;
  48. Eigen::Matrix<Scalar,Eigen::Dynamic,3> DC;
  49. while(true)
  50. {
  51. // Compute distance to each vertex in VA
  52. tree.squared_distance(VB,FB,VA,DV,DI,DC);
  53. DV = DV.array().sqrt();
  54. // Compute upper bound for each face in FA
  55. VectorXS U(FA.rows(),1);
  56. for(int i = 0;i<FA.rows();i++)
  57. {
  58. // Compute edge lengths
  59. Eigen::Matrix<Scalar,3,1> e;
  60. for(int c = 0;c<3;c++)
  61. {
  62. e(c) = (VA.row(FA(i,(c+1)%3)) - VA.row(FA(i,(c+2)%3))).norm();
  63. }
  64. // Semiperimeter
  65. Scalar s = e.array().sum()/2.0;
  66. // Area
  67. Scalar A = sqrt(s*(s-e(0))*(s-e(1))*(s-e(2)));
  68. // Circumradius
  69. Scalar R = e(0)*e(1)*e(2)/(4.0*A);
  70. // Inradius
  71. Scalar r = A/s;
  72. // Barycenter
  73. Eigen::Matrix<typename DerivedVA::Scalar,1,3> B =
  74. (VA.row(FA(i,0))+ VA.row(FA(i,1))+ VA.row(FA(i,2)))/3.0;
  75. // These still sometimes contribute
  76. Scalar u1 = inf;
  77. Scalar u2 = 0;
  78. // u3 is a _huge_ improvement over u1, u2
  79. Scalar u3 = 0;
  80. // u4 _is contributing_ but it's rather expensive
  81. Scalar u4 = inf;
  82. for(int c = 0;c<3;c++)
  83. {
  84. const Scalar dic = DV(FA(i,c));
  85. lower = std::max(lower,dic);
  86. u1 = std::min(u1,dic+max(e((c+1)%3), e((c+2)%3)));
  87. u2 = std::max(u2,dic);
  88. u3 = std::max(u3,dic);
  89. u3 = std::max(u3, (B-DC.row(FA(i,c))).norm());
  90. {
  91. Scalar u4c = 0;
  92. for(int o = 0;o<3;o++)
  93. {
  94. u4c =
  95. std::max(u4c,c==o?dic:(VA.row(FA(i,c))-DC.row(FA(i,o))).norm());
  96. }
  97. u4 = std::min(u4,u4c);
  98. }
  99. }
  100. u2 += ( s-r > 2.*R ? R : e.maxCoeff()/2.0 );
  101. U(i) = std::min(std::min(std::min(u1,u2),u3),u4);
  102. }
  103. upper = U.maxCoeff();
  104. //cout<<std::setprecision(17) << FA.rows()<<"\t"<<lower<< "\t"<<upper<<endl;
  105. if(upper-lower <= eps)
  106. {
  107. return;
  108. }
  109. // Remove faces with too small upper bounds to impact result
  110. slice_mask(DerivedFA(FA),(U.array()>lower).eval(),1,FA);
  111. {
  112. Eigen::Matrix<typename DerivedFA::Index,Eigen::Dynamic,1> _;
  113. remove_unreferenced(DerivedVA(VA),DerivedFA(FA),VA,FA,_);
  114. }
  115. // Upsample all (remaining) faces in A
  116. upsample(DerivedVA(VA),DerivedFA(FA),VA,FA);
  117. }
  118. }
  119. template <
  120. typename DerivedVA,
  121. typename DerivedFA,
  122. typename DerivedVB,
  123. typename DerivedFB,
  124. typename Scalar>
  125. IGL_INLINE void igl::hausdorff(
  126. const Eigen::PlainObjectBase<DerivedVA> & VA,
  127. const Eigen::PlainObjectBase<DerivedFA> & FA,
  128. const Eigen::PlainObjectBase<DerivedVB> & VB,
  129. const Eigen::PlainObjectBase<DerivedFB> & FB,
  130. Scalar & d)
  131. {
  132. using namespace Eigen;
  133. auto X = VA.colwise().maxCoeff().array().max(VB.colwise().maxCoeff().array());
  134. auto N = VA.colwise().minCoeff().array().min(VB.colwise().minCoeff().array());
  135. const double bbd = (X-N).matrix().norm();
  136. const double eps = igl::EPS<Scalar>()*bbd;
  137. double lab,uab,lba,uba;
  138. igl::hausdorff(VA,FA,VB,FB,eps,lab,uab);
  139. igl::hausdorff(VB,FB,VA,FA,eps,lba,uba);
  140. d = std::max(lab,lba);
  141. }
  142. #ifdef IGL_STATIC_LIBRARY
  143. template void igl::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double&);
  144. #endif