You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
7.0 KiB

  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2009 Ilya Baran <ibaran@mit.edu>
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla
  7. // Public License v. 2.0. If a copy of the MPL was not distributed
  8. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. #include "main.h"
  10. #include <Eigen/StdVector>
  11. #include <Eigen/Geometry>
  12. #include <unsupported/Eigen/BVH>
  13. namespace StormEigen {
  14. template<typename Scalar, int Dim> AlignedBox<Scalar, Dim> bounding_box(const Matrix<Scalar, Dim, 1> &v) { return AlignedBox<Scalar, Dim>(v); }
  15. }
  16. template<int Dim>
  17. struct Ball
  18. {
  19. EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(double, Dim)
  20. typedef Matrix<double, Dim, 1> VectorType;
  21. Ball() {}
  22. Ball(const VectorType &c, double r) : center(c), radius(r) {}
  23. VectorType center;
  24. double radius;
  25. };
  26. template<int Dim> AlignedBox<double, Dim> bounding_box(const Ball<Dim> &b)
  27. { return AlignedBox<double, Dim>(b.center.array() - b.radius, b.center.array() + b.radius); }
  28. inline double SQR(double x) { return x * x; }
  29. template<int Dim>
  30. struct BallPointStuff //this class provides functions to be both an intersector and a minimizer, both for a ball and a point and for two trees
  31. {
  32. typedef double Scalar;
  33. typedef Matrix<double, Dim, 1> VectorType;
  34. typedef Ball<Dim> BallType;
  35. typedef AlignedBox<double, Dim> BoxType;
  36. BallPointStuff() : calls(0), count(0) {}
  37. BallPointStuff(const VectorType &inP) : p(inP), calls(0), count(0) {}
  38. bool intersectVolume(const BoxType &r) { ++calls; return r.contains(p); }
  39. bool intersectObject(const BallType &b) {
  40. ++calls;
  41. if((b.center - p).squaredNorm() < SQR(b.radius))
  42. ++count;
  43. return false; //continue
  44. }
  45. bool intersectVolumeVolume(const BoxType &r1, const BoxType &r2) { ++calls; return !(r1.intersection(r2)).isNull(); }
  46. bool intersectVolumeObject(const BoxType &r, const BallType &b) { ++calls; return r.squaredExteriorDistance(b.center) < SQR(b.radius); }
  47. bool intersectObjectVolume(const BallType &b, const BoxType &r) { ++calls; return r.squaredExteriorDistance(b.center) < SQR(b.radius); }
  48. bool intersectObjectObject(const BallType &b1, const BallType &b2){
  49. ++calls;
  50. if((b1.center - b2.center).norm() < b1.radius + b2.radius)
  51. ++count;
  52. return false;
  53. }
  54. bool intersectVolumeObject(const BoxType &r, const VectorType &v) { ++calls; return r.contains(v); }
  55. bool intersectObjectObject(const BallType &b, const VectorType &v){
  56. ++calls;
  57. if((b.center - v).squaredNorm() < SQR(b.radius))
  58. ++count;
  59. return false;
  60. }
  61. double minimumOnVolume(const BoxType &r) { ++calls; return r.squaredExteriorDistance(p); }
  62. double minimumOnObject(const BallType &b) { ++calls; return (std::max)(0., (b.center - p).squaredNorm() - SQR(b.radius)); }
  63. double minimumOnVolumeVolume(const BoxType &r1, const BoxType &r2) { ++calls; return r1.squaredExteriorDistance(r2); }
  64. double minimumOnVolumeObject(const BoxType &r, const BallType &b) { ++calls; return SQR((std::max)(0., r.exteriorDistance(b.center) - b.radius)); }
  65. double minimumOnObjectVolume(const BallType &b, const BoxType &r) { ++calls; return SQR((std::max)(0., r.exteriorDistance(b.center) - b.radius)); }
  66. double minimumOnObjectObject(const BallType &b1, const BallType &b2){ ++calls; return SQR((std::max)(0., (b1.center - b2.center).norm() - b1.radius - b2.radius)); }
  67. double minimumOnVolumeObject(const BoxType &r, const VectorType &v) { ++calls; return r.squaredExteriorDistance(v); }
  68. double minimumOnObjectObject(const BallType &b, const VectorType &v){ ++calls; return SQR((std::max)(0., (b.center - v).norm() - b.radius)); }
  69. VectorType p;
  70. int calls;
  71. int count;
  72. };
  73. template<int Dim>
  74. struct TreeTest
  75. {
  76. typedef Matrix<double, Dim, 1> VectorType;
  77. typedef std::vector<VectorType, aligned_allocator<VectorType> > VectorTypeList;
  78. typedef Ball<Dim> BallType;
  79. typedef std::vector<BallType, aligned_allocator<BallType> > BallTypeList;
  80. typedef AlignedBox<double, Dim> BoxType;
  81. void testIntersect1()
  82. {
  83. BallTypeList b;
  84. for(int i = 0; i < 500; ++i) {
  85. b.push_back(BallType(VectorType::Random(), 0.5 * internal::random(0., 1.)));
  86. }
  87. KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
  88. VectorType pt = VectorType::Random();
  89. BallPointStuff<Dim> i1(pt), i2(pt);
  90. for(int i = 0; i < (int)b.size(); ++i)
  91. i1.intersectObject(b[i]);
  92. BVIntersect(tree, i2);
  93. VERIFY(i1.count == i2.count);
  94. }
  95. void testMinimize1()
  96. {
  97. BallTypeList b;
  98. for(int i = 0; i < 500; ++i) {
  99. b.push_back(BallType(VectorType::Random(), 0.01 * internal::random(0., 1.)));
  100. }
  101. KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
  102. VectorType pt = VectorType::Random();
  103. BallPointStuff<Dim> i1(pt), i2(pt);
  104. double m1 = (std::numeric_limits<double>::max)(), m2 = m1;
  105. for(int i = 0; i < (int)b.size(); ++i)
  106. m1 = (std::min)(m1, i1.minimumOnObject(b[i]));
  107. m2 = BVMinimize(tree, i2);
  108. VERIFY_IS_APPROX(m1, m2);
  109. }
  110. void testIntersect2()
  111. {
  112. BallTypeList b;
  113. VectorTypeList v;
  114. for(int i = 0; i < 50; ++i) {
  115. b.push_back(BallType(VectorType::Random(), 0.5 * internal::random(0., 1.)));
  116. for(int j = 0; j < 3; ++j)
  117. v.push_back(VectorType::Random());
  118. }
  119. KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
  120. KdBVH<double, Dim, VectorType> vTree(v.begin(), v.end());
  121. BallPointStuff<Dim> i1, i2;
  122. for(int i = 0; i < (int)b.size(); ++i)
  123. for(int j = 0; j < (int)v.size(); ++j)
  124. i1.intersectObjectObject(b[i], v[j]);
  125. BVIntersect(tree, vTree, i2);
  126. VERIFY(i1.count == i2.count);
  127. }
  128. void testMinimize2()
  129. {
  130. BallTypeList b;
  131. VectorTypeList v;
  132. for(int i = 0; i < 50; ++i) {
  133. b.push_back(BallType(VectorType::Random(), 1e-7 + 1e-6 * internal::random(0., 1.)));
  134. for(int j = 0; j < 3; ++j)
  135. v.push_back(VectorType::Random());
  136. }
  137. KdBVH<double, Dim, BallType> tree(b.begin(), b.end());
  138. KdBVH<double, Dim, VectorType> vTree(v.begin(), v.end());
  139. BallPointStuff<Dim> i1, i2;
  140. double m1 = (std::numeric_limits<double>::max)(), m2 = m1;
  141. for(int i = 0; i < (int)b.size(); ++i)
  142. for(int j = 0; j < (int)v.size(); ++j)
  143. m1 = (std::min)(m1, i1.minimumOnObjectObject(b[i], v[j]));
  144. m2 = BVMinimize(tree, vTree, i2);
  145. VERIFY_IS_APPROX(m1, m2);
  146. }
  147. };
  148. void test_BVH()
  149. {
  150. for(int i = 0; i < g_repeat; i++) {
  151. #ifdef EIGEN_TEST_PART_1
  152. TreeTest<2> test2;
  153. CALL_SUBTEST(test2.testIntersect1());
  154. CALL_SUBTEST(test2.testMinimize1());
  155. CALL_SUBTEST(test2.testIntersect2());
  156. CALL_SUBTEST(test2.testMinimize2());
  157. #endif
  158. #ifdef EIGEN_TEST_PART_2
  159. TreeTest<3> test3;
  160. CALL_SUBTEST(test3.testIntersect1());
  161. CALL_SUBTEST(test3.testMinimize1());
  162. CALL_SUBTEST(test3.testIntersect2());
  163. CALL_SUBTEST(test3.testMinimize2());
  164. #endif
  165. #ifdef EIGEN_TEST_PART_3
  166. TreeTest<4> test4;
  167. CALL_SUBTEST(test4.testIntersect1());
  168. CALL_SUBTEST(test4.testMinimize1());
  169. CALL_SUBTEST(test4.testIntersect2());
  170. CALL_SUBTEST(test4.testMinimize2());
  171. #endif
  172. }
  173. }