(如何)在增强几何图形中创建自己的多边形类型,并对其使用multi_polygon类型?

时间:2019-08-08 11:43:55

标签: c++ boost boost-geometry

我目前正在尝试将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

但是问题仍然存在。

2 个答案:

答案 0 :(得分:1)

我发现了如何通过继承来做到这一点(第二代码段):

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

答案 1 :(得分: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的特殊化,将其内部环的集合的类型定义为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<>更改为以下内容的自定义结构 方便。如果没有,则必须使用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";
}