OpenVDB 7.0.0

GridTransformer.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
6
7 #ifndef OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
8 #define OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
9
10 #include <openvdb/Grid.h>
11 #include <openvdb/Types.h>
12 #include <openvdb/math/Math.h> // for isApproxEqual()
13 #include <openvdb/util/NullInterrupter.h>
14 #include "ChangeBackground.h"
15 #include "Interpolation.h"
16 #include "LevelSetRebuild.h" // for doLevelSetRebuild()
17 #include "SignedFloodFill.h" // for signedFloodFill
18 #include "Prune.h" // for pruneLevelSet
19 #include <tbb/blocked_range.h>
20 #include <tbb/parallel_reduce.h>
21 #include <cmath>
22 #include <functional>
23
24 namespace openvdb {
25 OPENVDB_USE_VERSION_NAMESPACE
26 namespace OPENVDB_VERSION_NAME {
27 namespace tools {
28
52 template<typename Sampler, typename Interrupter, typename GridType>
53 inline void
54 resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter);
55
77 template<typename Sampler, typename GridType>
78 inline void
79 resampleToMatch(const GridType& inGrid, GridType& outGrid);
80
81
83
84
85 namespace internal {
86
90 template<typename Sampler, typename TreeT>
91 class TileSampler: public Sampler
92 {
93 public:
94 using ValueT = typename TreeT::ValueType;
95
99 TileSampler(const CoordBBox& b, const ValueT& tileVal, bool on):
100 mBBox(b.min().asVec3d(), b.max().asVec3d()), mVal(tileVal), mActive(on), mEmpty(false)
101 {
102 mBBox.expand(-this->radius()); // shrink the bounding box by the sample radius
103 mEmpty = mBBox.empty();
104 }
105
106 bool sample(const TreeT& inTree, const Vec3R& inCoord, ValueT& result) const
107 {
108 if (!mEmpty && mBBox.isInside(inCoord)) { result = mVal; return mActive; }
109 return Sampler::sample(inTree, inCoord, result);
110 }
111
112 protected:
113 BBoxd mBBox;
114 ValueT mVal;
115 bool mActive, mEmpty;
116 };
117
118
121 template<typename TreeT>
122 class TileSampler<PointSampler, TreeT>: public PointSampler {
123 public:
124 TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {}
125 };
126
129 template<typename TreeT>
130 class TileSampler<StaggeredPointSampler, TreeT>: public StaggeredPointSampler {
131 public:
132 TileSampler(const CoordBBox&, const typename TreeT::ValueType&, bool) {}
133 };
134
135 } // namespace internal
136
137
139
140
158 class GridResampler
159 {
160 public:
161 using Ptr = SharedPtr<GridResampler>;
162 using InterruptFunc = std::function<bool (void)>;
163
164 GridResampler(): mThreaded(true), mTransformTiles(true) {}
165 virtual ~GridResampler() {}
166
167 GridResampler(const GridResampler&) = default;
168 GridResampler& operator=(const GridResampler&) = default;
169
171 void setThreaded(bool b) { mThreaded = b; }
173 bool threaded() const { return mThreaded; }
175 void setTransformTiles(bool b) { mTransformTiles = b; }
177 bool transformTiles() const { return mTransformTiles; }
178
182 template<typename InterrupterType> void setInterrupter(InterrupterType&);
183
184 template<typename Sampler, typename GridT, typename Transformer>
185 void transformGrid(const Transformer&,
186 const GridT& inGrid, GridT& outGrid) const;
187
188 protected:
189 template<typename Sampler, typename GridT, typename Transformer>
190 void applyTransform(const Transformer&, const GridT& inGrid, GridT& outGrid) const;
191
192 bool interrupt() const { return mInterrupt && mInterrupt(); }
193
194 private:
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&,
198 const Sampler& = Sampler());
199
200 template<typename Sampler, typename TreeT, typename Transformer>
201 class RangeProcessor;
202
203 bool mThreaded, mTransformTiles;
204 InterruptFunc mInterrupt;
205 };
206
207
209
210
229 class GridTransformer: public GridResampler
230 {
231 public:
232 using Ptr = SharedPtr<GridTransformer>;
233
234 GridTransformer(const Mat4R& xform);
235 GridTransformer(
236 const Vec3R& pivot,
237 const Vec3R& scale,
238 const Vec3R& rotate,
239 const Vec3R& translate,
240 const std::string& xformOrder = "tsr",
241 const std::string& rotationOrder = "zyx");
242 ~GridTransformer() override = default;
243
244 GridTransformer(const GridTransformer&) = default;
245 GridTransformer& operator=(const GridTransformer&) = default;
246
247 const Mat4R& getTransform() const { return mTransform; }
248
249 template<class Sampler, class GridT>
250 void transformGrid(const GridT& inGrid, GridT& outGrid) const;
251
252 private:
253 struct MatrixTransform;
254
255 inline void init(const Vec3R& pivot, const Vec3R& scale,
256 const Vec3R& rotate, const Vec3R& translate,
257 const std::string& xformOrder, const std::string& rotOrder);
258
259 Vec3R mPivot;
260 Vec3i mMipLevels;
261 Mat4R mTransform, mPreScaleTransform, mPostScaleTransform;
262 };
263
264
266
267
268 namespace local_util {
269
272 template<typename T>
273 inline bool
274 decompose(const math::Mat4<T>& m, math::Vec3<T>& scale,
275 math::Vec3<T>& rotate, math::Vec3<T>& translate)
276 {
277 if (!math::isAffine(m)) return false;
278
279 // This is the translation in world space
280 translate = m.getTranslation();
281 // Extract translation.
282 const math::Mat3<T> xform = m.getMat3();
283
284 const math::Vec3<T> unsignedScale(
285 (math::Vec3<T>(1, 0, 0) * xform).length(),
286 (math::Vec3<T>(0, 1, 0) * xform).length(),
287 (math::Vec3<T>(0, 0, 1) * xform).length());
288
289 const bool hasUniformScale = unsignedScale.eq(math::Vec3<T>(unsignedScale[0]));
290
291 bool hasRotation = false;
292 bool validDecomposition = false;
293
294 T minAngle = std::numeric_limits<T>::max();
295
296 // If the transformation matrix contains a reflection,
297 // test different negative scales to find a decomposition
298 // that favors the optimal resampling algorithm.
299 for (size_t n = 0; n < 8; ++n) {
300
301 const math::Vec3<T> signedScale(
302 n & 0x1 ? -unsignedScale.x() : unsignedScale.x(),
303 n & 0x2 ? -unsignedScale.y() : unsignedScale.y(),
304 n & 0x4 ? -unsignedScale.z() : unsignedScale.z());
305
306 // Extract scale and potentially reflection.
307 const math::Mat3<T> mat = xform * math::scale<math::Mat3<T> >(signedScale).inverse();
308 if (mat.det() < T(0.0)) continue; // Skip if mat contains a reflection.
309
310 const math::Vec3<T> tmpAngle = math::eulerAngles(mat, math::XYZ_ROTATION);
311
312 const math::Mat3<T> rebuild =
313 math::rotation<math::Mat3<T> >(math::Vec3<T>(1, 0, 0), tmpAngle.x()) *
314 math::rotation<math::Mat3<T> >(math::Vec3<T>(0, 1, 0), tmpAngle.y()) *
315 math::rotation<math::Mat3<T> >(math::Vec3<T>(0, 0, 1), tmpAngle.z()) *
316 math::scale<math::Mat3<T> >(signedScale);
317
318 if (xform.eq(rebuild)) {
319
320 const T maxAngle = std::max(std::abs(tmpAngle[0]),
321 std::max(std::abs(tmpAngle[1]), std::abs(tmpAngle[2])));
322
323 if (!(minAngle < maxAngle)) { // Update if less or equal.
324
325 minAngle = maxAngle;
326 rotate = tmpAngle;
327 scale = signedScale;
328
329 hasRotation = !rotate.eq(math::Vec3<T>::zero());
330 validDecomposition = true;
331
332 if (hasUniformScale || !hasRotation) {
333 // Current decomposition is optimal.
334 break;
335 }
336 }
337 }
338 }
339
340 if (!validDecomposition || (hasRotation && !hasUniformScale)) {
341 // The decomposition is invalid if the transformation matrix contains shear.
342 // No unique decomposition if scale is nonuniform and rotation is nonzero.
343 return false;
344 }
345
346 return true;
347 }
348
349 } // namespace local_util
350
351
353
354
358 struct GridTransformer::MatrixTransform
359 {
360 MatrixTransform(): mat(Mat4R::identity()), invMat(Mat4R::identity()) {}
361 MatrixTransform(const Mat4R& xform): mat(xform), invMat(xform.inverse()) {}
362
363 bool isAffine() const { return math::isAffine(mat); }
364
365 Vec3R transform(const Vec3R& pos) const { return mat.transformH(pos); }
366
367 Vec3R invTransform(const Vec3R& pos) const { return invMat.transformH(pos); }
368
369 Mat4R mat, invMat;
370 };
371
372
374
375
380 class ABTransform
381 {
382 public:
385 ABTransform(const math::Transform& aXform, const math::Transform& bXform):
386 mAXform(aXform),
387 mBXform(bXform),
388 mIsAffine(mAXform.isLinear() && mBXform.isLinear()),
389 mIsIdentity(mIsAffine && mAXform == mBXform)
390 {}
391
392 bool isAffine() const { return mIsAffine; }
393
394 bool isIdentity() const { return mIsIdentity; }
395
396 openvdb::Vec3R transform(const openvdb::Vec3R& pos) const
397 {
398 return mBXform.worldToIndex(mAXform.indexToWorld(pos));
399 }
400
401 openvdb::Vec3R invTransform(const openvdb::Vec3R& pos) const
402 {
403 return mAXform.worldToIndex(mBXform.indexToWorld(pos));
404 }
405
406 const math::Transform& getA() const { return mAXform; }
407 const math::Transform& getB() const { return mBXform; }
408
409 private:
410 const math::Transform &mAXform, &mBXform;
411 const bool mIsAffine;
412 const bool mIsIdentity;
413 };
414
415
422 template<typename Sampler, typename Interrupter, typename GridType>
423 inline void
424 doResampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter)
425 {
426 ABTransform xform(inGrid.transform(), outGrid.transform());
427
428 if (Sampler::consistent() && xform.isIdentity()) {
429 // If the transforms of the input and output are identical, the
430 // output tree is simply a deep copy of the input tree.
431 outGrid.setTree(inGrid.tree().copy());
432 } else if (xform.isAffine()) {
433 // If the input and output transforms are both affine, create an
434 // input to output transform (in:index-to-world * out:world-to-index)
435 // and use the fast GridTransformer API.
436 Mat4R mat = xform.getA().baseMap()->getAffineMap()->getMat4() *
437 ( xform.getB().baseMap()->getAffineMap()->getMat4().inverse() );
438
439 GridTransformer transformer(mat);
440 transformer.setInterrupter(interrupter);
441
442 // Transform the input grid and store the result in the output grid.
443 transformer.transformGrid<Sampler>(inGrid, outGrid);
444 } else {
445 // If either the input or the output transform is non-affine,
446 // use the slower GridResampler API.
447 GridResampler resampler;
448 resampler.setInterrupter(interrupter);
449
450 resampler.transformGrid<Sampler>(xform, inGrid, outGrid);
451 }
452 }
453
454
455 template<typename Sampler, typename Interrupter, typename GridType>
456 inline void
457 resampleToMatch(const GridType& inGrid, GridType& outGrid, Interrupter& interrupter)
458 {
459 if (inGrid.getGridClass() == GRID_LEVEL_SET) {
460 // If the input grid is a level set, resample it using the level set rebuild tool.
461
462 if (inGrid.constTransform() == outGrid.constTransform()) {
463 // If the transforms of the input and output grids are identical,
464 // the output tree is simply a deep copy of the input tree.
465 outGrid.setTree(inGrid.tree().copy());
466 return;
467 }
468
469 // If the output grid is a level set, resample the input grid to have the output grid's
470 // background value. Otherwise, preserve the input grid's background value.
471 using ValueT = typename GridType::ValueType;
472 const bool outIsLevelSet = outGrid.getGridClass() == openvdb::GRID_LEVEL_SET;
473
474 OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
475 const ValueT halfWidth = outIsLevelSet
476 ? ValueT(outGrid.background() * (1.0 / outGrid.voxelSize()[0]))
477 : ValueT(inGrid.background() * (1.0 / inGrid.voxelSize()[0]));
478 OPENVDB_NO_TYPE_CONVERSION_WARNING_END
479
480 typename GridType::Ptr tempGrid;
481 try {
482 tempGrid = doLevelSetRebuild(inGrid, /*iso=*/zeroVal<ValueT>(),
483 /*exWidth=*/halfWidth, /*inWidth=*/halfWidth,
484 &outGrid.constTransform(), &interrupter);
485 } catch (TypeError&) {
486 // The input grid is classified as a level set, but it has a value type
487 // that is not supported by the level set rebuild tool. Fall back to
488 // using the generic resampler.
489 tempGrid.reset();
490 }
491 if (tempGrid) {
492 outGrid.setTree(tempGrid->treePtr());
493 return;
494 }
495 }
496
497 // If the input grid is not a level set, use the generic resampler.
498 doResampleToMatch<Sampler>(inGrid, outGrid, interrupter);
499 }
500
501
502 template<typename Sampler, typename GridType>
503 inline void
504 resampleToMatch(const GridType& inGrid, GridType& outGrid)
505 {
506 util::NullInterrupter interrupter;
507 resampleToMatch<Sampler>(inGrid, outGrid, interrupter);
508 }
509
510
512
513
514 inline
515 GridTransformer::GridTransformer(const Mat4R& xform):
516 mPivot(0, 0, 0),
517 mMipLevels(0, 0, 0),
518 mTransform(xform),
519 mPreScaleTransform(Mat4R::identity()),
520 mPostScaleTransform(Mat4R::identity())
521 {
522 Vec3R scale, rotate, translate;
523 if (local_util::decompose(mTransform, scale, rotate, translate)) {
524 // If the transform can be decomposed into affine components,
525 // use them to set up a mipmapping-like scheme for downsampling.
526 init(mPivot, scale, rotate, translate, "srt", "zyx");
527 }
528 }
529
530
531 inline
532 GridTransformer::GridTransformer(
533 const Vec3R& pivot, const Vec3R& scale,
534 const Vec3R& rotate, const Vec3R& translate,
535 const std::string& xformOrder, const std::string& rotOrder):
536 mPivot(0, 0, 0),
537 mMipLevels(0, 0, 0),
538 mPreScaleTransform(Mat4R::identity()),
539 mPostScaleTransform(Mat4R::identity())
540 {
541 init(pivot, scale, rotate, translate, xformOrder, rotOrder);
542 }
543
544
546
547
548 inline void
549 GridTransformer::init(
550 const Vec3R& pivot, const Vec3R& scale,
551 const Vec3R& rotate, const Vec3R& translate,
552 const std::string& xformOrder, const std::string& rotOrder)
553 {
554 if (xformOrder.size() != 3) {
555 OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")");
556 }
557 if (rotOrder.size() != 3) {
558 OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")");
559 }
560
561 mPivot = pivot;
562
563 // Scaling is handled via a mipmapping-like scheme of successive
564 // halvings of the tree resolution, until the remaining scale
565 // factor is greater than or equal to 1/2.
566 Vec3R scaleRemainder = scale;
567 for (int i = 0; i < 3; ++i) {
568 double s = std::fabs(scale(i));
569 if (s < 0.5) {
570 mMipLevels(i) = int(std::floor(-std::log(s)/std::log(2.0)));
571 scaleRemainder(i) = scale(i) * (1 << mMipLevels(i));
572 }
573 }
574
575 // Build pre-scale and post-scale transform matrices based on
576 // the user-specified order of operations.
577 // Note that we iterate over the transform order string in reverse order
578 // (e.g., "t", "r", "s", given "srt"). This is because math::Mat matrices
579 // postmultiply row vectors rather than premultiplying column vectors.
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) { // reverse iteration
585 switch (xformOrder[ix]) {
586
587 case 'r':
588 rpos = ix;
589 mTransform.preTranslate(pivot);
590 remainder->preTranslate(pivot);
591
592 int xpos, ypos, zpos;
593 xpos = ypos = zpos = 3;
594 for (int ir = 2; ir >= 0; --ir) {
595 switch (rotOrder[ir]) {
596 case 'x':
597 xpos = ir;
598 mTransform.preRotate(math::X_AXIS, rotate.x());
599 remainder->preRotate(math::X_AXIS, rotate.x());
600 break;
601 case 'y':
602 ypos = ir;
603 mTransform.preRotate(math::Y_AXIS, rotate.y());
604 remainder->preRotate(math::Y_AXIS, rotate.y());
605 break;
606 case 'z':
607 zpos = ir;
608 mTransform.preRotate(math::Z_AXIS, rotate.z());
609 remainder->preRotate(math::Z_AXIS, rotate.z());
610 break;
611 }
612 }
613 // Reject rotation order strings that don't contain exactly one
614 // instance of "x", "y" and "z".
615 if (xpos > 2 || ypos > 2 || zpos > 2) {
616 OPENVDB_THROW(ValueError, "invalid rotation order (" + rotOrder + ")");
617 }
618
619 mTransform.preTranslate(-pivot);
620 remainder->preTranslate(-pivot);
621 break;
622
623 case 's':
624 spos = ix;
625 mTransform.preTranslate(pivot);
626 mTransform.preScale(scale);
627 mTransform.preTranslate(-pivot);
628
629 remainder->preTranslate(pivot);
630 remainder->preScale(scaleRemainder);
631 remainder->preTranslate(-pivot);
632 remainder = &mPreScaleTransform;
633 break;
634
635 case 't':
636 tpos = ix;
637 mTransform.preTranslate(translate);
638 remainder->preTranslate(translate);
639 break;
640 }
641 }
642 // Reject transform order strings that don't contain exactly one
643 // instance of "t", "r" and "s".
644 if (tpos > 2 || rpos > 2 || spos > 2) {
645 OPENVDB_THROW(ValueError, "invalid transform order (" + xformOrder + ")");
646 }
647 }
648
649
651
652
653 template<typename InterrupterType>
654 void
655 GridResampler::setInterrupter(InterrupterType& interrupter)
656 {
657 mInterrupt = std::bind(&InterrupterType::wasInterrupted,
658 /*this=*/&interrupter, /*percent=*/-1);
659 }
660
661
662 template<typename Sampler, typename GridT, typename Transformer>
663 void
664 GridResampler::transformGrid(const Transformer& xform,
665 const GridT& inGrid, GridT& outGrid) const
666 {
667 tools::changeBackground(outGrid.tree(), inGrid.background());
668 applyTransform<Sampler>(xform, inGrid, outGrid);
669 }
670
671
672 template<class Sampler, class GridT>
673 void
674 GridTransformer::transformGrid(const GridT& inGrid, GridT& outGrid) const
675 {
676 tools::changeBackground(outGrid.tree(), inGrid.background());
677
678 if (!Sampler::mipmap() || mMipLevels == Vec3i::zero()) {
679 // Skip the mipmapping step.
680 const MatrixTransform xform(mTransform);
681 applyTransform<Sampler>(xform, inGrid, outGrid);
682
683 } else {
684 bool firstPass = true;
685 const typename GridT::ValueType background = inGrid.background();
686 typename GridT::Ptr tempGrid = GridT::create(background);
687
688 if (!mPreScaleTransform.eq(Mat4R::identity())) {
689 firstPass = false;
690 // Apply the pre-scale transform to the input grid
691 // and store the result in a temporary grid.
692 const MatrixTransform xform(mPreScaleTransform);
693 applyTransform<Sampler>(xform, inGrid, *tempGrid);
694 }
695
696 // While the scale factor along one or more axes is less than 1/2,
697 // scale the grid by half along those axes.
698 Vec3i count = mMipLevels; // # of halvings remaining per axis
699 while (count != Vec3i::zero()) {
700 MatrixTransform xform;
701 xform.mat.setTranslation(mPivot);
702 xform.mat.preScale(Vec3R(
703 count.x() ? .5 : 1, count.y() ? .5 : 1, count.z() ? .5 : 1));
704 xform.mat.preTranslate(-mPivot);
705 xform.invMat = xform.mat.inverse();
706
707 if (firstPass) {
708 firstPass = false;
709 // Scale the input grid and store the result in a temporary grid.
710 applyTransform<Sampler>(xform, inGrid, *tempGrid);
711 } else {
712 // Scale the temporary grid and store the result in a transient grid,
713 // then swap the two and discard the transient grid.
714 typename GridT::Ptr destGrid = GridT::create(background);
715 applyTransform<Sampler>(xform, *tempGrid, *destGrid);
716 tempGrid.swap(destGrid);
717 }
718 // (3, 2, 1) -> (2, 1, 0) -> (1, 0, 0) -> (0, 0, 0), etc.
719 count = math::maxComponent(count - 1, Vec3i::zero());
720 }
721
722 // Apply the post-scale transform and store the result in the output grid.
723 if (!mPostScaleTransform.eq(Mat4R::identity())) {
724 const MatrixTransform xform(mPostScaleTransform);
725 applyTransform<Sampler>(xform, *tempGrid, outGrid);
726 } else {
727 outGrid.setTree(tempGrid->treePtr());
728 }
729 }
730 }
731
732
734
735
736 template<class Sampler, class TreeT, typename Transformer>
737 class GridResampler::RangeProcessor
738 {
739 public:
740 using LeafIterT = typename TreeT::LeafCIter;
741 using TileIterT = typename TreeT::ValueAllCIter;
742 using LeafRange = typename tree::IteratorRange<LeafIterT>;
743 using TileRange = typename tree::IteratorRange<TileIterT>;
744 using InTreeAccessor = typename tree::ValueAccessor<const TreeT>;
745 using OutTreeAccessor = typename tree::ValueAccessor<TreeT>;
746
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)
750 {}
751
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)
756 {}
757
758 ~RangeProcessor() { if (!mIsRoot) delete mOutTree; }
759
761 RangeProcessor(RangeProcessor& other, tbb::split):
762 mIsRoot(false),
763 mXform(other.mXform),
764 mBBox(other.mBBox),
765 mInTree(other.mInTree),
766 mOutTree(new TreeT(mInTree.background())),
767 mInAcc(mInTree),
768 mOutAcc(*mOutTree),
769 mInterrupt(other.mInterrupt)
770 {}
771
772 void setInterrupt(const InterruptFunc& f) { mInterrupt = f; }
773
775 void operator()(LeafRange& r)
776 {
777 for ( ; r; ++r) {
778 if (interrupt()) break;
779 LeafIterT i = r.iterator();
780 CoordBBox bbox(i->origin(), i->origin() + Coord(i->dim()));
781 if (!mBBox.empty()) {
782 // Intersect the leaf node's bounding box with mBBox.
783 bbox = CoordBBox(
784 Coord::maxComponent(bbox.min(), mBBox.min()),
785 Coord::minComponent(bbox.max(), mBBox.max()));
786 }
787 if (!bbox.empty()) {
788 transformBBox<Sampler>(mXform, bbox, mInAcc, mOutAcc, mInterrupt);
789 }
790 }
791 }
792
794 void operator()(TileRange& r)
795 {
796 for ( ; r; ++r) {
797 if (interrupt()) break;
798
799 TileIterT i = r.iterator();
800 // Skip voxels and background tiles.
801 if (!i.isTileValue()) continue;
802 if (!i.isValueOn() && math::isApproxEqual(*i, mOutTree->background())) continue;
803
804 CoordBBox bbox;
805 i.getBoundingBox(bbox);
806 if (!mBBox.empty()) {
807 // Intersect the tile's bounding box with mBBox.
808 bbox = CoordBBox(
809 Coord::maxComponent(bbox.min(), mBBox.min()),
810 Coord::minComponent(bbox.max(), mBBox.max()));
811 }
812 if (!bbox.empty()) {
817 internal::TileSampler<Sampler, InTreeAccessor>
818 sampler(bbox, i.getValue(), i.isValueOn());
819 transformBBox(mXform, bbox, mInAcc, mOutAcc, mInterrupt, sampler);
820 }
821 }
822 }
823
825 void join(RangeProcessor& other)
826 {
827 if (!interrupt()) mOutTree->merge(*other.mOutTree);
828 }
829
830 private:
831 bool interrupt() const { return mInterrupt && mInterrupt(); }
832
833 const bool mIsRoot; // true if mOutTree is the top-level tree
834 Transformer mXform;
835 CoordBBox mBBox;
836 const TreeT& mInTree;
837 TreeT* mOutTree;
838 InTreeAccessor mInAcc;
839 OutTreeAccessor mOutAcc;
840 InterruptFunc mInterrupt;
841 };
842
843
845
846
847 template<class Sampler, class GridT, typename Transformer>
848 void
849 GridResampler::applyTransform(const Transformer& xform,
850 const GridT& inGrid, GridT& outGrid) const
851 {
852 using TreeT = typename GridT::TreeType;
853 const TreeT& inTree = inGrid.tree();
854 TreeT& outTree = outGrid.tree();
855
856 using RangeProc = RangeProcessor<Sampler, TreeT, Transformer>;
857
858 const GridClass gridClass = inGrid.getGridClass();
859
860 if (gridClass != GRID_LEVEL_SET && mTransformTiles) {
861 // Independently transform the tiles of the input grid.
862 // Note: Tiles in level sets can only be background tiles, and they
863 // are handled more efficiently with a signed flood fill (see below).
864
865 RangeProc proc(xform, CoordBBox(), inTree, outTree);
866 proc.setInterrupt(mInterrupt);
867
868 typename RangeProc::TileIterT tileIter = inTree.cbeginValueAll();
869 tileIter.setMaxDepth(tileIter.getLeafDepth() - 1); // skip leaf nodes
870 typename RangeProc::TileRange tileRange(tileIter);
871
872 if (mThreaded) {
873 tbb::parallel_reduce(tileRange, proc);
874 } else {
875 proc(tileRange);
876 }
877 }
878
879 CoordBBox clipBBox;
880 if (gridClass == GRID_LEVEL_SET) {
881 // Inactive voxels in level sets can only be background voxels, and they
882 // are handled more efficiently with a signed flood fill (see below).
883 clipBBox = inGrid.evalActiveVoxelBoundingBox();
884 }
885
886 // Independently transform the leaf nodes of the input grid.
887
888 RangeProc proc(xform, clipBBox, inTree, outTree);
889 proc.setInterrupt(mInterrupt);
890
891 typename RangeProc::LeafRange leafRange(inTree.cbeginLeaf());
892
893 if (mThreaded) {
894 tbb::parallel_reduce(leafRange, proc);
895 } else {
896 proc(leafRange);
897 }
898
899 // If the grid is a level set, mark inactive voxels as inside or outside.
900 if (gridClass == GRID_LEVEL_SET) {
901 tools::pruneLevelSet(outTree);
902 tools::signedFloodFill(outTree);
903 }
904 }
905
906
908
909
910 //static
911 template<class Sampler, class InTreeT, class OutTreeT, class Transformer>
912 void
913 GridResampler::transformBBox(
914 const Transformer& xform,
915 const CoordBBox& bbox,
916 const InTreeT& inTree,
917 OutTreeT& outTree,
918 const InterruptFunc& interrupt,
919 const Sampler& sampler)
920 {
921 using ValueT = typename OutTreeT::ValueType;
922
923 // Transform the corners of the input tree's bounding box
924 // and compute the enclosing bounding box in the output tree.
925 Vec3R
926 inRMin(bbox.min().x(), bbox.min().y(), bbox.min().z()),
927 inRMax(bbox.max().x()+1, bbox.max().y()+1, bbox.max().z()+1),
928 outRMin = math::minComponent(xform.transform(inRMin), xform.transform(inRMax)),
929 outRMax = math::maxComponent(xform.transform(inRMin), xform.transform(inRMax));
930 for (int i = 0; i < 8; ++i) {
931 Vec3R corner(
932 i & 1 ? inRMax.x() : inRMin.x(),
933 i & 2 ? inRMax.y() : inRMin.y(),
934 i & 4 ? inRMax.z() : inRMin.z());
935 outRMin = math::minComponent(outRMin, xform.transform(corner));
936 outRMax = math::maxComponent(outRMax, xform.transform(corner));
937 }
938 Vec3i
939 outMin = local_util::floorVec3(outRMin) - Sampler::radius(),
940 outMax = local_util::ceilVec3(outRMax) + Sampler::radius();
941
942 if (!xform.isAffine()) {
943 // If the transform is not affine, back-project each output voxel
944 // into the input tree.
945 Vec3R xyz, inXYZ;
946 Coord outXYZ;
947 int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z();
948 for (x = outMin.x(); x <= outMax.x(); ++x) {
949 if (interrupt && interrupt()) break;
950 xyz.x() = x;
951 for (y = outMin.y(); y <= outMax.y(); ++y) {
952 if (interrupt && interrupt()) break;
953 xyz.y() = y;
954 for (z = outMin.z(); z <= outMax.z(); ++z) {
955 xyz.z() = z;
956 inXYZ = xform.invTransform(xyz);
957 ValueT result;
958 if (sampler.sample(inTree, inXYZ, result)) {
959 outTree.setValueOn(outXYZ, result);
960 } else {
961 // Note: Don't overwrite existing active values with inactive values.
962 if (!outTree.isValueOn(outXYZ)) {
963 outTree.setValueOff(outXYZ, result);
964 }
965 }
966 }
967 }
968 }
969 } else { // affine
970 // Compute step sizes in the input tree that correspond to
971 // unit steps in x, y and z in the output tree.
972 const Vec3R
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;
977
978 #if defined(__ICC)
979 const Vec3R dummy = deltaX;
983 #endif
984
985 // Step by whole voxels through the output tree, sampling the
986 // corresponding fractional voxels of the input tree.
987 Vec3R inStartX = xform.invTransform(Vec3R(outMin));
988 Coord outXYZ;
989 int &x = outXYZ.x(), &y = outXYZ.y(), &z = outXYZ.z();
990 for (x = outMin.x(); x <= outMax.x(); ++x, inStartX += deltaX) {
991 if (interrupt && interrupt()) break;
992 Vec3R inStartY = inStartX;
993 for (y = outMin.y(); y <= outMax.y(); ++y, inStartY += deltaY) {
994 if (interrupt && interrupt()) break;
995 Vec3R inXYZ = inStartY;
996 for (z = outMin.z(); z <= outMax.z(); ++z, inXYZ += deltaZ) {
997 ValueT result;
998 if (sampler.sample(inTree, inXYZ, result)) {
999 outTree.setValueOn(outXYZ, result);
1000 } else {
1001 // Note: Don't overwrite existing active values with inactive values.
1002 if (!outTree.isValueOn(outXYZ)) {
1003 outTree.setValueOff(outXYZ, result);
1004 }
1005 }
1006 }
1007 }
1008 }
1009 }
1010 } // GridResampler::transformBBox()
1011
1012 } // namespace tools
1013 } // namespace OPENVDB_VERSION_NAME
1014 } // namespace openvdb
1015
1016 #endif // OPENVDB_TOOLS_GRIDTRANSFORMER_HAS_BEEN_INCLUDED
OPENVDB_NO_TYPE_CONVERSION_WARNING_END
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_END
Definition: Platform.h:197
openvdb::v7_0::math::Vec3::x
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:83
openvdb::v7_0::tools::internal::TileSampler
A TileSampler wraps a grid sampler of another type (BoxSampler, QuadraticSampler, etc....
Definition: GridTransformer.h:91
openvdb::v7_0::tools::PointSampler
Definition: Interpolation.h:96
openvdb::v7_0::tools::GridResampler::interrupt
bool interrupt() const
Definition: GridTransformer.h:192
openvdb::v7_0::math::Mat4::preScale
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:755
openvdb::v7_0::tools::ABTransform::isIdentity
bool isIdentity() const
Definition: GridTransformer.h:394
openvdb::v7_0::tools::GridResampler
Definition: GridTransformer.h:158
openvdb::v7_0::math::Vec3i
Vec3< int32_t > Vec3i
Definition: Vec3.h:659
openvdb::v7_0::tools::ABTransform::getB
const math::Transform & getB() const
Definition: GridTransformer.h:407
openvdb::v7_0::tools::GridTransformer::MatrixTransform::MatrixTransform
MatrixTransform(const Mat4R &xform)
Definition: GridTransformer.h:361
openvdb::v7_0::math::BBox< Vec3d >
LevelSetRebuild.h
openvdb::v7_0::math::isApproxEqual
bool isApproxEqual(const Type &a, const Type &b)
Return true if a is equal to b to within the default floating-point comparison tolerance.
Definition: Math.h:351
openvdb::v7_0::tools::local_util::decompose
bool decompose(const math::Mat4< T > &m, math::Vec3< T > &scale, math::Vec3< T > &rotate, math::Vec3< T > &translate)
Decompose an affine transform into scale, rotation and translation components.
Definition: GridTransformer.h:274
openvdb::v7_0::tools::internal::TileSampler::mVal
ValueT mVal
Definition: GridTransformer.h:114
openvdb::v7_0::Vec3R
math::Vec3< Real > Vec3R
Definition: Types.h:49
Types.h
openvdb::v7_0::tools::GridTransformer::MatrixTransform::isAffine
bool isAffine() const
Definition: GridTransformer.h:363
openvdb::v7_0::math::Mat4::preRotate
void preRotate(Axis axis, T angle)
Left multiplies by a rotation clock-wiseabout the given axis into this matrix.
Definition: Mat4.h:817
openvdb::v7_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
openvdb::v7_0::math::Z_AXIS
Definition: Math.h:852
openvdb::v7_0::math::XYZ_ROTATION
Definition: Math.h:857
openvdb::v7_0::tools::internal::TileSampler::ValueT
typename TreeT::ValueType ValueT
Definition: GridTransformer.h:94
openvdb::v7_0::tools::GridTransformer::MatrixTransform::transform
Vec3R transform(const Vec3R &pos) const
Definition: GridTransformer.h:365
openvdb::v7_0::math::minComponent
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:503
openvdb::v7_0::tools::Sampler
Provises a unified interface for sampling, i.e. interpolation.
Definition: Interpolation.h:63
openvdb::v7_0::tools::Sampler::mipmap
static bool mipmap()
openvdb::v7_0::tools::ABTransform
This class implements the Transformer functor interface (specifically, the isAffine(),...
Definition: GridTransformer.h:380
openvdb::v7_0::Mat4R
math::Mat4< Real > Mat4R
Definition: Types.h:78
openvdb::v7_0::tools::ABTransform::isAffine
bool isAffine() const
Definition: GridTransformer.h:392
openvdb::v7_0::math::Mat4::preTranslate
void preTranslate(const Vec3< T0 > &tr)
Left multiples by the specified translation, i.e. Trans * (*this)
Definition: Mat4.h:722
openvdb::v7_0::tools::GridTransformer::MatrixTransform
Definition: GridTransformer.h:358
openvdb::v7_0::tools::GridResampler::InterruptFunc
std::function< bool(void)> InterruptFunc
Definition: GridTransformer.h:162
openvdb::v7_0::tree::ValueAccessor< const TreeT >
openvdb::v7_0::math::Coord::maxComponent
void maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition: Coord.h:184
openvdb::v7_0::tools::internal::TileSampler< StaggeredPointSampler, TreeT >::TileSampler
TileSampler(const CoordBBox &, const typename TreeT::ValueType &, bool)
Definition: GridTransformer.h:132
openvdb::v7_0::tools::internal::TileSampler::mBBox
BBoxd mBBox
Definition: GridTransformer.h:113
openvdb::v7_0::math::rotation
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:177
openvdb::v7_0::math::Coord::y
Int32 y() const
Definition: Coord.h:132
openvdb::v7_0::math::X_AXIS
Definition: Math.h:850
openvdb::v7_0::tools::GridResampler::~GridResampler
virtual ~GridResampler()
Definition: GridTransformer.h:165
openvdb::v7_0::tools::GridResampler::applyTransform
void applyTransform(const Transformer &, const GridT &inGrid, GridT &outGrid) const
Definition: GridTransformer.h:849
openvdb::v7_0::tools::ABTransform::getA
const math::Transform & getA() const
Definition: GridTransformer.h:406
openvdb::v7_0::tools::GridResampler::setTransformTiles
void setTransformTiles(bool b)
Enable or disable processing of tiles. (Enabled by default, except for level set grids....
Definition: GridTransformer.h:175
openvdb::v7_0::tools::internal::TileSampler::TileSampler
TileSampler(const CoordBBox &b, const ValueT &tileVal, bool on)
Definition: GridTransformer.h:99
openvdb::v7_0::tools::internal::TileSampler::sample
bool sample(const TreeT &inTree, const Vec3R &inCoord, ValueT &result) const
Definition: GridTransformer.h:106
openvdb::v7_0::tools::GridResampler::transformGrid
void transformGrid(const Transformer &, const GridT &inGrid, GridT &outGrid) const
Definition: GridTransformer.h:664
openvdb::v7_0::math::Mat4< Real >::identity
static const Mat4< Real > & identity()
Predefined constant for identity matrix.
Definition: Mat4.h:125
openvdb::v7_0::math::Coord::x
Int32 x() const
Definition: Coord.h:131
openvdb::v7_0::tools::GridResampler::setInterrupter
void setInterrupter(InterrupterType &)
Allow processing to be aborted by providing an interrupter object. The interrupter will be queried pe...
Definition: GridTransformer.h:655
openvdb::v7_0::tools::ABTransform::transform
openvdb::Vec3R transform(const openvdb::Vec3R &pos) const
Definition: GridTransformer.h:396
Grid.h
openvdb::v7_0::SharedPtr
std::shared_ptr< T > SharedPtr
Definition: Types.h:91
openvdb::v7_0::math::Mat4::getTranslation
Vec3< T > getTranslation() const
Return the translation component.
Definition: Mat4.h:328
openvdb::v7_0::tools::local_util::ceilVec3
Vec3i ceilVec3(const Vec3R &v)
Definition: Interpolation.h:591
openvdb::v7_0::math::Vec3::y
T & y()
Definition: Vec3.h:84
openvdb::v7_0::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:248
openvdb::v7_0::tools::GridTransformer::MatrixTransform::invTransform
Vec3R invTransform(const Vec3R &pos) const
Definition: GridTransformer.h:367
openvdb::v7_0::util::NullInterrupter
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:25
openvdb::v7_0::math::Vec3::eq
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:131
openvdb::v7_0::tools::GridTransformer
A GridTransformer applies a geometric transformation to an input grid using one of several sampling s...
Definition: GridTransformer.h:229
openvdb::v7_0::math::Y_AXIS
Definition: Math.h:851
openvdb::v7_0::math::Mat4< Real >
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
openvdb::v7_0::tools::doResampleToMatch
void doResampleToMatch(const GridType &inGrid, GridType &outGrid, Interrupter &interrupter)
Definition: GridTransformer.h:424
openvdb::v7_0::math::Vec3::z
T & z()
Definition: Vec3.h:85
openvdb::v7_0::tools::pruneLevelSet
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:389
Prune.h
Defined various multi-threaded utility functions for trees.
openvdb::v7_0::TypeError
Definition: Exceptions.h:64
openvdb::v7_0::tools::internal::TileSampler::mEmpty
bool mEmpty
Definition: GridTransformer.h:115
openvdb::v7_0::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:106
openvdb::v7_0::math::Mat3::eq
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:322
openvdb::v7_0::tools::ABTransform::invTransform
openvdb::Vec3R invTransform(const openvdb::Vec3R &pos) const
Definition: GridTransformer.h:401
openvdb::v7_0::math::CoordBBox::max
const Coord & max() const
Definition: Coord.h:322
openvdb::v7_0::math::Vec3< Real >
NullInterrupter.h
openvdb::v7_0::math::Mat4::getMat3
Mat3< T > getMat3() const
Definition: Mat4.h:316
openvdb::v7_0::math::CoordBBox::min
const Coord & min() const
Definition: Coord.h:321
openvdb::v7_0::math::mat3_internal::pivot
void pivot(int i, int j, Mat3< T > &S, Vec3< T > &D, Mat3< T > &Q)
Definition: Mat3.h:689
Interpolation.h
openvdb::v7_0::tools::GridResampler::setThreaded
void setThreaded(bool b)
Enable or disable threading. (Threading is enabled by default.)
Definition: GridTransformer.h:171
openvdb::v7_0::tools::GridResampler::Ptr
SharedPtr< GridResampler > Ptr
Definition: GridTransformer.h:161
openvdb::v7_0::tools::local_util::floorVec3
Vec3i floorVec3(const Vec3R &v)
Definition: Interpolation.h:584
openvdb::v7_0::math::Coord::z
Int32 z() const
Definition: Coord.h:133
openvdb::v7_0::math::Mat4::eq
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:352
openvdb::v7_0::tools::StaggeredPointSampler
Definition: Interpolation.h:196
openvdb::v7_0::math::Mat3
3x3 matrix class.
Definition: Mat3.h:28
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:154
openvdb::v7_0::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:102
openvdb::v7_0::tools::Sampler::sample
static bool sample(const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &result)
Sample inTree at the floating-point index coordinate inCoord and store the result in result.
openvdb::v7_0::tools::ABTransform::ABTransform
ABTransform(const math::Transform &aXform, const math::Transform &bXform)
Definition: GridTransformer.h:385
OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
Bracket code with OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN/_END, to inhibit warnings about type conve...
Definition: Platform.h:196
SignedFloodFill.h
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
openvdb::v7_0::tools::GridTransformer::GridTransformer
GridTransformer(const Mat4R &xform)
Definition: GridTransformer.h:515
openvdb::v7_0::math::Transform
Definition: Transform.h:39
openvdb::v7_0::math::maxComponent
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:512
openvdb::v7_0::tools::GridResampler::transformTiles
bool transformTiles() const
Return true if tile processing is enabled.
Definition: GridTransformer.h:177
openvdb::v7_0::tools::GridResampler::GridResampler
GridResampler()
Definition: GridTransformer.h:164
openvdb::v7_0::tools::GridResampler::threaded
bool threaded() const
Return true if threading is enabled.
Definition: GridTransformer.h:173
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:102
openvdb::v7_0::tools::GridTransformer::MatrixTransform::invMat
Mat4R invMat
Definition: GridTransformer.h:369
openvdb::v7_0::tools::Sampler::radius
static int radius()
openvdb::v7_0::math::scale
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:620
openvdb::v7_0::tools::GridTransformer::MatrixTransform::MatrixTransform
MatrixTransform()
Definition: GridTransformer.h:360
ChangeBackground.h
Efficient multi-threaded replacement of the background values in tree.
openvdb::v7_0::tools::GridTransformer::MatrixTransform::mat
Mat4R mat
Definition: GridTransformer.h:369
openvdb::v7_0::tools::changeBackground
void changeBackground(TreeOrLeafManagerT &tree, const typename TreeOrLeafManagerT::ValueType &background, bool threaded=true, size_t grainSize=32)
Replace the background value in all the nodes of a tree.
Definition: ChangeBackground.h:203
openvdb::v7_0::ValueError
Definition: Exceptions.h:65
openvdb::v7_0::math::Mat4::setTranslation
void setTranslation(const Vec3< T > &t)
Definition: Mat4.h:333
openvdb::v7_0::math::Mat4::inverse
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:504
openvdb::v7_0::GridClass
GridClass
Definition: Types.h:452
openvdb::v7_0::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:49
openvdb::v7_0::GRID_LEVEL_SET
Definition: Types.h:454
openvdb::v7_0::math::Coord::minComponent
void minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition: Coord.h:176
openvdb
Definition: Exceptions.h:13
openvdb::v7_0::tools::GridTransformer::getTransform
const Mat4R & getTransform() const
Definition: GridTransformer.h:247
openvdb::v7_0::tree::IteratorRange
Definition: TreeIterator.h:1307
openvdb::v7_0::tools::internal::TileSampler< PointSampler, TreeT >::TileSampler
TileSampler(const CoordBBox &, const typename TreeT::ValueType &, bool)
Definition: GridTransformer.h:124
openvdb::v7_0::math::eulerAngles
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:338
openvdb::v7_0::tools::resampleToMatch
void resampleToMatch(const GridType &inGrid, GridType &outGrid)
Resample an input grid into an output grid of the same type such that, after resampling,...
Definition: GridTransformer.h:504
openvdb::v7_0::tools::GridTransformer::transformGrid
void transformGrid(const GridT &inGrid, GridT &outGrid) const
Definition: GridTransformer.h:674
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:82
openvdb::v7_0::tools::signedFloodFill
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:266
openvdb::v7_0::math::isAffine
bool isAffine(const Mat4< T > &m)
Definition: Mat4.h:1323