OpenWalnut 1.3.1
WTriangleMesh.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <iostream>
00026 #include <list>
00027 #include <map>
00028 #include <sstream>
00029 #include <string>
00030 #include <utility>
00031 #include <vector>
00032 
00033 #include <osg/io_utils>
00034 
00035 #include "../common/datastructures/WUnionFind.h"
00036 #include "WTriangleMesh.h"
00037 
00038 // init _static_ member variable and provide a linker reference to it
00039 boost::shared_ptr< WPrototyped > WTriangleMesh::m_prototype = boost::shared_ptr< WPrototyped >();
00040 
00041 boost::shared_ptr< WPrototyped > WTriangleMesh::getPrototype()
00042 {
00043     if( !m_prototype )
00044     {
00045          m_prototype = boost::shared_ptr< WPrototyped >( new WTriangleMesh( 0, 0 ) );
00046     }
00047     return m_prototype;
00048 }
00049 
00050 /**
00051  * constructor that already reserves space for a given number of triangles and vertexes
00052  */
00053 WTriangleMesh::WTriangleMesh( size_t vertNum, size_t triangleNum )
00054     : m_countVerts( 0 ),
00055       m_countTriangles( 0 ),
00056       m_meshDirty( true ),
00057       m_neighborsCalculated( false )
00058 {
00059     m_verts = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
00060     m_textureCoordinates = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
00061     m_vertNormals = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( vertNum ) );
00062     m_vertColors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array( vertNum ) );
00063 
00064     m_triangles.resize( triangleNum * 3 );
00065     m_triangleNormals = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array( triangleNum ) );
00066     m_triangleColors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array( triangleNum ) );
00067 }
00068 
00069 WTriangleMesh::WTriangleMesh( osg::ref_ptr< osg::Vec3Array > vertices, const std::vector< size_t >& triangles )
00070     : m_countVerts( vertices->size() ),
00071       m_countTriangles( triangles.size() / 3 ),
00072       m_meshDirty( true ),
00073       m_neighborsCalculated( false ),
00074       m_verts( vertices ),
00075       m_textureCoordinates( new osg::Vec3Array( vertices->size() ) ),
00076       m_vertNormals( new osg::Vec3Array( vertices->size() ) ),
00077       m_vertColors( new osg::Vec4Array( vertices->size() ) ),
00078       m_triangles( triangles ),
00079       m_triangleNormals( new osg::Vec3Array( triangles.size() / 3 ) ),
00080       m_triangleColors( new osg::Vec4Array( triangles.size() / 3 ) )
00081 {
00082     WAssert( triangles.size() % 3 == 0, "Invalid triangle vector, having an invalid size (not divideable by 3)" );
00083 }
00084 
00085 WTriangleMesh::~WTriangleMesh()
00086 {
00087 }
00088 
00089 void WTriangleMesh::addVertex( float x, float y, float z )
00090 {
00091     addVertex( osg::Vec3( x, y, z ) );
00092 }
00093 
00094 void WTriangleMesh::addVertex( WPosition vert )
00095 {
00096     addVertex( osg::Vec3( vert[0], vert[1], vert[2] ) );
00097 }
00098 
00099 void WTriangleMesh::addTriangle( size_t vert0, size_t vert1, size_t vert2 )
00100 {
00101     if( m_triangles.size() == m_countTriangles * 3 )
00102     {
00103         m_triangles.resize( m_countTriangles * 3 + 3 );
00104     }
00105     m_triangles[ m_countTriangles * 3 ] = vert0;
00106     m_triangles[ m_countTriangles * 3 + 1 ] = vert1;
00107     m_triangles[ m_countTriangles * 3 + 2 ] = vert2;
00108     ++m_countTriangles;
00109 }
00110 
00111 void WTriangleMesh::addTriangle( osg::Vec3 vert0, osg::Vec3 vert1, osg::Vec3 vert2 )
00112 {
00113     addVertex( vert0 );
00114     addVertex( vert1 );
00115     addVertex( vert2 );
00116     addTriangle( m_countVerts - 3, m_countVerts - 2, m_countVerts - 1 );
00117 }
00118 
00119 void WTriangleMesh::setVertexNormal( size_t index, osg::Vec3 normal )
00120 {
00121     WAssert( index < m_countVerts, "set vertex normal: index out of range" );
00122     ( *m_vertNormals )[index] = normal;
00123 }
00124 
00125 void WTriangleMesh::setVertexNormal( size_t index, WPosition normal )
00126 {
00127     WAssert( index < m_countVerts, "set vertex normal: index out of range" );
00128     setVertexNormal( index, osg::Vec3( normal[0], normal[1], normal[2] ) );
00129 }
00130 
00131 void WTriangleMesh::setVertexColor( size_t index, osg::Vec4 color )
00132 {
00133     WAssert( index < m_countVerts, "set vertex color: index out of range" );
00134     ( *m_vertColors )[index] = color;
00135 }
00136 
00137 void WTriangleMesh::setTriangleColor( size_t index, osg::Vec4 color )
00138 {
00139     WAssert( index < m_countTriangles, "set triangle color: index out of range" );
00140     ( *m_triangleColors )[index] = color;
00141 }
00142 
00143 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getVertexArray()
00144 {
00145     return m_verts;
00146 }
00147 
00148 osg::ref_ptr< const osg::Vec3Array >WTriangleMesh::getVertexArray() const
00149 {
00150     return m_verts;
00151 }
00152 
00153 osg::ref_ptr< osg::Vec3Array > WTriangleMesh::getTextureCoordinateArray()
00154 {
00155     return m_textureCoordinates;
00156 }
00157 
00158 osg::ref_ptr< const osg::Vec3Array > WTriangleMesh::getTextureCoordinateArray() const
00159 {
00160     return m_textureCoordinates;
00161 }
00162 
00163 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getVertexNormalArray( bool forceRecalc )
00164 {
00165     if( forceRecalc || m_meshDirty )
00166     {
00167         recalcVertNormals();
00168     }
00169     return m_vertNormals;
00170 }
00171 
00172 osg::ref_ptr< osg::Vec3Array >WTriangleMesh::getTriangleNormalArray( bool forceRecalc )
00173 {
00174     if( forceRecalc || m_meshDirty )
00175     {
00176         recalcVertNormals();
00177     }
00178     return m_triangleNormals;
00179 }
00180 
00181 
00182 osg::ref_ptr< osg::Vec4Array >WTriangleMesh::getVertexColorArray()
00183 {
00184     return m_vertColors;
00185 }
00186 
00187 const std::vector< size_t >& WTriangleMesh::getTriangles() const
00188 {
00189     return m_triangles;
00190 }
00191 
00192 osg::Vec3 WTriangleMesh::getVertex( size_t index ) const
00193 {
00194     WAssert( index < m_countVerts, "get vertex: index out of range" );
00195     return ( *m_verts )[index];
00196 }
00197 
00198 osg::Vec4 WTriangleMesh::getVertColor( size_t index ) const
00199 {
00200     WAssert( index < m_countVerts, "get vertex color: index out of range" );
00201     return ( *m_vertColors )[index];
00202 }
00203 
00204 WVector3d WTriangleMesh::getNormal( size_t index )
00205 {
00206     WAssert( index < m_countVerts, "get normal as position: index out of range" );
00207     if( m_meshDirty )
00208     {
00209         recalcVertNormals();
00210     }
00211     return WPosition( ( *m_vertNormals )[index][0], ( *m_vertNormals )[index][1], ( *m_vertNormals )[index][2] );
00212 }
00213 
00214 void WTriangleMesh::removeVertex( size_t index )
00215 {
00216     WAssert( index < m_countVerts, "remove vertex: index out of range" );
00217     if( m_vertexIsInTriangle[ index ].size() > 0 )
00218     {
00219         return;
00220     }
00221     ( *m_verts ).erase( ( *m_verts ).begin() + index );
00222 
00223     for( size_t i = 0; i < m_countTriangles * 3; ++i )
00224     {
00225         if( m_triangles[ i ] > index )
00226         {
00227             --m_triangles[ i ];
00228         }
00229     }
00230     m_meshDirty = true;
00231 }
00232 
00233 void WTriangleMesh::removeTriangle( size_t index )
00234 {
00235     WAssert( index < m_countTriangles, "remove triangle: index out of range" );
00236     m_triangles.erase( m_triangles.begin() + index * 3, m_triangles.begin() + index * 3 + 3 );
00237     m_meshDirty = true;
00238 }
00239 
00240 void WTriangleMesh::recalcVertNormals()
00241 {
00242     updateVertsInTriangles();
00243 
00244     ( *m_vertNormals ).resize( m_countVerts );
00245     ( *m_triangleNormals ).resize( m_countTriangles );
00246 
00247     for( size_t i = 0; i < m_countTriangles; ++i )
00248     {
00249         ( *m_triangleNormals )[i] = calcTriangleNormal( i );
00250     }
00251 
00252     for( size_t vertId = 0; vertId < m_countVerts; ++vertId )
00253     {
00254         osg::Vec3 tempNormal( 0.0, 0.0, 0.0 );
00255         for( size_t neighbour = 0; neighbour < m_vertexIsInTriangle[vertId].size(); ++neighbour )
00256         {
00257             tempNormal += ( *m_triangleNormals )[ m_vertexIsInTriangle[vertId][neighbour] ];
00258         }
00259         tempNormal *= 1./m_vertexIsInTriangle[vertId].size();
00260 
00261         tempNormal.normalize();
00262         ( *m_vertNormals )[vertId] = tempNormal;
00263     }
00264 
00265     m_meshDirty = false;
00266 }
00267 
00268 void WTriangleMesh::updateVertsInTriangles()
00269 {
00270     m_vertexIsInTriangle.clear();
00271     std::vector< size_t >v;
00272     m_vertexIsInTriangle.resize( ( *m_verts ).size(), v );
00273 
00274     for( size_t i = 0; i < m_countTriangles; ++i )
00275     {
00276         m_vertexIsInTriangle[ getTriVertId0( i ) ].push_back( i );
00277         m_vertexIsInTriangle[ getTriVertId1( i ) ].push_back( i );
00278         m_vertexIsInTriangle[ getTriVertId2( i ) ].push_back( i );
00279     }
00280 }
00281 
00282 osg::Vec3 WTriangleMesh::calcTriangleNormal( size_t triangle )
00283 {
00284     osg::Vec3 v1( getTriVert( triangle, 1 ) - getTriVert( triangle, 0 ) );
00285     osg::Vec3 v2( getTriVert( triangle, 2 ) - getTriVert( triangle, 0 ) );
00286 
00287     osg::Vec3 tempNormal( 0, 0, 0 );
00288 
00289     tempNormal[0] = v1[1] * v2[2] - v1[2] * v2[1];
00290     tempNormal[1] = v1[2] * v2[0] - v1[0] * v2[2];
00291     tempNormal[2] = v1[0] * v2[1] - v1[1] * v2[0];
00292 
00293     tempNormal.normalize();
00294 
00295     return tempNormal;
00296 }
00297 
00298 osg::Vec3 WTriangleMesh::calcNormal( osg::Vec3 vert0, osg::Vec3 vert1, osg::Vec3 vert2 )
00299 {
00300     osg::Vec3 v1( vert1 - vert0 );
00301     osg::Vec3 v2( vert2 - vert0 );
00302 
00303     osg::Vec3 tempNormal( 0, 0, 0 );
00304 
00305     tempNormal[0] = v1[1] * v2[2] - v1[2] * v2[1];
00306     tempNormal[1] = v1[2] * v2[0] - v1[0] * v2[2];
00307     tempNormal[2] = v1[0] * v2[1] - v1[1] * v2[0];
00308 
00309     tempNormal.normalize();
00310 
00311     return tempNormal;
00312 }
00313 
00314 size_t WTriangleMesh::vertSize() const
00315 {
00316     return m_countVerts;
00317 }
00318 
00319 size_t WTriangleMesh::triangleSize() const
00320 {
00321     return m_countTriangles;
00322 }
00323 
00324 void WTriangleMesh::calcNeighbors()
00325 {
00326     std::vector<size_t> v( 3, -1 );
00327     m_triangleNeighbors.resize( ( *m_triangleNormals ).size(), v );
00328 
00329     for( size_t triId = 0; triId < m_countTriangles; ++triId )
00330     {
00331         size_t coVert0 = getTriVertId0( triId );
00332         size_t coVert1 = getTriVertId1( triId );
00333         size_t coVert2 = getTriVertId2( triId );
00334 
00335         m_triangleNeighbors[triId][0] = getNeighbor( coVert0, coVert1, triId );
00336         m_triangleNeighbors[triId][1] = getNeighbor( coVert1, coVert2, triId );
00337         m_triangleNeighbors[triId][2] = getNeighbor( coVert2, coVert0, triId );
00338     }
00339     m_neighborsCalculated = true;
00340 }
00341 
00342 size_t WTriangleMesh::getNeighbor( const size_t coVert1, const size_t coVert2, const size_t triangleNum )
00343 {
00344     std::vector< size_t > candidates = m_vertexIsInTriangle[coVert1];
00345     std::vector< size_t > compares = m_vertexIsInTriangle[coVert2];
00346 
00347     for( size_t i = 0; i < candidates.size(); ++i )
00348     {
00349         for( size_t k = 0; k < compares.size(); ++k )
00350         {
00351             if( ( candidates[i] != triangleNum ) && ( candidates[i] == compares[k] ) )
00352             {
00353                 return candidates[i];
00354             }
00355         }
00356     }
00357     return triangleNum;
00358 }
00359 
00360 void WTriangleMesh::doLoopSubD()
00361 {
00362     m_numTriVerts = m_countVerts;
00363     m_numTriFaces = m_countTriangles;
00364 
00365     ( *m_verts ).resize( m_numTriVerts * 4 );
00366     m_triangles.resize( m_numTriFaces * 4 * 3 );
00367 
00368     updateVertsInTriangles();
00369 
00370     osg::Vec3* newVertexPositions = new osg::Vec3[m_numTriVerts];
00371 
00372     //std::cout << "Loop subdivision pass 1" << std::endl;
00373     for( size_t i = 0; i < m_numTriVerts; ++i )
00374     {
00375         newVertexPositions[i] = loopCalcNewPosition( i );
00376     }
00377 
00378     //std::cout << "Loop subdivision pass 2" << std::endl;
00379     for( size_t i = 0; i < m_numTriFaces; ++i )
00380     {
00381         loopInsertCenterTriangle( i );
00382     }
00383     ( *m_verts ).resize( m_countVerts );
00384     std::vector< size_t >v;
00385     m_vertexIsInTriangle.resize( ( *m_verts ).size(), v );
00386 
00387     //std::cout << "Loop subdivision pass 3" << std::endl;
00388     for( size_t i = 0; i < m_numTriFaces; ++i )
00389     {
00390         loopInsertCornerTriangles( i );
00391     }
00392 
00393     //std::cout << "Loop subdivision pass 4" << std::endl;
00394     for( size_t i = 0; i < m_numTriVerts; ++i )
00395     {
00396         ( *m_verts )[i] = newVertexPositions[i];
00397     }
00398 
00399     delete[] newVertexPositions;
00400 
00401     m_vertNormals->resize( m_verts->size() );
00402     m_vertColors->resize( m_verts->size() );
00403     m_triangleColors->resize( m_triangles.size() / 3 );
00404 
00405     m_meshDirty = true;
00406 }
00407 
00408 
00409 osg::Vec3 WTriangleMesh::loopCalcNewPosition( size_t vertId )
00410 {
00411     std::vector< size_t > starP = m_vertexIsInTriangle[vertId];
00412     int starSize = starP.size();
00413 
00414     osg::Vec3 oldPos = getVertex( vertId );
00415     double alpha = loopGetAlpha( starSize );
00416 
00417     double scale = 1.0 - ( static_cast<double>( starSize ) * alpha );
00418     oldPos *= scale;
00419 
00420     osg::Vec3 newPos;
00421     int edgeV = 0;
00422     for( int i = 0; i < starSize; i++ )
00423     {
00424         edgeV = loopGetNextVertex( starP[i], vertId );
00425         osg::Vec3 translate = getVertex( edgeV );
00426         newPos += translate;
00427     }
00428     newPos *= alpha;
00429 
00430     return oldPos + newPos;
00431 }
00432 
00433 void WTriangleMesh::loopInsertCenterTriangle( size_t triId )
00434 {
00435     size_t edgeVerts[3];
00436 
00437     edgeVerts[0] = loopCalcEdgeVert( triId, getTriVertId0( triId ), getTriVertId1( triId ), getTriVertId2( triId ) );
00438     edgeVerts[1] = loopCalcEdgeVert( triId, getTriVertId1( triId ), getTriVertId2( triId ), getTriVertId0( triId ) );
00439     edgeVerts[2] = loopCalcEdgeVert( triId, getTriVertId2( triId ), getTriVertId0( triId ), getTriVertId1( triId ) );
00440 
00441     addTriangle( edgeVerts[0], edgeVerts[1], edgeVerts[2] );
00442 }
00443 
00444 
00445 size_t WTriangleMesh::loopCalcEdgeVert( size_t triId, size_t edgeV1, size_t edgeV2, size_t V3 )
00446 {
00447     size_t neighborVert = -1;
00448     size_t neighborFaceNum = -1;
00449     osg::Vec3 edgeVert;
00450 
00451     neighborFaceNum = getNeighbor( edgeV1, edgeV2, triId );
00452 
00453     if( neighborFaceNum == triId )
00454     {
00455         osg::Vec3 edgeVert = ( ( *m_verts )[edgeV1] + ( *m_verts )[edgeV2] ) / 2.0;
00456         size_t vertId = m_countVerts;
00457         addVertex( edgeVert );
00458         return vertId;
00459     }
00460 
00461     else if( neighborFaceNum > triId )
00462     {
00463         neighborVert = loopGetThirdVert( edgeV1, edgeV2, neighborFaceNum );
00464 
00465         osg::Vec3 edgePart = ( *m_verts )[edgeV1] + ( *m_verts )[edgeV2];
00466         osg::Vec3 neighborPart = ( *m_verts )[neighborVert] + ( *m_verts )[V3];
00467 
00468         edgeVert = ( ( edgePart * ( 3.0 / 8.0 ) ) + ( neighborPart * ( 1.0 / 8.0 ) ) );
00469         size_t vertId = m_countVerts;
00470         addVertex( edgeVert );
00471         return vertId;
00472     }
00473     else
00474     {
00475         size_t neighborCenterP = neighborFaceNum + m_numTriFaces;
00476         size_t neighborP = neighborFaceNum;
00477 
00478         if( getTriVertId0( neighborP ) == edgeV2 )
00479         {
00480             return getTriVertId0( neighborCenterP );
00481         }
00482         else if( getTriVertId1( neighborP ) == edgeV2 )
00483         {
00484             return getTriVertId1( neighborCenterP );
00485         }
00486         else
00487         {
00488             return getTriVertId2( neighborCenterP );
00489         }
00490     }
00491     return -1;
00492 }
00493 
00494 void WTriangleMesh::loopInsertCornerTriangles( size_t triId )
00495 {
00496     // comment:             center are twisted from the orignal vertices.
00497     // original:    0, 1, 2
00498     // center:              a, b, c
00499     // reAsgnOrig:  0, a, c
00500     // addTris:             1, b, a
00501     // addTris:             2, c, b
00502     //
00503     size_t originalTri0 = getTriVertId0( triId );
00504     size_t originalTri1 = getTriVertId1( triId );
00505     size_t originalTri2 = getTriVertId2( triId );
00506 
00507     size_t centerTri0 = getTriVertId0( triId + m_numTriFaces );
00508     size_t centerTri1 = getTriVertId1( triId + m_numTriFaces );
00509     size_t centerTri2 = getTriVertId2( triId + m_numTriFaces );
00510 
00511     addTriangle( originalTri1, centerTri1, centerTri0 );
00512     addTriangle( originalTri2, centerTri2, centerTri1 );
00513     loopSetTriangle( triId, originalTri0, centerTri0, centerTri2 );
00514 }
00515 
00516 void WTriangleMesh::loopSetTriangle( size_t triId, size_t vertId1, size_t vertId2, size_t vertId3 )
00517 {
00518     loopEraseTriangleFromVertex( triId, getTriVertId1( triId ) );
00519     loopEraseTriangleFromVertex( triId, getTriVertId2( triId ) );
00520 
00521     setTriVert0( triId, vertId1 );
00522     setTriVert1( triId, vertId2 );
00523     setTriVert2( triId, vertId3 );
00524 
00525     m_vertexIsInTriangle[vertId2].push_back( triId );
00526     m_vertexIsInTriangle[vertId3].push_back( triId );
00527 }
00528 
00529 void WTriangleMesh::loopEraseTriangleFromVertex( size_t triId, size_t vertId )
00530 {
00531     std::vector< size_t > temp;
00532     for( size_t i = 0; i < m_vertexIsInTriangle[vertId].size(); ++i )
00533     {
00534         if( triId != m_vertexIsInTriangle[vertId][i] )
00535             temp.push_back( m_vertexIsInTriangle[vertId][i] );
00536     }
00537     m_vertexIsInTriangle[vertId] = temp;
00538 }
00539 
00540 double WTriangleMesh::loopGetAlpha( int n )
00541 {
00542     double answer;
00543     if( n > 3 )
00544     {
00545         double center = ( 0.375 + ( 0.25 * cos( ( 2.0 * 3.14159265358979 ) / static_cast<double>( n ) ) ) );
00546         answer = ( 0.625 - ( center * center ) ) / static_cast<double>( n );
00547     }
00548     else
00549     {
00550         answer = 3.0 / 16.0;
00551     }
00552     return answer;
00553 }
00554 
00555 size_t WTriangleMesh::loopGetNextVertex( size_t triNum, size_t vertNum )
00556 {
00557     if( getTriVertId0( triNum ) == vertNum )
00558     {
00559         return getTriVertId1( triNum );
00560     }
00561     else if( getTriVertId1( triNum ) == vertNum )
00562     {
00563         return getTriVertId2( triNum );
00564     }
00565     return getTriVertId0( triNum );
00566 }
00567 
00568 size_t WTriangleMesh::loopGetThirdVert( size_t coVert1, size_t coVert2, size_t triangleNum )
00569 {
00570     if( !( getTriVertId0( triangleNum ) == coVert1 ) && !( getTriVertId0( triangleNum ) == coVert2 ) )
00571     {
00572         return getTriVertId0( triangleNum );
00573     }
00574     else if( !( getTriVertId1( triangleNum ) == coVert1 ) && !( getTriVertId1( triangleNum ) == coVert2 ) )
00575     {
00576         return getTriVertId1( triangleNum );
00577     }
00578     return getTriVertId2( triangleNum );
00579 }
00580 
00581 void WTriangleMesh::addMesh( boost::shared_ptr<WTriangleMesh> mesh, float xOff, float yOff, float zOff )
00582 {
00583     size_t oldVertSize = m_countVerts;
00584 
00585     ( *m_vertColors ).resize( oldVertSize + mesh->vertSize() );
00586     for( size_t i = 0; i < mesh->vertSize(); ++i )
00587     {
00588         osg::Vec3 v( mesh->getVertex( i ) );
00589         v[0] += xOff;
00590         v[1] += yOff;
00591         v[2] += zOff;
00592         addVertex( v );
00593         setVertexColor( oldVertSize + i, mesh->getVertColor( i ) );
00594     }
00595     for( size_t i = 0; i < mesh->triangleSize(); ++i )
00596     {
00597         addTriangle( mesh->getTriVertId0( i ) + oldVertSize, mesh->getTriVertId1( i ) + oldVertSize, mesh->getTriVertId2( i ) + oldVertSize );
00598     }
00599     m_meshDirty = true;
00600 }
00601 
00602 void WTriangleMesh::translateMesh( float xOff, float yOff, float zOff )
00603 {
00604     osg::Vec3 t( xOff, yOff, zOff );
00605     for( size_t i = 0; i < ( *m_verts ).size(); ++i )
00606     {
00607         ( *m_verts )[i] += t;
00608     }
00609 }
00610 
00611 void WTriangleMesh::zoomMesh( float zoom )
00612 {
00613     for( size_t i = 0; i < ( *m_verts ).size(); ++i )
00614     {
00615         ( *m_verts )[i] *= zoom;
00616     }
00617 }
00618 
00619 void WTriangleMesh::rescaleVertexColors()
00620 {
00621     float maxR = 0;
00622     float maxG = 0;
00623     float maxB = 0;
00624     for( size_t vertId = 0; vertId < m_vertColors->size(); ++vertId )
00625     {
00626         if( ( *m_vertColors )[vertId][0] > maxR )
00627         {
00628             maxR = ( *m_vertColors )[vertId][0];
00629         }
00630         if( ( *m_vertColors )[vertId][1] > maxG )
00631         {
00632             maxG = ( *m_vertColors )[vertId][1];
00633         }
00634         if( ( *m_vertColors )[vertId][2] > maxB )
00635         {
00636             maxB = ( *m_vertColors )[vertId][2];
00637         }
00638     }
00639     for( size_t vertId = 0; vertId < m_vertColors->size(); ++vertId )
00640     {
00641         ( *m_vertColors )[vertId][0] /= maxR;
00642         ( *m_vertColors )[vertId][1] /= maxG;
00643         ( *m_vertColors )[vertId][2] /= maxB;
00644     }
00645 }
00646 
00647 std::ostream& tm_utils::operator<<( std::ostream& os, const WTriangleMesh& rhs )
00648 {
00649     std::stringstream ss;
00650     ss << "WTriangleMesh( #vertices=" << rhs.vertSize() << " #triangles=" << rhs.triangleSize() << " )" << std::endl;
00651     using string_utils::operator<<;
00652     size_t count = 0;
00653     ss << std::endl;
00654     const std::vector< size_t >& triangles = rhs.getTriangles();
00655     osg::ref_ptr< const osg::Vec3Array > vertices = rhs.getVertexArray();
00656     for( size_t vID = 0 ; vID <= triangles.size() - 3; ++count )
00657     {
00658         std::stringstream prefix;
00659         prefix << "triangle: " << count << "[ ";
00660         std::string indent( prefix.str().size(), ' ' );
00661         using osg::operator<<; // using operator<< as defined in osg/io_utils
00662         ss << prefix.str() << vertices->at( triangles[ vID++ ] ) << std::endl;
00663         ss << indent << vertices->at( triangles[ vID++ ] ) << std::endl;
00664         ss << indent << vertices->at( triangles[ vID++ ] ) << std::endl;
00665         ss << std::string( indent.size() - 2, ' ' ) << "]" << std::endl;
00666     }
00667     return os << ss.str();
00668 }
00669 
00670 boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > tm_utils::componentDecomposition( const WTriangleMesh& mesh )
00671 {
00672     boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > result( new std::list< boost::shared_ptr< WTriangleMesh > >() );
00673     if( mesh.vertSize() <= 0 ) // no component possible
00674     {
00675         return result;
00676     }
00677     if( mesh.triangleSize() < 3 )
00678     {
00679         if( mesh.vertSize() > 0 )
00680         {
00681             // there are vertices but no triangles
00682             WAssert( false, "Not implemented the decomposition of a TriangleMesh without any triangles" );
00683         }
00684         else // no component possible
00685         {
00686             return result;
00687         }
00688     }
00689 
00690     WUnionFind uf( mesh.vertSize() ); // idea: every vertex in own component, then successivley join in accordance with the triangles
00691 
00692     const std::vector< size_t >& triangles = mesh.getTriangles();
00693     for( size_t vID = 0; vID <= triangles.size() - 3; vID += 3)
00694     {
00695         uf.merge( triangles[ vID ], triangles[ vID + 1 ] );
00696         uf.merge( triangles[ vID ], triangles[ vID + 2 ] ); // uf.merge( triangles[ vID + 2 ], triangles[ vID + 1 ] ); they are already in same
00697     }
00698 
00699     // ATTENTION: The reason for using the complex BucketType instead of pasting vertices directly into a new WTriangleMesh
00700     // is performance! For example: If there are many vertices reused inside the former WTriangleMesh mesh, then we want
00701     // to reuse them in the new components too. Hence we must determine if a certain vertex is already inside the new component.
00702     // Since the vertices are organized in a vector, we can use std::find( v.begin, v.end(), vertexToLookUp ) which results
00703     // in O(N^2) or we could use faster lookUp via key and value leading to the map and the somehow complicated BucketType.
00704     typedef std::map< osg::Vec3, size_t > VertexType; // look up fast if a vertex is already inside the new mesh!
00705     typedef std::vector< size_t > TriangleType;
00706     typedef std::pair< VertexType, TriangleType > BucketType; // Later on the Bucket will be transformed into the new WTriangleMesh component
00707     std::map< size_t, BucketType > buckets; // Key identify with the cannonical element from UnionFind the new connected component
00708 
00709     osg::ref_ptr< const osg::Vec3Array > vertices = mesh.getVertexArray();
00710     for( size_t vID = 0; vID <= triangles.size() - 3; vID += 3 )
00711     {
00712         size_t component = uf.find( triangles[ vID ] );
00713         if( buckets.find( component ) == buckets.end() )
00714         {
00715             buckets[ component ] = BucketType( VertexType(), TriangleType() ); // create new bucket
00716         }
00717 
00718         // Note: We discard the order of the points and indices, but semantically the structure remains the same
00719         VertexType& mapRef = buckets[ component ].first; // short hand alias
00720         for( int i = 0; i < 3; ++i )
00721         {
00722             size_t id = 0;
00723             const osg::Vec3& vertex = ( *vertices )[ triangles[ vID + i ] ];
00724             if( mapRef.find( vertex ) == mapRef.end() )
00725             {
00726                 id = mapRef.size(); // since size might change in next line
00727                 mapRef[ vertex ] = id;
00728             }
00729             else
00730             {
00731                 id = mapRef[ vertex ];
00732             }
00733             buckets[ component ].second.push_back( id );
00734         }
00735     }
00736 
00737     for( std::map< size_t, BucketType >::const_iterator cit = buckets.begin(); cit != buckets.end(); ++cit )
00738     {
00739         osg::ref_ptr< osg::Vec3Array > newVertices( new osg::Vec3Array );
00740         newVertices->resize( cit->second.first.size() );
00741         for( VertexType::const_iterator vit = cit->second.first.begin(); vit != cit->second.first.end(); ++vit )
00742         {
00743             newVertices->at( vit->second ) = vit->first; // if you are sure that vit->second is always valid replace at() call with operator[]
00744         }
00745         boost::shared_ptr< WTriangleMesh > newMesh( new WTriangleMesh( newVertices, cit->second.second ) );
00746         result->push_back( newMesh );
00747     }
00748 
00749     return result;
00750 }
00751 
00752 osg::ref_ptr< osg::Vec4Array > WTriangleMesh::getTriangleColors() const
00753 {
00754     return m_triangleColors;
00755 }