7 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
8 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
19 #include <tbb/blocked_range.h>
20 #include <tbb/parallel_reduce.h>
52 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
54 resampleToMatch(
const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
77 template<
typename Sampler,
typename Gr
idType>
90 template<
typename Sampler,
typename TreeT>
94 using ValueT =
typename TreeT::ValueType;
100 mBBox(b.
min().asVec3d(), b.
max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
102 mBBox.expand(-this->radius());
103 mEmpty = mBBox.empty();
108 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal;
return mActive; }
109 return Sampler::sample(inTree, inCoord, result);
121 template<
typename TreeT>
129 template<
typename TreeT>
182 template<
typename InterrupterType>
void setInterrupter(InterrupterType&);
184 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
185 void transformGrid(
const Transformer&,
186 const GridT& inGrid, GridT& outGrid)
const;
189 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
190 void applyTransform(
const Transformer&,
const GridT& inGrid, GridT& outGrid)
const;
192 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
195 template<
typename Sampler,
typename InTreeT,
typename OutTreeT,
typename Transformer>
196 static void transformBBox(
const Transformer&,
const CoordBBox& inBBox,
197 const InTreeT& inTree, OutTreeT& outTree,
const InterruptFunc&,
200 template<
typename Sampler,
typename TreeT,
typename Transformer>
201 class RangeProcessor;
203 bool mThreaded, mTransformTiles;
204 InterruptFunc mInterrupt;
239 const Vec3R& translate,
240 const std::string& xformOrder =
"tsr",
241 const std::string& rotationOrder =
"zyx");
249 template<
class Sampler,
class Gr
idT>
250 void transformGrid(
const GridT& inGrid, GridT& outGrid)
const;
253 struct MatrixTransform;
257 const std::string& xformOrder,
const std::string& rotOrder);
261 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
268 namespace local_util {
289 const bool hasUniformScale = unsignedScale.
eq(
math::Vec3<T>(unsignedScale[0]));
291 bool hasRotation =
false;
292 bool validDecomposition =
false;
299 for (
size_t n = 0; n < 8; ++n) {
302 n & 0x1 ? -unsignedScale.
x() : unsignedScale.
x(),
303 n & 0x2 ? -unsignedScale.
y() : unsignedScale.
y(),
304 n & 0x4 ? -unsignedScale.
z() : unsignedScale.
z());
307 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
308 if (mat.det() < T(0.0))
continue;
313 math::rotation<math::Mat3<T> >(
math::Vec3<T>(1, 0, 0), tmpAngle.
x()) *
318 if (xform.
eq(rebuild)) {
320 const T maxAngle =
std::max(std::abs(tmpAngle[0]),
321 std::max(std::abs(tmpAngle[1]), std::abs(tmpAngle[2])));
323 if (!(minAngle < maxAngle)) {
330 validDecomposition =
true;
332 if (hasUniformScale || !hasRotation) {
340 if (!validDecomposition || (hasRotation && !hasUniformScale)) {
388 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
389 mIsIdentity(mIsAffine && mAXform == mBXform)
398 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
403 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
411 const bool mIsAffine;
412 const bool mIsIdentity;
422 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
426 ABTransform xform(inGrid.transform(), outGrid.transform());
428 if (Sampler::consistent() && xform.isIdentity()) {
431 outGrid.setTree(inGrid.tree().copy());
432 }
else if (xform.isAffine()) {
436 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
437 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
455 template<
typename Sampler,
typename Interrupter,
typename Gr
idType>
462 if (inGrid.constTransform() == outGrid.constTransform()) {
465 outGrid.setTree(inGrid.tree().copy());
471 using ValueT =
typename GridType::ValueType;
475 const ValueT halfWidth = outIsLevelSet
476 ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
477 : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0]));
480 typename GridType::Ptr tempGrid;
482 tempGrid = doLevelSetRebuild(inGrid, zeroVal<ValueT>(),
483 halfWidth, halfWidth,
484 &outGrid.constTransform(), &interrupter);
492 outGrid.setTree(tempGrid->treePtr());
498 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
502 template<
typename Sampler,
typename Gr
idType>
507 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
515 GridTransformer::GridTransformer(
const Mat4R& xform):
519 mPreScaleTransform(
Mat4R::identity()),
520 mPostScaleTransform(
Mat4R::identity())
526 init(mPivot,
scale, rotate, translate,
"srt",
"zyx");
535 const std::string& xformOrder,
const std::string& rotOrder):
538 mPreScaleTransform(
Mat4R::identity()),
539 mPostScaleTransform(
Mat4R::identity())
541 init(
pivot,
scale, rotate, translate, xformOrder, rotOrder);
549 GridTransformer::init(
552 const std::string& xformOrder,
const std::string& rotOrder)
554 if (xformOrder.size() != 3) {
557 if (rotOrder.size() != 3) {
567 for (
int i = 0; i < 3; ++i) {
568 double s = std::fabs(
scale(i));
570 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
571 scaleRemainder(i) =
scale(i) * (1 << mMipLevels(i));
580 mTransform = mPreScaleTransform = mPostScaleTransform =
Mat4R::identity();
581 Mat4R* remainder = &mPostScaleTransform;
582 int rpos, spos, tpos;
583 rpos = spos = tpos = 3;
584 for (
int ix = 2; ix >= 0; --ix) {
585 switch (xformOrder[ix]) {
590 remainder->preTranslate(
pivot);
592 int xpos, ypos, zpos;
593 xpos = ypos = zpos = 3;
594 for (
int ir = 2; ir >= 0; --ir) {
595 switch (rotOrder[ir]) {
615 if (xpos > 2 || ypos > 2 || zpos > 2) {
616 OPENVDB_THROW(ValueError,
"invalid rotation order (" + rotOrder +
")");
620 remainder->preTranslate(-
pivot);
629 remainder->preTranslate(
pivot);
630 remainder->preScale(scaleRemainder);
631 remainder->preTranslate(-
pivot);
632 remainder = &mPreScaleTransform;
638 remainder->preTranslate(translate);
644 if (tpos > 2 || rpos > 2 || spos > 2) {
645 OPENVDB_THROW(ValueError,
"invalid transform order (" + xformOrder +
")");
653 template<
typename InterrupterType>
662 template<
typename Sampler,
typename Gr
idT,
typename Transformer>
665 const GridT& inGrid, GridT& outGrid)
const
668 applyTransform<Sampler>(xform, inGrid, outGrid);
672 template<
class Sampler,
class Gr
idT>
681 applyTransform<Sampler>(xform, inGrid, outGrid);
684 bool firstPass =
true;
685 const typename GridT::ValueType background = inGrid.background();
686 typename GridT::Ptr tempGrid = GridT::create(background);
693 applyTransform<Sampler>(xform, inGrid, *tempGrid);
698 Vec3i count = mMipLevels;
699 while (count != Vec3i::zero()) {
703 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
710 applyTransform<Sampler>(xform, inGrid, *tempGrid);
714 typename GridT::Ptr destGrid = GridT::create(background);
715 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
716 tempGrid.swap(destGrid);
725 applyTransform<Sampler>(xform, *tempGrid, outGrid);
727 outGrid.setTree(tempGrid->treePtr());
736 template<
class Sampler,
class TreeT,
typename Transformer>
737 class GridResampler::RangeProcessor
740 using LeafIterT =
typename TreeT::LeafCIter;
741 using TileIterT =
typename TreeT::ValueAllCIter;
747 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inT, TreeT& outT):
748 mIsRoot(true), mXform(xform), mBBox(b),
749 mInTree(inT), mOutTree(&outT), mInAcc(mInTree), mOutAcc(*mOutTree)
752 RangeProcessor(
const Transformer& xform,
const CoordBBox& b,
const TreeT& inTree):
753 mIsRoot(false), mXform(xform), mBBox(b),
754 mInTree(inTree), mOutTree(new TreeT(inTree.background())),
755 mInAcc(mInTree), mOutAcc(*mOutTree)
758 ~RangeProcessor() {
if (!mIsRoot)
delete mOutTree; }
761 RangeProcessor(RangeProcessor& other, tbb::split):
763 mXform(other.mXform),
765 mInTree(other.mInTree),
766 mOutTree(new TreeT(mInTree.background())),
769 mInterrupt(other.mInterrupt)
772 void setInterrupt(
const InterruptFunc& f) { mInterrupt = f; }
775 void operator()(LeafRange& r)
779 LeafIterT i = r.iterator();
780 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
781 if (!mBBox.empty()) {
788 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
794 void operator()(TileRange& r)
799 TileIterT i = r.iterator();
801 if (!i.isTileValue())
continue;
805 i.getBoundingBox(bbox);
806 if (!mBBox.empty()) {
817 internal::TileSampler<Sampler, InTreeAccessor>
818 sampler(bbox, i.getValue(), i.isValueOn());
819 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
825 void join(RangeProcessor& other)
827 if (!
interrupt()) mOutTree->merge(*other.mOutTree);
831 bool interrupt()
const {
return mInterrupt && mInterrupt(); }
836 const TreeT& mInTree;
838 InTreeAccessor mInAcc;
839 OutTreeAccessor mOutAcc;
847 template<
class Sampler,
class Gr
idT,
typename Transformer>
850 const GridT& inGrid, GridT& outGrid)
const
852 using TreeT =
typename GridT::TreeType;
853 const TreeT& inTree = inGrid.tree();
854 TreeT& outTree = outGrid.tree();
856 using RangeProc = RangeProcessor<Sampler, TreeT, Transformer>;
858 const GridClass gridClass = inGrid.getGridClass();
865 RangeProc proc(xform,
CoordBBox(), inTree, outTree);
866 proc.setInterrupt(mInterrupt);
868 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
869 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1);
870 typename RangeProc::TileRange tileRange(tileIter);
873 tbb::parallel_reduce(tileRange, proc);
883 clipBBox = inGrid.evalActiveVoxelBoundingBox();
888 RangeProc proc(xform, clipBBox, inTree, outTree);
889 proc.setInterrupt(mInterrupt);
891 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
894 tbb::parallel_reduce(leafRange, proc);
911 template<
class Sampler,
class InTreeT,
class OutTreeT,
class Transformer>
913 GridResampler::transformBBox(
914 const Transformer& xform,
916 const InTreeT& inTree,
918 const InterruptFunc& interrupt,
921 using ValueT =
typename OutTreeT::ValueType;
927 inRMax(bbox.
max().
x()+1, bbox.
max().
y()+1, bbox.
max().
z()+1),
930 for (
int i = 0; i < 8; ++i) {
932 i & 1 ? inRMax.x() : inRMin.x(),
933 i & 2 ? inRMax.y() : inRMin.y(),
934 i & 4 ? inRMax.z() : inRMin.z());
942 if (!xform.isAffine()) {
947 int &x = outXYZ.
x(), &y = outXYZ.
y(), &z = outXYZ.
z();
948 for (x = outMin.x(); x <= outMax.x(); ++x) {
951 for (y = outMin.y(); y <= outMax.y(); ++y) {
954 for (z = outMin.z(); z <= outMax.z(); ++z) {
956 inXYZ = xform.invTransform(xyz);
958 if (sampler.
sample(inTree, inXYZ, result)) {
959 outTree.setValueOn(outXYZ, result);
962 if (!outTree.isValueOn(outXYZ)) {
963 outTree.setValueOff(outXYZ, result);
973 translation = xform.invTransform(
Vec3R(0, 0, 0)),
974 deltaX = xform.invTransform(
Vec3R(1, 0, 0)) - translation,
975 deltaY = xform.invTransform(
Vec3R(0, 1, 0)) - translation,
976 deltaZ = xform.invTransform(
Vec3R(0, 0, 1)) - translation;
979 const Vec3R dummy = deltaX;
987 Vec3R inStartX = xform.invTransform(
Vec3R(outMin));
989 int &x = outXYZ.
x(), &y = outXYZ.y(), &z = outXYZ.z();
990 for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) {
992 Vec3R inStartY = inStartX;
993 for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) {
995 Vec3R inXYZ = inStartY;
996 for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
998 if (sampler.
sample(inTree, inXYZ, result)) {
999 outTree.setValueOn(outXYZ, result);
1002 if (!outTree.isValueOn(outXYZ)) {
1003 outTree.setValueOff(outXYZ, result);
1016 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED