windowed_pointtree.h

Back to Orphans

pastel/geometry/

// Description: Point kd-tree on a windowed point-set

#ifndef PASTELGEOMETRY_WINDOWED_POINTTREE_H
#define PASTELGEOMETRY_WINDOWED_POINTTREE_H

#include "pastel/geometry/pointkdtree/pointkdtree.h"
#include "pastel/geometry/difference/difference_alignedbox_alignedbox.h"
#include "pastel/geometry/shape/alignedbox.h"

#include <unordered_map>

namespace Pastel
{

    class PointQuery_WindowedPointTree_Concept
    {
    public:
        using Locator = UserDefinedType;

        // The compile-time dimension of the window.
        // If M != Dynamic, M == queryDimension().
        static constexpr int M = UserDefinedInteger;

        integer queryDimension() const;

        const Locator& locator() const;

        template <typename Point_Functor>
        void queryPoints(
            const AlignedBox<integer, M>& region,
            Point_Functor report);
    };

    template <typename PointQuery>
    class WindowedPointTree
    {
    public:
        using Locator = typename PointQuery::Locator;
        using Point = typename Locator::Point;
        using Real = typename Locator::Real;

        static constexpr int N = Locator::N;
        static constexpr int M = PointQuery::M;

        using Tree = PointKdTree<Real, N, Locator>;
        using ConstIterator = typename Tree::Point_ConstIterator;

        using ActiveSet = std::unordered_map<Point, ConstIterator>;
        using ActiveIterator = typename ActiveSet::iterator;
        using ConstActiveIterator = typename ActiveSet::iterator;

        explicit WindowedPointTree(
            const PointQuery& pointQuery = PointQuery());

        void swap(WindowedPointTree& that);

        template <typename SplitRule>
        void refine(const SplitRule& splitRule,
            integer bucketSize = 8);

        void setWindow(
            const AlignedBox<integer, M>& window);

        const AlignedBox<integer, PointQuery::M>& window() const;

        const Tree& tree() const;

        const ActiveSet& activeSet() const;

    private:
        Tree tree_;
        AlignedBox<integer, M> window_;
        ActiveSet activeSet_;
        PointQuery pointQuery_;
    };

}

namespace Pastel
{

    template <typename PointQuery>
    WindowedPointTree<PointQuery>::WindowedPointTree(
        const PointQuery& pointQuery)
        : tree_(pointQuery.locator(), false)
        , window_()
        , activeSet_()
        , pointQuery_(pointQuery)
    {
    }

    template <typename PointQuery>
    void WindowedPointTree<PointQuery>::swap(
        WindowedPointTree& that)
    {
        using std::swap;

        tree_.swap(that.tree_);
        window_.swap(that.window_);
        activeSet_.swap(that.activeSet_);
        swap(pointQuery_, that.pointQuery_);
    }

    template <typename PointQuery>
    template <typename SplitRule>
    void WindowedPointTree<PointQuery>::refine(
        const SplitRule& splitRule,
        integer bucketSize)
    {
        tree_.refine(splitRule, bucketSize);
    }

    template <typename PointQuery>
    void WindowedPointTree<PointQuery>::setWindow(
        const AlignedBox<integer, M>& window)
    {
        // The points that are in the current window,
        // but not in the new window, need to be removed.
        auto pointEraser = [&](const Point& point) -> bool
        {
            ActiveIterator iter = activeSet_.find(point);
            PENSURE(iter != activeSet_.end())
                //tree_.erase(iter->second);
                tree_.hide(iter->second);
            //activeSet_.erase(point);

            return true;
        };

        difference(window_, window, 
            [&](const AlignedBox<integer, M>& box) -> bool
        {
            pointQuery_.queryPoints(box, pointEraser);
            return true;
        });

        // The points that are in the new window,
        // but not in the current window, need to be added.

        auto pointInserter = [&](const Point& point)
        {
            ActiveIterator iter = activeSet_.find(point);
            if (iter != activeSet_.end())
            {
                tree_.show(iter->second);
            }
            else
            {
                activeSet_.insert(
                    std::make_pair(point,
                    tree_.insert(point)));
            }
        };

        difference(window, window_, 
            [&](const AlignedBox<integer, M>& box) -> bool
        {
            pointQuery_.queryPoints(box, pointInserter);
            return true;
        });

        // Set the new window.
        window_ = window;
    }

    template <typename PointQuery>
    const AlignedBox<integer, PointQuery::M>& 
        WindowedPointTree<PointQuery>::window() const
    {
        return window_;
    }

    template <typename PointQuery>
    const typename WindowedPointTree<PointQuery>::Tree& 
        WindowedPointTree<PointQuery>::tree() const
    {
        return tree_;
    }

    template <typename PointQuery>
    const typename WindowedPointTree<PointQuery>::ActiveSet& 
        WindowedPointTree<PointQuery>::activeSet() const
    {
        return activeSet_;
    }

}

#endif