vertexData.cpp

00001 /*  
00002  *  vertexData.cpp
00003  *  Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch>
00004  *                2009, Stefan Eilemann <eile@equalizergraphics.com>
00005  *
00006  * This library is free software; you can redistribute it and/or modify it under
00007  * the terms of the GNU Lesser General Public License version 2.1 as published
00008  * by the Free Software Foundation.
00009  *  
00010  * This library is distributed in the hope that it will be useful, but WITHOUT
00011  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00012  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00013  * details.
00014  * 
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this library; if not, write to the Free Software Foundation, Inc.,
00017  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018   
00019     
00020     Implementation of the VertexData class.
00021 */
00022 
00023 
00024 #include "vertexData.h"
00025 #include "ply.h"
00026 #include <cstdlib>
00027 #include <algorithm>
00028 
00029 
00030 using namespace std;
00031 using namespace mesh;
00032 
00033 
00034 /*  Contructor.  */
00035 VertexData::VertexData()
00036     : _invertFaces( false )
00037 {
00038     _boundingBox[0] = Vertex( 0.0f );
00039     _boundingBox[1] = Vertex( 0.0f );
00040 }
00041 
00042 
00043 /*  Read the vertex and (if available/wanted) color data from the open file.  */
00044 void VertexData::readVertices( PlyFile* file, const int nVertices, 
00045                                const bool readColors )
00046 {
00047     // temporary vertex structure for ply loading
00048     struct _Vertex
00049     {
00050         float           x;
00051         float           y;
00052         float           z;
00053         unsigned char   r;
00054         unsigned char   g;
00055         unsigned char   b;
00056     } vertex;
00057 
00058     PlyProperty vertexProps[] = 
00059     {
00060         { "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 },
00061         { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 },
00062         { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 },
00063         { "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, r ), 0, 0, 0, 0 },
00064         { "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, g ), 0, 0, 0, 0 },
00065         { "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, b ), 0, 0, 0, 0 }
00066     };
00067     
00068     // use all 6 properties when reading colors, only the first 3 otherwise
00069     int limit = readColors ? 6 : 3;
00070     for( int i = 0; i < limit; ++i ) 
00071         ply_get_property( file, "vertex", &vertexProps[i] );
00072     
00073     vertices.clear();
00074     vertices.reserve( nVertices );
00075     
00076     if( readColors )
00077     {
00078         colors.clear();
00079         colors.reserve( nVertices );
00080     }
00081     
00082     // read in the vertices
00083     for( int i = 0; i < nVertices; ++i )
00084     {
00085         ply_get_element( file, static_cast< void* >( &vertex ) );
00086         vertices.push_back( Vertex( vertex.x, vertex.y, vertex.z ) );
00087         if( readColors )
00088             colors.push_back( Color( vertex.r, vertex.g, vertex.b, 0 ) );
00089     }
00090 }
00091 
00092 
00093 /*  Read the index data from the open file.  */
00094 void VertexData::readTriangles( PlyFile* file, const int nFaces )
00095 {
00096     // temporary face structure for ply loading
00097     struct _Face
00098     {
00099         unsigned char   nVertices;
00100         int*            vertices;
00101     } face;
00102 
00103     PlyProperty faceProps[] = 
00104     {
00105         { "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ), 
00106           1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) }
00107     };
00108     
00109     ply_get_property( file, "face", &faceProps[0] );
00110     
00111     triangles.clear();
00112     triangles.reserve( nFaces );
00113     
00114     // read in the faces, asserting that they are only triangles
00115     uint8_t ind1 = _invertFaces ? 2 : 0;
00116     uint8_t ind3 = _invertFaces ? 0 : 2;
00117     for( int i = 0; i < nFaces; ++i )
00118     {
00119         ply_get_element( file, static_cast< void* >( &face ) );
00120         MESHASSERT( face.vertices != 0 );
00121         if( face.nVertices != 3 )
00122         {
00123             free( face.vertices );
00124             throw MeshException( "Error reading PLY file. Encountered a "
00125                                  "face which does not have three vertices." );
00126         }
00127         triangles.push_back( Triangle( face.vertices[ind1], 
00128                                        face.vertices[1],
00129                                        face.vertices[ind3] ) );
00130         
00131         // free the memory that was allocated by ply_get_element
00132         free( face.vertices );
00133     }
00134 }
00135 
00136 
00137 /*  Open a PLY file and read vertex, color and index data.  */
00138 bool VertexData::readPlyFile( const std::string& filename )
00139 {
00140     int     nPlyElems;
00141     char**  elemNames;
00142     int     fileType;
00143     float   version;
00144     bool    result = false;
00145     
00146     PlyFile* file = ply_open_for_reading( const_cast<char*>( filename.c_str( )),
00147                                           &nPlyElems, &elemNames, 
00148                                           &fileType, &version );
00149     if( !file )
00150     {
00151         MESHERROR << "Unable to open PLY file " << filename 
00152                   << " for reading." << endl;
00153         return result;
00154     }
00155     MESHASSERT( elemNames != 0 );
00156     
00157     #ifndef NDEBUG
00158     MESHINFO << filename << ": " << nPlyElems << " elements, file type = " 
00159              << fileType << ", version = " << version << endl;
00160     #endif
00161     
00162     for( int i = 0; i < nPlyElems; ++i )
00163     {
00164         int nElems;
00165         int nProps;
00166         
00167         PlyProperty** props = ply_get_element_description( file, elemNames[i], 
00168                                                            &nElems, &nProps );
00169         MESHASSERT( props != 0 );
00170         
00171         #ifndef NDEBUG
00172         MESHINFO << "element " << i << ": name = " << elemNames[i] << ", "
00173                  << nProps << " properties, " << nElems << " elements" << endl;
00174         for( int j = 0; j < nProps; ++j )
00175         {
00176             MESHINFO << "element " << i << ", property " << j << ": "
00177                      << "name = " << props[j]->name << endl;
00178         }
00179         #endif
00180         
00181         if( equal_strings( elemNames[i], "vertex" ) )
00182         {
00183             bool hasColors = false;
00184             // determine if the file stores vertex colors
00185             for( int j = 0; j < nProps; ++j )
00186                 if( equal_strings( props[j]->name, "red" ) )
00187                     hasColors = true;
00188             
00189             readVertices( file, nElems, hasColors );
00190             MESHASSERT( vertices.size() == static_cast< size_t >( nElems ) );
00191             if( hasColors )
00192             {
00193                 MESHASSERT( colors.size() == static_cast< size_t >( nElems ));
00194             }
00195         }
00196         else if( equal_strings( elemNames[i], "face" ) )
00197         try
00198         {
00199             readTriangles( file, nElems );
00200             MESHASSERT( triangles.size() == static_cast< size_t >( nElems ) );
00201             result = true;
00202         }
00203         catch( exception& e )
00204         {
00205             MESHERROR << "Unable to read PLY file, an exception occured:  " 
00206                       << e.what() << endl;
00207             // stop for loop by setting the loop variable to break condition
00208             // this way resources still get released even on error cases
00209             i = nPlyElems;
00210         }
00211         
00212         // free the memory that was allocated by ply_get_element_description
00213         for( int j = 0; j < nProps; ++j )
00214             free( props[j] );
00215         free( props );
00216     }
00217     
00218     ply_close( file );
00219     
00220     // free the memory that was allocated by ply_open_for_reading
00221     for( int i = 0; i < nPlyElems; ++i )
00222         free( elemNames[i] );
00223     free( elemNames );
00224     
00225     return result;
00226 }
00227 
00228 
00229 /*  Calculate the face or vertex normals of the current vertex data.  */
00230 void VertexData::calculateNormals( const bool vertexNormals )
00231 {
00232     #ifndef NDEBUG
00233     int wrongNormals = 0;
00234     #endif
00235     
00236     normals.clear();
00237     if( vertexNormals )
00238     {
00239         normals.reserve( vertices.size() );
00240         
00241         // initialize all normals to zero
00242         for( size_t i = 0; i < vertices.size(); ++i )
00243             normals.push_back( Normal( 0, 0, 0 ) );
00244     }
00245     else
00246         normals.reserve( triangles.size() );
00247     
00248     // iterate over all triangles and add their normals to adjacent vertices
00249     Normal  triangleNormal;
00250     Index   i0, i1, i2;
00251     for( size_t i = 0; i < triangles.size(); ++i )
00252     {
00253         i0 = triangles[i].at(0);
00254         i1 = triangles[i].at(1);
00255         i2 = triangles[i].at(2);
00256         triangleNormal.compute_normal( vertices[i0], vertices[i1], vertices[i2] );
00257         
00258         // count emtpy normals in debug mode
00259         #ifndef NDEBUG
00260         if( triangleNormal.length() == 0.0f )
00261             ++wrongNormals;
00262         #endif
00263          
00264         if( vertexNormals )
00265         {
00266             normals[i0] += triangleNormal; 
00267             normals[i1] += triangleNormal; 
00268             normals[i2] += triangleNormal;
00269         }
00270         else
00271             normals.push_back( triangleNormal ); 
00272     }
00273     
00274     // normalize all the normals
00275     if( vertexNormals )
00276         for( size_t i = 0; i < vertices.size(); ++i )
00277             normals[i].normalize();
00278     
00279     #ifndef NDEBUG
00280     if( wrongNormals > 0 )
00281         MESHINFO << wrongNormals << " faces had no valid normal." << endl;
00282     #endif 
00283 }
00284 
00285 
00286 /*  Calculate the bounding box of the current vertex data.  */
00287 void VertexData::calculateBoundingBox()
00288 {
00289     _boundingBox[0] = vertices[0];
00290     _boundingBox[1] = vertices[0];
00291     for( size_t v = 1; v < vertices.size(); ++v )
00292         for( size_t i = 0; i < 3; ++i )
00293         {
00294             _boundingBox[0][i] = min( _boundingBox[0][i], vertices[v][i] );
00295             _boundingBox[1][i] = max( _boundingBox[1][i], vertices[v][i] );
00296         }
00297 }
00298 
00299 
00300 /* Calculates longest axis for a set of triangles */
00301 Axis VertexData::getLongestAxis( const size_t start,
00302                                  const size_t elements ) const
00303 {
00304     if( start + elements > triangles.size() )
00305     {
00306         EQERROR << "incorrect request to getLongestAxis" << endl
00307                 << "start:     " << start                << endl
00308                 << "elements:  " << elements             << endl
00309                 << "sum:       " << start+elements       << endl
00310                 << "data size: " << triangles.size()     << endl;
00311         return AXIS_X;
00312     }
00313 
00314     BoundingBox bb;
00315     bb[0] = vertices[ triangles[start][0] ];
00316     bb[1] = vertices[ triangles[start][0] ];
00317 
00318     for( size_t t = start; t < start+elements; ++t )
00319         for( size_t v = 0; v < 3; ++v )
00320             for( size_t i = 0; i < 3; ++i )
00321             {
00322                 bb[0][i] = min( bb[0][i], vertices[ triangles[t][v] ][i] );
00323                 bb[1][i] = max( bb[1][i], vertices[ triangles[t][v] ][i] );
00324             }
00325 
00326     const GLfloat bbX = bb[1][0] - bb[0][0];
00327     const GLfloat bbY = bb[1][1] - bb[0][1];
00328     const GLfloat bbZ = bb[1][2] - bb[0][2];
00329 
00330     if( bbX >= bbY && bbX >= bbZ )
00331         return AXIS_X;
00332 
00333     if( bbY >= bbX && bbY >= bbZ )
00334         return AXIS_Y;
00335 
00336     return AXIS_Z;
00337 }
00338 
00339 
00340 /*  Scales the data to be within +- baseSize/2 (default 2.0) coordinates.  */
00341 void VertexData::scale( const float baseSize )
00342 {
00343     // calculate bounding box if not yet done
00344     if( _boundingBox[0].length() == 0.0f && _boundingBox[1].length() == 0.0f )
00345         calculateBoundingBox();
00346     
00347     // find largest dimension and determine scale factor
00348     float factor = 0.0f;
00349     for( size_t i = 0; i < 3; ++i )
00350         factor = max( factor, _boundingBox[1][i] - _boundingBox[0][i] );
00351     factor = baseSize / factor;
00352     
00353     // determine scale offset
00354     Vertex offset;
00355     for( size_t i = 0; i < 3; ++i )
00356         offset[i] = ( _boundingBox[0][i] + _boundingBox[1][i] ) * 0.5f;
00357     
00358     // scale the data
00359     for( size_t v = 0; v < vertices.size(); ++v )
00360         for( size_t i = 0; i < 3; ++i )
00361         {
00362             vertices[v][i] -= offset[i];
00363             vertices[v][i] *= factor;
00364         }
00365     
00366     // scale the bounding box
00367     for( size_t v = 0; v < 2; ++v )
00368         for( size_t i = 0; i < 3; ++i )
00369         {
00370             _boundingBox[v][i] -= offset[i];
00371             _boundingBox[v][i] *= factor;
00372         }
00373 }
00374 
00375 
00376 /*  Helper structure to sort Triangles with standard library sort function.  */
00377 struct _TriangleSort
00378 {
00379     _TriangleSort( const VertexData& data, const Axis axis ) : _data( data ),
00380                                                                _axis( axis ) {}
00381     
00382     bool operator() ( const Triangle& t1, const Triangle& t2 )
00383     {
00384         // references to both triangles' three vertices
00385         const Vertex& v11 = _data.vertices[ t1[0] ];
00386         const Vertex& v12 = _data.vertices[ t1[1] ];
00387         const Vertex& v13 = _data.vertices[ t1[2] ];
00388         const Vertex& v21 = _data.vertices[ t2[0] ];
00389         const Vertex& v22 = _data.vertices[ t2[1] ];
00390         const Vertex& v23 = _data.vertices[ t2[2] ];
00391         
00392         // compare first by given axis
00393         int axis = _axis;
00394         do
00395         {
00396             // test median of 'axis' component of all three vertices
00397             const float median1 = (v11[axis] + v12[axis] + v13[axis] ) / 3.0f;
00398             const float median2 = (v21[axis] + v22[axis] + v23[axis] ) / 3.0f;
00399             if( median1 != median2 )
00400                 return ( median1 < median2 );
00401             
00402             // if still equal, move on to the next axis
00403             axis = ( axis + 1 ) % 3;
00404         }
00405         while( axis != _axis );
00406         
00407         return false;
00408     }
00409     
00410     const VertexData&   _data;
00411     const Axis          _axis;
00412 };
00413 
00414 
00415 /*  Sort the index data from start to start + length along the given axis.  */
00416 void VertexData::sort( const Index start, const Index length, const Axis axis )
00417 {
00418     MESHASSERT( length > 0 );
00419     MESHASSERT( start + length <= triangles.size() );
00420     
00421     std::sort( triangles.begin() + start, 
00422                triangles.begin() + start + length,
00423                _TriangleSort( *this, axis ) );
00424 }
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8