Point Cloud Library (PCL)  1.14.0-dev
mesh_io.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2009-2012, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  *
39  */
40 
41 #pragma once
42 
43 #include <fstream>
44 #include <iostream>
45 #include <sstream>
46 #include <string>
47 
48 namespace pcl {
49 namespace geometry {
50 /** \brief Read / write the half-edge mesh from / to a file.
51  * \tparam MeshT e.g. pcl::geometry::TriangleMesh or pcl::geometry::PolygonMesh
52  * \author Martin Saelzle
53  * \ingroup geometry
54  * \todo
55  * - Only writes the topology (not the mesh data).
56  * - Supports only ascii.
57  * - Does not consider the mesh traits (e.g. manifold or not)
58  */
59 template <class MeshT>
60 class MeshIO {
61 public:
62  using Mesh = MeshT;
63 
64  using Vertex = typename Mesh::Vertex;
65  using HalfEdge = typename Mesh::HalfEdge;
66  using Face = typename Mesh::Face;
67 
68  using Vertices = typename Mesh::Vertices;
69  using HalfEdges = typename Mesh::HalfEdges;
70  using Faces = typename Mesh::Faces;
71 
72  using VertexIndex = typename Mesh::VertexIndex;
74  using FaceIndex = typename Mesh::FaceIndex;
75 
76  /** \brief Constructor. */
77  MeshIO() = default;
78 
79  /** \brief Read the mesh from a file with the given filename.
80  * \param[in] filename Path to the file.
81  * \param[out] mesh The loaded mesh.
82  * \return true if success.
83  */
84  bool
85  read(const std::string& filename, Mesh& mesh) const
86  {
87  std::ifstream file(filename.c_str());
88 
89  if (!file.is_open()) {
90  std::cerr << "Error in MeshIO::read: Could not open the file '" << filename
91  << "'\n";
92  return (false);
93  }
94 
95  // Read the header
96  std::string line;
97  unsigned int line_number = 1;
98  int n_v = -1, n_he = -1, n_f = -1;
99 
100  if (!std::getline(file, line) || line != "PCL half-edge mesh") {
101  std::cerr << "Error loading '" << filename << "' (line " << line_number
102  << "): Wrong file format.\n";
103  return (false);
104  }
105  ++line_number;
106 
107  if (!std::getline(file, line)) {
108  std::cerr << "Error loading '" << filename << "'' (line " << line_number
109  << "): Number of vertices / half-edges / faces not found.\n";
110  return (false);
111  }
112  {
113  std::istringstream iss(line);
114  if (!(iss >> n_v >> n_he >> n_f) || iss.good()) // Don't allow more than 3 en
115  {
116  std::cerr << "Error loading '" << filename << "'' (line " << line_number
117  << "): Could not read the number of vertices / half-edges / faces.\n";
118  return (false);
119  }
120  }
121  if (n_v < 0 || n_he < 0 || n_f < 0) {
122  std::cerr << "Error loading '" << filename << "'' (line " << line_number
123  << "): Invalid number of vertices / half-edges / faces.\n";
124  return (false);
125  }
126  ++line_number;
127 
128  // Read the vertices.
129  {
130  mesh.vertices_.reserve(n_v);
131  HalfEdgeIndex idx_ohe; // Outgoing half-edge;
132 
133  for (int i = 0; i < n_v; ++i, ++line_number) {
134  if (!std::getline(file, line)) {
135  std::cerr << "Error loading '" << filename << "'' (line " << line_number
136  << "): Could not read the line.\n";
137  return (false);
138  }
139 
140  std::istringstream iss(line);
141  if (!(iss >> idx_ohe) || iss.good()) {
142  std::cerr << "Error loading '" << filename << "'' (line " << line_number
143  << "): Could not read the vertex.\n";
144  return (false);
145  }
146  mesh.vertices_.push_back(Vertex(idx_ohe));
147  }
148  }
149 
150  // Read the half-edges.
151  {
152  mesh.half_edges_.reserve(n_he);
153  VertexIndex idx_tv; // Terminating vertex.
154  HalfEdgeIndex idx_nhe; // Next half-edge;
155  HalfEdgeIndex idx_phe; // Previous half-edge.
156  FaceIndex idx_f; // Face.
157 
158  for (int i = 0; i < n_he; ++i, ++line_number) {
159  if (!std::getline(file, line)) {
160  std::cerr << "Error loading '" << filename << "'' (line " << line_number
161  << "): Could not read the line.\n";
162  return (false);
163  }
164 
165  std::istringstream iss(line);
166  if (!(iss >> idx_tv >> idx_nhe >> idx_phe >> idx_f) || iss.good()) {
167  std::cerr << "Error loading '" << filename << "'' (line " << line_number
168  << "): Could not read the half-edge.\n";
169  return (false);
170  }
171  mesh.half_edges_.push_back(HalfEdge(idx_tv, idx_nhe, idx_phe, idx_f));
172  }
173  }
174 
175  // Read the faces.
176  {
177  mesh.faces_.reserve(n_f);
178  HalfEdgeIndex idx_ihe; // Inner half-edge.
179 
180  for (int i = 0; i < n_f; ++i, ++line_number) {
181  if (!std::getline(file, line)) {
182  std::cerr << "Error loading '" << filename << "'' (line " << line_number
183  << "): Could not read the line.\n";
184  return (false);
185  }
186 
187  std::istringstream iss(line);
188  if (!(iss >> idx_ihe) || iss.good()) {
189  std::cerr << "Error loading '" << filename << "'' (line " << line_number
190  << "): Could not read the face.\n";
191  return (false);
192  }
193  mesh.faces_.push_back(Face(idx_ihe));
194  }
195  }
196 
197  // Set the data
198  if (Mesh::HasVertexData::value)
199  mesh.vertex_data_cloud_.resize(n_v);
200  if (Mesh::HasHalfEdgeData::value)
201  mesh.half_edge_data_cloud_.resize(n_he);
202  if (Mesh::HasEdgeData::value)
203  mesh.edge_data_cloud_.resize(n_he / 2);
204  if (Mesh::HasFaceData::value)
205  mesh.face_data_cloud_.resize(n_f);
206 
207  return (true);
208  }
209 
210  /** \brief Write the mesh to a file with the given filename.
211  * \param[in] filename Path to the file.
212  * \param[in] mesh The saved mesh.
213  * \return true if success
214  */
215  bool
216  write(const std::string& filename, const Mesh& mesh) const
217  {
218  std::ofstream file(filename.c_str());
219 
220  // Write the header
221  if (!file.is_open()) {
222  std::cerr << "Error in MeshIO::write: Could not open the file '" << filename
223  << "'\n";
224  return (false);
225  }
226 
227  file << "PCL half-edge mesh\n";
228  file << mesh.sizeVertices() << " " << mesh.sizeHalfEdges() << " "
229  << mesh.sizeFaces() << "\n";
230 
231  // Write the vertices
232  for (const auto& vertex : mesh.vertices_) {
233  file << vertex.idx_outgoing_half_edge_ << "\n";
234  }
235 
236  // Write the half-edges
237  for (const auto& edge : mesh.half_edges_) {
238  file << edge.idx_terminating_vertex_ << " " << edge.idx_next_half_edge_ << " "
239  << edge.idx_prev_half_edge_ << " " << edge.idx_face_ << "\n";
240  }
241 
242  // Write the faces
243  for (const auto& face : mesh.faces_) {
244  file << face.idx_inner_half_edge_ << "\n";
245  }
246 
247  return (true);
248  }
249 };
250 
251 } // End namespace geometry
252 } // End namespace pcl
Definition: surface.h:14
Read / write the half-edge mesh from / to a file.
Definition: mesh_io.h:60
typename Mesh::Face Face
Definition: mesh_io.h:66
typename Mesh::VertexIndex VertexIndex
Definition: mesh_io.h:72
typename Mesh::FaceIndex FaceIndex
Definition: mesh_io.h:74
typename Mesh::HalfEdges HalfEdges
Definition: mesh_io.h:69
typename Mesh::HalfEdgeIndex HalfEdgeIndex
Definition: mesh_io.h:73
bool read(const std::string &filename, Mesh &mesh) const
Read the mesh from a file with the given filename.
Definition: mesh_io.h:85
typename Mesh::Faces Faces
Definition: mesh_io.h:70
MeshIO()=default
Constructor.
typename Mesh::Vertex Vertex
Definition: mesh_io.h:64
typename Mesh::Vertices Vertices
Definition: mesh_io.h:68
bool write(const std::string &filename, const Mesh &mesh) const
Write the mesh to a file with the given filename.
Definition: mesh_io.h:216
typename Mesh::HalfEdge HalfEdge
Definition: mesh_io.h:65
pcl::detail::MeshIndex< struct FaceIndexTag > FaceIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:211
pcl::detail::MeshIndex< struct HalfEdgeIndexTag > HalfEdgeIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:199
pcl::detail::MeshIndex< struct VertexIndexTag > VertexIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:193