diff --git a/apps/sample/polygonmesh_quadsimpl/polygonmesh_quadsimpl.pro b/apps/sample/polygonmesh_quadsimpl/polygonmesh_quadsimpl.pro new file mode 100755 index 00000000..7b046b0d --- /dev/null +++ b/apps/sample/polygonmesh_quadsimpl/polygonmesh_quadsimpl.pro @@ -0,0 +1,8 @@ +TARGET = polygonmesh_quadsimpl +LIBPATH += +DEPENDPATH += . +INCLUDEPATH += . ../../.. +CONFIG += console stl +TEMPLATE = app +SOURCES += ../../../wrap/ply/plylib.cpp \ + quadsimpl.cpp diff --git a/apps/sample/polygonmesh_quadsimpl/quadsimpl.cpp b/apps/sample/polygonmesh_quadsimpl/quadsimpl.cpp new file mode 100644 index 00000000..db32f966 --- /dev/null +++ b/apps/sample/polygonmesh_quadsimpl/quadsimpl.cpp @@ -0,0 +1,495 @@ +/**************************************************************************** + * VCGLib o o * + * Visual and Computer Graphics Library o o * + * _ O _ * + * Copyright(C) 2004 \/)\/ * + * Visual Computing Lab /\/| * + * ISTI - Italian National Research Council | * + * \ * + * All rights reserved. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * + * for more details. * + * * + ****************************************************************************/ + +#include +#include +#include + +/*include the base definition for the vertex */ +#include + +/*include the base definition for the face */ +#include + +/*include the base definition for the edge */ +#include + +/*include the base definition for the trimesh*/ +#include + +/*include the algorithms for updating: */ +#include /* topology */ +#include /* bounding box */ +#include /* normal */ + +/*include the algorithms for mesh fixing */ +#include + +/*include the importer from disk*/ +#include + +#include + +/* include the support for polygon meshes (function to convert from/to trimesh)*/ +#include + +/* include the support for polygon meshes (the component for the face )*/ +#include + +/* include the support for half edges */ +#include + +#include + +#include + +#include + +#include + +using namespace vcg; +using namespace std; + +// forward declarations +class CFace; +class CVertex; +class CHEdge; +class CEdge; +class MyPolyVertex; + +struct CUsedTypes: public vcg::UsedTypes< vcg::Use::AsVertexType, vcg::Use::AsFaceType >{}; + +// Mesh of triangles +class CVertex : public Vertex< + CUsedTypes, + vertex::BitFlags, + vertex::Coord3f, + vertex::Normal3f, + vertex::VFAdj, + vertex::Mark, + vcg::vertex::Curvaturef, + vcg::vertex::CurvatureDirf, + vertex::Color4b, + vertex::Qualityf + >{}; + +class CFace : public Face< + CUsedTypes, + face::VertexRef, + face::Normal3f, + face::BitFlags, + face::FFAdj, + face::VFAdj, + face::Mark, + face::EdgePlane + > {}; + +class CMesh : public vcg::tri::TriMesh< vector, vector > {}; + + + + +// Poly mesh +class MyPolyFace; +class MyPolyVertex; + +struct PolyUsedTypes: public vcg::UsedTypes< + vcg::Use ::AsVertexType, + vcg::Use ::AsEdgeType, + vcg::Use ::AsHEdgeType, + vcg::Use ::AsFaceType + >{}; + +class MyPolyVertex:public Vertex< + PolyUsedTypes, + vertex::Coord3f, + vertex::Normal3f, + vertex::Mark, + vertex::BitFlags, + vertex::VHAdj, + vertex::VFAdj + >{}; + +class CEdge : public Edge{}; + +class CHEdge : public HEdge< + PolyUsedTypes, + hedge::BitFlags, + hedge::HFAdj, + hedge::HOppAdj, + hedge::HNextAdj, + hedge::HVAdj, + hedge::HPrevAdj, + hedge::Mark + >{}; + +class MyPolyFace:public Face< + PolyUsedTypes, + face::PolyInfo, + face::PFVAdj, + face::PFFAdj, + face::PFHAdj, + face::BitFlags, + face::Normal3f, + face::Mark + > {}; + +class MyPolyMesh: public tri::TriMesh< + std::vector, + std::vector, + std::vector, + std::vector + >{}; + + + +/*! + * \brief Collapse operation for adaptive simplification using fitmaps + * + */ +class MyCollapseAdaptive: public vcg::tri::QuadDiagonalCollapse< MyPolyMesh, MyCollapseAdaptive, CMesh , vcg::tri::VertReg ,vcg::tri::FitmapsCollapse , vcg::tri::FitmapsCollapse > +{ +public: + + typedef vcg::tri::QuadDiagonalCollapse< MyPolyMesh, MyCollapseAdaptive, CMesh , vcg::tri::VertReg, vcg::tri::FitmapsCollapse , vcg::tri::FitmapsCollapse > constructor; + + MyCollapseAdaptive(HEdgePointer he, int mark):constructor(he,mark){} +}; + +/*! + * \brief Collapse for uniform simplification + * + */ +class MyCollapse: public vcg::tri::QuadDiagonalCollapseBase< MyPolyMesh, MyCollapse, CMesh , vcg::tri::VertReg > +{ +public: + + typedef vcg::tri::QuadDiagonalCollapseBase< MyPolyMesh, MyCollapse, CMesh , vcg::tri::VertReg > constructor; + + MyCollapse(HEdgePointer he, int mark):constructor(he,mark){} +}; + + +typedef CMesh::FaceType TriFaceType; +typedef vcg::GridStaticPtr GRID; + +typedef CMesh::PerVertexAttributeHandle Fitmap_attr; + +/*! Initializes the grid for smoothing and fitmaps + * + * \param m Reference mesh + * + */ +void initGrid(CMesh & m) +{ + + GRID* grid = new GRID(); + + vcg::tri::UpdateBounding::Box(m); + vcg::tri::UpdateEdges::Set(m); + + grid->Set(m.face.begin(), m.face.end()); + +// grid->ShowStats(stdout); + MyCollapse::grid() = grid; + MyCollapseAdaptive::grid() = grid; + +} + +/*! Initializes the heap of operations on a mesh + * + * \param m Mesh + * \param loc + * \param Adaptive Specifies if simplificaton will be adaptive + * + */ +void init_heap(MyPolyMesh &m, vcg::LocalOptimization &loc, bool adaptive) +{ + if(adaptive) + MyCollapseAdaptive::Init(m, loc.h); + else + MyCollapse::Init(m,loc.h); + + std::make_heap(loc.h.begin(),loc.h.end()); + + if(!loc.h.empty()) + loc.currMetric=loc.h.front().pri; +} + +/*! Read fitmaps values from a file and loads them into a mesh + * + * \param m Mesh + * \param fn Name of the file to read + * + */ +bool read_fitmaps(CMesh &m, const char *fn) +{ + ifstream fitmaps; + fitmaps.open(fn); + + if(! fitmaps.is_open()) + return false; + + Fitmap_attr S_Fit = tri::Allocator::GetPerVertexAttribute(m,"S-Fitmap"); + Fitmap_attr M_Fit = tri::Allocator::GetPerVertexAttribute(m,"M-Fitmap"); + + int index; + float S_fit, M_fit; + do + { + fitmaps >> index >> S_fit >> M_fit; + S_Fit[m.vert[index]] = S_fit; + M_Fit[m.vert[index]] = M_fit; + + }while(fitmaps.good()); + + + bool eof = fitmaps.eof(); + + fitmaps.close(); + return eof; + +} + +/*! Writes fitmaps values into a file + * + * \param m Mesh + * \param fn Name of the file to write + * + */ +bool store_fitmaps(CMesh &m, const char *fn) +{ + ofstream fitmaps; + fitmaps.open(fn); + + if(! fitmaps.is_open()) + return false; + + Fitmap_attr S_Fit = tri::Allocator::GetPerVertexAttribute(m,"S-Fitmap"); + Fitmap_attr M_Fit = tri::Allocator::GetPerVertexAttribute(m,"M-Fitmap"); + + for(unsigned int i =0; i< m.vert.size(); i++) + { + if( !(m.vert[i].IsD()) ) + { + fitmaps << i << " " << S_Fit[m.vert[i]] << " " << M_Fit[m.vert[i]] << endl; + + if(!fitmaps.good()) + { + fitmaps.close(); + return false; + } + } + } + + fitmaps.close(); + return true; +} + +/*! Load fitmaps for a mesh, computing them or reading values from a file + * + * \param m Mesh + * \param fn Name of the mesh file + * + */ +void load_fitmaps(CMesh &m, char* fn) +{ + + Fitmap_attr S_Fit = tri::Allocator::AddPerVertexAttribute (m, string("S-Fitmap")); + Fitmap_attr M_Fit = tri::Allocator::AddPerVertexAttribute (m, string("M-Fitmap")); + + string filename(fn); + + int found = filename.find_last_of("/"); + + string name = filename.substr(found+1); + + string suffix = ".fmp"; + + if( !read_fitmaps( m, (name + suffix).c_str()) ) + { + tri::Fitmaps::computeSFitmap(m); + + for(CMesh::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + S_Fit[vi] = vi->Q(); + + tri::Fitmaps::computeMFitmap(m, 5); + + for(CMesh::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + M_Fit[vi] = vi->Q(); + + store_fitmaps(m, ( name + suffix).c_str()); + } + +} + +/*! Load a mesh, from a file + * + * \param m Mesh that will be filled with data from a file + * \param fn Name of the mesh file + * \param loadFitmaps Specifies if fitmaps have to be loaded + * + */ +void loadMesh(CMesh & m, char* fn, bool loadFitmaps = false) +{ + + int ret = vcg::tri::io::Importer::Open(m,fn); + + if(ret != 0) + { + cerr << "Error reading file " << fn << endl; + exit(1); + } + + tri::Clean::RemoveDegenerateFace(m); + tri::Clean::RemoveDuplicateFace(m); + tri::Clean::RemoveDuplicateVertex(m); + tri::Clean::RemoveUnreferencedVertex(m); + + tri::UpdateTopology::FaceFace(m); + + tri::Clean::RemoveNonManifoldFace(m); + tri::UpdateTopology::FaceFace(m); + + tri::Clean::RemoveNonManifoldVertex(m); + tri::UpdateTopology::FaceFace(m); + + // update bounding box + vcg::tri::UpdateBounding::Box (m); + + // update Normals + vcg::tri::UpdateNormals::PerVertexNormalizedPerFace(m); + vcg::tri::UpdateNormals::PerFaceNormalized(m); + + if(loadFitmaps) + load_fitmaps(m,fn); + +} + +int main(int argc, char *argv[]) { + + + // HE mesh + MyPolyMesh pm; + + // Tri meshes + CMesh mesh,refMesh; + + char* meshfile = NULL; + char* trimeshfile = NULL; + char* outfile = NULL; + int faces; + bool adaptive = false; + + if(argc < 2) + { + cerr << "Usage: " << argv[0] << " -meshfile filename [-trimeshfile filename] -faces num_faces [-adaptive] [-outfile filename]" << endl; + } + + for(int i=1; i< argc; i++) + { + string arg = string(argv[i]); + + if ( arg == "-meshfile") + meshfile = argv[++i]; + + else if (arg == "-trimeshfile") + trimeshfile = argv[++i]; + + else if (arg == "-faces") + { + stringstream myStream(argv[++i], stringstream::in | stringstream::out); + myStream >> faces; + } + + else if (arg == "-outfile") + outfile = argv[++i]; + + else if (arg == "-adaptive") + adaptive = true; + } + + + if( !meshfile) + { + cerr << "Missing mesh filename" << endl; + exit(1); + } + + if(faces < 0) + { + cerr << "Missing faces number" << endl; + exit(1); + } + + + // Load the mesh to simplify + loadMesh(mesh, meshfile); + + // Load the reference mesh + if(trimeshfile) + loadMesh(refMesh, trimeshfile, adaptive); + else + loadMesh(refMesh, meshfile, adaptive); + + initGrid(refMesh); + + MyCollapse::refMesh() = &refMesh; + MyCollapseAdaptive::refMesh() = &refMesh; + + + vcg::tri::PolygonSupport::ImportFromTriMesh(pm,mesh); + vcg::tri::UpdateHalfEdges::FromIndexed(pm); + + // After loading check mesh consistency + assert(vcg::tri::UpdateHalfEdges::CheckConsistency(pm)); + + vcg::LocalOptimization loc(pm); + init_heap(pm, loc, adaptive); + + loc.HeapSimplexRatio = 9; + loc.SetTargetSimplices(faces); + + // Perform simplification + loc.DoOptimization(); + + + assert(vcg::tri::UpdateHalfEdges::CheckConsistency(pm)); + vcg::tri::UpdateIndexed::FromHalfEdges(pm ); + + + int ret; + if(outfile) + ret = tri::io::ExporterOFF::Save(pm, outfile, tri::io::Mask::IOM_BITPOLYGONAL ); + else + ret = tri::io::ExporterOFF::Save(pm, "output.off", tri::io::Mask::IOM_BITPOLYGONAL ); + + if(ret != 0 ) + { + cerr << "Error saving file" << endl; + exit(1); + } + + cout << "Simplification ended successfully!" << endl; + +}