Reputation: 2127
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
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
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