void PartialAction :: relaxEdge (WingedMesh& mesh, WingedEdge& edge, AffectedFaces& affectedFaces) { if (relaxableEdge (edge)) { affectedFaces.insert (edge.leftFaceRef ()); affectedFaces.insert (edge.rightFaceRef ()); PartialAction::flipEdge (mesh, edge); } }
void PartialAction :: deleteEdgeFace ( WingedMesh& mesh, WingedEdge& edge , AffectedFaces& affectedFaces) { #ifndef NDEBUG const unsigned int numEdgesLeft = edge.leftFaceRef ().numEdges (); const unsigned int numEdgesRight = edge.rightFaceRef ().numEdges (); #endif assert (numEdgesLeft >= 2); assert (numEdgesRight >= 2); WingedFace& faceToDelete = edge.rightFaceRef (); WingedFace& remainingFace = edge.leftFaceRef (); assert (faceToDelete != remainingFace); affectedFaces.remove (faceToDelete); affectedFaces.insert (remainingFace); dissolveEdgeFace (edge); mesh.deleteEdge (edge); mesh.deleteFace (faceToDelete); assert (remainingFace.numEdges () >= 3); assert (remainingFace.numEdges () == numEdgesLeft + numEdgesRight - 2); }
void WingedUtil :: printStatistics (const WingedEdge& e) { auto maybeEdgeIndex = [] (WingedEdge* edge) { return bool (edge) ? std::to_string (edge->index ()) : std::string ("NULL"); }; auto maybeFaceIndex = [] (WingedFace* face) { return bool (face) ? std::to_string (face->index ()) : std::string ("NULL"); }; auto maybeVertexIndex = [] (WingedVertex* vertex) { return bool (vertex) ? std::to_string (vertex->index ()) : std::string ("NULL"); }; std::cout << "edge " << e.index () << "\n\tvertex 1:\t\t" << maybeVertexIndex (e.vertex1 ()) << "\tvertex 2:\t\t" << maybeVertexIndex (e.vertex2 ()) << "\n\tleft face:\t\t" << maybeFaceIndex (e.leftFace ()) << "\tright face:\t\t" << maybeFaceIndex (e.rightFace ()) << "\n\tleft predecessor:\t" << maybeEdgeIndex (e.leftPredecessor ()) << "\tleft successor:\t\t" << maybeEdgeIndex (e.leftSuccessor ()) << "\n\tright predecessor:\t" << maybeEdgeIndex (e.rightPredecessor ()) << "\tright successor:\t" << maybeEdgeIndex (e.rightSuccessor ()) << std::endl; }
void FEdgeXDetector::processShapes(WingedEdge& we) { bool progressBarDisplay = false; Vec3r Min, Max; vector<WShape*> wshapes = we.getWShapes(); WXShape * wxs; if(_pProgressBar != NULL) { _pProgressBar->reset(); _pProgressBar->setLabelText("Detecting feature lines"); _pProgressBar->setTotalSteps(wshapes.size() * 3); _pProgressBar->setProgress(0); progressBarDisplay = true; } for(vector<WShape*>::const_iterator it = wshapes.begin(); it != wshapes.end(); it++){ wxs = dynamic_cast<WXShape*>(*it); //printf("\n\nmesh silhouette = %d\n\n",wxs->MeshSilhouettes()); wxs->bbox(Min, Max); _bbox_diagonal = (Max-Min).norm(); if(_changes){ vector<WFace*>& wfaces = wxs->GetFaceList(); for(vector<WFace*>::iterator wf=wfaces.begin(), wfend=wfaces.end(); wf!=wfend; ++wf){ WXFace* wxf = dynamic_cast<WXFace*>(*wf); wxf->Clear(); } _computeViewIndependant = true; } else if (!(wxs)->getComputeViewIndependantFlag()) { wxs->Reset(); _computeViewIndependant = false; } else { _computeViewIndependant = true; } preProcessShape(wxs); if (progressBarDisplay) _pProgressBar->setProgress(_pProgressBar->getProgress() + 1); processBorderShape(wxs); // skipping crease detection: // processCreaseShape(wxs); if(_computeRidgesAndValleys) processRidgesAndValleysShape(wxs); if(_computeSuggestiveContours) processSuggestiveContourShape(wxs); processSilhouetteShape(wxs); if (progressBarDisplay) _pProgressBar->setProgress(_pProgressBar->getProgress() + 1); // build smooth edges: buildSmoothEdges(wxs); // Post processing for suggestive contours if(_computeSuggestiveContours) postProcessSuggestiveContourShape(wxs); if (progressBarDisplay) _pProgressBar->setProgress(_pProgressBar->getProgress() + 1); wxs->setComputeViewIndependantFlag(false); _computeViewIndependant = false; _changes = false; // reset user data (*it)->ResetUserData(); } }
// 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; }
// Adds 4 sub triangles based on three original vertices and 3 new vertices to the given mesh. // FIXME : Add better documentation and understanding to this function. void WingedEdge::performTriangulation(WingedEdge &mesh, Vertex &v1, Vertex &v2, Vertex &v3, Vertex &v4, Vertex &v5, Vertex &v6) { Edge e1, e2, e3; // Face 1. e1 = mesh.AddEdge(v1, v5); e2 = mesh.AddEdge(v1, v6); e3 = mesh.AddEdge(v5, v6); mesh.AddFace(e1, e2, e3); // Face 2. e1 = mesh.AddEdge(v2, v4); e2 = mesh.AddEdge(v2, v6); e3 = mesh.AddEdge(v4, v6); mesh.AddFace(e1, e2, e3); // // Face 3. e1 = mesh.AddEdge(v3, v4); e2 = mesh.AddEdge(v3, v5); e3 = mesh.AddEdge(v4, v5); mesh.AddFace(e1, e2, e3); // Face 4. e1 = mesh.AddEdge(v4, v5); e2 = mesh.AddEdge(v4, v6); e3 = mesh.AddEdge(v5, v6); mesh.AddFace(e1, e2, e3); }