From 57e7ca710e8b786c12801502598149d02b3c996c Mon Sep 17 00:00:00 2001 From: tonynsyde <antonio.leo.polito@gmail.com> Date: Thu, 3 Dec 2015 13:42:27 +0100 Subject: [PATCH] Vector draw in VTKWriter + bug fix --- src/VTKWriter.hpp | 1 + src/VTKWriter_graph.hpp | 909 +++++++++++++++++++++++------------ src/VTKWriter_unit_tests.hpp | 306 +++++++++++- 3 files changed, 890 insertions(+), 326 deletions(-) diff --git a/src/VTKWriter.hpp b/src/VTKWriter.hpp index ae30f6c5..ce2bdacb 100644 --- a/src/VTKWriter.hpp +++ b/src/VTKWriter.hpp @@ -46,6 +46,7 @@ template <typename T> std::string getType() return "unsigned_long"; else if (typeid(T) == typeid(bool)) return "bit"; + return ""; } diff --git a/src/VTKWriter_graph.hpp b/src/VTKWriter_graph.hpp index 061d2aed..a3a61529 100644 --- a/src/VTKWriter_graph.hpp +++ b/src/VTKWriter_graph.hpp @@ -8,6 +8,71 @@ #ifndef VTKWRITER_GRAPH_HPP_ #define VTKWRITER_GRAPH_HPP_ +/*! Property data store for scalar and vector + * + */ +template<bool is_array> +struct vtk_vertex_node_array_scalar_selector +{ + /*! /brief Print the geometric informations in case it is not an array + * + * \tparam T Type of the vertex + * \tparam ele_v Attribute element to check + * \tparam G Graph of reference + * \tparam s_type Vertex spatial type information + * + * \param vo Vertex object container + * \param x Array to store geometric informations + * \param z_set Value set to true id z axis is in use + */ + template<typename T, typename ele_v, typename G, typename s_type> + static inline void move(typename G::V_container &vo, s_type (&x)[3], bool &z_set) + { + if (G::V_type::attributes::name[T::value] == "x") + { + x[0] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>())>::type>::template to<s_type>(vo.template get<T::value>()); + } + else if (G::V_type::attributes::name[T::value] == "y") + { + x[1] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>())>::type>::template to<s_type>(vo.template get<T::value>()); + } + else if (G::V_type::attributes::name[T::value] == "z") + { + x[2] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>())>::type>::template to<s_type>(vo.template get<T::value>()); + z_set = true; + } + } +}; + +/*! Template specialization in the case of array type attribute + * + */ +template<> +struct vtk_vertex_node_array_scalar_selector<true> +{ + /*! \brief Store the geometric informations in case it is an array + * + * \tparam T Type of the vertex + * \tparam ele_v Attribute element to check + * \tparam G Graph of reference + * \tparam s_type Vertex spatial type information + * + * \param vo Vertex object container + * \param x Array to store geometric informations + * \param z_set Value set to true id z axis is in use + */ + template<typename T, typename ele_v, typename G, typename s_type> + static inline void move(typename G::V_container &vo, s_type (&x)[3], bool &z_set) + { + if (std::extent<ele_v>::value == 3) + z_set = true; + + for (size_t i = 0; i < std::extent<ele_v>::value; i++) + x[i] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>()[i])>::type>::template to<s_type>(vo.template get<T::value>()[i]); + + } +}; + /*! \brief this class is a functor for "for_each" algorithm * * This class is a functor for "for_each" algorithm. For each @@ -25,10 +90,10 @@ struct vtk_vertex_node { // Vertex spatial type information typedef typename G::V_type::s_type s_type; - - bool z_set; - - s_type (& x)[3]; + + bool z_set; + + s_type (&x)[3]; // Vertex object container typename G::V_container & vo; @@ -44,26 +109,29 @@ struct vtk_vertex_node * \param n_obj object container to access its properties for example encapc<...> * */ - vtk_vertex_node(std::string & v_node, typename G::V_container & n_obj, s_type (&x)[3]) - :x(x),vo(n_obj),v_node(v_node),z_set(false) + vtk_vertex_node(std::string & v_node, typename G::V_container & n_obj, s_type (&x)[3]) : + x(x), vo(n_obj), v_node(v_node), z_set(false) { - }; + } + ; //! \brief Write collected information void write() { - v_node += std::to_string(x[0]) + " " + std::to_string(x[1]) + " " + std::to_string(x[2]) + "\n"; + v_node += std::to_string(x[0]) + " " + std::to_string(x[1]) + " " + std::to_string(x[2]) + "\n"; } //! It call the functor for each member - template<typename T> - void operator()(T& t) - { - // if the attribute name is x y or z, create a string with the value of the properties and store it - if (G::V_type::attributes::name[T::value] == "x"){x[0] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>())>::type>::template to<s_type>(vo.template get<T::value>());} - else if (G::V_type::attributes::name[T::value] == "y"){x[1] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>())>::type>::template to<s_type>(vo.template get<T::value>());} - else if (G::V_type::attributes::name[T::value] == "z"){x[2] = convert<typename boost::remove_reference<decltype(vo.template get<T::value>())>::type>::template to<s_type>(vo.template get<T::value>());z_set=true;} - } + template<typename T> + void operator()(T& t) + { + typedef typename boost::mpl::at<typename G::V_type::type, boost::mpl::int_<T::value>>::type ele_v; + + // if the attribute name is x y or z, create a string with the value of the properties and store it + + vtk_vertex_node_array_scalar_selector<std::is_array<ele_v>::value>::template move<T, ele_v, G, s_type>(vo, x, z_set); + + } }; /*! \brief this class is a functor for "for_each" algorithm @@ -80,7 +148,7 @@ struct vtk_vertex_node */ template<typename G> -struct vtk_vertex_node<G,false> +struct vtk_vertex_node<G, false> { // Vertex object container typename G::V_container & vo; @@ -96,20 +164,20 @@ struct vtk_vertex_node<G,false> * \param n_obj object container to access its properties for example encapc<...> * */ - vtk_vertex_node(std::string & v_node, typename G::V_container & n_obj) - :vo(n_obj),v_node(v_node) + vtk_vertex_node(std::string & v_node, typename G::V_container & n_obj) : + vo(n_obj), v_node(v_node) { - }; + } + ; //! It call the functor for each member - template<typename T> - void operator()(T& t) - { - v_node += "0 0 0\n"; - } + template<typename T> + void operator()(T& t) + { + v_node += "0 0 0\n"; + } }; - /*! \brief this class is a functor for "for_each" algorithm * * This class is a functor for "for_each" algorithm. For each @@ -137,10 +205,11 @@ struct vtk_edge_node * \param n_prop number of properties * */ - vtk_edge_node(std::string & e_node, typename G::E_container & n_obj) - :vo(n_obj),e_node(e_node) + vtk_edge_node(std::string & e_node, typename G::E_container & n_obj) : + vo(n_obj), e_node(e_node) { - }; + } + ; /*! \brief Create a new node * @@ -154,6 +223,150 @@ struct vtk_edge_node } }; +/*! \brief Property writer for scalar and vector + * + */ +template<bool is_array> +struct prop_output_array_scalar_selector_vertex +{ + /*! \brief Writer in case the property is not an array + * + * \tparam ele_v Property element + * \tparam Graph Graph of reference + * \tparam i Property id + * + * \param v_out Buffer to write into + * \param g Graph + * \param p Property id + */ + template<typename ele_v, typename Graph, unsigned int i> + static inline void write(std::string &v_out, const Graph &g, size_t p) + { + v_out += std::to_string(g.vertex(p).template get<i>()) + "\n"; + } +}; + +/*! \brief Property writer for vector + * + */ +template<> +struct prop_output_array_scalar_selector_vertex<true> +{ + /*! \brief Writer in case the property is an array + * + * \tparam ele_v Property element + * \tparam Graph Graph of reference + * \tparam i Property id + * + * \param v_out Buffer to write into + * \param g Graph + * \param p Property id + */ + template<typename ele_v, typename Graph, unsigned int i> + static inline void write(std::string &v_out, const Graph &g, size_t p) + { + for (size_t j = 0; j < 2; j++) + { + v_out += std::to_string(g.vertex(p).template get<i>()[j]) + " "; + } + + if (std::extent<ele_v>::value == 2) + v_out += "0"; + else + v_out += std::to_string(g.vertex(p).template get<i>()[2]); + + v_out += "\n"; + } +}; + +/*! \brief Property writer for scalar and vector + * + */ +template<bool is_array> +struct prop_output_array_scalar_selector_edge +{ + /*! \brief Writer in case the property is not an array + * + * \tparam ele_v Property element + * \tparam Graph Graph of reference + * \tparam i Property id + * + * \param v_out Buffer to write into + * \param g Graph + * \param p Property id + */ + template<typename ele_v, typename Graph, unsigned int i> + static inline void write(std::string &v_out, const Graph &g, const typename Graph::E_container &edge) + { + v_out += std::to_string(edge.template get<i>()) + "\n"; + } +}; + +/*! \brief Property writer for vector + * + */ +template<> +struct prop_output_array_scalar_selector_edge<true> +{ + /*! \brief Writer in case the property is an array + * + * \tparam ele_v Property element + * \tparam Graph Graph of reference + * \tparam i Property id + * + * \param v_out Buffer to write into + * \param g Graph + * \param p Property id + */ + template<typename ele_v, typename Graph, unsigned int i> + static inline void write(std::string &v_out, const Graph &g, const typename Graph::E_container &edge) + { + for (size_t j = 0; j < 2; j++) + { + v_out += std::to_string(edge.template get<i>()[j]) + " "; + } + + if (std::extent<ele_v>::value == 2) + v_out += "0"; + else + v_out += std::to_string(edge.template get<i>()[2]); + + v_out += "\n"; + } +}; + +/*! \brief Property writer for scalar and vector, it fill the vertex data (needed for edge representation in vtk) + * + */ +template<bool is_array> +struct prop_output_array_scalar_selector_edge_fill_vertex +{ + /*! \brief Writer in case the property is not an array + * + * \param v_out Buffer to write into + */ + static inline void write(std::string &v_out) + { + v_out += "0\n"; + } +}; + +/*! \brief Property writer for vector + * + */ +template<> +struct prop_output_array_scalar_selector_edge_fill_vertex<true> +{ + /*! \brief Writer in case the property is an array + * + * \param v_out Buffer to write into + */ + static inline void write(std::string &v_out) + { + v_out += "0 0 0\n"; + } +}; + /*! \brief This class specialize functions in the case the type T * has or not defined attributes * @@ -190,8 +403,8 @@ public: // if there is the next element while (it.isNext()) { - // Print the property - v_out += std::to_string(g.vertex(it.get()).template get<i>()) + "\n"; + typedef typename boost::mpl::at<typename Graph::V_type::type, boost::mpl::int_<i>>::type ele_v; + prop_output_array_scalar_selector_vertex<std::is_array<ele_v>::value>::template write<ele_v, Graph, i>(v_out, g, it.get()); // increment the iterator and counter ++it; @@ -199,48 +412,47 @@ public: return v_out; } - - /*! \brief For each edge set the value, set 1 on verteces, needed by vtk file format - * - * \tparam i edge property to print - * - */ - - static std::string get_cell_data(const Graph & g) - { - //! vertex node output string - std::string e_out; - - - //! Get a vertex iterator - auto it_v = g.getVertexIterator(); - - // if there is the next element - while (it_v.isNext()) - { - // Print the property - e_out += std::to_string(0) + "\n"; - - // increment the iterator and counter - ++it_v; - } - - - //! Get an edge iterator - auto it_e = g.getEdgeIterator(); - - // if there is the next element - while(it_e.isNext()) - { - // Print the property - e_out += std::to_string(g.edge(it_e.get()).template get<i>()) + "\n"; - - // increment the iterator and counter - ++it_e; - } - - return e_out; - } + + /*! \brief For each edge set the value, set 1 on vertices, needed by vtk file format + * + * \tparam i edge property to print + * + */ + + static std::string get_cell_data(const Graph & g) + { + //! vertex node output string + std::string e_out; + + //! Get a vertex iterator + auto it_v = g.getVertexIterator(); + + // if there is the next element + while (it_v.isNext()) + { + // Print the property + typedef typename boost::mpl::at<typename Graph::E_type::type, boost::mpl::int_<i>>::type ele_v; + prop_output_array_scalar_selector_edge_fill_vertex<std::is_array<ele_v>::value>::write(e_out); + + // increment the iterator and counter + ++it_v; + } + + //! Get an edge iterator + auto it_e = g.getEdgeIterator(); + + // if there is the next element + while (it_e.isNext()) + { + typedef typename boost::mpl::at<typename Graph::E_type::type, boost::mpl::int_<i>>::type ele_v; + prop_output_array_scalar_selector_edge<std::is_array<ele_v>::value>::template write<ele_v, Graph, i>(e_out, g, g.edge(it_e.get())); + + // increment the iterator and counter + ++it_e; + } + + return e_out; + } /*! \brief Given a Graph return the point data header for a typename T * @@ -254,55 +466,95 @@ public: //! vertex node output string std::string v_out; + // Type of the property + std::string type; + + typedef typename boost::mpl::at<typename Graph::V_type::type, boost::mpl::int_<i>>::type T; + // Check if T is a supported format // for now we support only scalar of native type + if (std::is_array<T>::value == true && std::is_array<typename std::remove_extent<T>::type>::value == false) + { + //Get type of the property + type = getType<typename std::remove_all_extents<T>::type>(); - std::string type = getType<typename boost::fusion::result_of::at<typename Graph::V_type::type,boost::mpl::int_<i>>::type>(); + // if the type is not supported return + if (type.size() == 0) + return v_out; - // if the type is not supported return - if (type.size() == 0) - {return v_out;} + // Create point data properties + v_out += "VECTORS " + get_attributes_vertex() + " " + type + "\n"; + } + else + { + type = getType<T>(); - // Create point data properties - v_out += "SCALARS " + get_attributes_vertex() + " " + type + "\n"; + // if the type is not supported return + if (type.size() == 0) + return v_out; - // Default lookup table - v_out += "LOOKUP_TABLE default\n"; + // Create point data properties + v_out += "SCALARS " + get_attributes_vertex() + " " + type + "\n"; + + // Default lookup table + v_out += "LOOKUP_TABLE default\n"; + + } // return the vertex list return v_out; } - - /*! \brief Given a Graph return the cell data header for a typename T - * - * \tparam T type to write - * \param n_node number of the node - * - */ - - static std::string get_cell_property_header(size_t prop) - { - //! edge node output string - std::string e_out; - - // Check if T is a supported format - // for now we support only scalar of native type - - std::string type = getType<typename boost::fusion::result_of::at<typename Graph::E_type::type,boost::mpl::int_<i>>::type>(); - - // if the type is not supported return - if (type.size() == 0) - {return e_out;} - - // Create point data properties - e_out += "SCALARS " + get_attributes_edge() + " " + type + "\n"; - - // Default lookup table - e_out += "LOOKUP_TABLE default\n"; - - // return the vertex list - return e_out; - } + + /*! \brief Given a Graph return the cell data header for a typename T + * + * \tparam T type to write + * \param n_node number of the node + * + */ + + static std::string get_cell_property_header(size_t prop) + { + //! edge node output string + std::string e_out; + + // Type of the property + std::string type; + + typedef typename boost::mpl::at<typename Graph::E_type::type, boost::mpl::int_<i>>::type T; + + // Check if T is a supported format + // for now we support only scalar of native type + if (std::is_array<T>::value == true && std::is_array<typename std::remove_extent<T>::type>::value == false) + { + //Get type of the property + type = getType<typename std::remove_all_extents<T>::type>(); + + // if the type is not supported return + if (type.size() == 0) + return e_out; + + // Create point data properties + e_out += "VECTORS " + get_attributes_edge() + " " + type + "\n"; + } + else + { + type = getType<T>(); + + // if the type is not supported return + if (type.size() == 0) + return e_out; + + // Create point data properties + e_out += "SCALARS " + get_attributes_edge() + " " + type + "\n"; + + // Default lookup table + e_out += "LOOKUP_TABLE default\n"; + + } + + // return the vertex list + return e_out; + } /*! \brief Get the attributes name for vertex * @@ -312,15 +564,15 @@ public: { return Graph::V_type::attributes::name[i]; } - - /*! \brief Get the attributes name for edge - * - */ - - static std::string get_attributes_edge() - { - return Graph::E_type::attributes::name[i]; - } + + /*! \brief Get the attributes name for edge + * + */ + + static std::string get_attributes_edge() + { + return Graph::E_type::attributes::name[i]; + } }; /*! \brief This class specialize functions in the case the type T @@ -337,7 +589,7 @@ public: */ template<typename Graph, unsigned int i> -class prop_output<false,Graph,i> +class prop_output<false, Graph, i> { /*! \brief For each vertex set the value * @@ -365,49 +617,46 @@ class prop_output<false,Graph,i> return v_out; } - - /*! \brief For each edge set the value - * - * \tparam i edge property to print - * - */ - - static std::string get_cell_data(const Graph & g) - { - //! vertex node output string - std::string e_out; - - - //! Get a vertex iterator - auto it_v = g.getVertexIterator(); - - // if there is the next element - while (it_v.isNext()) - { - // Print the property - e_out += std::to_string(0) + "\n"; - - // increment the iterator and counter - ++it_v; - } - - - //! Get an edge iterator - auto it_e = g.getEdgeIterator(); - - // if there is the next element - while(it_e.isNext()) - { - // Print the property - e_out += std::to_string(g.edge(it_e.get()).template get<i>()) + "\n"; - - // increment the iterator and counter - ++it_e; - } - - return e_out; - } + /*! \brief For each edge set the value + * + * \tparam i edge property to print + * + */ + + static std::string get_cell_data(const Graph & g) + { + //! vertex node output string + std::string e_out; + + //! Get a vertex iterator + auto it_v = g.getVertexIterator(); + + // if there is the next element + while (it_v.isNext()) + { + // Print the property + e_out += std::to_string(0) + "\n"; + + // increment the iterator and counter + ++it_v; + } + + //! Get an edge iterator + auto it_e = g.getEdgeIterator(); + + // if there is the next element + while (it_e.isNext()) + { + // Print the property + e_out += std::to_string(g.edge(it_e.get()).template get<i>()) + "\n"; + + // increment the iterator and counter + ++it_e; + } + + return e_out; + } /*! \brief Given a Graph return the point data header for a typename T * @@ -426,11 +675,13 @@ class prop_output<false,Graph,i> // Check if T is a supported format // for now we support only scalar of native type - std::string type = getType<boost::fusion::result_of::at<typename Graph::V_type::type,boost::mpl::int_<i>>>("attr" + std::to_string(prop)); + std::string type = getType<boost::fusion::result_of::at<typename Graph::V_type::type, boost::mpl::int_<i>>>("attr" + std::to_string(prop)); // if the type is not supported return if (type.size() == 0) - {return v_out;} + { + return v_out; + } // Create point data properties v_out += "SCALARS " + get_attributes_vertex() + " " + type + "\n"; @@ -441,55 +692,74 @@ class prop_output<false,Graph,i> // return the vertex list return v_out; } - - /*! \brief Given a Graph return the cell data header for a typename T - * - * \tparam T type to write - * \param n_node number of the node - * - */ - - static std::string get_cell_property_header(size_t prop) - { - //! edge node output string - std::string e_out; - - // Check if T is a supported format - // for now we support only scalar of native type - - std::string type = getType<boost::fusion::result_of::at<typename Graph::E_type::type,boost::mpl::int_<i>>>("attr" + std::to_string(prop)); - - // if the type is not supported return - if (type.size() == 0) - {return e_out;} - - // Create point data properties - e_out += "SCALARS " + get_attributes_edge() + " " + type + "\n"; - - // Default lookup table - e_out += "LOOKUP_TABLE default\n"; - - // return the vertex list - return e_out; - } - - /*! \brief Get the attributes name for vertex - * - */ - - static std::string get_attributes_vertex() - { - return Graph::V_type::attributes::name[i]; - } - - /*! \brief Get the attributes name for edge - * - */ - - static std::string get_attributes_edge() - { - return Graph::E_type::attributes::name[i]; - } + + /*! \brief Given a Graph return the cell data header for a typename T + * + * \param n_node number of the node + * + */ + + static std::string get_cell_property_header(size_t prop) + { + //! edge node output string + std::string e_out; + + // Type of the property + std::string type; + + typedef typename boost::mpl::at<typename Graph::E_type::type, boost::mpl::int_<i>>::type T; + + // Check if T is a supported format + // for now we support only scalar of native type + if (std::is_array<T>::value == true && std::is_array<typename std::remove_extent<T>::type>::value == false) + { + //Get type of the property + type = getType<typename std::remove_all_extents<T>::type>(); + + // if the type is not supported return + if (type.size() == 0) + return e_out; + + // Create point data properties + e_out += "VECTORS " + get_attributes_edge() + " " + type + "\n"; + } + else + { + type = getType<T>(); + + // if the type is not supported return + if (type.size() == 0) + return e_out; + + // Create point data properties + e_out += "SCALARS " + get_attributes_edge() + " " + type + "\n"; + + // Default lookup table + e_out += "LOOKUP_TABLE default\n"; + + } + + // return the vertex list + return e_out; + } + + /*! \brief Get the attributes name for vertex + * + */ + + static std::string get_attributes_vertex() + { + return Graph::V_type::attributes::name[i]; + } + + /*! \brief Get the attributes name for edge + * + */ + + static std::string get_attributes_edge() + { + return Graph::E_type::attributes::name[i]; + } }; /*! \brief this class is a functor for "for_each" algorithm @@ -519,29 +789,31 @@ struct prop_out_vertex * \param v_out string to fill with the vertex properties * */ - prop_out_vertex(std::string & v_out, const Graph & g) - :v_out(v_out),g(g) - {}; + prop_out_vertex(std::string & v_out, const Graph & g) : + v_out(v_out), g(g) + { + } + ; //! It produce an output for each property - template<typename T> - void operator()(T& t) const - { - // actual string size - size_t sz = v_out.size(); + template<typename T> + void operator()(T& t) const + { + // actual string size + size_t sz = v_out.size(); // Produce the point properties header - v_out += prop_output<has_attributes<typename Graph::V_type>::value ,Graph,T::value>::get_point_property_header(t); + v_out += prop_output<has_attributes<typename Graph::V_type>::value, Graph, T::value>::get_point_property_header(t); // If the output has changed, we have to write the properties if (v_out.size() != sz) { - std::string attr = prop_output<has_attributes<typename Graph::V_type>::value,Graph,T::value>::get_attributes_vertex(); + std::string attr = prop_output<has_attributes<typename Graph::V_type>::value, Graph, T::value>::get_attributes_vertex(); // Produce point data - v_out += prop_output<has_attributes<typename Graph::V_type>::value ,Graph ,T::value>::get_point_data(g); + v_out += prop_output<has_attributes<typename Graph::V_type>::value, Graph, T::value>::get_point_data(g); } - } + } }; /*! \brief this class is a functor for "for_each" algorithm @@ -560,42 +832,43 @@ struct prop_out_vertex template<typename Graph> struct prop_out_edge { - // property output string - std::string & e_out; - - // Graph that we are processing - const Graph & g; - - /*! \brief constructor - * - * \param v_out string to fill with the vertex properties - * - */ - prop_out_edge(std::string & e_out, const Graph & g) - :e_out(e_out),g(g) - {}; - - //! It produce an output for each property - template<typename T> - void operator()(T& t) const - { - // actual string size - size_t sz = e_out.size(); - - // Produce the point properties header - e_out += prop_output<has_attributes<typename Graph::E_type>::value ,Graph,T::value>::get_cell_property_header(t); - - // If the output has changed, we have to write the properties - if (e_out.size() != sz) - { - std::string attr = prop_output<has_attributes<typename Graph::E_type>::value,Graph,T::value>::get_attributes_edge(); - - // Produce cell data - e_out += prop_output<has_attributes<typename Graph::E_type>::value ,Graph ,T::value>::get_cell_data(g); - } - } -}; + // property output string + std::string & e_out; + + // Graph that we are processing + const Graph & g; + + /*! \brief constructor + * + * \param v_out string to fill with the vertex properties + * + */ + prop_out_edge(std::string & e_out, const Graph & g) : + e_out(e_out), g(g) + { + } + ; + + //! It produce an output for each property + template<typename T> + void operator()(T& t) const + { + // actual string size + size_t sz = e_out.size(); + + // Produce the point properties header + e_out += prop_output<has_attributes<typename Graph::E_type>::value, Graph, T::value>::get_cell_property_header(t); + + // If the output has changed, we have to write the properties + if (e_out.size() != sz) + { + std::string attr = prop_output<has_attributes<typename Graph::E_type>::value, Graph, T::value>::get_attributes_edge(); + // Produce cell data + e_out += prop_output<has_attributes<typename Graph::E_type>::value, Graph, T::value>::get_cell_data(g); + } + } +}; /*! * @@ -605,8 +878,8 @@ struct prop_out_edge * */ -template <typename Graph> -class VTKWriter<Graph,GRAPH> +template<typename Graph> +class VTKWriter<Graph, GRAPH> { const Graph & g; @@ -664,7 +937,7 @@ class VTKWriter<Graph,GRAPH> std::string e_out; // write the number of lines - e_out += "LINES " + std::to_string(g.getNEdge()) + " " + std::to_string(3*g.getNEdge()) + "\n"; + e_out += "LINES " + std::to_string(g.getNEdge()) + " " + std::to_string(3 * g.getNEdge()) + "\n"; // return the vertex properties string return e_out; @@ -677,10 +950,10 @@ class VTKWriter<Graph,GRAPH> * */ - template <bool attr> std::string get_point_list() + template<bool attr> std::string get_point_list() { //! VTK spatial information - typename Graph::V_type::s_type x[3] = {0,0,0}; + typename Graph::V_type::s_type x[3] = { 0, 0, 0 }; //! vertex node output string std::string v_out; @@ -695,10 +968,10 @@ class VTKWriter<Graph,GRAPH> auto obj = g.vertex(it.get()); // create a vertex list functor - vtk_vertex_node<Graph,attr> vn(v_out,obj,x); + vtk_vertex_node<Graph, attr> vn(v_out, obj, x); // Iterate through all the vertex and create the vertex list - boost::mpl::for_each< boost::mpl::range_c<int,0,Graph::V_type::max_prop-1> >(vn); + boost::mpl::for_each<boost::mpl::range_c<int, 0, Graph::V_type::max_prop - 1> >(vn); // write the node string vn.write(); @@ -724,7 +997,7 @@ class VTKWriter<Graph,GRAPH> std::string v_out; //! For each point create a vertex - for (size_t i = 0 ; i < g.getNVertex() ; i++) + for (size_t i = 0; i < g.getNVertex(); i++) { v_out += "1 " + std::to_string(i) + "\n"; } @@ -747,21 +1020,21 @@ class VTKWriter<Graph,GRAPH> return v_out; } - - /*! \brief Get the point data header - * - * \return a string with the point data header for VTK format - * - */ - - std::string get_cell_data_header() - { - std::string v_out; - - v_out += "CELL_DATA " + std::to_string(g.getNVertex()+g.getNEdge()) + "\n"; - - return v_out; - } + + /*! \brief Get the point data header + * + * \return a string with the point data header for VTK format + * + */ + + std::string get_cell_data_header() + { + std::string v_out; + + v_out += "CELL_DATA " + std::to_string(g.getNVertex() + g.getNEdge()) + "\n"; + + return v_out; + } /*! \brief Return the edge list * @@ -802,9 +1075,10 @@ public: * \param g Graph to write * */ - VTKWriter(const Graph & g) - :g(g) - {} + VTKWriter(const Graph & g) : + g(g) + { + } /*! \brief It write a VTK file from a graph * @@ -816,7 +1090,7 @@ public: * */ - template<int prp = -1> bool write(std::string file, std::string graph_name="Graph", file_type ft = file_type::ASCII) + template<int prp = -1> bool write(std::string file, std::string graph_name = "Graph", file_type ft = file_type::ASCII) { // Check that the Vertex type define x y and z attributes @@ -846,20 +1120,23 @@ public: std::string point_data_header; // Data point std::string point_data; - // Cell data header - std::string cell_data_header; - // Cell data - std::string cell_data; + // Cell data header + std::string cell_data_header; + // Cell data + std::string cell_data; // VTK header - vtk_header = "# vtk DataFile Version 3.0\n" - + graph_name + "\n"; + vtk_header = "# vtk DataFile Version 3.0\n" + graph_name + "\n"; // Choose if binary or ASCII if (ft == file_type::ASCII) - {vtk_header += "ASCII\n";} + { + vtk_header += "ASCII\n"; + } else - {vtk_header += "BINARY\n";} + { + vtk_header += "BINARY\n"; + } // Data type for graph is DATASET POLYDATA vtk_header += "DATASET POLYDATA\n"; @@ -884,37 +1161,38 @@ public: // Get the point data header point_data_header = get_point_data_header(); - - // Get the cell data header - cell_data_header = get_cell_data_header(); - + + // Get the cell data header + cell_data_header = get_cell_data_header(); + // For each property in the vertex type produce a point data prop_out_vertex<Graph> pp(point_data, g); if (prp == -1) - boost::mpl::for_each< boost::mpl::range_c<int,0, Graph::V_type::max_prop> >(pp); + boost::mpl::for_each<boost::mpl::range_c<int, 0, Graph::V_type::max_prop> >(pp); + else + boost::mpl::for_each<boost::mpl::range_c<int, prp, prp> >(pp); + + // For each property in the edge type produce a point data + + prop_out_edge<Graph> ep(cell_data, g); + + if (prp == -1) + boost::mpl::for_each<boost::mpl::range_c<int, 0, Graph::E_type::max_prop> >(ep); else - boost::mpl::for_each< boost::mpl::range_c<int,prp, prp> >(pp); - - // For each property in the edge type produce a point data - - prop_out_edge<Graph> ep(cell_data, g); - - if (prp == -1) - boost::mpl::for_each< boost::mpl::range_c<int,0, Graph::E_type::max_prop> >(ep); - else - boost::mpl::for_each< boost::mpl::range_c<int,prp, prp> >(ep); + boost::mpl::for_each<boost::mpl::range_c<int, prp, prp> >(ep); // write the file std::ofstream ofs(file); // Check if the file is open if (ofs.is_open() == false) - {std::cerr << "Error cannot create the VTK file: " + file;} + { + std::cerr << "Error cannot create the VTK file: " + file; + } - ofs << vtk_header << point_prop_header << point_list << - vertex_prop_header << vertex_list << edge_prop_header << edge_list << point_data_header << point_data << cell_data_header << cell_data; + ofs << vtk_header << point_prop_header << point_list << vertex_prop_header << vertex_list << edge_prop_header << edge_list << point_data_header << point_data << cell_data_header << cell_data; // Close the file @@ -925,5 +1203,4 @@ public: } }; - #endif /* VTKWRITER_GRAPH_HPP_ */ diff --git a/src/VTKWriter_unit_tests.hpp b/src/VTKWriter_unit_tests.hpp index c86b5d08..a9d79f63 100644 --- a/src/VTKWriter_unit_tests.hpp +++ b/src/VTKWriter_unit_tests.hpp @@ -33,22 +33,13 @@ struct vertex //! The data type data; - - //! computation property id in boost::fusion::vector static const unsigned int x = 0; - //! computation property id in boost::fusion::vector static const unsigned int y = 1; - //! memory property id in boost::fusion::vector static const unsigned int z = 2; - //! computation property id in boost::fusion::vector static const unsigned int prp1 = 3; - //! computation property id in boost::fusion::vector static const unsigned int prp2 = 4; - //! memory property id in boost::fusion::vector static const unsigned int prp3 = 5; - //! memory property id in boost::fusion::vector static const unsigned int prp4 = 6; - //! memory property sub_id in boost::fusion::vector static const unsigned int prp5 = 7; //! total number of properties boost::fusion::vector @@ -76,10 +67,305 @@ struct vertex } }; +const std::string vertex::attributes::name[] = {"x","y","z","prp1","prp2","prp3","prp4","prp5"}; + +struct vertex2 +{ + //! The node contain 3 unsigned long integer for communication computation memory and id + typedef boost::fusion::vector<float[3],size_t,double> type; + + typedef typename memory_traits_inte<type>::type memory_int; + typedef typename memory_traits_lin<type>::type memory_lin; + + //! type of the positional field + typedef float s_type; + + //! Attributes name + struct attributes + { + static const std::string name[]; + }; + + //! The data + type data; + + //! computation property id in boost::fusion::vector + static const unsigned int x = 0; + static const unsigned int prp1 = 1; + static const unsigned int prp2 = 2; + + //! total number of properties boost::fusion::vector + static const unsigned int max_prop = 3; + + /*! + * Default constructor + * + */ + vertex2() + { + + } + + /*! \brief Initialize the VTKVertex + * + * \param + * + */ + vertex2(float x, float y, float z) + { + boost::fusion::at_c<vertex::x>(data)[0] = x; + boost::fusion::at_c<vertex::x>(data)[1] = y; + boost::fusion::at_c<vertex::x>(data)[2] = z; + } +}; + // use the vertex like the edge typedef vertex edge; -const std::string vertex::attributes::name[] = {"x","y","z","prp1","prp2","prp3","prp4","prp5"}; +const std::string vertex2::attributes::name[] = {"x","prp1","prp2"}; + + + +BOOST_AUTO_TEST_CASE( vtk_writer_use_graph3D ) +{ + // Create some graphs and output them + + // Graph + + Graph_CSR<vertex2,edge> gr; + + // Create a cube graph + + gr.addVertex(vertex2(0.0,0.0,0.0)); + gr.addVertex(vertex2(0.0,0.0,1.0)); + gr.addVertex(vertex2(0.0,1.0,0.0)); + gr.addVertex(vertex2(0.0,1.0,1.0)); + gr.addVertex(vertex2(1.0,0.0,0.0)); + gr.addVertex(vertex2(1.0,0.0,1.0)); + gr.addVertex(vertex2(1.0,1.0,0.0)); + gr.addVertex(vertex2(1.0,1.0,1.0)); + + gr.addEdge(0,6); + gr.addEdge(6,4); + gr.addEdge(4,0); + + gr.addEdge(0,2); + gr.addEdge(2,6); + gr.addEdge(6,0); + + gr.addEdge(0,3); + gr.addEdge(3,2); + gr.addEdge(2,0); + + gr.addEdge(0,1); + gr.addEdge(1,3); + gr.addEdge(3,0); + + gr.addEdge(2,7); + gr.addEdge(7,6); + gr.addEdge(6,2); + + gr.addEdge(2,3); + gr.addEdge(3,7); + gr.addEdge(7,2); + + gr.addEdge(4,6); + gr.addEdge(6,7); + gr.addEdge(7,4); + + gr.addEdge(4,7); + gr.addEdge(7,5); + gr.addEdge(5,4); + + gr.addEdge(0,4); + gr.addEdge(4,5); + gr.addEdge(5,0); + + gr.addEdge(0,5); + gr.addEdge(5,1); + gr.addEdge(1,0); + + gr.addEdge(1,5); + gr.addEdge(5,7); + gr.addEdge(7,1); + + gr.addEdge(1,7); + gr.addEdge(7,3); + gr.addEdge(3,1); + + // Write the VTK file + + VTKWriter<Graph_CSR<vertex2,edge>,GRAPH> vtk(gr); + vtk.write("vtk_graph_v2.vtk"); + + // check that match + + bool test = compare("vtk_graph_v2.vtk","vtk_graph_test.vtk"); + BOOST_REQUIRE_EQUAL(true,test); +} + +BOOST_AUTO_TEST_CASE( vtk_writer_use_graph3D_edge ) +{ + // Create some graphs and output them + + // Graph + + Graph_CSR<vertex2,vertex2> gr; + + // Create a cube graph + + gr.addVertex(vertex2(0.0,0.0,0.0)); + gr.addVertex(vertex2(0.0,0.0,1.0)); + gr.addVertex(vertex2(0.0,1.0,0.0)); + gr.addVertex(vertex2(0.0,1.0,1.0)); + gr.addVertex(vertex2(1.0,0.0,0.0)); + gr.addVertex(vertex2(1.0,0.0,1.0)); + gr.addVertex(vertex2(1.0,1.0,0.0)); + gr.addVertex(vertex2(1.0,1.0,1.0)); + + gr.addEdge(0,6,vertex2(0.0,0.0,1.0)); + gr.addEdge(6,4,vertex2(0.0,0.0,1.0)); + gr.addEdge(4,0,vertex2(0.0,0.0,1.0)); + + gr.addEdge(0,2,vertex2(0.0,0.0,1.0)); + gr.addEdge(2,6,vertex2(0.0,0.0,1.0)); + gr.addEdge(6,0,vertex2(0.0,0.0,1.0)); + + gr.addEdge(0,3,vertex2(0.0,0.0,1.0)); + gr.addEdge(3,2,vertex2(0.0,0.0,1.0)); + gr.addEdge(2,0,vertex2(0.0,0.0,1.0)); + + gr.addEdge(0,1,vertex2(0.0,0.0,1.0)); + gr.addEdge(1,3,vertex2(0.0,0.0,1.0)); + gr.addEdge(3,0,vertex2(0.0,0.0,1.0)); + + gr.addEdge(2,7,vertex2(0.0,0.0,1.0)); + gr.addEdge(7,6,vertex2(0.0,0.0,1.0)); + gr.addEdge(6,2,vertex2(0.0,0.0,1.0)); + + gr.addEdge(2,3,vertex2(0.0,0.0,1.0)); + gr.addEdge(3,7,vertex2(0.0,0.0,1.0)); + gr.addEdge(7,2,vertex2(0.0,0.0,1.0)); + + gr.addEdge(4,6,vertex2(0.0,0.0,1.0)); + gr.addEdge(6,7,vertex2(0.0,0.0,1.0)); + gr.addEdge(7,4,vertex2(0.0,0.0,1.0)); + + gr.addEdge(4,7,vertex2(0.0,0.0,1.0)); + gr.addEdge(7,5,vertex2(0.0,0.0,1.0)); + gr.addEdge(5,4,vertex2(0.0,0.0,1.0)); + + gr.addEdge(0,4,vertex2(0.0,0.0,1.0)); + gr.addEdge(4,5,vertex2(0.0,0.0,1.0)); + gr.addEdge(5,0,vertex2(0.0,0.0,1.0)); + + gr.addEdge(0,5,vertex2(0.0,0.0,1.0)); + gr.addEdge(5,1,vertex2(0.0,0.0,1.0)); + gr.addEdge(1,0,vertex2(0.0,0.0,1.0)); + + gr.addEdge(1,5,vertex2(0.0,0.0,1.0)); + gr.addEdge(5,7,vertex2(0.0,0.0,1.0)); + gr.addEdge(7,1,vertex2(0.0,0.0,1.0)); + + gr.addEdge(1,7,vertex2(0.0,0.0,1.0)); + gr.addEdge(7,3,vertex2(0.0,0.0,1.0)); + gr.addEdge(3,1,vertex2(0.0,0.0,1.0)); + + // Write the VTK file + + VTKWriter<Graph_CSR<vertex2,vertex2>,GRAPH> vtk(gr); + vtk.write("vtk_graph_v4.vtk"); + + // check that match + + bool test = compare("vtk_graph_v4.vtk","vtk_graph_test.vtk"); + BOOST_REQUIRE_EQUAL(true,test); +} + +struct vertex3 +{ + //! The node contain 3 unsigned long integer for communication computation memory and id + typedef boost::fusion::vector<float[2],size_t,double> type; + + typedef typename memory_traits_inte<type>::type memory_int; + typedef typename memory_traits_lin<type>::type memory_lin; + + //! type of the positional field + typedef float s_type; + + //! Attributes name + struct attributes + { + static const std::string name[]; + }; + + //! The data + type data; + + //! computation property id in boost::fusion::vector + static const unsigned int x = 0; + static const unsigned int prp1 = 1; + static const unsigned int prp2 = 2; + + //! total number of properties boost::fusion::vector + static const unsigned int max_prop = 3; + + /*! + * Default constructor + * + */ + vertex3() + { + + } + + /*! \brief Initialize the VTKVertex + * + * \param + * + */ + vertex3(float x, float y) + { + boost::fusion::at_c<vertex::x>(data)[0] = x; + boost::fusion::at_c<vertex::x>(data)[1] = y; + } +}; + +// use the vertex like the edge +typedef vertex edge; + +const std::string vertex3::attributes::name[] = {"x","prp1","prp2"}; + +BOOST_AUTO_TEST_CASE( vtk_writer_use_graph2D ) +{ + // Create some graphs and output them + + // Graph + + Graph_CSR<vertex3,edge> gr; + + // Create a cube graph + + gr.addVertex(vertex3(0.0,0.0)); + gr.addVertex(vertex3(0.0,1.0)); + gr.addVertex(vertex3(1.0,0.0)); + gr.addVertex(vertex3(1.0,1.0)); + + gr.addEdge(0,1); + gr.addEdge(1,3); + gr.addEdge(3,2); + gr.addEdge(2,0); + + // Write the VTK file + + VTKWriter<Graph_CSR<vertex3,edge>,GRAPH> vtk(gr); + vtk.write("vtk_graph_v3.vtk"); + + // check that match + + bool test = compare("vtk_graph_v3.vtk","vtk_graph_test.vtk"); + BOOST_REQUIRE_EQUAL(true,test); +} BOOST_AUTO_TEST_CASE( vtk_writer_use_graph) { -- GitLab