【问题标题】:How to adapt a custom polygon type in boost geometry如何在增强几何中调整自定义多边形类型
【发布时间】:2026-02-04 05:50:01
【问题描述】:

我正在尝试将 boost 几何算法与我自己的自定义多边形类型一起使用。但我收到编译器错误(在 Visual Studio 2019 Windows 10 中)。

我已将我正在尝试做的事情简化为以下代码。

在 my_custom_polygon.hpp 中

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>

using point = boost::geometry::model::d2::point_xy<double>;
using ring = boost::geometry::model::ring<point>;

struct MyPoly
{
    ring exteriorRing;
    std::vector<ring> interiorRings;
};

using polygon = MyPoly;
using multipolygon = std::vector<MyPoly>;
//using polygon = boost::geometry::model::polygon<point>;
//using multipolygon = boost::geometry::model::multi_polygon<polygon>;

namespace boost::geometry::traits
{
    template<> struct tag<MyPoly> { using type = polygon_tag; };
    template<> struct tag<std::vector<MyPoly>> { using type = multi_polygon_tag; };
    template<> struct ring_const_type<MyPoly> { using type = const ring; };
    template<> struct ring_mutable_type<MyPoly> { using type = ring; };
    template<> struct interior_const_type<MyPoly> { using type = const std::vector<ring>; };
    template<> struct interior_mutable_type<MyPoly> { using type = std::vector<ring>; };

    template<> struct exterior_ring<MyPoly>
    {
        static ring& get(MyPoly& poly) { return poly.exteriorRing; }
        static const ring& get(const MyPoly& poly) { return poly.exteriorRing; }
    };

    template<> struct interior_rings<MyPoly>
    {
        static std::vector<ring>& get(MyPoly& poly) { return poly.interiorRings; }
        static const std::vector<ring>& get(const MyPoly& poly) { return poly.interiorRings; }
    };
}

在 my_custom_polygon.cpp 中

int main(int argc, const char** argv)
{
    const double buffer_distance = 1.0;
    const int points_per_circle = 36;
    boost::geometry::strategy::buffer::distance_symmetric<double> distance_strategy(buffer_distance);
    boost::geometry::strategy::buffer::join_round join_strategy(points_per_circle);
    boost::geometry::strategy::buffer::end_round end_strategy(points_per_circle);
    boost::geometry::strategy::buffer::point_circle circle_strategy(points_per_circle);
    boost::geometry::strategy::buffer::side_straight side_strategy;

    multipolygon result;

    point p{0.0, 0.0};

    boost::geometry::buffer(p, result,
            distance_strategy, side_strategy,
            join_strategy, end_strategy, circle_strategy);

    return 0
}

编译失败,在 boost/geometry/algorithms/detail/overlay/convert_ring.hpp 第 70 行出现错误 C2664

它说它不能将参数 2 从 'boost::geometry::model::ring' 转换为 'Geometry2 &'

但是,如果我将 .hpp 文件中注释掉的行用于多边形和多多边形类型,它编译并运行得很好。

我显然没有正确调整多边形。

有人有什么想法吗?

谢谢

【问题讨论】:

    标签: c++ boost geometry


    【解决方案1】:

    首先想到的是阅读标题...哦男孩:我们又来了:)

    折腾了一阵子(稍微清理了一下),发现原因是ring_{mutable,const}_type::type需要作为这个算法的引用。

    这让我觉得我之前所做的调整不是最理想的,并导致不必要的环复制,参见例如Further problems in adapting a geometry object model using boost geometry(How to) Create own polygon type in boost geometry and use multi_polygon type with it?

    那么,废话不多说:

    Live On Coliru

    #include <boost/geometry.hpp>
    #include <boost/geometry/geometries/geometries.hpp>
    #include <iostream>
    
    namespace bg = boost::geometry;
    
    using Point = bg::model::d2::point_xy<double>;
    using Ring  = bg::model::ring<Point>;
    using Rings = std::vector<Ring>;
    
    struct MyPoly {
        Ring  exteriorRing;
        Rings interiorRings;
    };
    
    using MyMultiPoly = std::vector<MyPoly>;
    
    namespace boost::geometry::traits {
        template <> struct tag<MyPoly>                   { using type = polygon_tag;  };
        template <> struct ring_mutable_type<MyPoly>     { using type = Ring&;        };
        template <> struct ring_const_type<MyPoly>       { using type = const Ring&;  };
        template <> struct interior_mutable_type<MyPoly> { using type = Rings;        };
        template <> struct interior_const_type<MyPoly>   { using type = const Rings;  };
    
        template<> struct exterior_ring<MyPoly> {
            static auto& get(MyPoly& poly)       { return poly.exteriorRing; } 
            static auto& get(const MyPoly& poly) { return poly.exteriorRing; } 
        };
    
        template<> struct interior_rings<MyPoly> {
            static auto& get(MyPoly& poly)       { return poly.interiorRings; } 
            static auto& get(const MyPoly& poly) { return poly.interiorRings; } 
        };
    } // namespace boost::geometry::traits
    
    namespace boost::geometry::traits {
        template <> struct tag<MyMultiPoly> { using type = multi_polygon_tag; };
    } // namespace boost::geometry::traits
    
    int main() {
        MyMultiPoly result;
        Point p{0.0, 0.0};
    
        namespace bs = bg::strategy::buffer;
        const double buffer_distance   = 1.0;
        const int    points_per_circle = 36;
    
        bs::distance_symmetric<double> distance(buffer_distance);
        bs::join_round                 join(points_per_circle);
        bs::end_round                  end(points_per_circle);
        bs::point_circle               circle(points_per_circle);
        bs::side_straight              side;
    
        bg::buffer(p, result, distance, side, join, end, circle);
    
        std::cout << "result: " << bg::wkt(result) << "\n";
    }
    

    打印

    result: MULTIPOLYGON(((1 0,0.984808 -0.173648,0.939693 -0.34202,0.866025 -0.5,0.766044 -0.642788,0.642788 -0.766044,0.5 -0.866025,0.34202 -0.939693,0.173648 -0.984808,6.12323e-17 -1,-0.173648 -0.984808,-0.34202 -0.939693,-0.5 -0.866025,-0.642788 -0.766044,-0.766044 -0.642788,-0.866025 -0.5,-0.939693 -0.34202,-0.984808 -0.173648,-1 -1.45473e-15,-0.984808 0.173648,-0.939693 0.34202,-0.866025 0.5,-0.766044 0.642788,-0.642788 0.766044,-0.5 0.866025,-0.34202 0.939693,-0.173648 0.984808,-2.84823e-15 1,0.173648 0.984808,0.34202 0.939693,0.5 0.866025,0.642788 0.766044,0.766044 0.642788,0.866025 0.5,0.939693 0.34202,0.984808 0.173648,1 0)))

    【讨论】:

    • 哇!非常感谢。我不知道为什么这在 boost 文档中一点也不明显,但我很高兴你能弄明白。我搜索和搜索,在互联网上我能找到的信息很少。希望这篇文章的可搜索性足以让遇到此问题的其他人能够找到它。
    • 他们实际上无法让它非常明显。有人可能想要调整一种不为这些访问器返回引用类型的类型。也许您会返回某种代理类型。一些算法不需要参考语义(由较旧的答案证明)。缓冲区算法内部实际上可能存在“实现质量问题”,它需要左值引用,而不是接受潜在的引用代理。但这就是高度通用的库的方式。