bgschiller
bgschiller

Reputation: 2127

boost::variant geometry algorithms assertion fails

I'd like to have a std::vector of the geometries of geographic areas. Some of these areas are contiguous, and are represented by polygons. Some areas are discontiguous and are represented by multipolygons. My plan is to use a std::vector<boost::variant<polygon,multipolygon>> to take care of this discrepancy.

Both polygon and multipolygon fulfill the Geometry concept, so we should be able to call envelope on either one. That works, but I can't seem to call envelope on a 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;
}

If I uncomment the line bg::envelope(county,bb);, compilation will fail the following error:

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.

I don't think this is related to implicit instantiation of undefined template: Boost Bug or Clang Bug? , because I'm using boost version 1.55.0.

The if statement after the commented line is workable, but it seems like a hack. Is there a way to get it to work without resorting to enumerating the different types in the variant?

Upvotes: 2

Views: 1143

Answers (1)

sehe
sehe

Reputation: 393064

You can make a polymorphic function that dispatches on the variant using a boost::static_visitor:

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


generic_envelope(county,bb);

Where envelope_ is defined as:

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

See it Live On Coliru

Full Program

for future reference:

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

Upvotes: 5

Related Questions