00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <vector>
00025 #include <string>
00026 #include <sstream>
00027
00028
00029 #include <vcg/simplex/vertex/base.h>
00030
00031
00032 #include <vcg/simplex/face/base.h>
00033
00034
00035 #include <vcg/connectors/hedge.h>
00036
00037
00038 #include <vcg/complex/complex.h>
00039
00040
00041 #include <vcg/complex/algorithms/update/topology.h>
00042 #include <vcg/complex/algorithms/update/bounding.h>
00043 #include <vcg/complex/algorithms/update/normal.h>
00044
00045
00046 #include <vcg/complex/algorithms/clean.h>
00047
00048
00049 #include <wrap/io_trimesh/import.h>
00050
00051 #include <wrap/io_trimesh/export_off.h>
00052
00053
00054 #include <vcg/complex/algorithms/polygon_support.h>
00055
00056
00057 #include <vcg/simplex/face/component_polygon.h>
00058
00059
00060 #include <vcg/complex/algorithms/update/halfedge_indexed.h>
00061
00062 #include <vcg/complex/algorithms/local_optimization/quad_diag_collapse.h>
00063
00064 #include <vcg/complex/algorithms/update/edges.h>
00065
00066 #include <vcg/simplex/face/component_rt.h>
00067
00068 #include <vcg/complex/algorithms/update/fitmaps.h>
00069
00070 using namespace vcg;
00071 using namespace std;
00072
00073
00074 class CFace;
00075 class CVertex;
00076 class CHEdge;
00077 class CEdge;
00078 class MyPolyVertex;
00079
00080 struct CUsedTypes: public vcg::UsedTypes< vcg::Use<CVertex>::AsVertexType, vcg::Use<CFace>::AsFaceType >{};
00081
00082
00083 class CVertex : public Vertex<
00084 CUsedTypes,
00085 vertex::BitFlags,
00086 vertex::Coord3f,
00087 vertex::Normal3f,
00088 vertex::VFAdj,
00089 vertex::Mark,
00090 vcg::vertex::Curvaturef,
00091 vcg::vertex::CurvatureDirf,
00092 vertex::Color4b,
00093 vertex::Qualityf
00094 >{};
00095
00096 class CFace : public Face<
00097 CUsedTypes,
00098 face::VertexRef,
00099 face::Normal3f,
00100 face::BitFlags,
00101 face::FFAdj,
00102 face::VFAdj,
00103 face::Mark,
00104 face::EdgePlane
00105 > {};
00106
00107 class CMesh : public vcg::tri::TriMesh< vector<CVertex>, vector<CFace> > {};
00108
00109
00110
00111
00112
00113 class MyPolyFace;
00114 class MyPolyVertex;
00115
00116 struct PolyUsedTypes: public vcg::UsedTypes<
00117 vcg::Use<MyPolyVertex> ::AsVertexType,
00118 vcg::Use<CEdge> ::AsEdgeType,
00119 vcg::Use<CHEdge> ::AsHEdgeType,
00120 vcg::Use<MyPolyFace> ::AsFaceType
00121 >{};
00122
00123 class MyPolyVertex:public Vertex<
00124 PolyUsedTypes,
00125 vertex::Coord3f,
00126 vertex::Normal3f,
00127 vertex::Mark,
00128 vertex::BitFlags,
00129 vertex::VHAdj,
00130 vertex::VFAdj
00131 >{};
00132
00133 class CEdge : public Edge<PolyUsedTypes>{};
00134
00135 class CHEdge : public HEdge<
00136 PolyUsedTypes,
00137 hedge::BitFlags,
00138 hedge::HFAdj,
00139 hedge::HOppAdj,
00140 hedge::HNextAdj,
00141 hedge::HVAdj,
00142 hedge::HPrevAdj,
00143 hedge::Mark
00144 >{};
00145
00146 class MyPolyFace:public Face<
00147 PolyUsedTypes,
00148 face::PolyInfo,
00149 face::PFVAdj,
00150 face::PFFAdj,
00151 face::PFHAdj,
00152 face::BitFlags,
00153 face::Normal3f,
00154 face::Mark
00155 > {};
00156
00157 class MyPolyMesh: public tri::TriMesh<
00158 std::vector<MyPolyVertex>,
00159 std::vector<MyPolyFace>,
00160 std::vector<CHEdge>,
00161 std::vector<CEdge>
00162 >{};
00163
00164
00165
00170 class MyCollapseAdaptive: public vcg::tri::QuadDiagonalCollapse< MyPolyMesh, MyCollapseAdaptive, CMesh , vcg::tri::VertReg<MyPolyMesh> ,vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> , vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> >
00171 {
00172 public:
00173
00174 typedef vcg::tri::QuadDiagonalCollapse< MyPolyMesh, MyCollapseAdaptive, CMesh , vcg::tri::VertReg<MyPolyMesh>, vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> , vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> > constructor;
00175
00176 MyCollapseAdaptive(HEdgePointer he, int mark):constructor(he,mark){}
00177 };
00178
00183 class MyCollapse: public vcg::tri::QuadDiagonalCollapseBase< MyPolyMesh, MyCollapse, CMesh , vcg::tri::VertReg<MyPolyMesh> >
00184 {
00185 public:
00186
00187 typedef vcg::tri::QuadDiagonalCollapseBase< MyPolyMesh, MyCollapse, CMesh , vcg::tri::VertReg<MyPolyMesh> > constructor;
00188
00189 MyCollapse(HEdgePointer he, int mark):constructor(he,mark){}
00190 };
00191
00192
00193 typedef CMesh::FaceType TriFaceType;
00194 typedef vcg::GridStaticPtr<CMesh::FaceType, TriFaceType::ScalarType> GRID;
00195
00196 typedef CMesh::PerVertexAttributeHandle<float> Fitmap_attr;
00197
00203 void initGrid(CMesh & m)
00204 {
00205
00206 GRID* grid = new GRID();
00207
00208 vcg::tri::UpdateBounding<CMesh>::Box(m);
00209 vcg::tri::UpdateEdges<CMesh>::Set(m);
00210
00211 grid->Set(m.face.begin(), m.face.end());
00212
00213
00214 MyCollapse::grid() = grid;
00215 MyCollapseAdaptive::grid() = grid;
00216
00217 }
00218
00226 void init_heap(MyPolyMesh &m, vcg::LocalOptimization<MyPolyMesh> &loc, bool adaptive)
00227 {
00228 if(adaptive)
00229 MyCollapseAdaptive::Init(m, loc.h);
00230 else
00231 MyCollapse::Init(m,loc.h);
00232
00233 std::make_heap(loc.h.begin(),loc.h.end());
00234
00235 if(!loc.h.empty())
00236 loc.currMetric=loc.h.front().pri;
00237 }
00238
00245 bool read_fitmaps(CMesh &m, const char *fn)
00246 {
00247 ifstream fitmaps;
00248 fitmaps.open(fn);
00249
00250 if(! fitmaps.is_open())
00251 return false;
00252
00253 Fitmap_attr S_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"S-Fitmap");
00254 Fitmap_attr M_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"M-Fitmap");
00255
00256 int index;
00257 float S_fit, M_fit;
00258 do
00259 {
00260 fitmaps >> index >> S_fit >> M_fit;
00261 S_Fit[m.vert[index]] = S_fit;
00262 M_Fit[m.vert[index]] = M_fit;
00263
00264 }while(fitmaps.good());
00265
00266
00267 bool eof = fitmaps.eof();
00268
00269 fitmaps.close();
00270 return eof;
00271
00272 }
00273
00280 bool store_fitmaps(CMesh &m, const char *fn)
00281 {
00282 ofstream fitmaps;
00283 fitmaps.open(fn);
00284
00285 if(! fitmaps.is_open())
00286 return false;
00287
00288 Fitmap_attr S_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"S-Fitmap");
00289 Fitmap_attr M_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"M-Fitmap");
00290
00291 for(unsigned int i =0; i< m.vert.size(); i++)
00292 {
00293 if( !(m.vert[i].IsD()) )
00294 {
00295 fitmaps << i << " " << S_Fit[m.vert[i]] << " " << M_Fit[m.vert[i]] << endl;
00296
00297 if(!fitmaps.good())
00298 {
00299 fitmaps.close();
00300 return false;
00301 }
00302 }
00303 }
00304
00305 fitmaps.close();
00306 return true;
00307 }
00308
00315 void load_fitmaps(CMesh &m, char* fn)
00316 {
00317
00318 Fitmap_attr S_Fit = tri::Allocator<CMesh>::AddPerVertexAttribute<float> (m, string("S-Fitmap"));
00319 Fitmap_attr M_Fit = tri::Allocator<CMesh>::AddPerVertexAttribute<float> (m, string("M-Fitmap"));
00320
00321 string filename(fn);
00322
00323 int found = filename.find_last_of("/");
00324
00325 string name = filename.substr(found+1);
00326
00327 string suffix = ".fmp";
00328
00329 if( !read_fitmaps( m, (name + suffix).c_str()) )
00330 {
00331 tri::Fitmaps<CMesh>::computeSFitmap(m);
00332
00333 for(CMesh::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00334 S_Fit[vi] = vi->Q();
00335
00336 tri::Fitmaps<CMesh>::computeMFitmap(m, 5);
00337
00338 for(CMesh::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00339 M_Fit[vi] = vi->Q();
00340
00341 store_fitmaps(m, ( name + suffix).c_str());
00342 }
00343
00344 }
00345
00353 void loadMesh(CMesh & m, char* fn, bool loadFitmaps = false)
00354 {
00355
00356 int ret = vcg::tri::io::Importer<CMesh>::Open(m,fn);
00357
00358 if(ret != 0)
00359 {
00360 cerr << "Error reading file " << fn << endl;
00361 exit(1);
00362 }
00363
00364 tri::Clean<CMesh>::RemoveDegenerateFace(m);
00365 tri::Clean<CMesh>::RemoveDuplicateFace(m);
00366 tri::Clean<CMesh>::RemoveDuplicateVertex(m);
00367 tri::Clean<CMesh>::RemoveUnreferencedVertex(m);
00368
00369 tri::UpdateTopology<CMesh>::FaceFace(m);
00370
00371 tri::Clean<CMesh>::RemoveNonManifoldFace(m);
00372 tri::UpdateTopology<CMesh>::FaceFace(m);
00373
00374 tri::Clean<CMesh>::RemoveNonManifoldVertex(m);
00375 tri::UpdateTopology<CMesh>::FaceFace(m);
00376
00377
00378 vcg::tri::UpdateBounding<CMesh>::Box (m);
00379
00380
00381 vcg::tri::UpdateNormals<CMesh>::PerVertexNormalizedPerFace(m);
00382 vcg::tri::UpdateNormals<CMesh>::PerFaceNormalized(m);
00383
00384 if(loadFitmaps)
00385 load_fitmaps(m,fn);
00386
00387 }
00388
00389 int main(int argc, char *argv[]) {
00390
00391
00392
00393 MyPolyMesh pm;
00394
00395
00396 CMesh mesh,refMesh;
00397
00398 char* meshfile = NULL;
00399 char* trimeshfile = NULL;
00400 char* outfile = "output.off";
00401 int faces;
00402 bool adaptive = false;
00403
00404 if(argc < 2)
00405 {
00406 cerr << "Usage: " << argv[0] << " -meshfile filename [-trimeshfile filename] -faces num_faces [-adaptive] [-outfile filename]" << endl;
00407 }
00408
00409 for(int i=1; i< argc; i++)
00410 {
00411 string arg = string(argv[i]);
00412
00413 if ( arg == "-meshfile")
00414 meshfile = argv[++i];
00415
00416 else if (arg == "-trimeshfile")
00417 trimeshfile = argv[++i];
00418
00419 else if (arg == "-faces")
00420 {
00421 stringstream myStream(argv[++i], stringstream::in | stringstream::out);
00422 myStream >> faces;
00423 }
00424
00425 else if (arg == "-outfile")
00426 outfile = argv[++i];
00427
00428 else if (arg == "-adaptive")
00429 adaptive = true;
00430 }
00431
00432
00433 if( !meshfile)
00434 {
00435 cerr << "Missing mesh filename" << endl;
00436 exit(1);
00437 }
00438
00439 if(faces < 0)
00440 {
00441 cerr << "Missing faces number" << endl;
00442 exit(1);
00443 }
00444
00445
00446
00447 loadMesh(mesh, meshfile);
00448
00449
00450 if(trimeshfile)
00451 loadMesh(refMesh, trimeshfile, adaptive);
00452 else
00453 loadMesh(refMesh, meshfile, adaptive);
00454
00455 initGrid(refMesh);
00456
00457 MyCollapse::refMesh() = &refMesh;
00458 MyCollapseAdaptive::refMesh() = &refMesh;
00459
00460
00461 vcg::tri::PolygonSupport<CMesh,MyPolyMesh>::ImportFromTriMesh(pm,mesh);
00462 vcg::tri::UpdateHalfEdges<MyPolyMesh>::FromIndexed(pm);
00463
00464
00465 assert(vcg::tri::UpdateHalfEdges<MyPolyMesh>::CheckConsistency(pm));
00466
00467 HalfedgeQuadClean<MyPolyMesh>::remove_singlets(pm);
00468 HalfedgeQuadClean<MyPolyMesh>::remove_doublets(pm);
00469
00470 vcg::LocalOptimization<MyPolyMesh> loc(pm);
00471 init_heap(pm, loc, adaptive);
00472
00473 loc.HeapSimplexRatio = 9;
00474 loc.SetTargetSimplices(faces);
00475
00476
00477 loc.DoOptimization();
00478
00479
00480 assert(vcg::tri::UpdateHalfEdges<MyPolyMesh>::CheckConsistency(pm));
00481 vcg::tri::UpdateIndexed<MyPolyMesh>::FromHalfEdges(pm );
00482
00483
00484 int ret = tri::io::ExporterOFF<MyPolyMesh>::Save(pm, outfile, tri::io::Mask::IOM_BITPOLYGONAL );
00485 if(ret != 0 )
00486 {
00487 cerr << "Error saving file" << endl;
00488 exit(1);
00489 }
00490
00491 cout << "Simplification ended successfully!" << endl;
00492
00493 }