float HalfEdgeMesh::FaceCurvature(unsigned int faceIndex) const { // NB Assumes vertex curvature already computed unsigned int indx = f(faceIndex).edge; const EdgeIterator it = GetEdgeIterator(indx); const Vertex& v1 = v(it.GetEdgeVertexIndex()); const Vertex &v2 = v(it.Next().GetEdgeVertexIndex()); const Vertex &v3 = v(it.Next().GetEdgeVertexIndex()); return (v1.curvature + v2.curvature + v3.curvature) / 3.f; }
/*! Subdivides the face at faceIndex given 3 not subdividable neighbors or if subdividable for this face is false */ std::vector< std::vector<Vector3<float> > > AdaptiveLoopSubdivisionMesh::Subdivide3(unsigned int faceIndex){ EdgeIterator eit = GetEdgeIterator( f(faceIndex).edge ); Vector3<float> v1 = VertexRule(eit.GetEdgeVertexIndex()); Vector3<float> v2 = VertexRule(eit.Next().GetEdgeVertexIndex()); Vector3<float> v3 = VertexRule(eit.Next().GetEdgeVertexIndex()); std::vector<Vector3<float> > face; face.push_back(v1); face.push_back(v2); face.push_back(v3); std::vector< std::vector<Vector3<float> > > faces; faces.push_back(face); return faces; }
Vector3<float> HalfEdgeMesh::FaceNormal(unsigned int faceIndex) const { unsigned int indx = f(faceIndex).edge; const EdgeIterator it = GetEdgeIterator(indx); const Vector3<float> &p1 = v(it.GetEdgeVertexIndex()).pos; const Vector3<float> &p2 = v(it.Next().GetEdgeVertexIndex()).pos; const Vector3<float> &p3 = v(it.Next().GetEdgeVertexIndex()).pos; const Vector3<float> e1 = p2-p1; const Vector3<float> e2 = p3-p1; return Cross(e1, e2).Normalize(); }
/*! Subdivides the face at faceIndex given 1 not subdividable neighbor */ std::vector< std::vector<Vector3<float> > > AdaptiveLoopSubdivisionMesh::Subdivide1(unsigned int faceIndex){ // We know we have one false face // 1. Start by orienting the triangle so that we always have the same case // We find the start edge as the edge who shares face with the _not_subdividable_ neighbor HalfEdgeMesh::EdgeIterator eit = GetEdgeIterator( f(faceIndex).edge ); unsigned int num = 0; while( Subdividable(eit.Pair().GetEdgeFaceIndex()) ){ eit.Pair().Next(); assert(num++ < 3); } // go back to inner edge eit.Pair(); // 2. Now find the vertices std::vector< std::vector<Vector3<float> > > faces; // corner vertices, labeled from current edge's origin vertex Vector3<float> v1 = VertexRule(eit.GetEdgeVertexIndex()); Vector3<float> v2 = VertexRule(eit.Next().GetEdgeVertexIndex()); Vector3<float> v3 = VertexRule(eit.Next().GetEdgeVertexIndex()); // edge vertices, labeled from start edge Vector3<float> e2v = EdgeRule( eit.Next().Next().GetEdgeIndex() ); Vector3<float> e3v = EdgeRule( eit.Next().GetEdgeIndex() ); // 3. Create the 3 faces and push them on the vector std::vector<Vector3<float> > face; face.push_back(v1); face.push_back(v2); face.push_back(e2v); faces.push_back(face); face.clear(); face.push_back(e2v); face.push_back(v3); face.push_back(e3v); faces.push_back(face); face.clear(); face.push_back(e3v); face.push_back(v1); face.push_back(e2v); faces.push_back(face); face.clear(); // 4. Return return faces; }
/*! Subdivides the face at faceindex into a vector of faces */ std::vector< std::vector<Vector3<float> > > LoopSubdivisionMesh::Subdivide(unsigned int faceIndex) { std::vector< std::vector<Vector3<float> > > faces; EdgeIterator eit = GetEdgeIterator( f(faceIndex).edge ); // get the inner halfedges unsigned int e0, e1, e2; // and their vertex indices unsigned int v0, v1, v2; e0 = eit.GetEdgeIndex(); v0 = eit.GetEdgeVertexIndex(); eit.Next(); e1 = eit.GetEdgeIndex(); v1 = eit.GetEdgeVertexIndex(); eit.Next(); e2 = eit.GetEdgeIndex(); v2 = eit.GetEdgeVertexIndex(); // Compute positions of the vertices Vector3<float> pn0 = VertexRule(v0); Vector3<float> pn1 = VertexRule(v1); Vector3<float> pn2 = VertexRule(v2); // Compute positions of the edge vertices Vector3<float> pn3 = EdgeRule(e0); Vector3<float> pn4 = EdgeRule(e1); Vector3<float> pn5 = EdgeRule(e2); // add the four new triangles to new mesh std::vector<Vector3<float> > verts; verts.push_back(pn0); verts.push_back(pn3); verts.push_back(pn5); faces.push_back(verts); verts.clear(); verts.push_back(pn3); verts.push_back(pn4); verts.push_back(pn5); faces.push_back(verts); verts.clear(); verts.push_back(pn3); verts.push_back(pn1); verts.push_back(pn4); faces.push_back(verts); verts.clear(); verts.push_back(pn5); verts.push_back(pn4); verts.push_back(pn2); faces.push_back(verts); return faces; }
/*! Subdivides the mesh one step, depending on subdividability */ void AdaptiveLoopSubdivisionMesh::Subdivide() { // Create new mesh and copy all the attributes HalfEdgeMesh subDivMesh; subDivMesh.SetTransform(GetTransform()); subDivMesh.SetName(GetName()); subDivMesh.SetColorMap(GetColorMap()); subDivMesh.SetWireframe(GetWireframe()); subDivMesh.SetShowNormals(GetShowNormals()); subDivMesh.SetOpacity(GetOpacity()); if (IsHovering()) subDivMesh.Hover(); if (IsSelected()) subDivMesh.Select(); subDivMesh.mMinCMap = mMinCMap; subDivMesh.mMaxCMap = mMaxCMap; subDivMesh.mAutoMinMax = mAutoMinMax; // loop over each face and create new ones for(unsigned int i=0; i<GetNumFaces(); i++){ // find neighbor faces unsigned int f1, f2, f3; EdgeIterator eit = GetEdgeIterator( f(i).edge ); f1 = eit.Pair().GetEdgeFaceIndex(); eit.Pair(); f2 = eit.Next().Pair().GetEdgeFaceIndex(); eit.Pair(); f3 = eit.Next().Pair().GetEdgeFaceIndex(); unsigned int numNotSubdividable = !Subdividable(f1) + !Subdividable(f2) + !Subdividable(f3); // Do not subdivide if "self" is not subdividable if(!Subdividable(i)){ numNotSubdividable = 3; } std::vector< std::vector <Vector3<float> > > faces; switch(numNotSubdividable){ case 0: // normal subdivision (from LoopSubdivisionMesh) faces = LoopSubdivisionMesh::Subdivide(i); break; case 1: // special case 1 faces = Subdivide1(i); break; case 2: // special case 2 faces = Subdivide2(i); break; case 3: // trivial case, no subdivision, same as if subdividable(fi) == false faces = Subdivide3(i); break; } // add the faces (if any) to subDivMesh for(unsigned int j=0; j<faces.size(); j++){ subDivMesh.AddFace(faces.at(j)); } } // Assign the new mesh *this = AdaptiveLoopSubdivisionMesh(subDivMesh, ++mNumSubDivs); Update(); }