7#ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
8#define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
20#include <tbb/blocked_range.h>
21#include <tbb/parallel_reduce.h>
53template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
55resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
78template<
typename Sampler,
typename Gr
idType>
92template<
typename Sampler,
typename TreeT>
93class TileSampler:
public Sampler
96 using ValueT =
typename TreeT::ValueType;
101 TileSampler(
const CoordBBox& b,
const ValueT& tileVal,
bool on):
102 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
104 mBBox.expand(-this->radius());
105 mEmpty = mBBox.empty();
108 bool sample(
const TreeT& inTree,
const Vec3R& inCoord, ValueT& result)
const
110 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
111 return Sampler::sample(inTree, inCoord, result);
117 bool mActive, mEmpty;
123template<
typename TreeT>
124class TileSampler<PointSampler, TreeT>:
public PointSampler {
126 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
131template<
typename TreeT>
132class TileSampler<StaggeredPointSampler, TreeT>:
public StaggeredPointSampler {
134 TileSampler(
const CoordBBox&,
const typename TreeT::ValueType&,
bool) {}
186 template<
typename InterrupterType>
void setInterrupter(InterrupterType&);
188 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
189 void transformGrid(
const Transformer&,
190 const GridT& inGrid, GridT&
outGrid)
const;
193 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
194 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT&
outGrid)
const;
196 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
199 template<
typename Sampler,
typename InTreeT,
typename OutTreeT,
typename Transformer>
200 static void transformBBox(
const Transformer&,
const CoordBBox& inBBox,
201 const InTreeT& inTree,
OutTreeT& outTree,
const InterruptFunc&,
204 template<
typename Sampler,
typename TreeT,
typename Transformer>
205 class RangeProcessor;
207 bool mThreaded, mTransformTiles;
208 InterruptFunc mInterrupt;
243 const Vec3R& translate,
244 const std::string& xformOrder =
"tsr",
245 const std::string& rotationOrder =
"zyx");
253 template<
class Sampler,
class Gr
idT>
254 void transformGrid(
const GridT& inGrid, GridT&
outGrid)
const;
257 struct MatrixTransform;
259 inline void init(
const Vec3R& pivot,
const Vec3R& scale,
261 const std::string& xformOrder,
const std::string& rotOrder);
265 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
298 const bool hasUniformScale = unsignedScale.
eq(
math::Vec3<T>(unsignedScale[0]));
300 bool hasRotation =
false;
301 bool validDecomposition =
false;
303 T minAngle = std::numeric_limits<T>::max();
307 for (
size_t n = 0; n < 8; ++n) {
309 n & 0x1 ? -unsignedScale.
x() : unsignedScale.
x(),
310 n & 0x2 ? -unsignedScale.
y() : unsignedScale.
y(),
311 n & 0x4 ? -unsignedScale.
z() : unsignedScale.
z());
315 if (mat.
det() < T(0.0))
continue;
325 if (xform.
eq(rebuild)) {
327 const T maxAngle = std::max(std::abs(tmpAngle[0]),
328 std::max(std::abs(tmpAngle[1]), std::abs(tmpAngle[2])));
330 if (!(minAngle < maxAngle)) {
337 validDecomposition =
true;
339 if (hasUniformScale || !hasRotation) {
347 if (!validDecomposition) {
351 if (hasRotation && !hasUniformScale) {
397 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
398 mIsIdentity(mIsAffine && mAXform == mBXform)
407 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
412 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
420 const bool mIsAffine;
421 const bool mIsIdentity;
431template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
440 outGrid.setTree(inGrid.tree().copy());
446 ( xform.
getB().baseMap()->getAffineMap()->getMat4().inverse() );
464template<
typename ValueType>
466 static ValueType
eval(
const ValueType& background,
const Vec3d& voxelSize)
469 ValueType result(background * (1.0 / voxelSize[0]));
484template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
491 if (inGrid.constTransform() ==
outGrid.constTransform()) {
494 outGrid.setTree(inGrid.tree().copy());
500 using ValueT =
typename GridType::ValueType;
503 const ValueT halfWidth = outIsLevelSet
507 typename GridType::Ptr tempGrid;
510 halfWidth, halfWidth,
511 &
outGrid.constTransform(), &interrupter);
519 outGrid.setTree(tempGrid->treePtr());
529template<
typename Sampler,
typename Gr
idType>
546 mPreScaleTransform(
Mat4R::identity()),
547 mPostScaleTransform(
Mat4R::identity())
549 Vec3R scale, rotate, translate;
553 init(mPivot, scale, rotate, translate,
"rst",
"zyx");
562 const std::string& xformOrder,
const std::string& rotOrder):
565 mPreScaleTransform(
Mat4R::identity()),
566 mPostScaleTransform(
Mat4R::identity())
568 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
576GridTransformer::init(
579 const std::string& xformOrder,
const std::string& rotOrder)
581 if (xformOrder.size() != 3) {
584 if (rotOrder.size() != 3) {
593 Vec3R scaleRemainder = scale;
594 for (
int i = 0; i < 3; ++i) {
595 double s = std::fabs(scale(i));
597 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
598 scaleRemainder(i) = scale(i) * (1 << mMipLevels(i));
607 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
608 Mat4R* remainder = &mPostScaleTransform;
609 int rpos, spos, tpos;
610 rpos = spos = tpos = 3;
611 for (
int ix = 2; ix >= 0; --ix) {
612 switch (xformOrder[ix]) {
616 mTransform.preTranslate(pivot);
617 remainder->preTranslate(pivot);
619 int xpos, ypos, zpos;
620 xpos = ypos = zpos = 3;
621 for (
int ir = 2; ir >= 0; --ir) {
622 switch (rotOrder[ir]) {
642 if (xpos > 2 || ypos > 2 || zpos > 2) {
643 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
646 mTransform.preTranslate(-pivot);
647 remainder->preTranslate(-pivot);
652 mTransform.preTranslate(pivot);
653 mTransform.preScale(scale);
654 mTransform.preTranslate(-pivot);
656 remainder->preTranslate(pivot);
657 remainder->preScale(scaleRemainder);
658 remainder->preTranslate(-pivot);
659 remainder = &mPreScaleTransform;
664 mTransform.preTranslate(translate);
665 remainder->preTranslate(translate);
671 if (tpos > 2 || rpos > 2 || spos > 2) {
672 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
680template<
typename InterrupterType>
684 mInterrupt = std::bind(&InterrupterType::wasInterrupted,
689template<
typename Sampler,
typename Gr
idT,
typename Transformer>
692 const GridT& inGrid, GridT&
outGrid)
const
699template<
class Sampler,
class Gr
idT>
711 bool firstPass =
true;
712 const typename GridT::ValueType background = inGrid.background();
713 typename GridT::Ptr tempGrid = GridT::create(background);
725 Vec3i count = mMipLevels;
730 count.
x() ? .5 : 1, count.
y() ? .5 : 1, count.
z() ? .5 : 1));
741 typename GridT::Ptr destGrid = GridT::create(background);
743 tempGrid.swap(destGrid);
754 outGrid.setTree(tempGrid->treePtr());
763template<
class Sampler,
class TreeT,
typename Transformer>
764class GridResampler::RangeProcessor
767 using LeafIterT =
typename TreeT::LeafCIter;
768 using TileIterT =
typename TreeT::ValueAllCIter;
774 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
775 mIsRoot(true), mXform(xform), mBBox(b),
776 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
779 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
780 mIsRoot(false), mXform(xform), mBBox(b),
781 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
782 mInAcc(mInTree), mOutAcc(*mOutTree)
785 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
788 RangeProcessor(RangeProcessor& other, tbb::split):
790 mXform(other.mXform),
792 mInTree(other.mInTree),
793 mOutTree(new TreeT(mInTree.background())),
796 mInterrupt(other.mInterrupt)
799 void setInterrupt(
const InterruptFunc& f) { mInterrupt = f; }
802 void operator()(
const LeafRange& r)
804 for (LeafRange it(r); it.test(); ++it) {
805 if (interrupt())
break;
806 LeafIterT i = it.iterator();
807 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
808 if (!mBBox.empty()) {
815 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
821 void operator()(
const TileRange& r)
823 for (TileRange it(r); it.test(); ++it) {
824 if (interrupt())
break;
826 TileIterT i = it.iterator();
828 if (!i.isTileValue())
continue;
832 i.getBoundingBox(bbox);
833 if (!mBBox.empty()) {
844 internal::TileSampler<Sampler, InTreeAccessor>
845 sampler(bbox, i.getValue(), i.isValueOn());
846 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
852 void join(RangeProcessor& other)
854 if (!interrupt()) mOutTree->merge(*other.mOutTree);
858 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
863 const TreeT& mInTree;
865 InTreeAccessor mInAcc;
866 OutTreeAccessor mOutAcc;
874template<
class Sampler,
class Gr
idT,
typename Transformer>
877 const GridT& inGrid, GridT&
outGrid)
const
879 using TreeT =
typename GridT::TreeType;
880 const TreeT& inTree = inGrid.tree();
881 TreeT& outTree =
outGrid.tree();
883 using RangeProc = RangeProcessor<Sampler, TreeT, Transformer>;
885 const GridClass gridClass = inGrid.getGridClass();
893 proc.setInterrupt(mInterrupt);
895 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
896 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
897 typename RangeProc::TileRange tileRange(tileIter);
900 tbb::parallel_reduce(tileRange,
proc);
910 clipBBox = inGrid.evalActiveVoxelBoundingBox();
915 RangeProc
proc(xform, clipBBox, inTree, outTree);
916 proc.setInterrupt(mInterrupt);
918 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
921 tbb::parallel_reduce(leafRange,
proc);
938template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
940GridResampler::transformBBox(
941 const Transformer& xform,
943 const InTreeT& inTree,
945 const InterruptFunc& interrupt,
948 using ValueT =
typename OutTreeT::ValueType;
954 inRMax(bbox.
max().
x()+1, bbox.
max().
y()+1, bbox.
max().
z()+1),
957 for (
int i = 0; i < 8; ++i) {
959 i & 1 ? inRMax.x() : inRMin.x(),
960 i & 2 ? inRMax.y() : inRMin.y(),
961 i & 4 ? inRMax.z() : inRMin.z());
969 if (!xform.isAffine()) {
974 int &x = outXYZ.
x(), &y = outXYZ.
y(), &z = outXYZ.
z();
975 for (x = outMin.
x(); x <= outMax.x(); ++x) {
978 for (y = outMin.
y(); y <= outMax.y(); ++y) {
981 for (z = outMin.
z(); z <= outMax.z(); ++z) {
983 inXYZ = xform.invTransform(xyz);
985 if (sampler.
sample(inTree, inXYZ, result)) {
986 outTree.setValueOn(outXYZ, result);
989 if (!outTree.isValueOn(outXYZ)) {
990 outTree.setValueOff(outXYZ, result);
1000 translation = xform.invTransform(
Vec3R(0, 0, 0)),
1001 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
1002 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
1003 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
1009 const Vec3R dummy = deltaX;
1014 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
1016 int &x = outXYZ.
x(), &y = outXYZ.y(), &z = outXYZ.z();
1017 for (x = outMin.
x(); x <= outMax.x(); ++x, inStartX += deltaX) {
1019 Vec3R inStartY = inStartX;
1020 for (y = outMin.
y(); y <= outMax.y(); ++y, inStartY += deltaY) {
1022 Vec3R inXYZ = inStartY;
1023 for (z = outMin.
z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
1025 if (sampler.
sample(inTree, inXYZ, result)) {
1026 outTree.setValueOn(outXYZ, result);
1029 if (!outTree.isValueOn(outXYZ)) {
1030 outTree.setValueOff(outXYZ, result);
1045#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1047#ifdef OPENVDB_INSTANTIATE_GRIDTRANSFORMER
1051#define _FUNCTION(TreeT) \
1052 void resampleToMatch<PointSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1056#define _FUNCTION(TreeT) \
1057 void resampleToMatch<BoxSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1061#define _FUNCTION(TreeT) \
1062 void resampleToMatch<QuadraticSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
1066#define _FUNCTION(TreeT) \
1067 void resampleToMatch<QuadraticSampler>(const Grid<TreeT>&, Grid<TreeT>&, util::NullInterrupter&)
Efficient multi-threaded replacement of the background values in tree.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Defined various multi-threaded utility functions for trees.
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
CoordBBox()
The default constructor produces an empty bounding box.
Definition Coord.h:297
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition Coord.h:176
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition Coord.h:184
Definition Exceptions.h:64
Definition Exceptions.h:65
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
const Coord & min() const
Definition Coord.h:324
const Coord & max() const
Definition Coord.h:325
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
Int32 y() const
Definition Coord.h:132
Int32 x() const
Definition Coord.h:131
Int32 z() const
Definition Coord.h:133
3x3 matrix class.
Definition Mat3.h:29
bool eq(const Mat3 &m, T eps=T(1.0e-8)) const
Return true if this matrix is equivalent to m within a tolerance of eps.
Definition Mat3.h:301
T det() const
Determinant of matrix.
Definition Mat3.h:479
4x4 -matrix class.
Definition Mat4.h:31
void preScale(const Vec3< T0 > &v)
Definition Mat4.h:736
Vec3< T > getTranslation() const
Return the translation component.
Definition Mat4.h:309
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this).
Definition Mat4.h:703
Mat4 inverse(T tolerance=0) const
Definition Mat4.h:485
Mat3< T > getMat3() const
Definition Mat4.h:297
static const Mat4< Real > & identity()
Definition Mat4.h:117
void setTranslation(const Vec3< T > &t)
Definition Mat4.h:314
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition Vec3.h:86
bool eq(const Vec3< T > &v, T eps=static_cast< T >(1.0e-7)) const
Test if "this" vector is equivalent to vector v with tolerance of eps.
Definition Vec3.h:134
T & y()
Definition Vec3.h:87
T & z()
Definition Vec3.h:88
static Vec3< T > zero()
Predefined constants, e.g. Vec3d v = Vec3d::xNegAxis();.
Definition Vec3.h:467
Definition TreeIterator.h:1304
Vec3< typename MatType::value_type > eulerAngles(const MatType &mat, RotationOrder rotationOrder, typename MatType::value_type eps=static_cast< typename MatType::value_type >(1.0e-8))
Return the Euler angles composing the given rotation matrix.
Definition Mat.h:333
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
Definition Math.h:431
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition Mat.h:615
Vec3< double > Vec3d
Definition Vec3.h:665
bool isAffine(const Mat4< T > &m)
Definition Mat4.h:1305
MatType rotation(const Quat< typename MatType::value_type > &q, typename MatType::value_type eps=static_cast< typename MatType::value_type >(1.0e-8))
Return the rotation matrix specified by the given quaternion.
Definition Mat.h:172
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition Vec2.h:504
Vec3< int32_t > Vec3i
Definition Vec3.h:662
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition Vec2.h:513
@ Z_AXIS
Definition Math.h:975
@ X_AXIS
Definition Math.h:973
@ Y_AXIS
Definition Math.h:974
@ XYZ_ROTATION
Definition Math.h:980
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
GridClass
Definition Types.h:520
@ GRID_LEVEL_SET
Definition Types.h:522
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
math::Mat4< Real > Mat4R
Definition Types.h:82
math::BBox< Vec3d > BBoxd
Definition Types.h:65
math::Vec3< Real > Vec3R
Definition Types.h:53
std::shared_ptr< T > SharedPtr
Definition Types.h:95
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Base class for interrupters.
Definition NullInterrupter.h:26
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218
#define OPENVDB_NUMERIC_TREE_INSTANTIATE(Function)
Definition version.h.in:163
#define OPENVDB_VEC3_TREE_INSTANTIATE(Function)
Definition version.h.in:164
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition version.h.in:165