SPH
MeshFile.cpp
Go to the documentation of this file.
1 #include "post/MeshFile.h"
2 #include "objects/Exceptions.h"
3 #include <fstream>
4 
6 
8  try {
9  std::ofstream ofs(path.native());
10  // http://paulbourke.net/dataformats/ply/
11  ofs << "ply\n";
12  ofs << "format ascii 1.0\n";
13  ofs << "comment Exported by " << CODE_NAME << "\n";
14 
15  Mesh mesh = getMeshFromTriangles(triangles, EPS);
16 
17  ofs << "element vertex " << mesh.vertices.size() << "\n";
18  ofs << "property float x\n";
19  ofs << "property float y\n";
20  ofs << "property float z\n";
21  ofs << "element face " << mesh.faces.size() << "\n";
22  ofs << "property list int int vertex_index\n";
23  ofs << "end_header\n";
24 
25  for (const Vector& v : mesh.vertices) {
26  // print components manually, we don't need formatted result here
27  ofs << v[X] << " " << v[Y] << " " << v[Z] << std::endl;
28  }
29  for (Size i = 0; i < mesh.faces.size(); ++i) {
30  ofs << "3 " << mesh.faces[i][0] << " " << mesh.faces[i][1] << " " << mesh.faces[i][2]
31  << std::endl;
32  }
33  return SUCCESS;
34  } catch (const std::exception& e) {
35  return makeFailed(e.what());
36  }
37 }
38 
39 static Optional<std::string> stripStart(const std::string& line, const std::string& format) {
40  if (line.size() < format.size()) {
41  return NOTHING;
42  }
43  if (line.substr(0, format.size()) == format) {
44  // remove the following space, if there is one
45  return line.substr(min(line.size(), format.size() + 1));
46  } else {
47  return NOTHING;
48  }
49 }
50 
52  try {
53  std::ifstream ifs(path.native());
54  std::string line;
55 
56  // check for the file format
57  if (!std::getline(ifs, line) || line != "ply") {
58  throw IoError("File does not have a valid .ply format");
59  }
60  if (!std::getline(ifs, line) || line != "format ascii 1.0") {
61  throw IoError("Only ascii format of the .ply file is currently supported");
62  }
63 
64  // parse the header
65  Size vertexCnt = Size(-1);
66  Size faceCnt = Size(-1);
67  Array<std::string> properties;
68  while (std::getline(ifs, line)) {
69  if (stripStart(line, "comment")) {
70  continue;
71  } else if (stripStart(line, "end_header")) {
72  break;
73  } else if (Optional<std::string> vertexStr = stripStart(line, "element vertex")) {
74  vertexCnt = std::stoul(vertexStr.value());
75  } else if (Optional<std::string> faceStr = stripStart(line, "element face")) {
76  faceCnt = std::stoul(faceStr.value());
77  } else if (Optional<std::string> property = stripStart(line, "property float")) {
78  properties.push(property.value());
79  }
80  }
81 
82  // check validity of the header info
83  if (faceCnt == Size(-1) || vertexCnt == Size(-1)) {
84  throw IoError("Header did not contain number of faces or vertices");
85  } else if (properties.size() < 3 || properties[0] != "x" || properties[1] != "y" ||
86  properties[2] != "z") {
87  throw IoError(
88  "Currently, only files where x, y, z are the first 3 float properties are supported");
89  }
90 
91  // parse the vertex data
92  Array<Vector> vertices;
93  while (vertices.size() < vertexCnt) {
94  std::getline(ifs, line);
95  if (ifs.fail()) {
96  break;
97  }
98  Vector v;
99  std::stringstream ss(line);
101  ss >> v[X] >> v[Y] >> v[Z];
102  // skip the other properties
103  for (Size i = 0; i < properties.size() - 3; ++i) {
104  Float dummy;
105  ss >> dummy;
106  }
107  if (!ss) {
108  throw IoError("Invalid line format when reading the vertex data");
109  }
110  vertices.push(v);
111  }
112  if (vertices.size() != vertexCnt) {
113  throw IoError("Incorrect number of vertices in the file");
114  }
115 
116  // parse the faces and generate the list of triangles
117  Array<Triangle> triangles;
118  while (triangles.size() < faceCnt) {
119  std::getline(ifs, line);
120  if (ifs.fail()) {
121  break;
122  }
123  Size cnt, i, j, k;
124  std::stringstream ss(line);
125  ss >> cnt >> i >> j >> k;
126  if (!ss || cnt != 3) {
127  throw IoError("Invalid line format when reading the index data");
128  }
129  triangles.emplaceBack(vertices[i], vertices[j], vertices[k]);
130  }
131  return Expected<Array<Triangle>>(std::move(triangles));
132 
133  } catch (const std::exception& e) {
134  return makeUnexpected<Array<Triangle>>(e.what());
135  }
136 }
137 
138 TabFile::TabFile(const Float lengthUnit)
139  : lengthUnit(lengthUnit) {}
140 
142  (void)path;
143  (void)triangles;
145 }
146 
148  try {
149  std::ifstream ifs(path.native());
150  Size vertexCnt, triangleCnt;
151  ifs >> vertexCnt >> triangleCnt;
152  if (!ifs) {
153  throw IoError("Invalid format: cannot read file header");
154  }
155 
156  Array<Vector> vertices;
157  Vector v;
158  Size dummy;
159  for (Size vertexIdx = 0; vertexIdx < vertexCnt; ++vertexIdx) {
160  ifs >> dummy >> v[X] >> v[Y] >> v[Z];
161  v *= lengthUnit;
162  vertices.push(v);
163  }
164 
165  Array<Triangle> triangles;
166  Size i, j, k;
167  for (Size triangleIdx = 0; triangleIdx < triangleCnt; ++triangleIdx) {
168  ifs >> dummy >> i >> j >> k;
169  // indices start at 1 in .tab
170  triangles.emplaceBack(vertices[i - 1], vertices[j - 1], vertices[k - 1]);
171  }
172  return Expected<Array<Triangle>>(std::move(triangles));
173 
174  } catch (const std::exception& e) {
175  return makeUnexpected<Array<Triangle>>(e.what());
176  }
177 }
178 
180  (void)path;
181  (void)triangles;
183 }
184 
186  try {
187  std::ifstream ifs(path.native());
188  Array<Vector> vertices;
189  Array<Triangle> triangles;
190 
191  std::string identifier;
192  while (ifs) {
193  ifs >> identifier;
194  if (identifier == "v") {
195  Vector v;
196  ifs >> v[X] >> v[Y] >> v[Z];
197  vertices.push(v);
198  } else if (identifier == "f") {
199  Size i, j, k;
200  ifs >> i >> j >> k;
201  triangles.emplaceBack(vertices[i - 1], vertices[j - 1], vertices[k - 1]);
202  }
203  }
204 
205  return Expected<Array<Triangle>>(std::move(triangles));
206 
207  } catch (const std::exception& e) {
208  return makeUnexpected<Array<Triangle>>(e.what());
209  }
210 }
211 
213  const std::string extension = path.extension().native();
214  if (extension == "ply") {
215  return makeAuto<PlyFile>();
216  } else if (extension == "obj") {
217  return makeAuto<ObjFile>();
218  } else {
220  }
221 }
222 
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
constexpr char CODE_NAME[]
Definition: Globals.h:32
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
NAMESPACE_SPH_BEGIN constexpr INLINE T min(const T &f1, const T &f2)
Minimum & Maximum value.
Definition: MathBasic.h:15
constexpr Float EPS
Definition: MathUtils.h:30
AutoPtr< IMeshFile > getMeshFile(const Path &path)
Deduces mesh type from extension of given path.
Definition: MeshFile.cpp:212
Mesh getMeshFromTriangles(ArrayView< const Triangle > triangles, const Float eps)
Converts array of triangles into a mesh.
Definition: Mesh.cpp:83
#define NAMESPACE_SPH_END
Definition: Object.h:12
const NothingType NOTHING
Definition: Optional.h:16
const SuccessTag SUCCESS
Global constant for successful outcome.
Definition: Outcome.h:141
INLINE Outcome makeFailed(TArgs &&... args)
Constructs failed object with error message.
Definition: Outcome.h:157
@ Y
Definition: Vector.h:23
@ X
Definition: Vector.h:22
@ Z
Definition: Vector.h:24
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
StorageType & emplaceBack(TArgs &&... args)
Constructs a new element at the end of the array in place, using the provided arguments.
Definition: Array.h:332
INLINE TCounter size() const noexcept
Definition: Array.h:193
Wrapper of pointer that deletes the resource from destructor.
Definition: AutoPtr.h:15
Wrapper of type that either contains a value of given type, or an error message.
Definition: Expected.h:25
Exception thrown when file cannot be read, it has invalid format, etc.
Definition: Exceptions.h:31
virtual Expected< Array< Triangle > > load(const Path &path) override
Definition: MeshFile.cpp:185
virtual Outcome save(const Path &path, ArrayView< const Triangle > triangles) override
Definition: MeshFile.cpp:179
Object representing a path on a filesystem.
Definition: Path.h:17
std::string native() const
Returns the native version of the path.
Definition: Path.cpp:71
Path extension() const
Returns the extension of the filename.
Definition: Path.cpp:59
virtual Expected< Array< Triangle > > load(const Path &path) override
Definition: MeshFile.cpp:51
virtual Outcome save(const Path &path, ArrayView< const Triangle > triangles) override
Definition: MeshFile.cpp:7
virtual Expected< Array< Triangle > > load(const Path &path) override
Definition: MeshFile.cpp:147
virtual Outcome save(const Path &path, ArrayView< const Triangle > triangles) override
Definition: MeshFile.cpp:141
TabFile(const Float lengthUnit=1.e3_f)
Definition: MeshFile.cpp:138
Definition: Mesh.h:7
Array< Vector > vertices
Definition: Mesh.h:8
Array< Face > faces
Definition: Mesh.h:47