boost :: variant几何算法断言失败

时间:2014-05-20 18:35:28

标签: c++ boost boost-geometry

我希望拥有std::vector个地理区域的几何图形。其中一些区域是连续的,并由多边形表示。有些区域是不连续的,由多边形表示。我的计划是使用std::vector<boost::variant<polygon,multipolygon>>来解决这种差异。

polygonmultipolygon都符合几何概念,因此我们应该可以在任何一个上调用信封。这样做有效,但我似乎无法在envelope上致电variant<polygon,multipolygon>

#include <vector>

#include <boost/variant.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>

namespace bg = boost::geometry;

typedef bg::model::point<double, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef bg::model::polygon<point, true, true> polygon; //cw, closed polygon
typedef bg::model::multi_polygon<polygon> multipolygon;
typedef boost::variant<polygon,multipolygon> star_polygon;

int main(void){
    polygon staunton_county;
    bg::read_wkt("POLYGON ((-79.091666 38.132142, -79.09711 38.184771,"
        " -79.02301 38.195777, -79.049779 38.121112, -79.091666 38.132142))",
        staunton_county);

    multipolygon dickson_county;
    bg::read_wkt("MULTIPOLYGON (((-87.151995 36.289037, -87.146906 36.293344,"
        " -87.144172 36.292142, -87.142315 36.294607, -87.139332 36.292418,"
        " -87.14237199999999 36.290684, -87.151995 36.289037)),"
        " ((-87.20424199999999 35.959186, -87.53453 35.993074,"
        " -87.56679800000001 36.177857, -87.513533 36.334713,"
        " -87.286501 36.321933, -87.17730299999999 36.314145,"
        " -87.14987600000001 36.176878, -87.182573 36.049726,"
        " -87.20424199999999 35.959186)))",
        dickson_county);

    box bb;
    bg::envelope(staunton_county,bb);
    std::cout << bg::dsv(bb) << std::endl;

    bg::envelope(dickson_county,bb);;
    std::cout << bg::dsv(bb) << std::endl;

    star_polygon county;
    county = staunton_county;
    //bg::envelope(county,bb);

    if (county.type() == typeid(polygon)){
        bg::envelope(boost::get<polygon>(county),bb);
    } else {
        bg::envelope(boost::get<multipolygon>(county),bb);
    }

    std::cout << bg::dsv(bb) << std::endl;

    return 0;
}

如果我取消注释行bg::envelope(county,bb);,编译将失败以下错误:

In file included from variant_envelope.cpp:4:
In file included from /usr/local/include/boost/geometry.hpp:17:
In file included from /usr/local/include/boost/geometry/geometry.hpp:35:
In file included from /usr/local/include/boost/geometry/strategies/strategies.hpp:25:
In file included from /usr/local/include/boost/geometry/strategies/intersection.hpp:22:
In file included from /usr/local/include/boost/geometry/strategies/cartesian/cart_intersect.hpp:21:
In file included from /usr/local/include/boost/geometry/algorithms/detail/assign_values.hpp:29:
In file included from /usr/local/include/boost/geometry/algorithms/append.hpp:24:
In file included from /usr/local/include/boost/geometry/geometries/concepts/check.hpp:33:
/usr/local/include/boost/geometry/algorithms/not_implemented.hpp:64:5: error:
      no matching function for call to 'assertion_failed'
    BOOST_MPL_ASSERT_MSG
    ^~~~~~~~~~~~~~~~~~~~
/usr/local/include/boost/mpl/assert.hpp:434:48: note: expanded from macro
      'BOOST_MPL_ASSERT_MSG'
#define BOOST_MPL_ASSERT_MSG( c, msg, types_ ) \
                                               ^
/usr/local/include/boost/mpl/assert.hpp:428:9: note: expanded from macro '\
BOOST_MPL_ASSERT_MSG_IMPL'
  ...boost::mpl::assertion_failed<(c)>( BOOST_PP_CAT(mpl_assert_arg,counter)::assert_arg() ) \
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/boost/mpl/assert.hpp:59:58: note: expanded from macro '\
BOOST_MPL_AUX_ASSERT_CONSTANT'
#   define BOOST_MPL_AUX_ASSERT_CONSTANT(T, expr) enum { expr }
                                                         ^
/usr/local/include/boost/geometry/algorithms/not_implemented.hpp:105:7: note:
      in instantiation of template class
      'boost::geometry::nyi::not_implemented_error<void, void, void>' requested
      here
      nyi::not_implemented_error
      ^
/usr/local/include/boost/geometry/algorithms/envelope.hpp:90:18: note: in
      instantiation of template class 'boost::geometry::not_implemented<void,
      void, void>' requested here
struct envelope: not_implemented<Tag>
                 ^
/usr/local/include/boost/geometry/algorithms/envelope.hpp:163:15: note: in
      instantiation of template class
      'boost::geometry::dispatch::envelope<boost::variant<boost::geometry::model::polygon<boost::geometry::model::point<double,
      2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
      std::allocator, std::allocator>,
      boost::geometry::model::multi_polygon<boost::geometry::model::polygon<boost::geometry::model::point<double,
      2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
      std::allocator, std::allocator>, std::vector, std::allocator>,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_>, void>'
      requested here
    dispatch::envelope<Geometry>::apply(geometry, mbr);
              ^
variant_envelope.cpp:44:13: note: in instantiation of function template
      specialization
      'boost::geometry::envelope<boost::variant<boost::geometry::model::polygon<boost::geometry::model::point<double,
      2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
      std::allocator, std::allocator>,
      boost::geometry::model::multi_polygon<boost::geometry::model::polygon<boost::geometry::model::point<double,
      2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
      std::allocator, std::allocator>, std::vector, std::allocator>,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_,
      boost::detail::variant::void_, boost::detail::variant::void_>,
      boost::geometry::model::box<boost::geometry::model::point<double, 2,
      boost::geometry::cs::cartesian> > >' requested here
        bg::envelope(county,bb);
            ^
/usr/local/include/boost/mpl/assert.hpp:82:5: note: candidate function
      [with C = false] not viable: no known conversion from 'boost::mpl::failed
      ************(boost::geometry::nyi::not_implemented_error<void, void,
      void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED::************)(types<void,
      void, void>)' to 'typename assert<false>::type'
      (aka 'mpl_::assert<false>') for 1st argument
int assertion_failed( typename assert<C>::type );
    ^
1 error generated.

我不认为这与implicit instantiation of undefined template: Boost Bug or Clang Bug?有关,因为我使用的是升级版1.55.0。

注释行之后的if语句是可行的,但它似乎是一个黑客。有没有办法让它工作而不需要枚举变量中的不同类型?

1 个答案:

答案 0 :(得分:5)

您可以使用boost::static_visitor创建一个用于调度变体的多态函数:

static const envelope_ generic_envelope { };
// ...


generic_envelope(county,bb);

envelope_定义为:

struct envelope_ : boost::static_visitor<void> {
    template <typename... T> //dispatch
    void operator()(boost::variant<T...> const& v, box& bb) const {
        boost::apply_visitor(boost::bind(*this, ::_1, boost::ref(bb)), v);
    }

    template <typename T> // relay
    void operator()(T const& v, box& bb) const {
        bg::envelope(v, bb);
    }
};

查看 Live On Coliru

完整计划

供将来参考:

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>

#include <boost/variant.hpp>
#include <boost/bind.hpp>

namespace bg = boost::geometry;

typedef bg::model::point<double, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef bg::model::polygon<point, true, true> polygon; //cw, closed polygon
typedef bg::model::multi_polygon<polygon> multipolygon;
typedef boost::variant<polygon,multipolygon> star_polygon;

struct envelope_ : boost::static_visitor<void>
{
    template <typename... T> //dispatch
    void operator()(boost::variant<T...> const& v, box& bb) const {
        boost::apply_visitor(boost::bind(*this, ::_1, boost::ref(bb)), v);
    }

    template <typename T> // relay
    void operator()(T const& v, box& bb) const {
        bg::envelope(v, bb);
    }
};

int main(void){
    static const envelope_ generic_envelope { };

    polygon staunton_county;
    bg::read_wkt("POLYGON ((-79.091666 38.132142, -79.09711 38.184771,"
        " -79.02301 38.195777, -79.049779 38.121112, -79.091666 38.132142))",
        staunton_county);

    multipolygon dickson_county;
    bg::read_wkt("MULTIPOLYGON (((-87.151995 36.289037, -87.146906 36.293344,"
        " -87.144172 36.292142, -87.142315 36.294607, -87.139332 36.292418,"
        " -87.14237199999999 36.290684, -87.151995 36.289037)),"
        " ((-87.20424199999999 35.959186, -87.53453 35.993074,"
        " -87.56679800000001 36.177857, -87.513533 36.334713,"
        " -87.286501 36.321933, -87.17730299999999 36.314145,"
        " -87.14987600000001 36.176878, -87.182573 36.049726,"
        " -87.20424199999999 35.959186)))",
        dickson_county);

    box bb;
    bg::envelope(staunton_county,bb);
    std::cout << bg::dsv(bb) << std::endl;

    bg::envelope(dickson_county,bb);;
    std::cout << bg::dsv(bb) << std::endl;

    star_polygon county;
    county = staunton_county;
    generic_envelope(county,bb);

    std::cout << bg::dsv(bb) << std::endl;
}