opensurgsim
TriangleMesh-inl.h
1 // This file is a part of the OpenSurgSim project.
2 // Copyright 2013, SimQuest Solutions Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #ifndef SURGSIM_DATASTRUCTURES_TRIANGLEMESH_INL_H
17 #define SURGSIM_DATASTRUCTURES_TRIANGLEMESH_INL_H
18 
19 #include "SurgSim/Framework/Log.h"
20 
21 
22 namespace SurgSim
23 {
24 namespace DataStructures
25 {
26 
27 template <class VertexData, class EdgeData, class TriangleData>
29 {
30 }
31 
32 template <class VertexData, class EdgeData, class TriangleData>
35  Vertices<VertexData>::Vertices(other),
36  SurgSim::Framework::Asset(),
37  m_edges(other.getEdges()),
38  m_triangles(other.getTriangles()),
39  m_freeTriangles(other.m_freeTriangles)
40 {
41 }
42 
43 template <class VertexData, class EdgeData, class TriangleData>
44 template <class V, class E, class T>
46  Vertices<VertexData>::Vertices(other),
47  SurgSim::Framework::Asset()
48 {
49  m_edges.reserve(other.getEdges().size());
50  for (auto& edge : other.getEdges())
51  {
52  addEdge(EdgeType(edge));
53  }
54 
55  size_t index = 0;
56  m_triangles.reserve(other.getTriangles().size());
57  for (auto& triangle : other.getTriangles())
58  {
59  addTriangle(TriangleType(triangle));
60  if (!triangle.isValid)
61  {
62  m_freeTriangles.push_back(index);
63  }
64  ++index;
65  }
66 }
67 
68 template <class VertexData, class EdgeData, class TriangleData>
70 {
71 }
72 
73 template <class VertexData, class EdgeData, class TriangleData>
75 {
76  return m_className;
77 }
78 
79 
80 template <class VertexData, class EdgeData, class TriangleData>
82 {
83  m_edges.push_back(edge);
84  return m_edges.size() - 1;
85 }
86 
87 template <class VertexData, class EdgeData, class TriangleData>
89 {
90  size_t result;
91 
92  SURGSIM_ASSERT(triangle.isValid) << "Cannot insert invalid triangle into mesh.";
93 
94  if (m_freeTriangles.empty())
95  {
96  m_triangles.push_back(triangle);
97  result = m_triangles.size() - 1;
98  }
99  else
100  {
101  result = m_freeTriangles.back();
102  m_freeTriangles.pop_back();
103  m_triangles[result] = triangle;
104  }
105 
106  return result;
107 }
108 
109 template <class VertexData, class EdgeData, class TriangleData>
111 {
112  return m_edges.size();
113 }
114 
115 template <class VertexData, class EdgeData, class TriangleData>
117 {
118  return m_triangles.size() - m_freeTriangles.size();
119 }
120 
121 template <class VertexData, class EdgeData, class TriangleData>
122 const std::vector<typename TriangleMesh<VertexData, EdgeData, TriangleData>::EdgeType>&
124 {
125  return m_edges;
126 }
127 
128 template <class VertexData, class EdgeData, class TriangleData>
129 std::vector<typename TriangleMesh<VertexData, EdgeData, TriangleData>::EdgeType>&
131 {
132  return m_edges;
133 }
134 
135 template <class VertexData, class EdgeData, class TriangleData>
136 const std::vector<typename TriangleMesh<VertexData, EdgeData, TriangleData>::TriangleType>&
138 {
139  return m_triangles;
140 }
141 
142 template <class VertexData, class EdgeData, class TriangleData>
143 std::vector<typename TriangleMesh<VertexData, EdgeData, TriangleData>::TriangleType>&
145 {
146  return m_triangles;
147 }
148 
149 template <class VertexData, class EdgeData, class TriangleData>
152 {
153  return m_edges[id];
154 }
155 
156 template <class VertexData, class EdgeData, class TriangleData>
159 {
160  return m_edges[id];
161 }
162 
163 template <class VertexData, class EdgeData, class TriangleData>
164 std::array<SurgSim::Math::Vector3d, 2>
166 {
167  auto& ids = getEdge(id).verticesId;
168  std::array<SurgSim::Math::Vector3d, 2> result =
169  {{
170  Vertices<VertexData>::getVertex(ids[0]).position,
171  Vertices<VertexData>::getVertex(ids[1]).position
172  }};
173 
174  return result;
175 }
176 
177 template <class VertexData, class EdgeData, class TriangleData>
180 {
181  auto const& triangle = m_triangles[id];
182  SURGSIM_ASSERT(triangle.isValid)
183  << "Attempted to access invalid or deleted triangle " << id << " have " << getNumTriangles();
184  return triangle;
185 }
186 
187 template <class VertexData, class EdgeData, class TriangleData>
190 {
191  auto& triangle = m_triangles[id];
192  SURGSIM_ASSERT(triangle.isValid) << "Attempted to access invalid or deleted triangle.";
193  return triangle;
194 }
195 
196 template <class VertexData, class EdgeData, class TriangleData>
198 {
199  auto& triangle = m_triangles[id];
200  if (triangle.isValid)
201  {
202  triangle.isValid = false;
203  m_freeTriangles.push_back(id);
204  }
205 }
206 
207 template <class VertexData, class EdgeData, class TriangleData>
208 std::array<SurgSim::Math::Vector3d, 3>
210 {
211  auto& ids = getTriangle(id).verticesId;
212  std::array<SurgSim::Math::Vector3d, 3> result =
213  {{
214  Vertices<VertexData>::getVertex(ids[0]).position,
215  Vertices<VertexData>::getVertex(ids[1]).position,
216  Vertices<VertexData>::getVertex(ids[2]).position
217  }};
218 
219  return result;
220 }
221 
222 template <class VertexData, class EdgeData, class TriangleData>
224 {
227 
228  size_t numVertices = Vertices<VertexData>::getNumVertices();
229 
230  // Test edges validity
231  for (typename std::vector<EdgeType>::const_iterator it = m_edges.begin(); it != m_edges.end(); ++it)
232  {
233  for (int vertexId = 0; vertexId < 2; vertexId++)
234  {
235  if (it->verticesId[vertexId] >= numVertices)
236  {
237  return false;
238  }
239  }
240  }
241 
242  // Test triangles validity
243  for (typename std::vector<TriangleType>::const_iterator it = m_triangles.begin(); it != m_triangles.end(); ++it)
244  {
245  for (int vertexId = 0; vertexId < 3; vertexId++)
246  {
247  if (it->verticesId[vertexId] >= numVertices)
248  {
249  return false;
250  }
251  }
252  }
253 
254  return true;
255 }
256 
257 
258 template <class VertexData, class EdgeData, class TriangleData>
260 {
261  m_edges.clear();
262 }
263 
264 template <class VertexData, class EdgeData, class TriangleData>
266 {
267  m_triangles.clear();
268  m_freeTriangles.clear();
269 }
270 
271 template <class VertexData, class EdgeData, class TriangleData>
273 {
274  const TriangleMesh& triangleMesh = static_cast<const TriangleMesh&>(mesh);
275  return Vertices<VertexData>::isEqual(triangleMesh) && m_edges == triangleMesh.getEdges() &&
276  m_triangles == triangleMesh.getTriangles();
277 }
278 
279 template <class VertexData, class EdgeData, class TriangleData>
281 {
282  PlyReader reader(fileName);
283  if (! reader.isValid())
284  {
286  << "'" << fileName << "' is an invalid .ply file.";
287  return false;
288  }
289 
291  auto delegate = std::make_shared<TriangleMeshPlyReaderDelegate<MeshType>>(this->shared_from_this());
292  if (! reader.parseWithDelegate(delegate))
293  {
295  << "The input file '" << fileName << "' does not have the property required by triangle mesh.";
296  return false;
297  }
298 
299  return true;
300 }
301 
302 template <class VertexData, class EdgeData, class TriangleData>
304 {
305  doClearTriangles();
306  doClearEdges();
307  doClearVertices();
308 }
309 
310 template <class VertexData, class EdgeData, class TriangleData>
312  Vertices<VertexData>::Vertices(std::move(other))
313 {
314  doClearTriangles();
315  doClearEdges();
316  std::swap(m_triangles, other.m_triangles);
317  std::swap(m_edges, other.m_edges);
318  std::swap(m_freeTriangles, other.m_freeTriangles);
319 }
320 
321 template <class VertexData, class EdgeData, class TriangleData>
324 {
326  m_triangles = other.m_triangles;
327  m_edges = other.m_edges;
328  m_freeTriangles = other.m_freeTriangles;
329  return *this;
330 }
331 
332 template <class VertexData, class EdgeData, class TriangleData>
335 {
336  Vertices<VertexData>::operator=(std::move(other));
337  doClearTriangles();
338  doClearEdges();
339  std::swap(m_triangles, other.m_triangles);
340  std::swap(m_edges, other.m_edges);
341  std::swap(m_freeTriangles, other.m_freeTriangles);
342  return *this;
343 }
344 
345 template <class VertexData, class EdgeData, class TriangleData>
347 {
348  std::fstream out(fileName, std::ios::out);
349 
350  if (out.is_open())
351  {
352  out << "ply" << std::endl;
353  out << "format ascii 1.0" << std::endl;
354  out << "comment Created by OpenSurgSim, www.opensurgsim.org" << std::endl;
355  out << "element vertex " << getNumVertices() << std::endl;
356  out << "property float x\nproperty float y\nproperty float z" << std::endl;
357  out << "element face " << getNumTriangles() << std::endl;
358  out << "property list uchar uint vertex_indices" << std::endl;
359  out << "end_header" << std::endl;
360 
361  for (const auto& vertex : getVertices())
362  {
363  out << vertex.position[0] << " " << vertex.position[1] << " " << vertex.position[2] << std::endl;
364  }
365 
366  for (const auto& tri : getTriangles())
367  {
368  out << "3 " << tri.verticesId[0] << " " << tri.verticesId[1] << " " << tri.verticesId[2] << std::endl;
369  }
370 
371  if (out.bad())
372  {
374  << "There was a problem writing " << fileName;
375  }
376 
377  out.close();
378  }
379  else
380  {
382  << "Could not open " << fileName << " for writing.";
383  }
384 
385 }
386 
387 
388 
389 }; // namespace DataStructures
390 }; // namespace SurgSim
391 
392 #endif // SURGSIM_DATASTRUCTURES_TRIANGLEMESH_INL_H
Wraps glewInit() to separate the glew opengl definitions from the osg opengl definitions only imgui n...
Definition: AddRandomSphereBehavior.cpp:36
#define SURGSIM_LOG_WARNING(logger)
Logs a message to the specified logger at the WARNING level.
Definition: LogMacros.h:96
Definition: MockObjects.h:47
bool isValid() const
Test if the TriangleMesh is valid (valid vertex Ids used in all MeshElements)
Definition: TriangleMesh-inl.h:223
#define SURGSIM_ASSERT(condition)
Assert that condition is true.
Definition: Assert.h:77
The convenience header that provides the entirety of the logging API.
Wrapper for the C .ply file parser This class wraps the main functionality for the original C ...
Definition: PlyReader.h:85
const std::vector< TriangleType > & getTriangles() const
Retrieve all triangles.
Definition: TriangleMesh-inl.h:137
void save(const std::string &fileName)
Save the triangle mesh in the ply format.
Definition: TriangleMesh-inl.h:346
TriangleMesh()
Constructor. The mesh is initially empty (no vertices, no edges, no triangles).
Definition: TriangleMesh-inl.h:28
void clear()
Clear mesh to return to an empty state (no vertices).
Definition: Vertices-inl.h:80
Basic class for storing Triangle Meshes, handling basic vertex, edge, and triangle functionality...
Definition: TriangleMesh.h:62
Element structure for meshes.
Definition: MeshElement.h:44
bool isValid() const
Query if this object is valid.
Definition: PlyReader.cpp:92
static std::shared_ptr< Logger > getDefaultLogger()
Get default logger.
Definition: Logger.h:116
const std::vector< EdgeType > & getEdges() const
Retrieve all edges.
Definition: TriangleMesh-inl.h:123
bool parseWithDelegate(std::shared_ptr< PlyReaderDelegate > delegate)
Sets a delegate for parsing and then parse the file.
Definition: PlyReader.cpp:336
Base class for mesh structures, handling basic vertex functionality.
Definition: Vertices.h:51
#define SURGSIM_LOG_SEVERE(logger)
Logs a message to the specified logger at the SEVERE level.
Definition: LogMacros.h:106
bool isValid
Is this a valid element.
Definition: MeshElement.h:84