подсчитайте частоту групп в векторе, используя rtree (или любой другой алгоритм)

задан следующий набор точек в векторе {(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();
  }

person Prem    schedule 29.06.2015    source источник
comment
Совсем не широко, наоборот, весьма специфично. Я подготовил ответ, пожалуйста, снова откройте, чтобы я мог опубликовать его   -  person Nikos Athanasiou    schedule 29.06.2015
comment
@NikosAthanasiou - ваше редактирование вопроса действительно должно было быть комментарием. Я отменил редактирование, но не стесняйтесь ссылаться на свой ответ здесь, в комментариях.   -  person Michael0x2a    schedule 29.06.2015
comment
@ Michael0x2a Мое редактирование вопроса должно было быть ответом, и этот вопрос не должен был быть закрыт. Я боролся с такими темами в прошлом и могу понять, насколько это может быть неприятно. В любом случае, вот Ссылка, получайте удовольствие, я Буду признателен за уведомление, если тема снова откроется (многое можно сказать о коде в ссылке)   -  person Nikos Athanasiou    schedule 30.06.2015
comment
@NikosAthanasiou спасибо за элегантный код с использованием rtree. Но это не совсем то, что я хочу сделать. Как только соседи определены, я хочу исключить их на следующем шаге. В выводе вашего кода окрестности точки {100, 150} ------------------ {101, 152} {102, 151} --------- -------- теперь я не хочу вычислять соседей для {101, 152} и {102, 151}. Я хотел бы продолжить проверку {105, 155}. Пожалуйста, направьте меня, как я могу этого добиться.   -  person Prem    schedule 30.06.2015
comment
@NikosAthanasiou Я включил свой код в вопрос. Я вижу, что ваш код более элегантный. Не могли бы вы помочь мне с окончательным решением. Потому что ты был тем, кто понял, что именно мне нужно в первую очередь.   -  person Prem    schedule 01.07.2015
comment
@NikosAthanasiou вопрос снова открыт.   -  person gsamaras    schedule 01.07.2015
comment
@ Michael0x2a Опубликовал это как ответ   -  person Nikos Athanasiou    schedule 01.07.2015


Ответы (2)


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-деревья имеют метод 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. Например, что, если точки, которые вы исключили из-за того, что они расположены близко к point1, оказались ближе к point2?

Тем не менее, если вы действительно хотите это сделать, это просто вопрос бухгалтерского учета. Определите точку так

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

Полный код демонстрирует проблемы в этой логике: множество кварталы остаются пустыми.

То же самое, что и выше, может быть достигнуто с гораздо меньшим количеством кода, но значительно более сложным (в основном мы помещаем запрос в лямбда-функцию и используем итераторы запросов для циклического просмотра результатов) Демо

person Nikos Athanasiou    schedule 01.07.2015
comment
Я получаю сообщение об ошибке для auto в следующей функции lambada. не подскажете чем его заменить? std::for_each(hood.begin(), hood.end(), [&rec](auto &&pt) { rec.push_back(pt.second); - person Prem; 01.07.2015
comment
@Prem замените auto на pointI const& и получите обновление компилятора для Visual Studio. - person Nikos Athanasiou; 01.07.2015
comment
Большое спасибо ... это именно то, что мне было нужно, когда я разместил этот вопрос .... Еще раз спасибо .... - person Prem; 02.07.2015
comment
не могли бы вы объяснить логику следования в коде? if (rec.end() == std::find(rec.begin(), rec.end(), i)) и // исключить окрестности из следующих запросов std::for_each(hood.begin(), hood. end(), [&rec](auto &&pt) { rec.push_back(pt.second); - person Prem; 05.07.2015
comment
@Prem Вы можете либо задать другой вопрос SO (они бесплатны), либо погуглить следующие ключевые слова: std::find std::for_each и lambda functions. Сомневаюсь, что смог бы подробно остановиться на них в виде комментариев. Вы можете уведомить меня со ссылкой на вопрос, хотя я верю, что на него быстро ответят. - person Nikos Athanasiou; 05.07.2015
comment
я задал этот вопрос /31320633/ можем ли мы использовать алгоритм упаковки для того же примера вместо квадратичного, упаковка кажется намного быстрее, чем другие варианты. Поскольку у нас уже есть значения для вставки в rtree в векторе, не должно возникнуть проблем с указанием диапазона при создании rtree. Заранее спасибо... :) - person Prem; 09.07.2015
comment
Есть одна проблема с кодом. UnaryPredicate, переданный в satisfies() BGIPredicate, проверяется для каждого значения, хранящегося в R-дереве. Таким образом, функции пространственного индексирования не используются во время этого запроса, потому что все значения будут проверены в любом случае. В дополнение к вашему UnaryPredicate вы должны передать пространственный предикат для фильтрации нежелательных областей пространства, например: bgi::intersects(box(point(bg::get<0>(p)-5, bg::get<1>(p)-5), point(bg::get<0>(p)+5, bg::get<1>(p)+5))) && bgi::satisfies(distance_pred(p, 5)) - person Adam Wulkiewicz; 22.10.2015
comment
@Prem R-дерево Boost.Geometry создается с помощью алгоритма упаковки, когда Range передается в конструктор. Так что на самом деле этот случай покрыт ответом. - person Adam Wulkiewicz; 22.10.2015

R-tree — это просто структура данных, но не алгоритм, и мне он кажется довольно сложным . Если вам действительно не нужно иметь дело с эффективностью mirco, я бы использовал простые стандартные алгоритмы и вектор точек. std::count_if было бы моим первым предположением.

person 463035818_is_not_a_number    schedule 29.06.2015
comment
Я решил использовать R-tree после долгой и разочаровывающей попытки решить с помощью count_if. Могу ли я получить более подробную информацию о решении? Это вообще не решение. И для ветеранов, которые проголосовали за мой вопрос как за широкий и общий, вы хотите, чтобы я опубликовал код, который я написал, пытаясь решить эту проблему конкретно? - person Prem; 30.06.2015
comment
@Prem еще раз: мне не имеет особого смысла выбирать между R-Tree или с использованием count_if. Один представляет собой структуру данных, а другой — алгоритм (работающий с определенными структурами данных). И да, публикация любых уже предпринятых вами усилий может только помочь получить более качественные ответы. Учитывая информацию, которую вы предоставляете на данный момент, указать вам на стандартный алгоритм — это лучшее, что я могу сделать, чтобы помочь вам. - person 463035818_is_not_a_number; 30.06.2015
comment
Я очень хорошо понимаю разницу. Я хотел сказать, что сначала попытался использовать count_if с простым вектором, а затем использовал RTree для организации своих данных и извлечения необходимой информации из RTree. Мой код делает то же самое, что и код, опубликованный Никосом Афанасиу. Не могли бы вы предложить некоторые изменения в коде, чтобы исключить соседей предыдущих точек. например В выводе кода окрестности точки {100, 150} есть {101, 152} {102, 151}, теперь я не хочу вычислять соседей для {101, 152} и {102, 151}. Я хотел бы продолжить проверку {105, 155}. - person Prem; 01.07.2015
comment
R-дерево является набором алгоритмов: вставка, поиск, удаление и т. д. - person Has QUIT--Anony-Mousse; 01.07.2015
comment
@Anony-Mousse Следуя этой логике, std::vector также представляет собой набор алгоритмов: вставка, удаление и т. д. Я почти уверен, что можно написать алгоритмы (например, поиск), которые работают как на R-дереве, так и на std::vector (например, с помощью итераторы). Таким образом, в этом контексте я бы назвал R-дерево структурой данных, а не алгоритмами. На самом деле любой контейнер должен предлагать какой-то способ вставки/удаления элементов, и это не делает его алгоритмом. Тем не менее, я не профессионал, и я всегда рад, когда меня поправят, когда я говорю глупости ;) - person 463035818_is_not_a_number; 02.07.2015
comment
да, это тоже алгоритмы. Вставка в вектор обычно выполняется за O(n) или O(1), в зависимости от алгоритма. Также довольно легко сделать худший алгоритм вставки. - person Has QUIT--Anony-Mousse; 02.07.2015