c – Boost :: geometry查询返回索引

我想拥有类,它使用boost :: geometry :: index :: rtree作为空间索引器.这个类本身应该知道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));
    ???
}

我不知道怎么做正确的查询(请不要看这个可怕的矢量返回副本,它只是为了清酒).我可以做这个:

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;
}

我想知道,我怎样才能摆脱内部副本(不是返回副本,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是常数,您甚至可以直接返回惰性范围,甚至不分配单个向量.

原始/旧答案文本如下:

您无法在没有引用计数的情况下复制共享指针.

当然,您可以更改值对以包含对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";
}
点赞