Skip to content

Commit f49097e

Browse files
committed
Add a unit test for LevelSetFilter::fillet.
Signed-off-by: apradhana <[email protected]>
1 parent bb1853f commit f49097e

File tree

4 files changed

+96
-9
lines changed

4 files changed

+96
-9
lines changed

openvdb/openvdb/tools/LevelSetFilter.h

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,15 @@ class LevelSetFilter : public LevelSetTracker<GridT, InterruptT>
9898
/// @brief One iteration of filleting on the level set.
9999
/// @param mask Optional alpha mask.
100100
///
101-
/// @note This filter rounds off concave edges to create a smoother transition between surfaces
102-
/// Fillets a level set by
103-
/// offsetting at locations with a negative principal curvature, proportional to its magnitude
104-
/// leaves locations with non-negative principal curvatures untouched
105-
/// This filter converges to the convex hull if iterated enough times
101+
/// @note This filter rounds off concave edges to create a smoother
102+
/// transition between surfaces. Fillets a level set by offsetting
103+
/// at locations with a negative principal curvature, proportional
104+
/// to its magnitude leaves locations with non-negative principal
105+
/// curvatures untouched. This filter converges to the convex hull
106+
/// if iterated enough times.
107+
///
108+
/// @details See also Level Set Methods and Fast Marching Methods
109+
/// by James Sethian, pp. 204.
106110
void fillet(const MaskType* mask = nullptr)
107111
{
108112
Filter f(this, mask); f.fillet();
@@ -409,10 +413,10 @@ LevelSetFilter<GridT, MaskT, InterruptT>::Filter::meanCurvatureImpl(const LeafRa
409413
}
410414
}
411415

412-
/// Fillets a level set by
413-
/// offsetting at locations with a negative principal curvature, proportional to its magnitude
414-
/// leaves locations with non-negative principal curvatures untouched
415-
/// This filter converges to the convex hull if iterated enough times
416+
/// Fillets a level set by offsetting at locations with a negative principal
417+
/// curvature, proportional to its magnitude. Leaves locations with non-negative
418+
/// principal curvatures untouched. This filter converges to the convex hull if
419+
/// iterated enough times.
416420
template<typename GridT, typename MaskT, typename InterruptT>
417421
inline void
418422
LevelSetFilter<GridT, MaskT, InterruptT>::Filter::filletImpl(const LeafRange& range)

openvdb/openvdb/unittest/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ else()
119119
TestLeafManager.cc
120120
TestLeafMask.cc
121121
TestLeafOrigin.cc
122+
TestLevelSetFilter.cc
122123
TestLevelSetRayIntersector.cc
123124
TestLevelSetUtil.cc
124125
TestLinearInterp.cc
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright Contributors to the OpenVDB Project
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#include <openvdb/openvdb.h>
5+
#include <openvdb/tools/LevelSetFilter.h>
6+
#include <openvdb/tools/LevelSetSphere.h>
7+
#include <openvdb/io/File.h>
8+
#include <openvdb/tools/Composite.h> // for csgUnion()
9+
10+
#include <gtest/gtest.h>
11+
12+
using namespace openvdb;
13+
14+
class TestLevelSetFilter: public ::testing::Test
15+
{
16+
public:
17+
void SetUp() override { openvdb::initialize(); }
18+
void TearDown() override { openvdb::uninitialize(); }
19+
20+
void testLevelSetFillet();
21+
}; // class TestLevelSetFilter
22+
23+
24+
////////////////////////////////////////
25+
26+
27+
TEST_F(TestLevelSetFilter, testLevelSetFillet)
28+
{
29+
using GridT = FloatGrid;
30+
using FilterT = tools::LevelSetFilter<GridT>;
31+
32+
const float radius = 5.0f;
33+
const float voxelSize = 1.0f;
34+
const float halfWidth = 3.0f;
35+
typename GridT::Ptr sdfGrid = tools::createLevelSetSphere<GridT>(/*radius=*/radius,
36+
/*center=*/Vec3f(-radius, 0.0f, 0.0f),
37+
/*dx=*/voxelSize, /*halfWidth*/ halfWidth);
38+
typename GridT::Ptr sdfGridB = tools::createLevelSetSphere<GridT>(/*radius=*/radius,
39+
/*center=*/Vec3f(radius, 0.0f, 0.0f),
40+
/*dx=*/voxelSize, /*halfWidth*/ halfWidth);
41+
typename GridT::Accessor acc = sdfGrid->getAccessor();
42+
43+
EXPECT_TRUE(sdfGrid);
44+
EXPECT_TRUE(sdfGridB);
45+
46+
tools::csgUnion(*sdfGrid, *sdfGridB);
47+
48+
{
49+
EXPECT_TRUE(sdfGrid);
50+
51+
Coord ijk(0, 3, 0);
52+
53+
// We expect that the intersection between the two spheres are at (0, 0, 0)
54+
// so the SDF value of the union in these offsets locations should be > 0
55+
EXPECT_TRUE(acc.getValue(ijk) > 0.f);
56+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0, 0, 1)) > 0.0f);
57+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0, 0,-1)) > 0.0f);
58+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0,-1, 0)) > 0.0f);
59+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0,-1, 1)) > 0.0f);
60+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0,-1,-1)) > 0.0f);
61+
}
62+
63+
FilterT filter(*sdfGrid);
64+
filter.fillet();
65+
66+
{
67+
EXPECT_TRUE(sdfGrid);
68+
69+
Coord ijk(0, 3, 0);
70+
71+
// After the fillet operation, we expect that the zero-isocontour is
72+
// pushed outward.
73+
EXPECT_TRUE(acc.getValue(ijk) < 0.f);
74+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0, 0, 1)) < 0.0f);
75+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0, 0,-1)) < 0.0f);
76+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0,-1, 0)) < 0.0f);
77+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0,-1, 1)) < 0.0f);
78+
EXPECT_TRUE(acc.getValue(ijk.offsetBy(0,-1,-1)) < 0.0f);
79+
}
80+
}

pendingchanges/levelset_fillet.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
New Feature:
2+
- Added fillet() method in tools::LevelSetFilter to round off concave edges to create smoother transition between surfaces. [Contributed by Greg Hurst]

0 commit comments

Comments
 (0)