OpenVDB  12.1.0
Public Member Functions | List of all members
TransformTransfer Struct Reference

The TransformTransfer module should be used if the source transform of the input points and the target transforms of the destination volumes differ. The default rasterizer will skip index to world (and vice versa) transformations unless a transfer scheme derives from a TransformTransfer. More...

#include <openvdb/points/PointTransfer.h>

Public Member Functions

 TransformTransfer (const math::Transform &st, const math::Transform &tt)
 
template<typename T >
auto transformSourceToTarget (const T &value) const
 
template<typename T >
auto transformTargetToSource (const T &value) const
 
const math::TransformsourceTransform () const
 
const math::TransformtargetTransform () const
 

Detailed Description

The TransformTransfer module should be used if the source transform of the input points and the target transforms of the destination volumes differ. The default rasterizer will skip index to world (and vice versa) transformations unless a transfer scheme derives from a TransformTransfer.

A transfer scheme must be configured to call the provided rasterize
methods. See below for an example, or the various native VDB files which implement schemes e.g.:
  • PointRasterizeSDF.h
  • PointRasterizeTrilinear.h
  • PrincipalComponentAnalysisImpl.h
    struct Transfer
    {
    /// @return Returns the tree topology to loop over. This can be different
    /// from the destination tree i.e. This can act as a mask.
    inline auto& topology();
    /// @brief The maximum lookup range of this transfer scheme in index
    /// space of the source points.
    /// @details The return value represent how far away from the destination
    /// leaf node points should be accessed.
    /// @param origin The leaf origin of the topology being accessed
    /// @param idx The leaf index of the topology being accessed
    inline Int32 range(const Coord& origin, size_t idx) const;
    /// @brief The initialize function, called on each leaf which has valid
    /// topology to write to.
    /// @param origin The leaf origin of the topology being accessed
    /// @param idx The leaf index of the topology being accessed
    /// @param bounds The active voxel bounds of the leaf
    inline void initialize(const Coord& origin, size_t idx, const CoordBBox& bounds);
    /// @brief Run each time a point leaf is accessed. Typically this is
    /// where attribute handles can be constructed
    /// @param leaf The PointDataLeafNode which is being accessed.
    /// @return Return true to continue rasterization, false to early exit
    /// and skip the current leaf's contribution to the destination volume.
    inline bool startPointLeaf(const PointDataTree::LeafNodeType& leaf);
    ///////////////////////////////////////////////////////////////////////
    // Transfer scheme must implement either:
    // - rasterizePoint(Coord, Index, CoordBBox) OR
    // - rasterizePoints(Coord, Index, Index, CoordBBox)
    /// @brief The point stamp function. Each point which contributes to
    /// the current leaf will call this function exactly once.
    /// @param ijk The current voxel containing the point being rasterized.
    /// May be outside the destination leaf node depending on the range()
    /// @param id The point index being rasterized
    /// @param bounds The active bounds of the leaf node.
    void rasterizePoint(const Coord& ijk,
    const Index id,
    const CoordBBox& bounds);
    /// @brief Same as above, except this is passed a range of points
    /// that all belong to the same voxel
    /// @param ijk The current voxel containing the point being rasterized.
    /// May be outside the destination leaf node depending on the range()
    /// @param start The start point index being rasterized
    /// @param end The end point index being rasterized
    /// @param bounds The active bounds of the leaf node.
    void rasterizePoints(const Coord& ijk,
    const Index start,
    const Index end,
    const CoordBBox& bounds);
    ///////////////////////////////////////////////////////////////////////
    /// @brief Run each time a point leaf is finished with.
    /// @param leaf The PointDataLeafNode which was being accessed.
    /// @return Return true to continue rasterization, false to early exit
    /// and stop rasterization to the destination leaf node.
    inline bool endPointLeaf(const PointDataTree::LeafNodeType& leaf);
    /// @brief The finalization function for the given destination tree(s).
    /// @param origin The leaf origin of the topology being accessed
    /// @param idx The leaf index of the topology being accessed
    /// @return Return true to stop, false to recursively rasterize
    inline bool finalize(const Coord& origin, size_t idx);
    };

Below is a full example using the native components.

/// @brief Sum point distances into a target float tree
/// Note: Using TransformTransfer to handle different index spaces, and
/// VolumeTransfer for automatic buffer setup
struct MyTransfer :
public VolumeTransfer<FloatTree>
{
MyTransfer(FloatGrid& dest, const PointDataGrid& source)
: TransformTransfer(source.transform(), dest.transform())
, VolumeTransfer(dest.tree()) {}
MyTransfer(const MyTransfer& other)
, VolumeTransfer(other) {}
/// @brief Range in index space of the source points
Vec3i range(const Coord&, size_t) const { return Vec3i(1); }
/// @brief Every time we start a new point leaf, init the position array.
/// Always return true as we don't skip any leaf nodes.
bool startPointLeaf(const PointDataTree::LeafNodeType& leaf)
{
// @note consider caching the indices to "P" and "mygroup" for faster lookups
mHandle = std::make_unique<AttributeHandle<Vec3f>>(leaf.constAttributeArray("P"));
mFilter = std::make_unique<GroupFilter>("mygroup", leaf.attributeSet());
return true;
}
/// @brief For each point, compute its relative index space position in
/// the destination tree and sum the length of its distance
void rasterizePoint(const Coord& ijk, const Index id, const CoordBBox& bounds)
{
// skip points not in "mygroup"
if (!mFilter->valid(&id)) return;
Vec3d P = ijk.asVec3d() + Vec3d(this->mHandle->get(id));
P = this->transformSourceToTarget(P); // TransformTransfer::transformSourceToTarget
// for each active voxel, accumulate distance
const auto* mask = this->mask(); // VolumeTransfer::mask
for (auto& coord : bounds) {
const Index voxel = FloatTree::LeafNodeType::coordToOffset(coord);
if (!mask->isOn(voxel)) continue;
Vec3d dist = coord.asVec3d() - P;
this->buffer()[voxel] += dist.length(); // VolumeTransfer::buffer
}
}
/// @brief Return true for endPointLeaf() to continue, false for finalize() so
/// we don't recurse.
bool endPointLeaf(const PointDataTree::LeafNodeType&) { return true; }
bool finalize(const Coord&, size_t) { return false; }
private:
std::unique_ptr<AttributeHandle<Vec3f>> mHandle {nullptr};
std::unique_ptr<GroupFilter> mFilter {nullptr};
};

Constructor & Destructor Documentation

TransformTransfer ( const math::Transform st,
const math::Transform tt 
)
inline

Member Function Documentation

const math::Transform& sourceTransform ( ) const
inline
const math::Transform& targetTransform ( ) const
inline
auto transformSourceToTarget ( const T &  value) const
inline
auto transformTargetToSource ( const T &  value) const
inline