// 3 - 2 3 - 2 // | / | or | \ | // 0 - 1 0 - 1 FaceIndexPair addFace (const VertexIndex& idx_v_0, const VertexIndex& idx_v_1, const VertexIndex& idx_v_2, const VertexIndex& idx_v_3, const FaceData& face_data = FaceData ()) { // Try to add two faces // 3 - 2 // | / | // 0 - 1 FaceIndex idx_face_0 = this->addFace (idx_v_0, idx_v_1, idx_v_2, face_data); FaceIndex idx_face_1 = this->addFace (idx_v_0, idx_v_2, idx_v_3, face_data); if (idx_face_0.isValid ()) { return (std::make_pair (idx_face_0, idx_face_1)); } else if (idx_face_1.isValid ()) { idx_face_0 = this->addFace (idx_v_0, idx_v_1, idx_v_2, face_data); // might be possible to add now return (std::make_pair (idx_face_1, idx_face_0)); } // Try to add two faces // 3 - 2 // | \ | // 0 - 1 idx_face_0 = this->addFace (idx_v_1, idx_v_2, idx_v_3, face_data); idx_face_1 = this->addFace (idx_v_0, idx_v_1, idx_v_3, face_data); if (idx_face_0.isValid ()) { return (std::make_pair (idx_face_0, idx_face_1)); } else if (idx_face_1.isValid ()) { idx_face_0 = this->addFace (idx_v_1, idx_v_2, idx_v_3, face_data); // might be possible to add now return (std::make_pair (idx_face_1, idx_face_0)); } // Connect the triangle pair if possible if (!idx_v_0.isValid () || !idx_v_1.isValid () || !idx_v_2.isValid () || !idx_v_3.isValid ()) { return (std::make_pair (FaceIndex (), FaceIndex ())); } VertexIndexes vi; vi.reserve (4); vi.push_back (idx_v_0); vi.push_back (idx_v_1); vi.push_back (idx_v_2); vi.push_back (idx_v_3); if (!this->uniqueCheck (vi)) { return (std::make_pair (FaceIndex (), FaceIndex ())); } HalfEdgeIndex idx_he_01, idx_he_12, idx_he_23, idx_he_30; // Check manifoldness bool is_new_01 = true; bool is_new_12 = true; bool is_new_23 = true; bool is_new_30 = true; if (!Base::checkTopology1 (idx_v_0,idx_v_1, idx_he_01, is_new_01) || !Base::checkTopology1 (idx_v_1,idx_v_2, idx_he_12, is_new_12) || !Base::checkTopology1 (idx_v_2,idx_v_3, idx_he_23, is_new_23) || !Base::checkTopology1 (idx_v_3,idx_v_0, idx_he_30, is_new_30)) { return (std::make_pair (FaceIndex (), FaceIndex ())); } // Connect the triangle pair if (!is_new_01 && is_new_12 && !is_new_23 && is_new_30) { return (this->connectTrianglePair (idx_he_01, idx_he_23, idx_v_0, idx_v_1, idx_v_2, idx_v_3, face_data)); } else if (is_new_01 && !is_new_12 && is_new_23 && !is_new_30) { return (this->connectTrianglePair (idx_he_12, idx_he_30, idx_v_1, idx_v_2, idx_v_3, idx_v_0, face_data)); } else { assert (true); // This should not happen! return (std::make_pair (FaceIndex (), FaceIndex ())); } }
int main () { Mesh mesh; VertexIndexes vi; // Create a closed circle around vertex 0 // // 1 - 6 // // / \ / \ // // 2 - 0 - 5 // // \ / \ / // // 3 - 4 // vi.push_back (mesh.addVertex (MyVertexData (0))); vi.push_back (mesh.addVertex (MyVertexData (1))); vi.push_back (mesh.addVertex (MyVertexData (2))); vi.push_back (mesh.addVertex (MyVertexData (3))); vi.push_back (mesh.addVertex (MyVertexData (4))); vi.push_back (mesh.addVertex (MyVertexData (5))); vi.push_back (mesh.addVertex (6)); // Converted to MyVertexData vi.push_back (mesh.addVertex (7)); // Will not be connected -> isolated vertex mesh.addFace (vi[0], vi[1], vi[2]); mesh.addFace (vi[0], vi[2], vi[3]); mesh.addFace (vi[0], vi[3], vi[4]); mesh.addFace (vi[0], vi[4], vi[5]); mesh.addFace (vi[0], vi[5], vi[6]); mesh.addFace (0, 6, 1); // Converted to VertexIndex printVertexes (mesh); printFaces (mesh); ////////////////////////////////////////////////////////////////////////////// std::cout << "Outgoing half-edges of vertex 0:" << std::endl; OHEAVCC circ_oheav = mesh.getOutgoingHalfEdgeAroundVertexConstCirculator (vi[0]); const OHEAVCC circ_oheav_end = circ_oheav; do { std::cout << " " << circ_oheav->getOriginatingVertex (mesh) << " " << circ_oheav->getTerminatingVertex (mesh) << std::endl; ++circ_oheav; } while (circ_oheav!=circ_oheav_end); ////////////////////////////////////////////////////////////////////////////// std::cout << "Circulate around the boundary half-edges:" << std::endl; const HalfEdgeIndex& idx_he_boundary = mesh.getElement (vi[0]). getOutgoingHalfEdge (mesh). getTerminatingVertex (mesh). getOutgoingHalfEdgeIndex (); HEABCC circ_heab = mesh.getHalfEdgeAroundBoundaryConstCirculator (idx_he_boundary); const HEABCC circ_heab_end = circ_heab; do { std::cout << " " << circ_heab->getOriginatingVertex (mesh) << " " << circ_heab->getTerminatingVertex (mesh) << std::endl; ++circ_heab; } while (circ_heab!=circ_heab_end); ////////////////////////////////////////////////////////////////////////////// std::cout << std::endl << "Deleting face 1 and 4 ...\n"; std::cout << "(If the mesh is set to manifold further faces are removed automatically)\n\n"; mesh.deleteFace (FaceIndex (1)); mesh.deleteFace (4); // Converted to FaceIndex mesh.cleanUp (false); // Delete (true) or don't delete (false) isolated vertexes vi.clear (); // The vertex indexes are no longer synchronized with the mesh! printVertexes (mesh); printFaces (mesh); ////////////////////////////////////////////////////////////////////////// std::cout << "Circulate around all faces of vertex 0:\n"; FAVCC circ_fav = mesh.getFaceAroundVertexConstCirculator (mesh.frontVertexes ()); const FAVCC circ_fav_end = circ_fav; do { // Very important: Some half_edges are on the boundary // -> have an invalid face index if (circ_fav.isValid ()) { printFace (mesh, *circ_fav); } else { std::cout << " invalid face -> boundary half-edge\n"; } ++circ_fav; } while (circ_fav!=circ_fav_end); return (0); }
FaceIndex addFace (const VertexIndex& idx_v_0, const VertexIndex& idx_v_1, const VertexIndex& idx_v_2, const FaceData& face_data = FaceData ()) { if (!idx_v_0.isValid () || !idx_v_1.isValid () || !idx_v_2.isValid ()) { return (FaceIndex ()); } VertexIndexes vi; vi.reserve (3); vi.push_back (idx_v_0); vi.push_back (idx_v_1); vi.push_back (idx_v_2); if (!this->uniqueCheck (vi)) { return (FaceIndex ()); } HalfEdgeIndex idx_he_01, idx_he_12, idx_he_20; HalfEdgeIndex idx_he_10, idx_he_21, idx_he_02; if (Base::getElement (idx_v_0).isIsolated () && Base::getElement (idx_v_1).isIsolated () && Base::getElement (idx_v_2).isIsolated ()) { Base::addHalfEdgePair (idx_v_0,idx_v_1, HalfEdgeData (),HalfEdgeData (), idx_he_01,idx_he_10); Base::addHalfEdgePair (idx_v_1,idx_v_2, HalfEdgeData (),HalfEdgeData (), idx_he_12,idx_he_21); Base::addHalfEdgePair (idx_v_2,idx_v_0, HalfEdgeData (),HalfEdgeData (), idx_he_20,idx_he_02); Base::connectHalfEdges (true,true, idx_he_01,idx_he_10, idx_he_12,idx_he_21, idx_v_1); Base::connectHalfEdges (true,true, idx_he_12,idx_he_21, idx_he_20,idx_he_02, idx_v_2); Base::connectHalfEdges (true,true, idx_he_20,idx_he_02, idx_he_01,idx_he_10, idx_v_0); return (this->connectFace (face_data, idx_he_01,idx_he_12,idx_he_20)); } // Check for topological errors bool is_new_01 = true; bool is_new_12 = true; bool is_new_20 = true; if (!Base::checkTopology1 (idx_v_0,idx_v_1, idx_he_01, is_new_01) || !Base::checkTopology1 (idx_v_1,idx_v_2, idx_he_12, is_new_12) || !Base::checkTopology1 (idx_v_2,idx_v_0, idx_he_20, is_new_20)) { return (FaceIndex ()); } if (!Base::checkTopology2 (is_new_01,is_new_12, Base::getElement (idx_v_1).isIsolated ()) || !Base::checkTopology2 (is_new_12,is_new_20, Base::getElement (idx_v_2).isIsolated ()) || !Base::checkTopology2 (is_new_20,is_new_01, Base::getElement (idx_v_0).isIsolated ())) { return (FaceIndex ()); } // Reconnect the existing half-edges if needed bool make_adjacent_01_12 = false; bool make_adjacent_12_20 = false; bool make_adjacent_20_01 = false; HalfEdgeIndex idx_he_boundary_01_12; HalfEdgeIndex idx_he_boundary_12_20; HalfEdgeIndex idx_he_boundary_20_01; if (!Base::checkAdjacency (idx_he_01,idx_he_12, is_new_01,is_new_12, make_adjacent_01_12, idx_he_boundary_01_12) || !Base::checkAdjacency (idx_he_12,idx_he_20, is_new_12,is_new_20, make_adjacent_12_20, idx_he_boundary_12_20) || !Base::checkAdjacency (idx_he_20,idx_he_01, is_new_20,is_new_01, make_adjacent_20_01, idx_he_boundary_20_01)) { return (FaceIndex ()); } Base::makeAdjacent (idx_he_01,idx_he_12, make_adjacent_01_12, idx_he_boundary_01_12); Base::makeAdjacent (idx_he_12,idx_he_20, make_adjacent_12_20, idx_he_boundary_12_20); Base::makeAdjacent (idx_he_20,idx_he_01, make_adjacent_20_01, idx_he_boundary_20_01); // Add the new half-edges if needed if (is_new_01) Base::addHalfEdgePair (idx_v_0,idx_v_1, HalfEdgeData (),HalfEdgeData (), idx_he_01,idx_he_10); else idx_he_10 = Base::getElement (idx_he_01).getOppositeHalfEdgeIndex (); if (is_new_12) Base::addHalfEdgePair (idx_v_1,idx_v_2, HalfEdgeData (),HalfEdgeData (), idx_he_12,idx_he_21); else idx_he_21 = Base::getElement (idx_he_12).getOppositeHalfEdgeIndex (); if (is_new_20) Base::addHalfEdgePair (idx_v_2,idx_v_0, HalfEdgeData (),HalfEdgeData (), idx_he_20,idx_he_02); else idx_he_02 = Base::getElement (idx_he_20).getOppositeHalfEdgeIndex (); // Connect the half-edges and vertexes Base::connectHalfEdges (is_new_01,is_new_12, idx_he_01,idx_he_10, idx_he_12,idx_he_21, idx_v_1); Base::connectHalfEdges (is_new_12,is_new_20, idx_he_12,idx_he_21, idx_he_20,idx_he_02, idx_v_2); Base::connectHalfEdges (is_new_20,is_new_01, idx_he_20,idx_he_02, idx_he_01,idx_he_10, idx_v_0); // Connect the face return (this->connectFace (face_data, idx_he_01,idx_he_12,idx_he_20)); }