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