GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/unittest/TestClip.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 98 98 100.0%
Functions: 12 12 100.0%
Branches: 81 372 21.8%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #include <openvdb/openvdb.h>
5 #include <openvdb/math/Maps.h> // for math::NonlinearFrustumMap
6 #include <openvdb/tools/Clip.h>
7
8 #include <gtest/gtest.h>
9
10 // See also TestGrid::testClipping()
11 class TestClip: public ::testing::Test
12 {
13 public:
14 static const openvdb::CoordBBox kCubeBBox, kInnerBBox;
15
16 7 TestClip(): mCube{
17 7 []() {
18 7 auto cube = openvdb::FloatGrid{0.0f};
19
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 cube.fill(kCubeBBox, /*value=*/5.0f, /*active=*/true);
20 7 return cube;
21
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 }()}
22 7 {}
23
24 7 void SetUp() override { openvdb::initialize(); }
25 7 void TearDown() override { openvdb::initialize(); }
26
27 protected:
28 void validate(const openvdb::FloatGrid&);
29
30 const openvdb::FloatGrid mCube;
31 };
32
33 const openvdb::CoordBBox
34 // The volume to be clipped is a 21 x 21 x 21 solid cube.
35 TestClip::kCubeBBox{openvdb::Coord{-10}, openvdb::Coord{10}},
36 // The clipping mask is a 1 x 1 x 13 segment extending along the Z axis inside the cube.
37 TestClip::kInnerBBox{openvdb::Coord{4, 4, -6}, openvdb::Coord{4, 4, 6}};
38
39
40 ////////////////////////////////////////
41
42
43 void
44 6 TestClip::validate(const openvdb::FloatGrid& clipped)
45 {
46 using namespace openvdb;
47
48 6 const CoordBBox bbox = clipped.evalActiveVoxelBoundingBox();
49
1/14
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 EXPECT_EQ(kInnerBBox.min().x(), bbox.min().x());
50
1/14
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 EXPECT_EQ(kInnerBBox.min().y(), bbox.min().y());
51
1/14
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 EXPECT_EQ(kInnerBBox.min().z(), bbox.min().z());
52
1/14
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 EXPECT_EQ(kInnerBBox.max().x(), bbox.max().x());
53
1/14
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 EXPECT_EQ(kInnerBBox.max().y(), bbox.max().y());
54
1/14
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
6 EXPECT_EQ(kInnerBBox.max().z(), bbox.max().z());
55
1/14
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
6 EXPECT_EQ(6 + 6 + 1, int(clipped.activeVoxelCount()));
56
1/14
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
6 EXPECT_EQ(2, int(clipped.constTree().leafCount()));
57
58 FloatGrid::ConstAccessor acc = clipped.getConstAccessor();
59 6 const float bg = clipped.background();
60 Coord xyz;
61 int &x = xyz[0], &y = xyz[1], &z = xyz[2];
62
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 6 times.
132 for (x = kCubeBBox.min().x(); x <= kCubeBBox.max().x(); ++x) {
63
2/2
✓ Branch 0 taken 2646 times.
✓ Branch 1 taken 126 times.
2772 for (y = kCubeBBox.min().y(); y <= kCubeBBox.max().y(); ++y) {
64
2/2
✓ Branch 0 taken 55566 times.
✓ Branch 1 taken 2646 times.
58212 for (z = kCubeBBox.min().z(); z <= kCubeBBox.max().z(); ++z) {
65
8/8
✓ Branch 0 taken 2646 times.
✓ Branch 1 taken 52920 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 2520 times.
✓ Branch 4 taken 102 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 78 times.
✓ Branch 7 taken 24 times.
55566 if (x == 4 && y == 4 && z >= -6 && z <= 6) {
66
3/18
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 78 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 78 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
156 EXPECT_EQ(5.f, acc.getValue(Coord(4, 4, z)));
67 } else {
68
2/16
✓ Branch 1 taken 55488 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 55488 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
110976 EXPECT_EQ(bg, acc.getValue(Coord(x, y, z)));
69 }
70 }
71 }
72 }
73 6 }
74
75
76 ////////////////////////////////////////
77
78
79 // Test clipping against a bounding box.
80
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 TEST_F(TestClip, testBBox)
81 {
82 using namespace openvdb;
83 1 BBoxd clipBox(Vec3d(4.0, 4.0, -6.0), Vec3d(4.9, 4.9, 6.0));
84 1 FloatGrid::Ptr clipped = tools::clip(mCube, clipBox);
85
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 validate(*clipped);
86 1 }
87
88
89 // Test clipping against a camera frustum.
90
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 TEST_F(TestClip, testFrustum)
91 {
92 using namespace openvdb;
93
94 1 const auto d = double(kCubeBBox.max().z());
95 const math::NonlinearFrustumMap frustum{
96 1 /*position=*/Vec3d{0.0, 0.0, 5.0 * d},
97 1 /*direction=*/Vec3d{0.0, 0.0, -1.0},
98 2 /*up=*/Vec3d{0.0, d / 2.0, 0.0},
99 /*aspect=*/1.0,
100 1 /*near=*/4.0 * d + 1.0,
101 3 /*depth=*/kCubeBBox.dim().z() - 2.0,
102 /*x_count=*/100,
103 1 /*z_count=*/100};
104 1 const auto frustumIndexBBox = frustum.getBBox();
105
106 {
107 1 auto clipped = tools::clip(mCube, frustum);
108
109
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const auto bbox = clipped->evalActiveVoxelBoundingBox();
110 1 const auto cubeDim = kCubeBBox.dim();
111
2/16
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
1 EXPECT_EQ(kCubeBBox.min().z() + 1, bbox.min().z());
112
2/18
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
1 EXPECT_EQ(kCubeBBox.max().z() - 1, bbox.max().z());
113
1/16
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
1 EXPECT_TRUE(int(bbox.volume()) < int(cubeDim.x() * cubeDim.y() * (cubeDim.z() - 2)));
114
115 // Note: mCube index space corresponds to world space.
116
2/2
✓ Branch 0 taken 2870 times.
✓ Branch 1 taken 1 times.
2871 for (auto it = clipped->beginValueOn(); it; ++it) {
117 2870 const auto xyz = frustum.applyInverseMap(it.getCoord().asVec3d());
118
1/16
✗ Branch 0 not taken.
✓ Branch 1 taken 2870 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
2870 EXPECT_TRUE(frustumIndexBBox.isInside(xyz));
119 }
120 }
121 {
122
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 auto tile = openvdb::FloatGrid{0.0f};
123
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tile.tree().addTile(/*level=*/2, Coord{0}, /*value=*/5.0f, /*active=*/true);
124
125
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto clipped = tools::clip(tile, frustum);
126
2/18
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
1 EXPECT_TRUE(!clipped->empty());
127
2/2
✓ Branch 0 taken 367 times.
✓ Branch 1 taken 1 times.
368 for (auto it = clipped->beginValueOn(); it; ++it) {
128 367 const auto xyz = frustum.applyInverseMap(it.getCoord().asVec3d());
129
1/16
✗ Branch 0 not taken.
✓ Branch 1 taken 367 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
367 EXPECT_TRUE(frustumIndexBBox.isInside(xyz));
130 }
131
132
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 clipped = tools::clip(tile, frustum, /*keepInterior=*/false);
133
2/18
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
1 EXPECT_TRUE(!clipped->empty());
134
2/2
✓ Branch 0 taken 4751 times.
✓ Branch 1 taken 1 times.
4752 for (auto it = clipped->beginValueOn(); it; ++it) {
135 4751 const auto xyz = frustum.applyInverseMap(it.getCoord().asVec3d());
136
1/16
✗ Branch 0 not taken.
✓ Branch 1 taken 4751 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4751 EXPECT_TRUE(!frustumIndexBBox.isInside(xyz));
137 }
138 }
139 1 }
140
141
142 // Test clipping against a MaskGrid.
143
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TEST_F(TestClip, testMaskGrid)
144 {
145 using namespace openvdb;
146 2 MaskGrid mask(false);
147
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(kInnerBBox, true, true);
148
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 FloatGrid::Ptr clipped = tools::clip(mCube, mask);
149
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 validate(*clipped);
150 1 }
151
152
153 // Test clipping against a boolean mask grid.
154
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TEST_F(TestClip, testBoolMask)
155 {
156 using namespace openvdb;
157 2 BoolGrid mask(false);
158
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(kInnerBBox, true, true);
159
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 FloatGrid::Ptr clipped = tools::clip(mCube, mask);
160
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 validate(*clipped);
161 1 }
162
163
164 // Test clipping against a boolean mask grid with mask inversion.
165
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TEST_F(TestClip, testInvertedBoolMask)
166 {
167 using namespace openvdb;
168 // Construct a mask grid that is the "inverse" of the mask used in the other tests.
169 // (This is not a true inverse, since the mask's active voxel bounds are finite.)
170 2 BoolGrid mask(false);
171
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(kCubeBBox, true, true);
172
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(kInnerBBox, false, false);
173 // Clipping against the "inverted" mask with mask inversion enabled
174 // should give the same results as clipping normally against the normal mask.
175
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 FloatGrid::Ptr clipped = tools::clip(mCube, mask, /*keepInterior=*/false);
176
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 clipped->pruneGrid();
177
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 validate(*clipped);
178 1 }
179
180
181 // Test clipping against a non-boolean mask grid.
182
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TEST_F(TestClip, testNonBoolMask)
183 {
184 using namespace openvdb;
185 2 Int32Grid mask(0);
186
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(kInnerBBox, -5, true);
187
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 FloatGrid::Ptr clipped = tools::clip(mCube, mask);
188
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 validate(*clipped);
189 1 }
190
191
192 // Test clipping against a non-boolean mask grid with mask inversion.
193
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TEST_F(TestClip, testInvertedNonBoolMask)
194 {
195 using namespace openvdb;
196 // Construct a mask grid that is the "inverse" of the mask used in the other tests.
197 // (This is not a true inverse, since the mask's active voxel bounds are finite.)
198 2 Grid<UInt32Tree> mask(0);
199
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto paddedCubeBBox = kCubeBBox;
200 paddedCubeBBox.expand(2);
201
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(paddedCubeBBox, 99, true);
202
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 mask.fill(kInnerBBox, 0, false);
203 // Clipping against the "inverted" mask with mask inversion enabled
204 // should give the same results as clipping normally against the normal mask.
205
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 FloatGrid::Ptr clipped = tools::clip(mCube, mask, /*keepInterior=*/false);
206
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 clipped->pruneGrid();
207
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 validate(*clipped);
208 1 }
209