typename TAPosition::ValueType CalculateCenter(TVrtIter vrtsBegin, TVrtIter vrtsEnd, Grid::AttachmentAccessor<Vertex, TAPosition>& aaPos) { typename TAPosition::ValueType vMin, vMax; CalculateBoundingBox(vMin, vMax, vrtsBegin, vrtsEnd, aaPos); typename TAPosition::ValueType vRet; VecScaleAdd(vRet, 0.5, vMin, 0.5, vMax); return vRet; }
/// Creates an Icosahedron void GenerateIcosahedron(Grid& grid, const vector3& center, number radius, AVector3& aPos) { const number A = 0.85065080835204; const number B = 0.525731112119134; // create the vertices const number coords[12][3] = { {-B, A, 0}, {0, B, A}, {B, A, 0}, {0, B, -A}, {-A, 0, B}, {A, 0, B}, {A, 0, -B}, {-A, 0, -B}, {-B, -A, 0}, {0, -B, A}, {B, -A, 0}, {0, -B, -A}}; const int inds[20][3] = { {0, 1, 2}, {0, 2, 3}, {3, 7, 0}, {7, 4, 0}, {0, 4, 1}, {1, 5, 2}, {5, 6, 2}, {2, 6, 3}, {4, 9, 1}, {1, 9, 5}, {7, 3, 11}, {3, 6, 11}, {11, 8, 7}, {7, 8, 4}, {8, 9, 4}, {9, 10, 5}, {10, 6, 5}, {10, 11, 6}, {8, 10, 9}, {8, 11, 10}}; Vertex* vrts[12]; if(!grid.has_vertex_attachment(aPos)) grid.attach_to_vertices(aPos); Grid::AttachmentAccessor<Vertex, AVector3> aaPos(grid, aPos); for(size_t i = 0; i < 12; ++i){ vrts[i] = *grid.create<RegularVertex>(); aaPos[vrts[i]] = vector3(coords[i][0], coords[i][1], coords[i][2]); VecScaleAdd(aaPos[vrts[i]], 1.0, center, radius, aaPos[vrts[i]]); } // construct triangles for(size_t i = 0; i < 20; ++i){ grid.create<Triangle>(TriangleDescriptor(vrts[inds[i][0]], vrts[inds[i][1]], vrts[inds[i][2]])); } }
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; }
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(); }