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;
272namespace local_util {
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());
314 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
315 if (mat.
det() < T(0.0))
continue;
317 const math::Vec3<T> tmpAngle = math::eulerAngles(mat, math::XYZ_ROTATION);
320 math::rotation<math::Mat3<T> >(
math::Vec3<T>(0, 0, 1), tmpAngle.
z()) *
322 math::rotation<math::Mat3<T> >(
math::Vec3<T>(1, 0, 0), tmpAngle.
x()) *
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) {
372 bool isAffine()
const {
return math::isAffine(mat); }
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>
435 ABTransform xform(inGrid.transform(), outGrid.transform());
437 if (Sampler::consistent() && xform.
isIdentity()) {
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;
509 tempGrid = doLevelSetRebuild(inGrid, zeroVal<ValueT>(),
510 halfWidth, halfWidth,
511 &outGrid.constTransform(), &interrupter);
519 outGrid.setTree(tempGrid->treePtr());
525 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
529template<
typename Sampler,
typename Gr
idType>
534 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
542GridTransformer::GridTransformer(
const Mat4R& xform):
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]) {
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 +
")");
647 remainder->preTranslate(-pivot);
656 remainder->preTranslate(pivot);
657 remainder->preScale(scaleRemainder);
658 remainder->preTranslate(-pivot);
659 remainder = &mPreScaleTransform;
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>
775 mIsRoot(true), mXform(xform), mBBox(b),
776 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
780 mIsRoot(false), mXform(xform), mBBox(b),
781 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
782 mInAcc(mInTree), mOutAcc(*mOutTree)
790 mXform(other.mXform),
792 mInTree(other.mInTree),
793 mOutTree(new TreeT(mInTree.background())),
796 mInterrupt(other.mInterrupt)
805 if (interrupt())
break;
808 if (!mBBox.
empty()) {
815 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
824 if (interrupt())
break;
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);
854 if (!interrupt()) mOutTree->merge(*other.mOutTree);
858 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
863 const TreeT& mInTree;
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();
885 const GridClass gridClass = inGrid.getGridClass();
892 RangeProc proc(xform,
CoordBBox(), inTree, outTree);
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...
Definition Exceptions.h:64
Definition Exceptions.h:65
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:251
bool empty() const
Return true if this bounding box is empty (i.e., encloses no coordinates).
Definition Coord.h:358
const Coord & min() const
Definition Coord.h:323
const Coord & max() const
Definition Coord.h:324
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:25
Int32 y() const
Definition Coord.h:131
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition Coord.h:175
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition Coord.h:183
Int32 x() const
Definition Coord.h:130
Int32 z() const
Definition Coord.h:132
3x3 matrix class.
Definition Vec4.h:21
bool eq(const Mat3 &m, T eps=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
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
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
Definition Mat4.h:798
Mat3< T > getMat3() const
Definition Mat4.h:297
static const Mat4< Real > & identity()
Definition Mat4.h:117
bool eq(const Mat4 &m, T eps=1.0e-8) const
Return true if this matrix is equivalent to m within a tolerance of eps.
Definition Mat4.h:333
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:85
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:133
T & y()
Definition Vec3.h:86
T & z()
Definition Vec3.h:87
static Vec3< T > zero()
Predefined constants, e.g. Vec3d v = Vec3d::xNegAxis();.
Definition Vec3.h:466
Definition TreeIterator.h:1303
The Value Accessor Implementation and API methods. The majoirty of the API matches the API of a compa...
Definition ValueAccessor.h:367
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:406
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition Vec2.h:504
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:904
@ X_AXIS
Definition Math.h:902
@ Y_AXIS
Definition Math.h:903
GridClass
Definition Types.h:453
@ GRID_LEVEL_SET
Definition Types.h:455
math::Mat4< Real > Mat4R
Definition Types.h:101
math::BBox< Vec3d > BBoxd
Definition Types.h:84
math::Vec3< Real > Vec3R
Definition Types.h:72
std::shared_ptr< T > SharedPtr
Definition Types.h:114
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:212
#define OPENVDB_NUMERIC_TREE_INSTANTIATE(Function)
Definition version.h.in:158
#define OPENVDB_VEC3_TREE_INSTANTIATE(Function)
Definition version.h.in:159
#define OPENVDB_VOLUME_TREE_INSTANTIATE(Function)
Definition version.h.in:160