jlblancoc / nanoflann

nanoflann: a C++11 header-only library for Nearest Neighbor (NN) search with KD-trees
Other
2.24k stars 491 forks source link

KDTree Class pass object via pointer doesn't work #197

Open 538Michael opened 1 year ago

538Michael commented 1 year ago

Hi, I've created a KDTree Class, I call, from main.cpp, another .cpp file to create the KDTree object and then return to me the KDTree object created for searchs, but when the object is passed throw reference, for some reason the dataset is empty.

Heres the code: KDTree.h

#pragma once
#include "nanoflann.hpp"
#include "Vector3.h"

namespace pathfind
{
    template <typename T>
    struct PointCloud
    {
        struct Point
        {
            T x, y, z;
        };

        using coord_t = T;  //!< The type of each coordinate

        std::vector<Point> pts;

        // Must return the number of data points
        inline size_t kdtree_get_point_count() const { return pts.size(); }

        // Returns the dim'th component of the idx'th point in the class:
        // Since this is inlined and the "dim" argument is typically an immediate
        // value, the
        //  "if/else's" are actually solved at compile time.
        inline T kdtree_get_pt(const size_t idx, const size_t dim) const
        {
            if (dim == 0)
                return pts[idx].x;
            else if (dim == 1)
                return pts[idx].y;
            else
                return pts[idx].z;
        }

        // Optional bounding-box computation: return false to default to a standard
        // bbox computation loop.
        //   Return true if the BBOX was already computed by the class and returned
        //   in "bb" so it can be avoided to redo it again. Look at bb.size() to
        //   find out the expected dimensionality (e.g. 2 or 3 for point clouds)
        template <class BBOX>
        bool kdtree_get_bbox(BBOX& /* bb */) const
        {
            return false;
        }
    };

    class MyKDTree {
    public:
        MyKDTree();
        void buildIndex(PointCloud<float>& cloud);
        size_t findNearestPoint(Vector3 position);

        typedef nanoflann::KDTreeSingleIndexAdaptor<
            nanoflann::L2_Simple_Adaptor<double, PointCloud<float>>,PointCloud<float>,3> KDTreeType;
        KDTreeType* m_kdTree;
    };
}

KDTree.cpp

#pragma once
#include "KDTree.h"
#include <iostream>
#include <fstream>

namespace pathfind
{
    MyKDTree::MyKDTree()
        : m_kdTree(nullptr)
    {
    }

    void MyKDTree::buildIndex(PointCloud<float>& cloud)
    {

        if (m_kdTree != nullptr) {
            delete m_kdTree;
        }
        m_kdTree = new KDTreeType(3, cloud, nanoflann::KDTreeSingleIndexAdaptorParams(10));
        m_kdTree->buildIndex();
    }

    size_t MyKDTree::findNearestPoint(Vector3 position)
    {
        double query_pt[3] = { position.GetX(), position.GetY(), position.GetZ()};

        size_t ret_index;
        double out_dist_sqr;
        nanoflann::KNNResultSet<double> resultSet(1);
        resultSet.init(&ret_index, &out_dist_sqr);
        m_kdTree->findNeighbors(resultSet, &query_pt[0], nanoflann::SearchParams());

        return ret_index;
    }

}

genenerateKDTree.cpp

std::shared_ptr<MyKDTree> generateKDTree()
{
    PointCloud<float> cloud;
    . . .
    // Fill cloud with points
    . . .
    auto kdTree = std::make_shared<MyKDTree>();
    kdTree->buildIndex(cloud);

    // If i run the following code it works as it's intended, but if I call this in main.cpp, it doesn't work
    std::cout << kdTree->findNearestPoint(Vector3(1, 1, 1)) << std::endl;

    return kdTree;
}

main.cpp

int main(int argc, char* argv[])
{
    auto kdTree = generateKDTree();
    // When I call this, the dataset of the KDTree is empty.
    std::cout << kdTree->findNearestPoint(Vector3(1, 1, 1)) << std::endl;
}
Mintpasokon commented 1 year ago

In

m_kdTree = new KDTreeType(3, cloud, nanoflann::KDTreeSingleIndexAdaptorParams(10));

cloud are referenced but not copied, by const DatasetAdaptor& KDTreeSingleIndexAdaptor::dataset_. When 'generateKDTree()' completes, 'cloud' is deconstructed and 'dataset_' becomes a null reference.