104template<
typename T> 
inline 
  105const typename std::enable_if<!VecTraits<T>::IsVec, T>::type& 
 
  106min(
const T& a, 
const T& b) { 
return std::min(a, b); }
 
  108template<
typename T> 
inline 
  109const typename std::enable_if<!VecTraits<T>::IsVec, T>::type&
 
  110max(
const T& a, 
const T& b) { 
return std::max(a, b); }
 
  114template<
typename T> 
inline 
  115const typename std::enable_if<VecTraits<T>::IsVec, T>::type& 
 
  116min(
const T& a, 
const T& b)
 
  118    const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
 
  119    return (aMag < bMag ? a : (bMag < aMag ? b : std::min(a, b)));
 
 
  122template<
typename T> 
inline 
  123const typename std::enable_if<VecTraits<T>::IsVec, T>::type&
 
  124max(
const T& a, 
const T& b)
 
  126    const typename T::ValueType aMag = a.lengthSqr(), bMag = b.lengthSqr();
 
  127    return (aMag < bMag ? b : (bMag < aMag ? a : std::max(a, b)));
 
 
  131template<
typename T> 
inline 
  132typename std::enable_if<!std::is_integral<T>::value, T>::type 
 
  133divide(
const T& a, 
const T& b) { 
return a / b; }
 
  135template<
typename T> 
inline 
  136typename std::enable_if<std::is_integral<T>::value, T>::type 
 
  140    if (b != zero) 
return a / b;
 
  141    if (a == zero) 
return 0;
 
  142    return (a > 0 ? std::numeric_limits<T>::max() : -std::numeric_limits<T>::max());
 
 
  148inline bool divide(
bool a, 
bool ) { 
return a; }
 
  153enum CSGOperation { CSG_UNION, CSG_INTERSECTION, CSG_DIFFERENCE };
 
  155template<
typename TreeType, CSGOperation Operation>
 
  156struct BuildPrimarySegment
 
  158    using ValueType = 
typename TreeType::ValueType;
 
  159    using TreePtrType = 
typename TreeType::Ptr;
 
  160    using LeafNodeType = 
typename TreeType::LeafNodeType;
 
  161    using NodeMaskType = 
typename LeafNodeType::NodeMaskType;
 
  162    using RootNodeType = 
typename TreeType::RootNodeType;
 
  163    using NodeChainType = 
typename RootNodeType::NodeChainType;
 
  164    using InternalNodeType = 
typename NodeChainType::template Get<1>;
 
  166    BuildPrimarySegment(
const TreeType& lhs, 
const TreeType& rhs)
 
  167        : mSegment(new TreeType(lhs.background()))
 
  173    void operator()()
 const 
  175        std::vector<const LeafNodeType*> leafNodes;
 
  178            std::vector<const InternalNodeType*> internalNodes;
 
  179            mLhsTree->getNodes(internalNodes);
 
  181            ProcessInternalNodes op(internalNodes, *mRhsTree, *mSegment, leafNodes);
 
  182            tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
 
  185        ProcessLeafNodes op(leafNodes, *mRhsTree, *mSegment);
 
  186        tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
 
  189    TreePtrType& segment() { 
return mSegment; }
 
  193    struct ProcessInternalNodes {
 
  195        ProcessInternalNodes(std::vector<const InternalNodeType*>& lhsNodes,
 
  196            const TreeType& rhsTree, TreeType& outputTree,
 
  197            std::vector<const LeafNodeType*>& outputLeafNodes)
 
  198            : mLhsNodes(lhsNodes.
empty() ? nullptr : &lhsNodes.front())
 
  200            , mLocalTree(mRhsTree->background())
 
  201            , mOutputTree(&outputTree)
 
  203            , mOutputLeafNodes(&outputLeafNodes)
 
  207        ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
 
  208            : mLhsNodes(other.mLhsNodes)
 
  209            , mRhsTree(other.mRhsTree)
 
  210            , mLocalTree(mRhsTree->background())
 
  211            , mOutputTree(&mLocalTree)
 
  213            , mOutputLeafNodes(&mLocalLeafNodes)
 
  217        void join(ProcessInternalNodes& other)
 
  219            mOutputTree->merge(*other.mOutputTree);
 
  220            mOutputLeafNodes->insert(mOutputLeafNodes->end(),
 
  221                other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
 
  224        void operator()(
const tbb::blocked_range<size_t>& range)
 
  226            tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
 
  227            tree::ValueAccessor<TreeType>       outputAcc(*mOutputTree);
 
  229            std::vector<const LeafNodeType*> tmpLeafNodes;
 
  231            for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
 
  233                const InternalNodeType& lhsNode = *mLhsNodes[n];
 
  234                const Coord& ijk = lhsNode.origin();
 
  235                const InternalNodeType * rhsNode =
 
  236                    rhsAcc.template probeConstNode<InternalNodeType>(ijk);
 
  239                    lhsNode.getNodes(*mOutputLeafNodes);
 
  241                    if (Operation == CSG_INTERSECTION) {
 
  242                        if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
 
  243                            tmpLeafNodes.clear();
 
  244                            lhsNode.getNodes(tmpLeafNodes);
 
  245                            for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
 
  246                                outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
 
  250                        if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
 
  251                            tmpLeafNodes.clear();
 
  252                            lhsNode.getNodes(tmpLeafNodes);
 
  253                            for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
 
  254                                outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
 
  262        InternalNodeType 
const * 
const * 
const mLhsNodes;
 
  263        TreeType                 
const * 
const mRhsTree;
 
  265        TreeType                       * 
const mOutputTree;
 
  267        std::vector<const LeafNodeType*>         mLocalLeafNodes;
 
  268        std::vector<const LeafNodeType*> * 
const mOutputLeafNodes;
 
  271    struct ProcessLeafNodes {
 
  273        ProcessLeafNodes(std::vector<const LeafNodeType*>& lhsNodes,
 
  274            const TreeType& rhsTree, TreeType& output)
 
  275            : mLhsNodes(lhsNodes.
empty() ? nullptr : &lhsNodes.front())
 
  277            , mLocalTree(mRhsTree->background())
 
  278            , mOutputTree(&output)
 
  282        ProcessLeafNodes(ProcessLeafNodes& other, tbb::split)
 
  283            : mLhsNodes(other.mLhsNodes)
 
  284            , mRhsTree(other.mRhsTree)
 
  285            , mLocalTree(mRhsTree->background())
 
  286            , mOutputTree(&mLocalTree)
 
  290        void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
 
  292        void operator()(
const tbb::blocked_range<size_t>& range)
 
  294            tree::ValueAccessor<const TreeType> rhsAcc(*mRhsTree);
 
  295            tree::ValueAccessor<TreeType>       outputAcc(*mOutputTree);
 
  297            for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
 
  299                const LeafNodeType& lhsNode = *mLhsNodes[n];
 
  300                const Coord& ijk = lhsNode.origin();
 
  302                const LeafNodeType* rhsNodePt = rhsAcc.probeConstLeaf(ijk);
 
  306                    LeafNodeType* outputNode = outputAcc.touchLeaf(ijk);
 
  307                    ValueType * outputData = outputNode->buffer().data();
 
  308                    NodeMaskType& outputMask = outputNode->getValueMask();
 
  310                    const ValueType * lhsData = lhsNode.buffer().data();
 
  311                    const NodeMaskType& lhsMask = lhsNode.getValueMask();
 
  313                    const ValueType * rhsData = rhsNodePt->buffer().data();
 
  314                    const NodeMaskType& rhsMask = rhsNodePt->getValueMask();
 
  316                    if (Operation == CSG_INTERSECTION) {
 
  317                        for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
 
  318                            const bool fromRhs = lhsData[pos] < rhsData[pos];
 
  319                            outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
 
  320                            outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
 
  322                    } 
else if (Operation == CSG_DIFFERENCE){
 
  323                        for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
 
  324                            const ValueType rhsVal = math::negative(rhsData[pos]);
 
  325                            const bool fromRhs = lhsData[pos] < rhsVal;
 
  326                            outputData[pos] = fromRhs ? rhsVal : lhsData[pos];
 
  327                            outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
 
  330                        for (Index pos = 0; pos < LeafNodeType::SIZE; ++pos) {
 
  331                            const bool fromRhs = lhsData[pos] > rhsData[pos];
 
  332                            outputData[pos] = fromRhs ? rhsData[pos] : lhsData[pos];
 
  333                            outputMask.set(pos, fromRhs ? rhsMask.isOn(pos) : lhsMask.isOn(pos));
 
  338                    if (Operation == CSG_INTERSECTION) {
 
  339                        if (rhsAcc.getValue(ijk) < ValueType(0.0)) {
 
  340                            outputAcc.addLeaf(
new LeafNodeType(lhsNode));
 
  343                        if (!(rhsAcc.getValue(ijk) < ValueType(0.0))) {
 
  344                            outputAcc.addLeaf(
new LeafNodeType(lhsNode));
 
  351        LeafNodeType 
const * 
const * 
const mLhsNodes;
 
  352        TreeType             
const * 
const mRhsTree;
 
  354        TreeType                   * 
const mOutputTree;
 
  357    TreePtrType               mSegment;
 
  358    TreeType    
const * 
const mLhsTree;
 
  359    TreeType    
const * 
const mRhsTree;
 
  363template<
typename TreeType, CSGOperation Operation>
 
  364struct BuildSecondarySegment
 
  366    using ValueType = 
typename TreeType::ValueType;
 
  367    using TreePtrType = 
typename TreeType::Ptr;
 
  368    using LeafNodeType = 
typename TreeType::LeafNodeType;
 
  369    using NodeMaskType = 
typename LeafNodeType::NodeMaskType;
 
  370    using RootNodeType = 
typename TreeType::RootNodeType;
 
  371    using NodeChainType = 
typename RootNodeType::NodeChainType;
 
  372    using InternalNodeType = 
typename NodeChainType::template Get<1>;
 
  374    BuildSecondarySegment(
const TreeType& lhs, 
const TreeType& rhs)
 
  375        : mSegment(new TreeType(lhs.background()))
 
  381    void operator()()
 const 
  383        std::vector<const LeafNodeType*> leafNodes;
 
  386            std::vector<const InternalNodeType*> internalNodes;
 
  387            mRhsTree->getNodes(internalNodes);
 
  389            ProcessInternalNodes 
op(internalNodes, *mLhsTree, *mSegment, leafNodes);
 
  390            tbb::parallel_reduce(tbb::blocked_range<size_t>(0, internalNodes.size()), op);
 
  393        ProcessLeafNodes 
op(leafNodes, *mLhsTree, *mSegment);
 
  394        tbb::parallel_reduce(tbb::blocked_range<size_t>(0, leafNodes.size()), op);
 
  397    TreePtrType& segment() { 
return mSegment; }
 
  401    struct ProcessInternalNodes {
 
  403        ProcessInternalNodes(std::vector<const InternalNodeType*>& rhsNodes,
 
  404            const TreeType& lhsTree, TreeType& outputTree,
 
  405            std::vector<const LeafNodeType*>& outputLeafNodes)
 
  406            : mRhsNodes(rhsNodes.
empty() ? nullptr : &rhsNodes.front())
 
  408            , mLocalTree(mLhsTree->background())
 
  409            , mOutputTree(&outputTree)
 
  411            , mOutputLeafNodes(&outputLeafNodes)
 
  415        ProcessInternalNodes(ProcessInternalNodes& other, tbb::split)
 
  416            : mRhsNodes(other.mRhsNodes)
 
  417            , mLhsTree(other.mLhsTree)
 
  418            , mLocalTree(mLhsTree->background())
 
  419            , mOutputTree(&mLocalTree)
 
  421            , mOutputLeafNodes(&mLocalLeafNodes)
 
  425        void join(ProcessInternalNodes& other)
 
  427            mOutputTree->merge(*other.mOutputTree);
 
  428            mOutputLeafNodes->insert(mOutputLeafNodes->end(),
 
  429                other.mOutputLeafNodes->begin(), other.mOutputLeafNodes->end());
 
  432        void operator()(
const tbb::blocked_range<size_t>& range)
 
  434            tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
 
  435            tree::ValueAccessor<TreeType>       outputAcc(*mOutputTree);
 
  437            std::vector<const LeafNodeType*> tmpLeafNodes;
 
  439            for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
 
  441                const InternalNodeType& rhsNode = *mRhsNodes[n];
 
  442                const Coord& ijk = rhsNode.origin();
 
  443                const InternalNodeType * lhsNode =
 
  444                    lhsAcc.template probeConstNode<InternalNodeType>(ijk);
 
  447                   rhsNode.getNodes(*mOutputLeafNodes);
 
  449                    if (Operation == CSG_INTERSECTION) {
 
  450                        if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
 
  451                            tmpLeafNodes.clear();
 
  452                            rhsNode.getNodes(tmpLeafNodes);
 
  453                            for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
 
  454                                outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
 
  457                    } 
else if (Operation == CSG_DIFFERENCE) {
 
  458                        if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
 
  459                            tmpLeafNodes.clear();
 
  460                            rhsNode.getNodes(tmpLeafNodes);
 
  461                            for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
 
  462                                LeafNodeType* outputNode = 
new LeafNodeType(*tmpLeafNodes[i]);
 
  463                                outputNode->negate();
 
  464                                outputAcc.addLeaf(outputNode);
 
  468                        if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
 
  469                            tmpLeafNodes.clear();
 
  470                            rhsNode.getNodes(tmpLeafNodes);
 
  471                            for (
size_t i = 0, I = tmpLeafNodes.size(); i < I; ++i) {
 
  472                                outputAcc.addLeaf(
new LeafNodeType(*tmpLeafNodes[i]));
 
  480        InternalNodeType 
const * 
const * 
const mRhsNodes;
 
  481        TreeType                 
const * 
const mLhsTree;
 
  483        TreeType                       * 
const mOutputTree;
 
  485        std::vector<const LeafNodeType*>         mLocalLeafNodes;
 
  486        std::vector<const LeafNodeType*> * 
const mOutputLeafNodes;
 
  489    struct ProcessLeafNodes {
 
  491        ProcessLeafNodes(std::vector<const LeafNodeType*>& rhsNodes,
 
  492            const TreeType& lhsTree, TreeType& output)
 
  493            : mRhsNodes(rhsNodes.
empty() ? nullptr : &rhsNodes.front())
 
  495            , mLocalTree(mLhsTree->background())
 
  496            , mOutputTree(&output)
 
  500        ProcessLeafNodes(ProcessLeafNodes& rhs, tbb::split)
 
  501            : mRhsNodes(rhs.mRhsNodes)
 
  502            , mLhsTree(rhs.mLhsTree)
 
  503            , mLocalTree(mLhsTree->background())
 
  504            , mOutputTree(&mLocalTree)
 
  508        void join(ProcessLeafNodes& rhs) { mOutputTree->merge(*rhs.mOutputTree); }
 
  510        void operator()(
const tbb::blocked_range<size_t>& range)
 
  512            tree::ValueAccessor<const TreeType> lhsAcc(*mLhsTree);
 
  513            tree::ValueAccessor<TreeType>       outputAcc(*mOutputTree);
 
  515            for (
size_t n = range.begin(), N = range.end(); n < N; ++n) {
 
  517                const LeafNodeType& rhsNode = *mRhsNodes[n];
 
  518                const Coord& ijk = rhsNode.origin();
 
  520                const LeafNodeType* lhsNode = lhsAcc.probeConstLeaf(ijk);
 
  523                    if (Operation == CSG_INTERSECTION) {
 
  524                        if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
 
  525                            outputAcc.addLeaf(
new LeafNodeType(rhsNode));
 
  527                    } 
else if (Operation == CSG_DIFFERENCE) {
 
  528                        if (lhsAcc.getValue(ijk) < ValueType(0.0)) {
 
  529                            LeafNodeType* outputNode = 
new LeafNodeType(rhsNode);
 
  530                            outputNode->negate();
 
  531                            outputAcc.addLeaf(outputNode);
 
  534                        if (!(lhsAcc.getValue(ijk) < ValueType(0.0))) {
 
  535                            outputAcc.addLeaf(
new LeafNodeType(rhsNode));
 
  542        LeafNodeType 
const * 
const * 
const mRhsNodes;
 
  543        TreeType             
const * 
const mLhsTree;
 
  545        TreeType                   * 
const mOutputTree;
 
  548    TreePtrType               mSegment;
 
  549    TreeType    
const * 
const mLhsTree;
 
  550    TreeType    
const * 
const mRhsTree;
 
  554template<CSGOperation Operation, 
typename TreeType>
 
  555typename TreeType::Ptr
 
  556doCSGCopy(
const TreeType& lhs, 
const TreeType& rhs)
 
  558    BuildPrimarySegment<TreeType, Operation> primary(lhs, rhs);
 
  559    BuildSecondarySegment<TreeType, Operation> secondary(lhs, rhs);
 
  562    tbb::task_group tasks;
 
  564    tasks.run(secondary);
 
  567    primary.segment()->merge(*secondary.segment());
 
  570    tools::signedFloodFill(*primary.segment(), 
true, 1, 1);
 
  572    return primary.segment();
 
  579template<
typename TreeType>
 
  580struct GridOrTreeConstructor
 
  582    using TreeTypePtr = 
typename TreeType::Ptr;
 
  583    static TreeTypePtr construct(
const TreeType&, TreeTypePtr& tree) { 
return tree; }
 
  587template<
typename TreeType>
 
  588struct GridOrTreeConstructor<
Grid<TreeType> >
 
  591    using GridTypePtr = 
typename Grid<TreeType>::Ptr;
 
  592    using TreeTypePtr = 
typename TreeType::Ptr;
 
  594    static GridTypePtr construct(
const GridType& grid, TreeTypePtr& tree) {
 
  595        GridTypePtr maskGrid(GridType::create(tree));
 
  596        maskGrid->setTransform(grid.transform().copy());
 
  597        maskGrid->insertMeta(grid);
 
  606template <
typename LeafT>
 
  607using LeafPairList = std::vector<std::pair<LeafT*, LeafT*>>;
 
  613template <
typename TreeT>
 
  614void transferLeafNodes(TreeT &srcTree, TreeT &dstTree,
 
  615                              LeafPairList<typename TreeT::LeafNodeType> &overlapping)
 
  617    using LeafT = 
typename TreeT::LeafNodeType;
 
  618    tree::ValueAccessor<TreeT> acc(dstTree);
 
  619    std::vector<LeafT*> srcLeafNodes;
 
  620    srcLeafNodes.reserve(srcTree.leafCount());
 
  621    srcTree.stealNodes(srcLeafNodes);
 
  623    for (LeafT *srcLeaf : srcLeafNodes) {
 
  624        LeafT *dstLeaf = acc.probeLeaf(srcLeaf->origin());
 
  626            overlapping.emplace_back(dstLeaf, srcLeaf);
 
  628            acc.addLeaf(srcLeaf);
 
  634template <
typename TreeT, 
typename OpT>
 
  636typename std::enable_if<
 
  637    !std::is_same<typename TreeT::ValueType, bool>::value &&
 
  638    !std::is_same<typename TreeT::BuildType, ValueMask>::value &&
 
  639    std::is_same<
typename TreeT::LeafNodeType::Buffer::ValueType,
 
  640    typename TreeT::LeafNodeType::Buffer::StorageType>::value>::type
 
  641doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
 
  643    using LeafT  = 
typename TreeT::LeafNodeType;
 
  644    LeafPairList<LeafT> overlapping;
 
  645    transferLeafNodes(srcTree, dstTree, overlapping);
 
  647    using RangeT = tbb::blocked_range<size_t>;
 
  648    tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
 
  649        for (auto i = r.begin(); i != r.end(); ++i) {
 
  650            LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
 
  651            dstLeaf->getValueMask() |= srcLeaf->getValueMask();
 
  652            auto *ptr = dstLeaf->buffer().data();
 
  653            for (auto v = srcLeaf->cbeginValueOn(); v; ++v) op(ptr[v.pos()], *v);
 
  660template <
typename TreeT, 
typename OpT>
 
  662typename std::enable_if<
 
  663    std::is_same<typename TreeT::BuildType, ValueMask>::value &&
 
  664    std::is_same<typename TreeT::ValueType, bool>::value>::type
 
  665doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT)
 
  667    using LeafT  = 
typename TreeT::LeafNodeType;
 
  668    LeafPairList<LeafT> overlapping;
 
  669    transferLeafNodes(srcTree, dstTree, overlapping);
 
  671    using RangeT = tbb::blocked_range<size_t>;
 
  672    tbb::parallel_for(RangeT(0, overlapping.size()), [&overlapping](
const RangeT& r) {
 
  673        for (auto i = r.begin(); i != r.end(); ++i) {
 
  674            overlapping[i].first->getValueMask() |= overlapping[i].second->getValueMask();
 
  675            delete overlapping[i].second;
 
  681template <
typename TreeT, 
typename OpT>
 
  683typename std::enable_if<
 
  684    std::is_same<typename TreeT::ValueType, bool>::value &&
 
  685    !std::is_same<typename TreeT::BuildType, ValueMask>::value>::type
 
  686doCompActiveLeafVoxels(TreeT &srcTree, TreeT &dstTree, OpT op)
 
  688    using LeafT = 
typename TreeT::LeafNodeType;
 
  689    LeafPairList<LeafT> overlapping;
 
  690    transferLeafNodes(srcTree, dstTree, overlapping);
 
  692    using RangeT = tbb::blocked_range<size_t>;
 
  693    using WordT = 
typename LeafT::Buffer::WordType;
 
  694    tbb::parallel_for(RangeT(0, overlapping.size()), [op, &overlapping](
const RangeT& r) {
 
  695        for (auto i = r.begin(); i != r.end(); ++i) {
 
  696            LeafT *dstLeaf = overlapping[i].first, *srcLeaf = overlapping[i].second;
 
  697            WordT *w1 = dstLeaf->buffer().data();
 
  698            const WordT *w2 = srcLeaf->buffer().data();
 
  699            const WordT *w3 = &(srcLeaf->getValueMask().template getWord<WordT>(0));
 
  700            for (Index32 n = LeafT::Buffer::WORD_COUNT; n--; ++w1) {
 
  701                WordT tmp = *w1, state = *w3++;
 
  703                *w1 = (state & tmp) | (~state & *w1);
 
  705            dstLeaf->getValueMask() |= srcLeaf->getValueMask();
 
  712template <
typename TreeT>
 
  715    using ValueT = 
typename TreeT::ValueType;
 
  717    void operator()(ValueT& dst, 
const ValueT& src)
 const { dst = src; }
 
  720template <
typename TreeT>
 
  721void validateLevelSet(
const TreeT& 
tree, 
const std::string& gridName = std::string(
""))
 
  723    using ValueT = 
typename TreeT::ValueType;
 
  725    if (!(
tree.background() > zero)) {
 
  726        std::stringstream ss;
 
  727        ss << 
"expected grid ";
 
  728        if (!gridName.empty()) ss << gridName << 
" ";
 
  729        ss << 
"outside value > 0, got " << 
tree.background();
 
  732    if (!(-
tree.background() < zero)) {
 
  733        std::stringstream ss;
 
  734        ss << 
"expected grid ";
 
  735        if (!gridName.empty()) ss << gridName << 
" ";
 
  736        ss << 
"inside value < 0, got " << -
tree.background();