int NumAssociatedFaces(Grid& grid, Vertex* v) { Grid::face_traits::secure_container faces; grid.associated_elements(faces, v); return (int)faces.size(); }
bool CollapseEdge(Grid& grid, Edge* e, Vertex* newVrt) { // prepare the grid, so that we may perform Grid::replace_vertex. // create collapse geometries first and delete old geometries. Grid::face_traits::secure_container assFaces; if(grid.num_faces() > 0){ // collect adjacent faces grid.associated_elements(assFaces, e); // a vector thats is used to store the collapse-geometries. vector<Face*> vNewFaces; for(uint i = 0; i < assFaces.size(); ++i) { Face* f = assFaces[i]; int eInd = GetEdgeIndex(f, e); // create the collapse-geometry f->collapse_edge(vNewFaces, eInd, newVrt); // register the new faces for(uint j = 0; j < vNewFaces.size(); ++j) grid.register_element(vNewFaces[j], f); // before we erase the face, we first have to notify whether // edges were merged if(f->num_edges() == 3){ // two edges will be merged. we have to inform the grid. Vertex* conVrt = GetConnectedVertex(e, f); // now get the edge between conVrt and newVrt Edge* target = grid.get_edge(conVrt, newVrt); // now get the two old edges Edge* e1 = grid.get_edge(f, (eInd + 1) % 3); Edge* e2 = grid.get_edge(f, (eInd + 2) % 3); grid.objects_will_be_merged(target, e1, e2); } } } Grid::volume_traits::secure_container assVols; if(grid.num_volumes() > 0){ // used to identify merge-faces Grid::edge_traits::secure_container assEdges; // collect adjacent volumes grid.associated_elements(assVols, e); // a vector thats used to store the collapse-geometries. vector<Volume*> vNewVolumes; for(uint i = 0; i < assVols.size(); ++i) { Volume* v = assVols[i]; // create the collapse-geometry int eInd = GetEdgeIndex(v, e); v->collapse_edge(vNewVolumes, eInd, newVrt); // register the new volumes for(uint j = 0; j < vNewVolumes.size(); ++j) grid.register_element(vNewVolumes[j], v); // if v is a tetrahedron, two faces will be merged if(v->num_vertices() == 4){ // find the opposing edge of e Edge* oppEdge = NULL; grid.associated_elements(assEdges, v); for_each_in_vec(Edge* te, assEdges){ if(!GetSharedVertex(e, te)){ oppEdge = te; break; } }end_for; if(oppEdge){ Face* f0 = grid.get_face(FaceDescriptor( e->vertex(0), oppEdge->vertex(0), oppEdge->vertex(1))); Face* f1 = grid.get_face(FaceDescriptor( e->vertex(1), oppEdge->vertex(0), oppEdge->vertex(1))); Face* fNew = grid.get_face(FaceDescriptor( newVrt, oppEdge->vertex(0), oppEdge->vertex(1))); if(f0 && f1 && fNew) grid.objects_will_be_merged(fNew, f0, f1); } } }
void AdaptiveRegularRefiner_MultiGrid:: create_closure_elements_2d() { //todo: This method currently only works for one type of elements. No manifolds // are currently supported. // for each surface element (faces in 2d, volumes in 3d) adjacent to a constraining // element, we generate closure elements in the level above. if(!multi_grid()){ UG_THROW("AdaptiveRegularRefiner_MultiGrid has to be associated with a grid!"); } // remove all closure elements. This is currently required, since the selector // m_closureElems is currently also used to store non-closer elements, which are // to be refined. remove_closure_elements(); MultiGrid& mg = *multi_grid(); // iterate over all constraining edges and collect associated surface faces // Those then have to be refined to generate a closure. Grid::face_traits::secure_container assElems; Grid::edge_traits::secure_container assEdges; Face::ConstVertexArray vrts; std::vector<Vertex*> newVrtVrts; std::vector<Vertex*> newEdgeVrts; std::vector<Face*> newFaces; EdgeDescriptor ed; // we'll select all new elements on the fly m_closureElems.enable_autoselection(true); for(Grid::traits<ConstrainingEdge>::iterator i_edge = mg.begin<ConstrainingEdge>(); i_edge != mg.end<ConstrainingEdge>(); ++i_edge) { // check all associated elements of i_edge, whether one is a surface element. // If so, create the closure. mg.associated_elements(assElems, *i_edge); for(size_t i_elem = 0; i_elem < assElems.size(); ++i_elem){ Face* elem = assElems[i_elem]; if(mg.has_children(elem)) continue; newVrtVrts.clear(); newEdgeVrts.clear(); // copy associated vertices and edges to the next level vrts = elem->vertices(); size_t numVrts = elem->num_vertices(); for(size_t i_vrt = 0; i_vrt < numVrts; ++i_vrt){ Vertex* vrt = vrts[i_vrt]; if(!mg.has_children(vrt)){ newVrtVrts.push_back(*mg.create<RegularVertex>(vrt)); if(m_refCallback) m_refCallback->new_vertex(newVrtVrts.back(), vrt); } else newVrtVrts.push_back(mg.get_child_vertex(vrt)); } mg.associated_elements_sorted(assEdges, elem); for(size_t i = 0; i < assEdges.size(); ++i){ Edge* e = assEdges[i]; if(!mg.has_children(e)){ ed.set_vertices(mg.get_child_vertex(e->vertex(0)), mg.get_child_vertex(e->vertex(1))); mg.create<RegularEdge>(ed, e); newEdgeVrts.push_back(NULL); } else newEdgeVrts.push_back(mg.get_child_vertex(e)); } // refine the element Vertex* newFaceVrt; if(elem->refine(newFaces, &newFaceVrt, &newEdgeVrts.front(), NULL, &newVrtVrts.front())) { if(newFaceVrt){ mg.register_element(newFaceVrt, elem); if(m_refCallback) m_refCallback->new_vertex(newFaceVrt, elem); } for(size_t i = 0; i < newFaces.size(); ++i) mg.register_element(newFaces[i], elem); } } } // stop selecting new elements m_closureElems.enable_autoselection(false); }
void AdaptiveRegularRefiner_MultiGrid:: create_closure_elements_3d() { //todo: This method currently only works for one type of elements. No manifolds // are currently supported. // for each surface element (faces in 2d, volumes in 3d) adjacent to a constraining // element, we generate closure elements in the level above. if(!multi_grid()){ UG_THROW("AdaptiveRegularRefiner_MultiGrid has to be associated with a grid!"); } // remove all closure elements. This is currently required, since the selector // m_closureElems is currently also used to store non-closer elements, which are // to be refined. remove_closure_elements(); MultiGrid& mg = *multi_grid(); // iterate over all constraining edges and collect associated surface faces / volumes. // Those then have to be refined to generate a closure. Grid::volume_traits::secure_container assElems; Grid::edge_traits::secure_container assEdges; Grid::face_traits::secure_container assFaces; Volume::ConstVertexArray vrts; std::vector<Vertex*> newVolVrtVrts; std::vector<Vertex*> newVolEdgeVrts; std::vector<Vertex*> newVolFaceVrts; std::vector<Volume*> newVols; EdgeDescriptor ed; FaceDescriptor fd; // when refining the associated faces, we need some structs, too Grid::edge_traits::secure_container assFaceEdges; std::vector<Vertex*> newFaceVrtVrts; std::vector<Vertex*> newFaceEdgeVrts; std::vector<Face*> newFaces; // we'll select all new elements on the fly m_closureElems.enable_autoselection(true); for(Grid::traits<ConstrainingEdge>::iterator i_edge = mg.begin<ConstrainingEdge>(); i_edge != mg.end<ConstrainingEdge>(); ++i_edge) { // check all associated elements of i_edge, whether one is a surface element. // If so, select it into m_closureElems. This is only temporary, since it // isn't a real closure element. mg.associated_elements(assElems, *i_edge); for(size_t i_elem = 0; i_elem < assElems.size(); ++i_elem){ Volume* elem = assElems[i_elem]; if(mg.has_children(elem)) continue; newVolVrtVrts.clear(); newVolEdgeVrts.clear(); newVolFaceVrts.clear(); // copy associated vertices and edges to the next level vrts = elem->vertices(); size_t numVrts = elem->num_vertices(); for(size_t i_vrt = 0; i_vrt < numVrts; ++i_vrt){ Vertex* vrt = vrts[i_vrt]; if(!mg.has_children(vrt)){ newVolVrtVrts.push_back(*mg.create<RegularVertex>(vrt)); if(m_refCallback) m_refCallback->new_vertex(newVolVrtVrts.back(), vrt); } else newVolVrtVrts.push_back(mg.get_child_vertex(vrt)); } mg.associated_elements_sorted(assEdges, elem); for(size_t i = 0; i < assEdges.size(); ++i){ Edge* e = assEdges[i]; if(!mg.has_children(e)){ ed.set_vertices(mg.get_child_vertex(e->vertex(0)), mg.get_child_vertex(e->vertex(1))); mg.create<RegularEdge>(ed, e); newVolEdgeVrts.push_back(NULL); } else newVolEdgeVrts.push_back(mg.get_child_vertex(e)); } // we have to either refine or copy associated faces mg.associated_elements_sorted(assFaces, elem); for(size_t i_face = 0; i_face < assFaces.size(); ++i_face){ Face* f = assFaces[i_face]; if(mg.has_children(f)){ newVolFaceVrts.push_back(mg.get_child_vertex(f)); continue; } // collect child vertices of associated edges mg.associated_elements_sorted(assFaceEdges, f); newFaceEdgeVrts.clear(); bool faceRefinement = false; for(size_t i = 0; i < assFaceEdges.size(); ++i){ Vertex* child = mg.get_child_vertex(assFaceEdges[i]); newFaceEdgeVrts.push_back(child); faceRefinement |= (child != NULL); } if(faceRefinement){ newFaceVrtVrts.clear(); for(size_t i = 0; i < f->num_vertices(); ++i) newFaceVrtVrts.push_back(mg.get_child_vertex(f->vertex(i))); Vertex* newFaceVrt = NULL; if(f->refine(newFaces, &newFaceVrt, &newFaceEdgeVrts.front(), NULL, &newFaceVrtVrts.front())) { if(newFaceVrt){ mg.register_element(newFaceVrt, f); if(m_refCallback) m_refCallback->new_vertex(newFaceVrt, f); } for(size_t i = 0; i < newFaces.size(); ++i) mg.register_element(newFaces[i], f); } newVolFaceVrts.push_back(newFaceVrt); } else{ Face::ConstVertexArray fvrts = f->vertices(); if(f->num_vertices() == 3) mg.create<Triangle>(TriangleDescriptor( mg.get_child_vertex(fvrts[0]), mg.get_child_vertex(fvrts[1]), mg.get_child_vertex(fvrts[2])), f); else if(f->num_vertices() == 4) mg.create<Quadrilateral>(QuadrilateralDescriptor( mg.get_child_vertex(fvrts[0]), mg.get_child_vertex(fvrts[1]), mg.get_child_vertex(fvrts[2]), mg.get_child_vertex(fvrts[3])), f); newVolFaceVrts.push_back(NULL); } } // refine the element // if we're performing tetrahedral refinement, we have to collect // the corner coordinates, so that the refinement algorithm may choose // the best interior diagonal. vector3 corners[4]; vector3* pCorners = NULL; if((elem->num_vertices() == 4) && m_refCallback){ for(size_t i = 0; i < 4; ++i){ m_refCallback->current_pos(&corners[i].x(), vrts[i], 3); } pCorners = corners; } Vertex* newVolVrt; if(elem->refine(newVols, &newVolVrt, &newVolEdgeVrts.front(), &newVolFaceVrts.front(), NULL, RegularVertex(), &newVolVrtVrts.front(), pCorners)) { if(newVolVrt){ mg.register_element(newVolVrt, elem); if(m_refCallback) m_refCallback->new_vertex(newVolVrt, elem); } for(size_t i = 0; i < newVols.size(); ++i) mg.register_element(newVols[i], elem); } } } // stop selecting new elements m_closureElems.enable_autoselection(false); }
bool AdaptSurfaceGridToCylinder(Selector& selOut, Grid& grid, Vertex* vrtCenter, const vector3& normal, number radius, number rimSnapThreshold, AInt& aInt, APosition& aPos) { if(!grid.has_vertex_attachment(aPos)) { UG_THROW("Position attachment required!"); } Grid::VertexAttachmentAccessor<APosition> aaPos(grid, aPos); if(rimSnapThreshold < 0) rimSnapThreshold = 0; if(rimSnapThreshold > (radius - SMALL)) rimSnapThreshold = radius - SMALL; const number smallRadius = radius - rimSnapThreshold; const number smallRadiusSq = smallRadius * smallRadius; const number largeRadius = radius + rimSnapThreshold; const number largeRadiusSq = largeRadius * largeRadius; // the cylinder geometry vector3 axis; VecNormalize(axis, normal); vector3 center = aaPos[vrtCenter]; // recursively select all vertices in the cylinder which can be reached from a // selected vertex by following an edge. Start with the given one. // We'll also select edges which connect inner with outer vertices. Note that // some vertices are considered rim-vertices (those with a distance between // smallRadius and largeRadius). Those are neither considered inner nor outer. Selector& sel = selOut; sel.clear(); sel.select(vrtCenter); stack<Vertex*> vrtStack; vrtStack.push(vrtCenter); Grid::edge_traits::secure_container edges; Grid::face_traits::secure_container faces; vector<Quadrilateral*> quads; while(!vrtStack.empty()) { Vertex* curVrt = vrtStack.top(); vrtStack.pop(); // we have to convert associated quadrilaterals to triangles. // Be careful not to alter the array of associated elements while we iterate // over it... quads.clear(); grid.associated_elements(faces, curVrt); for(size_t i = 0; i < faces.size(); ++i) { if(faces[i]->num_vertices() == 4) { Quadrilateral* q = dynamic_cast<Quadrilateral*>(faces[i]); if(q) quads.push_back(q); } } for(size_t i = 0; i < quads.size(); ++i) { Triangulate(grid, quads[i], &aaPos); } // now check whether edges leave the cylinder and mark them accordingly. // Perform projection of vertices to the cylinder rim for vertices which // lie in the threshold area. grid.associated_elements(edges, curVrt); for(size_t i_edge = 0; i_edge < edges.size(); ++i_edge) { Edge* e = edges[i_edge]; Vertex* vrt = GetConnectedVertex(e, curVrt); if(sel.is_selected(vrt)) continue; vector3 p = aaPos[vrt]; vector3 proj; ProjectPointToRay(proj, p, center, axis); number distSq = VecDistanceSq(p, proj); if(distSq < smallRadiusSq) { sel.select(vrt); vrtStack.push(vrt); } else if(distSq < largeRadiusSq) { sel.select(vrt); // cut the ray from center through p with the cylinder hull to calculate // the new position of vrt. vector3 dir; VecSubtract(dir, p, center); number t0, t1; if(RayCylinderIntersection(t0, t1, center, dir, center, axis, radius)) VecScaleAdd(aaPos[vrt], 1., center, t1, dir); } else { // the edge will be refined later on sel.select(e); } } } // refine selected edges and use a special refinement callback, which places // new vertices on edges which intersect a cylinder on the cylinders hull. CylinderCutProjector refCallback(MakeGeometry3d(grid, aPos), center, axis, radius); Refine(grid, sel, aInt, &refCallback); // finally select all triangles which lie in the cylinder sel.clear(); vrtStack.push(vrtCenter); sel.select(vrtCenter); while(!vrtStack.empty()) { Vertex* curVrt = vrtStack.top(); vrtStack.pop(); grid.associated_elements(faces, curVrt); for(size_t i_face = 0; i_face < faces.size(); ++i_face) { Face* f = faces[i_face]; if(sel.is_selected(f)) continue; sel.select(f); for(size_t i = 0; i < f->num_vertices(); ++i) { Vertex* vrt = f->vertex(i); if(!sel.is_selected(vrt)) { number dist = DistancePointToRay(aaPos[vrt], center, axis); if(dist < (radius - SMALL)) { sel.select(vrt); vrtStack.push(vrt); } } } } } sel.clear<Vertex>(); return true; }