void LS_Surface::Subdivide() { subdivisionLevel++; // Linear subdivision of edges LS_EdgeList::iterator edge_itr = edges.begin(); int numEdges = edges.size(); int numVertices = vertices.size(); //TimeHandle t = TimeBegin(); for( int i = 0; i < numEdges; i++, edge_itr++ ) { // Only subdivide old edges (ones not attached to a new vertex) if ( (*edge_itr)->vertices[0]->creationLevel != subdivisionLevel && (*edge_itr)->vertices[1]->creationLevel != subdivisionLevel ) SubdivideEdge( *edge_itr ); } //printf("Subdivide Edge Time = %lf\n", TimeSlice(t)); // Create the new faces / Connect the new vertices LS_FaceList::iterator face_itr = faces.begin(); int orinumfaces = faces.size(); //t = TimeBegin(); for( int i = 0; i < orinumfaces; i++, face_itr++ ) { // Connect the new vertices into faces SubdivideFace( *face_itr ); } //printf("Subdivide Face Time = %lf\n", TimeSlice(t)); // Reposition new vertices LS_VertexList::iterator vertex_itr = vertices.begin(); //t = TimeBegin(); for( int i = 0; i < vertices.size(); i++, vertex_itr++ ) { RepositionVertex( *vertex_itr ); } //printf("Reposition Time = %lf\n", TimeSlice(t)); vertex_itr = vertices.begin(); //t = TimeBegin(); for( int i = 0; i < vertices.size(); i++, vertex_itr++ ) (*vertex_itr)->pos = (*vertex_itr)->newPos; //printf("Other Time = %lf\n", TimeSlice(t)); //UpdateNormals(); }
// Subdivides only the edges on the boundary. WingedEdge WingedEdge::BoundaryTrianglularSubdivide(float min_len) { WingedEdge mesh;// = *this; for (auto face_iter = faceList.begin(); face_iter != faceList.end(); ++face_iter) { const Face face = face_iter -> first; /* massive assumption that there is 3 edges in our face */ Edge e1 = face.E1(); Edge e2 = face.E2(); Edge e3 = face.E3(); // Compute the vertices opposite the cooresponding indiced edges. bool success = true; Vertex v1 = GetAdjacentVertex(face, e1, success); Vertex v2 = GetAdjacentVertex(face, e2, success); Vertex v3 = GetAdjacentVertex(face, e3, success); if(!success) { throw new RuntimeError("Error : Winged Edge topology is malformed!"); } // -- Compute boundary predicates that answer whether or not an edge should be divided. bool b1, b2, b3; b1 = getNumAdjacentFaces(e1) == 1; b2 = getNumAdjacentFaces(e2) == 1; b3 = getNumAdjacentFaces(e3) == 1; // Non Boundary --> do not subdivide the face. if(!(b1 || b2 || b3)) { e1 = mesh.AddEdge(e1); e2 = mesh.AddEdge(e2); e2 = mesh.AddEdge(e2); mesh.AddFace(e1, e2, e3); continue; } // FIXME : Only compute butterfly midpoints, if the original predicate is true. // Compute interpolated midpoints. Vertex mid_b1, mid_b2, mid_b3; mid_b1 = SubdivideEdge(face, e1, v1, false); mid_b2 = SubdivideEdge(face, e2, v2, false); mid_b3 = SubdivideEdge(face, e3, v3, false); // Bound the change in midpoint. if(min_len > 0) { // Compute linear mid points. Vertex mid_l1, mid_l2, mid_l3; mid_l1 = SubdivideEdge(face, e1, v1, true); mid_l2 = SubdivideEdge(face, e2, v2, true); mid_l3 = SubdivideEdge(face, e3, v3, true); float sqr_len_min = min_len > 1 ? min_len*min_len : min_len; b1 = b1 && computeSqrOffset(mid_b1, mid_l1) > sqr_len_min; b2 = b2 && computeSqrOffset(mid_b2, mid_l2) > sqr_len_min; b3 = b3 && computeSqrOffset(mid_b3, mid_l3) > sqr_len_min; } // -- Count the number of edges that are on the boundary. int boundary_count = 0; boundary_count = b1 ? boundary_count + 1 : boundary_count; boundary_count = b2 ? boundary_count + 1 : boundary_count; boundary_count = b3 ? boundary_count + 1 : boundary_count; // Non Boundary --> do not subdivide the face. if(boundary_count == 0) { e1 = mesh.AddEdge(e1); e2 = mesh.AddEdge(e2); e2 = mesh.AddEdge(e2); mesh.AddFace(e1, e2, e3); continue; } // 1 boundary --> subdivide into 2 vertices. if(boundary_count == 1) { Vertex v_new, v_old1, v_old2, v_old3; if(b1) { v_new = mid_b1; v_old1 = v1; v_old2 = v2; v_old3 = v3; } else if(b2) { v_new = mid_b2; v_old1 = v2; v_old2 = v3; v_old3 = v1; } else { v_new = mid_b3; v_old1 = v3; v_old2 = v1; v_old3 = v2; } // face1 e1 = mesh.AddEdge(v_new, v_old1); e2 = mesh.AddEdge(v_new, v_old2); e3 = mesh.AddEdge(v_old1, v_old2); mesh.AddFace(e1, e2, e3); // Face 2. e2 = mesh.AddEdge(v_new, v_old3); e3 = mesh.AddEdge(v_old1, v_old3); mesh.AddFace(e1, e2, e3); continue; } // 2 - 3 boundaries. Perform the full 4 face triangulation. if(boundary_count == 3) { performTriangulation(mesh, v1, v2, v3, mid_b1, mid_b2, mid_b3); continue; } if(boundary_count > 3) { throw new RuntimeError("Face has more than 3 edges. This is not a triangle!"); } // -- 2 boundary case. Subdivide into 3 triangles. Vertex v_new1, v_new2, v_old1, v_old2, v_old3; if(!b1) { v_old1 = v1; v_old2 = v2; v_old3 = v3; v_new1 = mid_b2; v_new2 = mid_b3; } else if(!b2) { v_old1 = v2; v_old2 = v3; v_old3 = v1; v_new1 = mid_b3; v_new2 = mid_b1; } else { v_old1 = v3; v_old2 = v1; v_old3 = v2; v_new1 = mid_b1; v_new2 = mid_b2; } // Boundary triangles. e1 = mesh.AddEdge(v_old1, v_new1); e2 = mesh.AddEdge(v_old1, v_new2); e3 = mesh.AddEdge(v_new1, v_new2); mesh.AddFace(e1, e2, e3); e1 = mesh.AddEdge(v_old3, v_new1); e2 = mesh.AddEdge(v_old3, v_new2); e3 = mesh.AddEdge(v_new1, v_new2); mesh.AddFace(e1, e2, e3); // Constant edge triangle. e1 = mesh.AddEdge(v_old2, v_new2); e2 = mesh.AddEdge(v_old3, v_new2); e3 = mesh.AddEdge(v_old3, v_old2); mesh.AddFace(e1, e2, e3); } return mesh; }
// Private work function. WingedEdge WingedEdge::Subdivide(bool linear, bool pascal, std::map<Vertex, std::vector<Vertex> > &derivations) { WingedEdge mesh; std::set<Edge> edges; for (auto face = faceList.begin(); face != faceList.end(); ++face) { /* massive assumption that there is 3 edges in our face */ Edge e1 = face -> first.E1(); Edge e2 = face -> first.E2(); Edge e3 = face -> first.E3(); /* might need to verify this doesn't pick duplicates */ Vertex v1 = e1.V1(); Vertex v2 = e1.V2(); Vertex v3 = (e2.V1() == v1 || e2.V1() == v2) ? e2.V2() : e2.V1(); /* guarantee we know what e2 is */ if (v1 == e3.V1() || v1 == e3.V2()) { Edge tmp = e3; e3 = e2; e2 = tmp; } int f1, f2, f3; f1 = getNumAdjacentFaces(e1); f2 = getNumAdjacentFaces(e2); f3 = getNumAdjacentFaces(e3); // Do not subdivide and do not incorporate non boundary faces. // This is the part the creates the pascal behavior, if(pascal && f1 == 2 && f2 == 2 && f3 == 2) { continue; } bool success = true; Vertex v4 = SubdivideEdge(face->first, e1, GetAdjacentVertex(face->first, e1, success), linear, derivations); Vertex v5 = SubdivideEdge(face->first, e2, GetAdjacentVertex(face->first, e2, success), linear, derivations); Vertex v6 = SubdivideEdge(face->first, e3, GetAdjacentVertex(face->first, e3, success), linear, derivations); // A half hearted success check. if(!success) { throw RuntimeError("WindgedEdge Error: Something is wrong with the mesh to be subdivided."); } { e1 = mesh.AddEdge(v1, v4); e2 = mesh.AddEdge(v1, v5); e3 = mesh.AddEdge(v5, v4); mesh.AddFace(e1, e2, e3); } { e1 = mesh.AddEdge(v4, v2); e2 = mesh.AddEdge(v4, v6); e3 = mesh.AddEdge(v6, v2); mesh.AddFace(e1, e2, e3); } { e1 = mesh.AddEdge(v5, v6); e2 = mesh.AddEdge(v5, v3); e3 = mesh.AddEdge(v3, v6); mesh.AddFace(e1, e2, e3); } { e1 = mesh.AddEdge(v6, v5); e2 = mesh.AddEdge(v6, v4); e3 = mesh.AddEdge(v4, v5); mesh.AddFace(e1, e2, e3); } } /* std::cout << "Subdivide info: " << std::endl; std::cout << "VertexList: " << mesh.NumVertices() << std::endl; std::cout << "EdgeList: " << mesh.NumEdges() << std::endl; std::cout << "FaceList: " << mesh.NumFaces() << std::endl; */ return mesh; }