заданный следующий набор точек в векторе
{(100, 150), (101, 152), (102, 151), (105, 155), (50, 50), (51, 55), (55, 55), (150, 250), ( 190, 260)}
Мне нужно определить соседние точки и их количество. Допустим, допустимое расстояние было установлено как 5. Теперь мне нужен следующий вывод:
частота точек (100, 150) с в 5 единицах равна 4.
частота точек (50, 50) с в 5 единицах составляет 3
частота точек (150, 250) в пределах 5 единиц равна 1
частота точек (190, 260) в пределах 5 единиц равна 1
Я пробовал RTree решение этой проблемы, но не смог определить логику для исключения всех соседних точек в качестве кандидатов. Означает, что как только я определил, что есть четыре соседа (100, 150), я не хочу идентифицировать соседей этих соседей. Я хотел бы перейти к следующему значению. Вот предположения:
1. эффективность является главной заботой
2. Вектор не отсортирован
3. вектор может содержать тысячи точек.
Я использую C ++ и поддерживаю реализацию RTree. Пожалуйста, наставьте меня, как я могу достичь решения
Вот код, следующий за кодом, который подсчитывает количество соседей уникальных точек в векторе. Мне нужно руководство по исключению соседей из точки, как только они были определены.
include set, iostream, boost/geometry.hpp, boost/geometry/geometries/point.hpp, boost/geometry/index/rtree.hpp
using namespace std;
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
typedef bg::model::point<int, 2, bg::cs::cartesian> point;
typedef std::pair<point, unsigned> value;
struct ltstr
{
bool operator()(const point &p1, const point &p2) const
{
return (p1.get < 0 >() < p2.get < 0 >() || p1.get < 1 >() < p2.get < 1 >());
}
};void main()
{
vector<point> candidatePoints{ point(457, 184), point(457, 184), point(457, 184), point(457, 184), point(457, 184),
point(456, 184), point(456, 184), point(456, 184), point(456, 184), point(456, 184),
point(456, 184), point(457, 184), point(457, 184), point(457, 184), point(458, 184), point(459, 185) };
bgi::rtree< value, bgi::quadratic<16> > rtree;
set<point, ltstr> uniqueCandidatePoints;
for (int i = 0; i < candidatePoints.size(); ++i)
{
int x = candidatePoints[i].get < 0 >();
int y = candidatePoints[i].get < 1 >();
uniqueCandidatePoints.insert(point(x, y));
rtree.insert(make_pair(candidatePoints[i], i));
}
for (auto it = uniqueCandidatePoints.begin(); it != uniqueCandidatePoints.end(); ++it)
{
std::vector<value> returnedValues;
point currentItem = *it;
rtree.query(bgi::satisfies([&](value const& v) {return bg::distance(v.first, currentItem) < 5; }),
std::back_inserter(returnedValues));
cout << "Current Item: " << currentItem.get < 0 >() << "," << currentItem.get < 1 >() << "Count: " << returnedValues.size() << endl;
}
getchar();
}
R-деревья являются одними из самых полезных пространственная индексация структуры данных пока доказали свою полезность для конкретных областей и проблем. Тем не менее, это не повод воздерживаться от дидактики (в конце концов, то, что спрашивается, может быть упрощением реальной проблемы).
Если вы решите использовать R-деревья, вы выполняете декомпозицию домена. Как и в случае с кривыми заполнения пространства, вы можете упорядочить пространство под рукой, но все же элементы узла сохраняют пространственную близость (чем дальше вы уходите от корня).
Идеальным решением было бы построить ваши R-деревья таким образом, чтобы radius=5
области формируются, но это потребует пользовательской структуры данных и настройки алгоритмов STR или массовой загрузки и будет напоминать кластеризация алгоритм.
С boost::index
доступно вы можете определить все окрестности, Я постараюсь уточнить код:
#include <vector>
#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
using point = bg::model::point < float, 2, bg::cs::cartesian > ;
Boost R-Trees имеют query
метод. Хотя он предназначен для выполнения типичных запросов, таких как kNN или перекрывающихся, вы можете кормить его пользовательские предикаты. Здесь мы разрабатываем тот, который возвращает true
если точка, которую мы запрашиваем, до max_dist
от base
точка (обе переменные указаны при построении)
struct distance_pred
{
point const& _base;
double _threshold;
distance_pred(point const& base, double max_dist)
: _base(base)
, _threshold(max_dist)
{
}
bool operator()(point const& p) const
{
auto d = boost::geometry::distance(_base, p);
return d && d < _threshold;
}
};
// just for output
std::ostream& operator<<(std::ostream &os, point const& p)
{
os << "{ " << p.get<0>() << ", " << p.get<1>() << " }";
return os;
}
Для каждой точки мы запрашиваем те, которые лежат не более distance=5
Кроме
int main()
{
std::vector<point> cloud {
point(100, 150), point(101, 152), point(102, 151),
point(105, 155), point( 50, 50), point( 51, 55),
point( 55, 55), point(150, 250), point(190, 260)
};
bgi::rtree<point, bgi::quadratic<16>> rtree(cloud.begin(), cloud.end());
std::vector<point> hood;
for (auto &&p : cloud)
{
hood.clear();
std::cout << "neighborhood of point " << p << "\n-----------------\n\n";
rtree.query(bgi::satisfies(distance_pred(p, 5)), std::back_inserter(hood));
// Output the results -----------------------------------------
if (!hood.empty())
{
for (auto &&pt : hood) std::cout << '\t' << pt << std::endl;
}
else
{
std::cout << "\t... is empty\n";
}
std::cout << std::endl;
}
}
Если вы хотите что-то исключить, я считаю, кластеризация алгоритм будет более подходящим, и это выходит за рамки RTrees. Например, что если точки, которые вы исключили из-за того, что лежали близко к точке 1, оказались ближе к точке 2?
Тем не менее, если вы действительно хотите это сделать, это просто вопрос поддержки. Определить точку так
using pointI = std::pair<point, std::size_t>; // remember : geometric info first
и превратить вас в петлю
for (std::size_t i(0), i < cloud.size(); ++i)
{
if (cloud.end() != std::find(rec.begin(), rec.end(), i))
{ // you'll only be building neighorhoods for points that are not touched
// queries and recording performed on point2 types
}
}
Полный код демонстрирует проблемы в этой логике: много окрестностей остаются пустыми.
То же самое, что и выше, может быть достигнуто с гораздо меньшим количеством кода, но несколько более сложным (в основном мы помещаем запрос в лямбда-функцию и используем итераторы запросов для циклического просмотра результатов). демонстрация
R-дерево это просто структура данных, а не алгоритм, и для меня это выглядит довольно сложно. Если вам не нужно иметь дело с эффективностью mirco, я бы использовал простые стандартные алгоритмы и вектор точек. std::count_if
будет моим первым предположением.