void MinimizeEdgeLength_SwapsOnly(Grid& grid, EdgeIterator edgesBegin, EdgeIterator edgesEnd, TAAPos& aaPos) { using namespace std; // helper to collect neighbors Face* nbrFaces[2]; vector<Edge*> edges; // flipCandidates queue<Edge*> candidates; // sadly we can't use marking. Thats why we attach a simple byte to the edges, // which will tell whether an edge is already a candidate. AByte aIsCandidate; grid.attach_to_edges_dv(aIsCandidate, 0, false); Grid::AttachmentAccessor<Edge, AByte> aaIsCandidate(grid, aIsCandidate); // set up candidate array for(EdgeIterator iter = edgesBegin; iter != edgesEnd; ++iter){ aaIsCandidate[*iter] = 1; candidates.push(*iter); } while(!candidates.empty()){ Edge* e = candidates.front(); candidates.pop(); aaIsCandidate[e] = 0; // we only perform swaps on regular manifolds. if(GetAssociatedFaces(nbrFaces, grid, e, 2) == 2){ // make sure that both neighbors are triangles if(nbrFaces[0]->num_vertices() != 3 || nbrFaces[1]->num_vertices() != 3) continue; // check whether a swap would make the edge shorter. Vertex* conVrt0 = GetConnectedVertex(e, nbrFaces[0]); Vertex* conVrt1 = GetConnectedVertex(e, nbrFaces[1]); if(VertexDistanceSq(conVrt0, conVrt1, aaPos) < EdgeLengthSq(e, aaPos)) { // it'll be shorter // now make sure that associated triangles won't flip //todo: add support for 2d position attachments vector3 n0, n1; CalculateNormal(n0, nbrFaces[0], aaPos); CalculateNormal(n1, nbrFaces[1], aaPos); number oldDot = VecDot(n0, n1); FaceDescriptor ntri; ntri.set_num_vertices(3); ntri.set_vertex(0, e->vertex(0)); ntri.set_vertex(1, conVrt1); ntri.set_vertex(2, conVrt0); CalculateNormal(n0, &ntri, aaPos); ntri.set_vertex(0, e->vertex(1)); ntri.set_vertex(1, conVrt0); ntri.set_vertex(2, conVrt1); CalculateNormal(n1, &ntri, aaPos); number newDot = VecDot(n0, n1); // if both have the same sign, we're fine! if(oldDot * newDot < 0){ continue;// not fine! } // ok - everything is fine. Now swap the edge e = SwapEdge(grid, e); UG_ASSERT(e, "SwapEdge did not produce a new edge."); // all edges of associated triangles are candidates again (except e) GetAssociatedFaces(nbrFaces, grid, e, 2); for(size_t i = 0; i < 2; ++i){ CollectAssociated(edges, grid, nbrFaces[i]); for(size_t j = 0; j < edges.size(); ++j){ if(edges[j] != e && (!aaIsCandidate[edges[j]])){ candidates.push(edges[j]); aaIsCandidate[edges[j]] = 1; } } } } } } grid.detach_from_edges(aIsCandidate); }
//////////////////////////////////////////////////////////////////////// // MergeVertices /// merges two vertices and restructures the adjacent elements. void MergeVertices(Grid& grid, Vertex* v1, Vertex* v2) { // make sure that GRIDOPT_VERTEXCENTRIC_INTERCONNECTION is enabled if(grid.num_edges() && (!grid.option_is_enabled(VRTOPT_STORE_ASSOCIATED_EDGES))) { LOG(" WARNING in MergeVertices: autoenabling VRTOPT_STORE_ASSOCIATED_EDGES\n"); grid.enable_options(VRTOPT_STORE_ASSOCIATED_EDGES); } if(grid.num_faces() && (!grid.option_is_enabled(VRTOPT_STORE_ASSOCIATED_FACES))) { LOG(" WARNING in MergeVertices: autoenabling VRTOPT_STORE_ASSOCIATED_FACES\n"); grid.enable_options(VRTOPT_STORE_ASSOCIATED_FACES); } if(grid.num_volumes() && (!grid.option_is_enabled(VRTOPT_STORE_ASSOCIATED_VOLUMES))) { LOG(" WARNING in MergeVertices: autoenabling VRTOPT_STORE_ASSOCIATED_VOLUMES\n"); grid.enable_options(VRTOPT_STORE_ASSOCIATED_VOLUMES); } Edge* conEdge = grid.get_edge(v1, v2); if(conEdge) { // perform an edge-collapse on conEdge CollapseEdge(grid, conEdge, v1); } else { // notify the grid, that the two vertices will be merged grid.objects_will_be_merged(v1, v1, v2); // we have to check if there are elements that connect the vertices. // We have to delete those. EraseConnectingElements(grid, v1, v2); // create new edges for each edge that is connected with v2. // avoid double edges if(grid.num_edges() > 0) { EdgeDescriptor ed; Grid::AssociatedEdgeIterator iterEnd = grid.associated_edges_end(v2); for(Grid::AssociatedEdgeIterator iter = grid.associated_edges_begin(v2); iter != iterEnd; ++iter) { Edge* e = *iter; if(e->vertex(0) == v2) ed.set_vertices(v1, e->vertex(1)); else ed.set_vertices(e->vertex(0), v1); Edge* existingEdge = grid.get_edge(ed); if(!existingEdge) grid.create_by_cloning(e, ed, e); else grid.objects_will_be_merged(existingEdge, existingEdge, e); } } // create new faces for each face that is connected to v2 // avoid double faces. if(grid.num_faces() > 0) { FaceDescriptor fd; Grid::AssociatedFaceIterator iterEnd = grid.associated_faces_end(v2); for(Grid::AssociatedFaceIterator iter = grid.associated_faces_begin(v2); iter != iterEnd; ++iter) { Face* f = *iter; uint numVrts = f->num_vertices(); fd.set_num_vertices(numVrts); for(uint i = 0; i < numVrts; ++i) { if(f->vertex(i) == v2) fd.set_vertex(i, v1); else fd.set_vertex(i, f->vertex(i)); } Face* existingFace = grid.get_face(fd); if(!existingFace) grid.create_by_cloning(f, fd, f); else grid.objects_will_be_merged(existingFace, existingFace, f); } } // create new volumes for each volume that is connected to v2 if(grid.num_volumes() > 0) { VolumeDescriptor vd; Grid::AssociatedVolumeIterator iterEnd = grid.associated_volumes_end(v2); for(Grid::AssociatedVolumeIterator iter = grid.associated_volumes_begin(v2); iter != iterEnd; ++iter) { Volume* v = *iter; uint numVrts = v->num_vertices(); vd.set_num_vertices(numVrts); for(uint i = 0; i < numVrts; ++i) { if(v->vertex(i) == v2) vd.set_vertex(i, v1); else vd.set_vertex(i, v->vertex(i)); } //assert(!"avoid double volumes! implement FindVolume and use it here."); grid.create_by_cloning(v, vd, v); } } // new elements have been created. remove the old ones. // it is sufficient to simply erase v2. grid.erase(v2); } }
void MultiGridRefiner::refine() { assert(m_pMG && "refiner not has to be assigned to a multi-grid!"); if(!m_pMG) return; // the multi-grid MultiGrid& mg = *m_pMG; // make sure that the required options are enabled. if(!mg.option_is_enabled(GRIDOPT_FULL_INTERCONNECTION)) { LOG("WARNING in MultiGridRefiner::refine(): auto-enabling GRIDOPT_FULL_INTERCONNECTION.\n"); mg.enable_options(GRIDOPT_FULL_INTERCONNECTION); } // access position attachments Grid::VertexAttachmentAccessor<APosition> aaPos; if(mg.has_vertex_attachment(aPosition)) aaPos.access(mg, aPosition); // collect objects for refine collect_objects_for_refine(); // notify derivates that refinement begins refinement_step_begins(); // cout << "num marked edges: " << m_selMarks.num<Edge>() << endl; // cout << "num marked faces: " << m_selMarks.num<Face>() << endl; // we want to add new elements in a new layer. bool bHierarchicalInsertionWasEnabled = mg.hierarchical_insertion_enabled(); if(!bHierarchicalInsertionWasEnabled) mg.enable_hierarchical_insertion(true); // some buffers vector<Vertex*> vVrts; vector<Vertex*> vEdgeVrts; vector<Edge*> vEdges; vector<Face*> vFaces; // some repeatedly used objects EdgeDescriptor ed; FaceDescriptor fd; VolumeDescriptor vd; //LOG("creating new vertices\n"); // create new vertices from marked vertices for(VertexIterator iter = m_selMarks.begin<Vertex>(); iter != m_selMarks.end<Vertex>(); ++iter) { Vertex* v = *iter; if(!mg.get_child_vertex(v)) { // create a new vertex in the next layer. Vertex* nVrt = *mg.create_by_cloning(v, v); if(aaPos.valid()) { aaPos[nVrt] = aaPos[v]; // change z-coord to visualise the hierarchy //aaPos[nVrt].z() += 0.01; } } } //LOG("creating new edges\n"); // create new vertices and edges from marked edges for(EdgeIterator iter = m_selMarks.begin<Edge>(); iter != m_selMarks.end<Edge>(); ++iter) { // collect_objects_for_refine removed all edges that already were // refined. No need to check that again. Edge* e = *iter; int rule = get_rule(e); switch(rule) { case RM_COPY: { // clone the edge. ed.set_vertices(mg.get_child_vertex(e->vertex(0)), mg.get_child_vertex(e->vertex(1))); Edge* newEdge = *mg.create_by_cloning(e, ed, e); set_status(newEdge, SM_COPY); }break; default: { // create two new edges by edge-split RegularVertex* nVrt = *mg.create<RegularVertex>(e); Vertex* substituteVrts[2]; substituteVrts[0] = mg.get_child_vertex(e->vertex(0)); substituteVrts[1] = mg.get_child_vertex(e->vertex(1)); if(aaPos.valid()) { VecScaleAdd(aaPos[nVrt], 0.5, aaPos[e->vertex(0)], 0.5, aaPos[e->vertex(1)]); // change z-coord to visualise the hierarchy //aaPos[nVrt].z() += 0.01; } // split the edge e->refine(vEdges, nVrt, substituteVrts); assert((vEdges.size() == 2) && "RegularEdge refine produced wrong number of edges."); mg.register_element(vEdges[0], e); mg.register_element(vEdges[1], e); set_status(vEdges[0], SM_REGULAR); set_status(vEdges[1], SM_REGULAR); }break; } } //LOG("creating new faces\n"); // create new vertices and faces from marked faces for(FaceIterator iter = m_selMarks.begin<Face>(); iter != m_selMarks.end<Face>(); ++iter) { Face* f = *iter; int rule = get_rule(f); switch(rule) { case RM_COPY: { // clone the face. if(fd.num_vertices() != f->num_vertices()) fd.set_num_vertices(f->num_vertices()); for(size_t i = 0; i < fd.num_vertices(); ++i) fd.set_vertex(i, mg.get_child_vertex(f->vertex(i))); Face* nf = *mg.create_by_cloning(f, fd, f); set_status(nf, SM_COPY); }break; default: { // collect child-vertices vVrts.clear(); for(uint j = 0; j < f->num_vertices(); ++j){ vVrts.push_back(mg.get_child_vertex(f->vertex(j))); } // collect the associated edges vEdgeVrts.clear(); //bool bIrregular = false; for(uint j = 0; j < f->num_edges(); ++j){ Vertex* vrt = mg.get_child_vertex(mg.get_edge(f, j)); vEdgeVrts.push_back(vrt); //if(!vrt) // bIrregular = true; } /* if(bIrregular){ assert((get_rule(f) != RM_REFINE) && "Bad refinement-rule set during collect_objects_for_refine!"); //TODO: care about anisotropy set_rule(f, RM_IRREGULAR); } */ Vertex* newVrt; if(f->refine(vFaces, &newVrt, &vEdgeVrts.front(), NULL, &vVrts.front())){ // if a new vertex was generated, we have to register it if(newVrt){ mg.register_element(newVrt, f); if(aaPos.valid()){ aaPos[newVrt] = CalculateCenter(f, aaPos); // change z-coord to visualise the hierarchy //aaPos[newVrt].z() += 0.01; } } int oldRule = get_rule(f); // register the new faces and assign status for(size_t j = 0; j < vFaces.size(); ++j){ mg.register_element(vFaces[j], f); switch(oldRule) { case RM_REFINE: set_status(vFaces[j], SM_REGULAR); break; case RM_IRREGULAR: set_status(vFaces[j], SM_IRREGULAR); break; default: assert((oldRule == RM_REFINE) && "rule not yet handled.");//always fails. break; } } } else{ LOG(" WARNING in Refine: could not refine face.\n"); } } } } // done - clean up if(!bHierarchicalInsertionWasEnabled) mg.enable_hierarchical_insertion(false); m_selMarks.clear(); // notify derivates that refinement ends refinement_step_ends(); }