11#ifndef OPENVDB_TOOLS_LEVEL_SET_MORPH_HAS_BEEN_INCLUDED 
   12#define OPENVDB_TOOLS_LEVEL_SET_MORPH_HAS_BEEN_INCLUDED 
   45template<
typename GridT,
 
   46         typename InterruptT = util::NullInterrupter>
 
   59    LevelSetMorphing(GridT& sourceGrid, 
const GridT& targetGrid, InterruptT* interrupt = 
nullptr)
 
   60        : mTracker(sourceGrid, interrupt)
 
   61        , mTarget(&targetGrid)
 
   63        , mSpatialScheme(
math::HJWENO5_BIAS)
 
   64        , mTemporalScheme(
math::TVD_RK2)
 
 
   74    void setTarget(
const GridT& targetGrid) { mTarget = &targetGrid; }
 
   92        return mTracker.getSpatialScheme();
 
 
   97        mTracker.setSpatialScheme(scheme);
 
 
  102        return mTracker.getTemporalScheme();
 
 
  107        mTracker.setTemporalScheme(scheme);
 
 
  139        mDeltaMask = max-min;
 
 
  153    size_t advect(ValueType time0, ValueType time1);
 
  161    template<math::BiasedGradientScheme SpatialScheme>
 
  162    size_t advect1(ValueType time0, ValueType time1);
 
  166    size_t advect2(ValueType time0, ValueType time1);
 
  171    size_t advect3(ValueType time0, ValueType time1);
 
  174    const GridT                    *mTarget, *mMask;
 
  177    ValueType                       mMinMask, mDeltaMask;
 
  188        Morph(
const Morph& other);
 
  190        Morph(Morph& other, tbb::split);
 
  195        size_t advect(ValueType time0, ValueType time1);
 
  197        void operator()(
const LeafRange& r)
 const 
  199            if (mTask) mTask(
const_cast<Morph*
>(
this), r);
 
  203        void operator()(
const LeafRange& r)
 
  205            if (mTask) mTask(
this, r);
 
  209        void join(
const Morph& other) { mMaxAbsS = math::Max(mMaxAbsS, other.mMaxAbsS); }
 
  212        enum ThreadingMode { PARALLEL_FOR, PARALLEL_REDUCE }; 
 
  214        void cook(ThreadingMode mode, 
size_t swapBuffer = 0);
 
  217        typename GridT::ValueType sampleSpeed(ValueType time0, ValueType time1, Index speedBuffer);
 
  218        void sampleXformedSpeed(
const LeafRange& r, Index speedBuffer);
 
  219        void sampleAlignedSpeed(
const LeafRange& r, Index speedBuffer);
 
  223        template <
int Nominator, 
int Denominator>
 
  224        void euler(
const LeafRange&, ValueType, Index, Index, Index);
 
  225        inline void euler01(
const LeafRange& r, ValueType t, Index s) {this->euler<0,1>(r,t,0,1,s);}
 
  226        inline void euler12(
const LeafRange& r, ValueType t) {this->euler<1,2>(r, t, 1, 1, 2);}
 
  227        inline void euler34(
const LeafRange& r, ValueType t) {this->euler<3,4>(r, t, 1, 2, 3);}
 
  228        inline void euler13(
const LeafRange& r, ValueType t) {this->euler<1,3>(r, t, 1, 2, 3);}
 
  230        using FuncType = 
typename std::function<void (Morph*, 
const LeafRange&)>;
 
  231        LevelSetMorphing* mParent;
 
  232        ValueType         mMinAbsS, mMaxAbsS;
 
 
  239template<
typename Gr
idT, 
typename InterruptT>
 
  243    switch (mSpatialScheme) {
 
  245        return this->advect1<math::FIRST_BIAS  >(time0, time1);
 
  253        return this->advect1<math::HJWENO5_BIAS>(time0, time1);
 
 
  264template<
typename Gr
idT, 
typename InterruptT>
 
  265template<math::BiasedGradientScheme SpatialScheme>
 
  267LevelSetMorphing<GridT, InterruptT>::advect1(ValueType time0, ValueType time1)
 
  269    switch (mTemporalScheme) {
 
  271        return this->advect2<SpatialScheme, math::TVD_RK1>(time0, time1);
 
  273        return this->advect2<SpatialScheme, math::TVD_RK2>(time0, time1);
 
  275        return this->advect2<SpatialScheme, math::TVD_RK3>(time0, time1);
 
  283template<
typename Gr
idT, 
typename InterruptT>
 
  287LevelSetMorphing<GridT, InterruptT>::advect2(ValueType time0, ValueType time1)
 
  291        return this->advect3<SpatialScheme, TemporalScheme, math::UniformScaleMap>(time0, time1);
 
  292    } 
else if (trans.
mapType() == math::UniformScaleTranslateMap::mapType()) {
 
  293        return this->advect3<SpatialScheme, TemporalScheme, math::UniformScaleTranslateMap>(
 
  295    } 
else if (trans.
mapType() == math::UnitaryMap::mapType()) {
 
  296        return this->advect3<SpatialScheme, TemporalScheme, math::UnitaryMap    >(time0, time1);
 
  297    } 
else if (trans.
mapType() == math::TranslationMap::mapType()) {
 
  298        return this->advect3<SpatialScheme, TemporalScheme, math::TranslationMap>(time0, time1);
 
  305template<
typename Gr
idT, 
typename InterruptT>
 
  306template<math::BiasedGradientScheme SpatialScheme,
 
  307         math::TemporalIntegrationScheme TemporalScheme,
 
  310LevelSetMorphing<GridT, InterruptT>::advect3(ValueType time0, ValueType time1)
 
  312    Morph<MapT, SpatialScheme, TemporalScheme> tmp(*
this);
 
  313    return tmp.advect(time0, time1);
 
  319template<
typename Gr
idT, 
typename InterruptT>
 
  320template <
typename MapT, math::BiasedGradientScheme SpatialScheme,
 
  321          math::TemporalIntegrationScheme TemporalScheme>
 
  323LevelSetMorphing<GridT, InterruptT>::
 
  324Morph<MapT, SpatialScheme, TemporalScheme>::
 
  325Morph(LevelSetMorphing<GridT, InterruptT>& parent)
 
  327    , mMinAbsS(ValueType(1e-6))
 
  328    , mMap(parent.mTracker.grid().transform().template constMap<MapT>().get())
 
  333template<
typename Gr
idT, 
typename InterruptT>
 
  339Morph(
const Morph& other)
 
  340    : mParent(other.mParent)
 
  341    , mMinAbsS(other.mMinAbsS)
 
  342    , mMaxAbsS(other.mMaxAbsS)
 
  348template<
typename Gr
idT, 
typename InterruptT>
 
  354Morph(Morph& other, tbb::split)
 
  355    : mParent(other.mParent)
 
  356    , mMinAbsS(other.mMinAbsS)
 
  357    , mMaxAbsS(other.mMaxAbsS)
 
  363template<
typename Gr
idT, 
typename InterruptT>
 
  369advect(ValueType time0, ValueType time1)
 
  371    namespace ph = std::placeholders;
 
  377    while (time0 < time1 && mParent->mTracker.checkInterrupter()) {
 
  378        mParent->mTracker.leafs().rebuildAuxBuffers(auxBuffers);
 
  380        const ValueType dt = this->sampleSpeed(time0, time1, auxBuffers);
 
  384        switch(TemporalScheme) {
 
  388            mTask = std::bind(&Morph::euler01, ph::_1, ph::_2, dt, 2);
 
  391            this->cook(PARALLEL_FOR, 1);
 
  396            mTask = std::bind(&Morph::euler01, ph::_1, ph::_2, dt, 2);
 
  399            this->cook(PARALLEL_FOR, 1);
 
  403            mTask = std::bind(&Morph::euler12, ph::_1, ph::_2, dt);
 
  406            this->cook(PARALLEL_FOR, 1);
 
  411            mTask = std::bind(&Morph::euler01, ph::_1, ph::_2, dt, 3);
 
  414            this->cook(PARALLEL_FOR, 1);
 
  418            mTask = std::bind(&Morph::euler34, ph::_1, ph::_2, dt);
 
  421            this->cook(PARALLEL_FOR, 2);
 
  425            mTask = std::bind(&Morph::euler13, ph::_1, ph::_2, dt);
 
  428            this->cook(PARALLEL_FOR, 2);
 
  432            OPENVDB_THROW(ValueError, 
"Temporal integration scheme not supported!");
 
  438        mParent->mTracker.leafs().removeAuxBuffers();
 
  441        mParent->mTracker.track();
 
  447template<
typename Gr
idT, 
typename InterruptT>
 
  450inline typename GridT::ValueType
 
  455    namespace ph = std::placeholders;
 
  458    const size_t leafCount = mParent->mTracker.
leafs().leafCount();
 
  459    if (leafCount==0 || time0 >= time1) 
return ValueType(0);
 
  461    const math::Transform& xform  = mParent->mTracker.grid().transform();
 
  462    if (mParent->mTarget->transform() == xform &&
 
  463        (mParent->mMask == 
nullptr || mParent->mMask->transform() == xform)) {
 
  464        mTask = std::bind(&Morph::sampleAlignedSpeed, ph::_1, ph::_2, speedBuffer);
 
  466        mTask = std::bind(&Morph::sampleXformedSpeed, ph::_1, ph::_2, speedBuffer);
 
  468    this->cook(PARALLEL_REDUCE);
 
  470    static const ValueType CFL = (TemporalScheme == 
math::TVD_RK1 ? ValueType(0.3) :
 
  471                                  TemporalScheme == math::
TVD_RK2 ? ValueType(0.9) :
 
  472                                  ValueType(1.0))/math::
Sqrt(ValueType(3.0));
 
  473    const ValueType dt = 
math::Abs(time1 - time0), dx = mParent->mTracker.voxelSize();
 
  474    return math::Min(dt, ValueType(CFL*dx/mMaxAbsS));
 
  477template<
typename Gr
idT, 
typename InterruptT>
 
  485    using VoxelIterT = 
typename LeafType::ValueOnCIter;
 
  486    using SamplerT = tools::GridSampler<typename GridT::ConstAccessor, tools::BoxSampler>;
 
  488    const MapT& map = *mMap;
 
  491    typename GridT::ConstAccessor targetAcc = mParent->mTarget->getAccessor();
 
  492    SamplerT target(targetAcc, mParent->mTarget->transform());
 
  493    if (mParent->mMask == 
nullptr) {
 
  494        for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
 
  495            ValueType* speed = leafIter.buffer(speedBuffer).data();
 
  497            for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
 
  498                ValueType& s = speed[voxelIter.pos()];
 
  499                s -= target.wsSample(map.applyMap(voxelIter.getCoord().asVec3d()));
 
  503            if (isZero) speed[0] = std::numeric_limits<ValueType>::max();
 
  506        const ValueType 
min = mParent->mMinMask, invNorm = 1.0f/(mParent->mDeltaMask);
 
  507        const bool invMask = mParent->isMaskInverted();
 
  508        typename GridT::ConstAccessor maskAcc = mParent->mMask->getAccessor();
 
  509        SamplerT mask(maskAcc,  mParent->mMask->transform());
 
  510        for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
 
  511            ValueType* speed = leafIter.buffer(speedBuffer).data();
 
  513            for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
 
  514                const Vec3R xyz = map.applyMap(voxelIter.getCoord().asVec3d());
 
  516                ValueType& s = speed[voxelIter.pos()];
 
  517                s -= target.wsSample(xyz);
 
  518                s *= invMask ? 1 - a : a;
 
  522            if (isZero) speed[0] = std::numeric_limits<ValueType>::max();
 
  527template<
typename Gr
idT, 
typename InterruptT>
 
  535    using VoxelIterT = 
typename LeafType::ValueOnCIter;
 
  539    typename GridT::ConstAccessor target = mParent->mTarget->getAccessor();
 
  541    if (mParent->mMask == 
nullptr) {
 
  542        for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
 
  543            ValueType* speed = leafIter.buffer(speedBuffer).data();
 
  545            for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
 
  546                ValueType& s = speed[voxelIter.pos()];
 
  547                s -= target.getValue(voxelIter.getCoord());
 
  551            if (isZero) speed[0] = std::numeric_limits<ValueType>::max();
 
  554        const ValueType 
min = mParent->mMinMask, invNorm = 1.0f/(mParent->mDeltaMask);
 
  555        const bool invMask = mParent->isMaskInverted();
 
  556        typename GridT::ConstAccessor mask = mParent->mMask->getAccessor();
 
  557        for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
 
  558            ValueType* speed = leafIter.buffer(speedBuffer).data();
 
  560            for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
 
  561                const Coord ijk = voxelIter.getCoord();
 
  563                ValueType& s = speed[voxelIter.pos()];
 
  564                s -= target.getValue(ijk);
 
  565                s *= invMask ? 1 - a : a;
 
  569            if (isZero) speed[0] = std::numeric_limits<ValueType>::max();
 
  574template<
typename Gr
idT, 
typename InterruptT>
 
  580cook(ThreadingMode mode, 
size_t swapBuffer)
 
  584    const int grainSize   = mParent->mTracker.getGrainSize();
 
  585    const LeafRange range = mParent->mTracker.leafs().leafRange(grainSize);
 
  587    if (mParent->mTracker.getGrainSize()==0) {
 
  589    } 
else if (mode == PARALLEL_FOR) {
 
  590        tbb::parallel_for(range, *
this);
 
  591    } 
else if (mode == PARALLEL_REDUCE) {
 
  592        tbb::parallel_reduce(range, *
this);
 
  594        OPENVDB_THROW(ValueError, 
"expected threading mode " << 
int(PARALLEL_FOR)
 
  595            << 
" or " << 
int(PARALLEL_REDUCE) << 
", got " << 
int(mode));
 
  598    mParent->mTracker.leafs().swapLeafBuffer(swapBuffer, grainSize == 0);
 
  600    mParent->mTracker.endInterrupter();
 
  603template<
typename Gr
idT, 
typename InterruptT>
 
  606template <
int Nominator, 
int Denominator>
 
  610euler(
const LeafRange& range, ValueType dt,
 
  613    using SchemeT = math::BIAS_SCHEME<SpatialScheme>;
 
  614    using StencilT = 
typename SchemeT::template ISStencil<GridType>::StencilType;
 
  615    using VoxelIterT = 
typename LeafType::ValueOnCIter;
 
  616    using NumGrad = math::GradientNormSqrd<MapT, SpatialScheme>;
 
  618    static const ValueType Alpha = ValueType(Nominator)/ValueType(Denominator);
 
  619    static const ValueType Beta  = ValueType(1) - Alpha;
 
  621    mParent->mTracker.checkInterrupter();
 
  622    const MapT& map = *mMap;
 
  623    StencilT stencil(mParent->mTracker.grid());
 
  625    for (
typename LeafRange::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
 
  626        const ValueType* speed = leafIter.buffer(speedBuffer).data();
 
  628        const ValueType* phi = leafIter.buffer(phiBuffer).data();
 
  629        ValueType* result = leafIter.buffer(resultBuffer).data();
 
  630        for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
 
  631            const Index n = voxelIter.pos();
 
  633            stencil.moveTo(voxelIter);
 
  634            const ValueType v = stencil.getValue() - dt * speed[n] * NumGrad::result(map, stencil);
 
  635            result[n] = Nominator ? Alpha * phi[n] + Beta * v : v;
 
  646#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION 
  648#ifdef OPENVDB_INSTANTIATE_LEVELSETMORPH 
Performs multi-threaded interface tracking of narrow band level sets. This is the building-block for ...
Definition Exceptions.h:65
TemporalIntegrationScheme
Temporal integration schemes.
Definition FiniteDifference.h:233
@ TVD_RK1
Definition FiniteDifference.h:235
@ UNKNOWN_TIS
Definition FiniteDifference.h:234
@ TVD_RK2
Definition FiniteDifference.h:236
@ TVD_RK3
Definition FiniteDifference.h:237
Type SmoothUnitStep(Type x)
Return 0 if x < 0, 1 if x > 1 or else (3 − 2 x) x².
Definition Math.h:287
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance.
Definition Math.h:349
float Sqrt(float x)
Return the square root of a floating-point value.
Definition Math.h:761
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
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition Math.h:595
BiasedGradientScheme
Biased Gradients are limited to non-centered differences.
Definition FiniteDifference.h:164
@ FIRST_BIAS
Definition FiniteDifference.h:166
@ THIRD_BIAS
Definition FiniteDifference.h:168
@ WENO5_BIAS
Definition FiniteDifference.h:169
@ UNKNOWN_BIAS
Definition FiniteDifference.h:165
@ SECOND_BIAS
Definition FiniteDifference.h:167
@ HJWENO5_BIAS
Definition FiniteDifference.h:170
const Type & Min(const Type &a, const Type &b)
Return the minimum of two values.
Definition Math.h:656
Coord Abs(const Coord &xyz)
Definition Coord.h:518
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition Math.h:443
bool isZero(const Type &x)
Return true if x is exactly equal to zero.
Definition Math.h:337
Index32 Index
Definition Types.h:54
math::Vec3< Real > Vec3R
Definition Types.h:72
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
#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_INSTANTIATE_CLASS
Definition version.h.in:158