test_tdtree.cpp

Back to Temporal kd-tree

test/pastel/geometry/

// Description: Testing for temporal kd-tree
// Documentation: tdtree.txt

#include "test/test_init.h"

#include "pastel/geometry/tdtree/tdtree.h"

#include "pastel/geometry/search_nearest.h"
#include "pastel/geometry/nearestset/kdtree_nearestset.h"
#include "pastel/geometry/nearestset/bruteforce_nearestset.h"
#include "pastel/geometry/distance/distance_point_point.h"

#include "pastel/sys/locator.h"
#include "pastel/sys/set.h"
#include "pastel/sys/output.h"
#include "pastel/sys/for_each_point.h"
#include "pastel/sys/random/random_gaussian.h"
#include "pastel/sys/iterator/counting_iterator.h"
#include "pastel/sys/iterator/constant_iterator.h"

namespace
{

    using Point = Vector2;
    using Locator = Vector_Locator<real, 2>;
    using Tree = TdTree<TdTree_Settings<Locator>>;
    using ConstIterator = Tree::ConstIterator;

    PASTEL_STATIC_ASSERT(IsTdTree<Tree>::value);

}

TEST_CASE("Concepts (TdTree)")
{
    PASTEL_CONCEPT_CHECK(Tree, PointSet_Concept);
    PASTEL_CONCEPT_CHECK(PointSet_Real<Tree>, Real_Concept);
}

TEST_CASE("Construction (TdTree)")
{
    Tree tree;
    REQUIRE(tree.simple());

    tree.clear();
    REQUIRE(tree.simple());

    Tree().swap(tree);
}

TEST_CASE("Grid (TdTree)")
{
    Array<Point> pointSet(Vector2i(5, 5));

    forEachPoint(
        AlignedBox2i(Point(0), Point(5)),
        [&](const Point& point)
    {
        pointSet(point[0], point[1]) = point;
    });

    PASTEL_CONCEPT_CHECK(decltype(pointSet), Set_Concept);
    pointSetLocator(pointSet);

    using PointSet = decltype(pointSet);
    PASTEL_CONCEPT_CHECK(PointSet, PointSet_Concept);
    PASTEL_CONCEPT_CHECK(Locator, Locator_Concept(PointSet_PointId<PointSet>));

    Tree tree(pointSet);
    REQUIRE(tree.simple());

    REQUIRE(tree.bound() == 
        AlignedBox2(Vector2(0, 0), Vector2(4, 4)));

    REQUIRE(tree.timeToIndex(-(real)Infinity()) == 0);
    REQUIRE(tree.timeToIndex(-2) == 0);
    REQUIRE(tree.timeToIndex(-1) == 0);
    REQUIRE(tree.timeToIndex(-0.5) == 0);
    REQUIRE(tree.timeToIndex(0) == 0);
    REQUIRE(tree.timeToIndex(0.5) == 1);
    REQUIRE(tree.timeToIndex(1) == 1);
    REQUIRE(tree.timeToIndex(24) == 24);
    REQUIRE(tree.timeToIndex(24.5) == 25);
    REQUIRE(tree.timeToIndex(25.5) == 25);
    REQUIRE(tree.timeToIndex(26) == 25);
    REQUIRE(tree.timeToIndex((real)Infinity()) == 25);

    std::unordered_set<ConstIterator, IteratorAddress_Hash> neighborSet;

    auto report = [&](
        real distance,
        const ConstIterator& point)
    {
        neighborSet.insert(point);
    };

    searchNearest(
        kdTreeNearestSet(tree), 
        Point(1, 3), 
        PASTEL_TAG(report), report,
        PASTEL_TAG(kNearest), 5);

    auto pointSet_ = tree.pointSetSet();

    REQUIRE(neighborSet.size() == 5);
    //REQUIRE(neighborSet.count(pointSet(1, 3)) > 0);
}

TEST_CASE("Linear (TdTree)")
{
    std::vector<Point> pointSet;
    integer n = 1000;
    for (integer i = 0; i < n; ++i)
    {
        pointSet.emplace_back(i, 0);
    }

    Tree tree(pointSet);
    REQUIRE(tree.simple());

    for (integer i = 0; i < n; ++i)
    {
        {
            Vector2 timeInterval = { (real)i, (real)n };
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            integer distance =
                searchNearest(
                    nearestSet, 
                    Point(0, 0)).first;
            REQUIRE(distance == square(i));
        }
        {
            Vector2 timeInterval = { (real)0, (real)i + 1 };
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            integer distance =
                searchNearest(
                    nearestSet, 
                    Point(0, 0)).first;
            REQUIRE(distance == 0);
        }
        {
            Vector2 timeInterval = { (real)i, (real)i + 1 };
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            integer distance =
                searchNearest(
                    nearestSet, 
                    Point(0, 0)).first;
            REQUIRE(distance == square(i));
        }
    }

    for (integer i = 0; i < n; ++i)
    {
        Vector4 timeInterval = { (real)i, (real)i + 1, (real)i + 5, (real)i + 6 };
        {
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            real distance =
                searchNearest(
                    nearestSet, 
                    Point(i + 2, 0)).first;

            REQUIRE((integer)distance == square(2));
        }

        {
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            real distance =
                searchNearest(
                    nearestSet, 
                    Point(i - 3, 0)).first;

            REQUIRE((integer)distance == square(3));
        }

        {
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            real distance =
                searchNearest(
                    nearestSet, 
                    Point(i + 4, 0)).first;
            integer correct = i < (n - 5) ? square(1) : square(4);

            REQUIRE((integer)distance == correct);
        }

        {
            auto nearestSet = kdTreeNearestSet(tree, PASTEL_TAG(intervalSequence), timeInterval);
            real distance =
                searchNearest(
                    nearestSet, 
                    Point(i + 7, 0)).first;
            integer correct = i < (n - 5) ? square(2) : square(7);

            REQUIRE((integer)distance == correct);
        }
    }
}