Boost::geometry 查询返回索引

Boost::geometry query returning indexes

我想要 class,它使用 boost::geometry::index::rtree 作为空间索引器。仅此 class 应该知道 boost,所以我使用这样的东西:

struct VeryImportantInfo
{
    ...
    float x;
    float y;
}

class Catalogue
{
    ...
public:
    std::vector<std::shared_ptr<VeryImportantInfo> > FindIn(float x1, float x2, float y1, float y2);

protected:
    using point = bg::model::point<float, 2, bg::cs::cartesian>;
    using value = std::pair<point, std::shared_ptr<VeryImportantInfo> >;
    using box = bg::model::box<point>;        

    boost::geometry::index::rtree< value, bgi::quadratic<16> > rtree;
}

std::vector<std::shared_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));
    ???
}

我不知道如何正确查询(请不要复制这个糟糕的向量return,它只是为了举例) .我可以这样做:

std::vector<std::shared_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));
    std::vector<value> result_s;
    rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));
    std::vector<std::shared_ptr<VeryImportantInfo> > results;
    results.reserve(result_s.size());
    for( auto& p : result_s)
    {
        results.emplace_back(p.second);
    }
    return results;
}

我想知道,我怎样才能摆脱内部副本(不是return副本,results.emplace_back(p.second); - 这个)。因为我可以在 result_s 中获得超过 10k 个结果,这将是一种浪费。

谢谢!

更新评论

如果一开始就担心临时向量,那就不要使用它。您可以使用来自 boost::geometry::index:

qbegin()/qend() 免费函数
std::vector<std::shared_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));

    auto b = bgi::qbegin(rtree, bgi::intersects(query_box)), 
        e = bgi::qend(rtree);

    auto range  = boost::make_iterator_range(b, e);

    using namespace boost::adaptors;
    return boost::copy_range<std::vector<std::shared_ptr<VeryImportantInfo>>>(
            range | transformed([](value const& p) { return p.second; }));
}

事实上,如果已知 rtree 是常量,您甚至可以直接 return 惰性范围,甚至不分配单个向量。


original/old 回答正文如下:


没有引用计数就不能复制共享指针。

当然,您可以更改 value 对以包含对 shared_ptr 的 引用 ,但是您可以使用原始引用 ( std::reference_wrapper) 或 weak_ptr.

std::reference_wrapper<T>

这是我对原始参考的看法(只需保留您的重要数据 :)):

Live On Coliru

#include <iostream>
#include <vector>

#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/index/rtree.hpp>

namespace bg  = boost::geometry;
namespace bgi = bg::index;

struct VeryImportantInfo {
    float x;
    float y;
};

VeryImportantInfo a = { 2, 2 };
VeryImportantInfo b = { 3, 3 };
VeryImportantInfo c = { 4, 4 };

class Catalogue
{
public:
    Catalogue() {
        rtree.insert(value(point(a.x, a.y), a));
        rtree.insert(value(point(b.x, b.y), b));
        rtree.insert(value(point(c.x, c.y), c));
    }

    std::vector<std::reference_wrapper<VeryImportantInfo> > FindIn(float x1, float x2, float y1, float y2);

protected:
    using point = bg::model::point<float, 2, bg::cs::cartesian>;
    using value = std::pair<point, std::reference_wrapper<VeryImportantInfo> >;
    using box   = bg::model::box<point>;

    boost::geometry::index::rtree< value, bgi::quadratic<16> > rtree;
};

std::vector<std::reference_wrapper<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));

    std::vector<value> result_s;
    rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));

    std::vector<std::reference_wrapper<VeryImportantInfo> > results;
    results.reserve(result_s.size());

    for(auto& p : result_s) {
        results.push_back(p.second);
    }
    return results;
}

int main() {
    Catalogue cat;
    for (VeryImportantInfo& vii : cat.FindIn(1,2,3,4))
        std::cout << vii.x << ", " << vii.y << "\n";
}

std::weak_ptr<T>

这里和weak_ptr<>一样。有人可能会争辩说这并不能解决很多问题(因为引用计数仍在进行)但至少需要的工作更少。

Live On Coliru

#include <iostream>
#include <memory>
#include <vector>

#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/index/rtree.hpp>

namespace bg  = boost::geometry;
namespace bgi = bg::index;

struct VeryImportantInfo {
    float x;
    float y;
};

auto a = std::make_shared<VeryImportantInfo>(VeryImportantInfo{2, 2});
auto b = std::make_shared<VeryImportantInfo>(VeryImportantInfo{3, 3});
auto c = std::make_shared<VeryImportantInfo>(VeryImportantInfo{4, 4});

class Catalogue
{
public:
    Catalogue() {
        rtree.insert(value(point(a->x, a->y), a));
        rtree.insert(value(point(b->x, b->y), b));
        rtree.insert(value(point(c->x, c->y), c));
    }

    std::vector<std::weak_ptr<VeryImportantInfo> > FindIn(float x1, float x2, float y1, float y2);

protected:
    using point = bg::model::point<float, 2, bg::cs::cartesian>;
    using value = std::pair<point, std::shared_ptr<VeryImportantInfo> >;
    using box   = bg::model::box<point>;

    boost::geometry::index::rtree< value, bgi::quadratic<16> > rtree;
};

std::vector<std::weak_ptr<VeryImportantInfo> > Catalogue::FindIn(float x1, float y1, float x2, float y2)
{
    box query_box(point(x1, y1), point(x2, y2));

    std::vector<value> result_s;
    rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));

    std::vector<std::weak_ptr<VeryImportantInfo> > results;
    results.reserve(result_s.size());

    for(auto& p : result_s) {
        results.push_back(p.second);
    }
    return results;
}

int main() {
    Catalogue cat;
    for (auto& vii_p : cat.FindIn(1,2,3,4))
        if (auto vii = vii_p.lock())
            std::cout << vii->x << ", " << vii->y << "\n";
}