1

I am trying to use boost geometry algorithms with my own custom polygon type. But I getting compiler errors (in Visual Studio 2019 Windows 10).

I have simplified what I am trying to do into the following code.

In 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; }
    };
}

In 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
}

This fails to compile with an error C2664 in boost/geometry/algorithms/detail/overlay/convert_ring.hpp on line 70

It says it cannot convert argument 2 from 'boost::geometry::model::ring<point,true,true,std::vector,std::allocator>' to 'Geometry2 &'

But if I use the commented out lines in the .hpp file for the polygon and multipolygon types it compiles and runs just fine.

I am obviously not adapting the polygon correctly.

Anybody have any ideas?

Thanks

nazame
  • 41
  • 2

1 Answers1

1

First thought reading the title... Oh boy: here we go again :)

Fiddling with it for a while (and cleaning up a little), I found that the cause is that ring_{mutable,const}_type::type needs to be references for this algorithm.

This is making me think that earlier adaptations I made were less-than-optimal and leading to unnecessary ring copying, see e.g. Further problems in adapting a geometry object model using boost geometry and (How to) Create own polygon type in boost geometry and use multi_polygon type with it?

So, without further ado:

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";
}

Prints

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)))

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    Wow! Thank you so much. I don't know why this is not obvious at all from the boost documentation, but I am glad you were able to figure it out. I searched and searched and there was very little information I could find about this on the Internet. Hopefully this post will be searchable enough that others who have this problem will be able to find it. – nazame Apr 22 '21 at 15:33
  • They couldn't actually make it very obvious. One might want to adapt a type that doesn't return a reference type for these accessors. Perhaps you'd return some kind of a proxy type. Some algorithms don't need the reference semantics (proven by the older answers). There might actually be a "quality of implementation issue" inside the buffer algorithm where it requires the lvalue-reference, instead of accepting a potential reference proxy. But this is how it goes with highly generic libraries. – sehe Apr 22 '21 at 15:37