OpenWalnut  1.5.0dev
WTriangleMesh.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <iostream>
26 #include <limits>
27 #include <list>
28 #include <map>
29 #include <memory>
30 #include <set>
31 #include <sstream>
32 #include <stack>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 
37 #include <Eigen/Eigenvalues>
38 #include <osg/io_utils>
39 
40 #include "../common/WAssert.h"
41 #include "../common/WLogger.h"
42 #include "../common/datastructures/WUnionFind.h"
43 #include "../common/math/WMath.h"
44 #include "WTriangleMesh.h"
45 
46 // init _static_ member variable and provide a linker reference to it
47 std::shared_ptr< WPrototyped > WTriangleMesh::m_prototype = std::shared_ptr< WPrototyped >();
48 
49 std::shared_ptr< WPrototyped > WTriangleMesh::getPrototype()
50 {
51  if( !m_prototype )
52  {
53  m_prototype = std::shared_ptr< WPrototyped >( new WTriangleMesh( 0, 0 ) );
54  }
55  return m_prototype;
56 }
57 
58 /**
59  * constructor that already reserves space for a given number of triangles and vertexes
60  */
61 WTriangleMesh::WTriangleMesh( size_t vertNum, size_t triangleNum )
62  : m_countVerts( 0 ),
63  m_countTriangles( 0 ),
64  m_meshDirty( true ),
65  m_autoNormal( true ),
66  m_neighborsCalculated( false ),
67  m_curvatureCalculated( false )
68 {
69  m_verts = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
70  m_textureCoordinates = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
71  m_vertNormals = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
72  m_vertFlatNormals = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
73  m_vertColors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array( vertNum ) );
74 
75  m_triangles.resize( triangleNum * 3 );
76  m_triangleNormals = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( triangleNum ) );
77  m_triangleColors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array( triangleNum ) );
78 }
79 
80 WTriangleMesh::WTriangleMesh( osg::ref_ptr< osg::Vec3Array > vertices, const std::vector< size_t >& triangles )
81  : m_countVerts( vertices->size() ),
82  m_countTriangles( triangles.size() / 3 ),
83  m_meshDirty( true ),
84  m_autoNormal( true ),
85  m_neighborsCalculated( false ),
86  m_verts( vertices ),
87  m_textureCoordinates( new osg::Vec3Array( vertices->size() ) ),
88  m_vertNormals( new osg::Vec3Array( vertices->size() ) ),
89  m_vertFlatNormals( new osg::Vec3Array( vertices->size() ) ),
90  m_vertColors( new osg::Vec4Array( vertices->size() ) ),
91  m_triangles( triangles ),
92  m_triangleNormals( new osg::Vec3Array( triangles.size() / 3 ) ),
93  m_triangleColors( new osg::Vec4Array( triangles.size() / 3 ) )
94 {
95  WAssert( triangles.size() % 3 == 0, "Invalid triangle vector, having an invalid size (not divideable by 3)" );
96 }
97 
99 {
100 }
101 
102 void WTriangleMesh::setAutoRecalcNormals( bool autoRecalc )
103 {
104  m_autoNormal = autoRecalc;
105 }
106 
107 size_t WTriangleMesh::addVertex( float x, float y, float z )
108 {
109  return addVertex( osg::Vec3( x, y, z ) );
110 }
111 
113 {
114  return addVertex( osg::Vec3( vert[0], vert[1], vert[2] ) );
115 }
116 
117 void WTriangleMesh::addTriangle( size_t vert0, size_t vert1, size_t vert2 )
118 {
119  if( m_triangles.size() == m_countTriangles * 3 )
120  {
121  m_triangles.resize( m_countTriangles * 3 + 3 );
122  }
123  m_triangles[ m_countTriangles * 3 ] = vert0;
124  m_triangles[ m_countTriangles * 3 + 1 ] = vert1;
125  m_triangles[ m_countTriangles * 3 + 2 ] = vert2;
127 }
128 
129 void WTriangleMesh::addTriangle( osg::Vec3 vert0, osg::Vec3 vert1, osg::Vec3 vert2 )
130 {
131  addVertex( vert0 );
132  addVertex( vert1 );
133  addVertex( vert2 );
135 }
136 
137 void WTriangleMesh::setVertexNormal( size_t index, osg::Vec3 normal )
138 {
139  WAssert( index < m_countVerts, "set vertex normal: index out of range" );
140  ( *m_vertNormals )[index] = normal;
141 }
142 
143 void WTriangleMesh::setVertexNormal( size_t index, WPosition normal )
144 {
145  setVertexNormal( index, osg::Vec3( normal[0], normal[1], normal[2] ) );
146 }
147 
148 void WTriangleMesh::setVertexNormal( size_t index, float x, float y, float z )
149 {
150  setVertexNormal( index, osg::Vec3( x, y, z ) );
151 }
152 
153 void WTriangleMesh::setVertexColor( size_t index, osg::Vec4 color )
154 {
155  WAssert( index < m_countVerts, "set vertex color: index out of range" );
156  ( *m_vertColors )[index] = color;
157 }
158 
159 void WTriangleMesh::setTriangleColor( size_t index, osg::Vec4 color )
160 {
161  WAssert( index < m_countTriangles, "set triangle color: index out of range" );
162  ( *m_triangleColors )[index] = color;
163 }
164 
165 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getVertexArray()
166 {
167  return m_verts;
168 }
169 
170 osg::ref_ptr< const osg::Vec3Array >WTriangleMesh::getVertexArray() const
171 {
172  return m_verts;
173 }
174 
175 osg::ref_ptr< osg::Vec3Array > WTriangleMesh::getTextureCoordinateArray()
176 {
177  return m_textureCoordinates;
178 }
179 
180 osg::ref_ptr< const osg::Vec3Array > WTriangleMesh::getTextureCoordinateArray() const
181 {
182  return m_textureCoordinates;
183 }
184 
185 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getVertexNormalArray( bool forceRecalc )
186 {
187  if( forceRecalc || ( m_meshDirty && m_autoNormal ) )
188  {
190  }
191  return m_vertNormals;
192 }
193 
194 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getVertexFlatNormalArray( bool forceRecalc )
195 {
196  if( forceRecalc || ( m_meshDirty && m_autoNormal ) )
197  {
199  }
200  return m_vertFlatNormals;
201 }
202 
203 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getTriangleNormalArray( bool forceRecalc )
204 {
205  if( forceRecalc || ( m_meshDirty && m_autoNormal ) )
206  {
208  }
209  return m_triangleNormals;
210 }
211 
212 
213 osg::ref_ptr< osg::Vec4Array >WTriangleMesh::getVertexColorArray()
214 {
215  return m_vertColors;
216 }
217 
218 const std::vector< size_t >& WTriangleMesh::getTriangles() const
219 {
220  return m_triangles;
221 }
222 
223 osg::Vec3 WTriangleMesh::getVertex( size_t index ) const
224 {
225  WAssert( index < m_countVerts, "get vertex: index out of range" );
226  return ( *m_verts )[index];
227 }
228 
229 osg::Vec4 WTriangleMesh::getVertColor( size_t index ) const
230 {
231  WAssert( index < m_countVerts, "get vertex color: index out of range" );
232  return ( *m_vertColors )[index];
233 }
234 
236 {
237  WAssert( index < m_countVerts, "get normal as position: index out of range" );
238  if( m_meshDirty )
239  {
241  }
242  return WPosition( ( *m_vertNormals )[index][0], ( *m_vertNormals )[index][1], ( *m_vertNormals )[index][2] );
243 }
244 
245 void WTriangleMesh::removeVertex( size_t index )
246 {
247  WAssert( index < m_countVerts, "remove vertex: index out of range" );
248  if( m_vertexIsInTriangle[ index ].size() > 0 )
249  {
250  return;
251  }
252  ( *m_verts ).erase( ( *m_verts ).begin() + index );
253 
254  for( size_t i = 0; i < m_countTriangles * 3; ++i )
255  {
256  if( m_triangles[ i ] > index )
257  {
258  --m_triangles[ i ];
259  }
260  }
261  m_meshDirty = true;
262 }
263 
264 void WTriangleMesh::removeTriangle( size_t index )
265 {
266  WAssert( index < m_countTriangles, "remove triangle: index out of range" );
267  m_triangles.erase( m_triangles.begin() + index * 3, m_triangles.begin() + index * 3 + 3 );
268  m_meshDirty = true;
269 }
270 
272 {
274 
275  ( *m_vertNormals ).resize( m_countVerts );
276  ( *m_vertFlatNormals ).resize( m_countVerts );
277  ( *m_triangleNormals ).resize( m_countTriangles );
278 
279  for( size_t i = 0; i < m_countTriangles; ++i )
280  {
281  ( *m_triangleNormals )[i] = calcTriangleNormal( i );
282  }
283 
284  for( size_t vertId = 0; vertId < m_countVerts; ++vertId )
285  {
286  osg::Vec3 tempNormal( 0.0, 0.0, 0.0 );
287  osg::Vec3 tempFlatNormal( 0.0, 0.0, 0.0 );
288  for( size_t neighbour = 0; neighbour < m_vertexIsInTriangle[vertId].size(); ++neighbour )
289  {
290  tempNormal += ( *m_triangleNormals )[ m_vertexIsInTriangle[vertId][neighbour] ];
291  tempFlatNormal = ( *m_triangleNormals )[ m_vertexIsInTriangle[vertId][0] ];
292  }
293  tempNormal *= 1./m_vertexIsInTriangle[vertId].size();
294 
295  tempNormal.normalize();
296  ( *m_vertNormals )[vertId] = tempNormal;
297  ( *m_vertFlatNormals )[vertId] = tempFlatNormal; // note: normal already normalized
298  }
299 
300  m_meshDirty = false;
301 }
302 
304 {
305  m_vertexIsInTriangle.clear();
306  std::vector< size_t >v;
307  m_vertexIsInTriangle.resize( ( *m_verts ).size(), v );
308 
309  for( size_t i = 0; i < m_countTriangles; ++i )
310  {
311  m_vertexIsInTriangle[ getTriVertId0( i ) ].push_back( i );
312  m_vertexIsInTriangle[ getTriVertId1( i ) ].push_back( i );
313  m_vertexIsInTriangle[ getTriVertId2( i ) ].push_back( i );
314  }
315 }
316 
317 osg::Vec3 WTriangleMesh::calcTriangleNormal( size_t triangle )
318 {
319  osg::Vec3 v1( getTriVert( triangle, 1 ) - getTriVert( triangle, 0 ) );
320  osg::Vec3 v2( getTriVert( triangle, 2 ) - getTriVert( triangle, 0 ) );
321 
322  osg::Vec3 tempNormal( 0, 0, 0 );
323 
324  tempNormal[0] = v1[1] * v2[2] - v1[2] * v2[1];
325  tempNormal[1] = v1[2] * v2[0] - v1[0] * v2[2];
326  tempNormal[2] = v1[0] * v2[1] - v1[1] * v2[0];
327 
328  tempNormal.normalize();
329 
330  return tempNormal;
331 }
332 
333 osg::Vec3 WTriangleMesh::calcNormal( osg::Vec3 vert0, osg::Vec3 vert1, osg::Vec3 vert2 )
334 {
335  osg::Vec3 v1( vert1 - vert0 );
336  osg::Vec3 v2( vert2 - vert0 );
337 
338  osg::Vec3 tempNormal( 0, 0, 0 );
339 
340  tempNormal[0] = v1[1] * v2[2] - v1[2] * v2[1];
341  tempNormal[1] = v1[2] * v2[0] - v1[0] * v2[2];
342  tempNormal[2] = v1[0] * v2[1] - v1[1] * v2[0];
343 
344  tempNormal.normalize();
345 
346  return tempNormal;
347 }
348 
350 {
351  return m_countVerts;
352 }
353 
355 {
356  return m_countTriangles;
357 }
358 
360 {
361  std::vector<size_t> v( 3, -1 );
362  m_triangleNeighbors.resize( ( *m_triangleNormals ).size(), v );
363 
364  for( size_t triId = 0; triId < m_countTriangles; ++triId )
365  {
366  size_t coVert0 = getTriVertId0( triId );
367  size_t coVert1 = getTriVertId1( triId );
368  size_t coVert2 = getTriVertId2( triId );
369 
370  m_triangleNeighbors[triId][0] = getNeighbor( coVert0, coVert1, triId );
371  m_triangleNeighbors[triId][1] = getNeighbor( coVert1, coVert2, triId );
372  m_triangleNeighbors[triId][2] = getNeighbor( coVert2, coVert0, triId );
373  }
374  m_neighborsCalculated = true;
375 }
376 
377 size_t WTriangleMesh::getNeighbor( const size_t coVert1, const size_t coVert2, const size_t triangleNum )
378 {
379  std::vector< size_t > candidates = m_vertexIsInTriangle[coVert1];
380  std::vector< size_t > compares = m_vertexIsInTriangle[coVert2];
381 
382  for( size_t i = 0; i < candidates.size(); ++i )
383  {
384  for( size_t k = 0; k < compares.size(); ++k )
385  {
386  if( ( candidates[i] != triangleNum ) && ( candidates[i] == compares[k] ) )
387  {
388  return candidates[i];
389  }
390  }
391  }
392  return triangleNum;
393 }
394 
396 {
399 
400  ( *m_verts ).resize( m_numTriVerts * 4 );
401  m_triangles.resize( m_numTriFaces * 4 * 3 );
402 
404 
405  osg::Vec3* newVertexPositions = new osg::Vec3[m_numTriVerts];
406 
407  //std::cout << "Loop subdivision pass 1" << std::endl;
408  for( size_t i = 0; i < m_numTriVerts; ++i )
409  {
410  newVertexPositions[i] = loopCalcNewPosition( i );
411  }
412 
413  //std::cout << "Loop subdivision pass 2" << std::endl;
414  for( size_t i = 0; i < m_numTriFaces; ++i )
415  {
417  }
418  ( *m_verts ).resize( m_countVerts );
419  std::vector< size_t >v;
420  m_vertexIsInTriangle.resize( ( *m_verts ).size(), v );
421 
422  //std::cout << "Loop subdivision pass 3" << std::endl;
423  for( size_t i = 0; i < m_numTriFaces; ++i )
424  {
426  }
427 
428  //std::cout << "Loop subdivision pass 4" << std::endl;
429  for( size_t i = 0; i < m_numTriVerts; ++i )
430  {
431  ( *m_verts )[i] = newVertexPositions[i];
432  }
433 
434  delete[] newVertexPositions;
435 
436  m_vertNormals->resize( m_verts->size() );
437  m_vertColors->resize( m_verts->size() );
438  m_triangleColors->resize( m_triangles.size() / 3 );
439 
440  m_meshDirty = true;
441 }
442 
443 
444 osg::Vec3 WTriangleMesh::loopCalcNewPosition( size_t vertId )
445 {
446  std::vector< size_t > starP = m_vertexIsInTriangle[vertId];
447  int starSize = starP.size();
448 
449  osg::Vec3 oldPos = getVertex( vertId );
450  double alpha = loopGetAlpha( starSize );
451 
452  double scale = 1.0 - ( static_cast<double>( starSize ) * alpha );
453  oldPos *= scale;
454 
455  osg::Vec3 newPos;
456  int edgeV = 0;
457  for( int i = 0; i < starSize; i++ )
458  {
459  edgeV = loopGetNextVertex( starP[i], vertId );
460  osg::Vec3 translate = getVertex( edgeV );
461  newPos += translate;
462  }
463  newPos *= alpha;
464 
465  return oldPos + newPos;
466 }
467 
469 {
470  size_t edgeVerts[3];
471 
472  edgeVerts[0] = loopCalcEdgeVert( triId, getTriVertId0( triId ), getTriVertId1( triId ), getTriVertId2( triId ) );
473  edgeVerts[1] = loopCalcEdgeVert( triId, getTriVertId1( triId ), getTriVertId2( triId ), getTriVertId0( triId ) );
474  edgeVerts[2] = loopCalcEdgeVert( triId, getTriVertId2( triId ), getTriVertId0( triId ), getTriVertId1( triId ) );
475 
476  addTriangle( edgeVerts[0], edgeVerts[1], edgeVerts[2] );
477 }
478 
479 
480 size_t WTriangleMesh::loopCalcEdgeVert( size_t triId, size_t edgeV1, size_t edgeV2, size_t V3 )
481 {
482  size_t neighborVert = -1;
483  size_t neighborFaceNum = -1;
484  osg::Vec3 edgeVert;
485 
486  neighborFaceNum = getNeighbor( edgeV1, edgeV2, triId );
487 
488  if( neighborFaceNum == triId )
489  {
490  osg::Vec3 edgeVert = ( ( *m_verts )[edgeV1] + ( *m_verts )[edgeV2] ) / 2.0;
491  size_t vertId = m_countVerts;
492  addVertex( edgeVert );
493  return vertId;
494  }
495 
496  else if( neighborFaceNum > triId )
497  {
498  neighborVert = loopGetThirdVert( edgeV1, edgeV2, neighborFaceNum );
499 
500  osg::Vec3 edgePart = ( *m_verts )[edgeV1] + ( *m_verts )[edgeV2];
501  osg::Vec3 neighborPart = ( *m_verts )[neighborVert] + ( *m_verts )[V3];
502 
503  edgeVert = ( ( edgePart * ( 3.0 / 8.0 ) ) + ( neighborPart * ( 1.0 / 8.0 ) ) );
504  size_t vertId = m_countVerts;
505  addVertex( edgeVert );
506  return vertId;
507  }
508  else
509  {
510  size_t neighborCenterP = neighborFaceNum + m_numTriFaces;
511  size_t neighborP = neighborFaceNum;
512 
513  if( getTriVertId0( neighborP ) == edgeV2 )
514  {
515  return getTriVertId0( neighborCenterP );
516  }
517  else if( getTriVertId1( neighborP ) == edgeV2 )
518  {
519  return getTriVertId1( neighborCenterP );
520  }
521  else
522  {
523  return getTriVertId2( neighborCenterP );
524  }
525  }
526  return -1;
527 }
528 
530 {
531  // comment: center are twisted from the orignal vertices.
532  // original: 0, 1, 2
533  // center: a, b, c
534  // reAsgnOrig: 0, a, c
535  // addTris: 1, b, a
536  // addTris: 2, c, b
537  //
538  size_t originalTri0 = getTriVertId0( triId );
539  size_t originalTri1 = getTriVertId1( triId );
540  size_t originalTri2 = getTriVertId2( triId );
541 
542  size_t centerTri0 = getTriVertId0( triId + m_numTriFaces );
543  size_t centerTri1 = getTriVertId1( triId + m_numTriFaces );
544  size_t centerTri2 = getTriVertId2( triId + m_numTriFaces );
545 
546  addTriangle( originalTri1, centerTri1, centerTri0 );
547  addTriangle( originalTri2, centerTri2, centerTri1 );
548  loopSetTriangle( triId, originalTri0, centerTri0, centerTri2 );
549 }
550 
551 void WTriangleMesh::loopSetTriangle( size_t triId, size_t vertId1, size_t vertId2, size_t vertId3 )
552 {
553  loopEraseTriangleFromVertex( triId, getTriVertId1( triId ) );
554  loopEraseTriangleFromVertex( triId, getTriVertId2( triId ) );
555 
556  setTriVert0( triId, vertId1 );
557  setTriVert1( triId, vertId2 );
558  setTriVert2( triId, vertId3 );
559 
560  m_vertexIsInTriangle[vertId2].push_back( triId );
561  m_vertexIsInTriangle[vertId3].push_back( triId );
562 }
563 
564 void WTriangleMesh::loopEraseTriangleFromVertex( size_t triId, size_t vertId )
565 {
566  std::vector< size_t > temp;
567  for( size_t i = 0; i < m_vertexIsInTriangle[vertId].size(); ++i )
568  {
569  if( triId != m_vertexIsInTriangle[vertId][i] )
570  temp.push_back( m_vertexIsInTriangle[vertId][i] );
571  }
572  m_vertexIsInTriangle[vertId] = temp;
573 }
574 
576 {
577  double answer;
578  if( n > 3 )
579  {
580  double center = ( 0.375 + ( 0.25 * cos( ( 2.0 * 3.14159265358979 ) / static_cast<double>( n ) ) ) );
581  answer = ( 0.625 - ( center * center ) ) / static_cast<double>( n );
582  }
583  else
584  {
585  answer = 3.0 / 16.0;
586  }
587  return answer;
588 }
589 
590 size_t WTriangleMesh::loopGetNextVertex( size_t triNum, size_t vertNum )
591 {
592  if( getTriVertId0( triNum ) == vertNum )
593  {
594  return getTriVertId1( triNum );
595  }
596  else if( getTriVertId1( triNum ) == vertNum )
597  {
598  return getTriVertId2( triNum );
599  }
600  return getTriVertId0( triNum );
601 }
602 
603 size_t WTriangleMesh::loopGetThirdVert( size_t coVert1, size_t coVert2, size_t triangleNum )
604 {
605  if( !( getTriVertId0( triangleNum ) == coVert1 ) && !( getTriVertId0( triangleNum ) == coVert2 ) )
606  {
607  return getTriVertId0( triangleNum );
608  }
609  else if( !( getTriVertId1( triangleNum ) == coVert1 ) && !( getTriVertId1( triangleNum ) == coVert2 ) )
610  {
611  return getTriVertId1( triangleNum );
612  }
613  return getTriVertId2( triangleNum );
614 }
615 
616 void WTriangleMesh::addMesh( std::shared_ptr<WTriangleMesh> mesh, float xOff, float yOff, float zOff )
617 {
618  size_t oldVertSize = m_countVerts;
619 
620  ( *m_vertColors ).resize( oldVertSize + mesh->vertSize() );
621  for( size_t i = 0; i < mesh->vertSize(); ++i )
622  {
623  osg::Vec3 v( mesh->getVertex( i ) );
624  v[0] += xOff;
625  v[1] += yOff;
626  v[2] += zOff;
627  addVertex( v );
628  setVertexColor( oldVertSize + i, mesh->getVertColor( i ) );
629  }
630  for( size_t i = 0; i < mesh->triangleSize(); ++i )
631  {
632  addTriangle( mesh->getTriVertId0( i ) + oldVertSize, mesh->getTriVertId1( i ) + oldVertSize, mesh->getTriVertId2( i ) + oldVertSize );
633  }
634  m_meshDirty = true;
635 }
636 
637 void WTriangleMesh::translateMesh( float xOff, float yOff, float zOff )
638 {
639  osg::Vec3 t( xOff, yOff, zOff );
640  for( size_t i = 0; i < ( *m_verts ).size(); ++i )
641  {
642  ( *m_verts )[i] += t;
643  }
644 }
645 
646 void WTriangleMesh::zoomMesh( float zoom )
647 {
648  for( size_t i = 0; i < ( *m_verts ).size(); ++i )
649  {
650  ( *m_verts )[i] *= zoom;
651  }
652 }
653 
655 {
656  float maxR = 0;
657  float maxG = 0;
658  float maxB = 0;
659  for( size_t vertId = 0; vertId < m_vertColors->size(); ++vertId )
660  {
661  if( ( *m_vertColors )[vertId][0] > maxR )
662  {
663  maxR = ( *m_vertColors )[vertId][0];
664  }
665  if( ( *m_vertColors )[vertId][1] > maxG )
666  {
667  maxG = ( *m_vertColors )[vertId][1];
668  }
669  if( ( *m_vertColors )[vertId][2] > maxB )
670  {
671  maxB = ( *m_vertColors )[vertId][2];
672  }
673  }
674  for( size_t vertId = 0; vertId < m_vertColors->size(); ++vertId )
675  {
676  ( *m_vertColors )[vertId][0] /= maxR;
677  ( *m_vertColors )[vertId][1] /= maxG;
678  ( *m_vertColors )[vertId][2] /= maxB;
679  }
680 }
681 
682 std::ostream& tm_utils::operator<<( std::ostream& os, const WTriangleMesh& rhs )
683 {
684  std::stringstream ss;
685  ss << "WTriangleMesh( #vertices=" << rhs.vertSize() << " #triangles=" << rhs.triangleSize() << " )" << std::endl;
686  using string_utils::operator<<;
687  size_t count = 0;
688  ss << std::endl;
689  const std::vector< size_t >& triangles = rhs.getTriangles();
690  osg::ref_ptr< const osg::Vec3Array > vertices = rhs.getVertexArray();
691  for( size_t vID = 0 ; vID <= triangles.size() - 3; ++count )
692  {
693  std::stringstream prefix;
694  prefix << "triangle: " << count << "[ ";
695  std::string indent( prefix.str().size(), ' ' );
696  using osg::operator<<; // using operator<< as defined in osg/io_utils
697  ss << prefix.str() << vertices->at( triangles[ vID++ ] ) << std::endl;
698  ss << indent << vertices->at( triangles[ vID++ ] ) << std::endl;
699  ss << indent << vertices->at( triangles[ vID++ ] ) << std::endl;
700  ss << std::string( indent.size() - 2, ' ' ) << "]" << std::endl;
701  }
702  return os << ss.str();
703 }
704 
705 std::shared_ptr< std::list< std::shared_ptr< WTriangleMesh > > > tm_utils::componentDecomposition( const WTriangleMesh& mesh )
706 {
707  std::shared_ptr< std::list< std::shared_ptr< WTriangleMesh > > > result( new std::list< std::shared_ptr< WTriangleMesh > >() );
708  if( mesh.vertSize() <= 0 ) // no component possible
709  {
710  return result;
711  }
712  if( mesh.triangleSize() < 3 )
713  {
714  if( mesh.vertSize() > 0 )
715  {
716  // there are vertices but no triangles
717  WAssert( false, "Not implemented the decomposition of a TriangleMesh without any triangles" );
718  }
719  else // no component possible
720  {
721  return result;
722  }
723  }
724 
725  WUnionFind uf( mesh.vertSize() ); // idea: every vertex in own component, then successivley join in accordance with the triangles
726 
727  const std::vector< size_t >& triangles = mesh.getTriangles();
728  for( size_t vID = 0; vID <= triangles.size() - 3; vID += 3 )
729  {
730  uf.merge( triangles[ vID ], triangles[ vID + 1 ] );
731  uf.merge( triangles[ vID ], triangles[ vID + 2 ] ); // uf.merge( triangles[ vID + 2 ], triangles[ vID + 1 ] ); they are already in same
732  }
733 
734  // ATTENTION: The reason for using the complex BucketType instead of pasting vertices directly into a new WTriangleMesh
735  // is performance! For example: If there are many vertices reused inside the former WTriangleMesh mesh, then we want
736  // to reuse them in the new components too. Hence we must determine if a certain vertex is already inside the new component.
737  // Since the vertices are organized in a vector, we can use std::find( v.begin, v.end(), vertexToLookUp ) which results
738  // in O(N^2) or we could use faster lookUp via key and value leading to the map and the somehow complicated BucketType.
739  typedef std::map< osg::Vec3, size_t > VertexType; // look up fast if a vertex is already inside the new mesh!
740  typedef std::vector< size_t > TriangleType;
741  typedef std::pair< VertexType, TriangleType > BucketType; // Later on the Bucket will be transformed into the new WTriangleMesh component
742  std::map< size_t, BucketType > buckets; // Key identify with the cannonical element from UnionFind the new connected component
743 
744  osg::ref_ptr< const osg::Vec3Array > vertices = mesh.getVertexArray();
745  for( size_t vID = 0; vID <= triangles.size() - 3; vID += 3 )
746  {
747  size_t component = uf.find( triangles[ vID ] );
748  if( buckets.find( component ) == buckets.end() )
749  {
750  buckets[ component ] = BucketType( VertexType(), TriangleType() ); // create new bucket
751  }
752 
753  // Note: We discard the order of the points and indices, but semantically the structure remains the same
754  VertexType& mapRef = buckets[ component ].first; // short hand alias
755  for( int i = 0; i < 3; ++i )
756  {
757  size_t id = 0;
758  const osg::Vec3& vertex = ( *vertices )[ triangles[ vID + i ] ];
759  if( mapRef.find( vertex ) == mapRef.end() )
760  {
761  id = mapRef.size(); // since size might change in next line
762  mapRef[ vertex ] = id;
763  }
764  else
765  {
766  id = mapRef[ vertex ];
767  }
768  buckets[ component ].second.push_back( id );
769  }
770  }
771 
772  for( std::map< size_t, BucketType >::const_iterator cit = buckets.begin(); cit != buckets.end(); ++cit )
773  {
774  osg::ref_ptr< osg::Vec3Array > newVertices( new osg::Vec3Array );
775  newVertices->resize( cit->second.first.size() );
776  for( VertexType::const_iterator vit = cit->second.first.begin(); vit != cit->second.first.end(); ++vit )
777  {
778  newVertices->at( vit->second ) = vit->first; // if you are sure that vit->second is always valid replace at() call with operator[]
779  }
780  std::shared_ptr< WTriangleMesh > newMesh( new WTriangleMesh( newVertices, cit->second.second ) );
781  result->push_back( newMesh );
782  }
783 
784  return result;
785 }
786 
787 osg::ref_ptr< osg::Vec4Array > WTriangleMesh::getTriangleColors() const
788 {
789  return m_triangleColors;
790 }
791 
792 void WTriangleMesh::performFeaturePreservingSmoothing( float sigmaDistance, float sigmaInfluence )
793 {
795 
796  calcNeighbors();
797 
798  // we perform a first smoothing pass and write the resulting vertex coords into a buffer
799  // this will only update the normals
800  performFeaturePreservingSmoothingMollificationPass( sigmaDistance / 2.0f, sigmaInfluence );
801 
802  // using the smoothed normals, we now perform a second smoothing pass, this time writing the new vertex coords
803  performFeaturePreservingSmoothingVertexPass( sigmaDistance, sigmaInfluence );
804 }
805 
806 void WTriangleMesh::performFeaturePreservingSmoothingMollificationPass( float sigmaDistance, float sigmaInfluence )
807 {
808  // calc Eq. 3 for every triangle
809  osg::ref_ptr< osg::Vec3Array > vtxArray = new osg::Vec3Array( m_verts->size() );
810 
811  for( std::size_t k = 0; k < m_verts->size(); ++k )
812  {
813  vtxArray->operator[] ( k ) = estimateSmoothedVertexPosition( k, sigmaDistance, sigmaInfluence, true );
814  }
815 
816  // calc the new normal directions - update triangle normals
817  for( std::size_t k = 0; k < m_triangles.size() / 3; ++k )
818  {
819  osg::Vec3 const& p0 = vtxArray->operator[]( m_triangles[ 3 * k + 0 ] );
820  osg::Vec3 const& p1 = vtxArray->operator[]( m_triangles[ 3 * k + 1 ] );
821  osg::Vec3 const& p2 = vtxArray->operator[]( m_triangles[ 3 * k + 2 ] );
822 
823  m_triangleNormals->operator[] ( k ) = ( p1 - p0 ) ^ ( p2 - p1 );
824  m_triangleNormals->operator[] ( k ).normalize();
825  }
826 }
827 
828 void WTriangleMesh::performFeaturePreservingSmoothingVertexPass( float sigmaDistance, float sigmaInfluence )
829 {
830  for( std::size_t k = 0; k < m_verts->size(); ++k )
831  {
832  m_verts->operator[] ( k ) = estimateSmoothedVertexPosition( k, sigmaDistance, sigmaInfluence, false );
833  }
834 
836 }
837 
838 osg::Vec3 WTriangleMesh::estimateSmoothedVertexPosition( std::size_t vtx, float sigmaDistance, float sigmaInfluence, bool mollify )
839 {
840  std::stack< std::size_t > triStack;
841  std::set< std::size_t > triSet;
842 
843  for( std::size_t k = 0; k < m_vertexIsInTriangle[ vtx ].size(); ++k )
844  {
845  triStack.push( m_vertexIsInTriangle[ vtx ][ k ] );
846  triSet.insert( m_vertexIsInTriangle[ vtx ][ k ] );
847  }
848 
849  while( !triStack.empty() )
850  {
851  std::size_t currentTriangle = triStack.top();
852  triStack.pop();
853 
854  for( std::size_t k = 0; k < m_triangleNeighbors[ currentTriangle ].size(); ++k )
855  {
856  osg::Vec3 center = calcTriangleCenter( m_triangleNeighbors[ currentTriangle ][ k ] );
857 
858  if( ( m_verts->operator[] ( vtx ) - center ).length() > 4.0 * sigmaDistance )
859  {
860  continue;
861  }
862 
863  if( triSet.find( m_triangleNeighbors[ currentTriangle ][ k ] ) == triSet.end() )
864  {
865  triStack.push( m_triangleNeighbors[ currentTriangle ][ k ] );
866  triSet.insert( m_triangleNeighbors[ currentTriangle ][ k ] );
867  }
868  }
869  }
870 
871  double sum = 0.0;
872  osg::Vec3 res( 0.0, 0.0, 0.0 );
873 
874  for( std::set< std::size_t >::const_iterator it = triSet.begin(); it != triSet.end(); ++it )
875  {
876  osg::Vec3 center = calcTriangleCenter( *it );
877  double area = calcTriangleArea( *it );
878 
879  // calc f
880  double dist = ( m_verts->operator[] ( vtx ) - center ).length();
881  double f = 1.0 / ( sigmaDistance * sqrt( 2.0 * pi() ) ) * exp( -0.5 * dist * dist );
882 
883  double g;
884  if( !mollify )
885  {
886  // calc prediction
887  osg::Vec3f const& p = m_verts->operator[] ( vtx );
888  osg::Vec3f const& n = m_triangleNormals->operator[] ( *it );
889  osg::Vec3f pred = p + n * ( n * ( center - p ) );
890 
891  dist = ( p - pred ).length();
892  }
893  g = 1.0 / ( sigmaInfluence * sqrt( 2.0 * pi() ) ) * exp( -0.5 * dist * dist );
894 
895  sum += area * f * g;
896  res += center * area * f * g;
897  }
898 
899  res /= sum;
900  return res;
901 }
902 
903 osg::Vec3 WTriangleMesh::calcTriangleCenter( std::size_t triIdx ) const
904 {
905  osg::Vec3 res = m_verts->operator[] ( m_triangles[ 3 * triIdx + 0 ] );
906  res += m_verts->operator[] ( m_triangles[ 3 * triIdx + 1 ] );
907  res += m_verts->operator[] ( m_triangles[ 3 * triIdx + 2 ] );
908 
909  res /= 3.0f;
910  return res;
911 }
912 
913 float WTriangleMesh::calcTriangleArea( std::size_t triIdx ) const
914 {
915  osg::Vec3 const& p0 = m_verts->operator[] ( m_triangles[ 3 * triIdx + 0 ] );
916  osg::Vec3 const& p1 = m_verts->operator[] ( m_triangles[ 3 * triIdx + 1 ] );
917  osg::Vec3 const& p2 = m_verts->operator[] ( m_triangles[ 3 * triIdx + 2 ] );
918 
919  return ( ( p1 - p0 ) ^ ( p2 - p0 ) ).length() * 0.5;
920 }
921 
923 {
925  calcNeighbors();
926 
927  std::vector< osg::Vec3 > normals( m_verts->size() );
928 
929  // init vectors
930  m_mainNormalCurvature = std::shared_ptr< std::vector< float > >( new std::vector< float >( m_verts->size() ) );
931  m_secondaryNormalCurvature = std::shared_ptr< std::vector< float > >( new std::vector< float >( m_verts->size() ) );
932  m_mainCurvaturePrincipalDirection = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( m_verts->size() ) );
933  m_secondaryCurvaturePrincipalDirection = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( m_verts->size() ) );
934 
935  // calculate vertex normals using distance-weighted summing of neighbor-triangle normals
936  for( std::size_t vtxId = 0; vtxId < m_verts->size(); ++vtxId )
937  {
938  osg::Vec3 const& p = m_verts->operator[] ( vtxId );
939  osg::Vec3 n( 0.0, 0.0, 0.0 );
940 
941  for( std::size_t k = 0; k < m_vertexIsInTriangle[ vtxId ].size(); ++k )
942  {
943  std::size_t triId = m_vertexIsInTriangle[ vtxId ][ k ];
944 
945  osg::Vec3 center = calcTriangleCenter( triId );
946  double w = 1.0 / ( center - p ).length();
947 
948  n += m_triangleNormals->operator[] ( triId ) * w;
949  }
950 
951  WAssert( n.length() > 0.0001, "Invalid normal!" );
952 
953  n.normalize();
954  normals[ vtxId ] = n;
955  }
956 
957  // calculate curvatures for every vertex
958  for( std::size_t vtxId = 0; vtxId < m_verts->size(); ++vtxId )
959  {
960  osg::Vec3 const& p = m_verts->operator[] ( vtxId );
961 
962  osg::Vec3 const& normal = normals[ vtxId ];
963 
964  // get the set of neighbor vertices
965  std::set< std::size_t > neighbors;
966 
967  for( std::size_t k = 0; k < m_vertexIsInTriangle[ vtxId ].size(); ++k )
968  {
969  std::size_t triId = m_vertexIsInTriangle[ vtxId ][ k ];
970 
971  for( std::size_t j = 0; j < 3; ++j )
972  {
973  std::size_t e = m_triangles[ 3 * triId + j ];
974 
975  if( neighbors.find( e ) == neighbors.end() && e != vtxId )
976  {
977  neighbors.insert( e );
978  }
979  }
980  }
981 
982  WAssert( neighbors.size() > 2, "Vertex has too few neighbors! Does this mesh have holes?" );
983 
984  double maxCurvature = -std::numeric_limits< double >::infinity();
985  std::vector< double > curvatures;
986 
987  osg::Vec3 maxCurvatureTangent( 0.0, 0.0, 0.0 );
988  std::vector< osg::Vec3 > tangents;
989 
990  // part 1: get curvatures at tangents and their maximum curvature
991  for( std::set< std::size_t >::const_iterator it = neighbors.begin(); it != neighbors.end(); ++it )
992  {
993  osg::Vec3 const& neighbPos = m_verts->operator[] ( *it );
994  osg::Vec3 const& neighbNormal = normals[ *it ];
995 
996  // project ( neighbPos - p ) onto the tangent plane
997  osg::Vec3 tangent = ( neighbPos - p ) - normal * ( ( neighbPos - p ) * normal );
998  tangent.normalize();
999 
1000  // approximate normal curvature in tangent direction
1001  double ncurv = -1.0 * ( ( neighbPos - p ) * ( neighbNormal - normal ) ) / ( ( neighbPos - p ) * ( neighbPos - p ) );
1002 
1003  if( ncurv > maxCurvature )
1004  {
1005  maxCurvature = ncurv;
1006  maxCurvatureTangent = tangent;
1007  }
1008 
1009  tangents.push_back( tangent );
1010  curvatures.push_back( ncurv );
1011  }
1012 
1013  WAssert( maxCurvatureTangent.length() > 0.0001, "Invalid tangent length!" );
1014 
1015  // part 2: choose a coordinate system in the tangent plane
1016  osg::Vec3 const& e1 = maxCurvatureTangent;
1017  osg::Vec3 e2 = e1 ^ normal;
1018 
1019  e2.normalize();
1020 
1021  bool significantCurvature = false;
1022  for( std::vector< double >::const_iterator it = curvatures.begin(); it != curvatures.end(); ++it )
1023  {
1024  if( fabs( *it ) > 0.00001 )
1025  {
1026  significantCurvature = true;
1027  break;
1028  }
1029  }
1030 
1031  if( !significantCurvature )
1032  {
1033  // curvatures were all almost zero
1034  // the mesh is flat at this point, write values accordingly
1035  m_mainNormalCurvature->operator[] ( vtxId ) = 0.0;
1036  m_mainCurvaturePrincipalDirection->operator[] ( vtxId ) = e1;
1037  m_secondaryNormalCurvature->operator[] ( vtxId ) = 0.0;
1038  m_secondaryCurvaturePrincipalDirection->operator[] ( vtxId ) = e2;
1039 
1040  continue;
1041  }
1042 
1043  // calculate coefficients of the ellipse a * cos²(theta) + b * cos(theta) * sin(theta) * c * sin²(theta)
1044  // this is done by estimating a as the largest curvature amoung the estimated curvatures in all tangent
1045  // direction belonging to points that share a triangle with the current one
1046  double const& a = maxCurvature;
1047 
1048  Eigen::Matrix< double, -1, -1 > X( tangents.size(), 2 );
1049  Eigen::Matrix< double, -1, -1 > y( tangents.size(), 1 );
1050 
1051  for( std::size_t k = 0; k < tangents.size(); ++k )
1052  {
1053  double theta = calcAngleBetweenNormalizedVectors( tangents[ k ], e1 );
1054 
1055  X( k, 0 ) = cos( theta ) * sin( theta );
1056  X( k, 1 ) = sin( theta ) * sin( theta );
1057  y( k, 0 ) = curvatures[ k ] - a * cos( theta ) * cos( theta );
1058  }
1059 
1060  // use LU decomposition to calculate rank
1061  Eigen::FullPivLU< Eigen::Matrix< double, -1, -1 > > lu( X );
1062 
1063  // we need a rank of at least 2 to calculate the coeffs
1064  if( lu.rank() < 2 )
1065  {
1066  wlog::warn( "WTriangleMesh::estimateCurvature" ) << "Rank too low, cannot estimate curvature for this vertex!";
1067 
1068  m_mainNormalCurvature->operator[] ( vtxId ) = a;
1069  m_mainCurvaturePrincipalDirection->operator[] ( vtxId ) = e1;
1070  m_secondaryNormalCurvature->operator[] ( vtxId ) = 0.0;
1071  m_secondaryCurvaturePrincipalDirection->operator[] ( vtxId ) = e2;
1072 
1073  continue;
1074  }
1075 
1076  // do least squares
1077  Eigen::Matrix< double, -1, -1 > bb = ( X.transpose() * X ).inverse() * X.transpose() * y;
1078 
1079  // the missing coeffs b and c are now:
1080  double b = bb( 0, 0 );
1081  double c = bb( 1, 0 );
1082 
1083  // this calculates the maximum and minimum normal curvatures
1084  // (as eigenvalues)
1085  double Kg = a * c - 0.25 * b * b;
1086  double H = 0.5 * ( a + c );
1087  double s = H * H - Kg;
1088 
1089  if( s < 0.0 )
1090  {
1091  s = 0.0;
1092  }
1093 
1094  double k1 = H + sqrt( s );
1095  double k2 = H - sqrt( s );
1096 
1097  if( fabs( k1 - k2 ) < 0.000001 )
1098  {
1099  // if the curvatures are equal, there is no single principal direction
1100  m_mainNormalCurvature->operator[] ( vtxId ) = a;
1101  m_mainCurvaturePrincipalDirection->operator[] ( vtxId ) = e1;
1102  }
1103  else
1104  {
1105  // if the curvatures differ, we can now find the direction of maximum curvature
1106  double temp = b / ( k2 - k1 );
1107 
1108  if( temp > 1.0 )
1109  {
1110  temp = 1.0;
1111  }
1112  if( temp < -1.0 )
1113  {
1114  temp = -1.0;
1115  }
1116 
1117  double theta = 0.5 * asin( temp );
1118 
1119  osg::Vec3 ne1 = e1 * cos( theta ) + e2 * sin( theta );
1120  osg::Vec3 ne2 = e2 * cos( theta ) - e1 * sin( theta );
1121 
1122  ne1.normalize();
1123  ne2.normalize();
1124 
1125  e2 = ne2;
1126 
1127  theta = calcAngleBetweenNormalizedVectors( ne1, e1 );
1128 
1129  m_mainNormalCurvature->operator[] ( vtxId ) = a * cos( theta ) * cos( theta )
1130  + b * cos( theta ) * sin( theta )
1131  + c * sin( theta ) * sin( theta );
1132  m_mainCurvaturePrincipalDirection->operator[] ( vtxId ) = ne1;
1133  }
1134 
1135  double theta = calcAngleBetweenNormalizedVectors( e2, e1 );
1136 
1137  m_secondaryNormalCurvature->operator[] ( vtxId ) = a * cos( theta ) * cos( theta )
1138  + b * cos( theta ) * sin( theta )
1139  + c * sin( theta ) * sin( theta );
1140  m_secondaryCurvaturePrincipalDirection->operator[] ( vtxId ) = e2;
1141  }
1142 
1143  m_curvatureCalculated = true;
1144 }
1145 
1146 double WTriangleMesh::calcAngleBetweenNormalizedVectors( osg::Vec3 const& v1, osg::Vec3 const& v2 )
1147 {
1148  // assumes vectors are normalized
1149  WAssert( v1.length() < 1.0001, "Vector is not normalized!" );
1150  WAssert( v1.length() > -1.0001, "Vector is not normalized!" );
1151  WAssert( v2.length() < 1.0001, "Vector is not normalized!" );
1152  WAssert( v2.length() > -1.0001, "Vector is not normalized!" );
1153 
1154  double temp = v1 * v2;
1155 
1156  // avoid NaNs due to numerical errors
1157  if( temp < -1.0 )
1158  {
1159  temp = -1.0;
1160  }
1161  if( temp > 1.0 )
1162  {
1163  temp = 1.0;
1164  }
1165 
1166  return acos( temp );
1167 }
1168 
1169 double WTriangleMesh::getMainCurvature( std::size_t vtxId ) const
1170 {
1171  return m_mainNormalCurvature->operator[] ( vtxId );
1172 }
1173 
1174 double WTriangleMesh::getSecondaryCurvature( std::size_t vtxId ) const
1175 {
1176  return m_secondaryNormalCurvature->operator[] ( vtxId );
1177 }
1178 
1179 std::shared_ptr< std::vector< float > > const& WTriangleMesh::getMainCurvatures() const
1180 {
1181  return m_mainNormalCurvature;
1182 }
1183 
1184 std::shared_ptr< std::vector< float > > const& WTriangleMesh::getSecondaryCurvatures() const
1185 {
1187 }
1188 
1189 osg::Vec3 WTriangleMesh::getCurvatureMainPrincipalDirection( std::size_t vtxId ) const
1190 {
1191  return m_mainCurvaturePrincipalDirection->operator[] ( vtxId );
1192 }
1193 
1195 {
1196  return m_secondaryCurvaturePrincipalDirection->operator[] ( vtxId );
1197 }
1198 
1199 void WTriangleMesh::setTextureCoord( std::size_t index, osg::Vec3 texCoord )
1200 {
1201  m_textureCoordinates->operator[] ( index ) = texCoord;
1202 }
1203 
1205 {
1207 }
1208 
1210 {
1212 }
1213 
This only is a 3d double vector.
Triangle mesh data structure allowing for convenient access of the elements.
Definition: WTriangleMesh.h:46
void setVertexNormal(size_t index, osg::Vec3 normal)
sets the normal for a given vertex
size_t getNeighbor(const size_t coVert1, const size_t coVert2, const size_t triangleNum)
returns the triangle index of a triangle neighboring a given edge of a vertex
osg::Vec3 getVertex(size_t index) const
getter
bool m_curvatureCalculated
Indicates whether the curvature and its principal directions have been calculated.
size_t getTriVertId1(size_t triId) const
returns the id of the second vertex of a triangle
osg::Vec3 getTriVert(size_t triId, size_t vertNum)
getter
osg::ref_ptr< osg::Vec3Array > m_secondaryCurvaturePrincipalDirection
Stores the second principal curvature direction for each vertex.
osg::ref_ptr< osg::Vec3Array > m_mainCurvaturePrincipalDirection
Stores the first principal curvature direction for each vertex.
void zoomMesh(float zoom)
multiplies the vertex vectors of the mesh with a given number
void setTriVert2(size_t triId, size_t vertId)
higher level access function to the triangle vector, sets the third vertex of a triangle to a given v...
osg::ref_ptr< osg::Vec3Array > m_triangleNormals
array containing the triangle normals
size_t getTriVertId0(size_t triId) const
returns the id of the first vertex of a triangle
void updateVertsInTriangles()
updates the list for which vertexes appear in which triangle
bool m_autoNormal
flag denoting whether normals should be calculated automatically.
osg::ref_ptr< osg::Vec3Array > getTextureCoordinateArray()
Returns a reference pointer to the texture coordinate array.
void setTriVert1(size_t triId, size_t vertId)
higher level access function to the triangle vector, sets the second vertex of a triangle to a given ...
osg::ref_ptr< osg::Vec3Array > m_verts
array containing the vertices
void setVertexColor(size_t index, osg::Vec4 color)
sets the color for a given vertex
std::vector< size_t > m_triangles
array containing the triangles
osg::ref_ptr< osg::Vec3Array > getMainPrincipalCurvatureDirectionArray()
Retreive the array of principal directions e.g.
osg::Vec3 getCurvatureMainPrincipalDirection(std::size_t vtxId) const
Retreive the 3d principal direction of curvature of a vertex.
osg::ref_ptr< osg::Vec3Array > getVertexNormalArray(bool forceRecalc=false)
Get normal array containing smooth normals for each vertex.
osg::ref_ptr< osg::Vec3Array > getVertexArray()
getter
float calcTriangleArea(std::size_t triIdx) const
Calculates the area of a triangle.
void loopSetTriangle(size_t triId, size_t vertId1, size_t vertId2, size_t vertId3)
changes the vertex ids of a triangle
osg::Vec3 calcNormal(osg::Vec3 vert0, osg::Vec3 vert1, osg::Vec3 vert2)
calculates a normal from the 3 points in space
void performFeaturePreservingSmoothing(float sigmaDistance, float sigmaInfluence)
Implements the feature-preserving mesh smoothing algorithm of Jones et al.
osg::ref_ptr< osg::Vec3Array > m_textureCoordinates
array containing the texture coordinates
size_t getTriVertId2(size_t triId) const
return the id of the third vertex of a triangle
void performFeaturePreservingSmoothingVertexPass(float sigmaDistance, float sigmaInfluence)
Performs the second pass of the feature-preserving smoothing.
osg::Vec3 calcTriangleCenter(std::size_t triIdx) const
Calculates the center position of a triangle.
void addMesh(std::shared_ptr< WTriangleMesh > mesh, float xOff=0., float yOff=0., float zOff=0.)
adds a mesh to the existing, no check for duplicate vertexes is performed, an additional vector may b...
osg::Vec4 getVertColor(size_t index) const
getter
void loopInsertCornerTriangles(size_t triId)
inserts the 3 corner triangles in a given triangle
double loopGetAlpha(int n)
loop helper function
double calcAngleBetweenNormalizedVectors(osg::Vec3 const &v1, osg::Vec3 const &v2)
Calculates the angle between two NORMALIZED vectors.
size_t triangleSize() const
getter
void calcNeighbors()
calculates neighbor information for triangles
void doLoopSubD()
performs a loop subdivision on the triangle mesh
void setTriVert0(size_t triId, size_t vertId)
higher level access function to the triangle vector, sets the first vertex of a triangle to a given v...
osg::Vec3 estimateSmoothedVertexPosition(std::size_t vtx, float sigmaDistance, float sigmaInfluence, bool mollify)
Calculates Eq.
osg::Vec3 getCurvatureSecondaryPrincipalDirection(std::size_t vtxId) const
Retreive the 3d principal direction of curvature for the minimum normal curvature of a vertex.
void addTriangle(size_t vert0, size_t vert1, size_t vert2)
adds a tringle to the mesh
bool m_neighborsCalculated
flag indicating whether the neighbor information has been calculated yet
size_t m_countVerts
number of vertexes in the mesh
osg::ref_ptr< osg::Vec3Array > m_vertNormals
array containing the vertex normals
void setTextureCoord(std::size_t index, osg::Vec3 texCoord)
Set a texture coordinate.
osg::ref_ptr< osg::Vec4Array > getVertexColorArray()
Color array with a color for each vertex.
std::shared_ptr< std::vector< float > > const & getMainCurvatures() const
Get the vector of main curvature values.
osg::ref_ptr< osg::Vec3Array > getTriangleNormalArray(bool forceRecalc=false)
Normal per triangle.
double getSecondaryCurvature(std::size_t vtxId) const
Retreive the secondary (minimum) curvature of a vertex.
size_t vertSize() const
getter
osg::Vec3 calcTriangleNormal(size_t triangle)
calculates a normal from the 3 points in space defining a triangle
osg::ref_ptr< osg::Vec4Array > getTriangleColors() const
Return triangle colors.
std::shared_ptr< std::vector< float > > const & getSecondaryCurvatures() const
Get the vector of secondary curvature values.
void translateMesh(float xOff, float yOff, float zOff)
moves the entire mesh to a new postion
size_t m_numTriFaces
stores the number of triangles before the loop subdivion is run, needed by the loop algorithm
double getMainCurvature(std::size_t vtxId) const
Retreive the main (maximum) curvature of a vertex.
std::vector< std::vector< size_t > > m_triangleNeighbors
edge neighbors for each triangle
size_t loopGetNextVertex(size_t triNum, size_t vertNum)
returns the id of the next vertex int he triangle
osg::ref_ptr< osg::Vec3Array > getSecondaryPrincipalCurvatureDirectionArray()
Retreive the array of principal directions e.g.
osg::ref_ptr< osg::Vec4Array > m_triangleColors
array containing the triangle colors
void loopEraseTriangleFromVertex(size_t triId, size_t vertId)
erases a triangle from the vertexe's list of triangles it is part of
virtual ~WTriangleMesh()
destructor
osg::Vec3 loopCalcNewPosition(size_t vertId)
calculates the new position of a vertex depending on it's location in the grid and number of neighbor...
void rescaleVertexColors()
Rescale the vertex colors so that the maximum of all r, g and b values is 1.
bool m_meshDirty
flag indicating a change took place which requires a recalculation of components
void setTriangleColor(size_t index, osg::Vec4 color)
sets the color for a given triangle
std::shared_ptr< std::vector< float > > m_secondaryNormalCurvature
Stores the minimum normal curvature (for the second principal direction) for each vertex.
WTriangleMesh()
we don't allow the standard constructor
void loopInsertCenterTriangle(size_t triId)
inserts the center triangle in a given triangle,
size_t loopGetThirdVert(size_t coVert1, size_t coVert2, size_t triangleNum)
returns the id of the third vertex of a triangle for two given vertexes
void estimateCurvature()
Estimates the normal curvatures and their principal directions for every vertex using the algorithm o...
static std::shared_ptr< WPrototyped > m_prototype
The prototype as singleton.
std::vector< std::vector< size_t > > m_vertexIsInTriangle
for each vertex, list of triangles it is part of
void setAutoRecalcNormals(bool autoRecalc=true)
Set this to true to force automatic normal calculation.
size_t m_countTriangles
number of triangles in the mesh
osg::ref_ptr< osg::Vec3Array > m_vertFlatNormals
array containing the flat vertex normals
const std::vector< size_t > & getTriangles() const
Returns a const reference to the vertex ids of the triangles.
size_t addVertex(osg::Vec3 vert)
adds a vertex position to the mesh
size_t m_numTriVerts
stores the number of vertexes before the loop subdivion is run, needed by the loop algorithm
void performFeaturePreservingSmoothingMollificationPass(float sigmaDistance, float sigmaInfluence)
Performs the first pass of the feature-preserving smoothing, only changing the triangle normals.
osg::ref_ptr< osg::Vec4Array > m_vertColors
array containing vertex colors
static std::shared_ptr< WPrototyped > getPrototype()
Returns a prototype instantiated with the true type of the deriving class.
WVector3d getNormal(size_t index)
getter
osg::ref_ptr< osg::Vec3Array > getVertexFlatNormalArray(bool forceRecalc=false)
Get the normal array with flat normals for each vertex.
size_t loopCalcEdgeVert(size_t triId, size_t edgeV1, size_t edgeV2, size_t V3)
calculates the vertex id for a given edge, inserts a new vertex of none exists yet
void removeTriangle(size_t index)
removes a triangle from the mesh
void removeVertex(size_t index)
removes a vertex from the vertex array, if any triangles still index that vertex they will be removed...
std::shared_ptr< std::vector< float > > m_mainNormalCurvature
Stores the maximum normal curvature (for the first principal direction) for each vertex.
void recalcVertNormals()
recalculates the vertex normals
Implements a very simple union-find datastructure aka disjoint_sets.
Definition: WUnionFind.h:74
void merge(size_t i, size_t j)
Merges two components (iow: makes a union) where the given elements are members of.
Definition: WUnionFind.cpp:60
size_t find(size_t x)
Find the canonical element of the given element and do path compression.
Definition: WUnionFind.cpp:45
std::ostream & operator<<(std::ostream &os, const WTriangleMesh &rhs)
Prints for each mesh #vertices and #triangles, as well as each triangle with its positions.
std::shared_ptr< std::list< std::shared_ptr< WTriangleMesh > > > componentDecomposition(const WTriangleMesh &mesh)
Decompose the given mesh into connected components.
WStreamedLogger warn(const std::string &source)
Logging a warning message.
Definition: WLogger.h:309