# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlGraphics/PolygonSimplifier.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.com                                               */
    00005 /*                                                                                    */
    00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
    00007 /*  All rights reserved.                                                              */
    00008 /*                                                                                    */
    00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
    00010 /*  are permitted provided that the following conditions are met:                     */
    00011 /*                                                                                    */
    00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
    00013 /*  list of conditions and the following disclaimer.                                  */
    00014 /*                                                                                    */
    00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
    00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
    00017 /*  other materials provided with the distribution.                                   */
    00018 /*                                                                                    */
    00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
    00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
    00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
    00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
    00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
    00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
    00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
    00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
    00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
    00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
    00029 /*                                                                                    */
    00030 /**************************************************************************************/
    00031
    00032 #include <vlGraphics/PolygonSimplifier.hpp>
    00033 #include <vlGraphics/DoubleVertexRemover.hpp>
    00034 #include <vlCore/Time.hpp>
    00035 #include <vlCore/Log.hpp>
    00036 #include <vlCore/Say.hpp>
    00037 #include <set>
    00038
    00039 using namespace vl;
    00040
    00041 //-----------------------------------------------------------------------------
    00042 namespace
    00043 {
    00044   class VertexPtrWrapper
    00045   {
    00046   public:
    00047     VertexPtrWrapper(PolygonSimplifier::Vertex* ptr=NULL): mVertex(ptr) {}
    00048
    00049     bool operator==(const VertexPtrWrapper& other) const
    00050     {
    00051       return mVertex == other.mVertex;
    00052     }
    00053
    00054     bool operator!=(const VertexPtrWrapper& other) const
    00055     {
    00056       return mVertex == other.mVertex;
    00057     }
    00058
    00059     bool operator<(const VertexPtrWrapper& other) const
    00060     {
    00061       if ( mVertex->collapseCost() != other.mVertex->collapseCost() )
    00062         return mVertex->collapseCost() < other.mVertex->collapseCost();
    00063       else
    00064         return mVertex < other.mVertex;
    00065     }
    00066     PolygonSimplifier::Vertex* mVertex;
    00067   };
    00068 }
    00069 //-----------------------------------------------------------------------------
    00070 void PolygonSimplifier::simplify(float simplification_ratio, Geometry* geom)
    00071 {
    00072   if ( simplification_ratio > 1.0f || simplification_ratio <= 0.0f )
    00073     return;
    00074
    00075   ArrayFloat3* pvec3 = dynamic_cast<ArrayFloat3*>( geom->vertexArray() );
    00076   if (pvec3)
    00077   {
    00078     simplify( (int)(simplification_ratio*pvec3->size()), geom );
    00079   }
    00080   else
    00081   {
    00082     Log::error("PolygonSimplifier::simplify() supports only position arrays of type ArrayFloat3.\n");
    00083     return;
    00084   }
    00085 }
    00086 //-----------------------------------------------------------------------------
    00087 void PolygonSimplifier::simplify(int target_vertex_count, Geometry* geom)
    00088 {
    00089   // we don't support vertex attributes of any kind yet
    00090   #ifndef NDEBUG
    00091     bool problem = false;
    00092     problem |= geom->normalArray() != NULL;
    00093     problem |= geom->colorArray() != NULL;
    00094     problem |= geom->secondaryColorArray() != NULL;
    00095     problem |= geom->fogCoordArray() != NULL;
    00096     for( int i=0; i<VL_MAX_TEXTURE_UNITS; ++i)
    00097       problem |= geom->texCoordArray(i) != NULL;
    00098     problem |= geom->vertexAttribArrays()->size() != 0;
    00099     if (problem)
    00100       Log::warning("PolygonSimplifier::simplify() simplifies only the position array of a Geometry, the other attibutes will be discarded.\n");
    00101   #endif
    00102
    00103   if (!dynamic_cast<ArrayFloat3*>(geom->vertexArray()))
    00104   {
    00105     Log::error("PolygonSimplifier::simplify() supports only position arrays of type ArrayFloat3!\n");
    00106     return;
    00107   }
    00108
    00109   Time timer;
    00110   timer.start();
    00111
    00112   if ( removeDoubles() )
    00113   {
    00114     DoubleVertexRemover remover;
    00115     remover.removeDoubles( geom );
    00116   }
    00117
    00118   std::vector<fvec3> verts;
    00119   std::vector<int> indices;
    00120   indices.reserve(1000);
    00121
    00122   // merge all triangles in a single DrawElementsUInt
    00123   ref<DrawElementsUInt> pint = new DrawElementsUInt(PT_TRIANGLES, 1);
    00124   for(int i=0; i<geom->drawCalls()->size(); ++i)
    00125   {
    00126     DrawCall* prim = geom->drawCalls()->at(i);
    00127     for(TriangleIterator trit = prim->triangleIterator(); !trit.isEnd(); trit.next())
    00128     {
    00129       indices.push_back( trit.a() );
    00130       indices.push_back( trit.b() );
    00131       indices.push_back( trit.c() );
    00132     }
    00133   }
    00134
    00135   // fill vertices
    00136   ref<ArrayFloat3> pvec3 = dynamic_cast<ArrayFloat3*>( geom->vertexArray() );
    00137   verts.resize( pvec3->size() );
    00138   memcpy( &verts[0], pvec3->ptr(), sizeof(verts[0])   * verts.size() );
    00139
    00140   simplify(target_vertex_count, verts, indices);
    00141
    00142   pvec3->resize( (int)verts.size() );
    00143   pint->indices()->resize( (int)indices.size() );
    00144   memcpy( pvec3->ptr(),               &verts[0],   sizeof(verts[0])   * verts.size() );
    00145   memcpy( pint->indices()->ptr(), &indices[0], sizeof(indices[0]) * indices.size() );
    00146
    00147   // install draw call
    00148
    00149   geom->drawCalls()->clear();
    00150   geom->drawCalls()->push_back(pint.get());
    00151
    00152   // clear up other vertex arrays
    00153   geom->setNormalArray(NULL);
    00154   geom->setColorArray(NULL);
    00155   geom->setSecondaryColorArray(NULL);
    00156   geom->setFogCoordArray(NULL);
    00157   for( int i=0; i<VL_MAX_TEXTURE_UNITS; ++i)
    00158     geom->setTexCoordArray(i, NULL);
    00159   geom->vertexAttribArrays()->clear();
    00160
    00161   if (verbose())
    00162     Log::print( Say("PolygonSimplifier::simplify() done in %.3ns\n") << timer.elapsed() );
    00163 }
    00164 //-----------------------------------------------------------------------------
    00165 void PolygonSimplifier::simplify(int target_vertex_count, std::vector<fvec3>& in_out_verts, std::vector<int>& in_out_tris)
    00166 {
    00167   if (verbose())
    00168     Log::print("PolygonSimplifier::simplify() starting ... \n");
    00169
    00170   Time timer;
    00171   timer.start();
    00172
    00173   mSimplifiedVertices.clear();
    00174   mSimplifiedTriangles.clear();
    00175   mProtectedVerts.clear();
    00176   mTriangleLump.clear();
    00177   mVertexLump.clear(); // mic fixme: this is the one taking time.
    00178
    00179   // preallocate vertices and triangles in one chunk
    00180   mTriangleLump.resize(in_out_tris.size()/3);
    00181   mVertexLump.resize(in_out_verts.size());
    00182
    00183   int polys_before = (int)in_out_tris.size() / 3;
    00184   int verts_before = (int)in_out_verts.size();
    00185
    00186   mSimplifiedTriangles.resize( in_out_tris.size() / 3 );
    00187   mSimplifiedVertices.resize( in_out_verts.size() );
    00188
    00189 #define SHUFFLE_VERTICES 0
    00190
    00191 #if SHUFFLE_VERTICES
    00192   std::vector<Vertex*> vertex_pool;
    00193   vertex_pool.resize( in_out_verts.size() );
    00194   for(int i=0; i<(int)mVertexLump.size(); ++i)
    00195     vertex_pool[i] = &mVertexLump[i];
    00196
    00197   // shuffle the vertices
    00198   for(int i=0; i<(int)vertex_pool.size(); ++i)
    00199   {
    00200     int a = int( (float)rand() / (RAND_MAX+1) * vertex_pool.size() );
    00201     int b = int( (float)rand() / (RAND_MAX+1) * vertex_pool.size() );
    00202     Vertex* tmp = vertex_pool[a];
    00203     vertex_pool[a] = vertex_pool[b];
    00204     vertex_pool[b] = tmp;
    00205   }
    00206 #endif
    00207
    00208   // initialize vertices
    00209   for(int ivert=0; ivert<(int)in_out_verts.size(); ++ivert)
    00210   {
    00211 #if SHUFFLE_VERTICES
    00212     mSimplifiedVertices[ivert] = vertex_pool[ivert];
    00213 #else
    00214     mSimplifiedVertices[ivert] = &mVertexLump[ivert];
    00215 #endif
    00216     mSimplifiedVertices[ivert]->mPosition = in_out_verts[ivert];
    00217     // so that the user knows which vertex is which and can regenerate per-vertex
    00218     // information like textures coordinates, colors etc.
    00219     mSimplifiedVertices[ivert]->mOriginalIndex = ivert;
    00220
    00221     // unprotect the vertex
    00222     mSimplifiedVertices[ivert]->mProtected = false;
    00223
    00224     // reserve the memory for quicker allocation
    00225     mSimplifiedVertices[ivert]->mIncidentTriangles.reserve(12);
    00226     mSimplifiedVertices[ivert]->mAdjacentVerts.reserve(12);
    00227   }
    00228
    00229   // initialize triangles
    00230   for(int idx=0, itri=0; idx<(int)in_out_tris.size(); idx+=3, ++itri)
    00231   {
    00232     mSimplifiedTriangles[itri] = &mTriangleLump[itri];
    00233     mSimplifiedTriangles[itri]->mVertices[0] = mSimplifiedVertices[ in_out_tris[idx+0] ];
    00234     mSimplifiedTriangles[itri]->mVertices[1] = mSimplifiedVertices[ in_out_tris[idx+1] ];
    00235     mSimplifiedTriangles[itri]->mVertices[2] = mSimplifiedVertices[ in_out_tris[idx+2] ];
    00236   }
    00237
    00238   // compute vertex/vertex and vertex/triangle connectivity
    00239   for(int itri=0; itri<(int)mSimplifiedTriangles.size(); ++itri)
    00240   {
    00241     // add this triangle to all its vertices
    00242     mSimplifiedTriangles[itri]->mVertices[0]->mIncidentTriangles.push_back( mSimplifiedTriangles[itri] );
    00243     mSimplifiedTriangles[itri]->mVertices[1]->mIncidentTriangles.push_back( mSimplifiedTriangles[itri] );
    00244     mSimplifiedTriangles[itri]->mVertices[2]->mIncidentTriangles.push_back( mSimplifiedTriangles[itri] );
    00245     // add adjacent vertices
    00246     mSimplifiedTriangles[itri]->mVertices[0]->addAdjacentVertex( mSimplifiedTriangles[itri]->mVertices[1] ); // vertex 0
    00247     mSimplifiedTriangles[itri]->mVertices[0]->addAdjacentVertex( mSimplifiedTriangles[itri]->mVertices[2] );
    00248     mSimplifiedTriangles[itri]->mVertices[1]->addAdjacentVertex( mSimplifiedTriangles[itri]->mVertices[0] ); // vertex 1
    00249     mSimplifiedTriangles[itri]->mVertices[1]->addAdjacentVertex( mSimplifiedTriangles[itri]->mVertices[2] );
    00250     mSimplifiedTriangles[itri]->mVertices[2]->addAdjacentVertex( mSimplifiedTriangles[itri]->mVertices[0] ); // vertex 2
    00251     mSimplifiedTriangles[itri]->mVertices[2]->addAdjacentVertex( mSimplifiedTriangles[itri]->mVertices[1] );
    00252     // compute normal
    00253     mSimplifiedTriangles[itri]->computeNormal();
    00254     // error
    00255     QErr qerr = mSimplifiedTriangles[itri]->computeQErr();
    00256     mSimplifiedTriangles[itri]->mVertices[0]->addQErr(qerr);
    00257     mSimplifiedTriangles[itri]->mVertices[1]->addQErr(qerr);
    00258     mSimplifiedTriangles[itri]->mVertices[2]->addQErr(qerr);
    00259   }
    00260
    00261   // - remove vertices without triangles
    00262   // - compute edge penalties
    00263   // - initialize the collapse info of each vertex
    00264   for( int ivert=(int)mSimplifiedVertices.size(); ivert--; )
    00265   {
    00266     if ( mSimplifiedVertices[ivert]->incidentTrianglesCount() == 0 )
    00267       mSimplifiedVertices.erase( mSimplifiedVertices.begin() + ivert );
    00268     else
    00269     {
    00270       mSimplifiedVertices[ivert]->computeEdgePenalty();
    00271       computeCollapseInfo( mSimplifiedVertices[ivert] );
    00272     }
    00273   }
    00274
    00275   // sets the protected vertices
    00276   for(int i=0; i<(int)mProtectedVerts.size(); ++i)
    00277   {
    00278     VL_CHECK(mProtectedVerts[i] < (int)mSimplifiedVertices.size() )
    00279     mSimplifiedVertices[ mProtectedVerts[i] ]->mProtected = true;
    00280   }
    00281
    00282   if (verbose())
    00283     Log::print(Say("database setup = %.3n\n") << timer.elapsed() );
    00284
    00285   std::set<VertexPtrWrapper> vertex_set;
    00286   for(int ivert=0; ivert<(int)mSimplifiedVertices.size(); ++ivert)
    00287     if ( !mSimplifiedVertices[ivert]->mProtected )
    00288       vertex_set.insert( mSimplifiedVertices[ivert] );
    00289
    00290   if (verbose())
    00291     Log::print(Say("heap setup = %.3n\n") << timer.elapsed() );
    00292
    00293   if (target_vertex_count < 3)
    00294   {
    00295     Log::print(Say("Invalid target_vertex_count = %n\n") << target_vertex_count);
    00296     return;
    00297   }
    00298
    00299   std::vector< PolygonSimplifier::Vertex* > adj_verts;
    00300   for( int remove_order=0; (int)vertex_set.size()>target_vertex_count; ++remove_order )
    00301   {
    00302     std::set<VertexPtrWrapper>::iterator it = vertex_set.begin();
    00303     PolygonSimplifier::Vertex* v = it->mVertex;
    00304     v->mRemoveOrder = remove_order;
    00305     vertex_set.erase(it);
    00306
    00307     // remove the adjacent vertices to v and v->collapseVert()
    00308     adj_verts.clear();
    00309     for(int i=0; i<v->adjacentVerticesCount(); ++i)
    00310     {
    00311       VL_CHECK( v != v->adjacentVertex(i) )
    00312       VL_CHECK( !v->adjacentVertex(i)->mAlreadyProcessed )
    00313
    00314       adj_verts.push_back( v->adjacentVertex(i) );
    00315       adj_verts.back()->mAlreadyProcessed = true;
    00316       vertex_set.erase( v->adjacentVertex(i) );
    00317     }
    00318     for(int i=0; i<v->collapseVertex()->adjacentVerticesCount(); ++i)
    00319     {
    00320       if ( !v->collapseVertex()->adjacentVertex(i)->mAlreadyProcessed )
    00321       {
    00322         adj_verts.push_back( v->collapseVertex()->adjacentVertex(i) );
    00323         vertex_set.erase( v->collapseVertex()->adjacentVertex(i) );
    00324       }
    00325     }
    00326
    00327     VL_CHECK(!v->removed())
    00328     VL_CHECK(v->collapseVertex())
    00329     VL_CHECK(!v->collapseVertex()->removed())
    00330
    00331     collapse( v );
    00332
    00333     // reinsert the adj_verts if not removed
    00334     // NOTE: v->collapseVertex() might have been also removed
    00335     for( int i=(int)adj_verts.size(); i--; )
    00336     {
    00337       adj_verts[i]->mAlreadyProcessed = false;
    00338
    00339       if ( adj_verts[i]->removed() )
    00340         continue;
    00341
    00342       computeCollapseInfo( adj_verts[i] );
    00343
    00344       VL_CHECK( adj_verts[i]->checkTriangles() )
    00345       VL_CHECK( adj_verts[i]->collapseVertex() != v )
    00346       VL_CHECK( !adj_verts[i]->collapseVertex()->removed() )
    00347
    00348       vertex_set.insert( adj_verts[i] );
    00349     }
    00350   }
    00351
    00352   if (verbose())
    00353     Log::print(Say("simplification = %.3n\n") << timer.elapsed() );
    00354
    00355   // generate indices for index buffer and regenerate vertex buffer
    00356   in_out_verts.clear();
    00357   int vert_index = 0;
    00358   for(int i=0; i<(int)mSimplifiedVertices.size(); ++i)
    00359   {
    00360     if (!mSimplifiedVertices[i]->mRemoved)
    00361     {
    00362       in_out_verts.push_back( mSimplifiedVertices[i]->mPosition );
    00363       mSimplifiedVertices[i]->mSimplifiedIndex = vert_index++;
    00364     }
    00365   }
    00366
    00367   // regenerate index buffer
    00368   in_out_tris.clear();
    00369   for(int i=0; i<(int)mSimplifiedTriangles.size(); ++i)
    00370   {
    00371     if(!mSimplifiedTriangles[i]->mRemoved)
    00372     {
    00373       VL_CHECK( !mSimplifiedTriangles[i]->mVertices[0]->mRemoved )
    00374       VL_CHECK( !mSimplifiedTriangles[i]->mVertices[1]->mRemoved )
    00375       VL_CHECK( !mSimplifiedTriangles[i]->mVertices[2]->mRemoved )
    00376
    00377       in_out_tris.push_back( mSimplifiedTriangles[i]->mVertices[0]->mSimplifiedIndex );
    00378       in_out_tris.push_back( mSimplifiedTriangles[i]->mVertices[1]->mSimplifiedIndex );
    00379       in_out_tris.push_back( mSimplifiedTriangles[i]->mVertices[2]->mSimplifiedIndex );
    00380     }
    00381   }
    00382
    00383   if (verbose())
    00384   {
    00385     float elapsed = (float)timer.elapsed();
    00386     int polys_after = (int)in_out_tris.size() / 3;
    00387     int verts_after = (int)in_out_verts.size();
    00388     Log::print(Say("POLYS: %n -> %n, %.2n%%, %.1nT/s\n") << polys_before << polys_after << 100.0f*verts_after/verts_before << (polys_before - polys_after)/elapsed );
    00389     Log::print(Say("VERTS: %n -> %n, %.2n%%, %.1nV/s\n") << verts_before << verts_after << 100.0f*verts_after/verts_before << (verts_before - verts_after)/elapsed );
    00390   }
    00391 }
    00392 //-----------------------------------------------------------------------------
    00393 void PolygonSimplifier::clearTrianglesAndVertices()
    00394 {
    00395   mSimplifiedVertices.clear();
    00396   mSimplifiedTriangles.clear();
    00397   mProtectedVerts.clear();
    00398   mTriangleLump.clear();
    00399   mVertexLump.clear();
    00400 }
    00401 //-----------------------------------------------------------------------------

Visualization Library v2011.05.1142 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 26 2011 22:51:24.
Permission is granted to use this page to write and publish articles regarding Visualization Library.