LibCarna Version 3.4.0
Loading...
Searching...
No Matches
MeshFactory.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010 - 2016 Leonid Kostrykin
3 * Copyright (C) 2015 Tim Schroeder
4 *
5 * Chair of Medical Engineering (mediTEC)
6 * RWTH Aachen University
7 * Pauwelsstr. 20
8 * 52074 Aachen
9 * Germany
10 *
11 *
12 * Copyright (C) 2021 - 2025 Leonid Kostrykin
13 *
14 */
15
16#ifndef MESHFACTORY_H_6014714286
17#define MESHFACTORY_H_6014714286
18
25#include <cstdint>
26#include <unordered_set>
27#include <functional>
28#include <memory>
29#include <istream>
30#include <ios>
31#include <string>
32
38namespace LibCarna
39{
40
41namespace base
42{
43
44
45
46// ----------------------------------------------------------------------------------
47// MeshFactory
48// ----------------------------------------------------------------------------------
49
59template< typename VertexType >
61{
62
63 template< typename VectorType >
64 static VertexType vertex( const VectorType& position, const VectorType& normal = VectorType(), const VectorType& color = VectorType() );
65
66public:
67
72 static ManagedMesh< VertexType, uint8_t >& createBox( float width, float height, float depth );
73
77
82 static ManagedMesh< VertexType, uint16_t >& createBall( float radius, unsigned int degree = 3 );
83
88
92 static ManagedMesh< VertexType, uint16_t >& createLineStrip( const std::vector< math::Vector3f >& points );
93
99 inline static ManagedMesh< VertexType, uint32_t >& createFromSTL( const std::string& path );
100
104
105}; // MeshFactory
106
107
108template< typename VertexType >
109template< typename VectorType >
111{
112 VertexType vertex;
113 vertex.x = position.x();
114 vertex.y = position.y();
115 vertex.z = position.z();
116 vertex.setNormal( normal );
117 vertex.setColor ( color );
118 return vertex;
119}
120
121
122template< typename VertexType >
124{
125 return createBox( size.x(), size.y(), size.z() );
126}
127
128
129template< typename VertexType >
131{
133
134 /* Define faces.
135 */
137 transforms[ 0 ] = math::basis4f( math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( -1, 0, 0 ) ); // left
138 transforms[ 1 ] = math::basis4f( math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( +1, 0, 0 ) ); // right
139 transforms[ 2 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, +1 ) ); // front
140 transforms[ 3 ] = math::basis4f( math::Vector3f( -1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, -1 ) ); // back
141 transforms[ 4 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ) ); // top
142 transforms[ 5 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, -1, 0 ) ); // bottom
143
144 const std::size_t verticesCount = 6 * 4;
145 const std::size_t indicesCount = 6 * 2 * 3;
146
148 typedef typename MeshInstance::Vertex Vertex;
149 typedef typename MeshInstance:: Index Index;
150 Vertex vertices[ verticesCount ];
151 Index indices[ indicesCount ];
152
153 int lastVertex = -1;
154 int lastIndex = -1;
155
156 /* Create vertices and indices.
157 */
158 for( unsigned int faceIndex = 0; faceIndex < 6; ++faceIndex )
159 {
161 const auto normalTransform = positionTransform.inverse().transpose();
162 const auto normalVector = ( normalTransform * math::Vector4f( 0, 0, 1, 0 ) ).normalized();
163
168
169 indices[ ++lastIndex ] = lastVertex - 3;
170 indices[ ++lastIndex ] = lastVertex - 2;
171 indices[ ++lastIndex ] = lastVertex;
172
173 indices[ ++lastIndex ] = lastVertex;
174 indices[ ++lastIndex ] = lastVertex - 2;
175 indices[ ++lastIndex ] = lastVertex - 1;
176 }
177
178 return MeshInstance::create
180 , vertices, verticesCount
181 , indices, indicesCount );
182}
183
184
185template< typename VertexType >
187{
188 const math::Matrix4f baseTransform = math::scaling4f( radius, radius, radius );
189 const unsigned int verticesPerEdge = 2 + degree;
190 const unsigned int verticesPerSide = verticesPerEdge * verticesPerEdge;
191 const unsigned int facesPerSide = ( verticesPerEdge - 1 ) * ( verticesPerEdge - 1 );
192 const unsigned int indicesPerSide = 6 * facesPerSide;
193
194 /* Define sides.
195 */
197 transforms[ 0 ] = math::basis4f( math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( -1, 0, 0 ) ); // left
198 transforms[ 1 ] = math::basis4f( math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( +1, 0, 0 ) ); // right
199 transforms[ 2 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, +1 ) ); // front
200 transforms[ 3 ] = math::basis4f( math::Vector3f( -1, 0, 0 ), math::Vector3f( 0, +1, 0 ), math::Vector3f( 0, 0, -1 ) ); // back
201 transforms[ 4 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, -1 ), math::Vector3f( 0, +1, 0 ) ); // top
202 transforms[ 5 ] = math::basis4f( math::Vector3f( +1, 0, 0 ), math::Vector3f( 0, 0, +1 ), math::Vector3f( 0, -1, 0 ) ); // bottom
203
204 const std::size_t verticesCount = 6 * verticesPerSide;
205 const std::size_t indicesCount = 6 * indicesPerSide;
206 LIBCARNA_ASSERT(indicesCount < ( 1 << 16 ));
207
209 typedef typename MeshInstance::Vertex Vertex;
210 typedef typename MeshInstance:: Index Index;
211 Vertex vertices[ verticesCount ];
212 Index indices[ indicesCount ];
213
214 int lastVertex = -1;
215 int lastIndex = -1;
216
217 /* Create vertices and indices.
218 */
219 for( unsigned int sideIndex = 0; sideIndex < 6; ++sideIndex )
220 {
222 const auto normalTransform = positionTransform.inverse().transpose();
223
224 for( unsigned int y = 0; y < verticesPerEdge; ++y )
225 for( unsigned int x = 0; x < verticesPerEdge; ++x )
226 {
227 const float fx = 2 * x / float( verticesPerEdge - 1 );
228 const float fy = 2 * y / float( verticesPerEdge - 1 );
229 const auto position = math::Vector3f( -1 + fx, -1 + fy, 1 ).normalized();
231 ( positionTransform * math::Vector4f( position.x(), position.y(), position.z(), 1 )
232 , normalTransform * math::Vector4f( position.x(), position.y(), position.z(), 0 )
233 );
234 }
235
236 for( unsigned int y = 0; y < verticesPerEdge - 1; ++y )
237 for( unsigned int x = 0; x < verticesPerEdge - 1; ++x )
238 {
239 const uint16_t ul = x + y * verticesPerEdge; // upper left
240 const uint16_t ur = x + 1 + y * verticesPerEdge; // upper right
241 const uint16_t ll = x + ( y + 1 ) * verticesPerEdge; // lower left
242 const uint16_t lr = x + 1 + ( y + 1 ) * verticesPerEdge; // lower right
243
244 indices[ ++lastIndex ] = verticesPerSide * sideIndex + ul;
245 indices[ ++lastIndex ] = verticesPerSide * sideIndex + lr;
246 indices[ ++lastIndex ] = verticesPerSide * sideIndex + ll;
247
248 indices[ ++lastIndex ] = verticesPerSide * sideIndex + ul;
249 indices[ ++lastIndex ] = verticesPerSide * sideIndex + ur;
250 indices[ ++lastIndex ] = verticesPerSide * sideIndex + lr;
251 }
252 }
253
254 return MeshInstance::create
256 , vertices, verticesCount
257 , indices, indicesCount );
258}
259
260
261template< typename VertexType >
263{
265 typedef typename MeshInstance::Vertex Vertex;
266 typedef typename MeshInstance:: Index Index;
267
268 Vertex vertex;
269 Index index = 0;
270
271 return MeshInstance::create( IndexBufferBase::PRIMITIVE_TYPE_POINTS, &vertex, 1, &index, 1 );
272}
273
274
275template< typename VertexType >
277{
278 return createFromSTL( std::fstream(path, std::ios::in | std::ios::binary) );
279}
280
281template< typename VertexType >
283{
284 auto origExceptMask = stlStream.exceptions();
285 stlStream.exceptions(std::istream::failbit | std::istream::badbit | std::istream::eofbit);
286
288
289 //discard first 80 bytes
290 stlStream.seekg(stlStream.beg + 80);
291
292 //read amount of triangles (32bit-uint)
293 stlStream.read(reinterpret_cast<char*>(&amountTriangles), 4);
294
296 typedef typename MeshInstance::Vertex Vertex;
297 typedef typename MeshInstance::Index Index;
298 typedef typename std::pair< Vertex, std::size_t > VertexIndexPair;
299
300 std::size_t indicesCount = amountTriangles * 3;
301 std::unique_ptr<Index[]> indices (new Index [indicesCount]);
302 std::unique_ptr<Vertex[]> vertices(new Vertex [indicesCount]);
303
304 std::function<std::size_t(const VertexIndexPair&)> vertexHash =
305 [](const VertexIndexPair& vertAndIndex) -> std::size_t
306 {
307 //creates combined hash value of the 3 public members "x","y","z" of a Vertex object; ignores the second member of pair
308 //This hash-combine-technique is taken from : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf (Page 2)
309 std::size_t hashVal = std::hash<decltype(vertAndIndex.first.x)>()(vertAndIndex.first.x);
310 hashVal ^= std::hash<decltype(vertAndIndex.first.y)>()(vertAndIndex.first.y) + 0x9e3779b9 + (hashVal << 6) + (hashVal >> 2);
311 hashVal ^= std::hash<decltype(vertAndIndex.first.z)> ()(vertAndIndex.first.z) + 0x9e3779b9 + (hashVal << 6) + (hashVal >> 2);
312 return hashVal;
313 };
314
315 std::function<std::size_t(const VertexIndexPair&, const VertexIndexPair&)> vertexComp =
317 {
318 //checks whether the members "x", "y", "z" of two Vertex objects are equal
319 return ((vertAndIndex1.first.x) == (vertAndIndex2.first.x)) && ((vertAndIndex1.first.y) == (vertAndIndex2.first.y)) && ((vertAndIndex1.first.z) == (vertAndIndex2.first.z));
320 };
321
322 std::unordered_set< VertexIndexPair, decltype(vertexHash), decltype(vertexComp) > vertsWithArrIndices(amountTriangles * 3, vertexHash, vertexComp);
323
324 std::size_t indicesItCount = 0;
325 std::size_t verticesItCount = 0;
326
327 //read triangles
328 for (unsigned int i = 0; i < amountTriangles; i++)
329 {
330 //discard normal
331 stlStream.seekg(12, std::ios_base::cur);
332
333 //read vertices
334 for (unsigned int j = 0; j < 3; j++) //read 3 vertices
335 {
336 float x, y, z;
337
338 //read 1 vertex
339 stlStream.read(reinterpret_cast<char*>(&x), 4);
340 stlStream.read(reinterpret_cast<char*>(&y), 4);
341 stlStream.read(reinterpret_cast<char*>(&z), 4);
342
343 Vertex vert;
344 vert.x = x;
345 vert.y = y;
346 vert.z = z;
347 //vert gets invalidated here
348 auto emplRes = vertsWithArrIndices.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(vert)), std::forward_as_tuple(verticesItCount));
349
350 if (emplRes.second)
351 {
352 vertices[verticesItCount++] = (emplRes.first)->first;
353 }
354
355 indices[indicesItCount++] = (emplRes.first)->second;
356 }
357
358 //discard 2 bytes
359 stlStream.seekg(2, std::ios_base::cur);
360 }
361
362 stlStream.exceptions(origExceptMask);
363
364 return MeshInstance::create
366 , vertices.get(), verticesItCount
367 , indices.get(), indicesCount);
368}
369
370
371template< typename VertexType >
373{
374 LIBCARNA_ASSERT( points.size() >= 2 );
375
377 typedef typename MeshInstance::Vertex Vertex;
378 typedef typename MeshInstance:: Index Index;
379 Vertex vertices[ points.size() ];
380 Index indices[ points.size() ];
381
382 int lastVertex = -1;
383 int lastIndex = -1;
384
385 /* Create vertices and indices.
386 */
387 for( unsigned int pointIndex = 0; pointIndex < points.size(); ++pointIndex )
388 {
389 const auto pos = points[ pointIndex ];
390 vertices[ pointIndex ] = vertex< math::Vector4f >( math::Vector4f( pos.x(), pos.y(), pos.z(), 1 ) );
391 indices [ pointIndex ] = pointIndex;
392 }
393
394 return MeshInstance::create
396 , vertices, points.size()
397 , indices, points.size() );
398}
399
400
401
402} // namespace LibCarna :: base
403
404} // namespace LibCarna
405
406#endif // MESHFACTORY_H_6014714286
Defines LibCarna::base::IndexBuffer.
#define LIBCARNA_ASSERT(expression)
If the given expression is false, a break point is raised in debug mode and an AssertionFailure throw...
Defines LibCarna::base::ManagedMesh.
Defines LibCarna::base::VertexAttributes.
Defines LibCarna::base::VertexBuffer.
Defines LibCarna::base::PVertex, LibCarna::base::PNVertex, LibCarna::base::VertexPosition,...
Represents an association.
AssociatedObjectType * get() const
Returns raw pointer to the referenced object.
static const unsigned int PRIMITIVE_TYPE_TRIANGLES
Draws triangles. Indicates that the indices make up the th triangle with .
static const unsigned int PRIMITIVE_TYPE_POINTS
Draws points. Indicates that each index makes up a single point.
static const unsigned int PRIMITIVE_TYPE_LINE_STRIP
Draws lines. Indicates that the indices make up a the th line segment with .
Creates simple predefined ManagedMesh instances.
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 .
static ManagedMesh< VertexType, uint16_t > & createLineStrip(const std::vector< math::Vector3f > &points)
Creates a line strip.
static ManagedMesh< VertexType, uint8_t > & createPoint()
Creates mesh that consists of a single point.
static ManagedMesh< VertexType, uint8_t > & createBox(float width, float height, float depth)
Creates box with width, height and depth. The box is centered in .
static ManagedMesh< VertexType, uint32_t > & createFromSTL(const std::string &path)
Creates mesh from an STL file.
Defines LibCarna::base::math namespace and LIBCARNA_FOR_VECTOR3UI.
Eigen::Matrix< float, 3, 1 > Vector3f
Defines vector.
Definition math.hpp:200
Eigen::Matrix< float, 4, 4, Eigen::ColMajor > Matrix4f
Defines matrix.
Definition math.hpp:197
Eigen::Matrix< float, 4, 1 > Vector4f
Defines vector.
Definition math.hpp:199
Matrix4f scaling4f(float x, float y, float z)
Creates scaling matrix for homogeneous coordinates.
Definition math.hpp:296
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.hpp:246