【问题标题】:How to calculate the convex hull with boost from arrays instead of setting each point separately?如何从数组中计算凸包而不是单独设置每个点?
【发布时间】:2016-02-05 00:19:00
【问题描述】:

我是 boost 和“重”模板的新手。从现在开始我就一直在玩,并试图将数组传递给惊人的 boost::geometry::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,而不是通过浮点数迭代并读出坐标浮动(因此,目标是:摆脱 bg::get(*it ))。

结果也应该有 [ x1, y1, x2, y2 ...]

我有一种感觉,这种提升并没有提供我想要的功能。那么,我摆脱循环的想法有问题吗?如何编写一个可以被 bg::convex_hull 函数使用的智能访问类?

【问题讨论】:

标签: c++ templates boost convex-hull boost-geometry


【解决方案1】:

除了the other answer 中显示的polygon&lt;&gt; 模型的机制之外,您也许可以将polygon&lt;&gt; 替换为ring&lt;&gt; 模型,因为似乎不涉及内环?

这样,您可以直接初始化到您的环中:

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());

演示

Live On Coliru

#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,

【讨论】:

  • 感谢您的努力,但这不是我们想要的解决方案。我澄清了这个问题。目标是为输入和输出提供一个平面 c 样式的浮点数组。数据的打印应该是这样的: for( int i = 0; i
  • 浮动是什么意思?
  • 交替的 x 和 y 坐标,如 OP 中所述。
  • @user3054986 我刚刚重新阅读了这个问题,那是/显然/不存在:)
【解决方案2】:

好吧,第三次是魅力吧

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());
}

看Live On Coliru

打印

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 

【讨论】:

【解决方案3】:

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,而不是遍历并读取浮动坐标(使用 bg::get(*它))。

可以传递初始向量元素的地址:

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

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

演示

注意事项确保您的多边形有效,满足convex_hull 算法的先决条件! correct 在这里做了必要的修复:

Live On Coliru

#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,

【讨论】:

    猜你喜欢
    • 2011-06-21
    • 2017-05-01
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    相关资源
    最近更新 更多