Vector3<float> HalfEdgeMesh::VertexNormal(unsigned int vertexIndex) const { Vector3<float> n(0,0,0); std::vector<unsigned int> fa = FindNeighborFaces(vertexIndex); for(int i = 0; i < fa.size(); i++) { n += f(fa.at(i)).normal; } return n.Normalize(); }
//----------------------------------------------------------------------------- Vector3<float> SimpleMesh::VertexNormal(unsigned int vertexIndex) const{ std::vector<unsigned int> neighborFaces = FindNeighborFaces(vertexIndex); Vector3<float> n(0,0,0); const unsigned int numCandidates = neighborFaces.size(); for (unsigned int i = 0; i < numCandidates; i++){ const Face& triangle = mFaces.at(neighborFaces.at(i)); // NB Assumes face normals already calculated n += triangle.normal; } n.Normalize(); return n; }
/*! * \param[in] indx vertex index, points into HalfEdgeMesh::mVerts */ Matrix4x4<float> QuadricDecimationMesh::createQuadricForVert(unsigned int indx) const{ float q[4][4] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}}; Matrix4x4<float> Q(q); std::vector<unsigned int> faces = FindNeighborFaces(indx); for(int i = 0; i < faces.size(); i++){ Q += createQuadricForFace(faces[i]); } // The quadric for a vertex is the sum of all the quadrics for the adjacent faces // Tip: Matrix4x4 has an operator += return Q; }
/*! Computes a new vertex, replacing a vertex in the old mesh If any of the neighboring faces have subdividability == false then we should not move this vertex, else use the rules from loop subdivision */ Vector3<float> AdaptiveLoopSubdivisionMesh::VertexRule(unsigned int vertexIndex) { // Get the current vertex Vector3<float> vtx = v(vertexIndex).pos; // Get face neighborhood std::vector<unsigned int> nb = FindNeighborFaces(vertexIndex); for(unsigned int i=0; i<nb.size(); i++){ if(Subdividable(nb.at(i)) == false){ // don't move position return vtx; } } // else return VertexRule for LSMesh return LoopSubdivisionMesh::VertexRule(vertexIndex); }
/*! Loops over the neighborhood of a vertex and collects all the vertices sorted counter clockwise. * \param [in] vertexIndex the index to vertex, unsigned int * \return a vector containing the indices to all the found vertices. */ std::vector<unsigned int> SimpleMesh::FindNeighborVertices(unsigned int vertexIndex) const{ std::vector<unsigned int> neighborFaces = FindNeighborFaces(vertexIndex); std::vector<unsigned int> oneRing; unsigned int currVert; // pick next counter clock wise vert if(mFaces.at(neighborFaces.at(0)).v1 == vertexIndex) currVert = mFaces.at(neighborFaces.at(0)).v2; if(mFaces.at(neighborFaces.at(0)).v2 == vertexIndex) currVert = mFaces.at(neighborFaces.at(0)).v3; if(mFaces.at(neighborFaces.at(0)).v3 == vertexIndex) currVert = mFaces.at(neighborFaces.at(0)).v1; oneRing.push_back(currVert); // collect one ring vertices for(unsigned int i=0; i< neighborFaces.size() - 1; i++){ if(mFaces.at(neighborFaces.at(i)).v1 == currVert) currVert = mFaces.at(neighborFaces.at(i)).v2; else if(mFaces.at(neighborFaces.at(i)).v2 == currVert) currVert = mFaces.at(neighborFaces.at(i)).v3; else if(mFaces.at(neighborFaces.at(i)).v3 == currVert) currVert = mFaces.at(neighborFaces.at(i)).v1; oneRing.push_back(currVert); } return oneRing; }
/*! Proceeds to check if the mesh is valid. All indices are inspected and * checked to see that they are initialized. The method checks: mEdges, mFaces and mVerts. * Also checks to see if all verts have a neighborhood using the findNeighbourFaces method. */ void HalfEdgeMesh::Validate() { std::vector<HalfEdge>::iterator iterEdge = mEdges.begin(); std::vector<HalfEdge>::iterator iterEdgeEnd = mEdges.end(); while (iterEdge != iterEdgeEnd) { if ((*iterEdge).face == UNINITIALIZED || (*iterEdge).next == UNINITIALIZED || (*iterEdge).pair == UNINITIALIZED || (*iterEdge).prev == UNINITIALIZED || (*iterEdge).vert == UNINITIALIZED) std::cerr << "HalfEdge " << iterEdge - mEdges.begin() << " not properly initialized" << std::endl; iterEdge++; } std::cerr << "Done with edge check (checked " << GetNumEdges() << " edges)" << std::endl; std::vector<Face>::iterator iterTri = mFaces.begin(); std::vector<Face>::iterator iterTriEnd = mFaces.end(); while (iterTri != iterTriEnd) { if ((*iterTri).edge == UNINITIALIZED) std::cerr << "Tri " << iterTri - mFaces.begin() << " not properly initialized" << std::endl; iterTri++; } std::cerr << "Done with face check (checked " << GetNumFaces() << " faces)" << std::endl; std::vector<Vertex>::iterator iterVertex = mVerts.begin(); std::vector<Vertex>::iterator iterVertexEnd = mVerts.end(); while (iterVertex != iterVertexEnd) { if ((*iterVertex).edge == UNINITIALIZED) std::cerr << "Vertex " << iterVertex - mVerts.begin() << " not properly initialized" << std::endl; iterVertex++; } std::cerr << "Done with vertex check (checked " << GetNumVerts() << " vertices)" << std::endl; std::cerr << "Looping through triangle neighborhood of each vertex... "; iterVertex = mVerts.begin(); iterVertexEnd = mVerts.end(); int emptyCount = 0; std::vector<unsigned int> problemVerts; while (iterVertex != iterVertexEnd) { std::vector<unsigned int> foundFaces = FindNeighborFaces(iterVertex - mVerts.begin()); std::vector<unsigned int> foundVerts = FindNeighborVertices(iterVertex - mVerts.begin()); if (foundFaces.empty() || foundVerts.empty()) emptyCount++; std::set<unsigned int> uniqueFaces(foundFaces.begin(), foundFaces.end()); std::set<unsigned int> uniqueVerts(foundVerts.begin(), foundVerts.end()); if ( foundFaces.size() != uniqueFaces.size() || foundVerts.size() != uniqueVerts.size() ) problemVerts.push_back(iterVertex - mVerts.begin()); iterVertex++; } std::cerr << std::endl << "Done: " << emptyCount << " isolated vertices found" << std::endl; if(problemVerts.size()){ std::cerr << std::endl << "Found " << problemVerts.size() << " duplicate faces in vertices: "; std::copy(problemVerts.begin(), problemVerts.end(), std::ostream_iterator<unsigned int>(std::cerr, ", ")); std::cerr << "\n"; } std::cerr << std::endl << "The mesh has genus " << Genus() << ", and consists of " << Shells() << " shells.\n"; }