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