Domanda

According to this related question (Boost Polygon Serialization). I am trying to serialize polygons with Boost. The problem I have now is that I am trying to compile an example using polygons of custom X, Y, points, but the compiler throws this error at compile time:

error: 'class boost::geometry::model::ring<boost::geometry::model::d2::point_xy<double> >' has no member named 'serialize'

Like there is no defined any function to serialize a ring. Since a Ring extends from std::vector, and as stated in the related question, it is not necessary to define a method for its serialization. But the compiler complains.

Here I have a full example about defining polygons, and its serialization:

#include <fstream>

#include <boost/serialization/vector.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/tracking.hpp>

#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/ring.hpp>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>

typedef boost::geometry::model::d2::point_xy< double > point;
typedef boost::geometry::model::ring< point > ring;
typedef boost::geometry::model::polygon< point > polygon;

namespace boost{
        namespace serialization{

                template<class Archive>
                inline void serialize(Archive & ar, point &point, const unsigned int file_version)
                {
                        std::cout << "Point: Serializing point" << std::endl;
                        ar & boost::serialization::make_nvp("x", point.x());
                        ar & boost::serialization::make_nvp("y", point.y());
                }

                template<class Archive>
                inline void serialize(Archive & ar, polygon &t, const unsigned int file_version)
                {
                        std::cout << "Polygon: Serializing outer ring" << std::endl;
                        ar & boost::serialization::make_nvp("outer", t.outer());

                        std::cout << "Polygon: Serializing inner rings" << std::endl;
                        ar & boost::serialization::make_nvp("inners", t.inners());
                }
        }
}

using namespace boost::geometry;
using namespace boost::archive;
using namespace std;

int main()
{
        polygon poly;
        append(poly, make<point>(0.0, 0.0));
        append(poly, make<point>(5.0, 5.0));
        append(poly, make<point>(5.0, 0.0));
        correct(poly);

        ofstream ofs("polygon.xml");
        xml_oarchive oa(ofs);
        oa << BOOST_SERIALIZATION_NVP(poly);
}

Any idea about how to get this working?

EDIT: Fully functional code about polygon serialization

#include <fstream>
#include <vector>

#include <boost/serialization/vector.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/tracking.hpp>
#include <boost/foreach.hpp>

#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/ring.hpp>

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

typedef boost::geometry::model::d2::point_xy< double > point;
typedef boost::geometry::model::ring< point > ring;
typedef boost::geometry::model::polygon< point > polygon;

namespace boost{
        namespace serialization{

                template<class Archive>
                inline void serialize(Archive & ar, point &point, const unsigned int file_version)
                {
                        std::cout << "Point: Serializing point" << std::endl;
                        ar & const_cast<double &>(point.x());
                        ar & const_cast<double &>(point.y());
                }

                template<class Archive>
                inline void serialize(Archive & ar, ring &ring, const unsigned int file_version)
                {
                        std::cout << "Ring: Serializing ring" << std::endl;
                        ar & static_cast<std::vector<point>& >(ring);
                }

                template<class Archive>
                inline void serialize(Archive & ar, polygon &t, const unsigned int file_version)
                {
                        std::cout << "Polygon: Serializing outer ring" << std::endl;
                        ar & t.outer();

                        std::cout << "Polygon: Serializing inner rings" << std::endl;
                        ar & t.inners();
                }
        }
}

using namespace boost::geometry;
using namespace boost::archive;
using namespace std;

int main()
{
        polygon poly;
        append(poly, make<point>(0.0, 0.0));
        append(poly, make<point>(5.0, 5.0));
        append(poly, make<point>(5.0, 0.0));
        correct(poly);

        BOOST_FOREACH(point& p, poly.outer())
        {
                std::cout << "point " << p.x() << "," << p.y() << std::endl;
        }

        ofstream ofs("polygon.dat");
        binary_oarchive oa(ofs);
        oa << poly;
        ofs.close();

        polygon polyFromFile;
        ifstream ifs("polygon.dat");
        binary_iarchive ia(ifs);
        ia >> polyFromFile;

        BOOST_FOREACH(point& p, polyFromFile.outer())
        {
                std::cout << "point " << p.x() << "," << p.y() << std::endl;
        }
        ifs.close();
}
È stato utile?

Soluzione

Even when partial specialization for serialzation exists for std:vector<T> this does not imply it will work for subclasses, so you have to add a serialization method for ring:

template<class Archive>
inline void serialize(Archive & ar, ring &t, const unsigned int file_version)
{
    // Impl
}

So what's in the implementation? As geometry is not built to be serialized, you cannot access types that would be useful for the serialization (for example, to select the correct default implementation for the container ring inherits), so you can force this somehow. For example, this seems to work:

template<class Archive>
inline void serialize(Archive & ar, ring &t, const unsigned int file_version)
{
     std::cout << "Ring: Serializing a ring" << std::endl;
     serialize(ar, static_cast< std::vector<point>& >(t), file_version);
}

You can also try to write some base class serialization call:

template<class Archive>
inline void serialize(Archive & ar, ring &t, const unsigned int file_version)
{
     std::cout << "Ring: Serializing a ring" << std::endl;
     ar & boost::serialization::make_nvp( "Base",
              boost::serialization::base_object<std::vector<point> >(t));
}

but again, the problem is that you should be able to access that inherited class from within ring. In fact, it is in the definition of ring, as base_type, but it is private to the class. If it was public, you could write the not so bad code using ring::base_type as a parameter for the serialization (instead of the bare std::vector<point> above).

Maybe knowing the inners of the serialization library you can "tie" the serialization machinery so that two calls are not neccessary, specializing some partial specialization for the ring class itself, but I doubt this would be portable.

Altri suggerimenti

As @Diego Sevilla pointed above, the major obstacle is that base_type is declared as private within ring<...>. It is a bit weird as the inheritance is in fact public.

Still, one can slightly generalize his solution by using detailed definition of the geometry::model::ring

namespace boost {
namespace serialization{
    template<class Archive,  //other template params are from model::ring
             typename Point,
             bool ClockWise , bool Closed ,
             template<typename, typename> class Container, //= std::vector,
             template<typename> class Allocator// = std::allocator
             >
    void serialize(Archive & ar,
                   geometry::model::ring<Point, ClockWise, 
                                        Closed, Container, Allocator> & rng,
                   const unsigned int version)
    {
        typedef Container<Point, Allocator<Point> > ring_base_type;
        ring_base_type & contour = rng;
        ar & BOOST_SERIALIZATION_NVP(contour);
    }
} //namespace serialization
} //namespace boost 

It should work correctly for almost any variant of boost::geometry::model::ring.

I use this for boost::geometry to string serialization:

boost::geometry::wkt https://www.boost.org/doc/libs/1_65_0/libs/geometry/doc/html/geometry/reference/io/wkt/wkt.html

and this for unserialization:

boost::geometry::read_wkt https://www.boost.org/doc/libs/1_65_1/libs/geometry/doc/html/geometry/reference/io/wkt/read_wkt.html

works perfect.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top