c++boostboost-geometry

How to extend boost geometry union_ strategy to handle own polygon type with additional data?


I've created an application with boost geometry which defines an own polygon type with some additional data called

struct taggedPolygon_t : bg::model::polygon<point_t>
{
    taggedPolygon_t() {}    
    std::string mask_;
};

Which carries some additional information.

What I want to achieve is the boost::geometry::union_ also handles this additional data. In my sample case it would be sufficient if member "mask" is unified like this or similar

resultPoly.mask = poly1.mask + poly2.mask;

I tried to create a sample application - but it's at the limits of Coliru.

I think everyone should get the idea?

#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>;

struct taggedPolygon_t : bg::model::polygon<point_t>
{
    taggedPolygon_t() {}    
    std::string mask_;
};

namespace boost::geometry::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

using multiTaggedPolygon_t = bg::model::multi_polygon<taggedPolygon_t>;

int main() {
    multiTaggedPolygon_t polygons;
    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)))", polygons);

    std::string reason;
    if (!bg::is_valid(polygons, reason)) {
        std::cout << "Correcting data: " << reason << "\n";
        bg::correct(polygons);
    }
    
    multiTaggedPolygon_t separated(std::move(polygons));
    
    multiTaggedPolygon_t newPolygons;
    for (auto& poly : separated)
    {
        // Unify polygons
        bg::union_(polygons, poly, newPolygons);
        std::swap(polygons, newPolygons);
        newPolygons.clear();
    }

    for (auto& p : polygons)
        std::cout << p.mask_ << std::endl;
}

http://coliru.stacked-crooked.com/a/ff15c25e4d672ebd

I thought that the strategies() parameter of the union_ function would be the way to go but I'm stuck as there seems to be no specific documentation for this case?


Solution

  • This is frequently requested, sad thing is due to the concepts there is no way to piggy-back meta data in geometry entities (specifically, points).

    Points are default constructible, and are assigned coordinates using the accessor functions.

    This is important for the generic case: if the output geometry has an entirely different types. Yes, specially for union_ you might expect some input points to be copy-constructed, but alas.

    I've previosly explained this in some more detail here: