LCOV - code coverage report
Current view: top level - src/efa - EFAFragment3D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 198 235 84.3 %
Date: 2025-09-04 07:58:55 Functions: 23 30 76.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "EFAFragment3D.h"
      11             : 
      12             : #include "EFAVolumeNode.h"
      13             : #include "EFANode.h"
      14             : #include "EFAEdge.h"
      15             : #include "EFAFace.h"
      16             : #include "EFAFuncs.h"
      17             : #include "EFAElement3D.h"
      18             : #include "EFAError.h"
      19             : 
      20       37441 : EFAFragment3D::EFAFragment3D(EFAElement3D * host,
      21             :                              bool create_faces,
      22             :                              const EFAElement3D * from_host,
      23       37441 :                              unsigned int frag_id)
      24       37441 :   : EFAFragment(), _host_elem(host)
      25             : {
      26       37441 :   if (create_faces)
      27             :   {
      28       34572 :     if (!from_host)
      29           0 :       EFAError("EFAfragment3D constructor must have a from_host to copy from");
      30       34572 :     if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself
      31             :     {
      32      139007 :       for (unsigned int i = 0; i < from_host->numFaces(); ++i)
      33      115686 :         _faces.push_back(new EFAFace(*from_host->getFace(i)));
      34             :     }
      35             :     else
      36             :     {
      37       11251 :       if (frag_id > from_host->numFragments() - 1)
      38           0 :         EFAError("In EFAfragment3D constructor fragment_copy_index out of bounds");
      39       71954 :       for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numFaces(); ++i)
      40       60703 :         _faces.push_back(new EFAFace(*from_host->getFragmentFace(frag_id, i)));
      41             :     }
      42       34572 :     findFacesAdjacentToFaces(); // IMPORTANT
      43             :   }
      44       37441 : }
      45             : 
      46       74882 : EFAFragment3D::~EFAFragment3D()
      47             : {
      48      229271 :   for (unsigned int i = 0; i < _faces.size(); ++i)
      49             :   {
      50      191830 :     if (_faces[i])
      51             :     {
      52      191830 :       delete _faces[i];
      53      191830 :       _faces[i] = nullptr;
      54             :     }
      55             :   }
      56       74882 : }
      57             : 
      58             : void
      59      543415 : EFAFragment3D::switchNode(EFANode * new_node, EFANode * old_node)
      60             : {
      61     3199586 :   for (unsigned int i = 0; i < _faces.size(); ++i)
      62     2656171 :     _faces[i]->switchNode(new_node, old_node);
      63      543415 : }
      64             : 
      65             : bool
      66     2086584 : EFAFragment3D::containsNode(EFANode * node) const
      67             : {
      68             :   bool contains = false;
      69     6876053 :   for (unsigned int i = 0; i < _faces.size(); ++i)
      70             :   {
      71     6047391 :     if (_faces[i]->containsNode(node))
      72             :     {
      73             :       contains = true;
      74             :       break;
      75             :     }
      76             :   }
      77     2086584 :   return contains;
      78             : }
      79             : 
      80             : unsigned int
      81       26673 : EFAFragment3D::getNumCuts() const
      82             : {
      83             :   unsigned int num_cut_faces = 0;
      84      160211 :   for (unsigned int i = 0; i < _faces.size(); ++i)
      85      133538 :     if (_faces[i]->hasIntersection())
      86        4843 :       num_cut_faces += 1;
      87       26673 :   return num_cut_faces;
      88             : }
      89             : 
      90             : unsigned int
      91           0 : EFAFragment3D::getNumCutNodes() const
      92             : {
      93           0 :   mooseError("Not implemented yet for 3D.");
      94             : }
      95             : 
      96             : std::set<EFANode *>
      97       55932 : EFAFragment3D::getAllNodes() const
      98             : {
      99             :   std::set<EFANode *> all_nodes;
     100      339065 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     101     1310731 :     for (unsigned int j = 0; j < _faces[i]->numNodes(); ++j)
     102     1027598 :       all_nodes.insert(_faces[i]->getNode(j));
     103       55932 :   return all_nodes;
     104             : }
     105             : 
     106             : bool
     107       26277 : EFAFragment3D::isConnected(EFAFragment * other_fragment) const
     108             : {
     109       26277 :   EFAFragment3D * other_frag3d = dynamic_cast<EFAFragment3D *>(other_fragment);
     110       26277 :   if (!other_frag3d)
     111           0 :     EFAError("in isConnected other_fragment is not of type EFAfragement3D");
     112             : 
     113       96641 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     114      506800 :     for (unsigned int j = 0; j < other_frag3d->numFaces(); ++j)
     115      436436 :       if (_faces[i]->equivalent(other_frag3d->_faces[j]))
     116             :         return true;
     117             : 
     118             :   return false;
     119             : }
     120             : 
     121             : bool
     122       30676 : EFAFragment3D::isEdgeConnected(EFAFragment * other_fragment) const
     123             : {
     124       30676 :   EFAFragment3D * other_frag3d = dynamic_cast<EFAFragment3D *>(other_fragment);
     125       30676 :   if (!other_frag3d)
     126           0 :     EFAError("in isEdgeConnected other_fragment is not of type EFAfragement3D");
     127             : 
     128       69267 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     129      238872 :     for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
     130     1080882 :       for (unsigned int k = 0; k < other_frag3d->numFaces(); ++k)
     131     4096716 :         for (unsigned int l = 0; l < other_frag3d->_faces[k]->numEdges(); ++l)
     132     3216115 :           if (_faces[i]->getEdge(j)->equivalent(*(other_frag3d->_faces[k]->getEdge(l))))
     133             :             return true;
     134             : 
     135             :   return false;
     136             : }
     137             : 
     138             : void
     139        3352 : EFAFragment3D::removeInvalidEmbeddedNodes(std::map<unsigned int, EFANode *> & EmbeddedNodes)
     140             : {
     141             :   // N.B. this method is only called before we update fragments
     142             :   // N.B. an embedded node is valid IF at least one of its host faces is exterior and has more than
     143             :   // 1 cuts
     144             :   // TODO: the invalid cases are generalized from 2D. The method may need improvements in 3D
     145        3352 :   if (hasFaceWithOneCut())
     146             :   {
     147             :     // build a local inverse map for all emb cut nodes in this fragment
     148             :     std::map<EFANode *, std::vector<EFAFace *>> emb_inverse_map;
     149        1394 :     for (unsigned int i = 0; i < _faces.size(); ++i)
     150        5540 :       for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j)
     151        4368 :         if (_faces[i]->getEdge(j)->hasIntersection())
     152             :         {
     153         908 :           EFANode * emb_node = _faces[i]->getEdge(j)->getEmbeddedNode(0);
     154         908 :           emb_inverse_map[emb_node].push_back(_faces[i]);
     155             :         }
     156             : 
     157             :     // find all invalid embedded nodes
     158             :     std::vector<EFANode *> invalid_emb;
     159             :     std::map<EFANode *, std::vector<EFAFace *>>::iterator it;
     160         676 :     for (it = emb_inverse_map.begin(); it != emb_inverse_map.end(); ++it)
     161             :     {
     162         454 :       EFANode * emb_node = it->first;
     163             :       std::vector<EFAFace *> & emb_faces = it->second;
     164         454 :       if (emb_faces.size() != 2)
     165           0 :         EFAError("one embedded node must be owned by 2 faces");
     166             :       unsigned int counter = 0;
     167        1362 :       for (unsigned int i = 0; i < emb_faces.size(); ++i)
     168             :       {
     169         908 :         unsigned int face_id = getFaceID(emb_faces[i]);
     170         908 :         if (!isFaceInterior(face_id) && emb_faces[i]->hasIntersection())
     171         464 :           counter += 1; // count the appropriate emb's faces
     172             :       }
     173         454 :       if (counter == 0)
     174           0 :         invalid_emb.push_back(emb_node);
     175             :     }
     176             : 
     177             :     // delete all invalid emb nodes
     178         222 :     for (unsigned int i = 0; i < invalid_emb.size(); ++i)
     179             :     {
     180           0 :       Efa::deleteFromMap(EmbeddedNodes, invalid_emb[i]);
     181           0 :       _host_elem->removeEmbeddedNode(invalid_emb[i], true); // also remove from neighbors
     182             :     }                                                       // i
     183         222 :   }
     184        3352 : }
     185             : 
     186             : void
     187         254 : EFAFragment3D::combine_tip_faces()
     188             : {
     189         254 :   if (!_host_elem)
     190           0 :     EFAError("In combine_tip_faces() the frag must have host_elem");
     191             : 
     192        1618 :   for (unsigned int i = 0; i < _host_elem->numFaces(); ++i)
     193             :   {
     194             :     std::vector<unsigned int> frag_tip_face_id;
     195        9793 :     for (unsigned int j = 0; j < _faces.size(); ++j)
     196        8429 :       if (_host_elem->getFace(i)->containsFace(_faces[j]))
     197        1628 :         frag_tip_face_id.push_back(j);
     198             : 
     199        1364 :     if (frag_tip_face_id.size() == 2) // combine the two frag faces on this elem face
     200         264 :       combine_two_faces(frag_tip_face_id[0], frag_tip_face_id[1], _host_elem->getFace(i));
     201        1364 :   }
     202             :   // TODO: may need to combine other frag faces that have tip edges
     203         254 : }
     204             : 
     205             : bool
     206     4791281 : EFAFragment3D::isFaceInterior(unsigned int face_id) const
     207             : {
     208     4791281 :   if (!_host_elem)
     209           0 :     EFAError("in isFaceInterior() fragment must have host elem");
     210             : 
     211             :   bool face_in_elem_face = false;
     212    17651995 :   for (unsigned int i = 0; i < _host_elem->numFaces(); ++i)
     213    16753613 :     if (_host_elem->getFace(i)->containsFace(_faces[face_id]))
     214             :     {
     215             :       face_in_elem_face = true;
     216             :       break;
     217             :     }
     218             : 
     219             :   // the face is interior if it does not coincide with an element face
     220     4791281 :   return !face_in_elem_face;
     221             : }
     222             : 
     223             : std::vector<unsigned int>
     224           0 : EFAFragment3D::get_interior_face_id() const
     225             : {
     226             :   std::vector<unsigned int> interior_face_id;
     227           0 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     228           0 :     if (isFaceInterior(i))
     229           0 :       interior_face_id.push_back(i);
     230             : 
     231           0 :   return interior_face_id;
     232           0 : }
     233             : 
     234             : bool
     235           0 : EFAFragment3D::isThirdInteriorFace(unsigned int face_id) const
     236             : {
     237           0 :   if (!_host_elem)
     238           0 :     EFAError("in isThirdInteriorFace fragment must have host elem");
     239             : 
     240           0 :   for (unsigned int i = 0; i < _host_elem->numInteriorNodes(); ++i)
     241           0 :     if (_faces[face_id]->containsNode(_host_elem->getInteriorNode(i)->getNode()))
     242             :       return true;
     243             : 
     244             :   return false;
     245             : }
     246             : 
     247             : unsigned int
     248     7770563 : EFAFragment3D::numFaces() const
     249             : {
     250     7770563 :   return _faces.size();
     251             : }
     252             : 
     253             : EFAFace *
     254     1309199 : EFAFragment3D::getFace(unsigned int face_id) const
     255             : {
     256     1309199 :   if (face_id > _faces.size() - 1)
     257           0 :     EFAError("in EFAfragment3D::get_face, index out of bounds");
     258     1309199 :   return _faces[face_id];
     259             : }
     260             : 
     261             : unsigned int
     262         908 : EFAFragment3D::getFaceID(EFAFace * face) const
     263             : {
     264        2942 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     265        2942 :     if (_faces[i] == face)
     266         908 :       return i;
     267           0 :   EFAError("face not found in get_face_id()");
     268             : }
     269             : 
     270             : void
     271       15705 : EFAFragment3D::addFace(EFAFace * new_face)
     272             : {
     273       15705 :   _faces.push_back(new_face);
     274       15705 : }
     275             : 
     276             : std::set<EFANode *>
     277           0 : EFAFragment3D::getFaceNodes(unsigned int face_id) const
     278             : {
     279             :   std::set<EFANode *> face_nodes;
     280           0 :   for (unsigned int i = 0; i < _faces[face_id]->numNodes(); ++i)
     281           0 :     face_nodes.insert(_faces[face_id]->getNode(i));
     282           0 :   return face_nodes;
     283             : }
     284             : 
     285             : EFAElement3D *
     286           0 : EFAFragment3D::getHostElement() const
     287             : {
     288           0 :   return _host_elem;
     289             : }
     290             : 
     291             : std::vector<EFAFragment3D *>
     292        1657 : EFAFragment3D::split()
     293             : {
     294             :   // This method will split one existing fragment into one or two new fragments
     295             :   std::vector<EFAFragment3D *> new_fragments;
     296             :   std::vector<std::vector<EFAFace *>> all_subfaces;
     297       10095 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     298             :   {
     299        8438 :     std::vector<EFAFace *> subfaces = _faces[i]->split();
     300        8438 :     all_subfaces.push_back(subfaces);
     301        8438 :   }
     302             : 
     303             :   // build new frags
     304        1657 :   if (hasFaceWithOneCut()) // "fakely" cut fragment
     305             :   {
     306         445 :     EFAFragment3D * new_frag = new EFAFragment3D(_host_elem, false, nullptr);
     307        2827 :     for (unsigned int i = 0; i < all_subfaces.size(); ++i)
     308        5231 :       for (unsigned int j = 0; j < all_subfaces[i].size(); ++j)
     309        2849 :         new_frag->addFace(all_subfaces[i][j]);
     310         445 :     new_frag->findFacesAdjacentToFaces();
     311         445 :     new_fragments.push_back(new_frag);
     312             :   }
     313             :   else // thoroughly cut fragment
     314             :   {
     315             :     // find the first face with 2 sub-faces
     316             :     EFAFace * start_face1 = nullptr;
     317             :     EFAFace * start_face2 = nullptr;
     318             :     unsigned int startOldFaceID = 0;
     319        1385 :     for (unsigned int i = 0; i < _faces.size(); ++i)
     320             :     {
     321        1385 :       if (all_subfaces[i].size() == 2)
     322             :       {
     323        1212 :         start_face1 = all_subfaces[i][0];
     324        1212 :         start_face2 = all_subfaces[i][1];
     325             :         startOldFaceID = i;
     326        1212 :         break;
     327             :       }
     328             :     } // i
     329        1212 :     EFAFragment3D * new_frag1 = connectSubfaces(start_face1, startOldFaceID, all_subfaces);
     330        1212 :     EFAFragment3D * new_frag2 = connectSubfaces(start_face2, startOldFaceID, all_subfaces);
     331        1212 :     new_fragments.push_back(new_frag1);
     332        1212 :     new_fragments.push_back(new_frag2);
     333             :   }
     334        1657 :   return new_fragments;
     335        1657 : }
     336             : 
     337             : void
     338       40129 : EFAFragment3D::findFacesAdjacentToFaces()
     339             : {
     340       40129 :   _faces_adjacent_to_faces.clear();
     341      244089 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     342             :   {
     343      203960 :     std::vector<EFAFace *> face_adjacents(_faces[i]->numEdges(), nullptr);
     344     1281010 :     for (unsigned int j = 0; j < _faces.size(); ++j)
     345     1077050 :       if (_faces[j] != _faces[i] && _faces[i]->isAdjacent(_faces[j]))
     346             :       {
     347      739092 :         unsigned int adj_edge = _faces[i]->adjacentCommonEdge(_faces[j]);
     348      739092 :         face_adjacents[adj_edge] = _faces[j];
     349             :       }
     350             : 
     351      203960 :     _faces_adjacent_to_faces.push_back(face_adjacents);
     352      203960 :   } // i
     353       40129 : }
     354             : 
     355             : EFAFace *
     356           0 : EFAFragment3D::getAdjacentFace(unsigned int face_id, unsigned int edge_id) const
     357             : {
     358           0 :   return _faces_adjacent_to_faces[face_id][edge_id]; // possibly NULL
     359             : }
     360             : 
     361             : void
     362           0 : EFAFragment3D::removeEmbeddedNode(EFANode * emb_node)
     363             : {
     364           0 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     365           0 :     _faces[i]->removeEmbeddedNode(emb_node);
     366           0 : }
     367             : 
     368             : bool
     369        5009 : EFAFragment3D::hasFaceWithOneCut() const
     370             : {
     371             :   // N.B. this method can only be implemented when the fragment has just been marked
     372       28158 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     373       23816 :     if (_faces[i]->getNumCuts() == 1)
     374             :       return true;
     375             :   return false;
     376             : }
     377             : 
     378             : void
     379       54780 : EFAFragment3D::getNodeInfo(std::vector<std::vector<unsigned int>> & face_node_indices,
     380             :                            std::vector<EFANode *> & nodes) const
     381             : {
     382             :   // get all nodes' pointers - a vector
     383       54780 :   std::set<EFANode *> all_node_set = getAllNodes();
     384       54780 :   nodes.resize(all_node_set.size());
     385       54780 :   std::copy(all_node_set.begin(), all_node_set.end(), nodes.begin());
     386             : 
     387             :   // get face connectivity
     388       54780 :   face_node_indices.clear();
     389      331001 :   for (unsigned int i = 0; i < _faces.size(); ++i)
     390             :   {
     391             :     std::vector<unsigned int> line_face_indices;
     392     1276171 :     for (unsigned int j = 0; j < _faces[i]->numNodes(); ++j)
     393             :     {
     394      999950 :       EFANode * node = _faces[i]->getNode(j);
     395      999950 :       unsigned int vec_index = std::find(nodes.begin(), nodes.end(), node) - nodes.begin();
     396      999950 :       line_face_indices.push_back(vec_index);
     397             :     }
     398      276221 :     face_node_indices.push_back(line_face_indices);
     399      276221 :   }
     400       54780 : }
     401             : 
     402             : EFAFragment3D *
     403        2424 : EFAFragment3D::connectSubfaces(EFAFace * start_face,
     404             :                                unsigned int startOldFaceID,
     405             :                                std::vector<std::vector<EFAFace *>> & subfaces)
     406             : {
     407             :   // this method is only called in EFAfragment3D::split()
     408        2424 :   std::vector<bool> contributed(subfaces.size(), false);
     409             :   contributed[startOldFaceID] = true;
     410             :   unsigned int num_contrib_faces = 1;
     411             :   unsigned int old_num_contrib = 1;
     412        2424 :   std::vector<EFAFace *> frag_faces(1, start_face);
     413             : 
     414             :   // collect all subfaces connected to start_face
     415             :   do
     416             :   {
     417             :     old_num_contrib = num_contrib_faces;
     418       29156 :     for (unsigned int i = 0; i < subfaces.size(); ++i)
     419             :     {
     420       24296 :       if (!contributed[i]) // old face not contributed to new fragment yet
     421             :       {
     422             :         bool adjacent_found = false;
     423       17928 :         for (unsigned int j = 0; j < subfaces[i].size(); ++j)
     424             :         {
     425       33477 :           for (unsigned int k = 0; k < frag_faces.size(); ++k)
     426             :           {
     427       26929 :             if (subfaces[i][j]->isAdjacent(frag_faces[k]))
     428             :             {
     429             :               adjacent_found = true;
     430             :               contributed[i] = true;
     431        8008 :               frag_faces.push_back(subfaces[i][j]);
     432        8008 :               num_contrib_faces += 1;
     433             :               break;
     434             :             }
     435             :           } // k
     436             :           if (adjacent_found)
     437             :             break;
     438             :         } // j
     439             :       }
     440             :     } // i, loop over all old faces
     441        4860 :   } while (num_contrib_faces != old_num_contrib);
     442             : 
     443             :   // get the cut plane face
     444             :   std::vector<EFAEdge *> cut_plane_edges;
     445        2424 :   EFAFragment3D * new_frag = new EFAFragment3D(_host_elem, false, nullptr);
     446       12856 :   for (unsigned int i = 0; i < frag_faces.size(); ++i)
     447       10432 :     new_frag->addFace(frag_faces[i]);
     448        2424 :   new_frag->findFacesAdjacentToFaces();
     449             : 
     450       12856 :   for (unsigned int i = 0; i < new_frag->numFaces(); ++i)
     451             :   {
     452       10432 :     EFAEdge * lone_edge = new_frag->loneEdgeOnFace(i);
     453       10432 :     if (lone_edge != nullptr) // valid edge
     454        8752 :       cut_plane_edges.push_back(new EFAEdge(*lone_edge));
     455             :   }
     456             : 
     457        2424 :   EFAFace * cut_face = new EFAFace(cut_plane_edges.size());
     458       11176 :   for (unsigned int i = 0; i < cut_plane_edges.size(); ++i)
     459        8752 :     cut_face->setEdge(i, cut_plane_edges[i]);
     460        2424 :   cut_face->sortEdges();
     461        2424 :   cut_face->reverseEdges();
     462        2424 :   cut_face->createNodes();
     463             : 
     464             :   // finalize the new fragment
     465        2424 :   new_frag->addFace(cut_face);
     466        2424 :   new_frag->findFacesAdjacentToFaces();
     467        2424 :   return new_frag;
     468        2424 : }
     469             : 
     470             : EFAEdge *
     471       10432 : EFAFragment3D::loneEdgeOnFace(unsigned int face_id) const
     472             : {
     473             :   // if any face edge is not shared by any other face, we call it a lone edge
     474       34183 :   for (unsigned int i = 0; i < _faces[face_id]->numEdges(); ++i)
     475       32503 :     if (_faces_adjacent_to_faces[face_id][i] == nullptr)
     476        8752 :       return _faces[face_id]->getEdge(i);
     477             :   return nullptr;
     478             : }
     479             : 
     480             : void
     481         264 : EFAFragment3D::combine_two_faces(unsigned int face_id1,
     482             :                                  unsigned int face_id2,
     483             :                                  const EFAFace * elem_face)
     484             : {
     485             :   // get the new full face
     486         264 :   EFAFace * full_face = _faces[face_id1]->combineWithFace(_faces[face_id2]);
     487         264 :   full_face->resetEdgeIntersection(elem_face); // IMPORTANT
     488             : 
     489             :   // take care of the common adjacent faces (combine their tip edges)
     490             :   std::set<EFAFace *> face1_neigh;
     491         264 :   face1_neigh.insert(_faces_adjacent_to_faces[face_id1].begin(),
     492             :                      _faces_adjacent_to_faces[face_id1].end());
     493             :   std::set<EFAFace *> face2_neigh;
     494         264 :   face2_neigh.insert(_faces_adjacent_to_faces[face_id2].begin(),
     495             :                      _faces_adjacent_to_faces[face_id2].end());
     496         264 :   std::vector<EFAFace *> common_adjacent_faces = Efa::getCommonElems(face1_neigh, face2_neigh);
     497             : 
     498         782 :   for (unsigned int i = 0; i < common_adjacent_faces.size(); ++i)
     499             :   {
     500         518 :     EFAFace * comm_face = common_adjacent_faces[i];
     501         518 :     if (comm_face != nullptr)
     502             :     {
     503         508 :       unsigned int edge_id1 = comm_face->adjacentCommonEdge(_faces[face_id1]);
     504         508 :       unsigned int edge_id2 = comm_face->adjacentCommonEdge(_faces[face_id2]);
     505         508 :       comm_face->combineTwoEdges(edge_id1, edge_id2);
     506         508 :       comm_face->resetEdgeIntersection(elem_face); // IMPORTANT
     507             :     }
     508             :   }
     509             : 
     510             :   // delete old faces and update private members of EFAfragment3D
     511         264 :   delete _faces[face_id1];
     512         264 :   delete _faces[face_id2];
     513         264 :   _faces[face_id1] = full_face;
     514         264 :   _faces.erase(_faces.begin() + face_id2);
     515         264 :   findFacesAdjacentToFaces(); // rebuild _adjacent_face_ix: IMPORTANT
     516         528 : }

Generated by: LCOV version 1.14