libMesh
bbox_test.C
Go to the documentation of this file.
1 #include <libmesh/bounding_box.h>
2 #include <tuple>
3 #include <algorithm>
4 
5 #include "test_comm.h"
6 #include "libmesh_cppunit.h"
7 
8 using namespace libMesh;
9 
10 class BBoxTest : public CppUnit::TestCase {
11 
12 public:
13  LIBMESH_CPPUNIT_TEST_SUITE( BBoxTest );
14 #if LIBMESH_DIM > 2
15  CPPUNIT_TEST( test_one_degenerate );
16  CPPUNIT_TEST( test_two_degenerate );
17  CPPUNIT_TEST( test_no_degenerate );
18  CPPUNIT_TEST( test_signed_distance );
19 #endif
20  CPPUNIT_TEST_SUITE_END();
21 
22 public:
23  void setUp() {}
24 
25  void tearDown() {}
26 
28  {
29  LOG_UNIT_TEST;
30 
31  // Degenerate + Non-degenerate BBox tests: A unit square bounding
32  // box is intersected with the following degenerate (planar)
33  // bounding boxes:
34  // 1.) well inside the unit bbox
35  // 2.) just barely inside the unit bbox
36  // 3.) on the surface of the unit bbox
37  // 4.) just outside the surface of the unit bbox
38  // 5.) well outside the unit bbox
39  // For the "exact" intersection test: Tests 1-3 should return true, the rest false.
40  // For the "fuzzy" intersection test: Tests 1-4 should return true with large enough TOLERANCE, the rest false.
41 
42  // The smallest number for which 1 and 1 + epsilon compare unequal.
43  const Real eps = std::numeric_limits<Real>::epsilon();
44 
45  // Create unit square non-degenerate BBox for intersection testing.
46  const Point
47  min(0., 0., 0.),
48  max(1., 1., 1.);
49  BoundingBox non_degenerate(min, max);
50 
51  // Make (position, expected-exact-intersection, expected-fuzzy-intersection) tuples
52  typedef std::tuple<Real, bool, bool> TestTuple;
53  std::vector<TestTuple> tests =
54  {
55  std::make_tuple(0.5, true, true), // inside
56  std::make_tuple(1.0 - eps, true, true), // barely inside
57  std::make_tuple(1.0, true, true), // on
58  std::make_tuple(1.0 + eps, false, true), // barely outside
59  std::make_tuple(1.5, false, false) // outside
60  };
61 
62  for (unsigned int dir = 0; dir < 3; ++dir)
63  for (const auto & t : tests)
64  {
65  // Create degenerate bounding box
66  Point dmin = min, dmax = max;
67  dmin(dir) = dmax(dir) = std::get<0>(t);
68  BoundingBox degenerate(dmin, dmax);
69 
70  // std::cout << "degenerate.min() = " << degenerate.min() << std::endl;
71  // std::cout << "degenerate.max() = " << degenerate.max() << std::endl;
72 
73  // Exact tests
74  CPPUNIT_ASSERT(non_degenerate.intersects(degenerate) == std::get<1>(t));
75  CPPUNIT_ASSERT(degenerate.intersects(non_degenerate) == std::get<1>(t));
76 
77  // Fuzzy tests
78  CPPUNIT_ASSERT(non_degenerate.intersects(degenerate, /*abstol=*/TOLERANCE) == std::get<2>(t));
79  CPPUNIT_ASSERT(degenerate.intersects(non_degenerate, /*abstol=*/TOLERANCE) == std::get<2>(t));
80  }
81  }
82 
84  {
85  LOG_UNIT_TEST;
86 
87  // Degenerate + Degenerate BBox tests: test intersections of unit
88  // square degenerate (planar) bounding boxes in the x, y, and z
89  // directions in the following cases:
90  // 1.) Comparison BBox right on top of the original BBox.
91  // 2.) Comparison BBox slightly to the "left" of the original BBox.
92  // 3.) Comparison BBox slightly to the "right" of the original BBox.
93  // 4.) Comparison BBox far away from the original BBox.
94 
95  // The smallest number for which 1 and 1 + epsilon compare unequal.
96  const Real eps = std::numeric_limits<Real>::epsilon();
97  // To test intersections of degenerate x, y, and z plane BBoxes,
98  // we start with an x-plane and then permute the entries of
99  // these vectors to subsequently test in the y and z directions.
100  std::vector<Real>
101  mins = {0.5, 0, 0},
102  maxs = {.5, 1, 1};
103 
104  // Make (position, expected-exact-intersection, expected-fuzzy-intersection) tuples
105  typedef std::tuple<Real, bool, bool> TestTuple;
106  std::vector<TestTuple> tests =
107  {
108  std::make_tuple(0.5, true, true), // on
109  std::make_tuple(0.5 - eps, false, true), // barely left
110  std::make_tuple(0.5 + eps, false, true), // barely right
111  std::make_tuple(1.0, false, false) // off
112  };
113 
114  for (unsigned int dir = 0; dir < 3; ++dir)
115  {
116  // Debugging
117  // std::cout << "dir = " << dir
118  // << ", mins = " << mins[0] << ", " << mins[1] << ", " << mins[2]
119  // << ", maxs = " << maxs[0] << ", " << maxs[1] << ", " << maxs[2]
120  // << std::endl;
121 
122  const Point
123  min(Point(mins[0], mins[1], mins[2])),
124  max(Point(maxs[0], maxs[1], maxs[2]));
125  BoundingBox initial(min, max);
126 
127  // Create each degenerate comparison BoundingBox and make
128  // sure the expected intersection result is found.
129  for (const auto & t : tests)
130  {
131  // Create comparison bbox
132  Point cmin = min, cmax = max;
133  cmin(dir) = cmax(dir) = std::get<0>(t);
134  BoundingBox comparison(cmin, cmax);
135 
136  // Exact tests
137  CPPUNIT_ASSERT(initial.intersects(comparison) == std::get<1>(t));
138  CPPUNIT_ASSERT(comparison.intersects(initial) == std::get<1>(t));
139 
140  // Fuzzy tests
141  CPPUNIT_ASSERT(initial.intersects(comparison, /*abstol=*/TOLERANCE) == std::get<2>(t));
142  CPPUNIT_ASSERT(comparison.intersects(initial, /*abstol=*/TOLERANCE) == std::get<2>(t));
143  }
144 
145  // Go to the next cyclic permutation of mins and maxs by
146  // rotating the last entry off the end and onto the front of
147  // the array.
148  std::rotate(mins.rbegin(), mins.rbegin()+1, mins.rend());
149  std::rotate(maxs.rbegin(), maxs.rbegin()+1, maxs.rend());
150  }
151  }
152 
154  {
155  LOG_UNIT_TEST;
156 
157  // The smallest number for which 1 and 1 + epsilon compare unequal.
158  const Real eps = std::numeric_limits<Real>::epsilon();
159 
160  // Non-degenerate + Non-degenerate BBox tests. These tests
161  // consider two initially unit-sized bounding boxes "stacked" in
162  // the x, y, and z directions with slight perturbations to bring
163  // them into intersection or not.
164  std::vector<Real>
165  mins = {1, 0, 0},
166  maxs = {2, 1, 1};
167 
168  // All tests use the same unit bounding box for base comparisons.
169  BoundingBox initial(Point(0.,0.,0.), Point(1.,1.,1.));
170 
171  // Make (position, expected-exact-intersection, expected-fuzzy-intersection) tuples
172  typedef std::tuple<Real, bool, bool> TestTuple;
173  std::vector<TestTuple> tests =
174  {
175  std::make_tuple(1., true, true), // on
176  std::make_tuple(1. + eps, false, true), // barely outside
177  std::make_tuple(1. - eps, true, true), // barely inside
178  std::make_tuple(1.5, false, false), // definitely outside
179  std::make_tuple(0.5, true, true) // definitely inside
180  };
181 
182  for (unsigned int dir = 0; dir < 3; ++dir)
183  {
184  // Debugging
185  // std::cout << "dir = " << dir
186  // << ", mins = " << mins[0] << ", " << mins[1] << ", " << mins[2]
187  // << ", maxs = " << maxs[0] << ", " << maxs[1] << ", " << maxs[2]
188  // << std::endl;
189 
190  const Point
191  min(Point(mins[0], mins[1], mins[2])),
192  max(Point(maxs[0], maxs[1], maxs[2]));
193 
194  // Create each degenerate comparison BoundingBox and make
195  // sure the expected intersection result is found.
196  for (const auto & t : tests)
197  {
198  // Create comparison bbox with perturbed minimum coordinate.
199  Point cmin = min, cmax = max;
200  cmin(dir) = std::get<0>(t);
201  BoundingBox comparison(cmin, cmax);
202 
203  // std::cout << "cmin = " << cmin << ", cmax = " << cmax << std::endl;
204 
205  // Exact tests
206  CPPUNIT_ASSERT(initial.intersects(comparison) == std::get<1>(t));
207  CPPUNIT_ASSERT(comparison.intersects(initial) == std::get<1>(t));
208 
209  // Fuzzy tests
210  CPPUNIT_ASSERT(initial.intersects(comparison, /*abstol=*/TOLERANCE) == std::get<2>(t));
211  CPPUNIT_ASSERT(comparison.intersects(initial, /*abstol=*/TOLERANCE) == std::get<2>(t));
212  }
213 
214  // Go to the next cyclic permutation of mins and maxs by
215  // rotating the last entry off the end and onto the front of
216  // the array.
217  std::rotate(mins.rbegin(), mins.rbegin()+1, mins.rend());
218  std::rotate(maxs.rbegin(), maxs.rbegin()+1, maxs.rend());
219  }
220  }
221 
223  {
224  LOG_UNIT_TEST;
225 
226  // A "unit" size bounding box for making distance comparisons.
227  BoundingBox unit(Point(0.,0.,0.), Point(1.,1.,1.));
228 
229  // Test points inside the box
230  LIBMESH_ASSERT_FP_EQUAL(-0.5, unit.signed_distance(Point(0.5, 0.5, 0.5)), TOLERANCE * TOLERANCE);
231  LIBMESH_ASSERT_FP_EQUAL(-0.4, unit.signed_distance(Point(0.5, 0.6, 0.5)), TOLERANCE * TOLERANCE);
232  LIBMESH_ASSERT_FP_EQUAL(-0.4, unit.signed_distance(Point(0.4, 0.5, 0.5)), TOLERANCE * TOLERANCE);
233  LIBMESH_ASSERT_FP_EQUAL(-0.1, unit.signed_distance(Point(0.1, 0.1, 0.1)), TOLERANCE * TOLERANCE);
234 
235  // Test points on the box
236  LIBMESH_ASSERT_FP_EQUAL(0., unit.signed_distance(Point(1.0, 0.5, 0.5)), TOLERANCE * TOLERANCE);
237  LIBMESH_ASSERT_FP_EQUAL(0., unit.signed_distance(Point(1.0, 0., 0.)), TOLERANCE * TOLERANCE);
238 
239  // Test points outside the box
240  LIBMESH_ASSERT_FP_EQUAL(0.5, unit.signed_distance(Point(1.5, 0.5, 0.5)), TOLERANCE * TOLERANCE); // right
241  LIBMESH_ASSERT_FP_EQUAL(0.5, unit.signed_distance(Point(-0.5, 0.5, 0.5)), TOLERANCE * TOLERANCE); // left
242  LIBMESH_ASSERT_FP_EQUAL(0.5, unit.signed_distance(Point(0.5, 0.5, 1.5)), TOLERANCE * TOLERANCE); // above
243  LIBMESH_ASSERT_FP_EQUAL(0.5, unit.signed_distance(Point(0.5, 0.5, -0.5)), TOLERANCE * TOLERANCE); // below
244  LIBMESH_ASSERT_FP_EQUAL(0.5, unit.signed_distance(Point(0.5, -0.5, 0.5)), TOLERANCE * TOLERANCE); // front
245  LIBMESH_ASSERT_FP_EQUAL(0.5, unit.signed_distance(Point(0.5, 1.5, 0.5)), TOLERANCE * TOLERANCE); // back
246 
247  // Outside the box, closest to a corner.
248  LIBMESH_ASSERT_FP_EQUAL(std::sqrt(Real(3)), unit.signed_distance(Point(2., 2., 2.)), TOLERANCE * TOLERANCE); // Point along line (0,0,0) -> (1,1,1)
249  LIBMESH_ASSERT_FP_EQUAL(std::sqrt(Real(3)), unit.signed_distance(Point(-1., -1., -1.)), TOLERANCE * TOLERANCE); // Point along line (0,0,0) -> (1,1,1)
250  LIBMESH_ASSERT_FP_EQUAL(std::sqrt(Real(3))/2., unit.signed_distance(Point(1.5, 1.5, -0.5)), TOLERANCE * TOLERANCE); // Point along line (0.5,0.5,0.5) -> (1,1,0)
251  LIBMESH_ASSERT_FP_EQUAL(std::sqrt(Real(3))/2., unit.signed_distance(Point(1.5, -0.5, -0.5)), TOLERANCE * TOLERANCE); // Point along line (0.5,0.5,0.5) -> (1,0,0)
252  }
253 };
254 
CPPUNIT_TEST_SUITE_REGISTRATION(BBoxTest)
void test_signed_distance()
Definition: bbox_test.C:222
static constexpr Real TOLERANCE
bool intersects(const BoundingBox &) const
Definition: bounding_box.h:231
void test_no_degenerate()
Definition: bbox_test.C:153
The libMesh namespace provides an interface to certain functionality in the library.
Real signed_distance(const Point &p) const
Computes the signed distance, d, from a given Point p to this BoundingBox.
Definition: bounding_box.C:158
void tearDown()
Definition: bbox_test.C:25
RealTensorValue rotate(MeshBase &mesh, const Real phi, const Real theta=0., const Real psi=0.)
Rotates the mesh in the xy plane.
Defines a Cartesian bounding box by the two corner extremum.
Definition: bounding_box.h:40
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void setUp()
Definition: bbox_test.C:23
void test_two_degenerate()
Definition: bbox_test.C:83
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
void test_one_degenerate()
Definition: bbox_test.C:27