Carna  Version 3.3.2
MeshFactory.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 - 2015 Leonid Kostrykin
3  *
4  * Chair of Medical Engineering (mediTEC)
5  * RWTH Aachen University
6  * Pauwelsstr. 20
7  * 52074 Aachen
8  * Germany
9  *
10  */
11 
12 #ifndef MESHFACTORY_H_6014714286
13 #define MESHFACTORY_H_6014714286
14 
17 #include <Carna/base/IndexBuffer.h>
18 #include <Carna/base/ManagedMesh.h>
19 #include <Carna/base/Vertex.h>
20 #include <Carna/base/math.h>
21 #include <cstdint>
22 #include <unordered_set>
23 #include <functional>
24 #include <memory>
25 #include <istream>
26 #include <ios>
27 #include <string>
28 
33 namespace Carna
34 {
35 
36 namespace base
37 {
38 
39 
40 
41 // ----------------------------------------------------------------------------------
42 // MeshFactory
43 // ----------------------------------------------------------------------------------
44 
55 template< typename VertexType >
57 {
58 
59  template< typename VectorType >
60  static VertexType vertex( const VectorType& position, const VectorType& normal = VectorType(), const VectorType& color = VectorType() );
61 
62 public:
63 
68  static ManagedMesh< VertexType, uint8_t >& createBox( float width, float height, float depth );
69 
73 
81  static ManagedMesh< VertexType, uint16_t >& createBall( float radius, unsigned int degree = 3 );
82 
87 
95  inline static ManagedMesh< VertexType, uint32_t >& createFromSTL( const std::string& path );
96 
99  static ManagedMesh< VertexType, uint32_t >& createFromSTL( std::istream& stlStream );
100 
101 }; // MeshFactory
102 
103 
104 template< typename VertexType >
105 template< typename VectorType >
106 VertexType MeshFactory< VertexType >::vertex( const VectorType& position, const VectorType& normal, const VectorType& color )
107 {
108  VertexType vertex;
109  vertex.x = position.x();
110  vertex.y = position.y();
111  vertex.z = position.z();
112  vertex.setNormal( normal );
113  vertex.setColor ( color );
114  return vertex;
115 }
116 
117 
118 template< typename VertexType >
120 {
121  return createBox( size.x(), size.y(), size.z() );
122 }
123 
124 
125 template< typename VertexType >
127 {
128  const math::Matrix4f baseTransform = math::scaling4f( sizeX / 2, sizeY / 2, sizeZ / 2 );
129 
130  /* Define faces.
131  */
132  math::Matrix4f transforms[ 6 ];
133  transforms[ 0 ] = math::basis4f( math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( -1, 0, 0 ) ); // left
134  transforms[ 1 ] = math::basis4f( math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( +1, 0, 0 ) ); // right
135  transforms[ 2 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, +1 ) ); // front
136  transforms[ 3 ] = math::basis4f( math::Vector3f( -1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, -1 ) ); // back
137  transforms[ 4 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ) ); // top
138  transforms[ 5 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, -1, 0 ) ); // bottom
139 
140  const std::size_t verticesCount = 6 * 4;
141  const std::size_t indicesCount = 6 * 2 * 3;
142 
143  typedef ManagedMesh< VertexType, uint8_t > MeshInstance;
144  typedef typename MeshInstance::Vertex Vertex;
145  typedef typename MeshInstance:: Index Index;
146  Vertex vertices[ verticesCount ];
147  Index indices[ indicesCount ];
148 
149  int lastVertex = -1;
150  int lastIndex = -1;
151 
152  /* Create vertices and indices.
153  */
154  for( unsigned int faceIndex = 0; faceIndex < 6; ++faceIndex )
155  {
156  const auto positionTransform = baseTransform * transforms[ faceIndex ];
157  const auto normalTransform = positionTransform.inverse().transpose();
158  const auto normalVector = ( normalTransform * math::Vector4f( 0, 0, 1, 0 ) ).normalized();
159 
160  vertices[ ++lastVertex ] = vertex< math::Vector4f >( positionTransform * math::Vector4f( -1, -1, 1, 1 ), normalVector );
161  vertices[ ++lastVertex ] = vertex< math::Vector4f >( positionTransform * math::Vector4f( +1, -1, 1, 1 ), normalVector );
162  vertices[ ++lastVertex ] = vertex< math::Vector4f >( positionTransform * math::Vector4f( +1, +1, 1, 1 ), normalVector );
163  vertices[ ++lastVertex ] = vertex< math::Vector4f >( positionTransform * math::Vector4f( -1, +1, 1, 1 ), normalVector );
164 
165  indices[ ++lastIndex ] = lastVertex - 3;
166  indices[ ++lastIndex ] = lastVertex - 2;
167  indices[ ++lastIndex ] = lastVertex;
168 
169  indices[ ++lastIndex ] = lastVertex;
170  indices[ ++lastIndex ] = lastVertex - 2;
171  indices[ ++lastIndex ] = lastVertex - 1;
172  }
173 
174  return MeshInstance::create
176  , vertices, verticesCount
177  , indices, indicesCount );
178 }
179 
180 
181 template< typename VertexType >
183 {
184  const math::Matrix4f baseTransform = math::scaling4f( radius, radius, radius );
185  const unsigned int verticesPerEdge = 2 + degree;
186  const unsigned int verticesPerSide = verticesPerEdge * verticesPerEdge;
187  const unsigned int facesPerSide = ( verticesPerEdge - 1 ) * ( verticesPerEdge - 1 );
188  const unsigned int indicesPerSide = 6 * facesPerSide;
189 
190  /* Define sides.
191  */
192  math::Matrix4f transforms[ 6 ];
193  transforms[ 0 ] = math::basis4f( math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( -1, 0, 0 ) ); // left
194  transforms[ 1 ] = math::basis4f( math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( +1, 0, 0 ) ); // right
195  transforms[ 2 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, +1 ) ); // front
196  transforms[ 3 ] = math::basis4f( math::Vector3f( -1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, -1 ) ); // back
197  transforms[ 4 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ) ); // top
198  transforms[ 5 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, -1, 0 ) ); // bottom
199 
200  const std::size_t verticesCount = 6 * verticesPerSide;
201  const std::size_t indicesCount = 6 * indicesPerSide;
202  CARNA_ASSERT(indicesCount < ( 1 << 16 ));
203 
204  typedef ManagedMesh< VertexType, uint16_t > MeshInstance;
205  typedef typename MeshInstance::Vertex Vertex;
206  typedef typename MeshInstance:: Index Index;
207  Vertex vertices[ verticesCount ];
208  Index indices[ indicesCount ];
209 
210  int lastVertex = -1;
211  int lastIndex = -1;
212 
213  /* Create vertices and indices.
214  */
215  for( unsigned int sideIndex = 0; sideIndex < 6; ++sideIndex )
216  {
217  const auto positionTransform = baseTransform * transforms[ sideIndex ];
218  const auto normalTransform = positionTransform.inverse().transpose();
219 
220  for( unsigned int y = 0; y < verticesPerEdge; ++y )
221  for( unsigned int x = 0; x < verticesPerEdge; ++x )
222  {
223  const float fx = 2 * x / float( verticesPerEdge - 1 );
224  const float fy = 2 * y / float( verticesPerEdge - 1 );
225  const auto position = math::Vector3f( -1 + fx, -1 + fy, 1 ).normalized();
226  vertices[ ++lastVertex ] = vertex< math::Vector4f >
227  ( positionTransform * math::Vector4f( position.x(), position.y(), position.z(), 1 )
228  , normalTransform * math::Vector4f( position.x(), position.y(), position.z(), 0 )
229  );
230  }
231 
232  for( unsigned int y = 0; y < verticesPerEdge - 1; ++y )
233  for( unsigned int x = 0; x < verticesPerEdge - 1; ++x )
234  {
235  const uint16_t ul = x + y * verticesPerEdge; // upper left
236  const uint16_t ur = x + 1 + y * verticesPerEdge; // upper right
237  const uint16_t ll = x + ( y + 1 ) * verticesPerEdge; // lower left
238  const uint16_t lr = x + 1 + ( y + 1 ) * verticesPerEdge; // lower right
239 
240  indices[ ++lastIndex ] = verticesPerSide * sideIndex + ul;
241  indices[ ++lastIndex ] = verticesPerSide * sideIndex + lr;
242  indices[ ++lastIndex ] = verticesPerSide * sideIndex + ll;
243 
244  indices[ ++lastIndex ] = verticesPerSide * sideIndex + ul;
245  indices[ ++lastIndex ] = verticesPerSide * sideIndex + ur;
246  indices[ ++lastIndex ] = verticesPerSide * sideIndex + lr;
247  }
248  }
249 
250  return MeshInstance::create
252  , vertices, verticesCount
253  , indices, indicesCount );
254 }
255 
256 
257 template< typename VertexType >
259 {
260  typedef ManagedMesh< VertexType, uint8_t > MeshInstance;
261  typedef typename MeshInstance::Vertex Vertex;
262  typedef typename MeshInstance:: Index Index;
263 
264  Vertex vertex;
265  Index index = 0;
266 
267  return MeshInstance::create( IndexBufferBase::PRIMITIVE_TYPE_POINTS, &vertex, 1, &index, 1 );
268 }
269 
270 template< typename VertexType >
272 {
273  return createFromSTL( std::fstream(path, std::ios::in | std::ios::binary) );
274 }
275 
276 template< typename VertexType >
278 {
279  auto origExceptMask = stlStream.exceptions();
280  stlStream.exceptions(std::istream::failbit | std::istream::badbit | std::istream::eofbit);
281 
282  uint32_t amountTriangles;
283 
284  //discard first 80 bytes
285  stlStream.seekg(stlStream.beg + 80);
286 
287  //read amount of triangles (32bit-uint)
288  stlStream.read(reinterpret_cast<char*>(&amountTriangles), 4);
289 
290  typedef ManagedMesh< VertexType, uint32_t > MeshInstance;
291  typedef typename MeshInstance::Vertex Vertex;
292  typedef typename MeshInstance::Index Index;
293  typedef typename std::pair< Vertex, std::size_t > VertexIndexPair;
294 
295  std::size_t indicesCount = amountTriangles * 3;
296  std::unique_ptr<Index[]> indices (new Index [indicesCount]);
297  std::unique_ptr<Vertex[]> vertices(new Vertex [indicesCount]);
298 
299  std::function<std::size_t(const VertexIndexPair&)> vertexHash =
300  [](const VertexIndexPair& vertAndIndex) -> std::size_t
301  {
302  //creates combined hash value of the 3 public members "x","y","z" of a Vertex object; ignores the second member of pair
303  //This hash-combine-technique is taken from : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf (Page 2)
304  std::size_t hashVal = std::hash<decltype(vertAndIndex.first.x)>()(vertAndIndex.first.x);
305  hashVal ^= std::hash<decltype(vertAndIndex.first.y)>()(vertAndIndex.first.y) + 0x9e3779b9 + (hashVal << 6) + (hashVal >> 2);
306  hashVal ^= std::hash<decltype(vertAndIndex.first.z)> ()(vertAndIndex.first.z) + 0x9e3779b9 + (hashVal << 6) + (hashVal >> 2);
307  return hashVal;
308  };
309 
310  std::function<std::size_t(const VertexIndexPair&, const VertexIndexPair&)> vertexComp =
311  [](const VertexIndexPair& vertAndIndex1, const VertexIndexPair& vertAndIndex2) -> bool
312  {
313  //checks whether the members "x", "y", "z" of two Vertex objects are equal
314  return ((vertAndIndex1.first.x) == (vertAndIndex2.first.x)) && ((vertAndIndex1.first.y) == (vertAndIndex2.first.y)) && ((vertAndIndex1.first.z) == (vertAndIndex2.first.z));
315  };
316 
317  std::unordered_set< VertexIndexPair, decltype(vertexHash), decltype(vertexComp) > vertsWithArrIndices(amountTriangles * 3, vertexHash, vertexComp);
318 
319  std::size_t indicesItCount = 0;
320  std::size_t verticesItCount = 0;
321 
322  //read triangles
323  for (unsigned int i = 0; i < amountTriangles; i++)
324  {
325  //discard normal
326  stlStream.seekg(12, std::ios_base::cur);
327 
328  //read vertices
329  for (unsigned int j = 0; j < 3; j++) //read 3 vertices
330  {
331  float x, y, z;
332 
333  //read 1 vertex
334  stlStream.read(reinterpret_cast<char*>(&x), 4);
335  stlStream.read(reinterpret_cast<char*>(&y), 4);
336  stlStream.read(reinterpret_cast<char*>(&z), 4);
337 
338  Vertex vert;
339  vert.x = x;
340  vert.y = y;
341  vert.z = z;
342  //vert gets invalidated here
343  auto emplRes = vertsWithArrIndices.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(vert)), std::forward_as_tuple(verticesItCount));
344 
345  if (emplRes.second)
346  {
347  vertices[verticesItCount++] = (emplRes.first)->first;
348  }
349 
350  indices[indicesItCount++] = (emplRes.first)->second;
351  }
352 
353  //discard 2 bytes
354  stlStream.seekg(2, std::ios_base::cur);
355  }
356 
357  stlStream.exceptions(origExceptMask);
358 
359  return MeshInstance::create
361  , vertices.get(), verticesItCount
362  , indices.get(), indicesCount);
363 }
364 
365 
366 
367 } // namespace Carna :: base
368 
369 } // namespace Carna
370 
371 #endif // MESHFACTORY_H_6014714286
Defines Carna::base::math namespace and CARNA_FOR_VECTOR3UI.
Matrix4f scaling4f(float x, float y, float z)
Creates scaling matrix for homogeneous coordinates.
Definition: math.h:292
static const unsigned int PRIMITIVE_TYPE_POINTS
Draws points. Indicates that each index makes up a single point.
Definition: IndexBuffer.h:102
static ManagedMesh< VertexType, uint8_t > & createBox(float width, float height, float depth)
Creates box with width, height and depth. The box is centered in .
Definition: MeshFactory.h:126
Eigen::Matrix< float, 4, 1 > Vector4f
Defines vector.
Definition: math.h:195
Defines Carna::base::VertexAttributes.
static const unsigned int PRIMITIVE_TYPE_TRIANGLES
Draws triangles. Indicates that the indices make up the th triangle with .
Definition: IndexBuffer.h:65
Matrix4f basis4f(const Vector4f &x, const Vector4f &y, const Vector4f &z, const Vector4f &t=Vector4f(0, 0, 0, 0))
Creates basis embedded into a homogenous coordinates matrix.
Definition: math.h:242
Eigen::Matrix< float, 3, 1 > Vector3f
Defines vector.
Definition: math.h:196
Defines Carna::base::IndexBuffer.
Creates simple predefined ManagedMesh instances.
Definition: MeshFactory.h:56
Defines Carna::base::ManagedMesh.
Eigen::Matrix< float, 4, 4, Eigen::ColMajor > Matrix4f
Defines matrix.
Definition: math.h:193
Defines Carna::base::PVertex, Carna::base::PNVertex, Carna::base::VertexPosition, Carna::base::Vertex...
Implements MeshBase class for particular VertexType and IndexType.
Definition: ManagedMesh.h:147
static ManagedMesh< VertexType, uint8_t > & createPoint()
Creates mesh that consists of a single point.
Definition: MeshFactory.h:258
static ManagedMesh< VertexType, uint16_t > & createBall(float radius, unsigned int degree=3)
Creates sphere with radius and a vertices number determined by degree. The ball is centered in ...
Definition: MeshFactory.h:182
#define CARNA_ASSERT(expression)
If the given expression is false, a break point is raised in debug mode and an AssertionFailure throw...
Defines Carna::base::VertexBuffer.
static ManagedMesh< VertexType, uint32_t > & createFromSTL(const std::string &path)
Creates mesh from an STL file.
Definition: MeshFactory.h:271