(如何)在 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&lt;&gt; 更改为自定义结构 方便。如果没有,您必须使用元组 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 类型?的主要内容,如果未能解决你的问题,请参考以下文章

boost几何中的环和多边形有什么区别?

boost 几何是不是支持弯曲几何?

多边形交叉与Boost ::几何严重的性能恶化

如何在 SQL Server 中创建忽略 NULL 值的计算几何列

提高内点的几何多边形距离

从相交的线串计算有界多边形