diff --git a/contrib/hxt/CMakeLists.txt b/contrib/hxt/CMakeLists.txt index e3dc3fe89a0bec950b43ef7f272cdccb401a6a16..fdf2be26643629191b6335f3f28225f87b9cb54b 100644 --- a/contrib/hxt/CMakeLists.txt +++ b/contrib/hxt/CMakeLists.txt @@ -101,6 +101,8 @@ set(SRC hxt_tetColor.c hxt_tetColor.h hxt_tetDelaunay.c + hxt_tetDelaunayReshape.c + hxt_tetDelaunayReshape.h hxt_tetFlag.c hxt_tetMesh.c hxt_tetNodalSize.c diff --git a/contrib/hxt/tetMesh/CMakeLists.txt b/contrib/hxt/tetMesh/CMakeLists.txt index ba2e202ef8f7ca4e052fab0490a135d43a2c657b..9dca43f10707f59440dc490791861404ef4d2cf0 100644 --- a/contrib/hxt/tetMesh/CMakeLists.txt +++ b/contrib/hxt/tetMesh/CMakeLists.txt @@ -34,6 +34,7 @@ set(HXT_TETMESH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetQuality.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_edgeRemoval.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetDelaunay.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetDelaunayReshape.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetNodalSize.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/HXTSPR.h" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetSync.h" @@ -43,6 +44,7 @@ set(HXT_TETMESH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetRefine.h" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetQuality.h" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_edgeRemoval.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetDelaunayReshape.h" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetOptiUtils.h" "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetPartition.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetDelaunay.h" diff --git a/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c index cf857298416571d579b9549216785b598117084b..c31e3eee3f8013efc3eeb0e626b083183874f77c 100644 --- a/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c @@ -7,9 +7,8 @@ // Célestin Marot #include "hxt_tetDelaunay.h" -#include "hxt_tetPartition.h" +#include "hxt_tetDelaunayReshape.h" #include "predicates.h" -#include "hxt_tetSync.h" #include "hxt_tetFlag.h" #include "hxt_tetRepair.h" #include "hxt_sort.h" @@ -36,27 +35,6 @@ }while(0) -typedef struct { - uint64_t neigh; // the tet on the other side of the boundary - uint32_t node[3]; - uint16_t flag; -} cavityBnd_t; - - -typedef struct { - uint64_t hxtDeclareAligned Map[1024]; - - struct { - cavityBnd_t* array; - uint64_t num; - uint64_t size; - } ball; - - HXTDeleted deleted; - HXTPartition partition; -} TetLocal; - - static int compareNodeLexicographically(uint32_t* nodes0, uint32_t* nodes1) { for(int i=0; i<4; i++) { @@ -224,15 +202,6 @@ unsigned computePasses(uint32_t passes[12], } -static inline HXTStatus askForBall(TetLocal* local, uint64_t needed) { - needed += local->ball.num; - if(needed>local->ball.size) { - HXT_CHECK( hxtAlignedRealloc(&local->ball.array, sizeof(cavityBnd_t)*2*needed) ); - local->ball.size = 2*needed; - } - return HXT_STATUS_OK; -} - /****************************************** * initialisation of the TetLocal structure ******************************************/ @@ -611,265 +580,6 @@ static inline HXTStatus walking2Cavity(HXTMesh* mesh, HXTPartition* partition, u * digging cavity ***********************************/ -/* pushing cavity boundary information to local->ball */ -static inline void bndPush( TetLocal* local, uint16_t flag, - const uint32_t node1, const uint32_t node2, - const uint32_t node3, const uint64_t neigh){ - uint64_t n = local->ball.num; - local->ball.array[n].node[0] = node1; - local->ball.array[n].node[1] = node2; - local->ball.array[n].node[2] = node3; - local->ball.array[n].flag = flag; - local->ball.array[n].neigh = neigh; - local->ball.num++; -} - -/* check if the cavity is star shaped - This isn't usefull for pure Delaunay but when we constrain cavity with color, - it is usefull */ -static HXTStatus isStarShaped(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t* blindFaceIndex) -{ - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - double *vtaCoord = vertices[vta].coord; - - for (uint64_t i=0; i<local->ball.num; i++) { - if(local->ball.array[i].node[2]!=HXT_GHOST_VERTEX){ - double* b = vertices[local->ball.array[i].node[0]].coord; - double* c = vertices[local->ball.array[i].node[1]].coord; - double* d = vertices[local->ball.array[i].node[2]].coord; - if(orient3d(vtaCoord, b, c, d)>=0.0){ - *blindFaceIndex = i; - return HXT_STATUS_INTERNAL; - } - } - } - return HXT_STATUS_OK; -} - - -static HXTStatus undeleteTetrahedron(TetLocal* local, HXTMesh* mesh, uint64_t tetToUndelete) { - // the tetrahedra should not be deleted anymore - for (uint64_t i=local->deleted.num; ; i--) { - if(local->deleted.array[i-1]==tetToUndelete) { - local->deleted.num--; - local->deleted.array[i-1] = local->deleted.array[local->deleted.num]; - break; - } -#ifdef DEBUG - if(i==1) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "could not find the tetrahedra in the deleted array"); -#endif - } - unsetDeletedFlag(mesh, tetToUndelete); - - uint64_t bndFaces[4] = {HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT}; - int nbndFace = 0; - - // we should update the boundary (that's the difficult part...) - // first remove all the boundary faces that come from the tetrahedron we just removed from the cavity - for (uint64_t i=local->ball.num; nbndFace<4 && i>0; i--) { - if(mesh->tetrahedra.neigh[local->ball.array[i-1].neigh]/4==tetToUndelete) { - bndFaces[nbndFace++] = local->ball.array[i-1].neigh; - local->ball.num--; - local->ball.array[i-1] = local->ball.array[local->ball.num]; - } - } - - // we must replace them by all the other faces of the tetrahedron we just removed - const uint64_t* __restrict__ curNeigh = mesh->tetrahedra.neigh + tetToUndelete*4; - const uint32_t* __restrict__ curNode = mesh->tetrahedra.node + tetToUndelete*4; - -#ifdef DEBUG - int nbndFace2 = (getDeletedFlag(mesh, curNeigh[0]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 0)) + - (getDeletedFlag(mesh, curNeigh[1]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 1)) + - (getDeletedFlag(mesh, curNeigh[2]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 2)) + - (getDeletedFlag(mesh, curNeigh[3]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 3)); - if(nbndFace!=nbndFace2) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "found %d non-deleted tet adjacent to the tet we unremove but there should be %d %lu %lu %lu %lu", nbndFace, nbndFace2, bndFaces[0], bndFaces[1], bndFaces[2], bndFaces[3]); -#endif - - HXT_CHECK( askForBall(local, 3) ); - - if(curNeigh[0]!=bndFaces[0] && curNeigh[0]!=bndFaces[1] && curNeigh[0]!=bndFaces[2] && curNeigh[0]!=bndFaces[3]) - bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 0) ) | - (getEdgeConstraint(mesh, tetToUndelete, 1)>>1) | // constraint on edge 1 (facet 0 2) goes on edge 0 - (getEdgeConstraint(mesh, tetToUndelete, 0)<<1) | // constraint on edge 0 (facet 0 1) goes on edge 1 - (getEdgeConstraint(mesh, tetToUndelete, 2) ), // constraint on edge 2 (facet 0 3) goes on edge 2 - curNode[2], curNode[1], curNode[3], 4*tetToUndelete+0); - - if(curNeigh[1]!=bndFaces[0] && curNeigh[1]!=bndFaces[1] && curNeigh[1]!=bndFaces[2] && curNeigh[1]!=bndFaces[3]) - bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 1)>>1) |// constraint on facet 1 goes on facet 0 - (getEdgeConstraint(mesh, tetToUndelete, 0) ) | // constraint on edge 0 (facet 1 0) goes on edge 0 - (getEdgeConstraint(mesh, tetToUndelete, 3)>>2) | // constraint on edge 3 (facet 1 2) goes on edge 1 - (getEdgeConstraint(mesh, tetToUndelete, 4)>>2), // constraint on edge 4 (facet 1 3) goes on edge 2 - curNode[0], curNode[2], curNode[3], 4*tetToUndelete+1); - - if(curNeigh[2]!=bndFaces[0] && curNeigh[2]!=bndFaces[1] && curNeigh[2]!=bndFaces[2] && curNeigh[2]!=bndFaces[3]) - bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 2)>>2) |// constraint on facet 2 goes on facet 0 - (getEdgeConstraint(mesh, tetToUndelete, 3)>>3) | // constraint on edge 3 (facet 2 1) goes on edge 0 - (getEdgeConstraint(mesh, tetToUndelete, 1) ) | // constraint on edge 1 (facet 2 0) goes on edge 1 - (getEdgeConstraint(mesh, tetToUndelete, 5)>>3), // constraint on edge 5 (facet 2 3) goes on edge 2 - curNode[1], curNode[0], curNode[3], 4*tetToUndelete+2); - - if(curNeigh[3]!=bndFaces[0] && curNeigh[3]!=bndFaces[1] && curNeigh[3]!=bndFaces[2] && curNeigh[3]!=bndFaces[3]) - bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 3)>>3) |// constraint on facet 3 goes on facet 0 - (getEdgeConstraint(mesh, tetToUndelete, 2)>>2) | // constraint on edge 2 (facet 3 0) goes on edge 0 - (getEdgeConstraint(mesh, tetToUndelete, 4)>>3) | // constraint on edge 4 (facet 3 1) goes on edge 1 - (getEdgeConstraint(mesh, tetToUndelete, 5)>>3), // constraint on edge 5 (facet 3 2) goes on edge 2 - curNode[0], curNode[1], curNode[2], 4*tetToUndelete+3); - - return HXT_STATUS_OK; -} - - -static HXTStatus reshapeCavityIfNeeded(TetLocal* local, HXTMesh* mesh, const uint32_t vta) { - // we will remove the tetrahedra adjacent to the face that does not see the point, progressively, until the cavity is star shaped... - uint64_t blindFace = 0; - - uint64_t count = 0; - - // TODO: optimize this part of the algorithm. - // 1: only the faces that were not yet tested for star-shapedness need to be tested - // 2: only mark the tet as not deleted, and push it on a stack. - // => finding the tet. in local->deleted.array should be done with an optimized algo - // 3: the face and flags should not be pushed directly if it is going to be removed... recursive strategy ?? - // 4 ??: maybe use the SPR in some cases - while(isStarShaped(local, mesh, vta, &blindFace)==HXT_STATUS_INTERNAL) - { - HXT_CHECK( undeleteTetrahedron(local, mesh, mesh->tetrahedra.neigh[local->ball.array[blindFace].neigh]/4) ); - count++; - } - - if(count) - printf("nbr of tet to undelete = %lu, nbr of deleted tet = %lu\n", count, local->deleted.num); - return HXT_STATUS_OK; -} - - -static HXTStatus respectEdgeConstraint(TetLocal* local, HXTMesh* mesh, const uint32_t vta, const uint32_t color, const uint64_t prevDeleted) { - // HXT_WARNING("a constrained edge was inside the cavity, recovering it"); - - // all the tetrahedron have the same color 'color', we will use that color to flag them - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { - uint64_t delTet = local->deleted.array[i]; - mesh->tetrahedra.color[delTet] = 0; - } - - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { - uint64_t delTet = local->deleted.array[i]; - int exist = 1; - for (int edge=0; exist && edge<6; edge++) { - if(getEdgeConstraint(mesh, delTet, edge) && (mesh->tetrahedra.color[delTet] & (1U<<edge))==0) { - unsigned in_facet; - unsigned out_facet; - - getFacetsFromEdge(edge, &in_facet, &out_facet); - - int edgeIsSafe = 0; - uint64_t curTet = delTet; - - // first turn - do - { - uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet]; - - // go into the neighbor through out_facet - uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; - curTet = neigh/4; - in_facet = neigh%4; - - uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; - for (out_facet=0; out_facet<3; out_facet++) - if(nodes[out_facet]==newV) - break; - - if(getDeletedFlag(mesh, curTet)!=0) { - // mark that the edge as been treate - #ifdef DEBUG - if((mesh->tetrahedra.color[curTet] & (1U<<getEdgeFromFacets(in_facet, out_facet)))!=0) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "the flag says that the tet has already been processed for this edge..."); - #endif - mesh->tetrahedra.color[curTet] |= (1U<<getEdgeFromFacets(in_facet, out_facet)); - } - else { - edgeIsSafe=1; - } - - } while (curTet!=delTet); - - if(!edgeIsSafe) { // we must find a tetrahedron on the opposite side of vta and delete it. - getFacetsFromEdge(edge, &in_facet, &out_facet); - curTet = delTet; - - uint64_t tetContainingVta = local->deleted.array[prevDeleted]; - uint64_t tetToUndelete = HXT_NO_ADJACENT; - double distMax = 0.0; - double* vtaCoord = mesh->vertices.coord + 4*vta; - - #ifdef DEBUG - double* a = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta]; - double* b = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+1]; - double* c = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+2]; - double* d = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+3]; - - if(orient3d(vtaCoord,b,c,d)>0.0 || orient3d(a,vtaCoord,c,d)>0.0 || orient3d(a,b,vtaCoord,d)>0.0 || orient3d(a,b,c,vtaCoord)>0.0) { - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "an edge part of a ghost tetrahedron is constrained"); - } - #endif - - // second turn - do - { - uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet]; - - // go into the neighbor through out_facet - uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; - curTet = neigh/4; - in_facet = neigh%4; - - uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; - for (out_facet=0; out_facet<3; out_facet++) - if(nodes[out_facet]==newV) - break; - - double* coord1 = mesh->vertices.coord + newV; - double* coord2 = mesh->vertices.coord + nodes[in_facet]; - - if(curTet!=tetContainingVta) { - double dist = 0.0; - for (int l=0; l<3; l++) { - double meanCoord = (coord1[l]+coord2[l])*0.5; - double diff = meanCoord-vtaCoord[l]; - dist += diff*diff; - } - - if(dist>distMax) { - dist = distMax; - tetToUndelete = curTet; - } - } - } while (curTet!=delTet); - - if(tetToUndelete==delTet) - exist = 0; - - // printf("undeleting tetrahedron %lu\n", tetToUndelete); - mesh->tetrahedra.color[tetToUndelete] = color; - HXT_CHECK( undeleteTetrahedron(local, mesh, tetToUndelete) ); - } - } - } - } - - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { - uint64_t delTet = local->deleted.array[i]; - mesh->tetrahedra.color[delTet] = color; - } - - return HXT_STATUS_OK; -} - - /* this function does a Breadth-first search of the tetrahedra in the cavity * it add those to local->deleted * it also maintain a local->ball array with all the information concerning the boundary of the cavity @@ -1206,16 +916,15 @@ static HXTStatus insertion(HXT2Sync* shared2sync, restoreDeleted(mesh, local, prevDeleted); return HXT_STATUS_CONFLICT; } - else{ - HXT_CHECK(status); - } + HXT_CHECK(status); if(!perfectDelaunay) { if(edgeConstraint) { + // printf("we have an edge constraint\n"); HXT_CHECK( respectEdgeConstraint(local, mesh, vta, color, prevDeleted) ); } // reshape the cavity if it is not star shaped - HXT_CHECK( reshapeCavityIfNeeded(local, mesh, vta) ); + HXT_CHECK( reshapeCavityIfNeeded(local, mesh, vta, prevDeleted) ); } diff --git a/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c b/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c new file mode 100644 index 0000000000000000000000000000000000000000..2f2381615de3910064b83cae6a68443c209edf2a --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c @@ -0,0 +1,370 @@ +#include "hxt_tetDelaunayReshape.h" +#include "hxt_tetFlag.h" +#include "predicates.h" +#include <stdint.h> + +/* check if the cavity is star shaped + This isn't usefull for pure Delaunay but when we constrain cavity with color, + it is usefull */ +static HXTStatus isStarShaped(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t* blindFaceIndex) +{ + HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; + double *vtaCoord = vertices[vta].coord; + + for (uint64_t i=0; i<local->ball.num; i++) { + if(local->ball.array[i].node[2]!=HXT_GHOST_VERTEX){ + double* b = vertices[local->ball.array[i].node[0]].coord; + double* c = vertices[local->ball.array[i].node[1]].coord; + double* d = vertices[local->ball.array[i].node[2]].coord; + if(orient3d(vtaCoord, b, c, d)>=0.0){ + *blindFaceIndex = i; + return HXT_STATUS_INTERNAL; + } + } + } + return HXT_STATUS_OK; +} + + +static HXTStatus undeleteTetrahedron(TetLocal* local, HXTMesh* mesh, uint64_t tetToUndelete) { + // the tetrahedra should not be deleted anymore + for (uint64_t i=local->deleted.num; ; i--) { + if(local->deleted.array[i-1]==tetToUndelete) { + local->deleted.num--; + local->deleted.array[i-1] = local->deleted.array[local->deleted.num]; + break; + } +#ifdef DEBUG + if(i==1) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "could not find the tetrahedra in the deleted array"); +#endif + } + unsetDeletedFlag(mesh, tetToUndelete); + + uint64_t bndFaces[4] = {HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT}; + int nbndFace = 0; + + // we should update the boundary (that's the difficult part...) + // first remove all the boundary faces that come from the tetrahedron we just removed from the cavity + for (uint64_t i=local->ball.num; nbndFace<4 && i>0; i--) { + if(mesh->tetrahedra.neigh[local->ball.array[i-1].neigh]/4==tetToUndelete) { + bndFaces[nbndFace++] = local->ball.array[i-1].neigh; + local->ball.num--; + local->ball.array[i-1] = local->ball.array[local->ball.num]; + } + } + + // we must replace them by all the other faces of the tetrahedron we just removed + const uint64_t* __restrict__ curNeigh = mesh->tetrahedra.neigh + tetToUndelete*4; + const uint32_t* __restrict__ curNode = mesh->tetrahedra.node + tetToUndelete*4; + +#ifdef DEBUG + int nbndFace2 = (getDeletedFlag(mesh, curNeigh[0]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 0)) + + (getDeletedFlag(mesh, curNeigh[1]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 1)) + + (getDeletedFlag(mesh, curNeigh[2]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 2)) + + (getDeletedFlag(mesh, curNeigh[3]/4)==0 || getFacetConstraint(mesh, tetToUndelete, 3)); + if(nbndFace!=nbndFace2) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "found %d non-deleted tet adjacent to the tet we unremove but there should be %d %lu %lu %lu %lu", nbndFace, nbndFace2, bndFaces[0], bndFaces[1], bndFaces[2], bndFaces[3]); +#endif + + HXT_CHECK( askForBall(local, 3) ); + + if(curNeigh[0]!=bndFaces[0] && curNeigh[0]!=bndFaces[1] && curNeigh[0]!=bndFaces[2] && curNeigh[0]!=bndFaces[3]) + bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 0) ) | + (getEdgeConstraint(mesh, tetToUndelete, 1)>>1) | // constraint on edge 1 (facet 0 2) goes on edge 0 + (getEdgeConstraint(mesh, tetToUndelete, 0)<<1) | // constraint on edge 0 (facet 0 1) goes on edge 1 + (getEdgeConstraint(mesh, tetToUndelete, 2) ), // constraint on edge 2 (facet 0 3) goes on edge 2 + curNode[2], curNode[1], curNode[3], 4*tetToUndelete+0); + + if(curNeigh[1]!=bndFaces[0] && curNeigh[1]!=bndFaces[1] && curNeigh[1]!=bndFaces[2] && curNeigh[1]!=bndFaces[3]) + bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 1)>>1) |// constraint on facet 1 goes on facet 0 + (getEdgeConstraint(mesh, tetToUndelete, 0) ) | // constraint on edge 0 (facet 1 0) goes on edge 0 + (getEdgeConstraint(mesh, tetToUndelete, 3)>>2) | // constraint on edge 3 (facet 1 2) goes on edge 1 + (getEdgeConstraint(mesh, tetToUndelete, 4)>>2), // constraint on edge 4 (facet 1 3) goes on edge 2 + curNode[0], curNode[2], curNode[3], 4*tetToUndelete+1); + + if(curNeigh[2]!=bndFaces[0] && curNeigh[2]!=bndFaces[1] && curNeigh[2]!=bndFaces[2] && curNeigh[2]!=bndFaces[3]) + bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 2)>>2) |// constraint on facet 2 goes on facet 0 + (getEdgeConstraint(mesh, tetToUndelete, 3)>>3) | // constraint on edge 3 (facet 2 1) goes on edge 0 + (getEdgeConstraint(mesh, tetToUndelete, 1) ) | // constraint on edge 1 (facet 2 0) goes on edge 1 + (getEdgeConstraint(mesh, tetToUndelete, 5)>>3), // constraint on edge 5 (facet 2 3) goes on edge 2 + curNode[1], curNode[0], curNode[3], 4*tetToUndelete+2); + + if(curNeigh[3]!=bndFaces[0] && curNeigh[3]!=bndFaces[1] && curNeigh[3]!=bndFaces[2] && curNeigh[3]!=bndFaces[3]) + bndPush(local, (getFacetConstraint(mesh, tetToUndelete, 3)>>3) |// constraint on facet 3 goes on facet 0 + (getEdgeConstraint(mesh, tetToUndelete, 2)>>2) | // constraint on edge 2 (facet 3 0) goes on edge 0 + (getEdgeConstraint(mesh, tetToUndelete, 4)>>3) | // constraint on edge 4 (facet 3 1) goes on edge 1 + (getEdgeConstraint(mesh, tetToUndelete, 5)>>3), // constraint on edge 5 (facet 3 2) goes on edge 2 + curNode[0], curNode[1], curNode[2], 4*tetToUndelete+3); + + return HXT_STATUS_OK; +} + + + +HXTStatus respectEdgeConstraint(TetLocal* local, HXTMesh* mesh, const uint32_t vta, const uint32_t color, const uint64_t prevDeleted) +{ + // HXT_WARNING("a constrained edge was inside the cavity, recovering it"); + + // all the tetrahedron have the same color 'color', we will use that color to flag them + for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { + uint64_t delTet = local->deleted.array[i]; + mesh->tetrahedra.color[delTet] = 0; + } + + for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { + uint64_t delTet = local->deleted.array[i]; + int exist = 1; + for (int edge=0; exist && edge<6; edge++) { + if(getEdgeConstraint(mesh, delTet, edge) && (mesh->tetrahedra.color[delTet] & (1U<<edge))==0) { + unsigned in_facet; + unsigned out_facet; + + getFacetsFromEdge(edge, &in_facet, &out_facet); + + int edgeIsSafe = 0; + uint64_t curTet = delTet; + + // first turn + do + { + uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet]; + + // go into the neighbor through out_facet + uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; + curTet = neigh/4; + in_facet = neigh%4; + + uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; + for (out_facet=0; out_facet<3; out_facet++) + if(nodes[out_facet]==newV) + break; + + if(getDeletedFlag(mesh, curTet)!=0) { + // mark that the edge as been treate + #ifdef DEBUG + if((mesh->tetrahedra.color[curTet] & (1U<<getEdgeFromFacets(in_facet, out_facet)))!=0) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "the flag says that the tet has already been processed for this edge..."); + #endif + mesh->tetrahedra.color[curTet] |= (1U<<getEdgeFromFacets(in_facet, out_facet)); + } + else { + edgeIsSafe=1; + } + + } while (curTet!=delTet); + + if(!edgeIsSafe) { // we must find a tetrahedron on the opposite side of vta and delete it. + getFacetsFromEdge(edge, &in_facet, &out_facet); + curTet = delTet; + + uint64_t tetContainingVta = local->deleted.array[prevDeleted]; + uint64_t tetToUndelete = HXT_NO_ADJACENT; + double distMax = 0.0; + double* vtaCoord = mesh->vertices.coord + 4*vta; + + #ifdef DEBUG + double* a = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta]; + double* b = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+1]; + double* c = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+2]; + double* d = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+3]; + + if(orient3d(vtaCoord,b,c,d)>0.0 || orient3d(a,vtaCoord,c,d)>0.0 || orient3d(a,b,vtaCoord,d)>0.0 || orient3d(a,b,c,vtaCoord)>0.0) { + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "an edge part of a ghost tetrahedron is constrained"); + } + #endif + + // second turn + do + { + uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet]; + + // go into the neighbor through out_facet + uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; + curTet = neigh/4; + in_facet = neigh%4; + + uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; + for (out_facet=0; out_facet<3; out_facet++) + if(nodes[out_facet]==newV) + break; + + double* coord1 = mesh->vertices.coord + newV; + double* coord2 = mesh->vertices.coord + nodes[in_facet]; + + if(curTet!=tetContainingVta) { + double dist = 0.0; + for (int l=0; l<3; l++) { + double meanCoord = (coord1[l]+coord2[l])*0.5; + double diff = meanCoord-vtaCoord[l]; + dist += diff*diff; + } + + if(dist>distMax) { + dist = distMax; + tetToUndelete = curTet; + } + } + } while (curTet!=delTet); + + if(tetToUndelete==delTet) + exist = 0; + + // printf("undeleting tetrahedron %lu\n", tetToUndelete); + mesh->tetrahedra.color[tetToUndelete] = color; + HXT_CHECK( undeleteTetrahedron(local, mesh, tetToUndelete) ); + } + } + } + } + + for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { + uint64_t delTet = local->deleted.array[i]; + mesh->tetrahedra.color[delTet] = color; + } + + return HXT_STATUS_OK; +} + + +// functions above should be replaced + + + + + + + + + + + + + +#define BND_FACE_FLAG (UINT64_C(1)<<63) + +// remove the tetrahedra adjacent to the face that does not see the point, progressively, until the cavity is star shaped... +HXTStatus reshapeCavityIfNeeded(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t prevNumDeleted) +{ + uint64_t count = 0; + + // STEP 1: for each ball faces, we need the index of the tet in the deleted array, instead of the index of the tet in the mesh + // for each deleted tet, we need the index of the 4 faces in the ball, or the index of the neighbor in the deleted array + // if the facet is not a facet of the cavity. To differentiate both, BND_FACE_FLAG is set for indices of the ball. + uint64_t numTet = local->deleted.num - prevNumDeleted; + uint64_t* tets = &local->deleted.array[prevNumDeleted]; + uint64_t* faces; + HXT_CHECK( hxtMalloc(&faces, sizeof(uint64_t) * 4 * numTet) ); + + for(uint64_t i=0; i<4*numTet; i++) { + faces[i] = 0; + } + + // A priori, the order in which the delete tet appear and the order in which the faces appear should match (see @diggingACavity) + uint64_t tetToFind = mesh->tetrahedra.neigh[local->ball.array[0].neigh]; + uint64_t curFace = 0; + uint64_t curTet = 0; + while(curTet<numTet) { + if(tets[curTet] == tetToFind / 4) { + uint64_t index = 4 * curTet + tetToFind % 4; + local->ball.array[curFace].neigh = index; + faces[index] = curFace; + curFace++; + + if(curFace >= local->ball.num) + break; + + tetToFind = mesh->tetrahedra.neigh[local->ball.array[curFace].neigh]; + } + else { + curTet++; + } + } + + if(curFace < local->ball.num) { + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "DEBUG: Faces did not appear in the same order as deleted tet"); + } + + // double *vtaCoord = &mesh->vertices.coord[4 * vta]; + + // // STEP 2: for each face that does not see vta, delete the associated tet, and update the boundary of the cavity + // for (uint64_t curFace=0; curFace<local->ball.num; curFace++) { + // if(local->ball.array[curFace].node[2]==HXT_GHOST_VERTEX){ + // continue; + // } + + // double* b = &mesh->vertices.coord[4 * local->ball.array[curFace].node[0]]; + // double* c = &mesh->vertices.coord[4 * local->ball.array[curFace].node[1]]; + // double* d = &mesh->vertices.coord[4 * local->ball.array[curFace].node[2]]; + // if(orient3d(vtaCoord, b, c, d)<0.0){ + // continue; + // } + + // // 2.1 update the facets so that no facet points to the current tet... does not work with our structure. SHITTT !! + // // => we are forced to use an O(n^2) algo if we do not want to use a super large table + + // // 2.2: undelete the tetrahedron + // uint64_t index = local->ball.array[curFace].neigh; + // uint64_t tetToUndelete = local->deleted.array[index / 4]; + // unsigned facet = index % 4; + // unsetDeletedFlag(mesh, tetToUndelete); + + + + // // second part: remove the faces of the tet that were on the boundary + // // do not forget to update curFace to point just before the next face to process + // uint64_t bndFaces[4] = {HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT}; + // int nbndFace = 0; + + // // the way that the boundary faces are contructed, + // // TODO: use a bidirectional structure to be able to find the faces of deleted tet. + + // // face to delete: curface + + // for (uint64_t i=local->ball.num; nbndFace<4 && i>0; i--) { + // if(mesh->tetrahedra.neigh[local->ball.array[i-1].neigh]/4==tetToUndelete) { + // bndFaces[nbndFace++] = local->ball.array[i-1].neigh; + // local->ball.num--; + // local->ball.array[i-1] = local->ball.array[local->ball.num]; + // } + // } + + + // // third part: add new facets to the boundary + + // count++; + // } + + // if(count) + // printf("nbr of tet to undelete = %lu, nbr of deleted tet = %lu\n", count, local->deleted.num); + + // // STEP 3: compute all the flags at once ! ?? + + + // STEP 4: put back the right neighbor value inside the ball struct + for(uint64_t i=0; i<local->ball.num; i++) { + uint64_t index = local->ball.array[i].neigh; + uint64_t interiorTet = tets[index / 4]; + unsigned facet = index % 4; + local->ball.array[i].neigh = mesh->tetrahedra.neigh[4 * interiorTet + facet]; + } + + + HXT_CHECK( hxtFree(&faces) ); + + + uint64_t blindFace = 0; + + // TODO: optimize this part of the algorithm. + // 1: only the faces that were not yet tested for star-shapedness need to be tested + // 2: only mark the tet as not deleted, and push it on a stack. + // => finding the tet. in local->deleted.array should be done with an optimized algo + // 3: the face and flags should not be pushed directly if it is going to be removed... recursive strategy ?? + // 4 ??: maybe use the SPR in some cases + while(isStarShaped(local, mesh, vta, &blindFace)==HXT_STATUS_INTERNAL) + { + HXT_CHECK( undeleteTetrahedron(local, mesh, mesh->tetrahedra.neigh[local->ball.array[blindFace].neigh]/4) ); + } + + return HXT_STATUS_OK; +} diff --git a/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.h b/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.h new file mode 100644 index 0000000000000000000000000000000000000000..30bea1d327ea97c224b1b185393d27fe44c03777 --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.h @@ -0,0 +1,73 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETDELAUNAY_RESHAPE_H +#define HXT_TETDELAUNAY_RESHAPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hxt_mesh.h" +#include "hxt_tetSync.h" +#include "hxt_tetPartition.h" + +typedef struct { + uint64_t neigh; // the tet on the other side of the boundary + uint32_t node[3]; + uint16_t flag; +} cavityBnd_t; + + +typedef struct { + uint64_t hxtDeclareAligned Map[1024]; + + struct { + cavityBnd_t* array; + uint64_t num; + uint64_t size; + } ball; + + HXTDeleted deleted; + HXTPartition partition; +} TetLocal; + +/* pushing cavity boundary information to local->ball */ +static inline void bndPush( TetLocal* local, uint16_t flag, + const uint32_t node1, const uint32_t node2, + const uint32_t node3, const uint64_t neigh){ + uint64_t n = local->ball.num; + local->ball.array[n].node[0] = node1; + local->ball.array[n].node[1] = node2; + local->ball.array[n].node[2] = node3; + local->ball.array[n].flag = flag; + local->ball.array[n].neigh = neigh; + local->ball.num++; +} + +static inline HXTStatus askForBall(TetLocal* local, uint64_t needed) { + needed += local->ball.num; + if(needed>local->ball.size) { + HXT_CHECK( hxtAlignedRealloc(&local->ball.array, sizeof(cavityBnd_t)*2*needed) ); + local->ball.size = 2*needed; + } + return HXT_STATUS_OK; +} + + +// TODO: it only needs the ball and the deleted... no need to know about the whole tetLocal structure +HXTStatus reshapeCavityIfNeeded(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t prevNumDeleted); +HXTStatus respectEdgeConstraint(TetLocal* local, HXTMesh* mesh, const uint32_t vta, const uint32_t color, const uint64_t prevDeleted); + + + +#ifdef __cplusplus +} +#endif + +#endif