EFAFragment3D::EFAFragment3D(EFAElement3D * host, bool create_faces, const EFAElement3D * from_host, unsigned int frag_id) : EFAFragment(), _host_elem(host) { if (create_faces) { if (!from_host) EFAError("EFAfragment3D constructor must have a from_host to copy from"); if (frag_id == std::numeric_limits<unsigned int>::max()) // copy the from_host itself { for (unsigned int i = 0; i < from_host->numFaces(); ++i) _faces.push_back(new EFAFace(*from_host->getFace(i))); } else { if (frag_id > from_host->numFragments() - 1) EFAError("In EFAfragment3D constructor fragment_copy_index out of bounds"); for (unsigned int i = 0; i < from_host->getFragment(frag_id)->numFaces(); ++i) _faces.push_back(new EFAFace(*from_host->getFragmentFace(frag_id, i))); } findFacesAdjacentToFaces(); // IMPORTANT } }
void ElementFragmentAlgorithm::addElemEdgeIntersection(unsigned int elemid, unsigned int edgeid, double position) { // this method is called when we are marking cut edges std::map<unsigned int, EFAElement *>::iterator eit = _elements.find(elemid); if (eit == _elements.end()) EFAError("Could not find element with id: ", elemid, " in addEdgeIntersection"); EFAElement2D * curr_elem = dynamic_cast<EFAElement2D *>(eit->second); if (!curr_elem) EFAError("addElemEdgeIntersection: elem ", elemid, " is not of type EFAelement2D"); curr_elem->addEdgeCut(edgeid, position, NULL, _embedded_nodes, true); }
bool ElementFragmentAlgorithm::addFragEdgeIntersection(unsigned int elemid, unsigned int frag_edge_id, double position) { // N.B. this method must be called after addEdgeIntersection std::map<unsigned int, EFAElement *>::iterator eit = _elements.find(elemid); if (eit == _elements.end()) EFAError("Could not find element with id: ", elemid, " in addFragEdgeIntersection"); EFAElement2D * elem = dynamic_cast<EFAElement2D *>(eit->second); if (!elem) EFAError("addFragEdgeIntersection: elem ", elemid, " is not of type EFAelement2D"); return elem->addFragmentEdgeCut(frag_edge_id, position, _embedded_nodes); }
EFANode * EFAElement::getGlobalNodeFromLocalNode(const EFANode * local_node) const { //Given a local node, find the global node corresponding to that node if (local_node->category() != EFANode::N_CATEGORY_LOCAL_INDEX) EFAError("In getGlobalNodeFromLocalNode node passed in is not local"); EFANode * global_node = _nodes[local_node->id()]; if (global_node->category() != EFANode::N_CATEGORY_PERMANENT && global_node->category() != EFANode::N_CATEGORY_TEMP) EFAError("In getGlobalNodeFromLocalNode, the node stored by the element is not global"); return global_node; }
EFAFace * EFAFragment3D::getFace(unsigned int face_id) const { if (face_id > _faces.size() - 1) EFAError("in EFAfragment3D::get_face, index out of bounds"); return _faces[face_id]; }
EFAElement * ElementFragmentAlgorithm::add2DElement(std::vector<unsigned int> quad, unsigned int id) { unsigned int num_nodes = quad.size(); std::map<unsigned int, EFAElement *>::iterator mit = _elements.find(id); if (mit != _elements.end()) EFAError("In add2DElement element with id: ", id, " already exists"); EFAElement2D * newElem = new EFAElement2D(id, num_nodes); _elements.insert(std::make_pair(id, newElem)); for (unsigned int j = 0; j < num_nodes; ++j) { EFANode * currNode = NULL; std::map<unsigned int, EFANode *>::iterator mit = _permanent_nodes.find(quad[j]); if (mit == _permanent_nodes.end()) { currNode = new EFANode(quad[j], EFANode::N_CATEGORY_PERMANENT); _permanent_nodes.insert(std::make_pair(quad[j], currNode)); } else currNode = mit->second; newElem->setNode(j, currNode); _inverse_connectivity[currNode].insert(newElem); } newElem->createEdges(); return newElem; }
EFAElement * ElementFragmentAlgorithm::getElemByID(unsigned int id) { std::map<unsigned int, EFAElement *>::iterator mit = _elements.find(id); if (mit == _elements.end()) EFAError("in getElemByID() could not find element: ", id); return mit->second; }
EFAElement* EFAElement::getChild(unsigned int child_id) const { if (child_id < _children.size()) return _children[child_id]; else EFAError("child_id out of bounds"); }
unsigned int EFAElement::getCrackTipNeighbor(unsigned int index) const { if (index < _crack_tip_neighbors.size()) return _crack_tip_neighbors[index]; else EFAError("in getCrackTipNeighbor index out of bounds"); }
unsigned int EFAFragment3D::getFaceID(EFAFace * face) const { for (unsigned int i = 0; i < _faces.size(); ++i) if (_faces[i] == face) return i; EFAError("face not found in get_face_id()"); return 99999; }
void ElementFragmentAlgorithm::addElemFaceIntersection(unsigned int elemid, unsigned int faceid, std::vector<unsigned int> edgeid, std::vector<double> position) { // this method is called when we are marking cut edges std::map<unsigned int, EFAElement *>::iterator eit = _elements.find(elemid); if (eit == _elements.end()) EFAError("Could not find element with id: ", elemid, " in addEdgeIntersection"); EFAElement3D * curr_elem = dynamic_cast<EFAElement3D *>(eit->second); if (!curr_elem) EFAError("addElemEdgeIntersection: elem ", elemid, " is not of type EFAelement2D"); // add cuts to two face edges at the same time curr_elem->addFaceEdgeCut(faceid, edgeid[0], position[0], NULL, _embedded_nodes, true, true); curr_elem->addFaceEdgeCut(faceid, edgeid[1], position[1], NULL, _embedded_nodes, true, true); }
void EFAFragment3D::removeInvalidEmbeddedNodes(std::map<unsigned int, EFANode *> & EmbeddedNodes) { // N.B. this method is only called before we update fragments // N.B. an embedded node is valid IF at least one of its host faces is exterior and has more than // 1 cuts // TODO: the invalid cases are generalized from 2D. The method may need improvements in 3D if (hasFaceWithOneCut()) { // build a local inverse map for all emb cut nodes in this fragment std::map<EFANode *, std::vector<EFAFace *>> emb_inverse_map; for (unsigned int i = 0; i < _faces.size(); ++i) { for (unsigned int j = 0; j < _faces[i]->numEdges(); ++j) { if (_faces[i]->getEdge(j)->hasIntersection()) { EFANode * emb_node = _faces[i]->getEdge(j)->getEmbeddedNode(0); emb_inverse_map[emb_node].push_back(_faces[i]); } } // i } // j // find all invalid embedded nodes std::vector<EFANode *> invalid_emb; std::map<EFANode *, std::vector<EFAFace *>>::iterator it; for (it = emb_inverse_map.begin(); it != emb_inverse_map.end(); ++it) { EFANode * emb_node = it->first; std::vector<EFAFace *> & emb_faces = it->second; if (emb_faces.size() != 2) EFAError("one embedded node must be owned by 2 faces"); unsigned int counter = 0; for (unsigned int i = 0; i < emb_faces.size(); ++i) { unsigned int face_id = getFaceID(emb_faces[i]); if (!isFaceInterior(face_id) && emb_faces[i]->hasIntersection()) counter += 1; // count the appropriate emb's faces } if (counter == 0) invalid_emb.push_back(emb_node); } // delete all invalid emb nodes for (unsigned int i = 0; i < invalid_emb.size(); ++i) { Efa::deleteFromMap(EmbeddedNodes, invalid_emb[i]); _host_elem->removeEmbeddedNode(invalid_emb[i], true); // also remove from neighbors } // i } }
EFANode * EFAElement::createLocalNodeFromGlobalNode(const EFANode * global_node) const { //Given a global node, create a new local node if (global_node->category() != EFANode::N_CATEGORY_PERMANENT && global_node->category() != EFANode::N_CATEGORY_TEMP) EFAError("In createLocalNodeFromGlobalNode node is not global"); EFANode * new_local_node = NULL; unsigned int inode = 0; for (; inode < _nodes.size(); ++inode) { if (_nodes[inode] == global_node) { new_local_node = new EFANode(inode, EFANode::N_CATEGORY_LOCAL_INDEX); break; } } if (!new_local_node) EFAError("In createLocalNodeFromGlobalNode could not find global node"); return new_local_node; }
bool EFAFragment3D::isThirdInteriorFace(unsigned int face_id) const { bool is_third_cut = false; if (!_host_elem) EFAError("in isThirdInteriorFace fragment must have host elem"); for (unsigned int i = 0; i < _host_elem->numInteriorNodes(); ++i) { if (_faces[face_id]->containsNode(_host_elem->getInteriorNode(i)->getNode())) { is_third_cut = true; break; } } return is_third_cut; }
unsigned int EFAElement::getLocalNodeIndex(EFANode * node) const { unsigned int local_node_id = 99999; bool found_local_node = false; for (unsigned int i = 0; i < _num_nodes; ++i) { if (_nodes[i] == node) { found_local_node = true; local_node_id = i; break; } } if (!found_local_node) EFAError("In EFAelement::getLocalNodeIndex, cannot find the given node"); return local_node_id; }
void EFAFragment3D::combine_tip_faces() { if (!_host_elem) EFAError("In combine_tip_faces() the frag must have host_elem"); for (unsigned int i = 0; i < _host_elem->numFaces(); ++i) { std::vector<unsigned int> frag_tip_face_id; for (unsigned int j = 0; j < _faces.size(); ++j) { if (_host_elem->getFace(i)->containsFace(_faces[j])) frag_tip_face_id.push_back(j); } if (frag_tip_face_id.size() == 2) // combine the two frag faces on this elem face combine_two_faces(frag_tip_face_id[0], frag_tip_face_id[1], _host_elem->getFace(i)); } // TODO: may need to combine other frag faces that have tip edges }
void ElementFragmentAlgorithm::clearAncestry() { _inverse_connectivity.clear(); for (unsigned int i = 0; i < _parent_elements.size(); ++i) { if (!Efa::deleteFromMap(_elements, _parent_elements[i])) EFAError("Attempted to delete parent element: ", _parent_elements[i]->id(), " from _elements, but couldn't find it"); } _parent_elements.clear(); std::map<unsigned int, EFAElement *>::iterator eit; for (eit = _elements.begin(); eit != _elements.end(); ++eit) { EFAElement * curr_elem = eit->second; curr_elem->clearParentAndChildren(); for (unsigned int j = 0; j < curr_elem->numNodes(); j++) { EFANode * curr_node = curr_elem->getNode(j); _inverse_connectivity[curr_node].insert(curr_elem); } } std::map<unsigned int, EFANode *>::iterator mit; for (mit = _permanent_nodes.begin(); mit != _permanent_nodes.end(); ++mit) mit->second->removeParent(); for (mit = _temp_nodes.begin(); mit != _temp_nodes.end(); ++mit) { delete mit->second; mit->second = NULL; } _temp_nodes.clear(); _new_nodes.clear(); _child_elements.clear(); // TODO: Sanity check to make sure that there are no nodes that are not connected // to an element -- there shouldn't be any }
bool EFAFragment3D::isFaceInterior(unsigned int face_id) const { if (!_host_elem) EFAError("in isFaceInterior() fragment must have host elem"); bool face_in_elem_face = false; for (unsigned int i = 0; i < _host_elem->numFaces(); ++i) { if (_host_elem->getFace(i)->containsFace(_faces[face_id])) { face_in_elem_face = true; break; } } if (!face_in_elem_face) return true; // yes, is interior else return false; }
void ElementFragmentAlgorithm::clearPotentialIsolatedNodes() { // Collect all parent nodes that will be isolated std::map<EFANode *, std::vector<EFANode *>> isolate_parent_to_child; for (unsigned int i = 0; i < _new_nodes.size(); ++i) { EFANode * parent_node = _new_nodes[i]->parent(); if (!parent_node) EFAError("a new permanent node must have a parent node!"); bool isParentNodeInNewElem = false; for (unsigned int j = 0; j < _child_elements.size(); ++j) { if (_child_elements[j]->containsNode(parent_node)) { isParentNodeInNewElem = true; break; } } if (!isParentNodeInNewElem) isolate_parent_to_child[parent_node].push_back(_new_nodes[i]); } // For each isolated parent node, pick one of its child new node // Then, switch that child with its parent for all new elems std::map<EFANode *, std::vector<EFANode *>>::iterator mit; for (mit = isolate_parent_to_child.begin(); mit != isolate_parent_to_child.end(); ++mit) { EFANode * parent_node = mit->first; EFANode * child_node = (mit->second)[0]; // need to discard it and swap it back to its parent for (unsigned int i = 0; i < _child_elements.size(); ++i) { if (_child_elements[i]->containsNode(child_node)) _child_elements[i]->switchNode(parent_node, child_node, true); } _new_nodes.erase(std::remove(_new_nodes.begin(), _new_nodes.end(), child_node), _new_nodes.end()); Efa::deleteFromMap(_permanent_nodes, child_node); } }
bool EFAFragment3D::isConnected(EFAFragment* other_fragment) const { bool is_connected = false; EFAFragment3D* other_frag3d = dynamic_cast<EFAFragment3D*>(other_fragment); if (!other_frag3d) EFAError("in isConnected other_fragment is not of type EFAfragement3D"); for (unsigned int i = 0; i < _faces.size(); ++i) { for (unsigned int j = 0; j < other_frag3d->numFaces(); ++j) { if (_faces[i]->equivalent(other_frag3d->_faces[j])) { is_connected = true; break; } } if (is_connected) break; } // i return is_connected; }
unsigned int ElementFragmentAlgorithm::add2DElements(std::vector<std::vector<unsigned int>> & quads) { unsigned int first_id = 0; unsigned int num_nodes = quads[0].size(); if (quads.size() == 0) EFAError("add2DElements called with empty vector of quads"); for (unsigned int i = 0; i < quads.size(); ++i) { unsigned int new_elem_id = Efa::getNewID(_elements); EFAElement2D * newElem = new EFAElement2D(new_elem_id, num_nodes); _elements.insert(std::make_pair(new_elem_id, newElem)); if (i == 0) first_id = new_elem_id; for (unsigned int j = 0; j < num_nodes; ++j) { EFANode * currNode = NULL; std::map<unsigned int, EFANode *>::iterator mit = _permanent_nodes.find(quads[i][j]); if (mit == _permanent_nodes.end()) { currNode = new EFANode(quads[i][j], EFANode::N_CATEGORY_PERMANENT); _permanent_nodes.insert(std::make_pair(quads[i][j], currNode)); } else currNode = mit->second; newElem->setNode(j, currNode); _inverse_connectivity[currNode].insert(newElem); } newElem->createEdges(); } return first_id; }
void EFAElement::mergeNodes(EFANode* &childNode, EFANode* &childOfNeighborNode, EFAElement* childOfNeighborElem, std::map<unsigned int, EFANode*> &PermanentNodes, std::map<unsigned int, EFANode*> &TempNodes) { // Important: this must be run only on child elements that were just created if (!_parent) EFAError("no getParent element for child element " << _id << " in mergeNodes"); EFAElement* childElem = this; if (childNode != childOfNeighborNode) { if (childNode->category() == EFANode::N_CATEGORY_PERMANENT) { if (childOfNeighborNode->category() == EFANode::N_CATEGORY_PERMANENT) { if (childOfNeighborNode->parent() == childNode) // merge into childNode { childOfNeighborElem->switchNode(childNode, childOfNeighborNode, true); if (!Efa::deleteFromMap(PermanentNodes, childOfNeighborNode)) { EFAError("Attempted to delete node: " << childOfNeighborNode->id() << " from PermanentNodes, but couldn't find it"); } childOfNeighborNode = childNode; } else if (childNode->parent() == childOfNeighborNode) // merge into childOfNeighborNode { childElem->switchNode(childOfNeighborNode, childNode, true); if (!Efa::deleteFromMap(PermanentNodes, childNode)) { EFAError("Attempted to delete node: " << childNode->id() << " from PermanentNodes, but couldn't find it"); } childNode = childOfNeighborNode; } else if (childNode->parent() != NULL && childNode->parent() == childOfNeighborNode->parent()) { // merge into childNode if both nodes are child permanent childOfNeighborElem->switchNode(childNode, childOfNeighborNode, true); if (!Efa::deleteFromMap(PermanentNodes, childOfNeighborNode)) // delete childOfNeighborNode { EFAError("Attempted to delete node: " << childOfNeighborNode->id() << " from PermanentNodes, but couldn't find it"); } childOfNeighborNode = childNode; } else { EFAError("Attempting to merge nodes: " << childNode->id() << " and " << childOfNeighborNode->id() << " but both are permanent themselves"); } } else { if (childOfNeighborNode->parent() != childNode && childOfNeighborNode->parent() != childNode->parent()) { EFAError("Attempting to merge nodes " << childOfNeighborNode->idCatString() << " and " << childNode->idCatString() << " but neither the 2nd node nor its parent is parent of the 1st"); } childOfNeighborElem->switchNode(childNode, childOfNeighborNode, true); if (!Efa::deleteFromMap(TempNodes, childOfNeighborNode)) EFAError("Attempted to delete node: " << childOfNeighborNode->id() << " from TempNodes, but couldn't find it"); childOfNeighborNode = childNode; } } else if (childOfNeighborNode->category() == EFANode::N_CATEGORY_PERMANENT) { if (childNode->parent() != childOfNeighborNode && childNode->parent() != childOfNeighborNode->parent()) { EFAError("Attempting to merge nodes " << childNode->id() << " and " << childOfNeighborNode->id() << " but neither the 2nd node nor its parent is parent of the 1st"); } childElem->switchNode(childOfNeighborNode, childNode, true); if (!Efa::deleteFromMap(TempNodes, childNode)) EFAError("Attempted to delete node: " << childNode->id() << " from TempNodes, but couldn't find it"); childNode = childOfNeighborNode; } else //both nodes are temporary -- create new permanent node and delete temporary nodes { unsigned int new_node_id = Efa::getNewID(PermanentNodes); EFANode* newNode = new EFANode(new_node_id,EFANode::N_CATEGORY_PERMANENT,childNode->parent()); PermanentNodes.insert(std::make_pair(new_node_id,newNode)); childOfNeighborElem->switchNode(newNode, childOfNeighborNode, true); childElem->switchNode(newNode, childNode, true); if (childNode->parent() != childOfNeighborNode->parent()) { EFAError("Attempting to merge nodes " << childNode->id() << " and " << childOfNeighborNode->id() << " but they don't share a common parent"); } if (!Efa::deleteFromMap(TempNodes, childOfNeighborNode)) EFAError("Attempted to delete node: " << childOfNeighborNode->id() << " from TempNodes, but couldn't find it"); if (!Efa::deleteFromMap(TempNodes, childNode)) EFAError("Attempted to delete node: " << childNode->id() << " from TempNodes, but couldn't find it"); childOfNeighborNode = newNode; childNode = newNode; } } }