Как я могу использовать Rtree библиотеки Boost в C++?

Меня попросили написать функцию, которая принимает «LatLon» в качестве входных данных (LatLon — это класс с двумя двойниками: широта и долгота) и возвращает идентификатор (int) ближайшего пересечения к этой позиции. Мне даны функции, которые возвращают местоположение любого пересечения, а также возвращают расстояние между двумя позициями. Из-за «тестов производительности» мои инструкторы предложили мне хранить местоположения всех пересечений в R-дереве (из библиотеки повышения), где было бы быстрее найти ближайший перекресток, а не перебирать все пересечения. Однако я только изучаю, как работают R-деревья, и у меня возникают проблемы с их созданием.

Проблема в том, что я видел несколько примеров в Интернете, где они создают R-деревья, но что меня действительно смущает, так это то, что они используют только два аргумента, а не четыре, в одном из конструкторов. Например, они используют:

bgi::rtree‹ value_t, bgi::quadratic‹16> > rtree_;

где value_t — это пара box и unsigned int, а другой аргумент — это размер, однако, если я попытаюсь сделать:

bgi::rtree‹ точка, bgi::quadratic‹16>> пересечениеRTree;

где точка представляет собой пару беззнакового целого числа и LatLon, компилятор жалуется, что я использую неправильный конструктор и что он должен иметь четыре аргумента вместо двух.

Я прочитал онлайн и обнаружил, что должен использовать этот конструктор:

rtree (parameters_type const &, indexable_getter const &, value_equal const &, allocator_type const &)

Однако я не понимаю описания каждого аргумента, поэтому не знаю, как использовать этот конструктор. Итак, не могли бы вы помочь мне понять, что делать? И если можно, не могли бы вы привести мне короткий пример? Большое тебе спасибо.

Это класс LatLon. Он доступен только для чтения, поэтому я не могу его изменить:

class LatLon{

public:
LatLon(){}
explicit LatLon(float lat_, float lon_) : m_lat(lat_),m_lon(lon_){}

double lat() const { return m_lat; }
double lon() const { return m_lon; }

private:
float m_lat = std::numeric_limits<float>::quiet_NaN();
float m_lon = std::numeric_limits<float>::quiet_NaN();

friend class boost::serialization::access;
template<class Archive>void serialize(Archive& ar, unsigned int)
    { ar & m_lat & m_lon; }
};

std::ostream& operator<<(std::ostream& os,LatLon);
std::array<LatLon,4> bounds_to_corners(std::pair<LatLon,LatLon> bounds);

Вот почему я пытаюсь сделать:

#include "LatLon.h"
#include <string>
#include <vector>
#include <cmath>
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <algorithm>

namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
using namespace std;
typedef pair<unsigned,LatLon> point;

bgi::rtree<point, bgi::quadratic<16>> intersectionRTree;

for (unsigned intersection = 0; intersection < intersectionNumber; intersection++) 
{point intP = make_pair(intersection,getIntersectionPosition(intersection));
intersectionRTree.insert(intP);}

Функция getIntersectionPosition возвращает значение LatLon, intervalNumber — это максимальное количество пересечений, а пересечение — это индекс пересечения.

Компилятор дает мне детали ошибки, которая только отправляет меня к другим файлам, но на самом деле никогда не говорит мне, где я ошибаюсь.


person V. Vallejo    schedule 11.02.2017    source источник
comment
Пройдите тур и прочитайте страницу справки. Вот Полное руководство и список книг по C++.   -  person    schedule 12.02.2017
comment
Вы уверены, что это то, на что жалуется компилятор? Вы используете свой собственный тип точки? Не могли бы вы вставить фрагмент своего кода с помощью rtree?   -  person Adam Wulkiewicz    schedule 12.02.2017
comment
Вы можете проверить, пожалуйста? Я добавил код.   -  person V. Vallejo    schedule 12.02.2017


Ответы (1)


Чтобы использовать тип в Boost.Geometry в качестве одной из поддерживаемых геометрий, вы должны адаптировать этот тип к одной из концепций Boost.Geometry. Таким образом вы сообщаете библиотеке, как она может использовать объекты этого типа, как получить доступ к координатам, какая система координат и типы координат используются и т. д.

В случае Point: http://www.boost.org/doc/libs/1_63_0/libs/geometry/doc/html/geometry/reference/concepts/concept_point.html

Для удобства Boost.Geometry предоставляет макросы, которые делают это за вас в наиболее типичных случаях: http://www.boost.org/doc/libs/1_63_0/libs/geometry/doc/html/geometry/reference/адаптированный/register.html

Ваш пример немного проблематичен, ваша точка не определяет сеттеры, только геттеры, поэтому некоторые операции не будут работать с ней, например. его нельзя сохранить в bg::model::box, необходимом для пространственного запроса (например, bgi::intersects()) или запроса knn в недекартовой системе координат (bgi::nearest()), поскольку координаты могут быть нормализованы внутри. Поэтому, чтобы использовать его напрямую, вам придется делать больше вещей, чем обычно требуется.

Так что на вашем месте я бы просто сохранил Point типа bg::model::point в R-дереве и преобразовал LatLon в него перед вставкой, а затем обратно после выполнения запроса.

Но если вы действительно хотите использовать класс LatLon с библиотекой, вы можете:

  • получить от него или обернуть его в какой-то другой тип, реализовать необходимые операции в этом типе и использовать макрос REGISTER (пример ниже).
  • адаптируйте тип LatLon вручную, как это сделано здесь, например: noreferrer">https://github.com/boostorg/geometry/blob/develop/include/boost/geometry/geometries/point_xy.hpp#L87

Кстати, если вы не хотите реализовывать свой собственный IndexableGetter (3-й параметр шаблона rtree), вы должны поместить Point в std::pair как тип First. Ниже я предположил, что вы хотите использовать систему координат spherical_equatorial. Я также предположил, что тип координат — float, потому что это то, что вы фактически храните внутри LatLon в вашем примере.

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <iostream>
#include <limits>
#include <vector>

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

class LatLon
{
public:
    LatLon(){}
    explicit LatLon(float lat_, float lon_) : m_lat(lat_),m_lon(lon_){}

    float lat() const { return m_lat; }
    float lon() const { return m_lon; }

private:
    float m_lat = std::numeric_limits<float>::quiet_NaN();
    float m_lon = std::numeric_limits<float>::quiet_NaN();
};

struct MyLatLon
{
    MyLatLon() {}
    MyLatLon(float lat_, float lon_) : ll(lat_, lon_){}

    float get_lat() const { return ll.lat(); }
    float get_lon() const { return ll.lon(); }
    void set_lat(float v) { ll = LatLon(v, ll.lon()); }
    void set_lon(float v) { ll = LatLon(ll.lat(), v); }

    LatLon ll;
};

BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(MyLatLon, float,
                                         bg::cs::spherical_equatorial<bg::degree>,
                                         get_lon, get_lat, set_lon, set_lat)

int main()
{
    typedef std::pair<MyLatLon, unsigned> point_pair;

    bgi::rtree<point_pair, bgi::quadratic<16>> intersectionRTree;

    intersectionRTree.insert(std::make_pair(MyLatLon(0, 0), 0));
    intersectionRTree.insert(std::make_pair(MyLatLon(2, 2), 1));

    bg::model::box<MyLatLon> b(MyLatLon(1, 1), MyLatLon(3, 3));
    std::vector<point_pair> result1;
    intersectionRTree.query(bgi::intersects(b), std::back_inserter(result1));
    if (! result1.empty())
        std::cout << bg::wkt(result1[0].first) << std::endl;

    std::vector<point_pair> result2;
    intersectionRTree.query(bgi::nearest(MyLatLon(0, 1), 1), std::back_inserter(result2));
    if (! result2.empty())
        std::cout << bg::wkt(result2[0].first) << std::endl;
}
person Adam Wulkiewicz    schedule 15.02.2017