Как рассчитать выпуклую оболочку с усилением от массивов вместо того, чтобы устанавливать каждую точку отдельно?

Я новичок в бусте и «тяжелые» шаблоны. Я играл уже несколько дней и пытался передать массивы в удивительный повышение :: геометрия :: convex_hull функция. Без удачи

Я подготовил следующий пример:

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <iostream>

using namespace std;
namespace bg = boost::geometry;

BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)

int main()
{
typedef boost::tuple<float, float> point;
typedef bg::model::polygon<point> polygon;

polygon poly, hull;

// define rectangle, this will become also our convex hull
bg::append( poly, point( 0.0, 0.0 ) );
bg::append( poly, point( 1.0, 0.0 ) );
bg::append( poly, point( 1.0, 1.0 ) );
//    bg::append( poly, point( 2.0, 2.0 ) );
bg::append( poly, point( 1.0, 0.0 ) );

// mid point, which should not be part of the hull
bg::append( poly, point( 0.5, 0.5 ) );

// The above poly would ideally constructed with:
// float myInputData[] = { 0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   2.0, 2.0,   1.0, 0.0  };
// and then used like: bg::convex_hull( myInputData, hull );

bg::convex_hull( poly, hull );

cout << "convex hull is:\n";
vector<boost::tuples::tuple<float, float> >::iterator it;

for( it = hull.outer().begin(); it != hull.outer().end(); ++it )
cout << "(" << bg::get<0>(*it) << "/" << bg::get<1>(*it) << ")\n";
}

Точки, добавленные с помощью bg :: append, должны быть в виде простого c-массива, например:

float mydataArray[ 20 ];

где макет данных имеет вид [x1, y1, x2, y2 …] так что идеальная функция была бы: bg :: append_points (arrayOfAlternating_X_Y_coordinates)

Я также хочу передать результат (оболочку) как указатель массива на OpenGL вместо того, чтобы перебирать и считывать координаты float by float (так, цель: избавиться от bg :: get<0> (* это)).

Результат также должен иметь значение from из [x1, y1, x2, y2 …]

У меня такое ощущение, что буст не дает желаемой функциональности. Итак, что-то не так с моей идеей избавиться от петель? Как бы я написал интеллектуальный класс доступа, который мог бы использоваться функцией bg :: convx_hull?

2

Решение

В дополнение к механике polygon<> модель показана в другой ответ, Вы могли бы заменить polygon<> от ring<> модель, потому что, кажется, не вовлечены внутренние кольца?

Таким образом, вы можете непосредственно инициализировать в ваше кольцо:

typedef bg::model::ring<point> ring;

ring poly {
{ 0.0, 0.0 },
//{ 0.5, 0.5 }, // mid point, which should not be part of the hull
{ 1.0, 0.0 },
{ 1.0, 1.0 },
{ 2.0, 2.0 },
{ 1.0, 0.0 },
};

И вызов API может выглядеть так:

point const* hull_array_ptr = &hull.front();

call_API(hull_array_ptr, hull.size());

DEMO

Жить на Колиру

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <iostream>

using namespace std;
namespace bg = boost::geometry;

BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
typedef boost::tuple<float, float> point;

void dump(point const& p) { cout << get<0>(p) << " " << get<1>(p) << ","; }

void call_API(point const* arr, size_t n) {
cout << "hull (API):";
for_each(arr, arr+n, dump);
cout << "\n";
}

int main()
{
typedef bg::model::ring<point> ring;

ring poly {
{ 0.0, 0.0 },
//{ 0.5, 0.5 }, // mid point, which should not be part of the hull
{ 1.0, 0.0 },
{ 1.0, 1.0 },
{ 2.0, 2.0 },
{ 1.0, 0.0 },
};

cout << "raw:       " << bg::wkt(poly) << "\n";
bg::correct(poly);
cout << "corrected: " << bg::wkt(poly) << "\n";

ring hull;
bg::convex_hull(poly, hull);

cout << "hull:      " << bg::wkt(hull) << "\n";

point const* hull_array_ptr = &hull.front();

call_API(hull_array_ptr, hull.size());
}

Снова распечатки:

raw:       POLYGON((0 0,1 0,1 1,2 2,1 0))
corrected: POLYGON((0 0,1 0,1 1,2 2,1 0,0 0))
hull:      POLYGON((0 0,2 2,1 0,0 0))
hull (API):0 0,2 2,1 0,0 0,
1

Другие решения

Хорошо, третий раз это очарование, верно

OP: Спасибо за ваши усилия, но это не желаемое решение. Я уточнил вопрос. Цель состоит в том, чтобы иметь плоский массив чисел в стиле c для ввода и вывода. Распечатка данных должна работать так:

for( int i = 0; i<size; i++ )
cout << hull[i];

Мне: Что бы значили поплавки?

OP: Чередуя координаты x и y, […]

Если вы делаете необходимые вещи

  • проверка размера / заполнения
  • переопределение выравнивания

Вы можете создать кольцо в виде диапазона перфорированных очков над необработанным float[]:

template<typename T> using compact_point = boost::tuple<T, T>;
template<typename T> using compact_ring  = boost::iterator_range<T*>;

static_assert(sizeof(compact_point<float>)  == 2*sizeof(float), "");
static_assert(alignof(compact_point<float>) >= alignof(float), "");

BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
BOOST_GEOMETRY_REGISTER_RING_TEMPLATED(compact_ring)

using point = compact_point<float>;
using ring  = compact_ring<point>;

НОТА имейте в виду, что это работает только для колец только для чтения

Процедуры преобразования:

template <typename T, size_t N>
compact_ring<compact_point<T> > as_compact_ring(T (&arr)[N]) {
auto f = reinterpret_cast<point*>(+arr);
return { f, f + N/2 };
}

template <typename T>
boost::iterator_range<T const*> as_compact_points(std::vector<compact_point<T> > const& r) {
auto f = reinterpret_cast<T const*>(&r[0]);
return { f, f + r.size()*2 };
}

Теперь вы можете подать заявку:

демонстрация

int main() {
alignas(compact_point<float>) float ringdata[] {
0.0, 0.0, // clockwise rect
0.0, 2.0,
//
1.0, 1.0, // dent...
//
2.0, 2.0,
2.0, 0.0,
0.0, 0.0,
};

ring poly = as_compact_ring(ringdata);

cout << "raw: " << bg::wkt(poly) << "\n";

std::string reason;
if (!bg::is_valid(poly, reason)) {
std::cout << "NOT VALID: " << reason << "\n";
return 255;
}

bg::model::ring<point> hull; // not a range proxy though
bg::convex_hull(poly, hull);

cout << "hull:" << bg::wkt(hull) << "\n";

// force back:
auto view = as_compact_points(hull);
float const* rawhull = &*view.begin();

call_API(rawhull, 2*hull.size());
}

Видеть это Жить на Колиру

Печать

raw: POLYGON((0 0,0 2,1 1,2 2,2 0,0 0))
hull:POLYGON((0 0,0 2,2 2,2 0,0 0))
hull (API):0 0 0 2 2 2 2 0 0 0
1

Q. Точки, добавленные с помощью bg :: append, должны быть в массиве, чтобы идеальная функция была: bg::append_points(arrayOf_X_Y_coordinates)

Вы можете назначить внешнее кольцо многоугольника сразу:

point raw[] = {
{ 0.0, 0.0 },
//{ 0.5, 0.5 }, // mid point, which should not be part of the hull
{ 1.0, 0.0 },
{ 1.0, 1.0 },
// { 2.0, 2.0 },
{ 1.0, 0.0 },
};

// define rectangle, this will become also our convex hull
poly.outer().assign(begin(raw), end(raw));

Q. Я также хочу передать результат (оболочку) как указатель массива на OpenGL вместо того, чтобы перебирать и считывать координаты float by float (с помощью bg :: get<0> (* это)).

Вы можете передать адрес исходного векторного элемента:

point const* hull_array_ptr = &hull.outer().front();

call_API(hull_array_ptr, hull.outer().size());

DEMO

Заметки Убедитесь, что ваш полигон действительный, удовлетворяя предварительному условию для convex_hull алгоритм! correct делает необходимые исправления здесь:

Жить на Колиру

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <iostream>

using namespace std;
namespace bg = boost::geometry;

BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
typedef boost::tuple<float, float> point;

void dump(point const& p) { cout << get<0>(p) << " " << get<1>(p) << ","; }

void call_API(point const* arr, size_t n) {
cout << "hull (API):";
for_each(arr, arr+n, dump);
cout << "\n";
}

int main()
{
typedef bg::model::polygon<point> polygon;

polygon poly, hull;

point raw[] = {
{ 0.0, 0.0 },
//{ 0.5, 0.5 }, // mid point, which should not be part of the hull
{ 1.0, 0.0 },
{ 1.0, 1.0 },
{ 2.0, 2.0 },
{ 1.0, 0.0 },
};

poly.outer().assign(begin(raw), end(raw));
cout << "raw:       " << bg::wkt(poly) << "\n";
bg::correct(poly);
cout << "corrected: " << bg::wkt(poly) << "\n";

bg::convex_hull(poly, hull);

cout << "hull:      " << bg::wkt(hull) << "\n";

point const* hull_array_ptr = &hull.outer().front();

call_API(hull_array_ptr, hull.outer().size());
}

Выход:

raw:       POLYGON((0 0,1 0,1 1,2 2,1 0,0 0))
corrected: POLYGON((0 0,1 0,1 1,2 2,1 0,0 0))
hull:      POLYGON((0 0,2 2,1 0,0 0))
hull (API):0 0,2 2,1 0,0 0,
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector