(如何)在 boost 几何中创建自己的多边形类型并使用 multi_polygon 类型?
Posted
技术标签:
【中文标题】(如何)在 boost 几何中创建自己的多边形类型并使用 multi_polygon 类型?【英文标题】:(How to) Create own polygon type in boost geometry and use multi_polygon type with it? 【发布时间】:2019-08-08 11:43:55 【问题描述】:我目前正在尝试使用一些扩展 boost::geometry 多边形 附加信息。但是编译器会启动
#include <boost/geometry.hpp>
namespace bg = boost::geometry;
using point_t = bg::model::d2::point_xy<double>;
using polygon_t = bg::model::polygon<point_t>;
using mpolygon_t = bg::model::multi_polygon<polygon_t>;
using taggedPolygon_t = std::tuple<polygon_t, void*>;
using multiTaggedPolygon_t = bg::model::multi_polygon<taggedPolygon_t>;
void foo()
mpolygon_t poly; // OK
taggedPolygon_t taggedPoly; // OK
mpolygon_t mpoly; // OK
multiTaggedPolygon_t poly; // Compile error
有人提示如何正确处理这些东西吗? 我的目的是存储一些附加信息并将其附加到多边形以供以后使用。
我也尝试使用继承而不是 std::tuple:
struct taggedPolygon_t : bg::model::polygon<point_t>
void* tag;
;
namespace boost namespace geometry namespace traits
template<> struct tag<taggedPolygon_t> typedef polygon_tag type; ;
template<> struct ring_const_type<taggedPolygon_t> typedef const taggedPolygon_t& type; ;
template<> struct ring_mutable_type<taggedPolygon_t> typedef taggedPolygon_t& type; ;
template<> struct interior_const_type<taggedPolygon_t> typedef const taggedPolygon_t type; ;
template<> struct interior_mutable_type<taggedPolygon_t> typedef taggedPolygon_t type; ;
template<> struct exterior_ring<taggedPolygon_t> typedef const taggedPolygon_t type; ;
template<> struct interior_rings<taggedPolygon_t> typedef const taggedPolygon_t type; ;
// namespace boost::geometry::traits
但问题依然存在。
【问题讨论】:
当您尝试修复此问题时,编译错误非常方便(~~大~~)。 什么是“问题”?你可以包括例如编译器输出的前几行? 我知道该怎么做:我必须为我的班级提供特质专业化。做到了...并且有效。但是非常感谢您抽出宝贵的时间! 【参考方案1】:taggedPolygon_t taggedPoly; // OK
显然没问题。它只是声明一个元组对象。元组对模板参数没有任何限制。
multiTaggedPolygon_t poly; // Compile error
这不行,因为它定义了一个 multi_polugon 实例。该类型确实对模板参数类型提出了概念要求:它必须建模the Polygon concept。
元组不满足这些要求。
定义
多边形概念定义如下:
必须有traits::tag
的特化,将 polygon_tag
定义为类型
必须有一个专门化的traits::ring_type
,将其外环和内环的类型定义为类型
这种由 ring_type 定义的类型必须满足环概念
必须有一个专门化的traits::interior_type
,将其内环集合的类型定义为类型;此集合本身必须满足 Boost.Range
随机访问范围概念
必须有 traits::exterior_ring
的特化,其中有两个名为 get,
的函数返回外环,一个是 const,另一个是非 const
必须有一个 traits::interior_rings
的特化,其中有两个名为 get,
的函数返回内部环,一个是 const,另一个是非 const
所以让我们在这里快速而肮脏:
请注意,这些文档似乎与 w.r.t 有点不同步。可变/常量的区别。
namespace boost::geometry::traits
template <typename Underlying, typename Tag>
struct ring_mutable_type<taggedGeometry<Underlying, Tag> > : ring_mutable_type<Underlying> ;
template <typename Underlying, typename Tag>
struct ring_const_type<taggedGeometry<Underlying, Tag> > : ring_const_type<Underlying> ;
template <typename Underlying, typename Tag>
struct interior_mutable_type<taggedGeometry<Underlying, Tag> > : interior_mutable_type<Underlying> ;
template <typename Underlying, typename Tag>
struct interior_const_type<taggedGeometry<Underlying, Tag> > : interior_const_type<Underlying> ;
template <typename Underlying, typename Tag>
struct tag<taggedGeometry<Underlying, Tag> > : tag<Underlying> ;
template <typename Underlying, typename Tag>
struct exterior_ring<taggedGeometry<Underlying, Tag> > : exterior_ring<Underlying> ;
template <typename Underlying, typename Tag>
struct interior_rings<taggedGeometry<Underlying, Tag> > : interior_rings<Underlying> ;
现在你可以编译你的声明了。
Live On Coliru
mpolygon_t mpoly; // OK
multiTaggedPolygon_t poly; // OK
static_assert(std::is_same_v<bg::ring_type<mpolygon_t>::type, bg::ring_type<multiTaggedPolygon_t>::type>, "");
注意我说的是“又快又脏”。因为这还不够。
更多...
注意,我默默地从 std::tuple<>
更改为自定义结构
方便。如果没有,您必须使用元组 getter 委托:
template <typename Underlying, typename Tag>
struct exterior_ring<taggedGeometry<Underlying, Tag> > : exterior_ring<Underlying>
using G = taggedGeometry<Underlying, Tag>;
using base = exterior_ring<Underlying>;
static decltype(auto) get(G& v) return base::get(std::get<0>(v));
static decltype(auto) get(G const& v) return base::get(std::get<0>(v));
;
template <typename Underlying, typename Tag>
struct interior_rings<taggedGeometry<Underlying, Tag> > : interior_rings<Underlying>
using G = taggedGeometry<Underlying, Tag>;
using base = interior_rings<Underlying>;
static decltype(auto) get(G& v) return base::get(std::get<0>(v));
static decltype(auto) get(G const& v) return base::get(std::get<0>(v));
;
这也可以:Live On Coliru
演示
现在你可以实际使用它了:
Live On Coliru
int main()
multiTaggedPolygon_t poly;
bg::read_wkt("MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), "
"((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),"
"(30 20, 20 15, 20 25, 30 20)))", poly);
std::string reason;
if (!bg::is_valid(poly, reason))
std::cout << "Correcting data: " << reason << "\n";
bg::correct(poly);
std::cout << bg::wkt(poly) << " has an area of " << bg::area(poly) << "\n";
打印:
Correcting data: Geometry has wrong orientation
MULTIPOLYGON(((40 40,45 30,20 45,40 40)),((20 35,45 20,30 5,10 10,10 30,20 35),(30 20,20 25,20 15,30 20))) has an area of 712.5
注意事项
请注意,变异/生成算法不“支持”标记多边形。
例如,如果您将两个多边形相交,则结果将是使用库定义的通用方法新构建和构建的多边形,这意味着您“丢失”了标记信息。
上市
留给后代Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <iostream>
namespace bg = boost::geometry;
using point_t = bg::model::d2::point_xy<double>;
using polygon_t = bg::model::polygon<point_t>;
using mpolygon_t = bg::model::multi_polygon<polygon_t>;
template <typename Geo, typename Tag = void*>
using taggedGeometry = std::tuple<Geo, Tag>;
/*
template <typename Geo, typename Tag = void*>
struct taggedGeometry : Geo
using Geo::Geo;
Tag _tag_data;
;
*/
namespace boost::geometry::traits
template <typename Underlying, typename Tag>
struct ring_mutable_type<taggedGeometry<Underlying, Tag> > : ring_mutable_type<Underlying> ;
template <typename Underlying, typename Tag>
struct ring_const_type<taggedGeometry<Underlying, Tag> > : ring_const_type<Underlying> ;
template <typename Underlying, typename Tag>
struct interior_mutable_type<taggedGeometry<Underlying, Tag> > : interior_mutable_type<Underlying> ;
template <typename Underlying, typename Tag>
struct interior_const_type<taggedGeometry<Underlying, Tag> > : interior_const_type<Underlying> ;
template <typename Underlying, typename Tag>
struct tag<taggedGeometry<Underlying, Tag> > : tag<Underlying> ;
template <typename Underlying, typename Tag>
struct exterior_ring<taggedGeometry<Underlying, Tag> > : exterior_ring<Underlying>
using G = taggedGeometry<Underlying, Tag>;
using base = exterior_ring<Underlying>;
static decltype(auto) get(G& v) return base::get(std::get<0>(v));
static decltype(auto) get(G const& v) return base::get(std::get<0>(v));
;
template <typename Underlying, typename Tag>
struct interior_rings<taggedGeometry<Underlying, Tag> > : interior_rings<Underlying>
using G = taggedGeometry<Underlying, Tag>;
using base = interior_rings<Underlying>;
static decltype(auto) get(G& v) return base::get(std::get<0>(v));
static decltype(auto) get(G const& v) return base::get(std::get<0>(v));
;
using taggedPolygon_t = taggedGeometry<polygon_t>;
using multiTaggedPolygon_t = bg::model::multi_polygon<taggedPolygon_t>;
int main()
multiTaggedPolygon_t poly;
bg::read_wkt("MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), "
"((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),"
"(30 20, 20 15, 20 25, 30 20)))", poly);
std::string reason;
if (!bg::is_valid(poly, reason))
std::cout << "Correcting data: " << reason << "\n";
bg::correct(poly);
std::cout << bg::wkt(poly) << " has an area of " << bg::area(poly) << "\n";
【讨论】:
哇...你的答案很可能是最好的答案!谢谢!我仍然想知道什么有利于w.r.t。性能:继承还是元组? 我想说优化构建没有区别,除非您在某处错误地使用运行时多态性(例如,添加虚拟方法)。 godbolt.org 或 quick-bench.com 这样的工具可以提供帮助【参考方案2】:我发现了如何通过继承来做到这一点(第二个代码 sn-p):
struct taggedPolygon_t : bg::model::polygon<point_t>
void* tag;
;
namespace boost namespace geometry namespace traits
template<> struct tag<taggedPolygon_t> typedef polygon_tag type; ;
template<> struct ring_const_type<taggedPolygon_t> typedef const bg::model::polygon<point_t>::ring_type& type; ;
template<> struct ring_mutable_type<taggedPolygon_t> typedef bg::model::polygon<point_t>::ring_type& type; ;
template<> struct interior_const_type<taggedPolygon_t> typedef const bg::model::polygon<point_t>::inner_container_type& type; ;
template<> struct interior_mutable_type<taggedPolygon_t> typedef bg::model::polygon<point_t>::inner_container_type& type; ;
template<> struct exterior_ring<taggedPolygon_t>
static bg::model::polygon<point_t>::ring_type& get(bg::model::polygon<point_t>& p) return p.outer();
static bg::model::polygon<point_t>::ring_type const& get(bg::model::polygon<point_t> const& p) return p.outer();
;
template<> struct interior_rings<taggedPolygon_t>
static bg::model::polygon<point_t>::inner_container_type& get(bg::model::polygon<point_t>& p) return p.inners();
static bg::model::polygon<point_t>::inner_container_type const& get(bg::model::polygon<point_t> const& p) return p.inners();
;
// namespace boost::geometry::traits
【讨论】:
以上是关于(如何)在 boost 几何中创建自己的多边形类型并使用 multi_polygon 类型?的主要内容,如果未能解决你的问题,请参考以下文章