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