Vertex* FindVertexByCoordiante(vector3& coord, VertexIterator iterBegin, VertexIterator iterEnd, Grid::VertexAttachmentAccessor<APosition>& aaPos) { if(iterBegin == iterEnd) return NULL; Vertex* bestVrt = *iterBegin; number bestDistSq = VecDistanceSq(coord, aaPos[bestVrt]); VertexIterator iter = iterBegin; iter++; while(iter != iterEnd) { number distSq = VecDistanceSq(coord, aaPos[*iter]); if(distSq < bestDistSq) { bestDistSq = distSq; bestVrt = *iter; } ++iter; } return bestVrt; }
TElem* FindClosestByCoordinate(const typename TVertexPositionAttachmentAccessor::ValueType& coord, typename geometry_traits<TElem>::iterator iterBegin, typename geometry_traits<TElem>::iterator iterEnd, TVertexPositionAttachmentAccessor& aaPosVRT) { if(iterBegin == iterEnd) return NULL; typename geometry_traits<TElem>::iterator iter = iterBegin; TElem* bestElem = *iter; number bestDistSq = VecDistanceSq(coord, CalculateCenter(bestElem, aaPosVRT)); iter++; while(iter != iterEnd) { number distSq = VecDistanceSq(coord, CalculateCenter(*iter, aaPosVRT)); if(distSq < bestDistSq) { bestDistSq = distSq; bestElem = *iter; } ++iter; } return bestElem; }
number ElementDiameterSq(Grid& grid, TAAPos& aaPos, TElem* elem) { PointerConstArray<Vertex*> vVert; grid.associated_elements(vVert, elem); number max = 0.0; for(size_t i = 0; i < vVert.size(); ++i) for(size_t j = i+1; j < vVert.size(); ++j) max = std::max(max, VecDistanceSq(aaPos[vVert[i]], aaPos[vVert[j]])); return max; }
int FindVertexByCoordinate(const MathVector<dim>& coord, size_t ncoords, const MathVector<dim> vCoords[]) { if (ncoords <= 0) return -1; size_t bestVrt = 0; number bestDistSq = VecDistanceSq(coord, vCoords[0]); for (size_t i=1; i<ncoords; ++i) { number distSq = VecDistance(coord, vCoords[i]); if(distSq < bestDistSq) { bestDistSq = distSq; bestVrt = i; } } return bestVrt; }
number VertexDistanceSq(Vertex* v0, Vertex* v1, TAAPos& aaPos) { return VecDistanceSq(aaPos[v0], aaPos[v1]); }
void RemoveDoubles(Grid& grid, const TVrtIterator& iterBegin, const TVrtIterator& iterEnd, TAAPos aaPos, number threshold) { typedef Attachment<MathVector<dim> > attachment_type; KDTreeStatic<attachment_type, dim, MathVector<dim> > kdTree; kdTree.create_from_grid(grid, iterBegin, iterEnd, aaPos, 20, 10, KDSD_LARGEST); // we need temporary attachments: // a vector<Vertex*> attachment, that stores for each vertex all other vertices // closer than threshold, which have higher attachment data index. typedef Attachment<std::list<Vertex*> > AVertexList; AVertexList aVertexList; grid.attach_to_vertices(aVertexList); Grid::VertexAttachmentAccessor<AVertexList> aaVL(grid, aVertexList); // we'll store in this attachment whether a vertex will be merged or not. AInt aInt; grid.attach_to_vertices(aInt); Grid::VertexAttachmentAccessor<AInt> aaInt(grid, aInt); { for(TVrtIterator iter = iterBegin; iter != iterEnd; ++iter) aaInt[*iter] = 0; } // compare squares. threshold *= threshold; std::vector<Vertex*> neighbours; // iterate over all vertices and collect all that have aInt == 0 and are within range. for(TVrtIterator iter = iterBegin; iter != iterEnd; ++iter) { Vertex* v = *iter; if(aaInt[v] == 0) {// the vertex will not be removed during merge // find all vertices closer than threshold uint numClosest = 3; while(numClosest < grid.num_vertices()) { neighbours.clear(); kdTree.get_neighbourhood(neighbours, aaPos[v], numClosest); if(VecDistanceSq(aaPos[neighbours.back()], aaPos[v]) < threshold) numClosest *= 2; else break; } // store them in the vertexVec attachment if(!neighbours.empty()) { for(std::vector<Vertex*>::iterator nIter = neighbours.begin(); nIter != neighbours.end(); ++nIter) { Vertex* nv = *nIter; if(aaInt[nv] == 0) { if(nv != v) { if(VecDistanceSq(aaPos[v], aaPos[nv]) < threshold) { aaVL[v].push_back(nv); aaInt[nv] = 1; } else break; } } } } } } // iterate over all vertices again and merge collected ones // This iteration only works, if the iterators stem from a class // like Selector or SubsetHandler or Grid etc, which automatically // handle removed elements. //TODO: This should be improved somehow! { TVrtIterator iter = iterBegin; while(iter != iterEnd) { Vertex* v = *iter; if(!aaVL[v].empty()) { std::list<Vertex*>::iterator nIter = aaVL[v].begin(); while(nIter != aaVL[v].end()) { Vertex* delVrt = *nIter; nIter++; MergeVertices(grid, v, delVrt); } } ++iter; } } grid.detach_from_vertices(aVertexList); grid.detach_from_vertices(aInt); }
int Refine(int* newIndsOut, int* newEdgeVrts, bool& newCenterOut, vector3* corners, bool*) { newCenterOut = false; // If a refinement rule is not implemented, fillCount will stay at 0. // Before returning, we'll check, whether fillCount is at 0 and will // perform refinement with an additional vertex in this case. // corner status is used to mark vertices, which are connected to refined edges // the value tells, how many associated edges are refined. int cornerStatus[4] = {0, 0, 0, 0}; // here we'll store the index of each edge, which will be refined. // Size of the valid sub-array is numNewVrts, which is calculated below. int refEdgeInds[NUM_EDGES]; // count the number of new vertices and fill newVrtEdgeInds int numNewVrts = 0; for(int i = 0; i < NUM_EDGES; ++i){ if(newEdgeVrts[i]){ refEdgeInds[numNewVrts] = i; ++numNewVrts; // adjust corner status of associated vertices const int* evi = EDGE_VRT_INDS[i]; ++cornerStatus[evi[0]]; ++cornerStatus[evi[1]]; } } // the fillCount tells how much data has already been written to newIndsOut. int fillCount = 0; // depending on the number of new vertices, we will now apply different // refinement rules. Further distinction may have to be done. switch(numNewVrts){ case 0: { // simply put the default tetrahedron back to newIndsOut newIndsOut[fillCount++] = GOID_TETRAHEDRON; newIndsOut[fillCount++] = 0; newIndsOut[fillCount++] = 1; newIndsOut[fillCount++] = 2; newIndsOut[fillCount++] = 3; }break; case 1: { int refEdgeInd = refEdgeInds[0]; // the two faces which are not connected to the refined edge // serve as bottom for the new tetrahedrons. for(int i_face = 0; i_face < NUM_FACES; ++i_face){ if(!FACE_CONTAINS_EDGE[i_face][refEdgeInd]){ const int* fvi = FACE_VRT_INDS[i_face]; newIndsOut[fillCount++] = GOID_TETRAHEDRON; newIndsOut[fillCount++] = fvi[0]; newIndsOut[fillCount++] = fvi[1]; newIndsOut[fillCount++] = fvi[2]; newIndsOut[fillCount++] = NUM_VERTICES + refEdgeInd; } } }break; case 2: { // two types exist: The two refined edges share a vertex or not. if(OPPOSED_EDGE[refEdgeInds[0]] == refEdgeInds[1]){ // they do not share an edge // we create a local order from refEdgeInds[0], which // always has to be an edge in the base-triangle and // refEdgeInds[1], which always connects a base-corner with // the top. const int v0 = EDGE_VRT_INDS[refEdgeInds[0]][0]; const int v1 = EDGE_VRT_INDS[refEdgeInds[0]][1]; const int v2 = EDGE_VRT_INDS[refEdgeInds[1]][0]; const int v3 = EDGE_VRT_INDS[refEdgeInds[1]][1]; const int n0 = refEdgeInds[0] + NUM_VERTICES; const int n1 = refEdgeInds[1] + NUM_VERTICES; // from this local order we can now construct the 4 new tetrahedrons. int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v0; inds[fi++] = n0; inds[fi++] = v2; inds[fi++] = n1; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v0; inds[fi++] = n0; inds[fi++] = n1; inds[fi++] = v3; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = n0; inds[fi++] = v1; inds[fi++] = v2; inds[fi++] = n1; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = n0; inds[fi++] = v1; inds[fi++] = n1; inds[fi++] = v3; } else{ // they share an edge // We have to create a pyramid and a tetrahedron. // get the triangle, which contains both refEdges int refTriInd = FACE_FROM_EDGES[refEdgeInds[0]][refEdgeInds[1]]; const int* f = FACE_VRT_INDS[refTriInd]; // find the edge (v0, v1) in refTri, which won't be refined int v0 = -1; int v1 = -1; int v2 = -1; for(int i = 0; i < 3; ++i){ v0 = f[i]; v1 = f[(i+1)%3]; v2 = f[(i+2)%3]; if(cornerStatus[v0] == 1 && cornerStatus[v1] == 1) break; } // make sure that v2 is connected to two refined edges assert(cornerStatus[v2] == 2); // get the new vertex on edge v1v2 and on v2v0 int v1v2 = EDGE_FROM_VRTS[v1][v2] + NUM_VERTICES; int v2v0 = EDGE_FROM_VRTS[v2][v0] + NUM_VERTICES; // get the top (vertex with cornerState 0) int vtop = -1; for(int i = 0; i < NUM_VERTICES; ++i){ if(cornerStatus[i] == 0){ vtop = i; break; } } // now lets build the pyramid int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_PYRAMID; inds[fi++] = v0; inds[fi++] = v1; inds[fi++] = v1v2; inds[fi++] = v2v0; inds[fi++] = vtop; // and now the terahedron inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v2; inds[fi++] = vtop; inds[fi++] = v2v0; inds[fi++] = v1v2; } }break; case 3: { // different possibilities exist. First we'll treat the one, // where all new vertices lie on the edges of one triangle. // Note that refTriInd could be -1 after the call. int refTriInd = FACE_FROM_EDGES[refEdgeInds[0]][refEdgeInds[1]]; if(refTriInd == FACE_FROM_EDGES[refEdgeInds[1]][refEdgeInds[2]]) { // all three lie in one plane (refTriInd has to be != -1 to get here) // get the top (vertex with cornerState 0) int vtop = -1; for(int i = 0; i < NUM_VERTICES; ++i){ if(cornerStatus[i] == 0){ vtop = i; break; } } const int* f = FACE_VRT_INDS[refTriInd]; // create four new tetrahedrons const int v0 = f[0]; const int v1 = f[1]; const int v2 = f[2]; const int v0v1 = EDGE_FROM_VRTS[v0][v1] + NUM_VERTICES; const int v1v2 = EDGE_FROM_VRTS[v1][v2] + NUM_VERTICES; const int v2v0 = EDGE_FROM_VRTS[v2][v0] + NUM_VERTICES; int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v0; inds[fi++] = vtop; inds[fi++] = v0v1; inds[fi++] = v2v0; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v1; inds[fi++] = vtop; inds[fi++] = v1v2; inds[fi++] = v0v1; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v2; inds[fi++] = vtop; inds[fi++] = v2v0; inds[fi++] = v1v2; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v0v1; inds[fi++] = vtop; inds[fi++] = v1v2; inds[fi++] = v2v0; } else{ // we have to further distinguish. // gather the corners with corner-state 3 and corner state 1 int corner3 = -1; int freeCorner[NUM_VERTICES]; int freeCount = 0; for(int i = 0; i < NUM_VERTICES; ++i){ if(cornerStatus[i] == 3) corner3 = i; else freeCorner[freeCount++] = i; } if(corner3 != -1){ // a corner with corner state 3 exists. assert(freeCount == 3); // get the face which won't be refined (required for correct orientation) int freeTriInd = FACE_FROM_VRTS[freeCorner[0]][freeCorner[1]] [freeCorner[2]]; // the free tri is the new base, corner3 the top const int* f = FACE_VRT_INDS[freeTriInd]; int v2v3 = EDGE_FROM_VRTS[f[2]][corner3] + NUM_VERTICES; int v1v3 = EDGE_FROM_VRTS[f[1]][corner3] + NUM_VERTICES; int v0v3 = EDGE_FROM_VRTS[f[0]][corner3] + NUM_VERTICES; // add a prism and a tetrahedron int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_PRISM; inds[fi++] = f[0]; inds[fi++] = f[1]; inds[fi++] = f[2]; inds[fi++] = v0v3; inds[fi++] = v1v3; inds[fi++] = v2v3; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v2v3; inds[fi++] = corner3; inds[fi++] = v0v3; inds[fi++] = v1v3; } } }break; case 4: { // multiple settings with 4 refined edges exist. // Either two opposing edges are not marked (case all2 == true) // or the two unmarked edges are contained in 1 triangle // check whether all vertices have corner state 2 bool all2 = true; for(int i = 0; i < NUM_VERTICES; ++i){ if(cornerStatus[i] !=2){ all2 = false; break; } } if(all2){ // we've got a straight cut. // we'll rotate the tetrahedron around the tip so, that edge 2 won't be refined. int steps = 0; if(!newEdgeVrts[EDGE_FROM_VRTS[0][1]]) steps = 2; else if(!newEdgeVrts[EDGE_FROM_VRTS[1][2]]) steps = 1; int t[NUM_VERTICES] = {0, 1, 2, 3}; TetRotation(t, 3, steps); const int v0v1 = EDGE_FROM_VRTS[t[0]][t[1]] + NUM_VERTICES; const int v1v2 = EDGE_FROM_VRTS[t[1]][t[2]] + NUM_VERTICES; const int v0v3 = EDGE_FROM_VRTS[t[0]][t[3]] + NUM_VERTICES; const int v2v3 = EDGE_FROM_VRTS[t[2]][t[3]] + NUM_VERTICES; assert(newEdgeVrts[v0v1 - NUM_VERTICES]); assert(newEdgeVrts[v1v2 - NUM_VERTICES]); assert(newEdgeVrts[v0v3 - NUM_VERTICES]); assert(newEdgeVrts[v2v3 - NUM_VERTICES]); // now build two prisms int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_PRISM; inds[fi++] = t[0]; inds[fi++] = v0v3; inds[fi++] = v0v1; inds[fi++] = t[2]; inds[fi++] = v2v3; inds[fi++] = v1v2; inds[fi++] = GOID_PRISM; inds[fi++] = t[1]; inds[fi++] = v1v2; inds[fi++] = v0v1; inds[fi++] = t[3]; inds[fi++] = v2v3; inds[fi++] = v0v3; } else{ // one corner has state 1, one has state 3 and two have state 2. // Rotate the tet so that 1 is at the top and 4 is at the origin int I[NUM_VERTICES] = {0, 1, 2, 3}; int s1 = -1; for(int i = 0; i < 4; ++i){ if(cornerStatus[i] == 1){ s1 = i; break; } } if(s1 != 3){ const int fixedPoint = (s1 + 2) % 3; TetRotation(I, fixedPoint, 1); } if(cornerStatus[I[1]] == 3) TetRotation(I, 3, 2); else if(cornerStatus[I[2]] == 3) TetRotation(I, 3, 1); // indices of edge-center vertices const int v01 = EDGE_FROM_VRTS[I[0]][I[1]] + NUM_VERTICES; const int v02 = EDGE_FROM_VRTS[I[0]][I[2]] + NUM_VERTICES; const int v03 = EDGE_FROM_VRTS[I[0]][I[3]] + NUM_VERTICES; const int v12 = EDGE_FROM_VRTS[I[1]][I[2]] + NUM_VERTICES; int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = I[0]; inds[fi++] = v01; inds[fi++] = v02; inds[fi++] = v03; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = v01; inds[fi++] = v12; inds[fi++] = v02; inds[fi++] = v03; inds[fi++] = GOID_PYRAMID; inds[fi++] = I[3]; inds[fi++] = I[1]; inds[fi++] = v01; inds[fi++] = v03; inds[fi++] = v12; inds[fi++] = GOID_PYRAMID; inds[fi++] = I[2]; inds[fi++] = I[3]; inds[fi++] = v03; inds[fi++] = v02; inds[fi++] = v12; } }break; case 5:{ // only one edge is not marked for refinement int unmarkedEdge = 0; for(int i = 0; i < NUM_EDGES; ++i){ if(!newEdgeVrts[i]){ unmarkedEdge = i; break; } } int uei0 = EDGE_VRT_INDS[unmarkedEdge][0]; int uei1 = EDGE_VRT_INDS[unmarkedEdge][1]; // orientate the tetrahedron so that the unmarked edge connects // vertices 2 and 3 int I[NUM_VERTICES] = {0, 1, 2, 3}; // if the unmarked edge lies in the base triangle, we'll first have to // rotate so that it connects a base-vertex with the top if(unmarkedEdge < 3){ const int fixedPoint = (uei1 + 1) % 3; TetRotation(I, fixedPoint, 1); int IInv[4]; InverseTetTransform(IInv, I); uei0 = IInv[uei0]; uei1 = IInv[uei1]; unmarkedEdge = EDGE_FROM_VRTS[uei0][uei1]; } // now rotate the tet to its final place if(unmarkedEdge == 3) TetRotation(I, 3, 2); else if(unmarkedEdge == 4) TetRotation(I, 3, 1); // We obtained the final permutation I. Now create new elements // indices of edge-center vertices const int v01 = EDGE_FROM_VRTS[I[0]][I[1]] + NUM_VERTICES; const int v02 = EDGE_FROM_VRTS[I[0]][I[2]] + NUM_VERTICES; const int v03 = EDGE_FROM_VRTS[I[0]][I[3]] + NUM_VERTICES; const int v12 = EDGE_FROM_VRTS[I[1]][I[2]] + NUM_VERTICES; const int v13 = EDGE_FROM_VRTS[I[1]][I[3]] + NUM_VERTICES; int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = I[0]; inds[fi++] = v01; inds[fi++] = v02; inds[fi++] = v03; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = I[1]; inds[fi++] = v12; inds[fi++] = v01; inds[fi++] = v13; inds[fi++] = GOID_PYRAMID; inds[fi++] = v02; inds[fi++] = v12; inds[fi++] = v13; inds[fi++] = v03; inds[fi++] = v01; inds[fi++] = GOID_PRISM; inds[fi++] = v02; inds[fi++] = v12; inds[fi++] = I[2]; inds[fi++] = v03; inds[fi++] = v13; inds[fi++] = I[3]; }break; // REGULAR REFINEMENT case 6: { // depending on the user specified global refinement rule, we will now apply different // refinement rules. switch(g_refinementRule){ case STANDARD: { int& fi = fillCount; int* inds = newIndsOut; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = 0; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = 1; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = 2; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = 3; // for the remaining four tetrahedrons, we'll choose the shortest diagonal int bestDiag = 2; if(corners){ // there are three diagonals between the following edge-centers: // 0-5, 1-3, 2-4 vector3 c1, c2; // 0-5 VecAdd(c1, corners[0], corners[1]); VecScale(c1, c1, 0.5); VecAdd(c2, corners[2], corners[3]); VecScale(c2, c2, 0.5); number d05 = VecDistanceSq(c1, c2); // 1-3 VecAdd(c1, corners[1], corners[2]); VecScale(c1, c1, 0.5); VecAdd(c2, corners[0], corners[3]); VecScale(c2, c2, 0.5); number d13 = VecDistanceSq(c1, c2); // 2-4 VecAdd(c1, corners[0], corners[2]); VecScale(c1, c1, 0.5); VecAdd(c2, corners[1], corners[3]); VecScale(c2, c2, 0.5); number d = VecDistanceSq(c1, c2); if(d13 < d){ bestDiag = 1; d = d13; } if(d05 < d){ bestDiag = 0; } } switch(bestDiag){ case 0:// diag: 0-5 inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; break; case 1:// diag: 1-3 inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 1; break; case 2:// diag 2-4 inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 5; break; } }break; case HYBRID_TET_OCT: { // REGULAR REFINEMENT int& fi = fillCount; int* inds = newIndsOut; // outer tetrahedrons analogously defined to STANDARD case inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = 0; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = 1; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = 2; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = GOID_TETRAHEDRON; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = 3; // inner octahedron: // For the remaining inner cavity we'll choose the shortest diagonal // and order the octahedral nodes, so that, the implicit // subdivision of the octahedron into tetrahedrons during // discretization happens alongside exactly this shortest diagonal. int bestDiag = 2; if(corners){ // there are three diagonals between the following edge-centers: // 0-5, 1-3, 2-4 vector3 c1, c2; // 0-5 VecAdd(c1, corners[0], corners[1]); VecScale(c1, c1, 0.5); VecAdd(c2, corners[2], corners[3]); VecScale(c2, c2, 0.5); number d05 = VecDistanceSq(c1, c2); // 1-3 VecAdd(c1, corners[1], corners[2]); VecScale(c1, c1, 0.5); VecAdd(c2, corners[0], corners[3]); VecScale(c2, c2, 0.5); number d13 = VecDistanceSq(c1, c2); // 2-4 VecAdd(c1, corners[0], corners[2]); VecScale(c1, c1, 0.5); VecAdd(c2, corners[1], corners[3]); VecScale(c2, c2, 0.5); number d = VecDistanceSq(c1, c2); if(d13 < d){ bestDiag = 1; d = d13; } if(d05 < d){ bestDiag = 0; } } switch(bestDiag){ case 0:// diag: 0-5 inds[fi++] = GOID_OCTAHEDRON; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 3; break; case 1:// diag: 1-3 inds[fi++] = GOID_OCTAHEDRON; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 3; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 5; break; case 2:// diag 2-4 inds[fi++] = GOID_OCTAHEDRON; inds[fi++] = NUM_VERTICES + 1; inds[fi++] = NUM_VERTICES + 2; inds[fi++] = NUM_VERTICES + 0; inds[fi++] = NUM_VERTICES + 4; inds[fi++] = NUM_VERTICES + 5; inds[fi++] = NUM_VERTICES + 3; break; }break; }break; } }break; } if(fillCount == 0){ // call recursive refine fillCount = shared_rules::RecursiveRefine(newIndsOut, newEdgeVrts, FACE_VRT_INDS, FACE_EDGE_INDS, NUM_VERTICES, NUM_EDGES, NUM_FACES); // the rule requires a new center vertex newCenterOut = true; } return fillCount; }
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; }