// Returns. the vertice on the face that is not in the given edge. // FIXME : Do we really need to check successes? This should be guranteed. Vertex WingedEdge::GetAdjacentVertex(const Face& face, const Edge& edge, bool &success) { success = true; if (face.E1() != edge) return (face.E1().V1() == edge.V1()) ? face.E1().V2() : face.E1().V1(); else if (face.E2() != edge) return (face.E2().V1() == edge.V1()) ? face.E2().V2() : face.E2().V1(); else if (face.E3() != edge) return (face.E3().V1() == edge.V1()) ? face.E3().V2() : face.E3().V1(); // Bugus return. success = false; return edge.V1(); //throw RuntimeError("Couldn't find Adjacent Vertex"); }
/* This functions computes the new butterfly vertices based on the points in the stencil of the given edge. *FIXME : http://mrl.nyu.edu/~dzorin/papers/zorin1996ism.pdf Page 3. * The special internal cases still need to be implemented. * * Only the degree 6 vertice cases and boundary cases have been implemented for butterfly. * * FIXME : add a type variable to determine what type of interpolation should be used for the edges. * Currently it always uses the butterfly scheme. * * REQUIRES : e is in f1. b1 is in f1. b1 is not in e. * */ Vertex WingedEdge::SubdivideEdge(const Face& f1, Edge& e, Vertex b1, bool linear, std::map<Vertex, std::vector<Vertex> > &derivations) { // Initialize the derivation structure. std::vector<Vertex> derive_indices; // Find 'a' points. Vertex a1 = e.V1(); Vertex a2 = e.V2(); // Add 'a' points to the derivation vector. derive_indices.push_back(a1); derive_indices.push_back(a2); /* get our a midpoint */ Vertex v; v = a1 / 2.0; v = v + (a2 / 2.0); if(linear) { derivations[v] = derive_indices; return v; } // Flag for whether we are in theboundary case or not. bool boundary = false; do { bool success = true; Face f2 = GetAdjacentFace(f1, e, success); if(!success) { boundary = true; break; } /* get our opposing face's b point */ Vertex b2 = GetAdjacentVertex(f2, e, success); if(!success) { boundary = true; break; } v = v + (b1/8.0); v = v + (b2/8.0); // Add 'b' points to the derivation vector. derive_indices.push_back(b1); derive_indices.push_back(b2); /* time to get our c points */ std::set<Edge> edges; edges.insert(f1.E1()); edges.insert(f1.E2()); edges.insert(f1.E3()); for (auto edge = edges.begin(); edge != edges.end(); ++edge) { if (*edge != e) { Vertex c = GetAdjacentFaceVertex(f1, *edge, success); v = v - (c/16.0); if(derive_indices.size() < 8) { derive_indices.push_back(c); } if(!success) { boundary = true; break; } } } edges.erase(edges.begin(), edges.end()); edges.insert(f2.E1()); edges.insert(f2.E2()); edges.insert(f2.E3()); for (auto edge = edges.begin(); edge != edges.end(); ++edge) { if (*edge != e) { Vertex c = GetAdjacentFaceVertex(f2, *edge, success); v = v - (c/16.0); if(derive_indices.size() < 8) { derive_indices.push_back(c); } if(!success) { boundary = true; break; } } } } while(false); if(boundary) { /* * Proceed with boundary case. */ // Extract the 4 vertices. Vertex v1, v2, v3, v4; v1 = e.V1(); v2 = e.V2(); v3 = getOtherBoundaryVertice(v1, e); v4 = getOtherBoundaryVertice(v2, e); // For the boundary case, we will will ignore the derive_indices vector, // and just compute a new vector with the 4 indices. std::vector<Vertex> boundary_indices; boundary_indices.push_back(v1); boundary_indices.push_back(v2); boundary_indices.push_back(v3); boundary_indices.push_back(v4); Vertex output = (v1*9 + v2*9 - v3 - v4)/16.0; derivations[output] = boundary_indices; return output; } derivations[v] = derive_indices; return v; }
// 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; }
/* This functions computes the new butterfly vertices based on the points in the stencil of the given edge. *FIXME : http://mrl.nyu.edu/~dzorin/papers/zorin1996ism.pdf Page 3. * The special internal cases still need to be implemented. * * Only the degree 6 vertice cases and boundary cases have been implemented for butterfly. * * FIXME : add a type variable to determine what type of interpolation should be used for the edges. * Currently it always uses the butterfly scheme. * * REQUIRES : e is in f1. b1 is in f1. b1 is not in e. * */ Vertex WingedEdge::SubdivideEdge(const Face& f1, Edge& e, Vertex b1, bool linear) { /* get our a midpoint */ Vertex v; v = e.V1() / 2.0; v = v + (e.V2() / 2.0); if(linear) { return v; } // Flag for whether we are in theboundary case or not. bool boundary = false; do { bool success = true; Face f2 = GetAdjacentFace(f1, e, success); if(!success) { boundary = true; break; } /* get our opposing face's b point */ Vertex b2 = GetAdjacentVertex(f2, e, success); if(!success) { boundary = true; break; } v = v + (b1/8.0); v = v + (b2/8.0); /* time to get our c points */ std::set<Edge> edges; edges.insert(f1.E1()); edges.insert(f1.E2()); edges.insert(f1.E3()); for (auto edge = edges.begin(); edge != edges.end(); ++edge) { if (*edge != e) { v = v - (GetAdjacentFaceVertex(f1, *edge, success)/16.0); if(!success) { boundary = true; break; } } } edges.erase(edges.begin(), edges.end()); edges.insert(f2.E1()); edges.insert(f2.E2()); edges.insert(f2.E3()); for (auto edge = edges.begin(); edge != edges.end(); ++edge) { if (*edge != e) { v = v - (GetAdjacentFaceVertex(f2, *edge, success)/16.0); if(!success) { boundary = true; break; } } } } while(false); if(boundary) { /* * Proceed with boundary case. */ // Extract the 4 vertices. Vertex v1, v2, v3, v4; v1 = e.V1(); v2 = e.V2(); v3 = getOtherBoundaryVertice(v1, e); v4 = getOtherBoundaryVertice(v2, e); return (v1*9 + v2*9 - v3 - v4)/16.0; } return v; }