diff --git a/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h b/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h index 725d15ff120..76daf4494ab 100644 --- a/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h +++ b/Point_set_3/include/CGAL/Point_set_3/IO/PLY.h @@ -545,7 +545,7 @@ bool write_PLY(std::ostream& os, if(okay) { os << "property char " << prop[i] << std::endl; - printers.push_back(new internal::Char_property_printer(pmap)); + printers.push_back(new internal::Simple_property_printer(pmap)); continue; } } @@ -555,7 +555,7 @@ bool write_PLY(std::ostream& os, if(okay) { os << "property uchar " << prop[i] << std::endl; - printers.push_back(new internal::Char_property_printer(pmap)); + printers.push_back(new internal::Simple_property_printer(pmap)); continue; } } diff --git a/Stream_support/include/CGAL/IO/PLY/PLY_writer.h b/Stream_support/include/CGAL/IO/PLY/PLY_writer.h index 2e8bbad3a89..be015411a56 100644 --- a/Stream_support/include/CGAL/IO/PLY/PLY_writer.h +++ b/Stream_support/include/CGAL/IO/PLY/PLY_writer.h @@ -275,25 +275,37 @@ public: } }; -template -class Char_property_printer +template ::value_type, + typename ElementType = typename VectorType::value_type> +class Simple_property_vector_printer : public Abstract_property_printer { - typedef typename boost::property_traits::value_type Type; - PropertyMap m_pmap; - public: - Char_property_printer(const PropertyMap& pmap) : m_pmap(pmap) { } + Simple_property_vector_printer(const PropertyMap& pmap) : m_pmap(pmap) { } virtual void print(std::ostream& stream, const Index& index) { + const VectorType& vec = get(m_pmap, index); if(get_mode(stream) == CGAL::IO::ASCII) - stream << int(get(m_pmap, index)); + { + stream << vec.size(); + for(const ElementType& v : vec) + { + stream << " " << v; + } + } else { - Type t = get(m_pmap, index); - stream.write(reinterpret_cast(&t), sizeof(t)); + unsigned char size = (unsigned char)(vec.size()); + stream.write(reinterpret_cast(&size), sizeof(size)); + for(const ElementType& v : vec) + { + ElementType t = ElementType(v); + stream.write(reinterpret_cast(&t), sizeof(t)); + } } } }; diff --git a/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h b/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h index 1e59286bd01..544abd94230 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h @@ -145,10 +145,10 @@ public: const std::string& name = property->name(); if(name == "vertex_indices" || name == "vertex_index") { - CGAL_assertion(dynamic_cast*>(property) - || dynamic_cast*>(property)); + CGAL_assertion(dynamic_cast*>(property) + || dynamic_cast*>(property)); m_index_tag = name; - m_use_int32_t = dynamic_cast*>(property); + m_use_int32_t = dynamic_cast*>(property); return true; } if(name == "red" || @@ -205,10 +205,42 @@ public: instantiate_properties(element, m_halfedge_properties); } + template + void instantiate_properties_impl(PLY_element& element, + std::vector& properties, + internal::PLY_read_number* property, + std::tuple) + { + if(dynamic_cast*>(property)) + { + properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, property->name())); + return; + } + if(dynamic_cast*>(property)) + { + properties.push_back(new PLY_property_to_surface_mesh_property>(m_mesh, property->name())); + return; + } + instantiate_properties_impl(element, properties, property, std::tuple()); + } + + template + void instantiate_properties_impl(PLY_element&, + std::vector&, + internal::PLY_read_number*, + std::tuple<>) + {} + template void instantiate_properties(PLY_element& element, std::vector& properties) { + typedef std::tuple Type_tuple; + for(std::size_t j = 0; j < element.number_of_properties(); ++ j) { internal::PLY_read_number* property = element.property(j); @@ -216,40 +248,7 @@ public: if(has_simplex_specific_property(property, Simplex())) continue; - const std::string& name = property->name(); - - if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } - else if(dynamic_cast*>(property)) - { - properties.push_back(new PLY_property_to_surface_mesh_property(m_mesh, name)); - } + instantiate_properties_impl(element, properties, property, Type_tuple()); } } @@ -302,9 +301,9 @@ public: Face_index fi = m_mesh.null_face(); if(m_use_int32_t) - process_line(element, fi); + process_line(element, fi); else - process_line(element, fi); + process_line(element, fi); if(fi == Surface_mesh::null_face()) return false; @@ -344,9 +343,9 @@ public: Edge_index ei = m_mesh.null_edge(); if(m_use_int32_t) - process_line(element, ei); + process_line(element, ei); else - process_line(element, ei); + process_line(element, ei); if(ei == Surface_mesh::null_edge()) return false; @@ -377,9 +376,9 @@ public: Halfedge_index hi = m_mesh.null_halfedge(); if(m_use_int32_t) - process_line(element, hi); + process_line(element, hi); else - process_line(element, hi); + process_line(element, hi); if(hi == Surface_mesh::null_halfedge()) return false; @@ -421,7 +420,7 @@ bool fill_simplex_specific_header(std::ostream& os, if(prop == "v:point") { - if(boost::is_same::value) + if(std::is_same::value) { os << "property float x" << std::endl << "property float y" << std::endl @@ -441,10 +440,10 @@ bool fill_simplex_specific_header(std::ostream& os, if(prop == "v:normal") { Vector_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop); + std::tie(pmap, okay) = sm.template property_map(prop); if(okay) { - if(boost::is_same::value) + if(std::is_same::value) { os << "property float nx" << std::endl << "property float ny" << std::endl @@ -464,7 +463,7 @@ bool fill_simplex_specific_header(std::ostream& os, if(prop == "v:color") { Vcolor_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop); + std::tie(pmap, okay) = sm.template property_map(prop); if(okay) { os << "property uchar red" << std::endl @@ -498,7 +497,7 @@ bool fill_simplex_specific_header(std::ostream& os, if(prop == "f:color") { Fcolor_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop); + std::tie(pmap, okay) = sm.template property_map(prop); if(okay) { os << "property uchar red" << std::endl @@ -575,21 +574,65 @@ std::string get_property_raw_name(const std::string& prop, typename Surface_mesh return name; } + +template +void fill_header_impl(std::tuple, + const char* const type_strings[], + const Surface_mesh& sm, + const std::string& pname, + std::ostream& os, + std::vector*>& printers) +{ + constexpr std::size_t cid = s-std::tuple_size>::value; + bool okay = false; + { + typedef typename Surface_mesh::template Property_map Pmap; + Pmap pmap; + std::tie(pmap, okay) = sm.template property_map(pname); + if(okay) + { + std::string name = get_property_raw_name(pname, Simplex()); + os << "property " << type_strings[cid] << " " << name << std::endl; + printers.push_back(new internal::Simple_property_printer(pmap)); + return; + } + } + { + typedef typename Surface_mesh::template Property_map> Pmap; + Pmap pmap; + std::tie(pmap, okay) = sm.template property_map>(pname); + if(okay) + { + std::string name = get_property_raw_name(pname, Simplex()); + os << "property list uchar " << type_strings[cid] << " " << name << std::endl; + printers.push_back(new internal::Simple_property_vector_printer(pmap)); + return; + } + } + fill_header_impl(std::tuple(),type_strings, sm, pname, os, printers); +} + +template +void fill_header_impl(std::tuple<>, + const char* const [], + const Surface_mesh&, + const std::string&, + std::ostream&, + std::vector*>&) +{} + template void fill_header(std::ostream& os, const Surface_mesh& sm, std::vector*>& printers) { - typedef Surface_mesh SMesh; - typedef typename SMesh::template Property_map Int8_map; - typedef typename SMesh::template Property_map Uint8_map; - typedef typename SMesh::template Property_map Int16_map; - typedef typename SMesh::template Property_map Uint16_map; - typedef typename SMesh::template Property_map Int32_map; - typedef typename SMesh::template Property_map Uint32_map; - typedef typename SMesh::template Property_map Int64_map; - typedef typename SMesh::template Property_map Uint64_map; - typedef typename SMesh::template Property_map Float_map; - typedef typename SMesh::template Property_map Double_map; + typedef std::tuple Type_tuple; + + static constexpr const char* type_strings[] = + { "char", "uchar", "short", "ushort","int", "uint", "int", "uint", "float", "double" }; std::vector prop = sm.template properties(); @@ -598,110 +641,7 @@ void fill_header(std::ostream& os, const Surface_mesh& sm, if(fill_simplex_specific_header(os, sm, printers, prop[i])) continue; - // Cut the "v:" prefix - std::string name = get_property_raw_name(prop[i], Simplex()); - - bool okay = false; - { - Int8_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property char " << name << std::endl; - printers.push_back(new internal::Char_property_printer(pmap)); - continue; - } - } - { - Uint8_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property uchar " << name << std::endl; - printers.push_back(new internal::Char_property_printer(pmap)); - continue; - } - } - { - Int16_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property short " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Uint16_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property ushort " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Int32_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property int " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Uint32_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property uint " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Int64_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property int " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Uint64_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property uint " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Float_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property float " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } - { - Double_map pmap; - boost::tie(pmap, okay) = sm.template property_map(prop[i]); - if(okay) - { - os << "property double " << name << std::endl; - printers.push_back(new internal::Simple_property_printer(pmap)); - continue; - } - } + fill_header_impl::value>(Type_tuple(), type_strings, sm, prop[i], os, printers); } } diff --git a/Surface_mesh/test/Surface_mesh/sm_ply_io.cpp b/Surface_mesh/test/Surface_mesh/sm_ply_io.cpp index f2889f912bd..ddcda054507 100644 --- a/Surface_mesh/test/Surface_mesh/sm_ply_io.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_ply_io.cpp @@ -43,5 +43,92 @@ int main() // CGAL::IO::set_binary_mode(out); CGAL::IO::write_PLY(out, mesh); + // extra test for read/write of properties + mesh = SMesh(); + in.close(); + in.open(CGAL::data_file_path("meshes/colored_tetra.ply")); + CGAL::IO::read_PLY(in, mesh); + float fvalue=1001; + auto v_uvmap = mesh.add_property_map>("v:uv").first; + auto v_umap = mesh.add_property_map("v:u").first; + auto v_vmap = mesh.add_property_map("v:v").first; + for (SMesh::Vertex_index v : vertices(mesh)) + { + v_uvmap[v]={fvalue, -fvalue}; + v_umap[v]=fvalue; + v_vmap[v]=-fvalue; + ++fvalue; + } + + double dvalue=2001; + auto f_uvmap = mesh.add_property_map>("f:uv").first; + auto f_umap = mesh.add_property_map("f:u").first; + auto f_vmap = mesh.add_property_map("f:v").first; + for (SMesh::Face_index f : faces(mesh)) + { + f_uvmap[f]={dvalue, -dvalue}; + f_umap[f]=dvalue; + f_vmap[f]=-dvalue; + ++dvalue; + } + + out.close(); + out.open("out_ascii.ply"); + CGAL::IO::write_PLY(out, mesh); + out.close(); + out.open("out_binary.ply"); + CGAL::IO::set_binary_mode(out); + CGAL::IO::write_PLY(out, mesh); + out.close(); + mesh.clear(); + + const std::array fnames = {"out_ascii.ply", "out_binary.ply"}; + for (std::string fn : fnames) + { + std::cout << "Reading " << fn << "\n"; + in.close(); + in.open(fn); + SMesh mesh_bis; + CGAL::IO::read_PLY(in, mesh_bis); + + assert((mesh_bis.property_map("v:u").second)); + assert((mesh_bis.property_map("v:v").second)); + assert((mesh_bis.property_map>("v:uv").second)); + + v_uvmap = mesh_bis.property_map>("v:uv").first; + v_umap = mesh_bis.property_map("v:u").first; + v_vmap = mesh_bis.property_map("v:v").first; + + fvalue=1001; + for (SMesh::Vertex_index v : vertices(mesh_bis)) + { + assert(v_uvmap[v].size()==2); + assert(v_uvmap[v][0]==fvalue); + assert(v_uvmap[v][1]==-fvalue); + assert(v_umap[v]==fvalue); + assert(v_vmap[v]==-fvalue); + ++fvalue; + } + + assert((mesh_bis.property_map("f:u").second)); + assert((mesh_bis.property_map("f:v").second)); + assert((mesh_bis.property_map>("f:uv").second)); + + f_uvmap = mesh_bis.property_map>("f:uv").first; + f_umap = mesh_bis.property_map("f:u").first; + f_vmap = mesh_bis.property_map("f:v").first; + + dvalue=2001; + for (SMesh::Face_index f : faces(mesh_bis)) + { + assert(f_uvmap[f].size()==2); + assert(f_uvmap[f][0]==dvalue); + assert(f_uvmap[f][1]==-dvalue); + assert(f_umap[f]==dvalue); + assert(f_vmap[f]==-dvalue); + ++dvalue; + } + } + return 0; }