boost::geometry: nearest neighbors using a circle

微笑、不失礼 提交于 2019-12-18 02:48:07

问题


I am using the Rtree implementation of boost::geometry to store (lots of) 2D points. Now I need to do distance-based nearest neigbors queries.

However, the manual only describes queries as rectangular boxes (i.e. "Get me all the points that are inside this rectangle") or "KNN" queries ("Get me the nearest 'n' points from here).

What I want is actually "Get me the set of points that are at a distance less than 'n'".

I noticed that you can define a unary-predicate, but is is... unary (thus, not suitable for a condition on two points).

The manual documents some model::ring class that I thought at first might fit for a circle, but it is actually more a kind of a piece-wise line (a polygon). Is that assumption correct ?

Is there another way to process such a query ? Or is it simply not possible ?


回答1:


The last example in the documented "User-defined queries" shows how to use a lambda in the predicate. This lambda can bind other variables in the scope, for instance, the point whose neighbors you are looking for.

Here is a small example. The example looks for points that are closer to (5, 5) than 2 units, for a collection of points that lie on the straight y = x. It should be easy to modify in order to check first if the sought point is in the R-tree, or get it directly out of the R-tree.

#include <iostream>

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


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

typedef bg::model::point<float, 2, bg::cs::cartesian> point;
typedef std::pair<point, unsigned> value;

int main(int argc, char *argv[])
{
    bgi::rtree< value, bgi::quadratic<16> > rtree;

    // create some values
    for ( unsigned i = 0 ; i < 10 ; ++i )
    {
        point p = point(i, i);
        rtree.insert(std::make_pair(p, i));
    }

    // search for nearest neighbours
    std::vector<value> returned_values;
    point sought = point(5, 5);
    rtree.query(bgi::satisfies([&](value const& v) {return bg::distance(v.first, sought) < 2;}),
                std::back_inserter(returned_values));

    // print returned values
    value to_print_out;
    for (size_t i = 0; i < returned_values.size(); i++) {
        to_print_out = returned_values[i];
        float x = to_print_out.first.get<0>();
        float y = to_print_out.first.get<1>();
        std::cout << "Select point: " << to_print_out.second << std::endl;
        std::cout << "x: " << x << ", y: " << y << std::endl;
    }

    return 0;
}

Compile and run with Boost installed via Macports on OS X:

$ c++ -std=c++11 -I/opt/local/include -L/opt/local/lib main.cpp -o geom && ./geom
Select point: 4
x: 4, y: 4
Select point: 5
x: 5, y: 5
Select point: 6
x: 6, y: 6



回答2:


The manual documents some model::ring class that I thought at first might fit for a circle, but it is actually more a kind of a piece-wise line (a polygon). Is that assumption correct ?

I think that's correct.

I noticed that you can define a unary-predicate, but is is... unary (thus, not suitable for a condition on two points).

Would the 'second' (or reference) point not be fixed? Because then you can use a simple bind expression to supply the reference point.


Additionally you can use the KNN algorithm with a very large n and add some kind of breaking condition on the predicate:

Breaking or pausing the query

for ( Rtree::const_query_iterator it = tree.qbegin(bgi::nearest(pt, 10000)) ;
      it != tree.qend() ; ++it )
{
    // do something with value
    if ( has_enough_nearest_values() )
        break;
}

This could work pretty well, assuming that the algorithm already traverses the points in order of ascending distance (you will want to check that assumption of course).



来源:https://stackoverflow.com/questions/22909171/boostgeometry-nearest-neighbors-using-a-circle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!