int NumAssociatedEdges(Grid& grid, Vertex* v) { Grid::edge_traits::secure_container edges; grid.associated_elements(edges, v); return (int)edges.size(); }
void SelectShortPolychains(ISelector& sel, number maxLength, bool closedChainsOnly, TAAPos aaPos) { if(!sel.grid()) return; Grid& grid = *sel.grid(); // we'll collect all contained short polychains in this vector before deciding // to select them or not. If a polychain is already longer than maxLength // we won't add its edges to the vector std::vector<Edge*> curChain; std::queue<Edge*> nextEdges; Grid::edge_traits::secure_container edges; std::vector<Vertex*> junctionPoints; grid.begin_marking(); for(EdgeIterator eiter = grid.begin<Edge>(); eiter != grid.end<Edge>(); ++eiter){ if(grid.is_marked(*eiter)) continue; bool curChainIsClosed = true; number curChainLength = 0; curChain.clear(); junctionPoints.clear(); nextEdges.push(*eiter); grid.mark(*eiter); while(!nextEdges.empty()){ Edge* e = nextEdges.front(); nextEdges.pop(); curChainLength += EdgeLength(e, aaPos); if(curChainLength <= maxLength) curChain.push_back(e); for(size_t ivrt = 0; ivrt < 2; ++ivrt){ Vertex* vrt = e->vertex(ivrt); grid.associated_elements(edges, vrt); if(edges.size() < 2) curChainIsClosed = false; else if(edges.size() == 2){ for(size_t iedge = 0; iedge < 2; ++iedge){ Edge* nextEdge = edges[iedge]; if(!grid.is_marked(nextEdge)){ grid.mark(nextEdge); nextEdges.push(nextEdge); } } } else{ junctionPoints.push_back(vrt); } } } if((curChainLength <= maxLength)){ if(closedChainsOnly && curChainIsClosed && !junctionPoints.empty()){ // count the number of associated edges of each junction-point // in curChain. If one is associated with != 2 vertices the chain // is considered as not closed for(size_t ivrt = 0; ivrt < junctionPoints.size(); ++ivrt){ Vertex* vrt = junctionPoints[ivrt]; size_t numConnectedEdges = 0; for(size_t iedge = 0; iedge < curChain.size(); ++iedge){ if(EdgeContains(curChain[iedge], vrt)) ++numConnectedEdges; } if(numConnectedEdges != 2){ curChainIsClosed = false; break; } } } if(curChainIsClosed || !closedChainsOnly) sel.select(curChain.begin(), curChain.end()); } } grid.end_marking(); }
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; }