//-*-c++-*- #ifndef FLEXMESH_H #define FLEXMESH_H /* James R. Diebel Stanford University Started: 29 November 2005 General templated triangular mesh class capable of: - finding face-vertex-edge connectivity from vertex/face lists - finding per-face and per-vertex normal vectors Depends on FlexVertex, FlexFace, and FlexEdge classes, which are friends. Template parameters: - floating point type T */ #include #include #include #include #include #include "matmath.h" #include "flexvertex.h" #include "flexface.h" #include "flexedge.h" #define FM_CHECK_BOUNDS 1 #define FM_PO 2 // Forward Declarations template class FlexVertex; template class FlexFace; template class FlexEdge; template class FlexMesh; ////////////////////// // FlexMesh Class // ////////////////////// template class FlexMesh { public: // Constructors/Destructor and Related FlexMesh(); FlexMesh(const FlexMesh& m); FlexMesh(int nv_, int nf_); ~FlexMesh(); // Memory Allocation and Deallocation void startUp(int nv_, int nf_); // allocate memory void cleanUp(); // deallocate memory // References FlexVertex& v(const int i); FlexVertex& v(const int i) const; FlexEdge& e(const int i); FlexEdge& e(const int i) const; FlexFace& f(const int i); FlexFace& f(const int i) const; int numv() const; int nume() const; int numf() const; sla::Vec3 getFace(const int i) const; // Assignments void set(const FlexMesh& m); FlexMesh& operator = (const FlexMesh& m); void setVertex(const int i, bool boundary_,sla::Vec3 x_, sla::Vec3 c_); void setFace(const int i, const sla::Vec3& ind); // File I/O int readBSM(const char* filename); // read Binary FlexMesh int writeBSM(char* filename); // write Binary FlexMesh void writeTo(std::ostream& os); void readFrom(std::istream& is); void print(std::ostream& os) const; void print(); // Find Derived Data void findFaceNormals(); void findVertexNormals(); void findNormals(); void findFaceCenters(); void findEdgeCenters(); void findVertexToFace(); void findVertexToVertex(); void findFaceToFace(); void findEdges(); // Methods relating to Color-based smoothing void storeReferenceData(); void findColorWeights(); void findGradient(); // compute gradient of potential function void takeHillClimbingStep(); // take hill-climbing step protected: // Protected Data int nv, nf, ne; // numbers of vertices, faces, edges int nn; // total number of neighboring triangles FlexVertex* vd; // global vertex list FlexFace* fd; // global face list FlexEdge* ed; // global edge list bool haveVertexToFace; bool haveVertexToVertex; bool haveFaceToFace; bool haveEdges; }; // Instantiate a few instances template class FlexMesh; template class FlexMesh; // Declare a few common typdefs typedef FlexMesh FlexMeshf; typedef FlexMesh FlexMeshd; //////////////////////// // FlexMesh Methods // //////////////////////// // Constructor: default template inline FlexMesh::FlexMesh() { nv = nf = ne = nn = 0; haveVertexToFace = false; haveVertexToVertex = false; haveFaceToFace = false; haveEdges = false; vd = NULL; fd = NULL; } // Constructor: copy template inline FlexMesh::FlexMesh(const FlexMesh& m) { this->set(m); } // Constructor: with given size template inline FlexMesh::FlexMesh(int nv_, int nf_) { nv = nf = ne = nn = 0; haveVertexToFace = false; haveVertexToVertex = false; haveFaceToFace = false; haveEdges = false; vd = NULL; fd = NULL; startUp(nv_,nf_); } // Destructor: cleans up allocated memory template inline FlexMesh::~FlexMesh() { cleanUp(); } // Memory allocation template inline void FlexMesh::startUp(int nv_, int nf_) { cleanUp(); // always clean up first, in case of old data nv = nv_; nf = nf_; if (FM_PO>1) printf("Allocating memory for %i vertices and %i faces...", nv,nf); vd = new FlexVertex[nv]; fd = new FlexFace[nf]; if (FM_PO>1) printf("Done.\n"); } // Memory deallocation template inline void FlexMesh::cleanUp() { if (nv != 0) { if (FM_PO>1) printf("Deleting vertex list (%i)...",nv); delete [] vd; if (FM_PO>1) printf("Done.\n"); } if (nf != 0) { if (FM_PO>1) printf("Deleting face list (%i)...", nf); delete [] fd; if (FM_PO>1) printf("Done.\n"); } nv = nf = ne = nn = 0; haveVertexToFace = false; haveVertexToVertex = false; haveFaceToFace = false; haveEdges = false; vd = NULL; fd = NULL; } // Assignment operator template FlexMesh& FlexMesh::operator = (const FlexMesh& m) { this->set(m); return *this; } // Assignment function template void FlexMesh::set(const FlexMesh& m) { nv = nf = ne = nn = 0; vd = NULL; fd = NULL; startUp(m.nv,m.nf); for (int i=0;i inline FlexVertex& FlexMesh::v(const int i) { #if FM_CHECK_BOUNDS if (i < 0 || i >= nv) { printf("Vertex index %i out of range [0,%i], exiting.\n", i, nv); std::exit(1); } #endif return vd[i]; } // Returns vertex i in the global vertex list template inline FlexVertex& FlexMesh::v(const int i) const { #if FM_CHECK_BOUNDS if (i < 0 || i >= nv) { printf("Vertex index %i out of range [0,%i], exiting.\n", i, nv); std::exit(1); } #endif return vd[i]; } // Returns reference to edge i in the global edge list template inline FlexEdge& FlexMesh::e(const int i) { #if FM_CHECK_BOUNDS if (i < 0 || i >= ne) { printf("Edge index %i out of range [0,%i], exiting.\n", i, ne); std::exit(1); } #endif return ed[i]; } // Returns edge i in the global edge list template inline FlexEdge& FlexMesh::e(const int i) const { #if FM_CHECK_BOUNDS if (i < 0 || i >= ne) { printf("Edge index %i out of range [0,%i], exiting.\n", i, ne); std::exit(1); } #endif return ed[i]; } // Returns reference to face i in the global face list template inline FlexFace& FlexMesh::f(const int i) { #if FM_CHECK_BOUNDS if (i < 0 || i >= nf) { printf("Face index %i out of range [0,%i], exiting.\n", i, nf); std::exit(1); } #endif return fd[i]; } // Returns face i in the global face list template inline FlexFace& FlexMesh::f(const int i) const { #if FM_CHECK_BOUNDS if (i < 0 || i >= nf) { printf("Face index %i out of range [0,%i], exiting.\n", i, nf); std::exit(1); } #endif return fd[i]; } // Returns the total number of vertices template inline int FlexMesh::numv() const { return nv; } // Returns the total number of edges template inline int FlexMesh::nume() const { return ne; } // Returns the total number of faces template inline int FlexMesh::numf() const { return nf; } // Get face-vertex indices to passed values template inline sla::Vec3 FlexMesh::getFace(const int i) const { return f(i).getVertexIndices(vd); } // Set vertex position and color to passed values template inline void FlexMesh::setVertex(const int i, bool boundary_, sla::Vec3 x_, sla::Vec3 c_) { v(i).boundary = boundary_; v(i).x = x_; v(i).c = c_; } // Set face-vertex indices to passed values template inline void FlexMesh::setFace(const int i, const sla::Vec3& ind) { #if FM_CHECK_BOUNDS for (int j=0;j<3;j++) if (ind(j) < 0 || ind(j) >= nv) { printf("Vertex index %i out of range [0,%i], exiting.\n", ind(j), nf); std::exit(1); } #endif f(i).setVertexIndices(ind,vd); } // I/O: Writes state to stream (binary) template inline void FlexMesh::writeTo(std::ostream& os) { //write number of vertices and faces to file os.write(reinterpret_cast(&nv),sizeof(int)); os.write(reinterpret_cast(&nf),sizeof(int)); //write all vertices to file for (int i=0;i inline void FlexMesh::readFrom(std::istream& is) { //read number of vertices and faces from stream int nv_, nf_; is.read(reinterpret_cast(&nv_),sizeof(int)); is.read(reinterpret_cast(&nf_),sizeof(int)); //allocate memory startUp(nv_, nf_); //read all vertices from stream for (int i=0;i inline void FlexMesh::print(std::ostream& os) const { os << "Not implemented yet!" << std::endl; } // I/O: Reads binary file of mesh template inline int FlexMesh::readBSM(const char* filename) { if (FM_PO>0) printf("Reading BSM from %s ...\n", filename); std::fstream fin; fin.open(filename,std::ios::in|std::ios::binary); if (fin.is_open()) { readFrom(fin); } else { printf("Couldn't open file, exiting...\n"); std::exit(1); } fin.close(); if (FM_PO>0) printf("Done.\n"); return 0; } // I/O: Writes binary file format template inline int FlexMesh::writeBSM(char* filename) { if (FM_PO>0) printf("Writing BSM to %s ...\n", filename); std::fstream fout; fout.open(filename,std::ios::out|std::ios::binary); if (fout.is_open()) { writeTo(fout); } else { printf("Couldn't open file, exiting...\n"); std::exit(1); } fout.close(); if (FM_PO>0) printf("Done.\n"); return 0; } // Displays ascii mesh to screen template inline void FlexMesh::print() { if (FM_PO>0) printf("Printing ASM to screen...\n"); // write header printf("%i %i\n", nv, nf); // write all vertices for (int i=0;i0) printf("Done.\n"); } // Find face normals template inline void FlexMesh::findFaceNormals() { if (FM_PO>0) printf("Finding face normals..."); for (int i=0;i(f(i).v(1).x - f(i).v(0).x).cross (sla::Vec3(f(i).v(2).x - f(i).v(0).x)); f(i).n.normalize(); } if (FM_PO>0) printf("Done.\n"); } // Find vertex normals template inline void FlexMesh::findVertexNormals() { if (FM_PO>0) printf("Finding vertex normals..."); for (int i=0;i0) printf("Done.\n"); } // Find face and vertex normals template inline void FlexMesh::findNormals() { findFaceNormals(); findVertexNormals(); } // Find goemetric center of all faces template inline void FlexMesh::findFaceCenters() { for (int i=0;i inline void FlexMesh::findEdgeCenters() { for (int i=0;i inline void FlexMesh::findVertexToFace() { if (FM_PO>1) std::cout << "Finding vertex-to-face mappings..." << std::flush; // clean up previously-allocated memory/mappings if (haveVertexToFace){ if (FM_PO>1) std::cout << "deleting old mappings..." << std::flush; for (int i=0;i 0) { delete [] v(i).fd; v(i).nf = 0; v(i).fd = NULL; } if (FM_PO>1) std::cout << "Done. " << std::flush; } // count the number of faces touching each vertex for (int i=0;i 0) { v(i).fd = new FlexFace*[v(i).nf]; v(i).nf = 0; } // fill mappings for (int i=0;i1) std::cout << "Done." << std::endl << std::flush; } // Find vertex-to-vertex mappings template inline void FlexMesh::findVertexToVertex() { if (!haveVertexToFace) findVertexToFace(); if (FM_PO>1) std::cout << "Finding vertex-to-vertex mappings..." << std::flush; // clean up previously-allocated memory/mappings if (haveVertexToVertex){ if (FM_PO>1) std::cout << "deleting old mappings..." << std::flush; for (int i=0;i 0) { delete [] v(i).vd; v(i).nv = 0; v(i).vd = NULL; } if (FM_PO>1) std::cout << "Done..." << std::flush; } // for each vertex, find all neighboring vertices std::list nbrs; std::list::iterator iter; for (int i=0;i 0) { nbrs.sort(); nbrs.unique(); v(i).nv = nbrs.size(); v(i).vd = new FlexVertex*[v(i).nv]; iter = nbrs.begin(); for (int j=0;j1) std::cout << "Done." << std::endl << std::flush; } // Find face-to-face mappings template inline void FlexMesh::findFaceToFace() { if (!haveVertexToFace) findVertexToFace(); if (FM_PO>1) std::cout << "Finding face-to-face mappings..." << std::flush; // clean up previously-allocated memory/mappings if (haveFaceToFace){ if (FM_PO>1) std::cout << "deleting old mappings..." << std::flush; for (int i=0;i1) std::cout << "Done..." << std::flush; } // clear face flags for (int i=0;i 2) { std::cerr << "Error, too many faces!\n" << std::flush; std::cerr << "Face " << i << ":\n" << getFace(i) << "\n" << "Face: " << f(i).v(j).f(k).getVertexIndices(vd) << "\n"; exit(1); } f(i).fd[f(i).nf] = &(f(i).v(j).f(k)); f(i).nf++; } f(i).v(j).f(k).flag = i; } } } haveFaceToFace = true; if (FM_PO>1) std::cout << "Done." << std::endl << std::flush; } // Find vertex-to-edge mappings while defining edges themselves template inline void FlexMesh::findEdges() { if (!haveVertexToVertex) findVertexToVertex(); if (!haveVertexToFace) findVertexToFace(); if (FM_PO>1) std::cout << "Finding edges..." << std::flush; // reset links if needed if (haveEdges) { if (FM_PO>1) std::cout << "deleting old mappings..." << std::flush; if (ne > 0) delete [] ed; for (int i=0;i 0) { delete [] v(i).ed; v(i).ne = 0; } if (FM_PO>1) std::cout << "Done..." << std::flush; } // compute number of edges in mesh and allocate memory for them nn = 0; for (int i=0;i1) std::cout << "expect " << ne << "..." << std::flush; ed = new FlexEdge[ne]; // Go through and allocate memory for vertex-edge links for (int i=0;i 0) { v(i).ne = v(i).nv; v(i).ed = new FlexEdge*[v(i).ne]; for (int j=0;j1) std::cout << "found " << ce << "...Done." << std::endl << std::flush; } // Store current vertex positions as reference positions template inline void FlexMesh::storeReferenceData() { for (int i=0;i inline void FlexMesh::findColorWeights() { T coeff = T(0.01); if (!haveEdges) findEdges(); for (int i=0;i inline void FlexMesh::findGradient() { T coeff = T(0.1); // confidence given to measurement potential for (int i=0;i inline void FlexMesh::takeHillClimbingStep() { T stepSize = T(0.05); for (int i=0;i