Skip to content

Commit 48b6176

Browse files
committed
Adapt point conversion to work with Vec3f
Signed-off-by: Dan Bailey <[email protected]>
1 parent 05b3291 commit 48b6176

File tree

3 files changed

+238
-13
lines changed

3 files changed

+238
-13
lines changed

openvdb/openvdb/points/PointConversion.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ convertPointDataGridGroup( Group& group,
162162
const FilterT& filter = NullFilter(),
163163
const bool inCoreOnly = false);
164164

165+
// for internal use only - this traits class extracts T::value_type if defined,
166+
// otherwise falls back to using Vec3R
167+
namespace internal {
168+
template <typename...> using void_t = void;
169+
template <typename T, typename = void>
170+
struct ValueTypeTraits { using Type = Vec3R; /* default type if T::value_type is not defined*/ };
171+
template <typename T>
172+
struct ValueTypeTraits <T, void_t<typename T::value_type>> { using Type = typename T::value_type; };
173+
} // namespace internal
174+
165175
/// @ brief Given a container of world space positions and a target points per voxel,
166176
/// compute a uniform voxel size that would best represent the storage of the points in a grid.
167177
/// This voxel size is typically used for conversion of the points into a PointDataGrid.
@@ -172,9 +182,13 @@ convertPointDataGridGroup( Group& group,
172182
/// @param decimalPlaces for readability, truncate voxel size to this number of decimals
173183
/// @param interrupter an optional interrupter
174184
///
185+
/// @note VecT will be PositionWrapper::value_type or Vec3R (if there is no value_type defined)
186+
///
175187
/// @note if none or one point provided in positions, the default voxel size of 0.1 will be returned
176188
///
177-
template<typename PositionWrapper, typename InterrupterT = openvdb::util::NullInterrupter>
189+
template< typename PositionWrapper,
190+
typename InterrupterT = openvdb::util::NullInterrupter,
191+
typename VecT = typename internal::ValueTypeTraits<PositionWrapper>::Type>
178192
inline float
179193
computeVoxelSize( const PositionWrapper& positions,
180194
const uint32_t pointsPerVoxel,
@@ -565,7 +579,7 @@ struct ConvertPointDataGridGroupOp {
565579
const bool mInCoreOnly;
566580
}; // ConvertPointDataGridGroupOp
567581

568-
template<typename PositionArrayT>
582+
template<typename PositionArrayT, typename VecT = Vec3R>
569583
struct CalculatePositionBounds
570584
{
571585
CalculatePositionBounds(const PositionArrayT& positions,
@@ -582,7 +596,7 @@ struct CalculatePositionBounds
582596
, mMax(-std::numeric_limits<Real>::max()) {}
583597

584598
void operator()(const tbb::blocked_range<size_t>& range) {
585-
Vec3R pos;
599+
VecT pos;
586600
for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
587601
mPositions.getPos(n, pos);
588602
pos = mInverseMat.transform(pos);
@@ -603,7 +617,7 @@ struct CalculatePositionBounds
603617
private:
604618
const PositionArrayT& mPositions;
605619
const math::Mat4d& mInverseMat;
606-
Vec3R mMin, mMax;
620+
VecT mMin, mMax;
607621
};
608622

609623
} // namespace point_conversion_internal
@@ -867,7 +881,7 @@ convertPointDataGridGroup( Group& group,
867881
group.finalize();
868882
}
869883

870-
template<typename PositionWrapper, typename InterrupterT>
884+
template<typename PositionWrapper, typename InterrupterT, typename VecT>
871885
inline float
872886
computeVoxelSize( const PositionWrapper& positions,
873887
const uint32_t pointsPerVoxel,
@@ -938,7 +952,7 @@ computeVoxelSize( const PositionWrapper& positions,
938952
inverseTransform = math::unit(inverseTransform);
939953

940954
tbb::blocked_range<size_t> range(0, numPoints);
941-
CalculatePositionBounds<PositionWrapper> calculateBounds(positions, inverseTransform);
955+
CalculatePositionBounds<PositionWrapper, VecT> calculateBounds(positions, inverseTransform);
942956
tbb::parallel_reduce(range, calculateBounds);
943957

944958
BBoxd bbox = calculateBounds.getBoundingBox();
@@ -1000,7 +1014,7 @@ computeVoxelSize( const PositionWrapper& positions,
10001014
MaskGrid::Ptr mask = createGrid<MaskGrid>(false);
10011015
mask->setTransform(newTransform);
10021016
tools::PointsToMask<MaskGrid, InterrupterT> pointMaskOp(*mask, interrupter);
1003-
pointMaskOp.addPoints(positions);
1017+
pointMaskOp.template addPoints<PositionWrapper, VecT>(positions);
10041018

10051019
if (interrupter && util::wasInterrupted(interrupter)) break;
10061020

openvdb/openvdb/tools/PointsToMask.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,20 @@ class PointsToMask
123123
/// @param points List of points that active the voxels in the input grid.
124124
/// @param grainSize Set the grain-size used for multi-threading. A value of 0
125125
/// disables multi-threading!
126-
template<typename PointListT>
126+
template<typename PointListT, typename VecT = Vec3R>
127127
void addPoints(const PointListT& points, size_t grainSize = 1024)
128128
{
129129
if (mInterrupter) mInterrupter->start("PointsToMask: adding points");
130130
if (grainSize > 0) {
131131
typename GridT::Ptr examplar = mGrid->copyWithNewTree();
132132
PoolType pool( *examplar );//thread local storage pool of grids
133-
AddPoints<PointListT> tmp(points, pool, grainSize, *this );
133+
AddPoints<PointListT, VecT> tmp(points, pool, grainSize, *this );
134134
if ( this->interrupt() ) return;
135135
ReducePool reducePool(pool, mGrid, size_t(0));
136136
} else {
137137
const math::Transform& xform = mGrid->transform();
138138
typename GridT::Accessor acc = mGrid->getAccessor();
139-
Vec3R wPos;
139+
VecT wPos;
140140
for (size_t i = 0, n = points.size(); i < n; ++i) {
141141
if ( this->interrupt() ) break;
142142
points.getPos(i, wPos);
@@ -163,7 +163,7 @@ class PointsToMask
163163
// Private struct that implements concurrent thread-local
164164
// insersion of points into a grid
165165
using PoolType = tbb::enumerable_thread_specific<GridT>;
166-
template<typename PointListT> struct AddPoints;
166+
template<typename PointListT, typename VecT = Vec3R> struct AddPoints;
167167

168168
// Private class that implements concurrent reduction of a thread-local pool
169169
struct ReducePool;
@@ -175,7 +175,7 @@ class PointsToMask
175175
// Private member class that implements concurrent thread-local
176176
// insersion of points into a grid
177177
template<typename GridT, typename InterrupterT>
178-
template<typename PointListT>
178+
template<typename PointListT, typename VecT>
179179
struct PointsToMask<GridT, InterrupterT>::AddPoints
180180
{
181181
AddPoints(const PointListT& points,
@@ -194,7 +194,7 @@ struct PointsToMask<GridT, InterrupterT>::AddPoints
194194
GridT& grid = mPool->local();
195195
const math::Transform& xform = grid.transform();
196196
typename GridT::Accessor acc = grid.getAccessor();
197-
Vec3R wPos;
197+
VecT wPos;
198198
for (size_t i=range.begin(), n=range.end(); i!=n; ++i) {
199199
mPoints->getPos(i, wPos);
200200
acc.setValueOn( xform.worldToIndexCellCentered( wPos ) );

openvdb/openvdb/unittest/TestPointConversion.cc

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,3 +1242,214 @@ TEST_F(TestPointConversion, testPrecision)
12421242
EXPECT_EQ(positionAfterNull.z(), positionAfterFixed16.z());
12431243
}
12441244
}
1245+
1246+
TEST_F(TestPointConversion, testExample)
1247+
{
1248+
// this is the example from the documentation using both Vec3R and Vec3f
1249+
1250+
{ // Vec3R
1251+
// Create a vector with four point positions.
1252+
std::vector<openvdb::Vec3R> positions;
1253+
positions.push_back(openvdb::Vec3R(0, 1, 0));
1254+
positions.push_back(openvdb::Vec3R(1.5, 3.5, 1));
1255+
positions.push_back(openvdb::Vec3R(-1, 6, -2));
1256+
positions.push_back(openvdb::Vec3R(1.1, 1.25, 0.06));
1257+
1258+
// The VDB Point-Partioner is used when bucketing points and requires a
1259+
// specific interface. For convenience, we use the PointAttributeVector
1260+
// wrapper around an stl vector wrapper here, however it is also possible to
1261+
// write one for a custom data structure in order to match the interface
1262+
// required.
1263+
openvdb::points::PointAttributeVector<openvdb::Vec3R> positionsWrapper(positions);
1264+
1265+
// This method computes a voxel-size to match the number of
1266+
// points / voxel requested. Although it won't be exact, it typically offers
1267+
// a good balance of memory against performance.
1268+
int pointsPerVoxel = 8;
1269+
float voxelSize =
1270+
openvdb::points::computeVoxelSize(positionsWrapper, pointsPerVoxel);
1271+
1272+
// Create a transform using this voxel-size.
1273+
openvdb::math::Transform::Ptr transform =
1274+
openvdb::math::Transform::createLinearTransform(voxelSize);
1275+
1276+
// Create a PointDataGrid containing these four points and using the
1277+
// transform given. This function has two template parameters, (1) the codec
1278+
// to use for storing the position, (2) the grid we want to create
1279+
// (ie a PointDataGrid).
1280+
// We use no compression here for the positions.
1281+
openvdb::points::PointDataGrid::Ptr grid =
1282+
openvdb::points::createPointDataGrid<openvdb::points::NullCodec,
1283+
openvdb::points::PointDataGrid>(positions, *transform);
1284+
1285+
// Set the name of the grid
1286+
grid->setName("Points");
1287+
1288+
// Create a VDB file object and write out the grid.
1289+
openvdb::io::File("mypoints.vdb").write({grid});
1290+
1291+
// Create a new VDB file object for reading.
1292+
openvdb::io::File newFile("mypoints.vdb");
1293+
1294+
// Open the file. This reads the file header, but not any grids.
1295+
newFile.open();
1296+
1297+
// Read the grid by name.
1298+
openvdb::GridBase::Ptr baseGrid = newFile.readGrid("Points");
1299+
newFile.close();
1300+
1301+
// From the example above, "Points" is known to be a PointDataGrid,
1302+
// so cast the generic grid pointer to a PointDataGrid pointer.
1303+
grid = openvdb::gridPtrCast<openvdb::points::PointDataGrid>(baseGrid);
1304+
1305+
std::vector<Vec3R> resultingPositions;
1306+
1307+
// Iterate over all the leaf nodes in the grid.
1308+
for (auto leafIter = grid->tree().cbeginLeaf(); leafIter; ++leafIter) {
1309+
1310+
// Extract the position attribute from the leaf by name (P is position).
1311+
const openvdb::points::AttributeArray& array =
1312+
leafIter->constAttributeArray("P");
1313+
1314+
// Create a read-only AttributeHandle. Position always uses Vec3f.
1315+
openvdb::points::AttributeHandle<openvdb::Vec3f> positionHandle(array);
1316+
1317+
// Iterate over the point indices in the leaf.
1318+
for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) {
1319+
1320+
// Extract the voxel-space position of the point.
1321+
openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter);
1322+
1323+
// Extract the index-space position of the voxel.
1324+
const openvdb::Vec3d xyz = indexIter.getCoord().asVec3d();
1325+
1326+
// Compute the world-space position of the point.
1327+
openvdb::Vec3f worldPosition =
1328+
grid->transform().indexToWorld(voxelPosition + xyz);
1329+
1330+
resultingPositions.push_back(worldPosition);
1331+
}
1332+
}
1333+
1334+
EXPECT_EQ(size_t(4), resultingPositions.size());
1335+
1336+
// remap the position order
1337+
1338+
std::vector<size_t> remap;
1339+
remap.push_back(1);
1340+
remap.push_back(3);
1341+
remap.push_back(0);
1342+
remap.push_back(2);
1343+
1344+
for (int i = 0; i < 4; i++) {
1345+
EXPECT_NEAR(positions[i].x(), resultingPositions[remap[i]].x(), /*tolerance=*/1e-6);
1346+
EXPECT_NEAR(positions[i].y(), resultingPositions[remap[i]].y(), /*tolerance=*/1e-6);
1347+
EXPECT_NEAR(positions[i].z(), resultingPositions[remap[i]].z(), /*tolerance=*/1e-6);
1348+
}
1349+
1350+
remove("mypoints.vdb");
1351+
}
1352+
1353+
{ // Vec3f
1354+
// Create a vector with four point positions.
1355+
std::vector<openvdb::Vec3f> positions;
1356+
positions.push_back(openvdb::Vec3f(0.0f, 1.0f, 0.0f));
1357+
positions.push_back(openvdb::Vec3f(1.5f, 3.5f, 1.0f));
1358+
positions.push_back(openvdb::Vec3f(-1.0f, 6.0f, -2.0f));
1359+
positions.push_back(openvdb::Vec3f(1.1f, 1.25f, 0.06f));
1360+
1361+
// The VDB Point-Partioner is used when bucketing points and requires a
1362+
// specific interface. For convenience, we use the PointAttributeVector
1363+
// wrapper around an stl vector wrapper here, however it is also possible to
1364+
// write one for a custom data structure in order to match the interface
1365+
// required.
1366+
openvdb::points::PointAttributeVector<openvdb::Vec3f> positionsWrapper(positions);
1367+
1368+
// This method computes a voxel-size to match the number of
1369+
// points / voxel requested. Although it won't be exact, it typically offers
1370+
// a good balance of memory against performance.
1371+
int pointsPerVoxel = 8;
1372+
float voxelSize =
1373+
openvdb::points::computeVoxelSize(positionsWrapper, pointsPerVoxel);
1374+
1375+
// Create a transform using this voxel-size.
1376+
openvdb::math::Transform::Ptr transform =
1377+
openvdb::math::Transform::createLinearTransform(voxelSize);
1378+
1379+
// Create a PointDataGrid containing these four points and using the
1380+
// transform given. This function has two template parameters, (1) the codec
1381+
// to use for storing the position, (2) the grid we want to create
1382+
// (ie a PointDataGrid).
1383+
// We use no compression here for the positions.
1384+
openvdb::points::PointDataGrid::Ptr grid =
1385+
openvdb::points::createPointDataGrid<openvdb::points::NullCodec,
1386+
openvdb::points::PointDataGrid>(positions, *transform);
1387+
1388+
// Set the name of the grid
1389+
grid->setName("Points");
1390+
1391+
// Create a VDB file object and write out the grid.
1392+
openvdb::io::File("mypoints.vdb").write({grid});
1393+
1394+
// Create a new VDB file object for reading.
1395+
openvdb::io::File newFile("mypoints.vdb");
1396+
1397+
// Open the file. This reads the file header, but not any grids.
1398+
newFile.open();
1399+
1400+
// Read the grid by name.
1401+
openvdb::GridBase::Ptr baseGrid = newFile.readGrid("Points");
1402+
newFile.close();
1403+
1404+
// From the example above, "Points" is known to be a PointDataGrid,
1405+
// so cast the generic grid pointer to a PointDataGrid pointer.
1406+
grid = openvdb::gridPtrCast<openvdb::points::PointDataGrid>(baseGrid);
1407+
1408+
std::vector<Vec3f> resultingPositions;
1409+
1410+
// Iterate over all the leaf nodes in the grid.
1411+
for (auto leafIter = grid->tree().cbeginLeaf(); leafIter; ++leafIter) {
1412+
1413+
// Extract the position attribute from the leaf by name (P is position).
1414+
const openvdb::points::AttributeArray& array =
1415+
leafIter->constAttributeArray("P");
1416+
1417+
// Create a read-only AttributeHandle. Position always uses Vec3f.
1418+
openvdb::points::AttributeHandle<openvdb::Vec3f> positionHandle(array);
1419+
1420+
// Iterate over the point indices in the leaf.
1421+
for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) {
1422+
1423+
// Extract the voxel-space position of the point.
1424+
openvdb::Vec3f voxelPosition = positionHandle.get(*indexIter);
1425+
1426+
// Extract the index-space position of the voxel.
1427+
const openvdb::Vec3d xyz = indexIter.getCoord().asVec3d();
1428+
1429+
// Compute the world-space position of the point.
1430+
openvdb::Vec3f worldPosition =
1431+
grid->transform().indexToWorld(voxelPosition + xyz);
1432+
1433+
resultingPositions.push_back(worldPosition);
1434+
}
1435+
}
1436+
1437+
EXPECT_EQ(size_t(4), resultingPositions.size());
1438+
1439+
// remap the position order
1440+
1441+
std::vector<size_t> remap;
1442+
remap.push_back(1);
1443+
remap.push_back(3);
1444+
remap.push_back(0);
1445+
remap.push_back(2);
1446+
1447+
for (int i = 0; i < 4; i++) {
1448+
EXPECT_NEAR(positions[i].x(), resultingPositions[remap[i]].x(), /*tolerance=*/1e-6f);
1449+
EXPECT_NEAR(positions[i].y(), resultingPositions[remap[i]].y(), /*tolerance=*/1e-6f);
1450+
EXPECT_NEAR(positions[i].z(), resultingPositions[remap[i]].z(), /*tolerance=*/1e-6f);
1451+
}
1452+
1453+
remove("mypoints.vdb");
1454+
}
1455+
}

0 commit comments

Comments
 (0)