Skip to content

Commit 99bb2f6

Browse files
committed
Add support and test for doing arithmetic with Vec3H, i.e. Vec3<math::half>.
Signed-off-by: apradhana <[email protected]>
1 parent 6add394 commit 99bb2f6

File tree

7 files changed

+213
-9
lines changed

7 files changed

+213
-9
lines changed

openvdb/openvdb/math/Math.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ template<> inline std::string zeroVal<std::string>() { return ""; }
7575
/// Return the @c bool value that corresponds to zero.
7676
template<> inline constexpr bool zeroVal<bool>() { return false; }
7777

78+
79+
/// @note Extends the implementation of std::is_arithmetic to support math::half
80+
template<typename T>
81+
struct is_arithmetic : std::is_arithmetic<T> {};
82+
template<>
83+
struct is_arithmetic<math::half> : std::true_type {};
84+
// Helper variable template (equivalent to std::is_arithmetic_v)
85+
template<typename T>
86+
inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
87+
7888
namespace math {
7989

8090
/// @todo These won't be needed if we eliminate StringGrids.
@@ -987,12 +997,12 @@ enum RotationOrder {
987997
ZXZ_ROTATION
988998
};
989999

990-
991-
template <typename S, typename T>
1000+
template <typename S, typename T, typename = std::enable_if_t<openvdb::is_arithmetic_v<S>&& openvdb::is_arithmetic_v<T>>>
9921001
struct promote {
9931002
using type = typename boost::numeric::conversion_traits<S, T>::supertype;
9941003
};
9951004

1005+
9961006
/// @brief Return the index [0,1,2] of the smallest value in a 3D vector.
9971007
/// @note This methods assumes operator[] exists.
9981008
/// @details The return value corresponds to the largest index of the of

openvdb/openvdb/math/Vec3.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,11 +663,13 @@ using Vec3i = Vec3<int32_t>;
663663
using Vec3ui = Vec3<uint32_t>;
664664
using Vec3s = Vec3<float>;
665665
using Vec3d = Vec3<double>;
666+
using Vec3h = Vec3<math::half>;
666667

667668
OPENVDB_IS_POD(Vec3i)
668669
OPENVDB_IS_POD(Vec3ui)
669670
OPENVDB_IS_POD(Vec3s)
670671
OPENVDB_IS_POD(Vec3d)
672+
OPENVDB_IS_POD(Vec3h)
671673

672674
} // namespace math
673675
} // namespace OPENVDB_VERSION_NAME

openvdb/openvdb/unittest/TestMath.cc

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,185 @@ class TestMath: public ::testing::Test
1313
{
1414
};
1515

16+
// Testing the operators within the member functions of Vec3
17+
template<typename ValueT>
18+
void testMemberOperatorsImpl()
19+
{
20+
using namespace openvdb;
21+
using Vec3T = math::Vec3<ValueT>;
22+
23+
{
24+
Vec3T vecA(3.14,2.18,ValueT(-299792458.f));
25+
26+
// Alternative indexed the elements
27+
EXPECT_EQ(vecA(0), ValueT(3.14));
28+
EXPECT_EQ(vecA(1), ValueT(2.18));
29+
EXPECT_EQ(vecA(2), ValueT(-299792458.f));
30+
31+
// Assignment operator
32+
Vec3T vecB = vecA;
33+
EXPECT_EQ(vecB(0), vecA(0));
34+
EXPECT_EQ(vecB(1), vecA(1));
35+
EXPECT_EQ(vecB(2), vecA(2));
36+
37+
// Negation operator
38+
Vec3T vecC = -vecA;
39+
EXPECT_EQ(vecC(0), -vecA(0));
40+
EXPECT_EQ(vecC(1), -vecA(1));
41+
EXPECT_EQ(vecC(2), -vecA(2));
42+
43+
// Multiply each element of the vector by a scalar
44+
Vec3T vecD = vecA;
45+
const ValueT gr = ValueT(1.6180339887);
46+
vecD *= gr;
47+
EXPECT_EQ(vecD(0), ValueT(gr * vecA(0)));
48+
EXPECT_EQ(vecD(1), ValueT(gr * vecA(1)));
49+
EXPECT_EQ(vecD(2), ValueT(gr * vecA(2)));
50+
51+
// Multiply each element of the vector by the corresponding element
52+
Vec3T vecE = vecA;
53+
Vec3T vecF(-2.5, 1.2, 3.14159);
54+
vecE *= vecF;
55+
EXPECT_EQ(vecE(0), ValueT(vecA(0) * vecF(0)));
56+
EXPECT_EQ(vecE(1), ValueT(vecA(1) * vecF(1)));
57+
EXPECT_EQ(vecE(2), ValueT(vecA(2) * vecF(2)));
58+
59+
// Divide each element of the vector by a scalar
60+
Vec3T vecG = vecA;
61+
vecG /= gr;
62+
EXPECT_EQ(vecG(0), ValueT(vecA(0) / gr));
63+
EXPECT_EQ(vecG(1), ValueT(vecA(1) / gr));
64+
EXPECT_EQ(vecG(2), ValueT(vecA(2) / gr));
65+
66+
// Divide each element of the vector by the corresponding element of the given vector
67+
Vec3T vecH = vecA;
68+
vecH /= vecF;
69+
EXPECT_EQ(vecH(0), ValueT(vecA(0) / vecF(0)));
70+
EXPECT_EQ(vecH(1), ValueT(vecA(1) / vecF(1)));
71+
EXPECT_EQ(vecH(2), ValueT(vecA(2) / vecF(2)));
72+
73+
// Add a scalar to each element of the vector
74+
Vec3T vecI = vecA;
75+
vecI += gr;
76+
EXPECT_EQ(vecI(0), ValueT(vecA(0) + gr));
77+
EXPECT_EQ(vecI(1), ValueT(vecA(1) + gr));
78+
EXPECT_EQ(vecI(2), ValueT(vecA(2) + gr));
79+
80+
// Add each element of the given vector to the corresponding element of this vector
81+
Vec3T vecJ = vecA;
82+
vecJ += vecF;
83+
EXPECT_EQ(vecJ(0), ValueT(vecA(0) + vecF(0)));
84+
EXPECT_EQ(vecJ(1), ValueT(vecA(1) + vecF(1)));
85+
EXPECT_EQ(vecJ(2), ValueT(vecA(2) + vecF(2)));
86+
87+
// Subtract a scalar from each element of this vector
88+
Vec3T vecK = vecA;
89+
vecK -= gr;
90+
EXPECT_EQ(vecK(0), ValueT(vecA(0) - gr));
91+
EXPECT_EQ(vecK(1), ValueT(vecA(1) - gr));
92+
EXPECT_EQ(vecK(2), ValueT(vecA(2) - gr));
93+
94+
// Subtract each element of the given vector from the corresponding element of this vector
95+
Vec3T vecL = vecA;
96+
vecL -= vecF;
97+
EXPECT_EQ(vecL(0), ValueT(vecA(0) - vecF(0)));
98+
EXPECT_EQ(vecL(1), ValueT(vecA(1) - vecF(1)));
99+
EXPECT_EQ(vecL(2), ValueT(vecA(2) - vecF(2)));
100+
}
101+
}
102+
103+
TEST_F(TestMath, testMemberOperators)
104+
{
105+
using namespace openvdb;
106+
107+
testMemberOperatorsImpl<math::half>();
108+
testMemberOperatorsImpl<float>();
109+
testMemberOperatorsImpl<double>();
110+
}
111+
112+
template<typename ValueT>
113+
void testFreeFunctionOperatorsImpl()
114+
{
115+
using namespace openvdb;
116+
using Vec3T = math::Vec3<ValueT>;
117+
118+
{
119+
// Vec3T vecA(3.14,2.18,ValueT(-299792458.f));
120+
Vec3T vecA(1,2,3);
121+
Vec3T vecB(3,4,5);
122+
const ValueT gr = ValueT(1.6180339887);
123+
124+
/// Equality operator, does exact floating point comparisons ==
125+
bool eqRes = vecA == vecB;
126+
EXPECT_FALSE(eqRes);
127+
128+
/// Inequality operator, does exact floating point comparisons !=
129+
bool ineqRes = vecA != vecB;
130+
EXPECT_TRUE(ineqRes);
131+
132+
/// Multiply each element of the given vector by @a scalar and return the result. scalar * vec
133+
Vec3T scalarMultiplyA = gr * vecA;
134+
EXPECT_EQ(scalarMultiplyA(0), ValueT(vecA(0) * gr));
135+
EXPECT_EQ(scalarMultiplyA(1), ValueT(vecA(1) * gr));
136+
EXPECT_EQ(scalarMultiplyA(2), ValueT(vecA(2) * gr));
137+
138+
/// Multiply each element of the given vector by @a scalar and return the result. vec * scalar
139+
Vec3T scalarMultiplyB = vecA * gr;
140+
EXPECT_EQ(scalarMultiplyB(0), ValueT(vecA(0) * gr));
141+
EXPECT_EQ(scalarMultiplyB(1), ValueT(vecA(1) * gr));
142+
EXPECT_EQ(scalarMultiplyB(2), ValueT(vecA(2) * gr));
143+
144+
/// Multiply corresponding elements of @a v0 and @a v1 and return the result. vec0 * vec1
145+
Vec3T multiplyRes = vecA * vecB;
146+
EXPECT_EQ(multiplyRes, Vec3T(3, 8, 15));
147+
148+
/// Divide @a scalar by each element of the given vector and return the result. a / vec
149+
Vec3T scalarDivA = gr / vecA;
150+
EXPECT_EQ(scalarDivA(0), ValueT(gr / vecA(0)));
151+
EXPECT_EQ(scalarDivA(1), ValueT(gr / vecA(1)));
152+
EXPECT_EQ(scalarDivA(2), ValueT(gr / vecA(2)));
153+
154+
/// Divide each element of the given vector by @a scalar and return the result. vec / scalar
155+
Vec3T scalarDivB = vecA / gr;
156+
EXPECT_EQ(scalarDivB(0), ValueT(vecA(0) / gr));
157+
EXPECT_EQ(scalarDivB(1), ValueT(vecA(1) / gr));
158+
EXPECT_EQ(scalarDivB(2), ValueT(vecA(2) / gr));
159+
160+
/// Divide corresponding elements of @a v0 and @a v1 and return the result. vec0 / vec1
161+
Vec3T divRes = vecA / vecB;
162+
EXPECT_EQ(divRes(0), ValueT(ValueT(vecA(0)) / ValueT(vecB(0))));
163+
EXPECT_EQ(divRes(1), ValueT(ValueT(vecA(1)) / ValueT(vecB(1))));
164+
EXPECT_EQ(divRes(2), ValueT(ValueT(vecA(2)) / ValueT(vecB(2))));
165+
166+
/// Add corresponding elements of @a v0 and @a v1 and return the result. vec0 + vec1
167+
Vec3T addRes = vecA + vecB;
168+
EXPECT_EQ(addRes, Vec3T(4, 6, 8));
169+
170+
/// Add @a scalar to each element of the given vector and return the result. a + vec
171+
Vec3T addScalarRes = vecA + gr;
172+
EXPECT_EQ(addScalarRes(0), ValueT(vecA(0) + gr));
173+
EXPECT_EQ(addScalarRes(1), ValueT(vecA(1) + gr));
174+
EXPECT_EQ(addScalarRes(2), ValueT(vecA(2) + gr));
175+
176+
/// Subtract corresponding elements of @a v0 and @a v1 and return the result. vec0 - vec1
177+
Vec3T subtractRes = vecA - vecB;
178+
EXPECT_EQ(subtractRes, Vec3T(-2, -2, -2));
179+
180+
/// Subtract @a scalar from each element of the given vector and return the result. vec0 - a
181+
Vec3T subScalarRes = vecA - gr;
182+
EXPECT_EQ(subScalarRes(0), ValueT(vecA(0) - gr));
183+
EXPECT_EQ(subScalarRes(1), ValueT(vecA(1) - gr));
184+
EXPECT_EQ(subScalarRes(2), ValueT(vecA(2) - gr));
185+
}
186+
}
187+
188+
TEST_F(TestMath, testFreeFunctionOperators)
189+
{
190+
using namespace openvdb;
191+
testFreeFunctionOperatorsImpl<math::half>();
192+
193+
}
194+
16195

17196
// This suite of tests obviously needs to be expanded!
18197
TEST_F(TestMath, testAll)
@@ -23,6 +202,7 @@ TEST_F(TestMath, testAll)
23202
EXPECT_EQ(math::Sign( 3 ), 1);
24203
EXPECT_EQ(math::Sign(-1.0 ),-1);
25204
EXPECT_EQ(math::Sign( 0.0f), 0);
205+
EXPECT_EQ(math::Sign(math::half(0.)), 0);
26206
}
27207
{// SignChange
28208
EXPECT_TRUE( math::SignChange( -1, 1));

openvdb/openvdb/unittest/TestTools.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ testLevelSetSphereImpl()
123123
using Vec3T = typename openvdb::math::Vec3<ValueT>;
124124

125125
const ValueT radius = 4.3f;
126-
const Vec3T center(ValueT(15.8), ValueT(13.2), ValueT(16.7));
126+
Vec3T center(ValueT(15.8), ValueT(13.2), ValueT(16.7));
127127
const ValueT voxelSize = 1.5f, width = 3.25f;
128128
const int dim = 32;
129129
ValueT tolerance = std::is_floating_point<typename GridT::ValueType>::value ? 0.0001 : 0.004;
@@ -140,8 +140,14 @@ testLevelSetSphereImpl()
140140
for (int i=0; i<dim; ++i) {
141141
for (int j=0; j<dim; ++j) {
142142
for (int k=0; k<dim; ++k) {
143+
// Vec3T p(voxelSize*float(i), voxelSize*float(j), voxelSize*float(k));
144+
// Vec3T foobar = p;
145+
// foobar -= center;
146+
// const float dist = foobar.length() - radius;
143147
const openvdb::Vec3f p(voxelSize*float(i), voxelSize*float(j), voxelSize*float(k));
144-
const float dist = (p-center).length() - radius;
148+
const float dist = (p-openvdb::Vec3f(center)).length() - radius;
149+
//char* foo = openvdb::math::promote<openvdb::Vec3f::ValueType, typename Vec3T::ValueType>::type(1);
150+
//std::cout << foo << std::endl;
145151
const float val1 = grid1->tree().getValue(openvdb::Coord(i,j,k));
146152
const float val2 = grid2->tree().getValue(openvdb::Coord(i,j,k));
147153
if (dist > outside) {

openvdb/openvdb/unittest/TestTree.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,7 +2015,9 @@ testSignedFloodFillImpl()
20152015
for (xyz[1]=0; xyz[1]<dim[1]; ++xyz[1]) {
20162016
for (xyz[2]=0; xyz[2]<dim[2]; ++xyz[2]) {
20172017
const openvdb::Vec3R p = grid->transform().indexToWorld(xyz);
2018-
const ValueT dist = float((p-center).length() - radius);
2018+
Vec3T foobar = p;
2019+
foobar -= center;
2020+
const ValueT dist = float(foobar.length() - radius);
20192021
if (fabs(dist) > outside) continue;
20202022
acc.setValue(xyz, dist);
20212023
}
@@ -2030,7 +2032,9 @@ testSignedFloodFillImpl()
20302032
for (xyz[1]=0; xyz[1]<dim[1]; ++xyz[1]) {
20312033
for (xyz[2]=0; xyz[2]<dim[2]; ++xyz[2]) {
20322034
const openvdb::Vec3R p = grid->transform().indexToWorld(xyz);
2033-
const ValueT dist = ValueT((p-center).length() - radius);
2035+
Vec3T foobar = p;
2036+
foobar -= center;
2037+
const ValueT dist = ValueT(foobar.length() - radius);
20342038
const ValueT val = acc.getValue(xyz);
20352039
if (dist < inside) {
20362040
ASSERT_DOUBLES_EXACTLY_EQUAL( val, outside);
@@ -2052,7 +2056,9 @@ testSignedFloodFillImpl()
20522056
for (xyz[1]=0; xyz[1]<dim[1]; ++xyz[1]) {
20532057
for (xyz[2]=0; xyz[2]<dim[2]; ++xyz[2]) {
20542058
const openvdb::Vec3R p = grid->transform().indexToWorld(xyz);
2055-
const ValueT dist = ValueT((p-center).length() - radius);
2059+
Vec3T foobar = p;
2060+
foobar -= center;
2061+
const ValueT dist = ValueT(foobar.length() - radius);
20562062
const ValueT val = acc.getValue(xyz);
20572063
if (dist < inside) {
20582064
ASSERT_DOUBLES_EXACTLY_EQUAL( val, inside);

openvdb/openvdb/unittest/TestVolumeToSpheres.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ testClosestSurfacePointImpl()
174174
using Vec3T = typename openvdb::math::Vec3<ValueT>;
175175

176176
const ValueT voxelSize = ValueT(1.0);
177-
const Vec3T center{ValueT(0.0)}; // ensure multiple internal nodes
177+
const Vec3R center{ValueT(0.0)}; // ensure multiple internal nodes
178178

179179
for (const float radius: { 8.0f, 50.0f }) {
180180
// Construct a spherical level set.

pendingchanges/half_grid_support.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ Tests:
2121
[ ] Test explicit template instantiation
2222

2323
# TODO, but will be addressed later:
24-
[ ] Add support for csgUnion for HalfGrid.
24+
[ ] Add support for csgUnion for HalfGrid.

0 commit comments

Comments
 (0)