// Copyright (c) 2018 GeometryFactory Sarl (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Surface_mesh/include/CGAL/Surface_mesh/IO/PLY.h $ // $Id: PLY.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Simon Giraudot #ifndef CGAL_SURFACE_MESH_IO_PLY #define CGAL_SURFACE_MESH_IO_PLY #include namespace CGAL { namespace internal { #if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES) namespace PLY { template class Surface_mesh_filler { public: typedef typename Kernel_traits::Kernel Kernel; typedef typename Kernel::Vector_3 Vector; typedef CGAL::Surface_mesh Surface_mesh; typedef typename Surface_mesh::size_type size_type; typedef typename Surface_mesh::Vertex_index Vertex_index; typedef typename Surface_mesh::Face_index Face_index; typedef typename Surface_mesh::Edge_index Edge_index; typedef typename Surface_mesh::Halfedge_index Halfedge_index; private: struct Abstract_ply_property_to_surface_mesh_property { virtual ~Abstract_ply_property_to_surface_mesh_property() { } virtual void assign (PLY_element& element, size_type index) = 0; }; template class PLY_property_to_surface_mesh_property : public Abstract_ply_property_to_surface_mesh_property { typedef typename Surface_mesh::template Property_map Map; Map m_map; std::string m_name; public: PLY_property_to_surface_mesh_property (Surface_mesh& sm, const std::string& name) : m_name (name) { m_map = sm.template add_property_map(prefix(Simplex()) + name).first; } virtual void assign (PLY_element& element, size_type index) { Type t{}; element.assign (t, m_name.c_str()); put(m_map, Simplex(index), t); } std::string prefix(Vertex_index) const { return "v:"; } std::string prefix(Face_index) const { return "f:"; } std::string prefix(Edge_index) const { return "e:"; } std::string prefix(Halfedge_index) const { return "h:"; } }; Surface_mesh& m_mesh; std::vector m_map_v2v; bool m_use_floats; int m_normals; typename Surface_mesh::template Property_map m_normal_map; int m_vcolors; typename Surface_mesh::template Property_map m_vcolor_map; int m_fcolors; typename Surface_mesh::template Property_map m_fcolor_map; bool m_use_int32_t; std::string m_index_tag; std::vector m_vertex_properties; std::vector m_face_properties; std::vector m_edge_properties; std::vector m_halfedge_properties; public: Surface_mesh_filler (Surface_mesh& mesh) : m_mesh (mesh), m_use_floats (false), m_normals(0), m_vcolors(0), m_fcolors(0) { } ~Surface_mesh_filler() { for (std::size_t i = 0; i < m_vertex_properties.size(); ++ i) delete m_vertex_properties[i]; for (std::size_t i = 0; i < m_face_properties.size(); ++ i) delete m_face_properties[i]; for (std::size_t i = 0; i < m_edge_properties.size(); ++ i) delete m_edge_properties[i]; for (std::size_t i = 0; i < m_halfedge_properties.size(); ++ i) delete m_halfedge_properties[i]; } bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Vertex_index) { const std::string& name = property->name(); if (name == "x" || name == "y" || name == "z") { if (dynamic_cast*>(property)) m_use_floats = true; return true; } if (name == "nx" || name == "ny" || name == "nz") { ++ m_normals; if (m_normals == 3) m_normal_map = m_mesh.template add_property_map("v:normal").first; return true; } if (name == "red" || name == "green" || name == "blue") { ++ m_vcolors; if (m_vcolors == 3) m_vcolor_map = m_mesh.template add_property_map("v:color").first; return true; } return false; } bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Face_index) { const std::string& name = property->name(); if (name == "vertex_indices" || name == "vertex_index") { CGAL_assertion (dynamic_cast*>(property) || dynamic_cast*>(property)); m_index_tag = name; m_use_int32_t = dynamic_cast*>(property); return true; } if (name == "red" || name == "green" || name == "blue") { ++ m_fcolors; if (m_fcolors == 3) m_fcolor_map = m_mesh.template add_property_map("f:color").first; return true; } return false; } bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Edge_index) { const std::string& name = property->name(); if (name == "v0" || name == "v1") return true; return false; } bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Halfedge_index) { const std::string& name = property->name(); if (name == "source" || name == "target") return true; return false; } void instantiate_vertex_properties (PLY_element& element) { m_map_v2v.reserve(element.number_of_items()); instantiate_properties (element, m_vertex_properties); } void instantiate_face_properties (PLY_element& element) { instantiate_properties (element, m_face_properties); } void instantiate_edge_properties (PLY_element& element) { instantiate_properties (element, m_edge_properties); } void instantiate_halfedge_properties (PLY_element& element) { instantiate_properties (element, m_halfedge_properties); } template void instantiate_properties (PLY_element& element, std::vector& properties) { for (std::size_t j = 0; j < element.number_of_properties(); ++ j) { internal::PLY::PLY_read_number* property = element.property(j); 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)); } } } void process_vertex_line (PLY_element& element) { Vertex_index vi; if (m_use_floats) process_line(element, vi); else process_line(element, vi); for (std::size_t i = 0; i < m_vertex_properties.size(); ++ i) m_vertex_properties[i]->assign (element, vi); } template void process_line (PLY_element& element, Vertex_index& vi) { FT x = (FT)0.,y = (FT)0., z = (FT)0., nx = (FT)0., ny = (FT)0., nz = (FT)0.; element.assign (x, "x"); element.assign (y, "y"); element.assign (z, "z"); Point point (x, y, z); vi = m_mesh.add_vertex(point); m_map_v2v.push_back(vi); if (m_normals == 3) { element.assign (nx, "nx"); element.assign (ny, "ny"); element.assign (nz, "nz"); Vector normal (nx, ny, nz); m_normal_map[vi] = normal; } if (m_vcolors == 3) { unsigned char r, g, b; element.assign (r, "red"); element.assign (g, "green"); element.assign (b, "blue"); m_vcolor_map[vi] = CGAL::Color (r, g, b); } } bool process_face_line (PLY_element& element) { Face_index fi = m_mesh.null_face(); if (m_use_int32_t) process_line(element, fi); else process_line(element, fi); if (fi == Surface_mesh::null_face()) return false; for (std::size_t i = 0; i < m_face_properties.size(); ++ i) m_face_properties[i]->assign (element, fi); return true; } template void process_line (PLY_element& element, Face_index& fi) { std::vector indices; element.assign (indices, m_index_tag.c_str()); std::vector vertices; vertices.reserve(indices.size()); for (std::size_t i = 0; i < indices.size(); ++ i) vertices.push_back (m_map_v2v[std::size_t(indices[i])]); fi = m_mesh.add_face(vertices); if (fi == m_mesh.null_face()) return; if (m_fcolors == 3) { unsigned char r, g, b; element.assign (r, "red"); element.assign (g, "green"); element.assign (b, "blue"); m_fcolor_map[fi] = CGAL::Color (r, g, b); } } bool process_edge_line (PLY_element& element) { Edge_index ei = m_mesh.null_edge(); if (m_use_int32_t) process_line(element, ei); else process_line(element, ei); if (ei == Surface_mesh::null_edge()) return false; for (std::size_t i = 0; i < m_edge_properties.size(); ++ i) m_edge_properties[i]->assign (element, ei); return true; } template void process_line (PLY_element& element, Edge_index& ei) { IntType v0, v1; element.assign (v0, "v0"); element.assign (v1, "v1"); Halfedge_index hi = m_mesh.halfedge(m_map_v2v[std::size_t(v0)], m_map_v2v[std::size_t(v1)]); if (hi == m_mesh.null_halfedge()) return; ei = m_mesh.edge (hi); } bool process_halfedge_line (PLY_element& element) { Halfedge_index hi = m_mesh.null_halfedge(); if (m_use_int32_t) process_line(element, hi); else process_line(element, hi); if (hi == Surface_mesh::null_halfedge()) return false; for (std::size_t i = 0; i < m_halfedge_properties.size(); ++ i) m_halfedge_properties[i]->assign (element, hi); return true; } template void process_line (PLY_element& element, Halfedge_index& hi) { IntType source, target; element.assign (source, "source"); element.assign (target, "target"); hi = m_mesh.halfedge(m_map_v2v[std::size_t(source)], m_map_v2v[std::size_t(target)]); } }; template bool fill_simplex_specific_header (std::ostream& os, const Surface_mesh& sm, std::vector::Vertex_index>*>& printers, const std::string& prop) { typedef Surface_mesh SMesh; typedef typename SMesh::Vertex_index VIndex; typedef typename Kernel_traits::Kernel Kernel; typedef typename Kernel::FT FT; typedef typename Kernel::Vector_3 Vector; typedef typename SMesh::template Property_map Point_map; typedef typename SMesh::template Property_map Vector_map; typedef typename SMesh::template Property_map Vcolor_map; if (prop == "v:connectivity" || prop == "v:removed") return true; if (prop == "v:point") { if (boost::is_same::value) { os << "property float x" << std::endl << "property float y" << std::endl << "property float z" << std::endl; } else { os << "property double x" << std::endl << "property double y" << std::endl << "property double z" << std::endl; } printers.push_back (new Property_printer(sm.points())); return true; } bool okay = false; if (prop == "v:normal") { Vector_map pmap; boost::tie (pmap, okay) = sm.template property_map(prop); if (okay) { if (boost::is_same::value) { os << "property float nx" << std::endl << "property float ny" << std::endl << "property float nz" << std::endl; } else { os << "property double nx" << std::endl << "property double ny" << std::endl << "property double nz" << std::endl; } printers.push_back (new Property_printer(pmap)); return true; } } if (prop == "v:color") { Vcolor_map pmap; boost::tie (pmap, okay) = sm.template property_map(prop); if (okay) { os << "property uchar red" << std::endl << "property uchar green" << std::endl << "property uchar blue" << std::endl << "property uchar alpha" << std::endl; printers.push_back (new Property_printer(pmap)); return true; } } return false; } template bool fill_simplex_specific_header (std::ostream& os, const Surface_mesh& sm, std::vector::Face_index>*>& printers, const std::string& prop) { typedef Surface_mesh SMesh; typedef typename SMesh::Face_index FIndex; typedef typename SMesh::template Property_map Fcolor_map; if (prop == "f:connectivity" || prop == "f:removed") return true; bool okay = false; if (prop == "f:color") { Fcolor_map pmap; boost::tie (pmap, okay) = sm.template property_map(prop); if (okay) { os << "property uchar red" << std::endl << "property uchar green" << std::endl << "property uchar blue" << std::endl << "property uchar alpha" << std::endl; printers.push_back (new Property_printer(pmap)); return true; } } return false; } template bool fill_simplex_specific_header (std::ostream& , const Surface_mesh& , std::vector::Edge_index>*>& , const std::string& prop) { if (prop == "e:removed") return true; return false; } template bool fill_simplex_specific_header (std::ostream& , const Surface_mesh& , std::vector::Halfedge_index>*>& , const std::string& prop) { if (prop == "h:connectivity") return true; return false; } template std::string get_property_raw_name (const std::string& prop, typename Surface_mesh::Vertex_index) { std::string name = prop; if (name.rfind("v:",0) == 0) name = std::string (prop.begin() + 2, prop.end()); return name; } template std::string get_property_raw_name (const std::string& prop, typename Surface_mesh::Face_index) { std::string name = prop; if (name.rfind("f:",0) == 0) name = std::string (prop.begin() + 2, prop.end()); return name; } template std::string get_property_raw_name (const std::string& prop, typename Surface_mesh::Edge_index) { std::string name = prop; if (name.rfind("e:",0) == 0) name = std::string (prop.begin() + 2, prop.end()); return name; } template std::string get_property_raw_name (const std::string& prop, typename Surface_mesh::Halfedge_index) { std::string name = prop; if (name.rfind("h:",0) == 0) name = std::string (prop.begin() + 2, prop.end()); return name; } 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; std::vector prop = sm.template properties(); for (std::size_t i = 0; i < prop.size(); ++ i) { 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::PLY::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::PLY::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::PLY::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::PLY::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::PLY::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::PLY::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::PLY::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::PLY::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::PLY::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::PLY::Simple_property_printer(pmap)); continue; } } } } } // namespace PLY #endif } // namespace internal } // namespace CGAL #endif // CGAL_SURFACE_MESH_IO_PLY