diff --git a/src/GraphMLWriter.hpp b/src/GraphMLWriter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..eea1c1c83063ce01b9a6b1717751ea424fe27152 --- /dev/null +++ b/src/GraphMLWriter.hpp @@ -0,0 +1,643 @@ +#ifndef GRAPHML_WRITER_HPP +#define GRAPHML_WRITER_HPP + +#include "map_graph.hpp" +#include <iostream> +#include <boost/fusion/include/mpl.hpp> +#include <boost/fusion/include/for_each.hpp> +#include <fstream> + +/*! \brief this class is a functor for "for_each" algorithm + * + * This class is a functor for "for_each" algorithm. For each + * element of the boost::vector the operator() is called. + * Is mainly used to create a string containing all the vertex + * properties + * + */ + +template<typename G> +struct vertex_prop +{ + // Properties counter + int cnt = 0; + + // vertex properties + std::string & v_prop; + + // Attribute names + std::string * attributes_names; + + // Number of attributes name defined into the vertex + int n_attr = 0; + + /*! \brief Constructor + * + * Create a vertex properties list + * + * \param v_prop std::string that is filled with the graph properties in the GraphML format + * \param stub SFINAE, it basically check if G has properties names defined, if yes this + * constructor is selected over the other one + * + */ + vertex_prop(std::string & v_prop, typename G::V_type::attributes & a_name) + :v_prop(v_prop),attributes_names(a_name.name) + { + // Calculate the number of attributes name + n_attr = sizeof(a_name.name)/sizeof(std::string); + }; + + /*! \brief Constructor + * + * Create a vertex properties list + * + * \param v_prop std::string that is filled with the graph properties in the GraphML format + * \param n_prop number of properties + * + */ + vertex_prop(std::string & v_prop) + :v_prop(v_prop),attributes_names(NULL) + { + }; + + //! It call the functor for each member + template<typename T> + void operator()(T& t) + { + //! Create an entry for the attribute + if (cnt < n_attr) + { + // if it is a yFile extension property name, does not process it + if (attributes_names[t] == "x" || attributes_names[t] == "y" + || attributes_names[t] == "z" || attributes_names[t] == "shape" ) + {cnt++; return ;} + + // Create a property string based on the type of the property + if (typeid(T) == typeid(float)) + v_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"float\"/>"; + else if (typeid(T) == typeid(double)) + v_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"double\"/>"; + else if (typeid(T) == typeid(int)) + v_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"int\"/>"; + else if (typeid(T) == typeid(long int)) + v_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"long\"/>"; + else if (typeid(T) == typeid(bool)) + v_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"boolean\"/>"; + else if (typeid(T) == typeid(std::string)) + v_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"string\"/>"; + } + + cnt++; + } +}; + +/*! \brief this class is a functor for "for_each" algorithm + * + * This class is a functor for "for_each" algorithm. For each + * element of the boost::vector the operator() is called. + * Is mainly used to create a string containing all the vertex + * properties + * + */ + +template<typename G> +struct vertex_node +{ + // Vertex object container + const typename G::V_container & vo; + + // Properties counter + int cnt = 0; + + // vertex counter + size_t v_c = 0; + + // vertex node string + std::string & v_node; + + // vertex yFile geometry extension + std::string yFile_geometry_ext; + + // vertex yFile shape extension + std::string yFile_shape_ext; + + // Attribute names + std::string * attributes_names; + + // Number of attributes name defined into the vertex + int n_attr = 0; + + /*! \brief Constructor + * + * Create a vertex node + * + * \param v_node std::string that is filled with the graph node definition in the GraphML format + * \param n_obj object container to access its properties for example encapc<...> + * \param stub SFINAE, it basically check if G has properties names defined, if yes this + * constructor is selected over the other one + * + */ + vertex_node(std::string & v_node, const typename G::V_container & n_obj, typename G::V_type::attributes & a_name) + :vo(n_obj),v_node(v_node),attributes_names(a_name.name) + { + // Calculate the number of attributes name + n_attr = sizeof(a_name.name)/sizeof(std::string); + }; + + /*! \brief Constructor + * + * Create a vertex properties list + * + * \param v_prop std::string that is filled with the graph properties in the GraphML format + * \param n_obj object container to access its properties for example encapc<...> + * \param n_prop number of properties + * + */ + vertex_node(std::string & v_node, const typename G::V_container & n_obj) + :vo(n_obj),v_node(v_node),attributes_names(NULL) + { + }; + + /*! \brief Create a new node + * + * Create a new node + * + */ + void new_node() + { + // start a new node + v_node += "<node id=\"n"+ std::to_string(v_c) + "\">"; + + // reset the counter properties + cnt = 0; + + // reset the yFile geometry extension node + yFile_geometry_ext.clear(); + + // reset the yFile shape extension node + yFile_shape_ext.clear(); + } + + /*! \brief Close a node + * + * Close a node + * + */ + void end_node() + { + // close a node + v_node += "</node>"; + } + + //! It call the functor for each member + template<typename T> + void operator()(T& t) + { + //! Create an entry for the attribute + if (T::value < n_attr) + { + // if it is a yFile extension property name process as yFile extension + if (attributes_names[T::value] == "x") + {yFile_geometry_ext += " x=" + std::to_string(vo.template get<T::value>());} + else if (attributes_names[T::value] == "y") + {yFile_geometry_ext += " x=" + std::to_string(vo.template get<T::value>());} + else if (attributes_names[T::value] == "z") + {yFile_geometry_ext += " z=" + std::to_string(vo.template get<T::value>());} + else if (attributes_names[T::value] == "shape" ) + {yFile_shape_ext += " shape=" + std::to_string(vo.template get<T::value>());} + else + { + // Create a property string based on the type of the property + if (typeid(decltype(vo.template get<T::value>())) == typeid(float)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(double)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(int)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(long int)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(bool)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(std::string)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + } + } + + cnt++; + } +}; + +/*! \brief this class is a functor for "for_each" algorithm + * + * This class is a functor for "for_each" algorithm. For each + * element of the boost::vector the operator() is called. + * Is mainly used to create a string containing all the edge + * properties + * + */ + +template<typename G> +struct edge_prop +{ + // Properties counter + int cnt = 0; + + // edge properties + std::string & e_prop; + + // Attribute names + std::string * attributes_names; + + // Number of attributes name defined into the vertex + int n_attr = 0; + + /*! \brief Constructor + * + * Create an edge properties list + * + * \param e_prop std::string that is filled with the graph properties in the GraphML format + * \param stub SFINAE, it basically check if G::E_type has properties names defined, if yes this + * constructor is selected over the other one + * + */ + edge_prop(std::string & e_prop, typename G::E_type::attributes & a_name) + :e_prop(e_prop),attributes_names(a_name.name) + { + // Calculate the number of attributes name + n_attr = sizeof(a_name.name)/sizeof(std::string); + }; + + /*! \brief Constructor + * + * Create an edge properties list + * + * \param e_prop std::string that is filled with the graph properties in the GraphML format + * \param n_prop number of properties + * + */ + edge_prop(std::string & v_prop) + :e_prop(e_prop),attributes_names(NULL) + { + }; + + //! It call the functor for each member + template<typename T> + void operator()(T& t) + { + //! Create an entry for the attribute + if (cnt < n_attr) + { + // if it is a yFile extension property name, does not process it + if (attributes_names[t] == "x" || attributes_names[t] == "y" + || attributes_names[t] == "z" || attributes_names[t] == "shape" ) + {cnt++; return ;} + + // Create a property string based on the type of the property + if (typeid(T) == typeid(float)) + e_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"float\"/>"; + else if (typeid(T) == typeid(double)) + e_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"double\"/>"; + else if (typeid(T) == typeid(int)) + e_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"int\"/>"; + else if (typeid(T) == typeid(long int)) + e_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"long\"/>"; + else if (typeid(T) == typeid(bool)) + e_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"boolean\"/>"; + else if (typeid(T) == typeid(std::string)) + e_prop += "<key id=\"v" + std::to_string(cnt) + "\" for=\"node\" attr.name=" + attributes_names[t] + " attr.type=\"string\"/>"; + } + + cnt++; + } +}; + +/*! \brief this class is a functor for "for_each" algorithm + * + * This class is a functor for "for_each" algorithm. For each + * element of the boost::vector the operator() is called. + * Is mainly used to create a string containing all the edge + * properties + * + */ + +template<typename G> +struct edge_node +{ + // Vertex object container + const typename G::E_container & vo; + + // Properties counter + int cnt = 0; + + // vertex counter + size_t v_c = 0; + + // edge node string + std::string & e_node; + + // edge yFile geometry extension + std::string yFile_geometry_ext; + + // edge yFile shape extension + std::string yFile_shape_ext; + + // Attribute names + std::string * attributes_names; + + // Number of attributes name defined into the vertex + int n_attr = 0; + + /*! \brief Constructor + * + * Create an edge node + * + * \param e_node std::string that is filled with the graph node definition in the GraphML format + * \param n_obj object container to access the object properties for example encapc<...> + * \param stub SFINAE, it basically check if G has properties names defined, if yes this + * constructor is selected over the other one + * + */ + edge_node(std::string & e_node, const typename G::E_container & n_obj, typename G::E_type::attributes & a_name) + :vo(n_obj),e_node(e_node),attributes_names(a_name.name) + { + // Calculate the number of attributes name + n_attr = sizeof(a_name.name)/sizeof(std::string); + }; + + /*! \brief Constructor + * + * Create an edge node + * + * \param e_node std::string that is filled with the graph properties in the GraphML format + * \param n_obj object container to access the object properties for example encapc<...> + * \param n_prop number of properties + * + */ + edge_node(std::string & v_node, const typename G::V_container & n_obj) + :vo(n_obj),e_node(e_node),attributes_names(NULL) + { + }; + + /*! \brief Create a new node + * + * Create a new node + * + */ + void new_node() + { + // start a new node + e_node += "<node id=\"n"+ std::to_string(v_c) + "\">"; + + // reset the counter properties + cnt = 0; + + // reset the yFile geometry extension node + yFile_geometry_ext.clear(); + + // reset the yFile shape extension node + yFile_shape_ext.clear(); + } + + /*! \brief Close a node + * + * Close a node + * + */ + void end_node() + { + // close a node + v_node += "</node>"; + } + + //! It call the functor for each member + template<typename T> + void operator()(T& t) + { + //! Create an entry for the attribute + if (T::value < n_attr) + { + // if it is a yFile extension property name process as yFile extension + if (attributes_names[T::value] == "x") + {yFile_geometry_ext += " x=" + std::to_string(vo.template get<T::value>());} + else if (attributes_names[T::value] == "y") + {yFile_geometry_ext += " x=" + std::to_string(vo.template get<T::value>());} + else if (attributes_names[T::value] == "z") + {yFile_geometry_ext += " z=" + std::to_string(vo.template get<T::value>());} + else if (attributes_names[T::value] == "shape" ) + {yFile_shape_ext += " shape=" + std::to_string(vo.template get<T::value>());} + else + { + // Create a property string based on the type of the property + if (typeid(decltype(vo.template get<T::value>())) == typeid(float)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(double)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(int)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(long int)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(bool)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + else if (typeid(decltype(vo.template get<T::value>())) == typeid(std::string)) + v_node += "<data key=\"key" + std::to_string(cnt) + "\">" + std::to_string(vo.template get<T::value>()) + "</>"; + } + } + + cnt++; + } +}; + +/*! + * + * From a Graphbasic structure it write a GraphML format file + * + */ + +template <typename Graph> +class GraphMLWriter +{ + Graph & g; + + + + /*! \brief It get the vertex properties list + * + * It get the vertex properties list of the vertex defined as a GraphML header + * x y z and shape are reserved properties name for yFile extension, and + * define position and shape of the node + * + * \return a string that define the vertex properties in graphML format + * + */ + + std::string get_vertex_properties_list() + { + //! vertex property output string + std::string v_out("<key id=\"d0\" for=\"node\" yfiles.type=\"nodegraphics\"/>"); + + // create a vertex property functor + vertex_prop<Graph> vp(v_out); + + // Iterate through all the vertex and create the vertex list + boost::mpl::for_each< typename Graph::V_type::type >(vp); + + // return the vertex properties string + return v_out; + } + + /*! \brief It get the edge properties list + * + * It get the edge properties list of the edge defined as a GraphML header + * + * \return a string that define the edge properties in graphML format + * + */ + + std::string get_edge_properties_list() + { + //! edge property output string + std::string v_out; + + // create a vertex property functor + edge_prop<Graph> vp(v_out); + + // Iterate through all the vertex and create the vertex list + boost::mpl::for_each< typename Graph::E_type::type >(vp); + + // return the edge properties string + return v_out; + } + + std::string get_vertex_list() + { + //! vertex node output string + std::string v_out; + + //! Get a vertex iterator + auto it = g.getVertexIterator(); + + // if there is the next element + while (it.isNext()) + { + // create a vertex list functor + vertex_node<Graph> vn(v_out,g.vertex(it.get())); + + // Iterate through all the vertex and create the vertex list + boost::mpl::for_each< typename Graph::V_type::type >(vn); + + // increment the operator + ++it; + } + + // return the vertex list + return v_out; + } + + std::string get_edge_list() + { + //! edge node output string + std::string v_out; + + //! Get an edge iterator + auto it = g.getEdgeIterator(); + + // if there is the next element + while (it.isNext()) + { + // create an edge list functor + edge_node<Graph> en(v_out,g.edge(it)); + + // Iterate through all the vertex and create the vertex list + boost::mpl::for_each< typename Graph::E_type::type >(en); + + // increment the operator + ++it; + } + + // return the edge list + return v_out; + } + +public: + + /*! + * + * GraphMLWriter constructor, it take a graph and write a GraphML format + * + * \param g Graph to write + * + */ + GraphMLWriter(Graph & g) + :g(g) + {} + + /*! \brief It write a GraphML file from a graph + * + * \param file path where to write + * \param name of the graph + * + */ + + bool write(std::string file, std::string graph_name="Graph") + { + // Header for the GraphML + std::string gml_header; + // Vertex list of the GraphML + std::string vertex_list; + // End for the GraphML + std::string gml_header_end; + // Graph header + std::string graph_header; + // Graph header end + std::string graph_header_end; + // Edge list of the GraphML + std::string edge_list; + // vertex properties header + std::string vertex_prop_header; + // edge properties header + std::string edge_prop_header; + + // GraphML header + gml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\ + <graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"\ + xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\ + xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns\ + http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">"; + + // Graph header to define an header + graph_header = "<graph id=" + graph_name + " edgedefault=\"directed\">"; + // Graph header end + graph_header_end = "</graph>"; + + // Vertex properties header + vertex_prop_header = get_vertex_properties_list(); + + // Edge properties header + edge_prop_header = get_edge_properties_list(); + + // Get the node graph list + vertex_list = get_vertex_list(); + + // Get the edge graph list + edge_list = get_edge_list(); + + // Header end + gml_header_end = "</graphml>"; + + // write the file + + std::ofstream ofs(file); + + // Check if the file is open + if (ofs.is_open()) + {std::cerr << "Error cannot creare the graphML file: " + file;} + + ofs << gml_header << graph_header << vertex_prop_header << edge_prop_header << + vertex_list << edge_list << graph_header_end << gml_header_end; + + // Completed succefully + return true; + } +}; + +#endif diff --git a/src/MatLabWriter.hpp b/src/MatLabWriter.hpp index 5db834a60886889d557af8080550546196ed3032..a50d3a1e3c7e676446f6c3137cdb8ce6a7f3f225 100644 --- a/src/MatLabWriter.hpp +++ b/src/MatLabWriter.hpp @@ -13,7 +13,7 @@ */ template<unsigned int dim, typename T> -class TiffWriter +class MatLabWriter { /*! \brief Save grid into tiff files * @@ -21,7 +21,7 @@ class TiffWriter * */ - template<typename grid, typename Mem> int write(grid data, std::string file) + template<typename grid, typename Mem> int operator<<(grid data, std::string file) { // Grid can have several properties we can save only scalar fields // for each properties save one scalar fields