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