如何从数组中提升而不是单独设置每个点来计算凸包? [英] How to calculate the convex hull with boost from arrays instead of setting each point separately?

查看:120
本文介绍了如何从数组中提升而不是单独设置每个点来计算凸包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新手,可以提升和沉重"地制作模板.我从现在开始玩过,并试图将数组传递给令人惊叹的

I am new to boost and "heavy" templating. I have played since days now and tried to pass arrays to the amazing boost::geometry::convex_hull function. Without luck.

我准备了以下示例:

#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数组中,例如:

The points appended with bg::append, should be in a siimple c-array like:

float mydataArray[ 20 ];

其中数据布局的格式为[x1,y1,x2,y2 ...] 这样理想的功能应该是:bg :: append_points(arrayOfAlternating_X_Y_coordinates)

where the data layout has the form [ x1, y1, x2, y2... ] so that the ideal function would be: bg::append_points( arrayOfAlternating_X_Y_coordinates )

我也想将结果(hull)作为数组指针传递给OpenGL,而不是遍历并逐个读取float坐标(因此,目标是:摆脱bg :: get< 0>(* it )).

I also wanna pass the result (hull) as an array pointer to OpenGL instead of iterating over and reading out the coordinates float by float ( so, the objective is: getting rid of bg::get<0>(*it)).

结果还应具有[x1,y1,x2,y2 ...]的取值

The result should also have the from of [ x1, y1, x2, y2 ...]

我有种感觉,提升没有提供我想要的功能.那么,我摆脱循环的想法有什么问题吗?我将如何编写可由bg :: convex_hull函数使用的智能访问类?

I have the feeling, that boost doesn't provide my wanted functionality. So, is there something wrong with my idea of getting rid of the loops? How would I write an intelligent access class which could be used by the bg::convex_hull function?

推荐答案

好吧,第三次是魅力,对

Okay, third time is the charm, right

OP::谢谢您的努力,但这不是想要的解决方案.我澄清了这个问题.目的是为输入和输出提供一个平面c样式的浮点数组.打印出的数据应该像这样:

OP: Thanks for you effort, but this is not the wanted solution. I clarified the question. The objective is to have a flat c-style array of floats for input and output. A print out of the data should work like this:

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

:

OP::交替显示x和y坐标,[...]

OP: Alternating x and y coordinates, [...]

如果您做了必要的事情

  • 大小/填充检查
  • 对齐方式替代

您可以在原始float[]上创建一个环,作为一系列类型标记点:

You can create a ring as a range of type-punned points over a raw 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>;

注意,请记住,这仅适用于只读铃声

NOTE keep in mind this only works for readonly rings

转换例程:

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

可以了,您现在可以申请:

There you go, you can now apply:

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

查看 在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 

这篇关于如何从数组中提升而不是单独设置每个点来计算凸包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆