CARLA
Mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #include <carla/geom/Mesh.h>
8 
9 #include <string>
10 #include <sstream>
11 #include <ios>
12 #include <iostream>
13 #include <fstream>
14 
15 #include <carla/geom/Math.h>
16 
17 namespace carla {
18 namespace geom {
19 
20  bool Mesh::IsValid() const {
21  // should be at least some one vertex
22  if (_vertices.empty()) {
23  std::cout << "Mesh validation error: there are no vertices in the mesh." << std::endl;
24  return false;
25  }
26 
27  // if there are indices, the amount must be multiple of 3
28  if (!_indexes.empty() && _indexes.size() % 3 != 0) {
29  std::cout << "Mesh validation error: the index amount must be multiple of 3." << std::endl;
30  return false;
31  }
32 
33  if (!_materials.empty() && _materials.back().index_end == 0) {
34  std::cout << "Mesh validation error: last material was not closed." << std::endl;
35  return false;
36  }
37 
38  return true;
39  }
40 
41  // e.g:
42  // 1 3 5 7
43  // #---#---#---#
44  // | / | / | / |
45  // #---#---#---#
46  // 2 4 6 8
47  void Mesh::AddTriangleStrip(const std::vector<Mesh::vertex_type> &vertices) {
48  if (vertices.size() == 0) {
49  return;
50  }
51  DEBUG_ASSERT(vertices.size() >= 3);
52  size_t i = GetVerticesNum() + 2;
53  AddVertices(vertices);
54  bool index_clockwise = true;
55  while (i < GetVerticesNum()) {
56  index_clockwise = !index_clockwise;
57  if (index_clockwise) {
58  AddIndex(i + 1);
59  AddIndex(i);
60  AddIndex(i - 1);
61  } else {
62  AddIndex(i - 1);
63  AddIndex(i);
64  AddIndex(i + 1);
65  }
66  ++i;
67  }
68  }
69 
70  // e.g:
71  // 2 1 6
72  // #---#---#
73  // | / | \ |
74  // #---#---#
75  // 3 4 5
76  void Mesh::AddTriangleFan(const std::vector<Mesh::vertex_type> &vertices) {
77  DEBUG_ASSERT(vertices.size() >= 3);
78  const size_t initial_index = GetVerticesNum() + 1;
79  size_t i = GetVerticesNum() + 2;
80  AddVertices(vertices);
81  while (i < GetVerticesNum()) {
82  AddIndex(initial_index);
83  AddIndex(i);
84  AddIndex(i + 1);
85  ++i;
86  }
87  }
88 
90  _vertices.push_back(vertex);
91  }
92 
93  void Mesh::AddVertices(const std::vector<Mesh::vertex_type> &vertices) {
94  std::copy(vertices.begin(), vertices.end(), std::back_inserter(_vertices));
95  }
96 
98  _normals.push_back(normal);
99  }
100 
102  _indexes.push_back(index);
103  }
104 
105  void Mesh::AddUV(uv_type uv) {
106  _uvs.push_back(uv);
107  }
108 
109  void Mesh::AddUVs(const std::vector<uv_type> & uv) {
110  std::copy(uv.begin(), uv.end(), std::back_inserter(_uvs));
111  }
112 
113  void Mesh::AddMaterial(const std::string &material_name) {
114  const size_t open_index = _indexes.size();
115  if (!_materials.empty()) {
116  if (_materials.back().index_end == 0) {
117  // @todo: change this comment to a debug warning
118  // std::cout << "last material was not closed, closing it..." << std::endl;
119  EndMaterial();
120  }
121  }
122  if (open_index % 3 != 0) {
123  std::cout << "open_index % 3 != 0" << std::endl;
124  return;
125  }
126  _materials.emplace_back(material_name, open_index, 0);
127  }
128 
130  const size_t close_index = _indexes.size();
131  if (_materials.empty() ||
132  _materials.back().index_start == close_index ||
133  _materials.back().index_end != 0) {
134  // @todo: change this comment to a debug warning
135  // std::cout << "WARNING: Bad end of material. Material not started." << std::endl;
136  return;
137  }
138  if (_indexes.empty() || close_index % 3 != 0) {
139  // @todo: change this comment to a debug warning
140  // std::cout << "WARNING: Bad end of material. Face not started/ended." << std::endl;
141  return;
142  }
143  _materials.back().index_end = close_index;
144  }
145 
146  std::string Mesh::GenerateOBJ() const {
147  if (!IsValid()) {
148  return "";
149  }
150  std::stringstream out;
151  out << std::fixed; // Avoid using scientific notation
152 
153  out << "# List of geometric vertices, with (x, y, z) coordinates." << std::endl;
154  for (auto &v : _vertices) {
155  out << "v " << v.x << " " << v.y << " " << v.z << std::endl;
156  }
157 
158  if (!_uvs.empty()) {
159  out << std::endl << "# List of texture coordinates, in (u, v) coordinates, these will vary between 0 and 1." << std::endl;
160  for (auto &vt : _uvs) {
161  out << "vt " << vt.x << " " << vt.y << std::endl;
162  }
163  }
164 
165  if (!_normals.empty()) {
166  out << std::endl << "# List of vertex normals in (x, y, z) form; normals might not be unit vectors." << std::endl;
167  for (auto &vn : _normals) {
168  out << "vn " << vn.x << " " << vn.y << " " << vn.z << std::endl;
169  }
170  }
171 
172  if (!_indexes.empty()) {
173  out << std::endl << "# Polygonal face element." << std::endl;
174  auto it_m = _materials.begin();
175  auto it = _indexes.begin();
176  size_t index_counter = 0u;
177  while (it != _indexes.end()) {
178  // While exist materials
179  if (it_m != _materials.end()) {
180  // If the current material ends at this index
181  if (it_m->index_end == index_counter) {
182  ++it_m;
183  }
184  // If the current material start at this index
185  if (it_m->index_start == index_counter) {
186  out << "\nusemtl " << it_m->name << std::endl;
187  }
188  }
189 
190  // Add the actual face using the 3 consecutive indices
191  out << "f " << *it; ++it;
192  out << " " << *it; ++it;
193  out << " " << *it << std::endl; ++it;
194 
195  index_counter += 3;
196  }
197  }
198 
199  return out.str();
200  }
201 
202  std::string Mesh::GenerateOBJForRecast() const {
203  if (!IsValid()) {
204  return "";
205  }
206  std::stringstream out;
207  out << std::fixed; // Avoid using scientific notation
208 
209  out << "# List of geometric vertices, with (x, y, z) coordinates." << std::endl;
210  for (auto &v : _vertices) {
211  // Switched "y" and "z" for Recast library
212  out << "v " << v.x << " " << v.z << " " << v.y << std::endl;
213  }
214 
215  if (!_indexes.empty()) {
216  out << std::endl << "# Polygonal face element." << std::endl;
217  auto it_m = _materials.begin();
218  auto it = _indexes.begin();
219  size_t index_counter = 0u;
220  while (it != _indexes.end()) {
221  // While exist materials
222  if (it_m != _materials.end()) {
223  // If the current material ends at this index
224  if (it_m->index_end == index_counter) {
225  ++it_m;
226  }
227  // If the current material start at this index
228  if (it_m->index_start == index_counter) {
229  out << "\nusemtl " << it_m->name << std::endl;
230  }
231  }
232  // Add the actual face using the 3 consecutive indices
233  // Changes the face build direction to clockwise since
234  // the space has changed.
235  out << "f " << *it; ++it;
236  const auto i_2 = *it; ++it;
237  const auto i_3 = *it; ++it;
238  out << " " << i_3 << " " << i_2 << std::endl;
239  index_counter += 3;
240  }
241  }
242 
243  return out.str();
244  }
245 
246  std::string Mesh::GeneratePLY() const {
247  if (!IsValid()) {
248  return "Invalid Mesh";
249  }
250  // Generate header
251  std::stringstream out;
252  return out.str();
253  }
254 
255  const std::vector<Mesh::vertex_type> &Mesh::GetVertices() const {
256  return _vertices;
257  }
258 
259  std::vector<Mesh::vertex_type> &Mesh::GetVertices() {
260  return _vertices;
261  }
262 
263  size_t Mesh::GetVerticesNum() const {
264  return _vertices.size();
265  }
266 
267  const std::vector<Mesh::normal_type> &Mesh::GetNormals() const {
268  return _normals;
269  }
270 
271  const std::vector<Mesh::index_type> &Mesh::GetIndexes() const {
272  return _indexes;
273  }
274 
275  std::vector<Mesh::index_type>& Mesh::GetIndexes() {
276  return _indexes;
277  }
278  size_t Mesh::GetIndexesNum() const {
279  return _indexes.size();
280  }
281 
282  const std::vector<Mesh::uv_type> &Mesh::GetUVs() const {
283  return _uvs;
284  }
285 
286  const std::vector<Mesh::material_type> &Mesh::GetMaterials() const {
287  return _materials;
288  }
289 
290  size_t Mesh::GetLastVertexIndex() const {
291  return _vertices.size();
292  }
293 
294  Mesh& Mesh::ConcatMesh(const Mesh& rhs, int num_vertices_to_link) {
295 
296  if (!rhs.IsValid()){
297  return *this += rhs;
298  }
299  const size_t v_num = GetVerticesNum();
300  const size_t i_num = GetIndexesNum();
301 
302  _vertices.insert(
303  _vertices.end(),
304  rhs.GetVertices().begin(),
305  rhs.GetVertices().end());
306 
307  _normals.insert(
308  _normals.end(),
309  rhs.GetNormals().begin(),
310  rhs.GetNormals().end());
311 
312  const size_t vertex_to_start_concating = v_num - num_vertices_to_link;
313  for( size_t i = 1; i < num_vertices_to_link; ++i ) {
314  _indexes.push_back( vertex_to_start_concating + i );
315  _indexes.push_back( vertex_to_start_concating + i + 1 );
316  _indexes.push_back( v_num + i );
317 
318  _indexes.push_back( vertex_to_start_concating + i + 1);
319  _indexes.push_back( v_num + i + 1);
320  _indexes.push_back( v_num + i);
321  }
322 
323  std::transform(
324  rhs.GetIndexes().begin(),
325  rhs.GetIndexes().end(),
326  std::back_inserter(_indexes),
327  [=](size_t index) {return index + v_num; });
328 
329  _uvs.insert(
330  _uvs.end(),
331  rhs.GetUVs().begin(),
332  rhs.GetUVs().end());
333 
334  std::transform(
335  rhs.GetMaterials().begin(),
336  rhs.GetMaterials().end(),
337  std::back_inserter(_materials),
338  [=](MeshMaterial mat) {
339  mat.index_start += i_num;
340  mat.index_end += i_num;
341  return mat;
342  });
343 
344  return *this;
345  }
346 
347  Mesh &Mesh::operator+=(const Mesh &rhs) {
348  const size_t v_num = GetVerticesNum();
349  const size_t i_num = GetIndexesNum();
350 
351  _vertices.insert(
352  _vertices.end(),
353  rhs.GetVertices().begin(),
354  rhs.GetVertices().end());
355 
356  _normals.insert(
357  _normals.end(),
358  rhs.GetNormals().begin(),
359  rhs.GetNormals().end());
360 
361  std::transform(
362  rhs.GetIndexes().begin(),
363  rhs.GetIndexes().end(),
364  std::back_inserter(_indexes),
365  [=](size_t index) {return index + v_num;});
366 
367  _uvs.insert(
368  _uvs.end(),
369  rhs.GetUVs().begin(),
370  rhs.GetUVs().end());
371 
372  std::transform(
373  rhs.GetMaterials().begin(),
374  rhs.GetMaterials().end(),
375  std::back_inserter(_materials),
376  [=](MeshMaterial mat) {
377  mat.index_start += i_num;
378  mat.index_end += i_num;
379  return mat;
380  });
381 
382  return *this;
383  }
384 
385  Mesh operator+(const Mesh &lhs, const Mesh &rhs) {
386  Mesh m = lhs;
387  return m += rhs;
388  }
389 
390 } // namespace geom
391 } // namespace carla
size_t index_type
Definition: Mesh.h:49
void AddUV(uv_type uv)
Appends a vertex to the vertices list, they will be read 3 in 3.
Definition: Mesh.cpp:105
void AddVertex(vertex_type vertex)
Appends a vertex to the vertices list.
Definition: Mesh.cpp:89
bool IsValid() const
Check if the mesh can be valid or not.
Definition: Mesh.cpp:20
size_t GetVerticesNum() const
Definition: Mesh.cpp:263
void AddNormal(normal_type normal)
Appends a normal to the normal list.
Definition: Mesh.cpp:97
void AddTriangleFan(const std::vector< vertex_type > &vertices)
Adds a triangle fan to the mesh, vertex order is counterclockwise.
Definition: Mesh.cpp:76
const std::vector< normal_type > & GetNormals() const
Definition: Mesh.cpp:267
size_t GetIndexesNum() const
Definition: Mesh.cpp:278
Mesh & operator+=(const Mesh &rhs)
Merges two meshes into a single mesh.
Definition: Mesh.cpp:347
void AddIndex(index_type index)
Appends a index to the indexes list.
Definition: Mesh.cpp:101
size_t GetLastVertexIndex() const
Returns the index of the last added vertex (number of vertices).
Definition: Mesh.cpp:290
This file contains definitions of common data structures used in traffic manager. ...
Definition: Carla.cpp:133
const std::vector< index_type > & GetIndexes() const
Definition: Mesh.cpp:271
void AddVertices(const std::vector< vertex_type > &vertices)
Appends a vertex to the vertices list.
Definition: Mesh.cpp:93
friend Mesh operator+(const Mesh &lhs, const Mesh &rhs)
Definition: Mesh.cpp:385
void AddUVs(const std::vector< uv_type > &uv)
Appends uvs.
Definition: Mesh.cpp:109
void AddMaterial(const std::string &material_name)
Starts applying a new material to the new added triangles.
Definition: Mesh.cpp:113
void EndMaterial()
Stops applying the material to the new added triangles.
Definition: Mesh.cpp:129
#define DEBUG_ASSERT(predicate)
Definition: Debug.h:66
Material that references the vertex index start and end of a mesh where it is affecting.
Definition: Mesh.h:25
const std::vector< uv_type > & GetUVs() const
Definition: Mesh.cpp:282
std::vector< material_type > _materials
Definition: Mesh.h:243
const std::vector< material_type > & GetMaterials() const
Definition: Mesh.cpp:286
void AddTriangleStrip(const std::vector< vertex_type > &vertices)
Adds a triangle strip to the mesh, vertex order is counterclockwise.
Definition: Mesh.cpp:47
Mesh data container, validator and exporter.
Definition: Mesh.h:44
std::string GenerateOBJ() const
Returns a string containing the mesh encoded in OBJ.
Definition: Mesh.cpp:146
std::string GeneratePLY() const
Returns a string containing the mesh encoded in PLY.
Definition: Mesh.cpp:246
std::string GenerateOBJForRecast() const
Returns a string containing the mesh encoded in OBJ.
Definition: Mesh.cpp:202
Mesh & ConcatMesh(const Mesh &rhs, int num_vertices_to_link)
Merges two meshes into a single mesh.
Definition: Mesh.cpp:294
std::vector< index_type > _indexes
Definition: Mesh.h:239
std::vector< uv_type > _uvs
Definition: Mesh.h:241
const std::vector< vertex_type > & GetVertices() const
Definition: Mesh.cpp:255
std::vector< normal_type > _normals
Definition: Mesh.h:237
std::vector< vertex_type > _vertices
Definition: Mesh.h:235