diff --git a/Fltk/onelabGroup.cpp b/Fltk/onelabGroup.cpp index 6097b6a2d05029b0d62251ab731adff8d1db0041..4b276dd7057347789b2d96ee23523b42e3e6868f 100644 --- a/Fltk/onelabGroup.cpp +++ b/Fltk/onelabGroup.cpp @@ -386,31 +386,24 @@ bool gmshLocalNetworkClient::run() setGmshServer(server); while(1) { - // loop on all the clients (usually only one, but can be more if we spawned - // subclients; in that case we might want to start from the one after the - // one we read from last, for better load balancing) - bool stop = false, haveData = false; - gmshLocalNetworkClient *c = 0; - if(getExecutable().empty() && !CTX::instance()->solver.listen){ // we stopped listening to the special "Listen" client - stop = true; break; } + // loop on all the clients (usually only one, but can be more if we spawned + // subclients; in that case we might want to start from the one after the + // one we read from last, for better load balancing) + bool stop = false, haveData = false; + gmshLocalNetworkClient *c = 0; for(int i = 0; i < getNumClients(); i++){ - if(getExecutable().empty() && !CTX::instance()->solver.listen){ - // we stopped listening to the special "Listen" client - stop = true; - break; - } c = getClient(i); if(c->getPid() < 0){ if(c == this){ // the "master" client stopped stop = true; break; } - else{ // this subclient is not active anymore + else{ // this subclient is not active anymore: pass to the next client continue; } } @@ -422,13 +415,11 @@ bool gmshLocalNetworkClient::run() } else{ int ret = s->NonBlockingWait(0.001, -1.); - if(ret == 0){ - // we have data from this particular client + if(ret == 0){ // we have data from this particular client haveData = true; break; } - else if(ret == 3){ - // pass to the next client + else if(ret == 3){ // pass to the next client continue; } else{ // an error occurred diff --git a/contrib/Tetgen1.5/predicates.cxx b/contrib/Tetgen1.5/predicates.cxx index 4120704c3521a80f27aa144feb1387ccf78c66a2..a4b77b69fe546cf1cf43491ab064963dfc842a60 100644 --- a/contrib/Tetgen1.5/predicates.cxx +++ b/contrib/Tetgen1.5/predicates.cxx @@ -149,8 +149,8 @@ /* which is disastrously slow. A faster way on IEEE machines might be to */ /* mask the appropriate bit, but that's difficult to do in C. */ -#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) -/* #define Absolute(a) fabs(a) */ +//#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +#define Absolute(a) fabs(a) /* Many of the operations are broken up into two pieces, a main part that */ /* performs an approximate operation, and a "tail" that computes the */ @@ -375,6 +375,24 @@ static REAL o3derrboundA, o3derrboundB, o3derrboundC; static REAL iccerrboundA, iccerrboundB, iccerrboundC; static REAL isperrboundA, isperrboundB, isperrboundC; +// Options to choose types of geometric computtaions. +// Added by H. Si, 2012-08-23. +static int _use_inexact_arith; // -X option. +static int _use_static_filter; // -S option. + +// Static filters. Added by H. Si, 2012-08-23. +static REAL o3dstaticfilter; +static REAL ispstaticfilter; + +#ifndef NDEBUG +// Counters for counting the number of calls. Added by H. Si, 2012-08-23. +long ori3dcount, ori3dadaptcount; +long insphcount, insphadaptcount, insphexactcount; +long ori4dcount, ori4dadaptcount, ori4dexactcount; +long o3dfilterfailscount; +long ispfilterfailscount; +#endif // #ifndef NDEBUG + /*****************************************************************************/ /* */ /* doubleprint() Print the bit representation of a double. */ @@ -660,7 +678,7 @@ float uniformfloatrand() /* */ /*****************************************************************************/ -REAL exactinit() +void exactinit(int noexact, int nofilter, REAL maxx, REAL maxy, REAL maxz) { REAL half; REAL check, lastcheck; @@ -722,7 +740,36 @@ REAL exactinit() isperrboundB = (5.0 + 72.0 * epsilon) * epsilon; isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon; - return epsilon; /* Added by H. Si 30 Juli, 2004. */ + _use_inexact_arith = noexact; + _use_static_filter = !nofilter; + + // Sort maxx < maxy < maxz. Re-use 'half' for swapping. + assert(maxx > 0); + assert(maxy > 0); + assert(maxz > 0); + + if (maxx > maxz) { + half = maxx; maxx = maxz; maxz = half; + } + if (maxy > maxz) { + half = maxy; maxy = maxz; maxz = half; + } + else if (maxy < maxx) { + half = maxy; maxy = maxx; maxx = half; + } + + // Calculate the static filters. + o3dstaticfilter = 5.1107127829973299e-15 * maxx * maxy * maxz; + ispstaticfilter = 1.2466136531027298e-13 * maxx * maxy * maxz * (maxz * maxz); + +#ifndef NDEBUG + // Clear the counters. + ori3dcount = ori3dadaptcount = 0l; + insphcount = insphadaptcount = insphexactcount = 0l; + ori4dcount = ori4dadaptcount = ori4dexactcount = 0l; + o3dfilterfailscount = 0l; + ispfilterfailscount = 0l; +#endif // #ifndef NDEBUG } /*****************************************************************************/ @@ -1869,16 +1916,6 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) REAL fin1[192], fin2[192]; int finlength; - //////////////////////////////////////////////////////// - // To avoid uninitialized warnings reported by valgrind. - int i; - for (i = 0; i < 8; i++) { - adet[i] = bdet[i] = cdet[i] = 0.0; - } - for (i = 0; i < 16; i++) { - abdet[i] = 0.0; - } - //////////////////////////////////////////////////////// REAL adxtail, bdxtail, cdxtail; REAL adytail, bdytail, cdytail; @@ -1916,6 +1953,10 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) INEXACT REAL _i, _j, _k; REAL _0; +#ifndef NDEBUG + ori3dadaptcount++; +#endif // #ifndef NDEBUG + adx = (REAL) (pa[0] - pd[0]); bdx = (REAL) (pb[0] - pd[0]); cdx = (REAL) (pc[0] - pd[0]); @@ -2263,31 +2304,6 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) return finnow[finlength - 1]; } -#ifdef INEXACT_GEOM_PRED - -REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) -{ - REAL adx, bdx, cdx; - REAL ady, bdy, cdy; - REAL adz, bdz, cdz; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - adz = pa[2] - pd[2]; - bdz = pb[2] - pd[2]; - cdz = pc[2] - pd[2]; - - return adx * (bdy * cdz - bdz * cdy) - + bdx * (cdy * adz - cdz * ady) - + cdx * (ady * bdz - adz * bdy); -} - -#else - REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; @@ -2295,6 +2311,10 @@ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) REAL det; REAL permanent, errbound; +#ifndef NDEBUG + ori3dcount++; +#endif // #ifndef NDEBUG + adx = pa[0] - pd[0]; bdx = pb[0] - pd[0]; cdx = pc[0] - pd[0]; @@ -2318,6 +2338,19 @@ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady); + if (_use_inexact_arith) { + return det; + } + + if (_use_static_filter) { + if (fabs(det) > o3dstaticfilter) return det; + //if (det > o3dstaticfilter) return det; + //if (det < minus_o3dstaticfilter) return det; +#ifndef NDEBUG + o3dfilterfailscount++; +#endif // #ifndef NDEBUG + } + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); @@ -2329,8 +2362,6 @@ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) return orient3dadapt(pa, pb, pc, pd, permanent); } -#endif // ifdef INEXACT_GEOM_PRED - /*****************************************************************************/ /* */ /* incirclefast() Approximate 2D incircle test. Nonrobust. */ @@ -3362,6 +3393,10 @@ REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) INEXACT REAL _i, _j; REAL _0; +#ifndef NDEBUG + insphexactcount++; +#endif // #ifndef NDEBUG + Two_Product(pa[0], pb[1], axby1, axby0); Two_Product(pb[0], pa[1], bxay1, bxay0); Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); @@ -3938,6 +3973,10 @@ REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, INEXACT REAL _i, _j; REAL _0; +#ifndef NDEBUG + insphadaptcount++; +#endif // #ifndef NDEBUG + aex = (REAL) (pa[0] - pe[0]); bex = (REAL) (pb[0] - pe[0]); cex = (REAL) (pc[0] - pe[0]); @@ -4114,52 +4153,6 @@ REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, return insphereexact(pa, pb, pc, pd, pe); } -#ifdef INEXACT_GEOM_PRED - -REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) -{ - REAL aex, bex, cex, dex; - REAL aey, bey, cey, dey; - REAL aez, bez, cez, dez; - REAL alift, blift, clift, dlift; - REAL ab, bc, cd, da, ac, bd; - REAL abc, bcd, cda, dab; - - aex = pa[0] - pe[0]; - bex = pb[0] - pe[0]; - cex = pc[0] - pe[0]; - dex = pd[0] - pe[0]; - aey = pa[1] - pe[1]; - bey = pb[1] - pe[1]; - cey = pc[1] - pe[1]; - dey = pd[1] - pe[1]; - aez = pa[2] - pe[2]; - bez = pb[2] - pe[2]; - cez = pc[2] - pe[2]; - dez = pd[2] - pe[2]; - - ab = aex * bey - bex * aey; - bc = bex * cey - cex * bey; - cd = cex * dey - dex * cey; - da = dex * aey - aex * dey; - - ac = aex * cey - cex * aey; - bd = bex * dey - dex * bey; - - abc = aez * bc - bez * ac + cez * ab; - bcd = bez * cd - cez * bd + dez * bc; - cda = cez * da + dez * ac + aez * cd; - dab = dez * ab + aez * bd + bez * da; - - alift = aex * aex + aey * aey + aez * aez; - blift = bex * bex + bey * bey + bez * bez; - clift = cex * cex + cey * cey + cez * cez; - dlift = dex * dex + dey * dey + dez * dez; - - return (dlift * abc - clift * dab) + (blift * cda - alift * bcd); -} -#else - REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { REAL aex, bex, cex, dex; @@ -4170,12 +4163,11 @@ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) REAL alift, blift, clift, dlift; REAL ab, bc, cd, da, ac, bd; REAL abc, bcd, cda, dab; - REAL aezplus, bezplus, cezplus, dezplus; - REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; - REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; - REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; REAL det; - REAL permanent, errbound; + +#ifndef NDEBUG + insphcount++; +#endif // #ifndef NDEBUG aex = pa[0] - pe[0]; bex = pb[0] - pe[0]; @@ -4222,6 +4214,25 @@ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); + if (_use_inexact_arith) { + return det; + } + + if (_use_static_filter) { + if (fabs(det) > ispstaticfilter) return det; + //if (det > ispstaticfilter) return det; + //if (det < minus_ispstaticfilter) return det; +#ifndef NDEBUG + ispfilterfailscount++; +#endif // #ifndef NDEBUG + } + + REAL aezplus, bezplus, cezplus, dezplus; + REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; + REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; + REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; + REAL permanent, errbound; + aezplus = Absolute(aez); bezplus = Absolute(bez); cezplus = Absolute(cez); @@ -4262,8 +4273,6 @@ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) return insphereadapt(pa, pb, pc, pd, pe, permanent); } -#endif // #ifdef INEXACT_GEOM_PRED - /*****************************************************************************/ /* */ /* orient4d() Return a positive value if the point pe lies above the */ @@ -4327,6 +4336,10 @@ REAL orient4dexact(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, INEXACT REAL _i, _j; REAL _0; +#ifndef NDEBUG + ori4dexactcount++; +#endif // #ifndef NDEBUG + Two_Product(pa[0], pb[1], axby1, axby0); Two_Product(pb[0], pa[1], bxay1, bxay0); Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); @@ -4540,6 +4553,10 @@ REAL orient4dadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, INEXACT REAL _i, _j; REAL _0; +#ifndef NDEBUG + ori4dadaptcount++; +#endif // #ifndef NDEBUG + aex = (REAL) (pa[0] - pe[0]); bex = (REAL) (pb[0] - pe[0]); cex = (REAL) (pc[0] - pe[0]); @@ -4699,108 +4716,135 @@ REAL orient4d(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, REAL aheight, REAL bheight, REAL cheight, REAL dheight, REAL eheight) { - REAL aex, bex, cex, dex; - REAL aey, bey, cey, dey; - REAL aez, bez, cez, dez; - REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; - REAL aexcey, cexaey, bexdey, dexbey; - REAL aeheight, beheight, ceheight, deheight; - REAL ab, bc, cd, da, ac, bd; - REAL abc, bcd, cda, dab; - REAL aezplus, bezplus, cezplus, dezplus; - REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; - REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; - REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; - REAL det; - REAL permanent, errbound; - - //orient4dcount++; - - aex = pa[0] - pe[0]; - bex = pb[0] - pe[0]; - cex = pc[0] - pe[0]; - dex = pd[0] - pe[0]; - aey = pa[1] - pe[1]; - bey = pb[1] - pe[1]; - cey = pc[1] - pe[1]; - dey = pd[1] - pe[1]; - aez = pa[2] - pe[2]; - bez = pb[2] - pe[2]; - cez = pc[2] - pe[2]; - dez = pd[2] - pe[2]; - aeheight = aheight - eheight; - beheight = bheight - eheight; - ceheight = cheight - eheight; - deheight = dheight - eheight; - - aexbey = aex * bey; - bexaey = bex * aey; - ab = aexbey - bexaey; - bexcey = bex * cey; - cexbey = cex * bey; - bc = bexcey - cexbey; - cexdey = cex * dey; - dexcey = dex * cey; - cd = cexdey - dexcey; - dexaey = dex * aey; - aexdey = aex * dey; - da = dexaey - aexdey; - - aexcey = aex * cey; - cexaey = cex * aey; - ac = aexcey - cexaey; - bexdey = bex * dey; - dexbey = dex * bey; - bd = bexdey - dexbey; - - abc = aez * bc - bez * ac + cez * ab; - bcd = bez * cd - cez * bd + dez * bc; - cda = cez * da + dez * ac + aez * cd; - dab = dez * ab + aez * bd + bez * da; + REAL aex, bex, cex, dex; + REAL aey, bey, cey, dey; + REAL aez, bez, cez, dez; + REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; + REAL aexcey, cexaey, bexdey, dexbey; + REAL aeheight, beheight, ceheight, deheight; + REAL ab, bc, cd, da, ac, bd; + REAL abc, bcd, cda, dab; + REAL aezplus, bezplus, cezplus, dezplus; + REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; + REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; + REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; + REAL det; + REAL permanent, errbound; + +#ifndef NDEBUG + ori4dcount++; +#endif // #ifndef NDEBUG + + aex = pa[0] - pe[0]; + bex = pb[0] - pe[0]; + cex = pc[0] - pe[0]; + dex = pd[0] - pe[0]; + aey = pa[1] - pe[1]; + bey = pb[1] - pe[1]; + cey = pc[1] - pe[1]; + dey = pd[1] - pe[1]; + aez = pa[2] - pe[2]; + bez = pb[2] - pe[2]; + cez = pc[2] - pe[2]; + dez = pd[2] - pe[2]; + aeheight = aheight - eheight; + beheight = bheight - eheight; + ceheight = cheight - eheight; + deheight = dheight - eheight; + + aexbey = aex * bey; + bexaey = bex * aey; + ab = aexbey - bexaey; + bexcey = bex * cey; + cexbey = cex * bey; + bc = bexcey - cexbey; + cexdey = cex * dey; + dexcey = dex * cey; + cd = cexdey - dexcey; + dexaey = dex * aey; + aexdey = aex * dey; + da = dexaey - aexdey; + + aexcey = aex * cey; + cexaey = cex * aey; + ac = aexcey - cexaey; + bexdey = bex * dey; + dexbey = dex * bey; + bd = bexdey - dexbey; + + abc = aez * bc - bez * ac + cez * ab; + bcd = bez * cd - cez * bd + dez * bc; + cda = cez * da + dez * ac + aez * cd; + dab = dez * ab + aez * bd + bez * da; + + det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * bcd); + + aezplus = Absolute(aez); + bezplus = Absolute(bez); + cezplus = Absolute(cez); + dezplus = Absolute(dez); + aexbeyplus = Absolute(aexbey); + bexaeyplus = Absolute(bexaey); + bexceyplus = Absolute(bexcey); + cexbeyplus = Absolute(cexbey); + cexdeyplus = Absolute(cexdey); + dexceyplus = Absolute(dexcey); + dexaeyplus = Absolute(dexaey); + aexdeyplus = Absolute(aexdey); + aexceyplus = Absolute(aexcey); + cexaeyplus = Absolute(cexaey); + bexdeyplus = Absolute(bexdey); + dexbeyplus = Absolute(dexbey); + permanent = ((cexdeyplus + dexceyplus) * bezplus + + (dexbeyplus + bexdeyplus) * cezplus + + (bexceyplus + cexbeyplus) * dezplus) + * Absolute(aeheight) + + ((dexaeyplus + aexdeyplus) * cezplus + + (aexceyplus + cexaeyplus) * dezplus + + (cexdeyplus + dexceyplus) * aezplus) + * Absolute(beheight) + + ((aexbeyplus + bexaeyplus) * dezplus + + (bexdeyplus + dexbeyplus) * aezplus + + (dexaeyplus + aexdeyplus) * bezplus) + * Absolute(ceheight) + + ((bexceyplus + cexbeyplus) * aezplus + + (cexaeyplus + aexceyplus) * bezplus + + (aexbeyplus + bexaeyplus) * cezplus) + * Absolute(deheight); + errbound = isperrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return orient4dadapt(pa, pb, pc, pd, pe, + aheight, bheight, cheight, dheight, eheight, permanent); +} - det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * bcd); - if (0) { //if (noexact) { - return det; +void predicates_statistics(int weighted) +{ +#ifndef NDEBUG + printf(" Number of orient3d tests: %ld\n", ori3dcount); + if (_use_static_filter) { + printf(" Number of static filter fails: %ld\n", o3dfilterfailscount); } - - aezplus = Absolute(aez); - bezplus = Absolute(bez); - cezplus = Absolute(cez); - dezplus = Absolute(dez); - aexbeyplus = Absolute(aexbey); - bexaeyplus = Absolute(bexaey); - bexceyplus = Absolute(bexcey); - cexbeyplus = Absolute(cexbey); - cexdeyplus = Absolute(cexdey); - dexceyplus = Absolute(dexcey); - dexaeyplus = Absolute(dexaey); - aexdeyplus = Absolute(aexdey); - aexceyplus = Absolute(aexcey); - cexaeyplus = Absolute(cexaey); - bexdeyplus = Absolute(bexdey); - dexbeyplus = Absolute(dexbey); - permanent = ((cexdeyplus + dexceyplus) * bezplus - + (dexbeyplus + bexdeyplus) * cezplus - + (bexceyplus + cexbeyplus) * dezplus) - * aeheight - + ((dexaeyplus + aexdeyplus) * cezplus - + (aexceyplus + cexaeyplus) * dezplus - + (cexdeyplus + dexceyplus) * aezplus) - * beheight - + ((aexbeyplus + bexaeyplus) * dezplus - + (bexdeyplus + dexbeyplus) * aezplus - + (dexaeyplus + aexdeyplus) * bezplus) - * ceheight - + ((bexceyplus + cexbeyplus) * aezplus - + (cexaeyplus + aexceyplus) * bezplus - + (aexbeyplus + bexaeyplus) * cezplus) - * deheight; - errbound = isperrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - return det; + if (!_use_inexact_arith) { + printf(" Number of orient3dadapt tests: %ld\n", ori3dadaptcount); } - - return orient4dadapt(pa, pb, pc, pd, pe, - aheight, bheight, cheight, dheight, eheight, permanent); + if (!weighted) { + printf(" Number of insphere tests: %ld\n", insphcount); + if (_use_static_filter) { + printf(" Number of static filter fails: %ld\n", ispfilterfailscount); + } + if (!_use_inexact_arith) { + printf(" Number of insphereadapt tests: %ld\n", insphadaptcount); + printf(" Number of insphereexact tests: %ld\n", insphexactcount); + } + } else { + printf(" Number of orient4d tests: %ld\n", ori4dcount); + printf(" Number of orient4dadapt tests: %ld\n", ori4dadaptcount); + printf(" Number of orient4dexact tests: %ld\n", ori4dexactcount); + } +#endif // #ifndef NDEBUG } + diff --git a/contrib/Tetgen1.5/tetgen.cxx b/contrib/Tetgen1.5/tetgen.cxx index 0a66de153c7e2825e01c02a2f1fdb01be35381ed..305d61b60a420fa4be0c1064abc5375a5b2d3aac 100644 --- a/contrib/Tetgen1.5/tetgen.cxx +++ b/contrib/Tetgen1.5/tetgen.cxx @@ -5,11 +5,7 @@ // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // // // // Version 1.5 // -// February 21, 2012 // -// // -// PRE-RELEASE TEST CODE. // -// PLEASE DO NOT DISTRIBUTE !! // -// PLEASE HELP ME TO IMPROVE IT !! // +// October 06, 2012 // // // // Copyright (C) 2002--2012 // // Hang Si // @@ -335,6 +331,10 @@ bool tetgenio::load_edge(char* filebasename) } edgelist[index++] = corner; } + if (numberofcorners == 10) { + // Skip an extra vertex (generated by a previous -o2 option). + stringptr = findnextnumber(stringptr); + } // Read the edge marker if it has. if (markers) { stringptr = findnextnumber(stringptr); @@ -419,6 +419,12 @@ bool tetgenio::load_face(char* filebasename) } trifacelist[index++] = corner; } + if (numberofcorners == 10) { + // Skip 3 extra vertices (generated by a previous -o2 option). + for (j = 0; j < 3; j++) { + stringptr = findnextnumber(stringptr); + } + } // Read the boundary marker if it exists. if (markers) { stringptr = findnextnumber(stringptr); @@ -627,7 +633,6 @@ bool tetgenio::load_var(char* filebasename) if (infile != (FILE *) NULL) { printf("Opening %s.\n", varfilename); } else { - // No such file. Ignore it without a message. return false; } @@ -740,7 +745,6 @@ bool tetgenio::load_mtr(char* filebasename) if (infile != (FILE *) NULL) { printf("Opening %s.\n", mtrfilename); } else { - // No such file. Return. return false; } @@ -1381,14 +1385,11 @@ bool tetgenio::load_off(char* filebasename) return false; } - // Check whether read all points if (iverts != nverts) { printf("Expected %d vertices, but read only %d vertices in file %s\n", nverts, iverts, infilename); return false; } - - // Check whether read all faces if (ifaces != nfaces) { printf("Expected %d faces, but read only %d faces in file %s\n", nfaces, ifaces, infilename); @@ -1603,14 +1604,11 @@ bool tetgenio::load_ply(char* filebasename) return false; } - // Check whether read all points if (iverts != nverts) { printf("Expected %d vertices, but read only %d vertices in file %s\n", nverts, iverts, infilename); return false; } - - // Check whether read all faces if (ifaces != nfaces) { printf("Expected %d faces, but read only %d faces in file %s\n", nfaces, ifaces, infilename); @@ -2389,6 +2387,7 @@ bool tetgenio::load_plc(char* filebasename, int object) } if (success) { + // Try to load the following files (.edge, .var, .mtr). load_edge(filebasename); load_var(filebasename); load_mtr(filebasename); @@ -2415,6 +2414,7 @@ bool tetgenio::load_tetmesh(char* filebasename, int object) success = load_tet(filebasename); } if (success) { + // Try to load the following files (.face, .edge, .vol). load_face(filebasename); load_edge(filebasename); load_vol(filebasename); @@ -2422,6 +2422,7 @@ bool tetgenio::load_tetmesh(char* filebasename, int object) } if (success) { + // Try to load the following files (.var, .mtr). load_var(filebasename); load_mtr(filebasename); } @@ -2902,16 +2903,22 @@ char* tetgenio::findnextnumber(char *string) void tetgenbehavior::syntax() { - printf(" tetgen [-pYrq_a_AiS_T_dzfenvgKJBNEFICQVh] input_file\n"); + printf(" tetgen [-pYq_Aa_mriO_S_T_XMwcdzfenvgKJBNEFICQVh] input_file\n"); printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n"); - printf(" -Y No splitting of input boundaries (facets and segments).\n"); - printf(" -r Reconstructs a previously generated mesh.\n"); + printf(" -Y Preserves the input surface mesh (does not modify it).\n"); printf(" -q Refines mesh (to improve mesh quality).\n"); - printf(" -a Applies a maximum tetrahedron volume constraint.\n"); printf(" -A Assigns attributes to tetrahedra in different regions.\n"); - printf(" -i Inserts a list of additional points into mesh.\n"); + printf(" -a Applies a maximum tetrahedron volume constraint.\n"); + printf(" -m Applies a mesh sizing function.\n"); + printf(" -r Reconstructs a previously generated mesh.\n"); + printf(" -i Inserts a list of additional points.\n"); + printf(" -O Specifies the level of mesh optimization.\n"); printf(" -S Specifies maximum number of added points.\n"); printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n"); + printf(" -X Suppresses use of exact arithmetic.\n"); + printf(" -M No merge of coplanar facets.\n"); + printf(" -w Generates weighted Delaunay (regular) triangulation.\n"); + printf(" -c Retains the convex hull of the PLC.\n"); printf(" -d Detects self-intersections of facets of the PLC.\n"); printf(" -z Numbers all output items starting from zero.\n"); printf(" -f Outputs all faces to .face file.\n"); @@ -3004,19 +3011,6 @@ void tetgenbehavior::usage() // of a C/C++ program. They together represent the command line user invoked // // from an environment in which TetGen is running. // // // -// When TetGen is invoked from an environment. 'argc' is nonzero, switches // -// and input filename should be supplied as zero-terminated strings in // -// argv[0] through argv[argc - 1] and argv[0] shall be the name used to // -// invoke TetGen, i.e. "tetgen". Switches are previously started with a // -// dash '-' to identify them from the input filename. // -// // -// When TetGen is called from within another program. 'argc' is set to zero. // -// switches are given in one zero-terminated string (no previous dash is // -// required.), and 'argv' is a pointer points to this string. No input // -// filename is required (usually the input data has been directly created by // -// user in the 'tetgenio' structure). A default filename 'tetgen-tmpfile' // -// will be created for debugging output purpose. // -// // /////////////////////////////////////////////////////////////////////////////// bool tetgenbehavior::parse_commandline(int argc, char **argv) @@ -3024,7 +3018,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) int startindex; int increment; int meshnumber; - int scount, ocount; int i, j, k; char workstring[1024]; @@ -3038,12 +3031,9 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) strcpy(commandline, argv[0]); strcat(commandline, " "); } - - // Count the number of '-O' and '-o' be used. - scount = ocount = 0; for (i = startindex; i < argc; i++) { - // Remember the command line switches. + // Remember the command line for output. strcat(commandline, argv[i]); strcat(commandline, " "); if (startindex == 1) { @@ -3051,7 +3041,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) if (argv[i][0] != '-') { strncpy(infilename, argv[i], 1024 - 1); infilename[1024 - 1] = '\0'; - // Go to the next string directly. continue; } } @@ -3072,11 +3061,17 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) facet_ang_tol = (REAL) strtod(workstring, (char **) NULL); } } else if (argv[i][j] == 's') { - psc = 1; + psc = 1; + } else if (argv[i][j] == 'Y') { + nobisect = 1; + if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + nobisect_param = (argv[i][j + 1] - '0'); + j++; + } } else if (argv[i][j] == 'r') { - refine++; + refine = 1; } else if (argv[i][j] == 'q') { - quality++; + quality = 1; if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { k = 0; @@ -3087,42 +3082,56 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) k++; } workstring[k] = '\0'; - if (quality == 1) { // -q# - minratio = (REAL) strtod(workstring, (char **) NULL); - } else if (quality == 2) { // -qq# + minratio = (REAL) strtod(workstring, (char **) NULL); + } + if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) { + j++; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; mindihedral = (REAL) strtod(workstring, (char **) NULL); } } - } else if (argv[i][j] == 'm') { - metric++; - } else if (argv[i][j] == 'Y') { - nobisect = 1; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e')) { - j++; - workstring[k] = argv[i][j]; - k++; + if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) { + j++; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + optmaxdihedral = (REAL) strtod(workstring, (char **) NULL); } - workstring[k] = '\0'; - nobisect_param = (int) strtol(workstring, (char **) NULL, 0); } } else if (argv[i][j] == 'w') { weighted = 1; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - weighted_param = (int) strtol(workstring, (char **) NULL, 0); + if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + weighted_param = (argv[i][j + 1] - '0'); + j++; } + } else if (argv[i][j] == 'b') { + brio_hilbert = 1; + if (argv[i][j + 1] == '0') { // -b0 + brio_hilbert = 0; // Turn off BRIO sorting. + j++; + } + } else if (argv[i][j] == 'l') { + incrflip = 1; + } else if (argv[i][j] == 'L') { + flipinsert = 1; + } else if (argv[i][j] == 'm') { + metric = 1; } else if (argv[i][j] == 'a') { if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { @@ -3141,71 +3150,32 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) varvolume = 1; } } else if (argv[i][j] == 'A') { - regionattrib++; - } else if (argv[i][j] == 'l') { - incrflip = 1; - // Check if a smallest edge length is given. - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || - (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - minedgelength = (REAL) strtod(workstring, (char **) NULL); - } - } else if (argv[i][j] == 'L') { - flipinsert++; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - if (flipinsert == 1) { // -L - fliplinklevel = (int) strtol(workstring, (char **) NULL, 0); - } else if (flipinsert == 2) { // -LL - flipstarsize = (int) strtol(workstring, (char **) NULL, 0); - } - } - } else if (argv[i][j] == 'u') { - // Set the maximum btree node size, -u0 means do not use btree. - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - max_btreenode_size = (int) strtol(workstring, (char **) NULL, 0); - } - if (max_btreenode_size == 0) { - btree = 0; + regionattrib = 1; + } else if (argv[i][j] == 'D') { + conforming = 1; + if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) { + reflevel = (argv[i][j + 1] - '1') + 1; + j++; } - } else if (argv[i][j] == 'U') { - hilbertcurve = 1; - btree = 0; } else if (argv[i][j] == 'i') { insertaddpoints = 1; } else if (argv[i][j] == 'd') { diagnose = 1; } else if (argv[i][j] == 'c') { convex = 1; + } else if (argv[i][j] == 'M') { + nomerge = 1; + } else if (argv[i][j] == 'X') { + if (argv[i][j + 1] == '1') { + nostaticfilter = 1; + j++; + } else { + noexact = 1; + } } else if (argv[i][j] == 'z') { zeroindex = 1; } else if (argv[i][j] == 'f') { - facesout = 1; + facesout++; } else if (argv[i][j] == 'e') { edgesout++; } else if (argv[i][j] == 'n') { @@ -3214,10 +3184,8 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) voroout = 1; } else if (argv[i][j] == 'g') { meditview = 1; - } else if (argv[i][j] == 'K') { + } else if (argv[i][j] == 'k') { vtkview = 1; - } else if (argv[i][j] == 'M') { - nomerge = 1; } else if (argv[i][j] == 'J') { nojettison = 1; } else if (argv[i][j] == 'B') { @@ -3226,10 +3194,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) nonodewritten = 1; } else if (argv[i][j] == 'E') { noelewritten = 1; - if (argv[i][j + 1] == '2') { - j++; - noelewritten = 2; - } } else if (argv[i][j] == 'F') { nofacewritten = 1; } else if (argv[i][j] == 'I') { @@ -3249,65 +3213,36 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) steinerleft = (int) strtol(workstring, (char **) NULL, 0); } } else if (argv[i][j] == 'o') { - ocount++; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || - (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - if (ocount == 1) { // -o# + if (argv[i][j + 1] == '2') { + order = 2; + j++; + } + if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) { + j++; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; optmaxdihedral = (REAL) strtod(workstring, (char **) NULL); - } else if (ocount == 2) { // -oo# - optminsmtdihed = (REAL) strtod(workstring, (char **) NULL); - } else if (ocount == 3) { // -ooo# - optminslidihed = (REAL) strtod(workstring, (char **) NULL); - } + } } } else if (argv[i][j] == 'O') { - scount++; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || - (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - if (scount == 1) { // -O - optlevel = (int) strtol(workstring, (char **) NULL, 0); - } else if (scount == 2) { // -OO - optpasses = (int) strtol(workstring, (char **) NULL, 0); - } else if (scount == 3) { // -OOO - optmaxfliplevel = (int) strtol(workstring, (char **) NULL, 0); - } else if (scount == 4) { // -OOOO - delmaxfliplevel = (int) strtol(workstring, (char **) NULL, 0); - } else if (scount == 5) { // -OOOOO (5 Os) - optmaxflipstarsize = (int) strtol(workstring, (char **) NULL, 0); - } + if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + optlevel = (argv[i][j + 1] - '0'); + j++; } - } else if (argv[i][j] == 'D') { - conforming = 1; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || - (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { + if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) { + j++; + if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) { + optscheme = (argv[i][j + 1] - '0'); j++; - workstring[k] = argv[i][j]; - k++; } - workstring[k] = '\0'; - reflevel = (int) strtol(workstring, (char **) NULL, 0); } } else if (argv[i][j] == 'T') { if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || @@ -3323,6 +3258,8 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) workstring[k] = '\0'; epsilon = (REAL) strtod(workstring, (char **) NULL); } + } else if (argv[i][j] == 'R') { + reversetetori = 1; } else if (argv[i][j] == 'C') { docheck++; } else if (argv[i][j] == 'Q') { @@ -3395,6 +3332,10 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) if (diagnose && !plc) { // -d plc = 1; } + if (plc && !quality && !nobisect) { // -p only + // Create a CDT, do not do mesh optimization. + optlevel = 0; + } // Detect improper combinations of switches. if (plc && refine) { @@ -3430,18 +3371,16 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) } } } - if (ocount == 0) { - // No user-specified dihedral angle bound. Use default ones. - if (!quality) { - if (optmaxdihedral < 179.0) { - optmaxdihedral = 179.0; - } - if (optminsmtdihed < 179.999) { - optminsmtdihed = 179.999; - } - if (optminslidihed < 179.999) { - optminslidihed = 179.99; - } + // No user-specified dihedral angle bound. Use default ones. + if (!quality) { + if (optmaxdihedral < 179.0) { + optmaxdihedral = 179.0; + } + if (optminsmtdihed < 179.999) { + optminsmtdihed = 179.999; + } + if (optminslidihed < 179.999) { + optminslidihed = 179.999; } } @@ -3500,10 +3439,8 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) int tetgenmesh::mod12[36] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; - -int tetgenmesh::mod6[18] = {0, 1, 2, 3, 4, 5, - 0, 1, 2, 3, 4, 5, - 0, 1, 2, 3, 4, 5}; +int tetgenmesh::mod6[18] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, + 0, 1, 2, 3, 4, 5}; // Table 'edgepivot' takes an directed edge (version) as input, returns the // inversed edge (version) of it. @@ -3542,8 +3479,6 @@ int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4}; int tetgenmesh::epivot[4] = {4, 5, 2, 11}; - - /////////////////////////////////////////////////////////////////////////////// // // // restart() Deallocate all objects in this pool. // @@ -4026,8 +3961,6 @@ void* tetgenmesh::memorypool::traverse() return newitem; } - - /////////////////////////////////////////////////////////////////////////////// // // // makeindex2pointmap() Create a map from index to vertices. // @@ -4059,7 +3992,6 @@ void tetgenmesh::makeindex2pointmap(point*& idx2verlist) } } - /////////////////////////////////////////////////////////////////////////////// // // // makesubfacemap() Create a map from vertex to subfaces incident at it. // @@ -4163,15 +4095,13 @@ void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron) // dead tetrahedra when traversing the list of all tetrahedra. dyingtetrahedron[4] = (tetrahedron) NULL; - //if (b->plc || b->refine) { //if (b->useshelles) { - // Dealloc the space to subfaces/subsegments. - if (dyingtetrahedron[8] != NULL) { - tet2segpool->dealloc((shellface *) dyingtetrahedron[8]); - } - if (dyingtetrahedron[9] != NULL) { - tet2subpool->dealloc((shellface *) dyingtetrahedron[9]); - } - //} + // Dealloc the space to subfaces/subsegments. + if (dyingtetrahedron[8] != NULL) { + tet2segpool->dealloc((shellface *) dyingtetrahedron[8]); + } + if (dyingtetrahedron[9] != NULL) { + tet2subpool->dealloc((shellface *) dyingtetrahedron[9]); + } tetrahedrons->dealloc((void *) dyingtetrahedron); } @@ -4319,6 +4249,7 @@ tetgenmesh::point tetgenmesh::pointtraverse() void tetgenmesh::maketetrahedron(triface *newtet) { newtet->tet = (tetrahedron *) tetrahedrons->alloc(); + // Initialize the four adjoining tetrahedra to be "outer space". newtet->tet[0] = NULL; newtet->tet[1] = NULL; @@ -4332,9 +4263,9 @@ void tetgenmesh::maketetrahedron(triface *newtet) // No attached segments and sbfaces yet. newtet->tet[8] = NULL; newtet->tet[9] = NULL; - // Initialize the marker (for flags). + // Initialize the marker (clear all flags). setelemmarker(newtet->tet, 0); - for (int i = 0; i < in->numberoftetrahedronattributes; i++) { + for (int i = 0; i < numelemattrib; i++) { setelemattribute(newtet->tet, i, 0.0); } if (b->varvolume) { @@ -4355,6 +4286,7 @@ void tetgenmesh::maketetrahedron(triface *newtet) void tetgenmesh::makeshellface(memorypool *pool, face *newface) { newface->sh = (shellface *) pool->alloc(); + // No adjointing subfaces. newface->sh[0] = NULL; newface->sh[1] = NULL; @@ -4382,7 +4314,7 @@ void tetgenmesh::makeshellface(memorypool *pool, face *newface) setshellmark(*newface, 0); // Set the default face type. setshelltype(*newface, NSHARP); - // Initialize the version to be Zero. + newface->shver = 0; } @@ -4394,9 +4326,14 @@ void tetgenmesh::makeshellface(memorypool *pool, face *newface) void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype) { - int ptmark, i; + int i; *pnewpoint = (point) points->alloc(); + + // Initialize the point attributes. + for (i = 0; i < numpointattrib; i++) { + (*pnewpoint)[3 + i] = 0.0; + } // Initialize the metric tensor. for (i = 0; i < sizeoftensor; i++) { (*pnewpoint)[pointmtrindex + i] = 0.0; @@ -4411,8 +4348,8 @@ void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype) } } // Initialize the point marker (starting from in->firstnumber). - ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); - setpointmark(*pnewpoint, ptmark); + i = (int) points->items - (in->firstnumber == 1 ? 0 : 1); + setpointmark(*pnewpoint, i); // Initialize the point type. setpointtype(*pnewpoint, vtype); // Clear the point flags. @@ -4447,22 +4384,43 @@ void tetgenmesh::initializepools() printf(" Initializing memorypools.\n"); } + // There are three input point lists available, which are in, addin, + // and bgm->in. These point lists may have different number of + // attributes. Decide the maximum number. + numpointattrib = in->numberofpointattributes; + if (bgm != NULL) { + if (bgm->in->numberofpointattributes > numpointattrib) { + numpointattrib = bgm->in->numberofpointattributes; + } + } + if (addin != NULL) { + if (addin->numberofpointattributes > numpointattrib) { + numpointattrib = addin->numberofpointattributes; + } + } + if (b->weighted || b->flipinsert) { // -w or -L. + // The internal number of point attribute needs to be at least 1 + // (for storing point weights). + if (numpointattrib == 0) { + numpointattrib = 1; + } + } + // Default varconstraint = 0; if (in->segmentconstraintlist || in->facetconstraintlist) { checkconstraints = 1; } - // Each vertex has three coordinates plus a weight, hence 4 REALs. // The index within each point at which its metric tensor is found. + // Each vertex has three coordinates. if (b->psc) { - // For '-s' option (PSC), the u,v coordinates are provided. It is - // saved directly after the list of point attributes. - pointmtrindex = 6 + in->numberofpointattributes; + // '-s' option (PSC), the u,v coordinates are provided. + pointmtrindex = 5 + numpointattrib; } else { - pointmtrindex = 4 + in->numberofpointattributes; + pointmtrindex = 3 + numpointattrib; } // The index within each point at which its u, v coordinates are found. - pointparamindex = pointmtrindex - 2; + pointparamindex = 3 + (numpointattrib > 0); // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file). if (b->metric) { // Decide the size (1, 3, or 6) of the metric tensor. @@ -4491,19 +4449,11 @@ void tetgenmesh::initializepools() // - a pointer to a parent point, read by point2ppt()). // - a pointer to a subface or segment, read by point2sh(); if (b->metric && (bgm != (tetgenmesh *) NULL)) { - // Increase one pointer to into the background mesh, point2bgmtet(). + // Increase one pointer into the background mesh, point2bgmtet(). pointsize = (point2simindex + 4) * sizeof(tetrahedron); } else { pointsize = (point2simindex + 3) * sizeof(tetrahedron); } - // The index within each point at which a pbc point is found. - point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1) - / sizeof(tetrahedron); - if (checkpbcs) { - // Increase the size by one pointer to a corresponding pbc point, - // read by point2pbcpt(). - pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron); - } } else { // Increase the point size by two pointer, which are: // - a pointer to a tet, read by point2tet(); @@ -4517,7 +4467,6 @@ void tetgenmesh::initializepools() // - an integer for boundary marker; // - an integer for vertex type; // - an integer for geometry tag (optional, -s option). - //pointsize = (pointmarkindex + 2)*sizeof(int); // Wrong for 64 bit system. pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron); // Decide the wordtype used in vertex pool. @@ -4558,19 +4507,21 @@ void tetgenmesh::initializepools() assert((sizeof(tetrahedron) % sizeof(int)) == 0); elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int); + // The actual number of element attributes. Note that if the + // `b->regionattrib' flag is set, an additional attribute will be added. + numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0); + // The index within each element at which its attributes are found, where // the index is measured in REALs. elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL); // The index within each element at which the maximum voulme bound is - // found, where the index is measured in REALs. Note that if the - // `b->regionattrib' flag is set, an additional attribute will be added. - volumeboundindex = elemattribindex + in->numberoftetrahedronattributes - + (b->regionattrib > 0); + // found, where the index is measured in REALs. + volumeboundindex = elemattribindex + numelemattrib; // If element attributes or an constraint are needed, increase the number // of bytes occupied by an element. if (b->varvolume) { elesize = (volumeboundindex + 1) * sizeof(REAL); - } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) { + } else if (numelemattrib > 0) { elesize = volumeboundindex * sizeof(REAL); } @@ -4604,7 +4555,7 @@ void tetgenmesh::initializepools() shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int); // Increase the number of bytes by two or three integers, one for facet // marker, one for shellface type, and optionally one for pbc group. - shsize = (shmarkindex + 2 + checkpbcs) * sizeof(shellface); + shsize = (shmarkindex + 2) * sizeof(shellface); // Initialize the pool of subfaces. Each subface record is eight-byte // aligned so it has room to store an edge version (from 0 to 5) in @@ -4648,7 +4599,7 @@ void tetgenmesh::initializepools() caveencseglist = new arraypool(sizeof(face), 8); } - // Initialize the pool for flips. + // Initialize the pools for flips. flippool = new memorypool(sizeof(badface), 1024, memorypool::POINTER, 0); unflipqueue = new arraypool(sizeof(badface), 10); @@ -5872,8 +5823,6 @@ REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe) { REAL sign; - inspherecount++; - sign = insphere(pa, pb, pc, pd, pe); if (sign != 0.0) { return sign; @@ -5947,15 +5896,13 @@ REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, { REAL sign; - inspherecount++; - sign = orient4d(pa, pb, pc, pd, pe, aheight, bheight, cheight, dheight, eheight); if (sign != 0.0) { return sign; } - insphere_sos_count++; + orient4d_sos_count++; // Symbolic perturbation. point pt[5], swappt; @@ -6000,7 +5947,6 @@ REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, return oriB; } - /////////////////////////////////////////////////////////////////////////////// // // // facenormal() Calculate the normal of the face. // @@ -6108,7 +6054,6 @@ REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2) return sqrt(dot(v2, v2) - l_p * l_p); } - /////////////////////////////////////////////////////////////////////////////// // // // triarea() Return the area of a triangle. // @@ -6205,9 +6150,7 @@ void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj) v2[2] = p[2] - e1[2]; len = sqrt(dot(v1, v1)); -#ifdef SELF_CHECK assert(len != 0.0); -#endif v1[0] /= len; v1[1] /= len; v1[2] /= len; @@ -6249,7 +6192,6 @@ void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj) prj[2] = p[2] - dist * fnormal[2]; } - /////////////////////////////////////////////////////////////////////////////// // // // facedihedral() Return the dihedral angle (in radian) between two // @@ -6559,7 +6501,59 @@ bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, return true; } +/////////////////////////////////////////////////////////////////////////////// +// // +// orthosphere() Calulcate the orthosphere of four weighted points. // +// // +// A weighted point (p, P^2) can be interpreted as a sphere centered at the // +// point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 + // +// p[1]^2 + p[2]^2 - P^2. // +// // +/////////////////////////////////////////////////////////////////////////////// + +bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, + REAL aheight, REAL bheight, REAL cheight, + REAL dheight, REAL* orthocent, REAL* radius) +{ + REAL A[4][4], rhs[4], D; + int indx[4]; + + // Set the coefficient matrix A (4 x 4). + A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2]; + A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2]; + A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2]; + A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2]; + + // Set the right hand side vector (4 x 1). + rhs[0] = 0.5 * aheight; + rhs[1] = 0.5 * bheight; + rhs[2] = 0.5 * cheight; + rhs[3] = 0.5 * dheight; + + // Solve the 4 by 4 equations use LU decomposition with partial pivoting + // and backward and forward substitute.. + if (!lu_decmp(A, 4, indx, &D, 0)) { + if (radius != (REAL *) NULL) *radius = 0.0; + return false; + } + lu_solve(A, 4, indx, rhs, 0); + if (orthocent != (REAL *) NULL) { + orthocent[0] = rhs[1]; + orthocent[1] = rhs[2]; + orthocent[2] = rhs[3]; + } + if (radius != (REAL *) NULL) { + // rhs[0] = - rheight / 2; + // rheight = - 2 * rhs[0]; + // = r[0]^2 + r[1]^2 + r[2]^2 - radius^2 + // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight + // = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0] + *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3] + + 2.0 * rhs[0]); + } + return true; +} /////////////////////////////////////////////////////////////////////////////// // // @@ -6607,8 +6601,6 @@ void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2, } } - - /////////////////////////////////////////////////////////////////////////////// // // // tetprismvol() Calculate the volume of a tetrahedral prism in 4D. // @@ -6711,7 +6703,7 @@ void tetgenmesh::flippush(badface*& fstack, triface* flipface) // If 'flipflag = 1', it is in the process of incrmental flip DT algorithm, // // and we assume that 'd' must be the newly inserted vertex. In such case, // // only the link faces at 'd', i.e., three faces [a,b,e], [b,c,e], and [c,a, // -// e] needs to be queued, see [Edelsbrunner & Shah'1996] and [M\"ucke'1998]. // +// e] needs to be queued ([Edelsbrunner & Shah'1996] and [M\"ucke'1998]). // // // /////////////////////////////////////////////////////////////////////////////// @@ -6725,6 +6717,7 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, badface *bface; // used by chkencflag point pa, pb, pc, pd, pe; REAL volneg[2], volpos[3], vol_diff; // volumes of involved tet-prisms. + REAL attrib, volume; int dummyflag = 0; // range = {-1, 0, 1, 2}. int i; @@ -6779,6 +6772,7 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, fliptets[1].ver = 11; setelemmarker(fliptets[0].tet, 0); // Clear all flags. setelemmarker(fliptets[1].tet, 0); + // NOTE: the element attributes and volume constraint remain unchanged. if (checksubsegflag) { // Dealloc the space to subsegments. if (fliptets[0].tet[8] != NULL) { @@ -6803,6 +6797,15 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, } // Create a new tet. maketetrahedron(&(fliptets[2])); + // The new tet have the same attributes from the old tet. + for (i = 0; i < numelemattrib; i++) { + attrib = elemattribute(fliptets[0].tet, i); + setelemattribute(fliptets[2].tet, i, attrib); + } + if (b->varvolume) { + volume = volumebound(fliptets[0].tet); + setvolumebound(fliptets[2].tet, volume); + } if (hullflag > 0) { // Check if d is dummytet. @@ -7039,17 +7042,13 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, if (flipflag > 0) { // Queue faces which may be locally non-Delaunay. - //pd = dest(fliptets[0]); // 'd' may be a new vertex. for (i = 0; i < 3; i++) { eprevesym(fliptets[i], newface); - //flippush(flipstack, &newface, pd); flippush(flipstack, &newface); } if (flipflag > 1) { - //pe = org(fliptets[0]); for (i = 0; i < 3; i++) { enextesym(fliptets[i], newface); - //flippush(flipstack, &newface, pe); flippush(flipstack, &newface); } } @@ -7082,8 +7081,18 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, // If 'flipflag = 1', it is in the process of incrmental flip DT algorithm, // // and we assume that 'a' must be the newly inserted vertex. In such case, // // only the link faces at 'a', i.e., two faces [c,b,d] and [b,c,e] needs to // -// be queued, refer to [Edelsbrunner & Shah'1996] and [M\"ucke'1998]. // +// be queued ( [Edelsbrunner & Shah'1996] and [M\"ucke'1998]). // // // +// If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a // +// segment. There may be two (interior) subfaces sharing at [e,d], which are // +// [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c), // +// or (c,a) In such case, a 2-to-2 flip is performed on these two subfaces // +// and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted // +// back into the tetrahedralization. However, it is possible that the new // +// subface ([p,q,e] or [p,q,d] already exists. In such case, we just delete // +// the conflict subface. As a result, either 'd' or 'e' is removed from the // +// surface mesh. A better solution would be to detect and perform a 3-to-1 // +// flip to remove 'd' or 'e' (see also 2011-11-15). // // // /////////////////////////////////////////////////////////////////////////////// @@ -7097,8 +7106,9 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag, badface *bface; // used by chkencflag point pa, pb, pc, pd, pe; REAL volneg[3], volpos[2], vol_diff; // volumes of involved tet-prisms. + REAL attrib, volume; int dummyflag = 0; // Rangle = {-1, 0, 1, 2} - int i; + int i, j; // For 2-to-2 flip (subfaces). face flipshs[3], flipfaces[2]; @@ -7186,6 +7196,28 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag, fliptets[1].ver = 11; setelemmarker(fliptets[0].tet, 0); // Clear all flags. setelemmarker(fliptets[1].tet, 0); + // NOTE: the element attributes and volume constraint must be set correctly. + if (checksubfaceflag) { + if (scount > 0) { + // There are two subfaces involved in this flip. The three tets are + // separated into two different regions, one may be exterior. The + // first region has two tets, and the second region has only one. + // The two created tets must be in the same region as the first region. + // The element attributes and volume constraint must be set correctly. + //assert(spivot != -1); + // The tet fliptets[spivot] is in the first region. + for (j = 0; j < 2; j++) { + for (i = 0; i < numelemattrib; i++) { + attrib = elemattribute(fliptets[spivot].tet, i); + setelemattribute(fliptets[j].tet, i, attrib); + } + if (b->varvolume) { + volume = volumebound(fliptets[spivot].tet); + setvolumebound(fliptets[j].tet, volume); + } + } + } + } if (checksubsegflag) { // Dealloc the space to subsegments. if (fliptets[0].tet[8] != NULL) { @@ -7686,6 +7718,7 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag, // Re-use fliptets[0] for [a,b,c,d]. fliptets[0].ver = 11; setelemmarker(fliptets[0].tet, 0); // Clean all flags. + // NOTE: the element attributes and volume constraint remain unchanged. if (checksubsegflag) { // Dealloc the space to subsegments. if (fliptets[0].tet[8] != NULL) { @@ -8677,9 +8710,7 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot, } } if (!rejflag && (fc != NULL)) { - //rejflag = checkflipeligibility(2, tmppts[0], tmppts[1], tmppts[2], - // pa, pb, level, abedgepivot, fc); - // Here we must permute 'a' and 'b'. Since in the check... function, + // Here we must exchange 'a' and 'b'. Since in the check... function, // we assume the following point sequence, 'a,b,c,d,e', where // the face [a,b,c] will be flipped and the edge [e,d] will be // created. The two new tets are [a,b,c,d] and [b,a,c,e]. @@ -8808,9 +8839,7 @@ int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot, } // The initial size of Star(ab) is 3. nn++; - } else { // nn > 2. - // The edge [a,b] exists. - } + } // Walk through the performed flips. for (i = nn; i < n; i++) { @@ -9025,11 +9054,6 @@ long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, unmarkface(fliptet); - // FOR DEBUG - if (flipflag == 1) { - assert(oppo(fliptet) == newpt); - } - if (ishulltet(fliptet)) { // It is a hull tet. if (((flipflag == 4) || peelsliverflag) && !b->convex) { @@ -9061,8 +9085,6 @@ long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, // [a,e],[b,e] are subsegments. If so, a 4-to-1 flip // (including a 3-to-1, and maybe a 2-to-1 flip) should be // applied to remove an exterior vertex. - // See figures (2011-11-13 and 15) for illustraions. - // First check if the face [b,a,d] is a hull face. eprev(neightet, fliptets[0]); esymself(fliptets[0]); // [d,a,b,e] @@ -9192,7 +9214,7 @@ long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, if (flipflag == 1) { // Check if the new point is visible by the hull face. ppt = (point *) neightet.tet; - ori = orient3d(ppt[4], ppt[5], ppt[6], newpt); orient3dcount++; + ori = orient3d(ppt[4], ppt[5], ppt[6], newpt); if (ori < 0) { // Visible. Perform a 2-to-3 flip on the flip face. fliptets[0] = fliptet; // [a,b,c,d], d = newpt. @@ -9296,7 +9318,7 @@ long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, for (i = 0; i < 3; i++) { p1 = org(fliptet); p2 = dest(fliptet); - ori = orient3d(p1, p2, pd, pe); orient3dcount++; + ori = orient3d(p1, p2, pd, pe); if (ori < 0) { // A locally non-convex edge. convflag = -1; @@ -9604,14 +9626,14 @@ long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, // // // insertvertex() Insert a point into current tetrahedralization. // // // -// This routine implements the famous Bowyer-Watson (B-W) algorithm to add a // -// new point p into current tetrahedralization, denoted as T. The baisc idea // -// of B-W algorithm is: first finds a "cavity", denoted as C inside T, where // -// C is a simplicial polyhedron formed by a union of tetrahedra in T. If all // -// boundary faces (triangles) of C are visible by p, i.e., C is star-shaped, // -// then T can be re-tetrahedralized by first deleting all old tetrahedra in // -// C, then replacing new tetrahedra formed by boundary faces of C and p. The // -// result is that p becomesis a vertex of T. // +// The Bowyer-Watson (B-W) algorithm is used to add a new point p into the // +// tetrahedralization T. It first finds a "cavity", denoted as C, in T, C // +// consists of tetrahedra in T that "conflict" with p. If T is a Delaunay // +// tetrahedralization, then all boundary faces (triangles) of C are visible // +// by p, i.e.,C is star-shaped. We can insert p into T by first deleting all // +// tetrahedra in C, then creating new tetrahedra formed by boundary faces of // +// C and p. If T is not a DT, then C may be not star-shaped. It must be // +// modified so that it becomes star-shaped. // // // // // /////////////////////////////////////////////////////////////////////////////// @@ -9638,9 +9660,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, int rejptflag, encptflag; // for protecting balls. int bgmloc; -#ifdef WITH_RUNTIME_COUNTERS - clock_t tstart, tend; -#endif if (b->verbose > 2) { printf(" Insert point %d\n", pointmark(insertpt)); @@ -9655,17 +9674,12 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, } if (loc == OUTSIDE) { -#ifdef WITH_RUNTIME_COUNTERS - tstart = clock(); -#endif - tetcount = ptloc_count; // Count the number of walked tets. + tetcount = ptloc_count; // Count the number of visited tets. if (searchtet->tet == NULL) { if (!b->weighted) { - if (b->btree) { - btree_search(insertpt, searchtet); - } else if (b->hilbertcurve) { // -U + if (b->brio_hilbert) { // -b *searchtet = recenttet; - } else { // -u0 + } else { // -b0 randomsample(insertpt, searchtet); } } else { @@ -9673,18 +9687,14 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, *searchtet = recenttet; } } - // Locate the point. Use 'randflag' if the mesh is non-convex. - loc = locate(insertpt, searchtet, ivf->chkencflag, checksubfaceflag); + // Locate the point. + loc = locate(insertpt, searchtet, ivf->chkencflag); if (b->verbose > 3) { printf(" Walk distance (# tets): %ld\n", ptloc_count-tetcount); } if (ptloc_max_count < (ptloc_count - tetcount)) { ptloc_max_count = (ptloc_count - tetcount); } -#ifdef WITH_RUNTIME_COUNTERS - tend = clock(); - t_ptloc += (tend - tstart); -#endif } if (b->verbose > 3) { @@ -9693,9 +9703,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, pointmark(apex(*searchtet)), pointmark(oppo(*searchtet))); } -#ifdef WITH_RUNTIME_COUNTERS - tstart = clock(); -#endif if (b->weighted) { if (loc != OUTSIDE) { @@ -9707,21 +9714,19 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, insertpt[3]); if (sign > 0) { // This new vertex does not lie below the lower hull. Skip it. - if (b->verbose > 2) { - printf(" The point is above the lower hull, skipped.\n"); - } - return OUTSIDE; + if (b->verbose > 1) { + printf(" Point #%d is non-regular, skipped.\n", + pointmark(insertpt)); + } + setpointtype(insertpt, NREGULARVERTEX); + nonregularcount++; + return NONREGULAR; } } } // Create the initial cavity C(p) which contains all tetrahedra directly // intersect with p. - // If 'bowywat > 2' and p lies on a segment or subface, also create the - // initial sub-cavity sC(p) which contains all subfaces (and segment) - // which directly intersect with p. - // If 'bowywat > 2', the initial C(p) is validated, i.e., all boundary - // faces of C(p) should be visible by p. // Remember the current hullsize. It is used to restore the hullsize // if the new point is rejected for insertion. @@ -9897,9 +9902,39 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, return (int) loc; } else if (loc == ENCSUBFACE) { if (b->verbose > 3) { - printf(" Encroached.\n"); + printf(" Beyond boundary.\n"); } // The vertex lies outside of the region boundary. + if (ivf->rejflag & 2) { + // Check if this vertex lies very close to the boundary face. + // This case needs to be handled due to the rounding off error. + tspivot(*searchtet, checksh); + assert(checksh.sh != NULL); + pa = sorg(checksh); + pb = sdest(checksh); + pc = sapex(checksh); + ori = orient3d(pa, pb, pc, insertpt); + // Re-use cent[3]. + cent[0] = distance(pa, insertpt); + cent[1] = distance(pb, insertpt); + cent[2] = distance(pb, insertpt); + // Choose the largest distance. + if (cent[0] < cent[1]) cent[0] = cent[1]; + if (cent[0] < cent[2]) cent[0] = cent[2]; + if (fabs(ori) / (cent[0] * cent[0] * cent[0]) < b->epsilon) { + // A nearly co-planar subface. We treat this case as coplanar, so + // the insertion point does not lie outside of the domain. + // Queue an encroached subface. + // Calculate the circumcenter of this subface (for refinement). + circumsphere(pa, pb, pc, NULL, cent, &rd); + encshlist->newindex((void **) &bface); + bface->ss = checksh; + bface->forg = pa; // Not a dad one. + for (j = 0; j < 3; j++) bface->cent[j] = cent[j]; + bface->key = rd; + return (int) ENCSUBFACE; + } + } // Treated it as outside loc = OUTSIDE; return (int) loc; @@ -9916,13 +9951,12 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, bgm->decode(point2bgmtet(pa), neightet); // neightet is in 'bgm'! bgmloc = bgm->scoutpoint(insertpt, &neightet, 0); // randflag = 0 if (bgmloc != (int) OUTSIDE) { - insertpt[pointmtrindex] = // posflag = 1 - bgm->getpointmeshsize(insertpt, &neightet, bgmloc, 1); + insertpt[pointmtrindex] = + bgm->getpointmeshsize(insertpt, &neightet, bgmloc); setpoint2bgmtet(insertpt, bgm->encode(neightet)); } } else { - insertpt[pointmtrindex] = // posflag = 1 - getpointmeshsize(insertpt, searchtet, (int) loc, 1); + insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc); } } // if (assignmeshsize) @@ -9943,7 +9977,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, ori = orient3d(pa, pb, pc, insertpt); if (ori <= 0) { // An invalid face. Enlarge the cavity. - //if (oppo(*cavetet) != dummypoint) { if (b->verbose > 3) { printf(" Enlarge cavity at (%d, %d, %d)\n", pointmark(pa), pointmark(pb), pointmark(pc)); @@ -9961,11 +9994,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, caveoldtetlist->newindex((void **) &parytet); *parytet = *cavetet; tetcount++; - //} else { - // printf("Error in insertvertex %d: ", pointmark(insertpt)); - // printf("Invalid initial cavity at face %d.\n", i + 1); - // assert(0); - //} } else { // A valid face. cavebdrylist->newindex((void **) &parytet); @@ -10026,7 +10054,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, if (!nonconvex) { // Test if this hull face is visible by the new point. ori = orient3d(pts[4], pts[5], pts[6], insertpt); - orient3dcount++; if (ori < 0) { // A visible hull face. //if (!nonconvex) { @@ -10260,7 +10287,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, if (encshlist->objects > 0) { if (b->verbose > 3) { printf(" Found %ld encroached subfaces. Reject it.\n", - caveencshlist->objects); + encshlist->objects); } for (i = 0; i < caveoldtetlist->objects; i++) { cavetet = (triface *) fastlookup(caveoldtetlist, i); @@ -10309,14 +10336,21 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, spivot(checksh, neighsh); assert(neighsh.sh != NULL); if (!smarktested(neighsh)) { - // Add this subface if it is inside C(p). stpivot(neighsh, neightet); if (infected(neightet)) { fsymself(neightet); if (infected(neightet)) { - smarktest(neighsh); - caveshlist->newindex((void **) &parysh); - *parysh = neighsh; + // This subface is inside C(p). + // Check if its diametrical circumsphere encloses 'p'. + pa = sorg(neighsh); + pb = sdest(neighsh); + pc = sapex(neighsh); + sign = incircle3d(pa, pb, pc, insertpt); + if (sign < 0) { + smarktest(neighsh); + caveshlist->newindex((void **) &parysh); + *parysh = neighsh; + } } } } @@ -10500,7 +10534,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, pa = org(*cavetet); pb = dest(*cavetet); pc = apex(*cavetet); - ori = orient3d(pa, pb, pc, insertpt); orient3dcount++; + ori = orient3d(pa, pb, pc, insertpt); enqflag = (ori > 0); // Comment: if ori == 0 (coplanar case), we also cut the tet. } else { @@ -10581,8 +10615,27 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // The cavity should contain at least one tet. if (caveoldtetlist->objects == 0l) { - printf("Invalid cavity of Steiner point %d.\n", pointmark(insertpt)); - assert(0); + assert(cavebdrylist->objects == 0l); + cavetetlist->restart(); + cavebdrylist->restart(); + caveoldtetlist->restart(); + cavetetseglist->restart(); + cavetetshlist->restart(); + if (ivf->splitbdflag) { //if (bowywat > 2) { + if (splitseg != NULL) { + sunmarktest(*splitseg); + } + for (i = 0; i < caveshlist->objects; i++) { + parysh = (face *) fastlookup(caveshlist, i); + assert(smarktested(*parysh)); + sunmarktest(*parysh); + } + caveshlist->restart(); + cavesegshlist->restart(); + } + // Restore the hullsize. + hullsize = bakhullsize; + return (int) BADELEMENT; } if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) { @@ -11034,15 +11087,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, setdest(newtet, org(neightet)); setapex(newtet, apex(neightet)); setoppo(newtet, insertpt); - // The new tet inherits attribtes from the old tet. - for (j = 0; j < in->numberoftetrahedronattributes; j++) { - attrib = elemattribute(oldtet.tet, j); - setelemattribute(newtet.tet, j, attrib); - } - if (b->varvolume) { - volume = volumebound(oldtet.tet); - setvolumebound(newtet.tet, volume); - } } else { // Create a new hull tet (see Fig. bowyerwatson 2). hullsize++; @@ -11054,6 +11098,15 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // Adjust back to the cavity bounday face. esymself(newtet); } + // The new tet inherits attribtes from the old tet. + for (j = 0; j < numelemattrib; j++) { + attrib = elemattribute(oldtet.tet, j); + setelemattribute(newtet.tet, j, attrib); + } + if (b->varvolume) { + volume = volumebound(oldtet.tet); + setvolumebound(newtet.tet, volume); + } // Connect newtet <==> neightet, this also disconnect the old bond. bond(newtet, neightet); // oldtet still connects to neightet. @@ -11062,7 +11115,8 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // Set a handle for speeding point location. recenttet = newtet; - setpoint2tet(insertpt, encode(newtet)); + //setpoint2tet(insertpt, encode(newtet)); + setpoint2tet(insertpt, (tetrahedron) (newtet.tet)); if (ivf->lawson > 1) { // if (lawson == 2 || lawson == 3) { // Re-use this list to save new interior cavity faces. @@ -11098,7 +11152,8 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, *parytet = neightet; } } - setpoint2tet(org(newtet), encode(newtet)); + //setpoint2tet(org(newtet), encode(newtet)); + setpoint2tet(org(newtet), (tetrahedron) (newtet.tet)); enextself(newtet); enextself(oldtet); } @@ -11247,7 +11302,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, pa = sorg(checkseg); pb = sdest(checkseg); point2tetorg(pa, neightet); - finddirection(&neightet, pb, 1); + finddirection(&neightet, pb); assert(dest(neightet) == pb); } assert(!infected(neightet)); @@ -11318,11 +11373,12 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, assert(searchtet->tet != NULL); // No tet has been deleted yet. if (infected(*searchtet)) { if (b->weighted) { - if (b->verbose > 2) { - printf(" Point #%d is removed from the hull.\n", - pointmark(*pts)); - } - setpointtype(*pts, UNUSEDVERTEX); + if (b->verbose > 1) { + printf(" Point #%d is non-regular after the insertion of #%d.\n", + pointmark(*pts), pointmark(insertpt)); + } + setpointtype(*pts, NREGULARVERTEX); + nonregularcount++; } else { if (b->verbose > 3) { printf(" Queue a dangling vertex %d.\n", pointmark(*pts)); @@ -11468,14 +11524,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // The vertex should already have a type. assert(pointtype(insertpt) != UNUSEDVERTEX); -#ifdef WITH_RUNTIME_COUNTERS - tend = clock(); - t_ptinsert += (tend - tstart); -#endif - if (b->btree) { - btree_insert(insertpt); - } // Clean the working lists. @@ -11518,10 +11567,10 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // // // transfernodes() Read the vertices from the input (tetgenio). // // // -// Initializing 'this->points'. Transferring all points from 'in->pointlist'// -// into it. All points are indexed (start from in->firstnumber). Each point // -// is initialized be UNUSEDVERTEX. The bounding box (xmin, xmax, ymin, ymax,// -// zmin, zmax) and the diameter (longest) of the point set are calculated. // +// Transferring all points from input ('in->pointlist') to TetGen's 'points'.// +// All points are indexed (the first point index is 'in->firstnumber'). Each // +// point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,// +// ...) and the diameter (longest) of the point set are calculated. // // // /////////////////////////////////////////////////////////////////////////////// @@ -11534,9 +11583,6 @@ void tetgenmesh::transfernodes() int mtrindex; int i, j; - if (b->psc) { - assert(in->pointparamlist != NULL); - } // Read the points. coordindex = 0; @@ -11547,30 +11593,32 @@ void tetgenmesh::transfernodes() // Read the point coordinates. x = pointloop[0] = in->pointlist[coordindex++]; y = pointloop[1] = in->pointlist[coordindex++]; - z = pointloop[2] = in->pointlist[coordindex++]; + z = pointloop[2] = in->pointlist[coordindex++]; + // Read the point attributes. (Including point weights.) + for (j = 0; j < in->numberofpointattributes; j++) { + pointloop[3 + j] = in->pointattributelist[attribindex++]; + } + // Read the point metric tensor. + for (j = 0; j < in->numberofpointmtrs; j++) { + pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++]; + } if (b->weighted) { // -w option if (in->numberofpointattributes > 0) { - // The first point attribute is weight. - w = in->pointattributelist[in->numberofpointattributes * i]; + // The first point attribute is its weight. + //w = in->pointattributelist[in->numberofpointattributes * i]; + w = pointloop[3]; } else { - // No given weight available. - w = 0; + // No given weight available. Default choose the maximum + // absolute value among its coordinates. + w = fabs(x); + if (w < fabs(y)) w = fabs(y); + if (w < fabs(z)) w = fabs(z); } if (b->weighted_param == 0) { pointloop[3] = x * x + y * y + z * z - w; // Weighted DT. } else { // -w1 option pointloop[3] = w; // Regular tetrahedralization. } - } else { - pointloop[3] = 0; - } - // Read the point attributes. - for (j = 0; j < in->numberofpointattributes; j++) { - pointloop[4 + j] = in->pointattributelist[attribindex++]; - } - // Read the point metric tensor. - for (j = 0; j < in->numberofpointmtrs; j++) { - pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++]; } // Determine the smallest and largests x, y and z coordinates. if (i == 0) { @@ -11620,293 +11668,239 @@ void tetgenmesh::transfernodes() /////////////////////////////////////////////////////////////////////////////// // // -// btree_sort() Sort vertices using a binary space partition (bsp) tree. // +// hilbert_init() Initialize the Gray code permutation table. // +// // +// The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray // +// code sequences traveled by the 1st order Hilbert curve in 3 dimensions. // +// The first column is the Gray code of the entry point of the curve, and // +// the second column is the direction (0, 1, or 2, 0 means the x-axis) where // +// the exit point of curve lies. // +// // +// The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the // +// indices from 0 to 7, modulo by '3'. The code for generating this table is // +// from: http://graphics.stanford.edu/~seander/bithacks.html. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::hilbert_init(int n) +{ + int gc[8], N, mask, travel_bit; + int e, d, f, k, g; + int v, c; + int i; + + N = (n == 2) ? 4 : 8; + mask = (n == 2) ? 3 : 7; + + // Generate the Gray code sequence. + for (i = 0; i < N; i++) { + gc[i] = i ^ (i >> 1); + } + + for (e = 0; e < N; e++) { + for (d = 0; d < n; d++) { + // Calculate the end point (f). + f = e ^ (1 << d); // Toggle the d-th bit of 'e'. + // travel_bit = 2**p, the bit we want to travel. + travel_bit = e ^ f; + for (i = 0; i < N; i++) { + // // Rotate gc[i] left by (p + 1) % n bits. + k = gc[i] * (travel_bit * 2); + g = ((k | (k / N)) & mask); + // Calculate the permuted Gray code by xor with the start point (e). + transgc[e][d][i] = (g ^ e); + } + assert(transgc[e][d][0] == e); + assert(transgc[e][d][N - 1] == f); + } // d + } // e + + // Count the consecutive '1' bits (trailing) on the right. + tsb1mod3[0] = 0; + for (i = 1; i < N; i++) { + v = ~i; // Count the 0s. + v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest + for (c = 0; v; c++) { + v >>= 1; + } + tsb1mod3[i] = c % n; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// hilbert_sort3() Sort points using the 3d Hilbert curve. // // // /////////////////////////////////////////////////////////////////////////////// -void tetgenmesh::btree_sort(point* vertexarray, int arraysize, int axis, - REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, - REAL bzmin, REAL bzmax, int depth) +int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1, + REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, + REAL bzmin, REAL bzmax) { - point *leftarray, *rightarray; - point **pptary, swapvert; + point swapvert; + int axis, d; REAL split; - bool lflag, rflag; - int i, j, k; // *iptr, + int i, j; - if (b->verbose > 3) { - printf(" Depth %d, %d verts. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n", - depth, arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax, - axis == 0 ? "x" : (axis == 1 ? "y" : "z")); - } - if (depth > max_btree_depth) { - max_btree_depth = depth; - } + // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which + // correspoding to x-, or y- or z-axis. + axis = (gc0 ^ gc1) >> 1; + // Calulate the split position along the axis. if (axis == 0) { - // Split along x-axis. split = 0.5 * (bxmin + bxmax); } else if (axis == 1) { - // Split along y-axis. split = 0.5 * (bymin + bymax); - } else { - // Split along z-axis. + } else { // == 2 split = 0.5 * (bzmin + bzmax); } + // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction + // of the axis is to the positive of the axis, otherwise, it is -1. + d = ((gc0 & (1<<axis)) == 0) ? 1 : -1; + + // Partition the vertices into left- and right-arraies such that left points + // have Hilbert indices lower than the right points. i = 0; j = arraysize - 1; // Partition the vertices into left- and right-arraies. - do { - for (; i < arraysize; i++) { - if (vertexarray[i][axis] >= split) { - break; - } - } - for (; j >= 0; j--) { - if (vertexarray[j][axis] < split) { - break; - } - } - // Is the partition finished? - if (i == (j + 1)) { - break; - } - // Swap i-th and j-th vertices. - swapvert = vertexarray[i]; - vertexarray[i] = vertexarray[j]; - vertexarray[j] = swapvert; - // Continue patitioning the array; - } while (true); - - if (b->verbose > 3) { - printf(" leftsize = %d, rightsize = %d\n", i, arraysize - i); - } - lflag = rflag = false; - - // Do not continue the partition if one of the array sizes is 0. - // if (depth < max_tree_depth) { - if (!((i == 0) || (i == arraysize))) { - if (i > b->max_btreenode_size) { - // Recursively partition the left array (length = i). - if (axis == 0) { // x - btree_sort(vertexarray, i, (axis + 1) % 3, bxmin, split, bymin, - bymax, bzmin, bzmax, depth + 1); - } else if (axis == 1) { // y - btree_sort(vertexarray, i, (axis + 1) % 3, bxmin, bxmax, bymin, - split, bzmin, bzmax, depth + 1); - } else { // z - btree_sort(vertexarray, i, (axis + 1) % 3, bxmin, bxmax, bymin, - bymax, bzmin, split, depth + 1); + if (d > 0) { + do { + for (; i < arraysize; i++) { + if (vertexarray[i][axis] >= split) break; + } + for (; j >= 0; j--) { + if (vertexarray[j][axis] < split) break; + } + // Is the partition finished? + if (i == (j + 1)) break; + // Swap i-th and j-th vertices. + swapvert = vertexarray[i]; + vertexarray[i] = vertexarray[j]; + vertexarray[j] = swapvert; + // Continue patitioning the array; + } while (true); + } else { + do { + for (; i < arraysize; i++) { + if (vertexarray[i][axis] <= split) break; } - } else { - lflag = true; - } - if ((arraysize - i) > b->max_btreenode_size) { - // Recursively partition the right array (length = arraysize - i). - if (axis == 0) { // x - btree_sort(&(vertexarray[i]), arraysize - i, (axis + 1) % 3, split, - bxmax, bymin, bymax, bzmin, bzmax, depth + 1); - } else if (axis == 1) { // y - btree_sort(&(vertexarray[i]), arraysize - i, (axis + 1) % 3, bxmin, - bxmax, split, bymax, bzmin, bzmax, depth + 1); - } else { // z - btree_sort(&(vertexarray[i]), arraysize - i, (axis + 1) % 3, bxmin, - bxmax, bymin, bymax, split, bzmax, depth + 1); + for (; j >= 0; j--) { + if (vertexarray[j][axis] > split) break; } - } else { - rflag = true; - } - } else { - // Both left and right are done. - lflag = rflag = true; - } - - if (lflag && (i > 0)) { - // Remember the maximal length of the partitions. - if (i > max_btreenode_size) { - max_btreenode_size = i; - } - // Allocate space for the left array (use the first entry to save - // the length of this array). - leftarray = new point[i + 1]; - leftarray[0] = (point) i; // The array lenth. - //iptr = (int *) &(leftarray[0]); - //*iptr = i; // Save the array lenth in the first entry. - // Put all points in this array. - for (k = 0; k < i; k++) { - leftarray[k + 1] = vertexarray[k]; - setpoint2ppt(leftarray[k + 1], (point) leftarray); - } - // Save this array in list. - btreenode_list->newindex((void **) &pptary); - *pptary = leftarray; - } - - // Get the length of the right array. - j = arraysize - i; - if (rflag && (j > 0)) { - if (j > max_btreenode_size) { - max_btreenode_size = j; - } - // Allocate space for the right array (use the first entry to save - // the length of this array). - rightarray = new point[j + 1]; - rightarray[0] = (point) j; // The array lenth. - //iptr = (int *) &(rightarray[0]); - //*iptr = j; // Save the array length in the first entry. - // Put all points in this array. - for (k = 0; k < j; k++) { - rightarray[k + 1] = vertexarray[i + k]; - setpoint2ppt(rightarray[k + 1], (point) rightarray); - } - // Save this array in list. - btreenode_list->newindex((void **) &pptary); - *pptary = rightarray; + // Is the partition finished? + if (i == (j + 1)) break; + // Swap i-th and j-th vertices. + swapvert = vertexarray[i]; + vertexarray[i] = vertexarray[j]; + vertexarray[j] = swapvert; + // Continue patitioning the array; + } while (true); } -} -/////////////////////////////////////////////////////////////////////////////// -// // -// btree_insert() Add a vertex into a tree node. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void tetgenmesh::btree_insert(point insertpt) -{ - point *ptary; - long arylen; // The array lenhgth is saved in ptary[0]. - - // Get the tree node (save in this point). - ptary = (point *) point2ppt(insertpt); - // Get the current array length. - arylen = (long long) ptary[0]; - // Insert the point into the node. - ptary[arylen + 1] = insertpt; - // Increase the array length by 1. - ptary[0] = (point) (arylen + 1); + return i; } -/////////////////////////////////////////////////////////////////////////////// -// // -// btree_search() Search a near point for an inserting point. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void tetgenmesh::btree_search(point insertpt, triface* searchtet) +void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d, + REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, + REAL bzmin, REAL bzmax, int depth) { - point *ptary; - point nearpt, candpt; - REAL dist2, mindist2; - int ptsamples, ptidx; - long arylen; - int i; - - // Get the tree node (save in this point). - ptary = (point *) point2ppt(insertpt); - // Get the current array length. - arylen = (long long) ptary[0]; - - if (arylen == 0) { - searchtet->tet = NULL; - return; - } - - if (1) { - - if (arylen < 5) { //if (arylen < 10) { - ptsamples = arylen; - } else { - ptsamples = 5; // Take at least 10 samples. - // The number of random samples taken is proportional to the third root - // of the number of points in the cell. - while (ptsamples * ptsamples * ptsamples < arylen) { - ptsamples++; + REAL x1, x2, y1, y2, z1, z2; + int p[9], w, e_w, d_w, k, ei, di; + int n = 3, mask = 7; + + + // Record the highest order of the curve. + if (depth + 1 > max_hcurve_depth_count) { + max_hcurve_depth_count = depth + 1; + } + + p[0] = 0; + p[8] = arraysize; + + // Sort the points according to the 1st order Hilbert curve in 3d. + p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4], + bxmin, bxmax, bymin, bymax, bzmin, bzmax); + p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2], + bxmin, bxmax, bymin, bymax, bzmin, bzmax); + p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1], + bxmin, bxmax, bymin, bymax, bzmin, bzmax); + p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2], + transgc[e][d][2], transgc[e][d][3], + bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2]; + p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4], + transgc[e][d][5], transgc[e][d][6], + bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4]; + p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4], + transgc[e][d][4], transgc[e][d][5], + bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4]; + p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6], + transgc[e][d][6], transgc[e][d][7], + bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6]; + + if (b->hilbert_order > 0) { + // A maximum order is prescribed. + if ((depth + 1) == b->hilbert_order) { + // The maximum prescribed order is reached. + return; + } + } + + // Recursivly sort the points in sub-boxes. + for (w = 0; w < 8; w++) { + // w is the local Hilbert index (NOT Gray code). + // Sort into the sub-box either there are more than 2 points in it, or + // the prescribed order of the curve is not reached yet. + if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) { + // Calulcate the start point (ei) of the curve in this sub-box. + // update e = e ^ (e(w) left_rotate (d+1)). + if (w == 0) { + e_w = 0; + } else { + // calculate e(w) = gc(2 * floor((w - 1) / 2)). + k = 2 * ((w - 1) / 2); + e_w = k ^ (k >> 1); // = gc(k). + } + k = e_w; + e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask); + ei = e ^ e_w; + // Calulcate the direction (di) of the curve in this sub-box. + // update d = (d + d(w) + 1) % n + if (w == 0) { + d_w = 0; + } else { + d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w]; } - } - - // Select "good" candidate using k random samples, taking the closest one. - mindist2 = 1.79769E+308; // The largest double value (8 byte). - nearpt = NULL; - - for (i = 0; i < ptsamples; i++) { - ptidx = randomnation((unsigned long) arylen); - candpt = ptary[ptidx + 1]; - dist2 = (candpt[0] - insertpt[0]) * (candpt[0] - insertpt[0]) - + (candpt[1] - insertpt[1]) * (candpt[1] - insertpt[1]) - + (candpt[2] - insertpt[2]) * (candpt[2] - insertpt[2]); - if (dist2 < mindist2) { - mindist2 = dist2; - nearpt = candpt; + di = (d + d_w + 1) % n; + // Calculate the bounding box of the sub-box. + if (transgc[e][d][w] & 1) { // x-axis + x1 = 0.5 * (bxmin + bxmax); + x2 = bxmax; + } else { + x1 = bxmin; + x2 = 0.5 * (bxmin + bxmax); } - } - - } else { - - // TEST, randomly select a point. - ptidx = randomnation((unsigned long) arylen); - nearpt = ptary[ptidx + 1]; - - } - - if (b->verbose > 2) { - printf(" Get point %d (cell size %ld).\n", pointmark(nearpt), arylen); - } - - decode(point2tet(nearpt), *searchtet); -} - -/////////////////////////////////////////////////////////////////////////////// -// // -// ordervertices() Order the vertices for incremental inserting. // -// // -// We assume the vertices have been sorted by a binary tree. // -// // -/////////////////////////////////////////////////////////////////////////////// - -void tetgenmesh::ordervertices(point* vertexarray, int arraysize) -{ - point **ipptary, **jpptary, *swappptary; - point *ptary; - long arylen; - int index, i, j; - - // First pick one vertex from each tree node. - for (i = 0; i < (int) btreenode_list->objects; i++) { - ipptary = (point **) fastlookup(btreenode_list, i); - ptary = *ipptary; - vertexarray[i] = ptary[1]; // Skip the first entry. - } - - index = i; - // Then put all other points in the array node by node. - for (i = (int) btreenode_list->objects - 1; i >= 0; i--) { - // Randomly pick a tree node. - j = randomnation(i + 1); - // Save the i-th node. - ipptary = (point **) fastlookup(btreenode_list, i); - // Get the j-th node. - jpptary = (point **) fastlookup(btreenode_list, j); - // Order the points in the node. - ptary = *jpptary; - arylen = (long long) ptary[0]; - for (j = 2; j <= arylen; j++) { // Skip the first point. - vertexarray[index] = ptary[j]; - index++; - } - // Clear this tree node. - ptary[0] = (point) 0; - // Swap i-th node to j-th node. - swappptary = *ipptary; - *ipptary = *jpptary; // [i] <= [j] - *jpptary = swappptary; // [j] <= [i] - } - - // Make sure we've done correctly. - assert(index == arraysize); + if (transgc[e][d][w] & 2) { // y-axis + y1 = 0.5 * (bymin + bymax); + y2 = bymax; + } else { + y1 = bymin; + y2 = 0.5 * (bymin + bymax); + } + if (transgc[e][d][w] & 4) { // z-axis + z1 = 0.5 * (bzmin + bzmax); + z2 = bzmax; + } else { + z1 = bzmin; + z2 = 0.5 * (bzmin + bzmax); + } + hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di, + x1, x2, y1, y2, z1, z2, depth+1); + } // if (p[w+1] - p[w] > 1) + } // w } /////////////////////////////////////////////////////////////////////////////// @@ -11938,13 +11932,10 @@ unsigned long tetgenmesh::randomnation(unsigned int choices) // // // randomsample() Randomly sample the tetrahedra for point loation. // // // -// This routine implements Muecke's Jump-and-walk point location algorithm. // -// It improves the simple walk-through by "jumping" to a good starting point // -// via random sampling. Searching begins from one of handles: the input // -// 'searchtet', a recently encountered tetrahedron 'recenttet', or from one // -// chosen from a random sample. The choice is made by determining which one // -// 's origin is closest to the point we are searcing for. Having chosen the // -// starting tetrahedron, the simple Walk-through algorithm is executed. // +// Searching begins from one of handles: the input 'searchtet', a recently // +// encountered tetrahedron 'recenttet', or from one chosen from a random // +// sample. The choice is made by determining which one's origin is closest // +// to the point we are searcing for. // // // /////////////////////////////////////////////////////////////////////////////// @@ -12071,19 +12062,15 @@ void tetgenmesh::randomsample(point searchpt, triface *searchtet) // - ONFACE, the search point lies on a face of 'searchtet'. // // - INTET, the search point lies in the interior of 'searchtet'. // // - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a // -// hull tetrahedron whose base face is visible by the search point. // +// hull face which is visible by the search point. // // // // WARNING: This routine is designed for convex triangulations, and will not // // generally work after the holes and concavities have been carved. // // // -// If 'randflag' is set (> 0). Randomly choose a tetrahedron when there are // -// multiple choices in the path. // -// // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult - tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag, - int randflag) + tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag) { triface neightet; face checksh; @@ -12091,8 +12078,7 @@ enum tetgenmesh::locateresult enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove; REAL ori, oriorg, oridest, oriapex; enum locateresult loc; - int s; // i; - + int s; if (searchtet->tet == NULL) { // A null tet. Choose the recenttet as the starting tet. @@ -12114,13 +12100,11 @@ enum tetgenmesh::locateresult torg = org(*searchtet); tdest = dest(*searchtet); tapex = apex(*searchtet); - ori = orient3d(torg, tdest, tapex, searchpt); orient3dcount++; + ori = orient3d(torg, tdest, tapex, searchpt); if (ori < 0.0) break; } - if (searchtet->ver == 4) { - // Either 'searchtet' is a very flat tet, or the 'searchpt' lies in - // infinity, or both of them. Return OUTSIDE. - assert(0); // return OUTSIDE; + if (searchtet->ver == 4) { // SELF_CHECK + assert(0); } loc = OUTSIDE; // Set a default return value. @@ -12128,7 +12112,7 @@ enum tetgenmesh::locateresult // Walk through tetrahedra to locate the point. while (true) { - ptloc_count++; // Algorithimic count. + ptloc_count++; // Count the number of visited tets. toppo = oppo(*searchtet); @@ -12141,58 +12125,43 @@ enum tetgenmesh::locateresult break; } - // We enter from serarchtet's base face. There are three other faces in - // searchtet (all connecting to toppo), which one is the exit? + // We enter from one of serarchtet's faces, which face do we exit? oriorg = orient3d(tdest, tapex, toppo, searchpt); oridest = orient3d(tapex, torg, toppo, searchpt); oriapex = orient3d(torg, tdest, toppo, searchpt); - orient3dcount+=3; // Now decide which face to move. It is possible there are more than one - // faces are viable moves. Use the opposite points of thier neighbors - // to discriminate, i.e., we choose the face whose opposite point has - // the shortest distance to searchpt. + // faces are viable moves. If so, randomly choose one. if (oriorg < 0) { if (oridest < 0) { if (oriapex < 0) { - if (0) { //if (!randflag) { + // All three faces are possible. + s = randomnation(3); // 's' is in {0,1,2}. + if (s == 0) { + nextmove = ORGMOVE; + } else if (s == 1) { + nextmove = DESTMOVE; } else { - // Randomly choose a direction. - s = randomnation(3); // 's' is in {0,1,2}. - if (s == 0) { - nextmove = ORGMOVE; - } else if (s == 1) { - nextmove = DESTMOVE; - } else { - nextmove = APEXMOVE; - } - } // if (randflag) + nextmove = APEXMOVE; + } } else { // Two faces, opposite to origin and destination, are viable. - if (0) { // if (!randflag) { + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = ORGMOVE; } else { - // Randomly choose a direction. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = ORGMOVE; - } else { - nextmove = DESTMOVE; - } - } // if (randflag) + nextmove = DESTMOVE; + } } } else { if (oriapex < 0) { // Two faces, opposite to origin and apex, are viable. - if (0) { // if (!randflag) { + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = ORGMOVE; } else { - // Randomly choose a direction. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = ORGMOVE; - } else { - nextmove = APEXMOVE; - } - } // if (randflag) + nextmove = APEXMOVE; + } } else { // Only the face opposite to origin is viable. nextmove = ORGMOVE; @@ -12202,16 +12171,12 @@ enum tetgenmesh::locateresult if (oridest < 0) { if (oriapex < 0) { // Two faces, opposite to destination and apex, are viable. - if (0) { // if (!randflag) { + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = DESTMOVE; } else { - // Randomly choose a direction. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = DESTMOVE; - } else { - nextmove = APEXMOVE; - } - } // if (randflag) + nextmove = APEXMOVE; + } } else { // Only the face opposite to destination is viable. nextmove = DESTMOVE; @@ -12306,7 +12271,6 @@ enum tetgenmesh::locateresult return loc; } - /////////////////////////////////////////////////////////////////////////////// // // // initialdelaunay() Create an initial Delaunay tetrahedralization. // @@ -12383,13 +12347,6 @@ void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd) setpointtype(pd, VOLVERTEX); } - if (b->btree) { - btree_insert(pa); - btree_insert(pb); - btree_insert(pc); - btree_insert(pd); - } - setpoint2tet(pa, encode(firsttet)); setpoint2tet(pb, encode(firsttet)); setpoint2tet(pc, encode(firsttet)); @@ -12414,56 +12371,45 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv) REAL v1[3], v2[3], n[3]; REAL bboxsize, bboxsize2, bboxsize3, ori; int randindex, loc; + int ngroup, nstart, nend; int i, j; if (!b->quiet) { printf("Delaunizing vertices...\n"); } - if (b->max_btreenode_size > 0) { // not -u0. - b->btree = 1; - btreenode_list = new arraypool(sizeof(point*), 10); - max_btreenode_size = 0; - max_btree_depth = 0; - } - - // Form a random permuation (uniformly at random) of the set of vertices. permutarray = new point[in->numberofpoints]; points->traversalinit(); - if (b->btree) { // -u option - for (i = 0; i < in->numberofpoints; i++) { - permutarray[i] = (point) points->traverse(); - } - if (b->verbose) { - printf(" Sorting vertices by a bsp-tree.\n"); - } - // Sort the points using a binary tree recursively. - btree_sort(permutarray, in->numberofpoints, 0, xmin, xmax, ymin, ymax, - zmin, zmax, 0); - if (b->verbose) { - printf(" Number of tree nodes: %ld.\n", btreenode_list->objects); - printf(" Maximum tree node size: %d.\n", max_btreenode_size); - printf(" Maximum tree depth: %d.\n", max_btree_depth); - } - // Order the sorted points. - ordervertices(permutarray, in->numberofpoints); - } else if (b->hilbertcurve) { + + if (b->verbose) { + printf(" Permuting vertices.\n"); + } + srand(in->numberofpoints); + for (i = 0; i < in->numberofpoints; i++) { + randindex = rand() % (i + 1); // randomnation(i + 1); + permutarray[i] = permutarray[randindex]; + permutarray[randindex] = (point) points->traverse(); + } + if (b->brio_hilbert) { // -b option if (b->verbose) { - printf(" Sorting vertices by hilbert curve.\n"); + printf(" Sort the points using simple BRIO and Hilbert curve L(%d).\n", + b->hilbert_limit); } - // To be done... - for (i = 0; i < in->numberofpoints; i++) { - permutarray[i] = (point) points->traverse(); + hilbert_init(in->mesh_dim); + max_hcurve_depth_count = 0; + + ngroup = (int) log((double) in->numberofpoints); + nstart = 0; + for (i = 0; i < ngroup; i++) { + nend = in->numberofpoints >> (ngroup - 1 - i); + hilbert_sort3(&(permutarray[nstart]), nend - nstart, 0, 0, // e, d + xmin, xmax, ymin, ymax, zmin, zmax, 0); + nstart = nend; } - } else { if (b->verbose) { - printf(" Permuting vertices.\n"); - } - for (i = 0; i < in->numberofpoints; i++) { - randindex = randomnation(i + 1); - permutarray[i] = permutarray[randindex]; - permutarray[randindex] = (point) points->traverse(); + printf(" Number of sorted subsets: %d.\n", ngroup); + printf(" Maximum curve order: %d.\n", max_hcurve_depth_count); } } @@ -12555,7 +12501,7 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv) printf(" Incrementally inserting vertices.\n"); } - // Choose algorithm: Bowyer-Watson (default) or Incremental Flip (-l). + // Choose algorithm: Bowyer-Watson (default) or Incremental Flip if (b->incrflip) { ivf.bowywat = 0; ivf.lawson = 1; @@ -12564,6 +12510,7 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv) ivf.lawson = 0; } + for (i = 4; i < in->numberofpoints; i++) { if (b->verbose > 2) printf(" #%d", i); if (pointtype(permutarray[i]) == UNUSEDVERTEX) { @@ -12588,22 +12535,20 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv) setpointtype(permutarray[i], DUPLICATEDVERTEX); dupverts++; continue; + } else if (loc == (int) NREGULARVERTEX) { + // The point is non-regular. Skipped. + continue; } if (ivf.lawson) { - // If -l option. Perform flip to recover Delaunayness. + // Perform flip to recover Delaunayness. lawsonflip3d(permutarray[i], ivf.lawson, 0, 0, 0); } } - if (b->btree) { - // Bsp-tree is used only in DT construction. - point **pptary; - for (i = 0; i < (int) btreenode_list->objects; i++) { - pptary = (point **) fastlookup(btreenode_list, i); - delete [] *pptary; - } - delete btreenode_list; - b->btree = 0; // Disable it. + + + if (b->brio_hilbert) { + b->brio_hilbert = 0; // Disable it. } delete [] permutarray; @@ -13522,7 +13467,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) { setshelltype(aseg, shelltype(*splitseg)); setshelltype(bseg, shelltype(*splitseg)); if (checkconstraints) { - setareabound(bseg, areabound(*splitseg)); + setareabound(aseg, areabound(*splitseg)); setareabound(bseg, areabound(*splitseg)); } @@ -14481,6 +14426,9 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist, int iloc; int i, j; + int idx, fmarker; + REAL area; + if (b->verbose > 2) { printf(" f%d: %ld vertices, %ld segments", shmark, ptlist->objects, conlist->objects); @@ -14566,6 +14514,19 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist, setpointtype(pc, FACETVERTEX); } + // Are there area constraints? + if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) { + idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker. + for (i = 0; i < in->numberoffacetconstraints; i++) { + fmarker = (int) in->facetconstraintlist[i * 2]; + if (fmarker == idx) { + area = in->facetconstraintlist[i * 2 + 1]; + setareabound(newsh, area); + break; + } + } + } + // Incrementally build the triangulation. pinfect(pa); pinfect(pb); @@ -14633,14 +14594,9 @@ void tetgenmesh::unifysubfaces(face *f1, face *f2) point pa, pb, pc, pd; int i; - assert(f1->sh != f2->sh); // SELF_CHECK - pa = sorg(*f1); pb = sdest(*f1); pc = sapex(*f1); - - assert(sorg(*f2) == pa); // SELF_CHECK - assert(sdest(*f2) == pb); // SELF_CHECK pd = sapex(*f2); if (pc != pd) { @@ -14687,10 +14643,6 @@ void tetgenmesh::unifysubfaces(face *f1, face *f2) sspivot(*f2, sseg); if (sseg.sh != NULL) { // f2 has a segment. It must be different to f1's. - sspivot(*f1, checkseg); // SELF_CHECK - if (checkseg.sh != NULL) { // SELF_CHECK - assert(checkseg.sh != sseg.sh); // SELF_CHECK - } // Disconnect bonds of subfaces to this segment. spivot(*f2, casout); if (casout.sh != NULL) { @@ -14743,6 +14695,9 @@ void tetgenmesh::unifysegments() int *idx2faclist; int idx, k, m; + int e1, e2; + REAL len; + if (b->verbose > 1) { printf(" Unifying segments.\n"); } @@ -14940,11 +14895,23 @@ void tetgenmesh::unifysegments() } } - // // All identified segments has a marker "-1". - //setshellmark(subsegloop, -1); // All identified segments has an init marker "0". flippool->restart(); + // Are there length constraints? + if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) { + for (k = 0; k < in->numberofsegmentconstraints; k++) { + e1 = (int) in->segmentconstraintlist[k * 3]; + e2 = (int) in->segmentconstraintlist[k * 3 + 1]; + if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) || + ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) { + len = in->segmentconstraintlist[k * 3 + 2]; + setareabound(subsegloop, len); + break; + } + } + } + subsegloop.sh = shellfacetraverse(subsegs); } @@ -15063,12 +15030,13 @@ void tetgenmesh::identifypscedges(point *idx2verlist) int edgemarker; int idx, i, j; + int e1, e2; + REAL len; + if (!b->quiet) { printf("Inserting edges ...\n"); } - //assert(in->numberofedges > 0); // SELF_CHECK - //assert(in->edgemarkerlist != NULL); // SELF_CHECK // All identified segments have the initial marker '0'. // All segments inserted here should have a non-zero marker. @@ -15079,6 +15047,7 @@ void tetgenmesh::identifypscedges(point *idx2verlist) for (i = 0; i < in->numberofedges; i++) { endpts = &(in->edgelist[(i << 1)]); // Find a face contains the edge. + newseg.sh = NULL; searchsh.sh = NULL; idx = endpts[0] - in->firstnumber; for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) { @@ -15151,6 +15120,21 @@ void tetgenmesh::identifypscedges(point *idx2verlist) setpointtype(pb, RIDGEVERTEX); //} } + + if (newseg.sh != NULL) { + if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) { + for (i = 0; i < in->numberofsegmentconstraints; i++) { + e1 = (int) in->segmentconstraintlist[i * 3]; + e2 = (int) in->segmentconstraintlist[i * 3 + 1]; + if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) || + ((pointmark(pa) == e2) && (pointmark(pb) == e1))) { + len = in->segmentconstraintlist[i * 3 + 2]; + setareabound(newseg, len); + break; + } + } + } + } } // i if (b->psc) { @@ -15442,9 +15426,7 @@ void tetgenmesh::interecursive(shellface** subfacearray, int arraysize, toright = true; } // At least one is true; -#ifdef SELF_CHECK assert(!(toleft == false && toright == false)); -#endif if (toleft) { leftarray[leftsize] = sface1.sh; leftsize++; @@ -15644,7 +15626,7 @@ void tetgenmesh::markacutevertices() printf(" Marking acute vertices.\n"); } anglimit = PI / 3.0; // 60 degree. - sharpanglimit = 10.0 / 180.0 * PI; // 10 degree. + sharpanglimit = 5.0 / 180.0 * PI; // 5 degree. minfaceang = PI; // 180 degree. acutecount = sharpsegcount = 0; @@ -15669,11 +15651,9 @@ void tetgenmesh::markacutevertices() // Do a brute-force pair-pair check. for (i=idx2seglist[idx]; i<idx2seglist[idx + 1]; i++) { pb = sdest(segperverlist[i]); - //for (j = i + 1; j < idx2seglist[idx + 1] && !acuteflag; j++) { for (j = i + 1; j < idx2seglist[idx + 1]; j++) { pc = sdest(segperverlist[j]); ang = interiorangle(pa, pb, pc, NULL); - //acuteflag = ang < anglimit; if (!acuteflag) { acuteflag = ang < anglimit; } @@ -15771,7 +15751,7 @@ void tetgenmesh::reportselfintersect(face *checkseg, face *checksh) /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult - tetgenmesh::finddirection(triface* searchtet, point endpt, int randflag) + tetgenmesh::finddirection(triface* searchtet, point endpt) { triface neightet; point pa, pb, pc, pd; @@ -15779,7 +15759,6 @@ enum tetgenmesh::interresult REAL hori, rori, lori; int s; - // The origin is fixed. pa = org(*searchtet); if ((point) searchtet->tet[7] == dummypoint) { @@ -15794,7 +15773,7 @@ enum tetgenmesh::interresult } else if ((point) searchtet->tet[6] == pa) { searchtet->ver = 7; } else { - assert((point) searchtet->tet[7] == pa); // SELF_CHECK + assert((point) searchtet->tet[7] == pa); searchtet->ver = 0; } } @@ -15846,54 +15825,39 @@ enum tetgenmesh::interresult hori = orient3d(pa, pb, pc, endpt); rori = orient3d(pb, pa, pd, endpt); lori = orient3d(pa, pc, pd, endpt); - orient3dcount += 3; // Now decide the tet to move. It is possible there are more than one - // tet are viable moves. Use the opposite points of thier neighbors - // to discriminate, i.e., we choose the tet whose opposite point has - // the shortest distance to 'endpt'. + // tets are viable moves. Is so, randomly choose one. if (hori > 0) { if (rori > 0) { if (lori > 0) { // Any of the three neighbors is a viable move. - if (0) { // if (!randflag) { + s = randomnation(3); + if (s == 0) { + nextmove = HMOVE; + } else if (s == 1) { + nextmove = RMOVE; } else { - // Randomly choose a direction. - s = randomnation(3); // 's' is in {0,1,2}. - if (s == 0) { - nextmove = HMOVE; - } else if (s == 1) { - nextmove = RMOVE; - } else { - nextmove = LMOVE; - } - } // if (randflag) + nextmove = LMOVE; + } } else { // Two tets, below horizon and below right, are viable. - if (0) { // if (!randflag) { + s = randomnation(2); + if (s == 0) { + nextmove = HMOVE; } else { - // Randomly choose a direction. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = HMOVE; - } else { - nextmove = RMOVE; - } - } // if (randflag) + nextmove = RMOVE; + } } } else { if (lori > 0) { // Two tets, below horizon and below left, are viable. - if (0) { // if (!randflag) { + s = randomnation(2); + if (s == 0) { + nextmove = HMOVE; } else { - // Randomly choose a direction. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = HMOVE; - } else { - nextmove = LMOVE; - } - } // if (randflag) + nextmove = LMOVE; + } } else { // The tet below horizon is chosen. nextmove = HMOVE; @@ -15903,16 +15867,12 @@ enum tetgenmesh::interresult if (rori > 0) { if (lori > 0) { // Two tets, below right and below left, are viable. - if (0) { // if (!randflag) { + s = randomnation(2); + if (s == 0) { + nextmove = RMOVE; } else { - // Randomly choose a direction. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = RMOVE; - } else { - nextmove = LMOVE; - } - } // if (randflag) + nextmove = LMOVE; + } } else { // The tet below right is chosen. nextmove = RMOVE; @@ -15972,7 +15932,7 @@ enum tetgenmesh::interresult fsymself(*searchtet); enextself(*searchtet); } - assert(org(*searchtet) == pa); // SELF_CHECK + assert(org(*searchtet) == pa); pb = dest(*searchtet); pc = apex(*searchtet); @@ -16023,7 +15983,7 @@ enum tetgenmesh::interresult } point2tetorg(startpt, *searchtet); - dir = finddirection(searchtet, endpt, 0); + dir = finddirection(searchtet, endpt); if (dir == ACROSSVERT) { pd = dest(*searchtet); @@ -16489,13 +16449,12 @@ void tetgenmesh::delaunizesegments() psseg = (face *) fastlookup(subsegstack, subsegstack->objects); sseg = *psseg; - assert(!sinfected(sseg)); // FOR DEBUG + assert(!sinfected(sseg)); // Check if this segment has been recovered. sstpivot1(sseg, searchtet); if (searchtet.tet != NULL) { - // FOR DEBUG // Check if the tet contains the same segment. - tsspivot1(searchtet, checkseg); + tsspivot1(searchtet, checkseg); // SELF_CHECK assert(checkseg.sh == sseg.sh); continue; // Not a missing segment. } @@ -16538,7 +16497,7 @@ void tetgenmesh::delaunizesegments() ivf.splitbdflag = 0; // ivf.validflag ivf.respectbdflag = 0; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; // Insert the new point into the tetrahedralization T. // Missing segments and subfaces are queued for recovery. // Note that T is convex (nonconvex = 0). @@ -16551,7 +16510,7 @@ void tetgenmesh::delaunizesegments() // For CDT, use flips to reocver Delaunayness. lawsonflip3d(newpt, ivf.lawson, 0, 0, 0); } - st_segref_count++; //st_segpro_count++; + st_segref_count++; if (steinerleft > 0) steinerleft--; } else { // The new point is either ON or VERY CLOSE to an existing point. @@ -16696,7 +16655,7 @@ enum tetgenmesh::interresult // Get a tet whose origin is a. point2tetorg(pa, *searchtet); // Search the edge [a,b]. - dir = finddirection(searchtet, pb, 0); + dir = finddirection(searchtet, pb); if (dir == ACROSSVERT) { // Check validity of a PLC. if (dest(*searchtet) != pb) { @@ -16792,7 +16751,7 @@ void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs, // Get a tet whose origin is a. point2tetorg(pa, searchtet); // Search the edge [a,b]. - dir = finddirection(&searchtet, pb, 0); + dir = finddirection(&searchtet, pb); if (dir != ACROSSVERT) { // This edge is missing. Its neighbor is a missing subface. spivot(*missh, neighsh); @@ -16857,7 +16816,6 @@ void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs, } - /////////////////////////////////////////////////////////////////////////////// // // // scoutcrossedge() Search an edge that crosses the missing region. // @@ -16969,22 +16927,6 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets, // #] which intersects R in its interior, where the edge [d,e] intersects R, // // and d lies below R. // // // -// By knowing a crossing edge [d,e], all tetrahedra sharing at [d,e] must // -// cross R. They are added into the list 'crosstets'. From this set of tets, // -// new crossing edges (if there exist) can be detected. The key is how to // -// detect them correctly. The approach used here is described as follows: // -// Suppose [d,e,a,b] is a crossing tet, where [d,e] intersects R and d lies // -// below R. We look at the face [d,e,a]. If the apex a is not pmarktested, // -// i.e., it is not a vertex of R, then either edge [e,a] or [a,d] intersects // -// R. A simple way is to perform above/below test between [a] and R. But it // -// is not clear which subface of R is the best for this test. Also, this is // -// not safe when R is not strictly planar. A second way is to test if [e,a] // -// intersects one of the subfaces of R. If an intersection is found, then [e,// -// a] is a crossing edge. Otherwise, the edge [a,d] must be a crossing edge // -// of R. NOTE: This statement is correct if the input PLC is correct. We can // -// also detect the incorrectness of the input, e.g., if [a] only touches a // -// subface of R. The second approach is implemented here. It is slow, but is // -// more robust. // // // // 'crosstets' returns the set of crossing tets. Every tet in it has the // // form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R. The // @@ -17017,8 +16959,6 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs, face checkseg; // *paryseg; point pa, pd, pe, *parypt; enum interresult dir; - //REAL ori; - //REAL elen[3]; bool testflag, invalidflag; int types[2], poss[4]; int i, j, k; @@ -17042,8 +16982,6 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs, // Collect all crossing tets. Each cross tet is saved in the standard // form [d,e,#,#], where [d,e] is a corossing edge, d lies below R. // NEITHER d NOR e is a vertex of R (!pmarktested). - // NOTE: hull tets may be collected. See fig/dump-cavity-case2a(b).lua. - // Make sure that neither d nor e is dummypoint. for (i = 0; i < crossedges->objects; i++) { // Get a crossing edge [d,e,#,#]. searchtet = (triface *) fastlookup(crossedges, i); @@ -18294,12 +18232,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue) // p[1], p[0], p[2], p[3]. insph = insphere(p[1], p[0], p[2], p[3], p[4]); - - if (b->flipinsert_ori4dexact) { - ori4 = orient4dexact(p[1], p[0], p[2], p[3], p[4],w[1],w[0],w[2],w[3],w[4]); - } else { - ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]); - } + ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]); if (b->verbose > 2) { printf(" Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]); @@ -18332,7 +18265,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue) // Search an item whose key is larger or equal to current key. prevbf = NULL; nextbf = *pqueue; - if (!b->flipinsert_random) { // Default use a priority queue. + //if (!b->flipinsert_random) { // Default use a priority queue. // Insert the item into priority queue. while (nextbf != NULL) { if (nextbf->key < parybf->key) { @@ -18342,7 +18275,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue) break; } } - } // if (!b->flipinsert_random) // -L1 + //} // if (!b->flipinsert_random) // Insert the new item between prev and next items. if (prevbf == NULL) { *pqueue = parybf; @@ -18456,7 +18389,6 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints, // The list for temporarily storing unflipable faces. bfacearray = new arraypool(sizeof(triface), 4); - fliploop: fcount = 0; // Count the number of flips. @@ -18545,9 +18477,19 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints, assert(checkseg.sh == NULL); // Collect tets sharing at this edge. + // NOTE: This operation may collect tets which lie outside the + // cavity, e.g., when the edge lies on the boundary of the + // cavity. Do not flip if there are outside tets at this edge. + // 2012-07-27. esym(fliptet, fliptets[0]); // [b,a,d,c] n = 0; do { + p1 = apex(fliptets[n]); + if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) { + // This apex is not on the cavity. Hence the face does not + // lie inside the cavity. Do not flip this edge. + n = 1000; break; + } fnext(fliptets[n], fliptets[n + 1]); n++; } while ((fliptets[n].tet != fliptet.tet) && (n < 5)); @@ -18655,7 +18597,7 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints, flipcertify(parytet, &pqueue); } crossfaces->restart(); - if (!b->flipinsert_random) { + if (1) { // if (!b->flipinsert_random) { // Insert all queued unflipped faces. for (i = 0; i < bfacearray->objects; i++) { parytet = (triface *) fastlookup(bfacearray, i); @@ -18683,18 +18625,6 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints, printf("!! No flip is found in %ld faces.\n", bfacearray->objects); assert(0); } - if (b->flipinsert_random) { - // Insert all queued unflipped faces. - for (i = 0; i < bfacearray->objects; i++) { - parytet = (triface *) fastlookup(bfacearray, i); - // This face may be changed. - if (!isdeadtet(*parytet)) { - flipcertify(parytet, &pqueue); - } - } - bfacearray->restart(); - goto fliploop; - } } // 'bfacearray' may be not empty (for what reason ??). @@ -18778,7 +18708,7 @@ bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds, ppt[0] = sorg(oldsh); ppt[1] = sdest(oldsh); point2tetorg(ppt[0], searchtet); - dir = finddirection(&searchtet, ppt[1], 0); + dir = finddirection(&searchtet, ppt[1]); assert(dir == ACROSSVERT); // SELF_CHECK insideflag = false; @@ -18926,7 +18856,7 @@ bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds, ppt[0] = sorg(*parysh); ppt[1] = sdest(*parysh); point2tetorg(ppt[0], searchtet); - dir = finddirection(&searchtet, ppt[1], 0); + dir = finddirection(&searchtet, ppt[1]); assert(dir == ACROSSVERT); // SELF_CHECK tsspivot1(searchtet, checkseg); if (checkseg.sh == NULL) { @@ -19196,7 +19126,7 @@ void tetgenmesh::refineregion() ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 0; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; loc = insertvertex(steinpt, &searchtet, &splitsh, NULL, &ivf); assert((loc != OUTSIDE) && (loc != ONVERTEX)); @@ -19243,7 +19173,7 @@ void tetgenmesh::refineregion() ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 0; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; loc = insertvertex(steinpt, &searchtet, &splitsh, &sseg, &ivf); if (loc == NEARVERTEX) { @@ -19595,10 +19525,8 @@ void tetgenmesh::constraineddelaunay(clock_t& tv) printf("Constrained Delaunay...\n"); } - //if (!b->psc) { - // Only identify acute vertex for PLC inputs. - markacutevertices(); - //} + // Identify acute vertex for PLC inputs. + markacutevertices(); if (b->verbose) { printf(" Delaunizing segments.\n"); @@ -19607,16 +19535,6 @@ void tetgenmesh::constraineddelaunay(clock_t& tv) checksubsegflag = 1; // Put all segments into the list. - if (0) { //if (b->order == 4) { // '-o4' option (for debug) - // In sequential order. - subsegs->traversalinit(); - for (i = 0; i < subsegs->items; i++) { - searchseg.sh = shellfacetraverse(subsegs); - //sinfect(searchseg); // Only save it once. - subsegstack->newindex((void **) &paryseg); - *paryseg = searchseg; - } - } else { // In random order. subsegs->traversalinit(); for (i = 0; i < subsegs->items; i++) { @@ -19630,7 +19548,6 @@ void tetgenmesh::constraineddelaunay(clock_t& tv) paryseg = (face *) fastlookup(subsegstack, s); *paryseg = searchseg; } - } // Recover non-Delaunay segments. delaunizesegments(); @@ -19711,10 +19628,6 @@ void tetgenmesh::constraineddelaunay(clock_t& tv) // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',// // other points must not be 'dummypoint'. // // // -// For avoiding mutually flipping, once a crossing face is flipped, it will // -// never be re-created again. Also, we never create a face or edge which is // -// intersecting the current recovering segment or subface. // -// // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, @@ -19746,20 +19659,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, tmppts[0] = pa; tmppts[1] = pb; tmppts[2] = pc; - if (0) { - // Make sure that the three new faces are not degenerate. - for (i = 0; i < 3 && !rejflag; i++) { - facenormal(pe, pd, tmppts[i], normal, 1, &len); - area = sqrt(DOT(normal, normal)); - if (area == 0) { - rejflag = 1; // A degenerate face. - } else { - if ((area / (len * len)) < b->epsilon) { - rejflag = 1; // A nearly degenerate face. - } - } - } // i - } for (i = 0; i < 3 && !rejflag; i++) { intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1], NULL, 1, types, poss); @@ -19775,12 +19674,7 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, // Since [e,d] is the newly created edge. Reject this flip. rejflag = 1; } - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } - } // dir + } } else if (intflag == 4) { // They may intersect at either a point or a line segment. dir = (enum interresult) types[0]; @@ -19790,11 +19684,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, // Since [e,d] is the newly created edge. Reject this flip. rejflag = 1; } - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } } } // if (intflag == 4) } // i @@ -19834,12 +19723,7 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, // Since [e,d] is the newly created edge. Reject this flip. rejflag = 1; } - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } - } + } } else if (intflag == 4) { // [e,d,abovept] is coplanar with the constraining edge 'fc'. // This is poissible if the edge in 'fc' is just the edge [e,d] @@ -19848,11 +19732,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, if (dir == ACROSSEDGE) { // This case can only happen if [e,d] is coplanar with 'fc'. assert(0); // Not possible. - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } } } } @@ -19860,18 +19739,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, } else if (fliptype == 2) { // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c] if (pc != dummypoint) { - if (0) { - // Make sure that [a,b,c] is a valid face. - facenormal(pa, pb, pc, normal, 1, &len); - area = sqrt(DOT(normal, normal)); - if (area == 0) { - rejflag = 1; // A degenerate face. - } else { - if ((area / (len * len)) < b->epsilon) { - rejflag = 1; // A nearly degenerate face. - } - } - } if (!rejflag) { // Check if the new face [a,b,c] intersect the edge in its interior. intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL, @@ -19885,11 +19752,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, } else if (dir == ACROSSEDGE) { // This case is possible since we allow a previous 2-to-3 flip // even it will create a degenerate tet at edge [a,b]. - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } } } else if (intflag == 4) { // [a,b,c] is coplanar with the edge. @@ -19936,11 +19798,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, if (dir == ACROSSEDGE) { assert(0); // Check this case. rejflag = 1; // Do not flip. - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } } } else if (intflag == 4) { // The edge 'fc' is coplanar with [a,b,abovept]. @@ -19950,11 +19807,6 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, if (dir == ACROSSEDGE) { // This case can only happen if [a,b] is coplanar with 'fc'. assert(0); // Not possible. - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || - (dir == TOUCHFACE)) { - assert(0); // Check this case. - } } } } // if (ori1 == 0 && ori2 == 0) @@ -19978,11 +19830,7 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, rejflag = 1; } else if (dir == ACROSSEDGE) { rejflag = 1; - } else { - if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || (dir == TOUCHFACE)) { - assert(0); // Check this case. - } - } + } } else if (intflag == 4) { // The edge [e,d] is coplanar with the face. // There may be two intersections. @@ -20123,7 +19971,7 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, // // // removeedgebyflips() Remove an edge by flips. // // // -// 'flipedge' is a non-convex or flat edge [a,b,#,#]. // +// 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed. // // // // The return value is a positive integer, it indicates whether the edge is // // removed or not. A value "2" means the edge is removed, othereise, the // @@ -20136,23 +19984,15 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) { triface *abtets, spintet; face checkseg, *paryseg; - int counter; // DEBUG int n, nn, i; - // Bakup valuses (for free spaces in flipnm_post()). - int bakunflip = fc->unflip; - int bakcollectnewtets = fc->collectnewtets; - - if (b->verbose > 2) { printf(" Removing edge (%d, %d)\n", pointmark(org(*flipedge)), pointmark(dest(*flipedge))); } - //if (fc != NULL) { - fc->clearcounters(); - //} + fc->clearcounters(); if (checksubsegflag) { // Do not flip a segment. @@ -20162,24 +20002,22 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) printf(" Can't flip a segment (%d, %d).\n", pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); } - //if (fc != NULL) { - fc->encsegcount++; - if (fc->collectencsegflag) { - if (!sinfected(checkseg)) { - // Queue this segment in list. - sinfect(checkseg); - caveencseglist->newindex((void **) &paryseg); - *paryseg = checkseg; - } + fc->encsegcount++; + if (fc->collectencsegflag) { + if (!sinfected(checkseg)) { + // Queue this segment in list. + sinfect(checkseg); + caveencseglist->newindex((void **) &paryseg); + *paryseg = checkseg; } - //} + } return 0; } } // Count the number of tets at edge [a,b]. n = 0; - counter = 0; // Sum of star counters; + int counter = 0; // Sum of star counters. // SELF_CHECK. spintet = *flipedge; i = 0; while (1) { @@ -20204,7 +20042,7 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) maxflipstarsize = n; } if ((b->flipstarsize > 0) && (n > b->flipstarsize)) { - // The star size exceeds the given limit (-YY__). + // The star size exceeds the limit. skpflipstarcount++; return 0; // Do not flip it. } @@ -20216,8 +20054,7 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) i = 0; while (1) { abtets[i] = spintet; - //marktest(abtets[i]); // Marktest it (in Star(ab)). - setelemcounter(abtets[i], 1); + setelemcounter(abtets[i], 1); // Marktest it (in Star(ab)). i++; fnextself(spintet); if (spintet.tet == flipedge->tet) break; @@ -20234,29 +20071,26 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) printf(" Edge is removed.\n"); } } else { + if (b->verbose > 2) { + printf(" Edge is not removed. n(%d), nn(%d).\n", n, nn); + } // Edge is not flipped. Unmarktest the remaining tets in Star(ab). for (i = 0; i < nn; i++) { - //assert(marktested(abtets[i])); - //unmarktest(abtets[i]); assert(elemcounter(abtets[i]) == 1); setelemcounter(abtets[i], 0); } - if (b->verbose > 2) { - printf(" Edge is not removed. n(%d), nn(%d).\n", n, nn); - } // Restore the input edge (needed by Lawson's flip). *flipedge = abtets[0]; } // Release the temporary allocated spaces. // NOTE: fc->unflip must be 0. + int bakunflip = fc->unflip; fc->unflip = 0; - fc->collectnewtets = 0; flipnm_post(abtets, n, nn, 0, fc); fc->unflip = bakunflip; - fc->collectnewtets = bakcollectnewtets; delete [] abtets; @@ -20277,12 +20111,8 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc) triface fliptets[3], flipedge; face checksh; point pa, pb, pc, pd, pe; - point pts[3]; - enum interresult dir; - int types[2], poss[4], pos; REAL ori; int reducflag, rejflag; - int i, j; if (checksubfaceflag) { tspivot(*flipface, checksh); @@ -20296,10 +20126,6 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc) fliptets[0] = *flipface; fsym(*flipface, fliptets[1]); - - assert(!ishulltet(fliptets[0])); - assert(!ishulltet(fliptets[1])); - pa = org(fliptets[0]); pb = dest(fliptets[0]); pc = apex(fliptets[0]); @@ -20343,99 +20169,14 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc) printf(" Face is removed by a 2-to-3 flip.\n"); } return 1; - } else { - if (b->verbose > 2) { - printf(" -- Reject a 2-to-3 flip at face (%d, %d, %d)\n", - pointmark(pa), pointmark(pb), pointmark(pc)); - } - if (fc != NULL) { - fc->rejf23count++; - } } } else { - if (0) { - // Try to flip one of the edges of this face. - pts[0] = org(flipedge); - pts[1] = dest(flipedge); - pts[2] = apex(flipedge); - // Start from the recorded locally non-convex edge 'flipedge'. - for (i = 0; i < 3; i++) { - if (removeedgebyflips(&flipedge, fc) == 2) { - if (b->verbose > 2) { - printf(" Face is removed by removing edge (%d, %d).\n", - pointmark(pts[i]), pointmark(pts[(i+1)%3])); - } - return 1; - } - // The 'flipedge' may be dead in above call. - point2tetorg(pts[i], flipedge); - finddirection(&flipedge, pts[(i+1)%3], 1); - if (dest(flipedge) != pts[(i+1)%3]) { - if (b->verbose > 2) { - printf(" Face is removed during removing edge (%d, %d).\n", - pointmark(pts[i]), pointmark(pts[(i+1)%3])); - } - return 1; - } - } // i - } else { - if (0) { //if (fc->seg[0] != NULL) { - // The face is intersecting a segment. - // Find the edge shared by three corssing faces. - // We assume that the 'flipface' is facing to 'fc->seg[0]'. It is the - // case when the function is called from 'recoveredgebyflips()'. - // DEBUG BEGIN - pa = org(*flipface); - pb = dest(*flipface); - pc = apex(*flipface); - ori = orient3d(pa, pb, pc, fc->seg[0]); - assert(ori < 0); - // DEBUG END - fsym(*flipface, flipedge); - pc = oppo(flipedge); - for (i = 0; i < 3; i++) { - pa = org(flipedge); - pb = dest(flipedge); - if (tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL, 1, - types, poss)) { - dir = (enum interresult) types[0]; - if (dir == ACROSSFACE) { - break; // Found the crossing face. - } else if (dir == ACROSSEDGE) { - // Found an edge intersects the segment. - esymself(flipedge); - pos = poss[0]; - for (j = 0; j < pos; j++) { - eprevself(flipedge); - } - // Flip this edge. - break; - } else if (dir == SHAREVERT) { - // We have reached the endpoint of the segment. - assert(pc == fc->seg[1]); - // The face is not flippable. - return 0; - } else { - assert(0); // Not possible. - } - } - enextself(flipedge); - } - assert(i < 3); - } else { - if (b->verbose > 2) { - pa = org(flipedge); - pb = dest(flipedge); - } - } - // Try to flip the selected edge of this face. - if (removeedgebyflips(&flipedge, fc) == 2) { - if (b->verbose > 2) { - printf(" Face is removed by removing edge (%d, %d).\n", - pointmark(pa), pointmark(pb)); - } - return 1; + // Try to flip the selected edge of this face. + if (removeedgebyflips(&flipedge, fc) == 2) { + if (b->verbose > 2) { + printf(" Face is removed by removing an edge.\n"); } + return 1; } } @@ -20461,22 +20202,19 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc) int tetgenmesh::recoveredgebyflips(point startpt, point endpt, triface* searchtet, int fullsearch) { - triface neightet, spintet; // *abtets; + triface neightet, spintet; point pa, pb, pc, pd; badface bakface; enum interresult dir, dir1; flipconstraints fc; int types[2], poss[4], pos = 0; int success; - //int n, endi; - int i, j; //, k; + int i, j; if (b->verbose > 2) { printf(" Recovering edge (%d, %d)\n", pointmark(startpt), pointmark(endpt)); } - - fc.seg[0] = startpt; fc.seg[1] = endpt; @@ -20485,14 +20223,13 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt, // Search the edge from 'startpt'. point2tetorg(startpt, *searchtet); - assert(org(*searchtet) == startpt); // SELF_CHECK - dir = finddirection(searchtet, endpt, 1); + dir = finddirection(searchtet, endpt); if (dir == ACROSSVERT) { if (dest(*searchtet) == endpt) { return 1; // Edge is recovered. } else { // A PLC problem, or there is a Steiner point. - terminatetetgen(3); //assert(0); // Debug + terminatetetgen(3); } } @@ -20518,168 +20255,165 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt, if (fullsearch) { - if (1) { - // Try to flip one of the faces/edges which intersects the edge. - success = 0; + // Try to flip one of the faces/edges which intersects the edge. + success = 0; - // Loop through the sequence of intersecting faces/edges from - // 'startpt' to 'endpt'. - point2tetorg(startpt, *searchtet); - assert(org(*searchtet) == startpt); // SELF_CHECK - dir = finddirection(searchtet, endpt, 1); - assert(dir != ACROSSVERT); + // Loop through the sequence of intersecting faces/edges from + // 'startpt' to 'endpt'. + point2tetorg(startpt, *searchtet); + dir = finddirection(searchtet, endpt); + //assert(dir != ACROSSVERT); - // Go to the face/edge intersecting the searching edge. - enextesymself(*searchtet); // Go to the opposite face. - // This face/edge has been tried in previous step. + // Go to the face/edge intersecting the searching edge. + enextesymself(*searchtet); // Go to the opposite face. + // This face/edge has been tried in previous step. - while (1) { // Loop I-I + while (1) { // Loop I-I - // Find the next intersecting face/edge. - fsymself(*searchtet); - if (dir == ACROSSFACE) { - neightet = *searchtet; - j = (neightet.ver & 3); // j is the current face number. - for (i = j + 1; i < j + 4; i++) { - neightet.ver = (i % 4); + // Find the next intersecting face/edge. + fsymself(*searchtet); + if (dir == ACROSSFACE) { + neightet = *searchtet; + j = (neightet.ver & 3); // j is the current face number. + for (i = j + 1; i < j + 4; i++) { + neightet.ver = (i % 4); + pa = org(neightet); + pb = dest(neightet); + pc = apex(neightet); + pd = oppo(neightet); // The above point. + if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) { + dir = (enum interresult) types[0]; + pos = poss[0]; + break; + } else { + dir = DISJOINT; + pos = 0; + } + } // i + // There must be an intersection face/edge. + assert(dir != DISJOINT); // SELF_CHECK + } else { + assert(dir == ACROSSEDGE); + while (1) { // Loop I-I-I + // Check the two opposite faces (of the edge) in 'searchtet'. + for (i = 0; i < 2; i++) { + if (i == 0) { + enextesym(*searchtet, neightet); + } else { + eprevesym(*searchtet, neightet); + } pa = org(neightet); pb = dest(neightet); pc = apex(neightet); pd = oppo(neightet); // The above point. - if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) { + if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) { dir = (enum interresult) types[0]; pos = poss[0]; - break; + break; // for loop } else { dir = DISJOINT; pos = 0; } } // i - // There must be an intersection face/edge. - assert(dir != DISJOINT); // SELF_CHECK - } else { - assert(dir == ACROSSEDGE); - while (1) { // Loop I-I-I - // Check the two opposite faces (of the edge) in 'searchtet'. - for (i = 0; i < 2; i++) { - if (i == 0) { - enextesym(*searchtet, neightet); - } else { - eprevesym(*searchtet, neightet); - } - pa = org(neightet); - pb = dest(neightet); - pc = apex(neightet); - pd = oppo(neightet); // The above point. - if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) { - dir = (enum interresult) types[0]; - pos = poss[0]; - break; // for loop - } else { - dir = DISJOINT; - pos = 0; - } - } // i - if (dir != DISJOINT) { - // Find an intersection face/edge. - break; // Loop I-I-I - } - // No intersection. Rotate to the next tet at the edge. - fnextself(*searchtet); - } // while (1) // Loop I-I-I - } + if (dir != DISJOINT) { + // Find an intersection face/edge. + break; // Loop I-I-I + } + // No intersection. Rotate to the next tet at the edge. + fnextself(*searchtet); + } // while (1) // Loop I-I-I + } - // Adjust to the intersecting edge/vertex. - for (i = 0; i < pos; i++) { - enextself(neightet); - } + // Adjust to the intersecting edge/vertex. + for (i = 0; i < pos; i++) { + enextself(neightet); + } - if (dir == SHAREVERT) { - // Check if we have reached the 'endpt'. - pd = org(neightet); - if (pd == endpt) { - // Failed to recover the edge. - break; // Loop I-I - } else { - // We need to further check this case. It might be a PLC problem - // or a Steiner point that was added at a bad location. - assert(0); - } + if (dir == SHAREVERT) { + // Check if we have reached the 'endpt'. + pd = org(neightet); + if (pd == endpt) { + // Failed to recover the edge. + break; // Loop I-I + } else { + // We need to further check this case. It might be a PLC problem + // or a Steiner point that was added at a bad location. + assert(0); } + } - // The next to be flipped face/edge. - *searchtet = neightet; + // The next to be flipped face/edge. + *searchtet = neightet; - // Bakup this face (tetrahedron). - bakface.forg = org(*searchtet); - bakface.fdest = dest(*searchtet); - bakface.fapex = apex(*searchtet); - bakface.foppo = oppo(*searchtet); + // Bakup this face (tetrahedron). + bakface.forg = org(*searchtet); + bakface.fdest = dest(*searchtet); + bakface.fapex = apex(*searchtet); + bakface.foppo = oppo(*searchtet); - // Try to flip this intersecting face/edge. - if (dir == ACROSSFACE) { - if (removefacebyflips(searchtet, &fc)) { - success = 1; - break; // Loop I-I - } - } else if (dir == ACROSSEDGE) { - if (removeedgebyflips(searchtet, &fc) == 2) { - success = 1; - break; // Loop I-I - } - } else { - assert(0); // A PLC problem. - } - - // The face/edge is not flipped. - if ((searchtet->tet == NULL) || - (org(*searchtet) != bakface.forg) || - (dest(*searchtet) != bakface.fdest) || - (apex(*searchtet) != bakface.fapex) || - (oppo(*searchtet) != bakface.foppo)) { - // 'searchtet' was flipped. We must restore it. - point2tetorg(bakface.forg, *searchtet); - dir1 = finddirection(searchtet, bakface.fdest, 1); - if (dir1 == ACROSSVERT) { - assert(dest(*searchtet) == bakface.fdest); - spintet = *searchtet; - while (1) { - if (apex(spintet) == bakface.fapex) { - // Found the face. - *searchtet = spintet; - break; - } - fnextself(spintet); - if (spintet.tet == searchtet->tet) { + // Try to flip this intersecting face/edge. + if (dir == ACROSSFACE) { + if (removefacebyflips(searchtet, &fc)) { + success = 1; + break; // Loop I-I + } + } else if (dir == ACROSSEDGE) { + if (removeedgebyflips(searchtet, &fc) == 2) { + success = 1; + break; // Loop I-I + } + } else { + assert(0); // A PLC problem. + } + + // The face/edge is not flipped. + if ((searchtet->tet == NULL) || + (org(*searchtet) != bakface.forg) || + (dest(*searchtet) != bakface.fdest) || + (apex(*searchtet) != bakface.fapex) || + (oppo(*searchtet) != bakface.foppo)) { + // 'searchtet' was flipped. We must restore it. + point2tetorg(bakface.forg, *searchtet); + dir1 = finddirection(searchtet, bakface.fdest); + if (dir1 == ACROSSVERT) { + assert(dest(*searchtet) == bakface.fdest); + spintet = *searchtet; + while (1) { + if (apex(spintet) == bakface.fapex) { + // Found the face. + *searchtet = spintet; + break; + } + fnextself(spintet); + if (spintet.tet == searchtet->tet) { + searchtet->tet = NULL; + break; // Not find. + } + } // while (1) + if (searchtet->tet != NULL) { + if (oppo(*searchtet) != bakface.foppo) { + fsymself(*searchtet); + if (oppo(*searchtet) != bakface.foppo) { + assert(0); // Check this case. searchtet->tet = NULL; break; // Not find. } - } // while (1) - if (searchtet->tet != NULL) { - if (oppo(*searchtet) != bakface.foppo) { - fsymself(*searchtet); - if (oppo(*searchtet) != bakface.foppo) { - assert(0); // Check this case. - searchtet->tet = NULL; - break; // Not find. - } - } } - } else { - searchtet->tet = NULL; // Not find. - } - if (searchtet->tet == NULL) { - success = 0; // This face/edge has been destroed. - break; // Loop I-I } + } else { + searchtet->tet = NULL; // Not find. + } + if (searchtet->tet == NULL) { + success = 0; // This face/edge has been destroed. + break; // Loop I-I } - } // while (1) // Loop I-I - - if (success) { - // One of intersecting faces/edges is flipped. - continue; } - } // if (0) + } // while (1) // Loop I-I + + if (success) { + // One of intersecting faces/edges is flipped. + continue; + } } // if (fullsearch) @@ -20701,24 +20435,13 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt, // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)]. Moreover, // // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'. A special // // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b]. // +// Such set of tets arises when we want to recover an edge from 'p0' to 'p_ // +// (n-1)', and the number of tets at [a,b] can not be reduced by any flip. // // // -// These set of tets arises when we want to recover an edge from 'p0' to 'p_ // -// (n-1)', and the recoveredgenbyflips() routine fails. Note that the outer // -// faces of these tets defines a polyhedron P, and the set of tets gives the // -// ONLY tetrahedralization of P. If we replace the two boundary faces [a,b, // -// p0] and [a,b,p_(n-1)] by [p0,p_(n-1),a] and [p0,p_(n-1),b], and call the // -// new polyhedron P'. In this routine, we think P' is not tetrahedralizable // -// (since the routine recoveredgenbyflips() fails!! AND no flip is possible // -// on any of these edges: [a,p1], [b,p1], [a,p2], [b,p2], ..., [a,p_(n-2)], // -// and [b,p_(n-1)]). If n = 3, P' is just the famous Schoenhardt polyhedron. // -// For n > 3, we call P' the generalized Schoenhardt polyhedron, it includes // -// the Bagemihl's polyhedron as a special case. // -// // -// It is obvious that P is a Star-shaped polyhedron. The mid-point of [a,b] // -// is visible by all boundary faces of P, push it slightly inside P does not // -// change the visibilty. Indeed every interior point of [a,b] is visible by // -// the boundary faces of P. // -// // +// The union of these tets is a polyhedron P. Obviously that P is a star- // +// shaped polyhedron. The midpoint of [a,b] is visible by all boundary faces // +// of P, push it slightly inside P does not change the visibilty. Indeed // +// every interior point of [a,b] is visible by the boundary faces of P. // // // /////////////////////////////////////////////////////////////////////////////// @@ -20874,7 +20597,7 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n, ivf.splitbdflag = 0; ivf.validflag = 0; ivf.respectbdflag = 0; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; // Insert the new point into the tetrahedralization T. // Note that T is convex (nonconvex = 0). @@ -20882,7 +20605,7 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n, if (loc == (int) INSTAR) { // The vertex has been inserted. - st_volref_count++; //st_inpoly_count++; + st_volref_count++; if (steinerleft > 0) steinerleft--; return 1; } else { @@ -20923,8 +20646,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) // Try to recover the edge by adding Steiner points. point2tetorg(startpt, searchtet); - assert(org(searchtet) == startpt); // SELF_CHECK - dir = finddirection(&searchtet, endpt, 1); + dir = finddirection(&searchtet, endpt); assert(dir != ACROSSVERT); // Get the first intersecting face/edge. @@ -21131,7 +20853,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; loc = insertvertex(steinerpt, &searchtet, &splitsh, misseg, &ivf); if (loc != ivf.iloc) { @@ -21167,7 +20889,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; loc = insertvertex(steinerpt, &searchtet, &splitsh, misseg, &ivf); assert(loc != (int) ONVERTEX); @@ -21189,17 +20911,11 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) // // // recoversegments() Recover all segments. // // // -// All segments need to be recovered are in 'subsegstack' (Q). They will be // -// be recovered one by one. // -// // -// Each segment is first tried to be recovered by a sequence of flips which // -// removes faces intersecting this segment. However, it is not always possi- // -// ble to recover it by only this way. Then, Steiner points will be added to // -// help the recovery of it by flips. // +// All segments need to be recovered are in 'subsegstack'. // // // -// If 'steinerflag' is set, Steiner points will be added if a segment is not // -// able to recovered by flips. Otherwise, the segment is not recovered, and // -// it is returned in 'misseglist'. // +// This routine first tries to recover each segment by only using flips. If // +// no flip is possible, and the flag 'steinerflag' is set, it then tries to // +// insert Steiner points near or in the segment. // // // /////////////////////////////////////////////////////////////////////////////// @@ -21211,7 +20927,7 @@ int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch, point startpt, endpt; int success; - long bak_inpoly_count = st_volref_count; //st_inpoly_count; + long bak_inpoly_count = st_volref_count; if (b->verbose > 1) { printf(" Recover segments [%s level = %2d] #: %ld.\n", @@ -21334,7 +21050,6 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc, pointmark(pb), pointmark(pc)); } - fc.fac[0] = pa; fc.fac[1] = pb; fc.fac[2] = pc; @@ -21344,8 +21059,7 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc, while (1) { // Get a tet containing the edge [a,b]. point2tetorg(fc.fac[i], *searchtet); - assert(org(*searchtet) == fc.fac[i]); // SELF_CHECK - dir = finddirection(searchtet, fc.fac[(i+1)%3], 1); + dir = finddirection(searchtet, fc.fac[(i+1)%3]); //assert(dir == ACROSSVERT); assert(dest(*searchtet) == fc.fac[(i+1)%3]); // Search the face [a,b,c] @@ -21553,7 +21267,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag) endpt = sdest(searchsh); point2tetorg(startpt, searchtet); assert(org(searchtet) == startpt); // SELF_CHECK - dir = finddirection(&searchtet, endpt, 1); + dir = finddirection(&searchtet, endpt); if (dir == ACROSSVERT) { if (dest(searchtet) == endpt) { success = 1; @@ -21653,7 +21367,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf); assert(loc != (int) OUTSIDE); @@ -21743,7 +21457,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = 0; + ivf.assignmeshsize = b->metric; loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf); assert(loc != (int) OUTSIDE); @@ -21982,13 +21696,13 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge) // Search for the edge [e1, e2]. point2tetorg(e1, *tedge); - finddirection(tedge, e2, 1); + finddirection(tedge, e2); if (dest(*tedge) == e2) { return 1; } else { // Search for the edge [e2, e1]. point2tetorg(e2, *tedge); - finddirection(tedge, e1, 1); + finddirection(tedge, e1); if (dest(*tedge) == e1) { esymself(*tedge); return 1; @@ -22121,7 +21835,7 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist) } } else { point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, *pendpt, 1); + dir = finddirection(&searchtet, *pendpt); } if (dir == ACROSSVERT) { if (dest(searchtet) == *pendpt) { @@ -22176,21 +21890,6 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist) // n edges connected at p. We try to reduce the number of edges by flipping // // any edge (not a segment) that is connecting at p. // // // -// The original location of 'p' in the tetrahedralization without 'p' is ind-// -// icated by 'iloc'. 'searchtet' (t) is a tet in the current tetrahedralizat-// -// ion which contains 'p'. Depending on 'iloc', it means the followig: // -// - INTET: the origin of 't' is 'p'; // -// - ONFACE: the origin of 't' is 'p', the face of 't' was split by 'p'; // -// - ONEDGE: the origin of 't' is 'p', the edge of 't' was split by 'p'; // -// // -// If 'parentsh' (s) is given (not NULL), it indicates that 'p' is a Steiner // -// point on a facet, and 's' was a subface created by the insertion of 'p'. // -// 'iloc' must be either ONFACE or 'OEDGE'. The origin of 's' is 'p'. // -// // -// If 'parentseg' (seg) is given (not NULL), it indicated that 'p' is a // -// Steiner point on a segment, and 'seg' was a subsegment created by 'p'. // -// 'iloc' must be ONEDGE. The original of 'seg' is 'p'. // -// // // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' // // can be successfully removed. // // // @@ -22241,13 +21940,11 @@ int tetgenmesh::removevertexbyflips(point steinerpt) if (b->verbose > 2) { printf(" Removing Steiner point %d in facet.\n", pointmark(steinerpt)); - } } else if (vt == FREEVOLVERTEX) { if (b->verbose > 2) { printf(" Removing Steiner point %d in volume.\n", pointmark(steinerpt)); - } } else { // It is not a Steiner point. @@ -22276,7 +21973,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt) // Inverted elements. getvertexstar(1, steinerpt, cavetetlist, NULL, NULL); if (cavetetlist->objects == 2) { - printf("to be continued..."); + printf("to be continued...\n"); assert(0); } else { assert(0); // Unknown cases. @@ -22399,7 +22096,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt) if (!removeflag) { if (vt == FREESEGVERTEX) { - // Check if the edge [lpr, rpt] exists. + // Check if the edge [lpt, rpt] exists. if (getedge(lpt, rpt, &searchtet)) { // We have recovered this edge. Shift the vertex into the volume. // We can recover this edge if the subfaces are not recovered yet. @@ -22536,14 +22233,6 @@ int tetgenmesh::removevertexbyflips(point steinerpt) // degenerate (has zero volume). It will be deleted in the followed // 4-to-1 flip. flip32(&(fliptets[3]), 1, 0, 0); - // DEBUG BEGIN - // fliptets[3] is [a,b,c,p], check it. - assert(org(fliptets[3]) == apex(fliptets[0])); // a - assert(dest(fliptets[3]) == apex(fliptets[1])); // b - assert(apex(fliptets[3]) == apex(fliptets[2])); // c - assert(oppo(fliptets[3]) == steinerpt); - // fliptets[4] is [b,a,c,e]. - // DEBUG END // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p]. // This creates a new tet [a,b,c,d]. flip41(fliptets, 1, 0, 0); @@ -22664,7 +22353,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt) // Insert the new segment. point2tetorg(lpt, searchtet); - finddirection(&searchtet, rpt, 1); + finddirection(&searchtet, rpt); assert(dest(searchtet) == rpt); sstbond1(rightseg, searchtet); spintet = searchtet; @@ -23249,7 +22938,6 @@ void tetgenmesh::recoverboundary(clock_t& tv) printf(" Flip link level = %d\n", b->fliplinklevel); } - //markacutevertices(); if (b->verbose) { printf(" Recovering segments.\n"); @@ -23261,16 +22949,6 @@ void tetgenmesh::recoverboundary(clock_t& tv) misseglist = new arraypool(sizeof(face), 8); bdrysteinerptlist = new arraypool(sizeof(point), 8); - if (0) { //if (b->order == 4) { // '-o4' option (for debug) - // In sequential order. - subsegs->traversalinit(); - for (i = 0; i < subsegs->items; i++) { - searchseg.sh = shellfacetraverse(subsegs); - //sinfect(searchseg); // Only save it once. - subsegstack->newindex((void **) &paryseg); - *paryseg = searchseg; - } - } else { // In random order. subsegs->traversalinit(); for (i = 0; i < subsegs->items; i++) { @@ -23284,7 +22962,6 @@ void tetgenmesh::recoverboundary(clock_t& tv) paryseg = (face *) fastlookup(subsegstack, s); *paryseg = searchseg; } - } // The init number of missing segments. ms = subsegs->items; @@ -23294,7 +22971,6 @@ void tetgenmesh::recoverboundary(clock_t& tv) } while (1) { - recoversegments(misseglist, 0, 0); if (misseglist->objects > 0) { @@ -23599,10 +23275,11 @@ void tetgenmesh::recoverboundary(clock_t& tv) // // /////////////////////////////////////////////////////////////////////////////// + void tetgenmesh::carveholes() { - arraypool *tetarray; - triface tetloop, neightet, hulltet, *parytet; + arraypool *tetarray, *hullarray; + triface tetloop, neightet, hulltet, *parytet, *parytet1; triface openface, casface; triface *regiontets; face checksh, casingout, casingin, *parysh; @@ -23614,20 +23291,27 @@ void tetgenmesh::carveholes() int regioncount; int attrnum, attr, maxattr; int remflag; - int i, j; + int i, j, k; tetrahedron ptr; + shellface sptr; if (!b->quiet) { printf("Removing exterior tetrahedra ...\n"); } + // Initialize the pool of exterior tets. tetarray = new arraypool(sizeof(triface), 10); - regiontets = NULL; + hullarray = new arraypool(sizeof(triface), 10); + regiontets = NULL; + regioncount = 0; maxattr = 0; // Choose a small number here. - attrnum = in->numberoftetrahedronattributes; + //attrnum = in->numberoftetrahedronattributes; + attrnum = numelemattrib - (b->regionattrib > 0); + // Comment: The element region marker is at the end of the list of + // the element attributes. // Mark as infected any unprotected hull tets. tetrahedrons->traversalinit(); @@ -23641,24 +23325,73 @@ void tetgenmesh::carveholes() infect(tetloop); tetarray->newindex((void **) &parytet); *parytet = tetloop; + hullsize--; + // Add the adjacent tet (not a hull tet) as well. + // tetloop's face number is 11 & 3 = 3. + decode(tetloop.tet[3], neightet); + if (!infected(neightet)) { + infect(neightet); + tetarray->newindex((void **) &parytet); + *parytet = neightet; + } } } tetloop.tet = alltetrahedrontraverse(); } - hullsize -= tetarray->objects; - if (in->numberofholes > 0) { // Mark as infected any tets inside volume holes. for (i = 0; i < 3 * in->numberofholes; i += 3) { // Search a tet containing the i-th hole point. neightet.tet = NULL; randomsample(&(in->holelist[i]), &neightet); - loc = locate(&(in->holelist[i]), &neightet, 0, 1); // randflag = 1; + loc = locate(&(in->holelist[i]), &neightet, 0); if (loc != OUTSIDE) { - infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; + // The tet 'neightet' contain this point. + if (!infected(neightet)) { + infect(neightet); + tetarray->newindex((void **) &parytet); + *parytet = neightet; + // Add its adjacent tet if it is not protected. + tspivot(neightet, checksh); + if (checksh.sh == NULL) { + decode(neightet.tet[neightet.ver & 3], tetloop); + if (!infected(tetloop)) { + infect(tetloop); + tetarray->newindex((void **) &parytet); + *parytet = tetloop; + } + } else { + // It is protected. Check if its adjacent tet is a hull tet. + decode(neightet.tet[neightet.ver & 3], tetloop); + if (!infected(tetloop)) { + if (ishulltet(tetloop)) { + // It is hull tet, add it into the list. Moreover, the subface + // is dead, i.e., both sides are in exterior. + infect(tetloop); + tetarray->newindex((void **) &parytet); + *parytet = tetloop; + stdissolve(checksh); + assert(!sinfected(checksh)); + //if (!sinfected(checksh)) { + sinfect(checksh); // Only queue it once. + subfacstack->newindex((void **) &parysh); + *parysh = checksh; + //} + hullsize--; + } + } else { + // Both sides of this subface are in exterior. + stdissolve(checksh); + assert(!sinfected(checksh)); + //if (!sinfected(checksh)) { + sinfect(checksh); // Only queue it once. + subfacstack->newindex((void **) &parysh); + *parysh = checksh; + //} + } + } + } // if (!infected(neightet)) } else { // A hole point locates outside of the convex hull. if (!b->quiet) { @@ -23666,7 +23399,7 @@ void tetgenmesh::carveholes() printf("lies outside the convex hull.\n"); } } - } + } // i } if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option. @@ -23678,7 +23411,7 @@ void tetgenmesh::carveholes() // Search a tet containing the i-th region point. neightet.tet = NULL; randomsample(&(in->regionlist[i]), &neightet); - loc = locate(&(in->regionlist[i]), &neightet, 0, 1); // randflag = 1; + loc = locate(&(in->regionlist[i]), &neightet, 0); if (loc != OUTSIDE) { regiontets[i/5] = neightet; if ((int) in->regionlist[i + 3] > maxattr) { @@ -23694,58 +23427,62 @@ void tetgenmesh::carveholes() } } + // Find and infect all exterior tets (in concave place and in holes). for (i = 0; i < tetarray->objects; i++) { parytet = (triface *) fastlookup(tetarray, i); - tetloop = *parytet; - for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { - fsym(tetloop, neightet); - // Is this side protected by a subface? - tspivot(tetloop, checksh); - if (checksh.sh == NULL) { - // Not protected. Infect it if it is not a hull tet. - if ((point) neightet.tet[7] != dummypoint) { - if (!infected(neightet)) { + // Check its three neighbors if it is not a hull tet. + if ((point) parytet->tet[7] != dummypoint) { + j = (parytet->ver & 3); // j is the current face number. + // Check the neighbors of the other three faces. + for (k = 0, j++; k < 3; k++, j++) { + decode(parytet->tet[j % 4], neightet); // neightet may be a hull tet. + if (!infected(neightet)) { + // Is neightet protected by a subface. + tspivot(neightet, checksh); + if (checksh.sh == NULL) { + // Not proected. Add it into the list. + // It should not be a hull tet. Since all unproected hull tets + // should have already been added into the list. + assert(!ishulltet(neightet)); // SELF_CHECK infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; - } - } - } else { - // Its adjacent tet is protected. - if ((point) neightet.tet[7] == dummypoint) { - // A hull tet. It is dead. - assert(!infected(neightet)); - infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; - // Both sides of this subface are exterior. - stdissolve(checksh); - // Queue this subface (to be deleted later). - if (!sinfected(checksh)) { - sinfect(checksh); // Only queue it once. - subfacstack->newindex((void **) &parysh); - *parysh = checksh; + tetarray->newindex((void **) &parytet1); + *parytet1 = neightet; + } else { + // It is protected. However, if neightet is a hull tet, it is + // also an exterior tet. Moverover, the subface is dead, i.e., + // both sides of it are exterior. + if ((point) neightet.tet[7] == dummypoint) { + infect(neightet); + tetarray->newindex((void **) &parytet1); + *parytet1 = neightet; + // Both sides of this subface are exterior. + stdissolve(checksh); + // Queue this subface (to be deleted later). + assert(!sinfected(checksh)); + //if (!sinfected(checksh)) { + sinfect(checksh); // Only queue it once. + subfacstack->newindex((void **) &parysh); + *parysh = checksh; + //} + hullsize--; + } } - hullsize--; } else { - if (!infected(neightet)) { - // The subface is still connect to a "live" tet - it survived. - // tsbond(neightet, checksh); - } else { - // Both sides of this subface are exterior. - stdissolve(checksh); - // Queue this subface (to be deleted later). + // Both sides of this face are in exterior. + // Check if there is a subface. + tspivot(neightet, checksh); + if (checksh.sh != NULL) { if (!sinfected(checksh)) { sinfect(checksh); // Only queue it once. subfacstack->newindex((void **) &parysh); *parysh = checksh; - } + } } } - } + } // j, k } - } + } // i if (b->regionattrib && (in->numberofregions > 0)) { // Re-check saved region tets to see if they lie outside. @@ -23760,65 +23497,76 @@ void tetgenmesh::carveholes() } } - // Remove all exterior tetrahedra (including infected hull tets). - for (i = 0; i < tetarray->objects; i++) { - parytet = (triface *) fastlookup(tetarray, i); - tetloop = *parytet; - for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { - fsym(tetloop, neightet); - if (!infected(neightet)) { - // A "live" tet (may be a hull tet). Clear its adjacent tet. - neightet.tet[neightet.ver & 3] = NULL; - } - } - tetrahedrondealloc(parytet->tet); - } // i - tetarray->restart(); // Re-use it for new hull tets. +if (!b->convex) { // Create new hull tets. // Update point-to-tet map, segment-to-tet map, and subface-to-tet map. - tetrahedrons->traversalinit(); - tetloop.tet = tetrahedrontraverse(); - while (tetloop.tet != (tetrahedron *) NULL) { - for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { - if (tetloop.tet[tetloop.ver] == NULL) { - tspivot(tetloop, checksh); - assert(checksh.sh != NULL); // SELF_CHECK - // Create a new hull tet. - maketetrahedron(&hulltet); - pa = org(tetloop); - pb = dest(tetloop); - pc = apex(tetloop); - setvertices(hulltet, pb, pa, pc, dummypoint); - bond(tetloop, hulltet); - // Update the subface-to-tet map. - sesymself(checksh); - tsbond(hulltet, checksh); - // Update the segment-to-tet map. - for (i = 0; i < 3; i++) { - tsspivot1(tetloop, checkseg); - if (checkseg.sh != NULL) { - tssbond1(hulltet, checkseg); - sstbond1(checkseg, hulltet); + for (i = 0; i < tetarray->objects; i++) { + parytet = (triface *) fastlookup(tetarray, i); + if ((point) parytet->tet[7] != dummypoint) { + // We must check all four adjacent tets. + for (j = 0; j < 4; j++) { + decode(parytet->tet[j], tetloop); + if (!infected(tetloop)) { + // This face becomes a hull face. + tspivot(tetloop, checksh); + assert(checksh.sh != NULL); // SELF_CHECK + maketetrahedron(&hulltet); + pa = org(tetloop); + pb = dest(tetloop); + pc = apex(tetloop); + setvertices(hulltet, pb, pa, pc, dummypoint); + bond(tetloop, hulltet); + // Update the subface-to-tet map. + sesymself(checksh); + tsbond(hulltet, checksh); + // Update the segment-to-tet map. + for (k = 0; k < 3; k++) { + tsspivot1(tetloop, checkseg); + if (checkseg.sh != NULL) { + tssbond1(hulltet, checkseg); + sstbond1(checkseg, hulltet); + } + enextself(tetloop); + eprevself(hulltet); + } + // Update the point-to-tet map. + ptr = encode(tetloop); + setpoint2tet(pa, ptr); + setpoint2tet(pb, ptr); + setpoint2tet(pc, ptr); + // Save this hull tet in list. + hullarray->newindex((void **) &parytet1); + *parytet1 = hulltet; + } + } // j + } else { + // It is a hull tet. Clear the adjacent hull tets' connections to it. + // Our data structure ensures that the 3rd face opposites dummypoint. + for (j = 0; j < 3; j++) { + decode(parytet->tet[j], neightet); + if (neightet.tet != NULL) { + assert(ishulltet(neightet)); + if (!infected(neightet)) { + neightet.tet[neightet.ver & 3] = NULL; } - enextself(tetloop); - eprevself(hulltet); } - // Save this hull tet in list. - tetarray->newindex((void **) &parytet); - *parytet = hulltet; - } - } - // Update the point-to-tet map. - tetloop.ver = 0; - ptr = encode(tetloop); - ppt = (point *) tetloop.tet; - for (i = 4; i < 8; i++) { - setpoint2tet(ppt[i], ptr); + } // j } - tetloop.tet = tetrahedrontraverse(); - } + } // i + + // Update the hull size. + hullsize += hullarray->objects; + + // Remove all exterior tetrahedra (including infected hull tets). + for (i = 0; i < tetarray->objects; i++) { + parytet = (triface *) fastlookup(tetarray, i); + tetrahedrondealloc(parytet->tet); + } // i + + tetarray->restart(); + if (subfacstack->objects > 0) { // Remove all subfaces which do not attach to any tetrahedron. @@ -23883,6 +23631,7 @@ void tetgenmesh::carveholes() subfacstack->restart(); } + // Some vertices may be not belong to any tet. Mark them. delvertcount = unuverts; delsteinercount = 0l; @@ -23950,12 +23699,10 @@ void tetgenmesh::carveholes() } } - // Update the hull size. - hullsize += tetarray->objects; // Connect new hull tets. - for (i = 0; i < tetarray->objects; i++) { - parytet = (triface *) fastlookup(tetarray, i); + for (i = 0; i < hullarray->objects; i++) { + parytet = (triface *) fastlookup(hullarray, i); hulltet = *parytet; for (j = 0; j < 3; j++) { esym(hulltet, neightet); @@ -23980,13 +23727,118 @@ void tetgenmesh::carveholes() } } - // Set region attributes (when has -A and -AA options). +} else { // '-c' option is set. + + + long bak_subface_count = subfaces->items; + long bak_segment_count = subsegs->items; + + // In this case, we regard every hull face/edge is a subface/segment. + for (i = 0; i < tetarray->objects; i++) { + parytet = (triface *) fastlookup(tetarray, i); + // Only need the hull tet to find convex hull faces. + if ((point) parytet->tet[7] == dummypoint) { + hulltet.tet = parytet->tet; + hulltet.ver = 3; // The hull face. + tspivot(hulltet, checksh); // SELF_CHECK + if (checksh.sh == NULL) { + // Create a subface. + makeshellface(subfaces, &checksh); + pa = org(hulltet); + pb = dest(hulltet); + pc = apex(hulltet); + setsorg(checksh, pa); + setsdest(checksh, pb); + setsapex(checksh, pc); + // Create the point-to-subface map. + sptr = sencode(checksh); + setpoint2sh(pa, sptr); + setpoint2sh(pb, sptr); + setpoint2sh(pc, sptr); + } + // Insert this subface. + // Note: Even the subface is already exist, it may have been + // disconnected from its adjacent tets. + tsbond(hulltet, checksh); + fsym(hulltet, neightet); + assert(infected(neightet)); + sesymself(checksh); + tsbond(neightet, checksh); + sesymself(checksh); + // Create three segments. + for (j = 0; j < 3; j++) { + tsspivot1(hulltet, checkseg); + if (checkseg.sh == NULL) { + // Create a segment. + makeshellface(subsegs, &checkseg); + pa = org(hulltet); + pb = dest(hulltet); + setshvertices(checkseg, pa, pb, NULL); + // Insert the segment into the mesh. + tetloop = hulltet; + pc = apex(hulltet); + checksh.sh = NULL; + while (1) { + tssbond1(tetloop, checkseg); + tspivot(tetloop, checksh); + if (checksh.sh != NULL) { + ssbond1(checksh, checkseg); + sbond1(checkseg, checksh); + } + fnextself(tetloop); + if (apex(tetloop) == pc) break; + } + sstbond1(checkseg, tetloop); + } + enextself(hulltet); + } + // Save this hull tet in list. + hullarray->newindex((void **) &parytet1); + *parytet1 = hulltet; + } + } // i + + hullsize += hullarray->objects; + + if (subfacstack->objects > 0) { + // Uninfect the collected exterior subfaces. + for (i = 0; i < subfacstack->objects; i++) { + parysh = (face *) fastlookup(subfacstack, i); + suninfect(*parysh); + } + } + if (b->regionattrib) { + // Only the hull tets need to be uninfected. + for (i = 0; i < hullarray->objects; i++) { + parytet = (triface *) fastlookup(hullarray, i); + uninfect(*parytet); + } + } else { + // Uninfect all collected tets. + for (i = 0; i < tetarray->objects; i++) { + parytet = (triface *) fastlookup(tetarray, i); + uninfect(*parytet); + } + } + + tetarray->restart(); + + if (b->verbose) { + printf(" Created %ld convex hull boundary faces.\n", + subfaces->items - bak_subface_count); + printf(" Created %ld convex hull boundary edges.\n", + subsegs->items - bak_segment_count); + } + +} // if (b->convex) + + // Set region attributes (the -A option). + if (b->regionattrib) { if (!b->quiet) { printf("Spreading region attributes.\n"); } - regioncount = 0; // If has user-defined region attributes. if (in->numberofregions > 0) { @@ -24007,81 +23859,61 @@ void tetgenmesh::carveholes() if (b->varvolume) { // If has -a option. setvolumebound(tetloop.tet, volume); } - for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { - fsym(tetloop, neightet); - // Is this side protected by a subface? - tspivot(tetloop, checksh); - if (checksh.sh == NULL) { - // Not protected. It must not be a hull tet. - // assert((point) neightet.tet[7] != dummypoint); - if ((point) neightet.tet[7] == dummypoint) { - assert(0); - } - if (!infected(neightet)) { + for (k = 0; k < 4; k++) { + decode(tetloop.tet[k], neightet); + // Is the adjacent already checked? + if (!infected(neightet)) { + // Is this side protected by a subface? + tspivot(neightet, checksh); + if (checksh.sh == NULL) { infect(neightet); tetarray->newindex((void **) &parytet); *parytet = neightet; } - } else { - // Protected. Set attribute for hull tet as well. - if ((point) neightet.tet[7] == dummypoint) { - setelemattribute(neightet.tet, attrnum, attr); - if (b->varvolume) { // If has -a option. - setvolumebound(neightet.tet, volume); - } - } } - } // ver + } // k } // j regioncount++; } // if (regiontets[i/5].tet != NULL) } // i } - if (b->regionattrib > 1) { // If has -AA option. - // Set attributes for all tetrahedra. - attr = maxattr + 1; - tetrahedrons->traversalinit(); - tetloop.tet = tetrahedrontraverse(); - while (tetloop.tet != (tetrahedron *) NULL) { - if (!infected(tetloop)) { - // An unmarked region. - tetarray->restart(); // Re-use this array. - infect(tetloop); - tetarray->newindex((void **) &parytet); - *parytet = tetloop; - // Find and mark all tets. - for (j = 0; j < tetarray->objects; j++) { - parytet = (triface *) fastlookup(tetarray, j); - tetloop = *parytet; - setelemattribute(tetloop.tet, attrnum, attr); - for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { - fsym(tetloop, neightet); + // Set attributes for all tetrahedra. + attr = maxattr + 1; + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + if (!infected(tetloop)) { + // An unmarked region. + tetarray->restart(); // Re-use this array. + infect(tetloop); + tetarray->newindex((void **) &parytet); + *parytet = tetloop; + // Find and mark all tets. + for (j = 0; j < tetarray->objects; j++) { + parytet = (triface *) fastlookup(tetarray, j); + tetloop = *parytet; + setelemattribute(tetloop.tet, attrnum, attr); + for (k = 0; k < 4; k++) { + decode(tetloop.tet[k], neightet); + // Is the adjacent tet already checked? + if (!infected(neightet)) { // Is this side protected by a subface? - tspivot(tetloop, checksh); + tspivot(neightet, checksh); if (checksh.sh == NULL) { - // Not protected. It must not be a hull tet. - assert((point) neightet.tet[7] != dummypoint); - if (!infected(neightet)) { - infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; - } - } else { - // Protected. Set attribute for hull tet as well. - if ((point) neightet.tet[7] == dummypoint) { - setelemattribute(neightet.tet, attrnum, attr); - } + infect(neightet); + tetarray->newindex((void **) &parytet); + *parytet = neightet; } - } // loc - } - attr++; // Increase the attribute. - regioncount++; - } // if (!infected(tetloop)) - tetloop.tet = tetrahedrontraverse(); + } + } // k + } // j + attr++; // Increase the attribute. + regioncount++; } - // Until here, every tet has a region attribute. + tetloop.tet = tetrahedrontraverse(); } + // Until here, every tet has a region attribute. // Uninfect processed tets. tetrahedrons->traversalinit(); @@ -24091,8 +23923,6 @@ void tetgenmesh::carveholes() tetloop.tet = tetrahedrontraverse(); } - // Mesh elements contain region attributes now. - in->numberoftetrahedronattributes++; if (b->verbose) { assert(regioncount > 0); @@ -24102,17 +23932,20 @@ void tetgenmesh::carveholes() printf(" Found 1 domain.\n"); } } - } // if (b->regionattrib) if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option. delete [] regiontets; } delete tetarray; + delete hullarray; + +if (!b->convex) { // The mesh is non-convex now. nonconvex = 1; + // Push all hull tets into 'flipstack'. tetrahedrons->traversalinit(); tetloop.ver = 11; // The face opposite to dummypoint. @@ -24130,6 +23963,9 @@ void tetgenmesh::carveholes() if (b->verbose && (opt_sliver_peels > 0l)) { printf(" Peeled %ld hull slivers.\n", opt_sliver_peels); } + +} + } /////////////////////////////////////////////////////////////////////////////// @@ -24672,7 +24508,7 @@ int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag) if (randflag) { randomsample(searchpt, searchtet); } - loc = locate(searchpt, searchtet, 0, 1); + loc = locate(searchpt, searchtet, 0); if (loc == OUTSIDE) { // Not found. This happens when the mesh is not convex. if (!randflag) break; @@ -24824,13 +24660,9 @@ int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag) // 'iloc' indicates the location of the point w.r.t. 'searchtet'. The size // // is obtained by linear interpolation on the vertices of the tet. // // // -// If 'posflag' is set, only do interpolation when all vertices have a posi- // -// tive value. // -// // /////////////////////////////////////////////////////////////////////////////// -REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc, - int posflag) +REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc) { point *pts, pa, pb, pc; REAL volume, vol[4], wei[4]; @@ -24842,9 +24674,9 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc, if (iloc == (int) INTETRAHEDRON) { pts = (point *) &(searchtet->tet[4]); assert(pts[3] != dummypoint); - if (!posflag || - ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) && - (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0))) { + // Only do interpolation if all vertices have non-zero sizes. + if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) && + (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) { // P1 interpolation. volume = orient3d(pts[0], pts[1], pts[2], pts[3]); vol[0] = orient3d(searchpt, pts[1], pts[2], pts[3]); @@ -24860,9 +24692,8 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc, pa = org(*searchtet); pb = dest(*searchtet); pc = apex(*searchtet); - if (!posflag || - ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) && - (pc[pointmtrindex] > 0))) { + if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) && + (pc[pointmtrindex] > 0)) { volume = triarea(pa, pb, pc); vol[0] = triarea(searchpt, pb, pc); vol[1] = triarea(pa, searchpt, pc); @@ -24874,7 +24705,7 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc, } else if (iloc == (int) ONEDGE) { pa = org(*searchtet); pb = dest(*searchtet); - if (!posflag || ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0))) { + if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) { volume = distance(pa, pb); vol[0] = distance(searchpt, pb); vol[1] = distance(pa, searchpt); @@ -24883,7 +24714,7 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc, } } else if (iloc == (int) ONVERTEX) { pa = org(*searchtet); - if (!posflag || (pa[pointmtrindex] > 0)) { + if (pa[pointmtrindex] > 0) { size = pa[pointmtrindex]; } } @@ -24919,8 +24750,8 @@ void tetgenmesh::interpolatemeshsize() searchtet.tet = NULL; iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1 if (iloc != (int) OUTSIDE) { - // Interpolate the mesh size (posflag = 0) - ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc, 0); + // Interpolate the mesh size. + ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc); setpoint2bgmtet(ploop, bgm->encode(searchtet)); if (count == 0) { // This is the first interpolated point. @@ -24962,7 +24793,8 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) face checkseg, *splitseg; point newpt; insertvertexflags ivf; - REAL *attr, x, y, z, w; + REAL x, y, z, w; + int attribindex, mtrindex; int randflag; int count, index; int loc; @@ -24975,42 +24807,39 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) randflag = 1; // Randomly select start tet for point location. count = 0; index = 0; + attribindex = 0; + mtrindex = 0; for (i = 0; i < addio->numberofpoints; i++) { - makepoint(&newpt, VOLVERTEX); + makepoint(&newpt, UNUSEDVERTEX); x = newpt[0] = addio->pointlist[index++]; y = newpt[1] = addio->pointlist[index++]; z = newpt[2] = addio->pointlist[index++]; + // Read the point attributes. (Including point weights.) + for (j = 0; j < addio->numberofpointattributes; j++) { + newpt[3 + j] = addio->pointattributelist[attribindex++]; + } + // Read the point metric tensor. + for (j = 0; j < addio->numberofpointmtrs; j++) { + newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++]; + } if (b->weighted) { // -w option if (addio->numberofpointattributes > 0) { - // The first point attribute is weight. - w = addio->pointattributelist[addio->numberofpointattributes * i]; + // The first point attribute is its weight. + w = newpt[3]; } else { - // No given weight available. - w = 0; + // No given weight available. Default choose the maximum + // absolute value among its coordinates. + w = fabs(x); + if (w < fabs(y)) w = fabs(y); + if (w < fabs(z)) w = fabs(z); } if (b->weighted_param == 0) { newpt[3] = x * x + y * y + z * z - w; // Weighted DT. } else { // -w1 option newpt[3] = w; // Regular tetrahedralization. } - } else { - newpt[3] = 0; } - // Read the add point attributes if current points have attributes. - if ((addio->numberofpointattributes > 0) && - (in->numberofpointattributes > 0)) { - attr = addio->pointattributelist + addio->numberofpointattributes * i; - for (j = 0; j < in->numberofpointattributes; j++) { - if (j < addio->numberofpointattributes) { - newpt[4 + j] = attr[j]; - } - } - } - // Read the point metric tensor. - //for (j = 0; j < in->numberofpointmtrs; j++) { - // pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++]; - //} // Find the location of the inserted point. searchtet.tet = NULL; @@ -25025,14 +24854,14 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) ivf.bowywat = 3; // Use the "Bowyer-Watson" algorithm to form cavity. ivf.validflag = 1; // Validate the B-W cavity. } - ivf.lawson = 3; - ivf.rejflag = 0; + ivf.lawson = 3; // ??? + ivf.rejflag = 0; // ??? ivf.chkencflag = 0; ivf.sloc = ivf.iloc; ivf.sbowywat = ivf.bowywat; // Surface mesh options. ivf.splitbdflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = 1; + ivf.assignmeshsize = b->metric; splitsh = NULL; splitseg = NULL; @@ -25065,6 +24894,8 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) setpointtype(newpt, FACETVERTEX); splitsh = &checksh; } + } else { + setpointtype(newpt, VOLVERTEX); } // Insert the vertex. @@ -25105,8 +24936,6 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) // // // marksharpsegments() Mark sharp segments. // // // -// All segments are initialized as type NSHARP. // -// // // A segment is SHARP if there are two facets intersecting at it with an // // internal dihedral angle (*) less than an angle \theta. // // // @@ -25139,7 +24968,7 @@ void tetgenmesh::marksharpsegments() minfacetdihed = PI; smallang = 65.0 * PI / 180.0; // 65 degree. - exsmallang = 15.0 * PI / 180.0; // 15 degree. + exsmallang = 5.0 * PI / 180.0; // 5 degree. sharpcount = exsharpcount = 0; // A segment s may have been split into many subsegments. Operate the one @@ -25297,13 +25126,8 @@ void tetgenmesh::marksharpsegments() // (4) the square root of a maximal area constraint in a .var file; // // (5) a maximal length constraint in a .var file; // // // -// If 'b->nobisect' ('-Y' option) is set, every input vertex has a feature // -// size. // -// // -// The feature size of a Steiner point is linearly interpolated from its adj-// -// acent vertices which belong to the "carrier" (the boundary of the lowrest // -// dimension) of this Steiner point. For example, a Steiner point on a seg- // -// ment gets its size from the two endpoints of the segment. // +// If 'b->nobisect' ('-Y' option) is set, every input vertex has a size. It // +// is used to prevent creating too close Steiner points. // // // /////////////////////////////////////////////////////////////////////////////// @@ -25334,9 +25158,8 @@ void tetgenmesh::decidefeaturepointsizes() maxlen = pow(6.0 * b->maxvolume, 1.0 / 3.0); } - // First only assign a size of p if p is not a Steiner point. The size of - // a Steiner point will be interpolated later from the endpoints of the - // segment on which it lies. + // First, assign a size of p if p is a feature point or an input point and + // the -Y option is used. featurecount = 0; points->traversalinit(); ploop = pointtraverse(); @@ -25509,9 +25332,9 @@ void tetgenmesh::decidefeaturepointsizes() printf(" %d feature points.\n", featurecount); } - // Second only assign sizes for all Steiner points. A Steiner point p - // inserted on a sharp segment s is assigned a size by interpolating - // the sizes of the original endpoints of s. + // Second only assign sizes for all Steiner points which were inserted on + // sharp segments. The sizes are interpolated from the endpoints of + // the segments. featurecount = 0; points->traversalinit(); ploop = pointtraverse(); @@ -25541,67 +25364,7 @@ void tetgenmesh::decidefeaturepointsizes() + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]); featurecount++; } // if (featureflag) - } else if (pointtype(ploop) == FREEFACETVERTEX) { - if (b->nobisect) { // -Y option. - // Collect vertices in the Star(p) which are also in the facet - // containing p. - point2shorg(ploop, parentsh); - checksh = parentsh; - while (1) { - assert(sorg(checksh) == ploop); - adjpt = sdest(checksh); - // Collect this vertex. - verlist->newindex((void **) &parypt); - *parypt = adjpt; - // Go to the next subface at p. (counterclockwise) - senext2self(checksh); - spivotself(checksh); - assert(checksh.sh != NULL); - if (checksh.sh == parentsh.sh) break; - if (sorg(checksh) != ploop) sesymself(checksh); - } - assert(verlist->objects > 0); - // Using Shepard interpolation (p=1) to interpolate the size for 'p'. - // Re-use len, lfs_0, lfs_1, lfs_2; - lfs_1 = lfs_2 = 0; - for (i = 0; i < verlist->objects; i++) { - parypt = (point *) fastlookup(verlist, i); - adjpt = *parypt; - if (adjpt[pointmtrindex] > 0) { - len = distance(adjpt, ploop); - lfs_0 = 1.0 / len; - lfs_1 += lfs_0 * adjpt[pointmtrindex]; - lfs_2 += lfs_0; - } - } - assert(lfs_2 > 0); - ploop[pointmtrindex] = lfs_1 / lfs_2; - verlist->restart(); - featurecount++; - } // if (b->nobisect) - } else if (pointtype(ploop) == FREEVOLVERTEX) { - if (b->nobisect) { // -Y option. - getvertexstar(1, ploop, tetlist, verlist, NULL); - // Using Shepard interpolation to interpolate the size for 'p'. - // Re-use len, lfs_0, lfs_1, lfs_2; - lfs_1 = lfs_2 = 0; - for (i = 0; i < verlist->objects; i++) { - parypt = (point *) fastlookup(verlist, i); - adjpt = *parypt; - if (adjpt[pointmtrindex] > 0) { - len = distance(adjpt, ploop); - lfs_0 = 1.0 / len; - lfs_1 += lfs_0 * adjpt[pointmtrindex]; - lfs_2 += lfs_0; - } - } - assert(lfs_2 > 0); - ploop[pointmtrindex] = lfs_1 / lfs_2; - tetlist->restart(); - verlist->restart(); - featurecount++; - } // if (b->nobisect) - } + } } // if (ploop[pointmtrindex] == 0.0) ploop = pointtraverse(); } @@ -25611,7 +25374,8 @@ void tetgenmesh::decidefeaturepointsizes() } if (checkconstraints) { - // A .var file exists. Adjust feature sizes. + // A .var file exists. Adjust feature sizes. And make sure that every + // corner of a constraining facet get a size. if (in->facetconstraintlist) { // Have facet area constrains. subfaces->traversalinit(); @@ -25627,6 +25391,9 @@ void tetgenmesh::decidefeaturepointsizes() if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } + } else { + // This corner has no size yet. Set it. + ploop[pointmtrindex] = varlen; } } // j } @@ -25647,6 +25414,8 @@ void tetgenmesh::decidefeaturepointsizes() if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } + } else { + ploop[pointmtrindex] = varlen; } } // j } @@ -25656,6 +25425,7 @@ void tetgenmesh::decidefeaturepointsizes() } // if (checkconstraints) } + /////////////////////////////////////////////////////////////////////////////// // // // checkseg4encroach() Check if an edge is encroached upon by a point. // @@ -25707,6 +25477,7 @@ int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt) // A segment needs to be split if it is in the following case: // // (1) It is encroached by an existing vertex. // // (2) It has bad quality (too long). // +// (3) Its length is larger than the mesh sizes at its endpoints. // // // // Return 1 if it needs to be split, otherwise, return 0. 'pencpt' returns // // an encroaching point if there exists. 'qflag' returns '1' if the segment // @@ -25860,21 +25631,19 @@ int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag, printf(" Split segment (%d, %d).\n", pointmark(pa), pointmark(pb)); } - if (qflag == 0) { if (shelltype(*splitseg) == SHARP) { // Do not split it (due to a very small angle) even it is encroached. // Avoid creating too many Steiner points. return 0; } - } - - // Quickly check if we CAN split this segment. - if ((encpt == NULL) && (qflag == 0)) { - // Do not split this segment if the length is smaller than the mesh - // size at one of its endpoints. - if ((len < pa[pointmtrindex]) || (len < pb[pointmtrindex])) { - return 0; + // Quickly check if we CAN split this segment. + if (encpt == NULL) { + // Do not split this segment if the length is smaller than the mesh + // size at one of its endpoints. + if ((len < pa[pointmtrindex]) || (len < pb[pointmtrindex])) { + return 0; + } } } @@ -25882,26 +25651,20 @@ int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag, getsteinerptonsegment(splitseg, encpt, newpt); - // Split the segment by the "Bowyer-Watson" algorithm. - // Parameters are chosen as follows: - // - bowywat = 3, preserve subsegments and subfaces; - // - flipflag = 3, check star & link facets for flipping; - // - rejflag = 0, do insertion even if it encoraches upon - // other subsegments or subfaces. + // Split the segment by the Bowyer-Watson algorithm. sstpivot1(*splitseg, searchtet); ivf.iloc = (int) ONEDGE; if (b->psc) { ivf.bowywat = 0; // Do not enlarge the initial cavity. ivf.validflag = 0; // Do not validate the initial cavity. } else { - ivf.bowywat = 3; // Use the "Bowyer-Watson" algorithm to form cavity. + ivf.bowywat = 3; // Preserve subsegments and subfaces; ivf.validflag = 1; // Validate the B-W cavity. } - ivf.lawson = 3; - ivf.rejflag = 0; + ivf.lawson = b->conforming ? 3 : 1; // Check flip for internal new faces?. + ivf.rejflag = 0; // Do not check encroachment of new segments/facets. if ((encpt == NULL) && (qflag == 0)) { - // Do not insert the point if it lies inside some protecting balls. - ivf.rejflag |= 4; + ivf.rejflag |= 4; // Do check encroachment of protecting balls. } ivf.chkencflag = chkencflag; ivf.sloc = ivf.iloc; @@ -25909,35 +25672,22 @@ int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag, ivf.splitbdflag = 1; ivf.respectbdflag = 1; ivf.assignmeshsize = 1; + loc = insertvertex(newpt, &searchtet, &searchsh, splitseg, &ivf); - // The new vertex should not too close to an existing point. - if (loc == (int) NEARVERTEX) { - outnodes(0); - outsubfaces(0); - outsubsegments(0); - assert(0); - } else if (loc == ENCVERTEX) { - // The point lies in some protecting balls. Rejected. - pointdealloc(newpt); - } else if (loc == (int) BADELEMENT) { - // Failed to create a valid sub-cavity in surface mesh. - pointdealloc(newpt); - //prob_subseg_count++; - } else if (loc == (int) ONEDGE) { - // Flip not locally Delaunay link facets by the 'Lawson's algo'. + if (loc == (int) ONEDGE) { + if (b->verbose > 2) { + printf(" Point inserted successfully on segment.\n"); + } + // Flip non-locally Delaunay faces at the link of its star. lawsonflip3d(newpt, 4, 0, chkencflag, 0); st_segref_count++; if (steinerleft > 0) steinerleft--; return 1; } else { - // The vertex was not inserted. For unknown reasons. - //pointdealloc(newpt); - assert(0); + pointdealloc(newpt); + return 0; } - - // Should not be here. - return 0; } /////////////////////////////////////////////////////////////////////////////// @@ -26123,9 +25873,9 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, cent[2] = pa[2] + rhs[2]; rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); - if (b->verbose > 2) { - printf(" circent: (%g, %g, %g)\n", cent[0], cent[1], cent[2]); - printf(" cirradi: %g\n", rd); + if (b->verbose > 3) { + printf(" circent: (%g, %g, %g)\n", cent[0], cent[1], cent[2]); + printf(" cirradi: %g\n", rd); } // Check the quality (radius-edge ratio) of this subface. @@ -26142,8 +25892,8 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, D = sqrt(D); - if (b->verbose > 2) { - printf(" shortest edge length = %g\n", D); + if (b->verbose > 3) { + printf(" shortest edge length = %g\n", D); } rhs[3] = rd / D; // The radius-edge ratio. @@ -26199,9 +25949,7 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, } sesymself(*chkfac); } - } else { - assert(0); - } // if (!lu_decomp) + } return 0; } @@ -26258,9 +26006,6 @@ int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag, rd = distance(ccent, pa); if ((rd <= pa[pointmtrindex]) || (rd <= pb[pointmtrindex]) || (rd <= pc[pointmtrindex])) { - if (b->verbose > 2) { - printf(" Encroaching a protecting ball. Rejected.\n"); - } return 0; } } @@ -26268,8 +26013,6 @@ int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag, // Initialize the inserting point. makepoint(&newpt, FREEFACETVERTEX); - if (0) { - } else { // Split the subface at its circumcenter. for (i = 0; i < 3; i++) newpt[i] = ccent[i]; // Search a subface which contains 'newpt'. @@ -26288,15 +26031,15 @@ int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag, pointdealloc(newpt); return 0; } - } + // Insert the point. stpivot(searchsh, searchtet); //assert((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE)); - // Split the subface by the "Bowyer-Watson" algorithm. - ivf.bowywat = 3; // Form B-W cavity. - ivf.lawson = 3; // Queue faces of the cavity for flipping. - ivf.rejflag = 1; // Reject it if it encroached upon any segment. + // Split the subface by the Bowyer-Watson algorithm. + ivf.bowywat = 3; // Preserve segments and subfaces. + ivf.lawson = b->conforming ? 3 : 1; + ivf.rejflag = 1; // Do check the encroachment of segments. if (qflag == 0) { ivf.rejflag |= 4; // Reject it if it encroached upon any vertex. } @@ -26313,57 +26056,54 @@ int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag, loc = insertvertex(newpt, &searchtet, &searchsh, NULL, &ivf); - if (loc == (int) ENCSEGMENT) { - // The new point encroaches upon some segments. - pointdealloc(newpt); - assert(encseglist->objects > 0); - // Select an encroached segment and split it. - splitflag = 0; - for (i = 0; i < encseglist->objects; i++) { - paryseg = (face *) fastlookup(encseglist, i); - if (splitsegment(paryseg, NULL, qflag, chkencflag | 1)) { - splitflag = 1; // A point is inserted on a segment. - break; - } - } - encseglist->restart(); - if (splitflag) { - // Some segments may need to be repaired. - repairencsegs(chkencflag | 1); - // Queue this subface if it is still alive and not queued. - if (splitfac->sh[3] != NULL) { - if (!smarktest2ed(*splitfac)) { - bface = (badface *) badsubfacs->alloc(); - bface->ss = *splitfac; - smarktest2(bface->ss); // Only queue it once. - bface->forg = sorg(*splitfac); // An alive badface. - } - } + if (loc == (int) ivf.iloc) { + if (b->verbose > 2) { + printf(" Point inserted successfully on facet.\n"); } - return splitflag; - } else if (loc == (int) ENCVERTEX) { - // The point lies inside some protecting balls. Rejected. - pointdealloc(newpt); - } else if (loc == (int) ONVERTEX) { - pointdealloc(newpt); - } else if (loc == (int) NEARVERTEX) { - pointdealloc(newpt); - } else if (loc == (int) BADELEMENT) { - // Failed to create a valid sub-cavity in surface mesh. - pointdealloc(newpt); - } else if (loc == (int) ivf.iloc) { // Flip not locally Delaunay link facets. lawsonflip3d(newpt, 4, 0, chkencflag, 0); st_facref_count++; if (steinerleft > 0) steinerleft--; - return 1; // A point is inserted on facet. + return 1; } else { - // Unknown error. - assert(0); + // Point was not inserted. + if (loc == (int) ENCSEGMENT) { + if (b->verbose > 2) { + printf(" Point encroached upon %ld segments.\n", + encseglist->objects); + } + assert(encseglist->objects > 0); + pointdealloc(newpt); + // Select an encroached segment and split it. + splitflag = 0; + for (i = 0; i < encseglist->objects; i++) { + paryseg = (face *) fastlookup(encseglist, i); + if (splitsegment(paryseg, NULL, qflag, chkencflag | 1)) { + splitflag = 1; // A point is inserted on a segment. + break; + } + } + encseglist->restart(); + if (splitflag) { + // Some segments may need to be repaired. + repairencsegs(chkencflag | 1); + // Queue this subface if it is still alive and not queued. + if (splitfac->sh[3] != NULL) { + if (!smarktest2ed(*splitfac)) { + bface = (badface *) badsubfacs->alloc(); + bface->ss = *splitfac; + smarktest2(bface->ss); // Only queue it once. + bface->forg = sorg(*splitfac); // An alive badface. + } + } + } + return splitflag; + } else { + pointdealloc(newpt); + return 0; + } } - // Should not be here. - return 0; } /////////////////////////////////////////////////////////////////////////////// @@ -26428,6 +26168,7 @@ void tetgenmesh::repairencfacs(int chkencflag) // // /////////////////////////////////////////////////////////////////////////////// + int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) { point pa, pb, pc, pd, *ppt; @@ -26468,8 +26209,8 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) if (!lu_decmp(A, 3, indx, &D, 0)) { // A degenerated tet (vol = 0). - if (b->verbose > 2) { - printf(" Min dihed = 0 (degree)\n"); + if (b->verbose > 3) { + printf(" Min dihed = 0 (degree)\n"); } // Return its barycenter. for (i = 0; i < 3; i++) { @@ -26481,8 +26222,8 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) // Check volume if '-a#' and '-a' options are used. if (b->varvolume || b->fixedvolume) { vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; - if (b->verbose > 2) { - printf(" volume = %g.\n", vol); + if (b->verbose > 3) { + printf(" volume = %g.\n", vol); } if (b->fixedvolume) { if (vol > b->maxvolume) { @@ -26545,8 +26286,8 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) } smlen = sqrt(smlen); D = rd / smlen; - if (b->verbose > 2) { - printf(" Ratio-edge ratio = %g, smlen = %g\n", D, smlen); + if (b->verbose > 3) { + printf(" Ratio-edge ratio = %g, smlen = %g\n", D, smlen); } if (D > b->minratio) { // A bad radius-edge ratio. @@ -26586,8 +26327,8 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd); //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd); } - if (b->verbose > 2) { - printf(" Min dihed = %g (degree)\n", acos(maxcosd) / PI * 180.0); + if (b->verbose > 3) { + printf(" Min dihed = %g (degree)\n", acos(maxcosd) / PI * 180.0); } if (maxcosd > cosmindihed) { // Calculate the circumcenter of this tet. @@ -26672,17 +26413,12 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, makepoint(&newpt, FREEVOLVERTEX); for (i = 0; i < 3; i++) newpt[i] = ccent[i]; + searchtet = *splittet; ivf.iloc = (int) OUTSIDE; - // Parameters are chosen as follows: - // - bowywat = 3, preserve subsegments and subfaces; - // - flipflag = 3, check star & link facets for flipping; - // - rejflag = 3, do not insert the point if it encroaches upon - // any segment or subface. - // - chkencflag = 4, (as input), only check tetrahedra. - ivf.bowywat = 3; - ivf.lawson = 3; - ivf.rejflag = 3; + ivf.bowywat = 3; // Preserve subsegments and subfaces; + ivf.lawson = b->conforming ? 3 : 1; + ivf.rejflag = 3; // Do check for encroached segments and subfaces. if (qflag == 0) { ivf.rejflag |= 4; // Reject it if it lies in some protecting balls. } @@ -26699,7 +26435,10 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, loc = insertvertex(newpt, &searchtet, NULL, NULL, &ivf); if (loc == (int) ENCSEGMENT) { - // There are encroached segments. + if (b->verbose > 2) { + printf(" Point encroached upon %ld segments.\n", + encseglist->objects); + } pointdealloc(newpt); assert(encseglist->objects > 0); splitflag = 0; @@ -26731,7 +26470,10 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, } return splitflag; } else if (loc == (int) ENCSUBFACE) { - // There are encroached subfaces. + if (b->verbose > 2) { + printf(" Point encroached upon %ld subfaces.\n", + encshlist->objects); + } pointdealloc(newpt); assert(encshlist->objects > 0); splitflag = 0; @@ -26782,6 +26524,9 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, } else if (loc == (int) BADELEMENT) { pointdealloc(newpt); } else { + if (b->verbose > 2) { + printf(" Point inserted successfully.\n"); + } // Recover Delaunayness. lawsonflip3d(newpt, 4, 0, chkencflag, 0); // Vertex is inserted. @@ -26850,6 +26595,7 @@ void tetgenmesh::repairbadtets(int chkencflag) } } + /////////////////////////////////////////////////////////////////////////////// // // // enforcequality() Refine the mesh. // @@ -26866,13 +26612,16 @@ void tetgenmesh::delaunayrefinement() int chkencflag; long bak_segref_count, bak_facref_count, bak_volref_count; + long bak_flipcount = flip23count + flip32count + flip44count; if (!b->quiet) { printf("Refining mesh...\n"); } if (b->verbose) { - printf(" Edge length limit = %g.\n", b->minedgelength); + printf(" Min radiu-edge ratio = %g.\n", b->minratio); + printf(" Min dihedral angle = %g.\n", b->mindihedral); + //printf(" Min Edge length = %g.\n", b->minedgelength); } steinerleft = b->steinerleft; // Upperbound of # Steiner points (by -S#). @@ -26884,7 +26633,7 @@ void tetgenmesh::delaunayrefinement() } else { if (!b->quiet) { printf("\nWarning: "); - printf("The desired number of Steiner points (%d) is reached.\n\n", + printf("The desired number of Steiner points (%d) has reached.\n\n", b->steinerleft); } return; // No more Steiner points. @@ -26899,6 +26648,7 @@ void tetgenmesh::delaunayrefinement() decidefeaturepointsizes(); + encseglist = new arraypool(sizeof(face), 8); encshlist = new arraypool(sizeof(badface), 8); @@ -27008,6 +26758,8 @@ void tetgenmesh::delaunayrefinement() st_segref_count - bak_segref_count, st_facref_count - bak_facref_count, st_volref_count - bak_volref_count); + printf(" Performed %ld flips.\n", flip23count + flip32count + + flip44count - bak_flipcount); } } // if (b->reflevel > 2) @@ -27060,10 +26812,10 @@ void tetgenmesh::recoverdelaunay() printf("Recovering Delaunayness...\n"); } - if (b->verbose) { - printf(" max_flipstarsize = %d.\n", b->optmaxflipstarsize); - printf(" max_fliplinklevel = %d.\n", b->delmaxfliplevel); - } + //if (b->verbose) { + // printf(" max_flipstarsize = %d.\n", b->optmaxflipstarsize); + // printf(" max_fliplinklevel = %d.\n", b->delmaxfliplevel); + //} calc_tetprism_vol = 1; tetprism_vol_sum = 0.0; // Initialize it. @@ -27121,7 +26873,7 @@ void tetgenmesh::recoverdelaunay() // For efficiency reason, we limit the maximium size of the edge star. // 'b->optmaxflipstarsize' is set by -OOOOO (5 Os), default is 10. int bakmaxflipstarsize = b->flipstarsize; - b->flipstarsize = b->optmaxflipstarsize; + b->flipstarsize = 10; //b->optmaxflipstarsize; flipqueue = new arraypool(sizeof(badface), 10); nextflipqueue = new arraypool(sizeof(badface), 10); @@ -27286,14 +27038,15 @@ long tetgenmesh::improvequalitybyflips() flipqueue = new arraypool(sizeof(badface), 10); nextflipqueue = new arraypool(sizeof(badface), 10); - // Flip edge options. - b->fliplinklevel = -1; - autofliplinklevel = 1; // Init value. + // Backup flip edge options. + int bakautofliplinklevel = autofliplinklevel; + int bakfliplinklevel = b->fliplinklevel; + int bakmaxflipstarsize = b->flipstarsize; - // For efficiency reason, we limit the maximium size of the edge star. - // 'b->optmaxflipstarsize' is set by -OOOOO (5 Os), default is 10. - int bakmaxflipstarsize = b->flipstarsize; - b->flipstarsize = b->optmaxflipstarsize; + // Set flip edge options. + autofliplinklevel = 1; + b->fliplinklevel = -1; + b->flipstarsize = 10; // b->optmaxflipstarsize; fc.remove_large_angle = 1; fc.unflip = 1; @@ -27320,6 +27073,7 @@ long tetgenmesh::improvequalitybyflips() bface = (badface *) fastlookup(flipqueue, k); if (gettetrahedron(bface->forg, bface->fdest, bface->fapex, bface->foppo, &bface->tt)) { + //assert(!ishulltet(bface->tt)); // There are bad dihedral angles in this tet. if (bface->tt.ver != 11) { // The dihedral angles are permuted. @@ -27413,12 +27167,12 @@ long tetgenmesh::improvequalitybyflips() totalremcount += remcount; if (unflipqueue->objects > 0l) { - // 'b->optmaxfliplevel' is set by -OOO, default is 2. - if (autofliplinklevel >= b->optmaxfliplevel) { - // For efficiency reason, we do not search too far. + //if (autofliplinklevel >= b->optmaxfliplevel) { + if (autofliplinklevel >= b->optlevel) { break; } autofliplinklevel+=b->fliplinklevelinc; + //b->flipstarsize = 10 + (1 << (b->optlevel - 1)); } // Swap the two flip queues. @@ -27427,6 +27181,9 @@ long tetgenmesh::improvequalitybyflips() unflipqueue = swapqueue; } // while (flipqueues->objects > 0) + // Restore original flip edge options. + autofliplinklevel = bakautofliplinklevel; + b->fliplinklevel = bakfliplinklevel; b->flipstarsize = bakmaxflipstarsize; delete flipqueue; @@ -27855,7 +27612,7 @@ int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag) int loc; int n, i; - // 'slitet' is [c,d,a,b], where [c,d] has a big hihedral angle. + // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle. // Go to the opposite edge [a,b]. eprev(*slitet, searchtet); esymself(searchtet); @@ -27868,13 +27625,18 @@ int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag) } // Count the number of tets shared at [a,b]. + // Do not split it if it is a hull edge. spintet = searchtet; n = 0; while (1) { + if (ishulltet(spintet)) break; n++; fnextself(spintet); if (spintet.tet == searchtet.tet) break; } + if (ishulltet(spintet)) { + return 0; // It is a hull edge. + } assert(n >= 3); // Get all tets at edge [a,b]. @@ -28121,11 +27883,12 @@ long tetgenmesh::removeslivers(int chkencflag) // // /////////////////////////////////////////////////////////////////////////////// -void tetgenmesh::optimizemesh(int optflag) +void tetgenmesh::optimizemesh() { badface *parybface; triface checktet; point *ppt; + int optpasses; optparameters opm; REAL ncosdd[6], maxdd; long totalremcount, remcount; @@ -28139,17 +27902,15 @@ void tetgenmesh::optimizemesh(int optflag) printf("Optimizing mesh...\n"); } - if (b->verbose > 1) { - printf(" min_max_dihedral = %g.\n", b->optmaxdihedral); - printf(" max_flipstarsize = %d.\n", b->optmaxflipstarsize); - printf(" max_fliplinklevel = %d.\n", b->optmaxfliplevel); - printf(" number of passes = %d.\n", b->optpasses); + if (b->verbose) { + printf(" Optimization level = %d.\n", b->optlevel); + printf(" Optimization scheme = %d.\n", b->optscheme); + printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral); } - totalsmtcount = totalsptcount = totalremcount = 0l; - if (b->verbose > 1) { - printf(" Removing large angles (> %g degree).\n", b->optmaxdihedral); - } + optpasses = ((1 << b->optlevel) - 1); + + totalsmtcount = totalsptcount = totalremcount = 0l; cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI); cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI); @@ -28181,7 +27942,7 @@ void tetgenmesh::optimizemesh(int optflag) totalremcount = improvequalitybyflips(); if ((unflipqueue->objects > 0l) && - ((b->optlevel & 2) || (b->optlevel & 4))) { // -O2 | -O4 + ((b->optscheme & 2) || (b->optscheme & 4))) { badtetrahedrons = new memorypool(sizeof(badface), b->tetrahedraperblock, memorypool::POINTER, 0); @@ -28195,9 +27956,9 @@ void tetgenmesh::optimizemesh(int optflag) chkencflag = 4; // Queue affected tets after splitting a sliver. iter = 0; - while (iter < b->optpasses) { + while (iter < optpasses) { smtcount = sptcount = remcount = 0l; - if (b->optlevel & 2) { + if (b->optscheme & 2) { smtcount += improvequalitybysmoothing(&opm); totalsmtcount += smtcount; if (smtcount > 0l) { @@ -28206,7 +27967,7 @@ void tetgenmesh::optimizemesh(int optflag) } } if (unflipqueue->objects > 0l) { - if (b->optlevel & 4) { + if (b->optscheme & 4) { sptcount += removeslivers(chkencflag); totalsptcount += sptcount; if (sptcount > 0l) { @@ -28228,7 +27989,7 @@ void tetgenmesh::optimizemesh(int optflag) delete badtetrahedrons; - } // // -O2 | -O4 + } if (unflipqueue->objects > 0l) { if (b->verbose > 1) { @@ -28436,10 +28197,10 @@ int tetgenmesh::checkshells(/*int sub2tet*/) while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) { if (nextsh.sh[3] == NULL) { printf(" !! !! Wrong subface-subface connection (Dead subface).\n"); - printf(" First: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, + printf(" First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); - printf(" Second: x%lx (DEAD)\n", (unsigned long long) nextsh.sh); + printf(" Second: x%lx (DEAD)\n", (unsigned long) nextsh.sh); horrors++; break; } @@ -28447,10 +28208,10 @@ int tetgenmesh::checkshells(/*int sub2tet*/) if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) || ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) { printf(" !! !! Wrong subface-subface connection.\n"); - printf(" First: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, + printf(" First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); - printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long long) nextsh.sh, + printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh, pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), pointmark(sapex(nextsh))); horrors++; @@ -28459,10 +28220,10 @@ int tetgenmesh::checkshells(/*int sub2tet*/) // Check they should not have the same apex. if (sapex(nextsh) == sapex(spinsh)) { printf(" !! !! Existing two duplicated subfaces.\n"); - printf(" First: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, + printf(" First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); - printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long long) nextsh.sh, + printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh, pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), pointmark(sapex(nextsh))); horrors++; @@ -28476,19 +28237,19 @@ int tetgenmesh::checkshells(/*int sub2tet*/) if (checkseg.sh != NULL) { if (checkseg.sh[3] == NULL) { printf(" !! !! Wrong subface-subseg connection (Dead subseg).\n"); - printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); - printf(" Sub: x%lx (Dead)\n", (unsigned long long) checkseg.sh); + printf(" Sub: x%lx (Dead)\n", (unsigned long) checkseg.sh); horrors++; } else { if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) || ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) { printf(" !! !! Wrong subface-subseg connection.\n"); - printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); - printf(" Seg: x%lx (%d, %d).\n", (unsigned long long) checkseg.sh, + printf(" Seg: x%lx (%d, %d).\n", (unsigned long) checkseg.sh, pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); horrors++; } @@ -28502,20 +28263,20 @@ int tetgenmesh::checkshells(/*int sub2tet*/) if (neightet.tet != NULL) { if (neightet.tet[4] == NULL) { printf(" !! !! Wrong sub-to-tet connection (Dead tet)\n"); - printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); - printf(" Tet: x%lx (DEAD)\n", (unsigned long long) neightet.tet); + printf(" Tet: x%lx (DEAD)\n", (unsigned long) neightet.tet); horrors++; } else { if (!((sorg(shloop) == org(neightet)) && (sdest(shloop) == dest(neightet)))) { printf(" !! !! Wrong sub-to-tet connection\n"); - printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); printf(" Tet: x%lx (%d, %d, %d, %d).\n", - (unsigned long long) neightet.tet, pointmark(org(neightet)), + (unsigned long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet))); horrors++; @@ -28524,11 +28285,11 @@ int tetgenmesh::checkshells(/*int sub2tet*/) if (!((sorg(spinsh) == org(neightet)) && (sdest(spinsh) == dest(neightet)))) { printf(" !! !! Wrong tet-sub connection.\n"); - printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); printf(" Tet: x%lx (%d, %d, %d, %d).\n", - (unsigned long long) neightet.tet, pointmark(org(neightet)), + (unsigned long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet))); horrors++; @@ -28539,11 +28300,11 @@ int tetgenmesh::checkshells(/*int sub2tet*/) if (!((sorg(spinsh) == org(symtet)) && (sdest(spinsh) == dest(symtet)))) { printf(" !! !! Wrong tet-sub connection.\n"); - printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); printf(" Tet: x%lx (%d, %d, %d, %d).\n", - (unsigned long long) symtet.tet, pointmark(org(symtet)), + (unsigned long) symtet.tet, pointmark(org(symtet)), pointmark(dest(symtet)), pointmark(apex(symtet)), pointmark(oppo(symtet))); horrors++; @@ -28623,9 +28384,9 @@ int tetgenmesh::checksegments() ((org(tetloop) == pb) && (dest(tetloop) == pa)))) { printf(" !! Wrong tet-seg connection.\n"); printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", - (unsigned long long) tetloop.tet, pointmark(org(tetloop)), + (unsigned long) tetloop.tet, pointmark(org(tetloop)), pointmark(dest(tetloop)), pointmark(apex(tetloop)), - pointmark(oppo(tetloop)), (unsigned long long) sseg.sh, + pointmark(oppo(tetloop)), (unsigned long) sseg.sh, pointmark(pa), pointmark(pb)); horrors++; } else { @@ -28636,11 +28397,11 @@ int tetgenmesh::checksegments() if (checkseg.sh != sseg.sh) { printf(" !! Wrong tet->seg connection.\n"); printf(" Tet: x%lx (%d, %d, %d, %d) - ", - (unsigned long long) neightet.tet, pointmark(org(neightet)), + (unsigned long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet))); if (checkseg.sh != NULL) { - printf("Seg x%lx (%d, %d).\n", (unsigned long long) checkseg.sh, + printf("Seg x%lx (%d, %d).\n", (unsigned long) checkseg.sh, pointmark(sorg(checkseg)),pointmark(sdest(checkseg))); } else { printf("Seg: NULL.\n"); @@ -28660,9 +28421,9 @@ int tetgenmesh::checksegments() ((org(neightet) == pb) && (dest(neightet) == pa)))) { printf(" !! Wrong seg->tet connection (Wrong edge).\n"); printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", - (unsigned long long) neightet.tet, pointmark(org(neightet)), + (unsigned long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), - pointmark(oppo(neightet)), (unsigned long long) sseg.sh, + pointmark(oppo(neightet)), (unsigned long) sseg.sh, pointmark(pa), pointmark(pb)); horrors++; } @@ -28679,7 +28440,7 @@ int tetgenmesh::checksegments() printf(" !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n", pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet)), - (unsigned long long) neightet.tet, neightet.ver); + (unsigned long) neightet.tet, neightet.ver); // Check if all tets at the edge are marked. spintet = neightet; while (1) { @@ -28688,7 +28449,7 @@ int tetgenmesh::checksegments() printf(" !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n", pointmark(org(spintet)), pointmark(dest(spintet)), pointmark(apex(spintet)), pointmark(oppo(spintet)), - (unsigned long long) spintet.tet, spintet.ver); + (unsigned long) spintet.tet, spintet.ver); horrors++; } if (spintet.tet == neightet.tet) break; @@ -28721,7 +28482,7 @@ int tetgenmesh::checksegments() // sesymself(spinsh); // printf(" !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n", // pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), - // pointmark(sapex(spinsh)), (unsigned long long) spinsh.sh, + // pointmark(sapex(spinsh)), (unsigned long) spinsh.sh, // spinsh.shver); // horrors++; //} @@ -28734,7 +28495,7 @@ int tetgenmesh::checksegments() printf(" !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n", pointmark(org(spintet)), pointmark(dest(spintet)), pointmark(apex(spintet)), pointmark(oppo(spintet)), - (unsigned long long) spintet.tet, spintet.ver); + (unsigned long) spintet.tet, spintet.ver); horrors++; } if (checkseg.sh != sseg.sh) { @@ -28753,7 +28514,7 @@ int tetgenmesh::checksegments() } else { printf(" !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n", pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), - pointmark(sapex(spinsh)), (unsigned long long) spinsh.sh, + pointmark(sapex(spinsh)), (unsigned long) spinsh.sh, spinsh.shver); horrors++; break; @@ -29575,7 +29336,11 @@ void tetgenmesh::statistics() tetnumber = tetrahedrons->items - hullsize; facenumber = (tetnumber * 4l + hullsize) / 2l; - printf("\n Mesh points: %ld\n", points->items); + if (b->weighted) { // -w option + printf("\n Mesh points: %ld\n", points->items - nonregularcount); + } else { + printf("\n Mesh points: %ld\n", points->items); + } printf(" Mesh tetrahedra: %ld\n", tetnumber); printf(" Mesh faces: %ld\n", facenumber); printf(" Mesh edges: %ld\n", meshedges); @@ -29584,10 +29349,10 @@ void tetgenmesh::statistics() printf(" Mesh boundary faces: %ld\n", subfaces->items); printf(" Mesh boundary edges: %ld\n", subsegs->items); if (st_segref_count > 0l) { - printf(" Steiner points in boundary edges: %ld\n", st_segref_count); + printf(" Steiner points on boundary edges: %ld\n", st_segref_count); } if (st_facref_count > 0l) { - printf(" Steiner points in boundary faces: %ld\n", st_facref_count); + printf(" Steiner points on boundary faces: %ld\n", st_facref_count); } if (st_volref_count > 0l) { printf(" Steiner points in mesh domain: %ld\n", st_volref_count); @@ -29596,6 +29361,9 @@ void tetgenmesh::statistics() printf(" Convex hull faces: %ld\n", hullsize); printf(" Convex hull edges: %ld\n", meshhulledges); } + if (b->weighted) { // -w option + printf(" Skipped non-regular points: %ld\n", nonregularcount); + } printf("\n"); @@ -29647,7 +29415,7 @@ void tetgenmesh::jettisonnodes() jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || (pointtype(pointloop) == UNUSEDVERTEX); if (jetflag) { - // It is a duplicated point, delete it. + // It is a duplicated or unused point, delete it. pointdealloc(pointloop); remcount++; } else { @@ -29662,12 +29430,6 @@ void tetgenmesh::jettisonnodes() newidx++; } oldidx++; - //if (oldidx == in->numberofpoints) { - // // Update the numbe of input points (Because some were removed). - // in->numberofpoints -= remcount; - // // Remember this number for output original input nodes. - // jettisoninverts = remcount; - //} pointloop = pointtraverse(); } if (b->verbose) { @@ -29683,6 +29445,100 @@ void tetgenmesh::jettisonnodes() points->deaditemstack = (void *) NULL; } +/////////////////////////////////////////////////////////////////////////////// +// // +// highorder() Create extra nodes for quadratic subparametric elements. // +// // +// 'highordertable' is an array (size = numberoftetrahedra * 6) for storing // +// high-order nodes of each tetrahedron. This routine is used only when -o2 // +// switch is used. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::highorder() +{ + triface tetloop, worktet, spintet; + point *extralist, *adjextralist; + point torg, tdest, newpoint; + int highorderindex; + int i, j; + + if (!b->quiet) { + printf("Adding vertices for second-order tetrahedra.\n"); + } + + // Initialize the 'highordertable'. + highordertable = new point[tetrahedrons->items * 6]; + if (highordertable == (point *) NULL) { + terminatetetgen(1); + } + + // This will overwrite the slot for element markers. + highorderindex = 11; + + // The following line ensures that dead items in the pool of nodes cannot + // be allocated for the extra nodes associated with high order elements. + // This ensures that the primary nodes (at the corners of elements) will + // occur earlier in the output files, and have lower indices, than the + // extra nodes. + points->deaditemstack = (void *) NULL; + + // Assign an entry for each tetrahedron to find its extra nodes. At the + // mean while, initialize all extra nodes be NULL. + i = 0; + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i]; + for (j = 0; j < 6; j++) { + highordertable[i + j] = (point) NULL; + } + i += 6; + tetloop.tet = tetrahedrontraverse(); + } + + // To create a unique node on each edge. Loop over all tetrahedra, and + // look at the six edges of each tetrahedron. If the extra node in + // the tetrahedron corresponding to this edge is NULL, create a node + // for this edge, at the same time, set the new node into the extra + // node lists of all other tetrahedra sharing this edge. + tetrahedrons->traversalinit(); + tetloop.tet = tetrahedrontraverse(); + while (tetloop.tet != (tetrahedron *) NULL) { + // Get the list of extra nodes. + extralist = (point *) tetloop.tet[highorderindex]; + worktet.tet = tetloop.tet; + for (i = 0; i < 6; i++) { + if (extralist[i] == (point) NULL) { + // Go to the ith-edge. + worktet.ver = edge2ver[i]; + // Create a new point in the middle of this edge. + torg = org(worktet); + tdest = dest(worktet); + makepoint(&newpoint, FREEVOLVERTEX); + for (j = 0; j < 3 + numpointattrib; j++) { + newpoint[j] = 0.5 * (torg[j] + tdest[j]); + } + // Interpolate its metrics. + for (j = 0; j < in->numberofpointmtrs; j++) { + newpoint[pointmtrindex + j] = + 0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]); + } + // Set this point into all extra node lists at this edge. + spintet = worktet; + while (1) { + if (!ishulltet(spintet)) { + adjextralist = (point *) spintet.tet[highorderindex]; + adjextralist[ver2edge[spintet.ver]] = newpoint; + } + fnextself(spintet); + if (spintet.tet == worktet.tet) break; + } + } // if (!extralist[i]) + } // i + tetloop.tet = tetrahedrontraverse(); + } +} /////////////////////////////////////////////////////////////////////////////// // // @@ -29758,7 +29614,7 @@ void tetgenmesh::outnodes(tetgenio* out) char outnodefilename[FILENAMESIZE]; face parentsh; point pointloop; - int nextras, bmark, marker = 0; + int nextras, bmark, marker = 0, weightDT = 0; int coordindex, attribindex; int pointnumber, firstindex; int index, i; @@ -29776,7 +29632,11 @@ void tetgenmesh::outnodes(tetgenio* out) } } - nextras = in->numberofpointattributes; + nextras = numpointattrib; + if (b->weighted) { // -w + if (b->weighted_param == 0) weightDT = 1; // Weighted DT. + } + bmark = !b->nobound && in->pointmarkerlist; if (out == (tetgenio *) NULL) { @@ -29860,7 +29720,13 @@ void tetgenmesh::outnodes(tetgenio* out) pointloop[0], pointloop[1], pointloop[2]); for (i = 0; i < nextras; i++) { // Write an attribute. - fprintf(outfile, " %.17g", pointloop[4 + i]); + if ((i == 0) && weightDT) { + fprintf(outfile, " %.17g", pointloop[0] * pointloop[0] + + pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2] + - pointloop[3 + i]); + } else { + fprintf(outfile, " %.17g", pointloop[3 + i]); + } } if (bmark) { // Write the boundary marker. @@ -29892,7 +29758,13 @@ void tetgenmesh::outnodes(tetgenio* out) // Point attributes. for (i = 0; i < nextras; i++) { // Output an attribute. - out->pointattributelist[attribindex++] = pointloop[4 + i]; + if ((i == 0) && weightDT) { + out->pointattributelist[attribindex++] = + pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] + + pointloop[2] * pointloop[2] - pointloop[3 + i]; + } else { + out->pointattributelist[attribindex++] = pointloop[3 + i]; + } } if (bmark) { // Output the boundary marker. @@ -30020,7 +29892,7 @@ void tetgenmesh::outelements(tetgenio* out) long ntets; int firstindex, shift; int pointindex, attribindex; - int highorderindex = 10; // The reserved pointer. + int highorderindex = 11; int elementnumber; int eextras; int ishulledge; @@ -30042,7 +29914,7 @@ void tetgenmesh::outelements(tetgenio* out) // The number of tets excluding hull tets. ntets = tetrahedrons->items - hullsize; - eextras = in->numberoftetrahedronattributes; + eextras = numelemattrib; if (out == (tetgenio *) NULL) { outfile = fopen(outelefilename, "w"); if (outfile == (FILE *) NULL) { @@ -30086,8 +29958,13 @@ void tetgenmesh::outelements(tetgenio* out) tptr = tetrahedrontraverse(); elementnumber = firstindex; // in->firstnumber; while (tptr != (tetrahedron *) NULL) { - p1 = (point) tptr[4]; - p2 = (point) tptr[5]; + if (!b->reversetetori) { + p1 = (point) tptr[4]; + p2 = (point) tptr[5]; + } else { + p1 = (point) tptr[5]; + p2 = (point) tptr[4]; + } p3 = (point) tptr[6]; p4 = (point) tptr[7]; if (out == (tetgenio *) NULL) { @@ -30095,9 +29972,9 @@ void tetgenmesh::outelements(tetgenio* out) fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, pointmark(p1) - shift, pointmark(p2) - shift, pointmark(p3) - shift, pointmark(p4) - shift); - if (0) { // if (b->order == 2) { + if (b->order == 2) { extralist = (point *) tptr[highorderindex]; - // Tetrahedron number, indices for four points plus six extra points. + // indices for six extra points. fprintf(outfile, " %5d %5d %5d %5d %5d %5d", pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift, pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift, @@ -30112,7 +29989,7 @@ void tetgenmesh::outelements(tetgenio* out) tlist[pointindex++] = pointmark(p2) - shift; tlist[pointindex++] = pointmark(p3) - shift; tlist[pointindex++] = pointmark(p4) - shift; - if (0) { // if (b->order == 2) { + if (b->order == 2) { extralist = (point *) tptr[highorderindex]; tlist[pointindex++] = pointmark(extralist[0]) - shift; tlist[pointindex++] = pointmark(extralist[1]) - shift; @@ -30125,10 +30002,8 @@ void tetgenmesh::outelements(tetgenio* out) talist[attribindex++] = elemattribute(tptr, i); } } - //if (b->neighout) { - // Remember the index of this element. - setelemindex(tptr, elementnumber); - //} + // Remember the index of this element (for counting edges). + setelemindex(tptr, elementnumber); tptr = tetrahedrontraverse(); elementnumber++; } @@ -30174,11 +30049,6 @@ void tetgenmesh::outelements(tetgenio* out) // // // outfaces() Output all faces to a .face file or a tetgenio object. // // // -// The total number of faces f can be calculated as following: Let t be the // -// total number of tets. Since each tet has 4 faces, the number t * 4 counts // -// each interior face twice and each hull face once. So f = (t * 4 + h) / 2, // -// where h is the total number of hull faces (which is known). // -// // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outfaces(tetgenio* out) @@ -30196,6 +30066,12 @@ void tetgenmesh::outfaces(tetgenio* out) int facenumber; int index; + // For -o2 option. + triface workface; + point *extralist, pp[3] = {0,0,0}; + int highorderindex = 11; + int i; + if (out == (tetgenio *) NULL) { strcpy(facefilename, b->outfilename); strcat(facefilename, ".face"); @@ -30211,7 +30087,6 @@ void tetgenmesh::outfaces(tetgenio* out) ntets = tetrahedrons->items - hullsize; faces = (ntets * 4l + hullsize) / 2l; - //bmark = !b->nobound && in->facetmarkerlist; if (out == (tetgenio *) NULL) { outfile = fopen(facefilename, "w"); @@ -30222,7 +30097,8 @@ void tetgenmesh::outfaces(tetgenio* out) fprintf(outfile, "%ld %d\n", faces, !b->nobound); } else { // Allocate memory for 'trifacelist'. - out->trifacelist = new int[faces * 3]; + //out->trifacelist = new int[faces * 3]; + out->trifacelist = new int[faces * (b->order == 1 ? 3 : 6)]; if (out->trifacelist == (int *) NULL) { printf("Error: Out of memory.\n"); terminatetetgen(1); @@ -30271,6 +30147,15 @@ void tetgenmesh::outfaces(tetgenio* out) torg = org(tface); tdest = dest(tface); tapex = apex(tface); + if (b->order == 2) { // -o2 + // Get the three extra vertices on edges. + extralist = (point *) (tface.tet[highorderindex]); + workface = tface; + for (i = 0; i < 3; i++) { + pp[i] = extralist[ver2edge[workface.ver]]; + enextself(workface); + } + } if (!b->nobound) { // Get the boundary marker of this face. if (b->plc || b->refine) { @@ -30306,6 +30191,10 @@ void tetgenmesh::outfaces(tetgenio* out) fprintf(outfile, "%5d %4d %4d %4d", facenumber, pointmark(torg) - shift, pointmark(tdest) - shift, pointmark(tapex) - shift); + if (b->order == 2) { // -o2 + fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift, + pointmark(pp[1]) - shift, pointmark(pp[2]) - shift); + } if (!b->nobound) { // Output a boundary marker. fprintf(outfile, " %d", marker); @@ -30319,6 +30208,11 @@ void tetgenmesh::outfaces(tetgenio* out) elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; elist[index++] = pointmark(tapex) - shift; + if (b->order == 2) { // -o2 + elist[index++] = pointmark(pp[0]) - shift; + elist[index++] = pointmark(pp[1]) - shift; + elist[index++] = pointmark(pp[2]) - shift; + } if (!b->nobound) { emlist[facenumber - in->firstnumber] = marker; } @@ -30454,6 +30348,12 @@ void tetgenmesh::outsubfaces(tetgenio* out) int neigh1 = 0, neigh2 = 0; int facenumber; + // For -o2 option. + triface workface; + point *extralist, pp[3]; + int highorderindex = 11; + int i; + if (out == (tetgenio *) NULL) { strcpy(facefilename, b->outfilename); strcat(facefilename, ".face"); @@ -30467,8 +30367,6 @@ void tetgenmesh::outsubfaces(tetgenio* out) } } - //bmark = !b->nobound && in->facetmarkerlist; - if (out == (tetgenio *) NULL) { outfile = fopen(facefilename, "w"); if (outfile == (FILE *) NULL) { @@ -30479,7 +30377,8 @@ void tetgenmesh::outsubfaces(tetgenio* out) fprintf(outfile, "%ld %d\n", subfaces->items, !b->nobound); } else { // Allocate memory for 'trifacelist'. - out->trifacelist = new int[subfaces->items * 3]; + //out->trifacelist = new int[subfaces->items * 3]; + out->trifacelist = new int[subfaces->items * (b->order == 1 ? 3 : 6)]; if (out->trifacelist == (int *) NULL) { terminatetetgen(1); } @@ -30514,18 +30413,39 @@ void tetgenmesh::outsubfaces(tetgenio* out) facenumber = firstindex; // in->firstnumber; while (faceloop.sh != (shellface *) NULL) { stpivot(faceloop, abuttingtet); + // If there is a tetrahedron containing this subface, orient it so + // that the normal of this face points to inside of the volume by + // right-hand rule. + if (abuttingtet.tet != NULL) { + if (ishulltet(abuttingtet)) { + fsymself(abuttingtet); + assert(!ishulltet(abuttingtet)); + } + } if (abuttingtet.tet != NULL) { - // If there is a tetrahedron containing this subface, orient it so - // that the normal of this face points to inside of the volume by - // right-hand rule. torg = org(abuttingtet); tdest = dest(abuttingtet); tapex = apex(abuttingtet); + if (b->order == 2) { // -o2 + // Get the three extra vertices on edges. + extralist = (point *) (abuttingtet.tet[highorderindex]); + workface = abuttingtet; + for (i = 0; i < 3; i++) { + pp[i] = extralist[ver2edge[workface.ver]]; + enextself(workface); + } + } } else { // This may happen when only a surface mesh be generated. torg = sorg(faceloop); tdest = sdest(faceloop); tapex = sapex(faceloop); + if (b->order == 2) { // -o2 + // There is no extra node list available. + pp[0] = torg; + pp[1] = tdest; + pp[2] = tapex; + } } if (!b->nobound) { if (in->facetmarkerlist) { @@ -30552,6 +30472,10 @@ void tetgenmesh::outsubfaces(tetgenio* out) fprintf(outfile, "%5d %4d %4d %4d", facenumber, pointmark(torg) - shift, pointmark(tdest) - shift, pointmark(tapex) - shift); + if (b->order == 2) { // -o2 + fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift, + pointmark(pp[1]) - shift, pointmark(pp[2]) - shift); + } if (!b->nobound) { fprintf(outfile, " %d", marker); } @@ -30564,6 +30488,11 @@ void tetgenmesh::outsubfaces(tetgenio* out) elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; elist[index++] = pointmark(tapex) - shift; + if (b->order == 2) { // -o2 + elist[index++] = pointmark(pp[0]) - shift; + elist[index++] = pointmark(pp[1]) - shift; + elist[index++] = pointmark(pp[2]) - shift; + } if (!b->nobound) { emlist[index1++] = marker; } @@ -30605,6 +30534,10 @@ void tetgenmesh::outedges(tetgenio* out) int index, index1; int i; + // For -o2 option. + point *extralist, pp = NULL; + int highorderindex = 11; + if (out == (tetgenio *) NULL) { strcpy(edgefilename, b->outfilename); strcat(edgefilename, ".edge"); @@ -30628,7 +30561,8 @@ void tetgenmesh::outedges(tetgenio* out) fprintf(outfile, "%ld %d\n", meshedges, !b->nobound); } else { // Allocate memory for 'edgelist'. - out->edgelist = new int[meshedges * 2]; + //out->edgelist = new int[meshedges * 2]; + out->edgelist = new int[meshedges * (b->order == 1 ? 2 : 3)]; if (out->edgelist == (int *) NULL) { printf("Error: Out of memory.\n"); terminatetetgen(1); @@ -30674,13 +30608,24 @@ void tetgenmesh::outedges(tetgenio* out) if (spintet.tet == worktet.tet) { torg = org(worktet); tdest = dest(worktet); + if (b->order == 2) { // -o2 + // Get the extra vertex on this edge. + extralist = (point *) worktet.tet[highorderindex]; + pp = extralist[ver2edge[worktet.ver]]; + } if (out == (tetgenio *) NULL) { fprintf(outfile, "%5d %4d %4d", edgenumber, pointmark(torg) - shift, pointmark(tdest) - shift); + if (b->order == 2) { // -o2 + fprintf(outfile, " %4d", pointmark(pp) - shift); + } } else { // Output three vertices of this face; elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; + if (b->order == 2) { // -o2 + elist[index++] = pointmark(pp) - shift; + } } if (!b->nobound) { if (b->plc || b->refine) { @@ -30737,6 +30682,11 @@ void tetgenmesh::outsubsegments(tetgenio* out) int marker; int edgenumber; + // For -o2 option. + triface workface, spintet; + point *extralist, pp = NULL; + int highorderindex = 11; + if (out == (tetgenio *) NULL) { strcpy(edgefilename, b->outfilename); strcat(edgefilename, ".edge"); @@ -30760,7 +30710,8 @@ void tetgenmesh::outsubsegments(tetgenio* out) fprintf(outfile, "%ld 1\n", subsegs->items); } else { // Allocate memory for 'edgelist'. - out->edgelist = new int[subsegs->items * 2]; + //out->edgelist = new int[subsegs->items * 2]; + out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)]; if (out->edgelist == (int *) NULL) { terminatetetgen(1); } @@ -30787,17 +30738,45 @@ void tetgenmesh::outsubsegments(tetgenio* out) while (edgeloop.sh != (shellface *) NULL) { torg = sorg(edgeloop); tdest = sdest(edgeloop); + if (b->order == 2) { // -o2 + // Get the extra vertex on this edge. + sstpivot1(edgeloop, workface); + if (workface.tet != NULL) { + // We must find a non-hull tet. + if (ishulltet(workface)) { + spintet = workface; + while (1) { + fnextself(spintet); + if (!ishulltet(spintet)) break; + if (spintet.tet == workface.tet) break; + } + assert(!ishulltet(spintet)); + workface = spintet; + } + extralist = (point *) workface.tet[highorderindex]; + pp = extralist[ver2edge[workface.ver]]; + } else { + pp = torg; // There is no extra node available. + } + } marker = shellmark(edgeloop); if (marker == 0) { marker = 1; // Default marker of a boundary edge is 1. } if (out == (tetgenio *) NULL) { - fprintf(outfile, "%5d %4d %4d %d\n", edgenumber, - pointmark(torg) - shift, pointmark(tdest) - shift, marker); + fprintf(outfile, "%5d %4d %4d", edgenumber, + pointmark(torg) - shift, pointmark(tdest) - shift); + if (b->order == 2) { // -o2 + fprintf(outfile, " %4d", pointmark(pp) - shift); + } + fprintf(outfile, " %d\n", marker); } else { // Output three vertices of this face; elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; + if (b->order == 2) { // -o2 + elist[index++] = pointmark(pp) - shift; + } out->edgemarkerlist[i++] = marker; } edgenumber++; @@ -30912,6 +30891,12 @@ void tetgenmesh::outneighbors(tetgenio* out) // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay // // vertex belonging to the convex hull. // // // +// aunay tetrahedralization - the power diagram - of the weighted point set. // +// Note that the vertices of the power disgram are the centers of the ortho- // +// spheres of the tetrahedra. // +// // +// NOTE: This routine is only used when the input is only a set of point. // +// // // Comment: Special thanks to Victor Liu for finding and fixing few bugs. // // // /////////////////////////////////////////////////////////////////////////////// @@ -31004,7 +30989,12 @@ void tetgenmesh::outvoronoi(tetgenio* out) pt[i] = (point) tetloop.tet[4 + i]; setpoint2tet(pt[i], encode(tetloop)); } - circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL); + if (b->weighted) { + orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3], + pt[3][3], ccent, NULL); + } else { + circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL); + } if (out == (tetgenio *) NULL) { fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift, ccent[0], ccent[1], ccent[2]); @@ -31277,7 +31267,8 @@ void tetgenmesh::outvoronoi(tetgenio* out) vpointcount = 0; while (ploop != (point) NULL) { if ((pointtype(ploop) != UNUSEDVERTEX) && - (pointtype(ploop) != DUPLICATEDVERTEX)) { + (pointtype(ploop) != DUPLICATEDVERTEX) && + (pointtype(ploop) != NREGULARVERTEX)) { getvertexstar(1, ploop, tetlist, ptlist, NULL); // Mark all vertices. Check if it is a hull vertex. ishullvert = 0; @@ -31337,14 +31328,6 @@ void tetgenmesh::outvoronoi(tetgenio* out) if (out == (tetgenio *) NULL) { fprintf(outfile, "\n"); } - // DEBUG BEGIN - for (i = 0; i < ptlist->objects; i++) { - neipt = * (point *) fastlookup(ptlist, i); - if (neipt != dummypoint) { - assert(!pinfected(neipt)); - } - } - // DEBUG END tetlist->restart(); ptlist->restart(); vpointcount++; @@ -31583,13 +31566,18 @@ void tetgenmesh::outmesh2medit(char* mfilename) tetrahedrons->traversalinit(); tetptr = tetrahedrontraverse(); while (tetptr != (tetrahedron *) NULL) { - p1 = (point) tetptr[4]; - p2 = (point) tetptr[5]; + if (!b->reversetetori) { + p1 = (point) tetptr[4]; + p2 = (point) tetptr[5]; + } else { + p1 = (point) tetptr[5]; + p2 = (point) tetptr[4]; + } p3 = (point) tetptr[6]; p4 = (point) tetptr[7]; fprintf(outfile, "%5d %5d %5d %5d", pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); - if (in->numberoftetrahedronattributes > 0) { + if (numelemattrib > 0) { fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); } else { fprintf(outfile, " 0"); @@ -31639,7 +31627,7 @@ void tetgenmesh::outmesh2vtk(char* ofilename) { FILE *outfile; char vtkfilename[FILENAMESIZE]; - point pointloop; + point pointloop, p1, p2, p3, p4; tetrahedron* tptr; double x, y, z; int n1, n2, n3, n4; @@ -31698,10 +31686,15 @@ void tetgenmesh::outmesh2vtk(char* ofilename) return; } while (tptr != (tetrahedron *) NULL) { - point p1 = (point) tptr[4]; - point p2 = (point) tptr[5]; - point p3 = (point) tptr[6]; - point p4 = (point) tptr[7]; + if (!b->reversetetori) { + p1 = (point) tptr[4]; + p2 = (point) tptr[5]; + } else { + p1 = (point) tptr[5]; + p2 = (point) tptr[4]; + } + p3 = (point) tptr[6]; + p4 = (point) tptr[7]; n1 = pointmark(p1) - in->firstnumber; n2 = pointmark(p2) - in->firstnumber; n3 = pointmark(p3) - in->firstnumber; @@ -31756,186 +31749,149 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, tetgenio *addin, tetgenio *bgmin) { tetgenmesh m; - clock_t tv[17]; // Timing informations (defined in time.h) + clock_t tv[10], ts[5]; // Timing informations (defined in time.h) + REAL cps = (REAL) CLOCKS_PER_SEC; tv[0] = clock(); m.b = b; m.in = in; + m.addin = addin; - if ((bgmin != NULL) && - ((bgmin->numberofpoints > 0) && (bgmin->pointmtrlist != NULL))) { + if ((b->metric) && (bgmin->numberofpoints > 0)) { m.bgm = new tetgenmesh(); // Create an empty background mesh. m.bgm->b = b; m.bgm->in = bgmin; } -#ifdef INEXACT_GEOM_PRED - if (!b->quiet) { - printf("Using inexact geometric predicates.\n"); - } -#else - exactinit(); -#endif - m.initializepools(); m.transfernodes(); + exactinit(b->noexact, b->nostaticfilter, m.xmax - m.xmin, + m.ymax - m.ymin, m.zmax - m.zmin); + tv[1] = clock(); if (b->refine) { m.reconstructmesh(); } else { // b->plc - if (!b->diagnose) { - m.incrementaldelaunay(tv[16]); - } + m.incrementaldelaunay(ts[0]); } tv[2] = clock(); if (!b->quiet) { if (b->refine) { - printf("Mesh reconstruction seconds: %g\n", - (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC); + printf("Mesh reconstruction seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps); } else { - if (!b->diagnose) { - printf("Delaunay seconds: %g\n", - (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC); - if (b->verbose) { - printf(" Point sorting seconds: %g\n", - (tv[16] - tv[1]) / (REAL) CLOCKS_PER_SEC); -#ifdef WITH_RUNTIME_COUNTERS - printf(" Point location seconds: %g\n", - m.t_ptloc / (REAL) CLOCKS_PER_SEC); - printf(" Point insertion seconds: %g\n", - m.t_ptinsert / (REAL) CLOCKS_PER_SEC); -#endif - } + printf("Delaunay seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps); + if (b->verbose) { + printf(" Point sorting seconds: %g\n", ((REAL)(ts[0]-tv[1])) / cps); } } } - if (b->plc) { + if (b->plc) { // -p m.meshsurface(); - } - tv[3] = clock(); + ts[0] = clock(); - if (!b->quiet) { - if (b->plc) { - printf("Surface mesh seconds: %g\n", - (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC); + if (!b->quiet) { + printf("Surface mesh seconds: %g\n", ((REAL)(ts[0]-tv[2])) / cps); + } + + if (b->diagnose) { // -d + m.detectinterfaces(); + + ts[1] = clock(); + + if (!b->quiet) { + printf("Self-intersection seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps); + } + + // Only output when self-intersecting faces exist. + if (m.subfaces->items > 0l) { + m.outnodes(out); + m.outsubfaces(out); + } + + return; } } - if (b->plc && b->diagnose) { // -d - m.detectinterfaces(); + tv[3] = clock(); + + if ((b->metric) && (m.bgm != NULL)) { // -m + m.bgm->initializepools(); + m.bgm->transfernodes(); + m.bgm->reconstructmesh(); - tv[4] = clock(); + ts[0] = clock(); if (!b->quiet) { - printf("Self-intersection seconds: %g\n", - (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC); + printf("Background mesh reconstruct seconds: %g\n", + ((REAL)(ts[0] - tv[3])) / cps); } - // Only output when self-intersecting faces exist. - if (m.subfaces->items > 0l) { - m.outnodes(out); - m.outsubfaces(out); - } + if (b->metric) { // -m + m.interpolatemeshsize(); - return; - } + ts[1] = clock(); - if (b->plc) { - if (b->nobisect) { // with -Y option - m.recoverboundary(tv[15]); - } else { - m.constraineddelaunay(tv[15]); + if (!b->quiet) { + printf("Size interpolating seconds: %g\n",((REAL)(ts[1]-ts[0])) / cps); + } } } tv[4] = clock(); - if (!b->quiet) { - if (b->plc) { - printf("Boundary recovery seconds: %g\n", - (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC); + if (b->plc) { // -p + if (b->nobisect) { // -Y + m.recoverboundary(ts[0]); + } else { + m.constraineddelaunay(ts[0]); + } + + ts[1] = clock(); + + if (!b->quiet) { + printf("Boundary recovery seconds: %g\n", ((REAL)(ts[1]-tv[4])) / cps); if (b->verbose) { - printf(" Segment recovery seconds: %g\n", - (tv[15] - tv[3]) / (REAL) CLOCKS_PER_SEC); - printf(" Facet recovery seconds: %g\n", - (tv[4] - tv[15]) / (REAL) CLOCKS_PER_SEC); + printf(" Segment recovery seconds: %g\n",((REAL)(ts[0]-tv[4]))/ cps); + printf(" Facet recovery seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps); } } - } - if (b->plc && !b->convex) { m.carveholes(); - } - tv[5] = clock(); + ts[2] = clock(); - if (!b->quiet) { - if (b->plc && !b->convex) { + if (!b->quiet) { printf("Exterior tets removal seconds: %g\n", - (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC); - } - } - - if (b->plc && b->nobisect) { - m.suppresssteinerpoints(); - } - - tv[6] = clock(); - - if (!b->quiet) { - if (b->plc && b->nobisect) { - printf("Steiner suppression seconds: %g\n", - (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC); + ((REAL)(ts[2]-ts[1])) / cps); } - } - if (b->plc && b->nobisect) { - m.recoverdelaunay(); - } + if (b->nobisect) { // -Y + m.suppresssteinerpoints(); - tv[7] = clock(); + ts[3] = clock(); - if (!b->quiet) { - if (b->plc && b->nobisect) { - printf("Delaunay recovery seconds: %g\n", - (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC); - } - } + if (!b->quiet) { + printf("Steiner suppression seconds: %g\n",((REAL)(ts[3]-ts[2]))/cps); + } - if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) { - m.bgm->initializepools(); - m.bgm->transfernodes(); - m.bgm->reconstructmesh(); - } + m.recoverdelaunay(); - tv[8] = clock(); + ts[4] = clock(); - if (!b->quiet) { - if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) { - printf("Background mesh reconstruct seconds: %g\n", - (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC); + if (!b->quiet) { + printf("Delaunay recovery seconds: %g\n", ((REAL)(ts[4]-ts[3])) / cps); + } } } - if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) { - m.interpolatemeshsize(); - } - - tv[9] = clock(); - - if (!b->quiet) { - if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) { - printf("Size interpolating seconds: %g\n", - (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC); - } - } + tv[5] = clock(); if ((b->plc || b->refine) && b->insertaddpoints) { // -i if ((addin != NULL) && (addin->numberofpoints > 0)) { @@ -31943,44 +31899,38 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, } } - tv[10] = clock(); + tv[6] = clock(); if (!b->quiet) { if ((b->plc || b->refine) && b->insertaddpoints) { if ((addin != NULL) && (addin->numberofpoints > 0)) { - printf("Constrained points seconds: %g\n", - (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC); + printf("Constrained points seconds: %g\n", ((REAL)(tv[6]-tv[5]))/cps); } } } - tv[11] = clock(); - - - if ((b->plc || b->refine) && b->quality) { + if (b->quality) { m.delaunayrefinement(); } - tv[12] = clock(); + tv[7] = clock(); if (!b->quiet) { - if ((b->plc || b->refine) && b->quality) { - printf("Refinement seconds: %g\n", - (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC); + if (b->quality) { + printf("Refinement seconds: %g\n", ((REAL)(tv[7] - tv[6])) / cps); } } - if ((b->plc || b->refine) && (b->optlevel > 0)) { - m.optimizemesh(1); + if ((b->plc || b->refine) && (b->optlevel > 0) && !b->conforming) { + m.optimizemesh(); } - tv[13] = clock(); + tv[8] = clock(); if (!b->quiet) { - if ((b->plc || b->refine) && (b->optlevel > 0)) { - printf("Optimization seconds: %g\n", - (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC); + if ((b->plc || b->refine) && (b->optlevel > 0) && !b->conforming) { + printf("Optimization seconds: %g\n", ((REAL)(tv[8] - tv[7])) / cps); } } @@ -31989,6 +31939,9 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, m.jettisonnodes(); } + if (b->order == 2) { + m.highorder(); + } if (!b->quiet) { printf("\n"); @@ -32007,7 +31960,7 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, m.outnodes(out); } - if (b->noelewritten == 1) { + if (b->noelewritten) { if (!b->quiet) { printf("NOT writing an .ele file.\n"); } @@ -32041,11 +31994,17 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, } - if (b->edgesout) { - if (b->edgesout > 1) { - m.outedges(out); // -ee, output all mesh edges. + if (b->nofacewritten) { + if (!b->quiet) { + printf("NOT writing an .edge file.\n"); + } + } else { + if (b->edgesout) { // -e + m.outedges(out); // output all mesh edges. } else { - m.outsubsegments(out); // -e, only output subsegments. + if (b->plc || b->refine) { + m.outsubsegments(out); // output subsegments. + } } } @@ -32078,13 +32037,11 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, } - tv[14] = clock(); + tv[9] = clock(); if (!b->quiet) { - printf("\nOutput seconds: %g\n", - (tv[14] - tv[13]) / (REAL) CLOCKS_PER_SEC); - printf("Total running seconds: %g\n", - (tv[14] - tv[0]) / (REAL) CLOCKS_PER_SEC); + printf("\nOutput seconds: %g\n", ((REAL)(tv[9] - tv[8])) / cps); + printf("Total running seconds: %g\n", ((REAL)(tv[9] - tv[0])) / cps); } if (b->docheck) { diff --git a/contrib/Tetgen1.5/tetgen.h b/contrib/Tetgen1.5/tetgen.h index 41634d03f49ee9d805eb18e5511c672f8d23478a..e02cbefa45c0b1b4e275a04869d725849b35b8b0 100644 --- a/contrib/Tetgen1.5/tetgen.h +++ b/contrib/Tetgen1.5/tetgen.h @@ -5,11 +5,7 @@ // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // // // // Version 1.5 // -// February 21, 2012 // -// // -// PRE-RELEASE TEST CODE. // -// PLEASE DO NOT DISTRIBUTE !! // -// PLEASE HELP ME TO IMPROVE IT !! // +// October 06, 2012 // // // // Copyright (C) 2002--2012 // // Hang Si // @@ -40,34 +36,27 @@ // #define TETLIBRARY -// Uncomment the following line to disable assert macros. These macros are -// inserted in places where I hope to catch bugs. +// Uncomment the following line to disable assert macros. These macros were +// inserted in the code where I hoped to catch bugs. They may slow down the +// speed of TetGen. // #define NDEBUG -// To insert lots of self-checks for internal errors, define the SELF_CHECK -// symbol. This will slow down the program a bit. - -// #define SELF_CHECK - -// Default, TetGen uses the double precision for a real number. +// TetGen uses the double precision for a real number. #define REAL double // The types 'intptr_t' and 'uintptr_t' are signed and unsigned integer types, // respectively. They are guaranteed to be the same width as a pointer. -// They are defined in <stdint.h> by the C99 Standard. -// However, Microsoft Visual C++ doesn't ship with this header file yet. We -// need to define them. -// Thanks to Steven G. Johnson (MIT) for the following code. - -// Define the _MSC_VER symbol if you are using Microsoft Visual C++. - -// #define _MSC_VER +// They are defined in <stdint.h> by the C99 Standard. However, Microsoft +// Visual C++ 2003 -- 2008 (Visual C++ 7.1 - 9) doesn't ship with this header +// file. In such case, we can define them by ourself. +// Update (learned from Stack Overflow): Visual Studio 2010 and Visual C++ 2010 +// Express both have stdint.h -// Define the _WIN64 symbol if you are running TetGen on Win64. - -// #define _WIN64 +// The following piece of code was provided by Steven Johnson (MIT). Define the +// symbol _MSC_VER if you are using Microsoft Visual C++. Moreover, define +// the _WIN64 symbol if you are running TetGen on Win64 systems. #ifdef _MSC_VER // Microsoft Visual C++ # ifdef _WIN64 @@ -93,7 +82,7 @@ // // // tetgenio // // // -// A structure for transfering data into and out of TetGen. // +// A structure for transfering data into and out of TetGen's mesh structure. // // // // It holds a collection of arrays of data, i.e., points, facets, tetrahedra,// // and so forth. It contains functions to read and write (input and output) // @@ -114,18 +103,18 @@ class tetgenio { public: // A "polygon" describes a simple polygon (no holes). It is not necessarily - // convex. Each polygon contains number of corners (points) and the same - // number of sides (edges). - // Note that the points of the polygon must be given in either counter- - // clockwise or clockwise order and they form a ring, so every two - // consective points forms an edge of the polygon. + // convex. Each polygon contains a number of corners (points) and the same + // number of sides (edges). The points of the polygon must be given in + // either counterclockwise or clockwise order and they form a ring, so + // every two consective points forms an edge of the polygon. typedef struct { int *vertexlist; int numberofvertices; } polygon; - // A "facet" describes a facet. Each facet is a polygonal region possibly - // with holes, edges, and points in it. + // A "facet" describes a polygonal region possibly with holes, edges, and + // points floating in it. Each facet consists of a list of polygons and + // a list of hole points (which lie strictly inside holes). typedef struct { polygon *polygonlist; int numberofpolygons; @@ -206,68 +195,73 @@ public: // attributes occupy 'numberofpointattributes' REALs. // 'pointmtrlist': An array of metric tensors at points. Each point's // tensor occupies 'numberofpointmtr' REALs. - // `pointmarkerlist': An array of point markers; one integer per point. + // 'pointmarkerlist': An array of point markers; one integer per point. REAL *pointlist; REAL *pointattributelist; REAL *pointmtrlist; - int *pointmarkerlist; + int *pointmarkerlist; pointparam *pointparamlist; int numberofpoints; int numberofpointattributes; int numberofpointmtrs; - // `elementlist': An array of element (triangle or tetrahedron) corners. - // The first element's first corner is at index [0], followed by its - // other corners in counterclockwise order, followed by any other - // nodes if the element represents a nonlinear element. Each element - // occupies `numberofcorners' ints. - // `elementattributelist': An array of element attributes. Each - // element's attributes occupy `numberofelementattributes' REALs. - // `elementconstraintlist': An array of constraints, i.e. triangle's - // area or tetrahedron's volume; one REAL per element. Input only. - // `neighborlist': An array of element neighbors; 3 or 4 ints per - // element. Output only. - int *tetrahedronlist; + // 'elementlist': An array of element (tetrahedron) corners. The first + // element's first corner is at index [0], followed by its other corners, + // followed by any other nodes if the element represents a nonlinear + // element. Each element occupies 'numberofcorners' ints. + // 'elementattributelist': An array of element attributes. Each + // element's attributes occupy 'numberofelementattributes' REALs. + // 'elementconstraintlist': An array of constraints, i.e. tetrahedron's + // volume; one REAL per element. Input only. + // 'neighborlist': An array of element neighbors; 4 ints per element. + // Output only. + int *tetrahedronlist; REAL *tetrahedronattributelist; REAL *tetrahedronvolumelist; - int *neighborlist; + int *neighborlist; int numberoftetrahedra; int numberofcorners; int numberoftetrahedronattributes; - // `facetlist': An array of facets. Each entry is a structure of facet. - // `facetmarkerlist': An array of facet markers; one int per facet. + // 'facetlist': An array of facets. Each entry is a structure of facet. + // 'facetmarkerlist': An array of facet markers; one int per facet. facet *facetlist; int *facetmarkerlist; int numberoffacets; - // `holelist': An array of holes. The first hole's x, y and z - // coordinates are at indices [0], [1] and [2], followed by the - // remaining holes. Three REALs per hole. + // 'holelist': An array of holes (in volume). Each hole is given by a + // seed (point) which lies strictly inside it. The first seed's x, y and z + // coordinates are at indices [0], [1] and [2], followed by the + // remaining seeds. Three REALs per hole. REAL *holelist; int numberofholes; - // `regionlist': An array of regional attributes and volume constraints. - // The first constraint's x, y and z coordinates are at indices [0], - // [1] and [2], followed by the regional attribute at index [3], foll- - // owed by the maximum volume at index [4]. Five REALs per constraint. - // Note that each regional attribute is used only if you select the `A' + // 'regionlist': An array of regions (subdomains). Each region is given by + // a seed (point) which lies strictly inside it. The first seed's x, y and + // z coordinates are at indices [0], [1] and [2], followed by the regional + // attribute at index [3], followed by the maximum volume at index [4]. + // Five REALs per region. + // Note that each regional attribute is used only if you select the 'A' // switch, and each volume constraint is used only if you select the - // `a' switch (with no number following). + // 'a' switch (with no number following). REAL *regionlist; int numberofregions; - // `facetconstraintlist': An array of facet maximal area constraints. - // Two REALs per constraint. The first (at index [0]) is the facet - // marker (cast it to int), the second (at index [1]) is its maximum - // area bound. + // 'facetconstraintlist': An array of facet constraints. Each constraint + // specifies a maximum area bound on the subfaces of that facet. The + // first facet constraint is given by a facet marker at index [0] and its + // maximum area bound at index [1], followed by the remaining facet con- + // straints. Two REALs per facet constraint. Note: the facet marker is + // actually an integer. REAL *facetconstraintlist; int numberoffacetconstraints; - // `segmentconstraintlist': An array of segment max. length constraints. - // Three REALs per constraint. The first two (at indcies [0] and [1]) - // are the indices of the endpoints of the segment, the third (at index - // [2]) is its maximum length bound. + // 'segmentconstraintlist': An array of segment constraints. Each constraint + // specifies a maximum length bound on the subsegments of that segment. + // The first constraint is given by the two endpoints of the segment at + // index [0] and [1], and the maximum length bound at index [2], followed + // by the remaining segment constraints. Three REALs per constraint. + // Note the segment endpoints are actually integers. REAL *segmentconstraintlist; int numberofsegmentconstraints; @@ -275,15 +269,14 @@ public: pbcgroup *pbcgrouplist; int numberofpbcgroups; - // `trifacelist': An array of triangular face endpoints. The first - // face's endpoints are at indices [0], [1] and [2], followed by the - // remaining faces. Three ints per face. - // `adjtetlist': An array of adjacent tetrahedra to the faces of - // trifacelist. Each face has at most two adjacent tets, the first - // face's adjacent tets are at [0], [1]. Two ints per face. A '-1' - // indicates outside (no adj. tet). This list is output when '-nn' - // switch is used. - // `trifacemarkerlist': An array of face markers; one int per face. + // 'trifacelist': An array of face (triangle) corners. The first face's + // corners are at indices [0], [1] and [2], followed by the remaining + // faces. Three ints per face. + // 'adjtetlist': An array of adjacent tetrahedra to the faces. The first + // face's two adjacent tetrahedra are at indices [0] and [1], followed by + // the remaining faces. A '-1' indicates outside (no adj. tet). This list + // is output when '-nn' switch is used. Output only. + // 'trifacemarkerlist': An array of face markers; one int per face. int *trifacelist; int *adjtetlist; int *trifacemarkerlist; @@ -445,7 +438,7 @@ public: pbcgroup *pg; int i, j; - // Notince that this routine assumes that the memory was allocated by + // Notice that this routine assumes that the memory was allocated by // C++ memory allocation operator 'new'. if (pointlist != (REAL *) NULL) { @@ -563,12 +556,13 @@ public: // // // tetgenbehavior // // // -// A structure to maintain the switches and parameters of TetGen. // +// A structure for maintaining the switches and parameters used by TetGen's // +// meshing algorithms. They are specified by the command line arguments. // // // -// parse_commandline() provides an simple interface to set the vaules of the // -// variables. It accepts the standard parameters (e.g., 'argc' and 'argv') // -// that pass to C/C++ main() function. Alternatively a string which contains // -// the command line options can be used as its parameter. // +// NOTE: Some of the switches are incompatinle to each other, while some are // +// depend on others. The routine parse_commandline() sets the switches from // +// the command line (a list of strings). Morover, it checks the consistency // +// of the applied switches. // // // /////////////////////////////////////////////////////////////////////////////// @@ -576,94 +570,81 @@ class tetgenbehavior { public: - // Switches of TetGen. They are briefly described in the function syntax(). - // Plerase consult the user's manual for complete explanations. The last - // column indicates their initial values. - int plc; // '-p' switch, 0. - int psc; // '-s' switch, 0. - int quality; // '-q' switch, 0. - int refine; // '-r' switch, 0. - int metric; // '-m' switch, 0. - int nobisect; // '-Y' switch, 0. - int weighted; // '-w' switch, 0. - int varvolume; // '-a' switch without number, 0. - int fixedvolume; // '-a' switch with number, 0. - int incrflip; // '-l' switch, 0. - int flipinsert; // '-L' switch, 0. - int btree; // '-u' switch, 0. - int hilbertcurve; // '-U' switch, 0. - int insertaddpoints; // '-i' switch, 0. - int regionattrib; // '-A' switch, 0. - int conforming; // '-D' switch, 0. - int diagnose; // '-d' switch, 0. - int convex; // '-c' switch, 0. - int zeroindex; // '-z' switch, 0. - int facesout; // '-f' switch, 0. - int edgesout; // '-e' switch, 0. - int neighout; // '-n' switch, 0. - int voroout; // '-v',switch, 0. - int meditview; // '-g' switch, 0. - int vtkview; // '-K' switch, 0. - int nobound; // '-B' switch, 0. - int nonodewritten; // '-N' switch, 0. - int noelewritten; // '-E' switch, 0. - int nofacewritten; // '-F' switch, 0. - int noiterationnum; // '-I' switch, 0. - int nomerge; // '-M' switch, 0. - int nojettison; // '-J' switch, 0. - int docheck; // '-C' switch, 0. - int quiet; // '-Q' switch, 0. - int verbose; // '-V' switch, 0. - - // Parameters of TetGen. They are numbers specified after switches. The - // last colume indicates their initial values. - int vertexperblock; // after '-b', 4092. - int tetrahedraperblock; // after '-b', 8188. - int shellfaceperblock; // after '-b', 4092. - int nobisect_param; // after '-Y', 1. - int weighted_param; // after '-w', 0. - int flipinsert_random; // after '-L', 0. - int flipinsert_ori4dexact; // after '-L', 0. - int fliplinklevel; // after '-L', -1. - int flipstarsize; // after '-LL', -1. - int fliplinklevelinc; // after '-LLLL', 1. - int max_btreenode_size; // after '-u', 100. - int reflevel; // after '-D', 3. - int optlevel; // after '-O', 7. - int optpasses; // after '-OO', 3. - int optmaxfliplevel; // after '-OOO', 2. - int delmaxfliplevel; // after '-OOOO', 1. - int optmaxflipstarsize; // after '-OOOOO', 10. - int order; // after '-o', 1. - int steinerleft; // after '-S', 0. - REAL facet_ang_tol; // after '-p', 179.9. - REAL maxvolume; // after '-a', -1.0. - REAL minratio; // after '-q', 0.0. - REAL mindihedral; // after '-qq', 5.0. - REAL optmaxdihedral; // after '-o', 165.0. - REAL optminsmtdihed; // after '-oo', 175.0. - REAL optminslidihed; // after '-ooo', 179.0. - REAL epsilon; // after '-T', 1.0e-8. - REAL minedgelength; // The shortest length of an edge, after '-l', 0.0. - - // Variables used to save command line switches and in/out file names. + // The list of switches of TetGen. + int plc; // '-p', 0. + int psc; // '-s', 0. + int refine; // '-r', 0. + int quality; // '-q', 0. + int nobisect; // '-Y', 0. + int weighted; // '-w', 0. + int brio_hilbert; // '-b', 1. + int incrflip; // '-l', 0. + int flipinsert; // '-L', 0. + int metric; // '-m', 0. + int varvolume; // '-a', 0. + int fixedvolume; // '-a', 0. + int regionattrib; // '-A', 0. + int conforming; // '-D', 0. + int insertaddpoints; // '-i', 0. + int diagnose; // '-d', 0. + int convex; // '-c', 0. + int nomerge; // '-M', 0. + int noexact; // '-X', 0. + int nostaticfilter; // '-X', 0. + int zeroindex; // '-z', 0. + int facesout; // '-f', 0. + int edgesout; // '-e', 0. + int neighout; // '-n', 0. + int voroout; // '-v', 0. + int meditview; // '-g', 0. + int vtkview; // '-k', 0. + int nobound; // '-B', 0. + int nonodewritten; // '-N', 0. + int noelewritten; // '-E', 0. + int nofacewritten; // '-F', 0. + int noiterationnum; // '-I', 0. + int nojettison; // '-J', 0. + int reversetetori; // '-R', 0. + int docheck; // '-C', 0. + int quiet; // '-Q', 0. + int verbose; // '-V', 0. + + // The list of parameters of TetGen. + int vertexperblock; // 4092. + int tetrahedraperblock; // 8188. + int shellfaceperblock; // 4092. + int nobisect_param; // '-Y', 1. + int weighted_param; // '-w', 0. + int hilbert_order; // -1. + int hilbert_limit; // 8. + int fliplinklevel; // -1. + int flipstarsize; // -1. + int fliplinklevelinc; // 1. + int reflevel; // '-D', 3. + int optlevel; // '-O', 2. + int optscheme; // '-O', 7. + int delmaxfliplevel; // 1. + int order; // '-o', 1. + int steinerleft; // '-S', 0. + REAL facet_ang_tol; // '-p', 179.9. + REAL maxvolume; // '-a', -1.0. + REAL minratio; // '-q', 0.0. + REAL mindihedral; // '-q', 5.0. + REAL optmaxdihedral; // 165.0. + REAL optminsmtdihed; // 179.0. + REAL optminslidihed; // 179.0. + REAL epsilon; // '-T', 1.0e-8. + REAL minedgelength; // 0.0. + + // Strings of command line arguments and input/output file names. char commandline[1024]; char infilename[1024]; char outfilename[1024]; char addinfilename[1024]; char bgmeshfilename[1024]; - // The input object type of TetGen. They are recognized by the input file - // extensions. Currently the following objects are supported: - // - NODES, a list of nodes (.node); - // - POLY, a piecewise linear complex (.poly or .smesh); - // - OFF, a polyhedron (.off, Geomview's file format); - // - PLY, a polyhedron (.ply, file format from gatech); - // - STL, a surface mesh (.stl, stereolithography format); - // - MEDIT, a surface mesh (.mesh, Medit's file format); - // - MESH, a tetrahedral mesh (.ele). - // If no extension is available, the imposed commandline switch - // (-p or -r) implies the object. + // The input object of TetGen. They are recognized by either the input + // file extensions or by the specified options. enum objecttype {NODES, POLY, OFF, PLY, STL, MEDIT, VTK, MESH} object; @@ -681,17 +662,18 @@ public: { plc = 0; psc = 0; - quality = 0; refine = 0; - metric = 0; + quality = 0; nobisect = 0; + metric = 0; weighted = 0; - varvolume = 0; - fixedvolume = 0; + brio_hilbert = 1; incrflip = 0; flipinsert = 0; - btree = 0; - hilbertcurve = 0; + varvolume = 0; + fixedvolume = 0; + noexact = 0; + nostaticfilter = 0; insertaddpoints = 0; regionattrib = 0; conforming = 0; @@ -711,6 +693,7 @@ public: noiterationnum = 0; nomerge = 0; nojettison = 0; + reversetetori = 0; docheck = 0; quiet = 0; verbose = 0; @@ -720,24 +703,21 @@ public: shellfaceperblock = 4092; nobisect_param = 1; weighted_param = 0; - flipinsert_random = 0; - flipinsert_ori4dexact = 0; + hilbert_order = -1; + hilbert_limit = 8; fliplinklevel = -1; // No limit on linklevel. flipstarsize = -1; // No limit on flip star size. fliplinklevelinc = 1; - max_btreenode_size = 100; // Default use b-tree sorting. reflevel = 3; - optlevel = 7; // 1 & 2 & 4, // min_max_dihedral. - optpasses = 3; - optmaxfliplevel = 2; + optscheme = 7; // 1 & 2 & 4, // min_max_dihedral. + optlevel = 2; delmaxfliplevel = 1; - optmaxflipstarsize = 10; order = 1; steinerleft = -1; facet_ang_tol = 179.9; maxvolume = -1.0; minratio = 2.0; - mindihedral = 0.0; // 5.0; + mindihedral = 5.0; optmaxdihedral = 165.00; // without -q, default is 179.0 optminsmtdihed = 179.00; // without -q, default is 179.999 optminslidihed = 179.00; // without -q, default is 179.999 @@ -757,45 +737,44 @@ public: /////////////////////////////////////////////////////////////////////////////// // // -// Geometric predicates // -// // -// Return one of the values +1, 0, and -1 on basic geometric questions such // -// as the orientation of point sets, in-circle, and in-sphere tests. They // -// are basic units for implmenting geometric algorithms. TetGen uses two 3D // -// geometric predicates: the orientation and in-sphere tests. // -// // -// Orientation test: let a, b, c be a sequence of 3 non-collinear points in // -// R^3. They defines a unique hypeplane H. Let H+ and H- be the two spaces // -// separated by H, which are defined as follows (using the left-hand rule): // -// make a fist using your left hand in such a way that your fingers follow // -// the order of a, b and c, then your thumb is pointing to H+. Given any // -// point d in R^3, the orientation test returns +1 if d lies in H+, -1 if d // -// lies in H-, or 0 if d lies on H. // -// // -// In-sphere test: let a, b, c, d be 4 non-coplanar points in R^3. They // -// defines a unique circumsphere S. Given any point e in R^3, the in-sphere // -// test returns +1 if e lies inside S, or -1 if e lies outside S, or 0 if e // -// lies on S. // -// // -// The following routines use arbitrary precision floating-point arithmetic. // -// They are provided by J. R. Schewchuk in public domain (http://www.cs.cmu. // -// edu/~quake/robust.html). The source code are in "predicates.cxx". // +// Robust Geometric predicates // +// // +// Geometric predicates are simple tests of spatial relations of a set of d- // +// dimensional points, such as the orientation test and the point-in-sphere // +// test. Each of these tests is performed by evaluating the sign of a deter- // +// minant of a matrix whose entries are the coordinates of these points. If // +// the computation is performed by using the floating-point numbers, e.g., // +// the single or double numbers in C/C++, roundoff error may cause an incor- // +// rect result. This may either lead to a wrong result or eventually lead to // +// a failure of the program. // +// // +// Various techniques are developed to avoid roundoff errors, such as exact // +// multi-precision computations, interval arthmetics, adaptive exact arthme- // +// tics, and filtered exact arthmetics, etc. Devillers and Pion give a nice // +// discussion and comparisons of these techniques for robustly computing the // +// Delaunay triangulations [Devillers and Pion 2002]. // +// // +// The following routines implemented the orientation test and the point-in- // +// sphere test use the adaptive exact floating-point arithmetics [Shewchuk // +// 1997]. They are generously provided by Jonathan Schewchuk in the public // +// domain, http://www.cs.cmu.edu/~quake/robust.html. The source code are in // +// file "predicates.cxx". // // // /////////////////////////////////////////////////////////////////////////////// -REAL exactinit(); +void exactinit(int, int, REAL, REAL, REAL); REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd); REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe); REAL orient4d(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, REAL ah, REAL bh, REAL ch, REAL dh, REAL eh); -REAL orient4dexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, - REAL ah, REAL bh, REAL ch, REAL dh, REAL eh); +void predicates_statistics(int weighted); /////////////////////////////////////////////////////////////////////////////// // // // tetgenmesh // // // -// The object to generate tetrahedral meshes. // +// A structure containing the mesh data structure and the implementations of // +// tetrahedral meshing algorithms of TetGen. // // // /////////////////////////////////////////////////////////////////////////////// @@ -806,7 +785,7 @@ public: // Labels that signify the type of a vertex. enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, RIDGEVERTEX, ACUTEVERTEX, FACETVERTEX, VOLVERTEX, FREESEGVERTEX, FREEFACETVERTEX, - FREEVOLVERTEX, HIDDENVERTEX, DEADVERTEX}; + FREEVOLVERTEX, NREGULARVERTEX, DEADVERTEX}; // Labels that signify the type of a subsegment. enum shestype {NSHARP, SHARP, FAKESH}; @@ -818,7 +797,8 @@ public: // Labels that signify the result of point location. enum locateresult {OUTSIDE, INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, INSTAR, - ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX,BADELEMENT}; + ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX, + NONREGULAR, BADELEMENT}; /////////////////////////////////////////////////////////////////////////////// // // @@ -831,25 +811,23 @@ public: // and edges in S and L are respectivly called subfaces and segments to dis- // // tinguish them from others in T. // // // -// The data structure to represent a tetrahedral mesh stores the tetrahedra // -// and vertices of T. Each tetrahedron is a structure including informations // -// of its vertices and adjacencies. Each vertex carries its geometric coord- // -// inates. The faces and edges of T are implicitly represented by tetrahedra.// -// This representation has a clear separation between combinatoric and geom- // -// etric data of a tetrahedral mesh. // -// // -// A hull face of T is the face on the exterior domain boundary, i.e., it is // -// contained by only one tetrahedron in T. TetGen adds fictitious tetrahedra // -// (one-to-one) at the hull faces of T, and connects them to an "infinite // -// vertex" which has no geometric coordinates. One can imagine such a vertex // -// lies in 4D space and is visible by all tetrahedra containing hull faces. // -// The extended set of tetrahedra with the infinite vertex is a tetrahedral- // -// ization of a compact 3-manifold without bounday. It has the property that // -// every face is shared by exactly two tetrahedra. // -// // -// The data structure stores explicitly the subfaces and segments (which are // -// in surface mesh S and the linear mesh L, respectively. Additional inform- // -// ations are stored in tetrahedra and subfaces to remember their relations. // +// TetGen stores the tetrahedra and vertices of T. Each tetrahedron contains // +// pointers to its vertices and adjacent tetrahedra. Each vertex stores its // +// x-, y-, and z-coordinates. The faces and edges of T are implicitly repre- // +// sented by tetrahedra. +// // +// Each face of T belongs to either two tetrahedra or one tetrahedron. In // +// the latter case, the face is an exterior boundary face of T. TetGen adds // +// fictitious tetrahedra (one-to-one) at such faces, and connects them to an // +// "infinite vertex" (which has no geometric coordinates). One can imagine // +// such a vertex lies in 4D space and is visible by all exterior boundary // +// faces. The extended set of tetrahedra (including the infinite vertex) is // +// a tetrahedralization of a compact 3-manifold without bounday. It has the // +// property that every face is shared by exactly two tetrahedra. // +// // +// TetGen stores explicitly the subfaces and segments (which are in surface // +// mesh S and the linear mesh L, respectively. Additional informations are // +// stored in tetrahedra and subfaces to remember their relations. // // // /////////////////////////////////////////////////////////////////////////////// @@ -860,7 +838,7 @@ public: // - a list of six segments (optional, for -p switch); // - a list of user-defined floating-point attributes (optional); // - a volume constraint (optional, for -a switch); - // - an integer of element marker; + // - an integer of element marker (and flags); // The structure of a tetrahedron is an array of pointers. Its actual size // (the length of the array) is determined at runtime. @@ -884,11 +862,11 @@ public: // - u, v coordinates (optional, for -s switch); // - a metric tensor (optional, for -q or -m switch); // - a pointer to an adjacent tetrahedron; - // - a pointer to a parent (or a duplicate) point, or a bsp_tree node; + // - a pointer to a parent (or a duplicate) point; // - a pointer to an adjacent subface or segment (optional, -p switch); // - a pointer to a tet in background mesh (optional, for -m switch); // - an integer for boundary marker (point index); - // - an integer for point type. + // - an integer for point type (and flags). // - an integer for geometry tag (optional, for -s switch). // The structure of a point is an array of REALs. Its acutal size is // determined at the runtime. @@ -912,8 +890,8 @@ public: // to the tetrahedron and v is a four-bit integer, in the range from 0 to 11,// // identifying the ordered version of the tetrahedron. Assume the faces of // // the tetrahedron is numbered from 0 to 3, and the edges in a face is numb- // -// ered from 0 to 2. The first two bits of v is used to identify the face of // -// the tetrahedron. The other two bits of v identify the edge in the face. // +// ered from 0 to 2. Then the two lower bits of v encode the face number, // +// and the two higher bits of v encode the edge number in that face. // // // // The four vertices of a tetrahedron are indexed from 0 to 3 (accodring to // // their storage in the data structure). Give each face the same index as // @@ -950,6 +928,9 @@ public: // ccw orieation | 0 2 4 // // cw orieation | 1 3 5 // // // +// In the following, a 'triface' is an order tetrahedron, and a 'face' is an // +// orider triangle. // +// // /////////////////////////////////////////////////////////////////////////////// class triface { @@ -1051,9 +1032,7 @@ public: point seg[2]; // A constraining edge to be recovered. point fac[3]; // A constraining face to be recovered. - point remvert; // A vertex to be removed. - //point remedge[2]; // A non-Delaunay edge to be removed. // Control flags int unflip; // Undo the performed flips. @@ -1062,16 +1041,12 @@ public: // Optimization flags. int remove_ndelaunay_edge; // Remove a non-Delaunay edge. - // remedge[0] and remedge[1] store the endpoints of a - // non-Delaunay edge to be removed. REAL bak_tetprism_vol; // The value to be minimized. - int remove_large_angle; // Remove a large dihedral angle at edge. REAL cosdihed_in; // The input cosine of the dihedral angle (> 0). - // Only perform a flip if new angles are less than it. REAL cosdihed_out; // The improved cosine of the dihedral angle. - // Counters. + // Internal counters. int maxflippedlinklevelcount; // Maximal flipped link levels. int misfliplinklevelcount; // Number of missed flip possibilities. int chrismastreecount; // Number of Chrismas trees (unflippable case). @@ -1092,7 +1067,6 @@ public: seg[0] = NULL; fac[0] = NULL; remvert = NULL; - //remedge[0] = NULL; unflip = 0; collectnewtets = 0; @@ -1100,7 +1074,6 @@ public: remove_ndelaunay_edge = 0; bak_tetprism_vol = 0.0; - remove_large_angle = 0; cosdihed_in = 0.0; cosdihed_out = 0.0; @@ -1166,8 +1139,8 @@ public: // Arraypool // // // // A dynamic linear array. // -// (It is simply copied from Shewchuk's Starbase.c, which is provided as // -// part of Stellar, a program for improving tetrahedral meshes.) // +// (It is from Shewchuk's Starbase.c, which is provided as part of Stellar, // +// a program for improving tetrahedral meshes.) // // // // Each arraypool contains an array of pointers to a number of blocks. Each // // block contains the same fixed number of objects. Each index of the array // @@ -1216,7 +1189,7 @@ public: // Memorypool // // // // A type used to allocate memory. // -// (It is simply copied from Shewchuk's triangle.c.) // +// (It is from Shewchuk's triangle.c.) // // // // firstblock is the first block of items. nowblock is the block from which // // items are currently being allocated. nextitem points to the next slab // @@ -1283,7 +1256,7 @@ public: /////////////////////////////////////////////////////////////////////////////// // Pointer to the input data (a set of nodes, a PLC, or a mesh). - tetgenio *in; + tetgenio *in, *addin; // Pointer to the switches and parameters. tetgenbehavior *b; @@ -1304,15 +1277,8 @@ public: memorypool *flippool; // A stack of faces to be flipped. badface *flipstack; - // Two queues for handling unflippable edges. - arraypool *unflipqueue; //, *flipqueue; - - // Entry to find the binary tree nodes (-u option). - arraypool *btreenode_list; - // The maximum size of a btree node (number after -u option) is - int max_btreenode_size; // <= b->max_btreenode_size. - // The maximum btree depth (for bookkeeping). - int max_btree_depth; + // A queue to store unflippable elements. + arraypool *unflipqueue; // Arrays used for point insertion (the Bowyer-Watson algorithm). arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist; @@ -1329,7 +1295,6 @@ public: // Two handles used for facet recovery in CDT. triface firsttopface, firstbotface; - // Three points define a plane (used in formcavity()). point plane_pa, plane_pb, plane_pc; @@ -1343,12 +1308,9 @@ public: // PI is the ratio of a circle's circumference to its diameter. static REAL PI; - // The increasement of link levels, default is 1. - int autofliplinklevel; - - // The volume of tetrahedral-prisms (in 4D). - REAL tetprism_vol_sum; - int calc_tetprism_vol; + // Array (size = numberoftetrahedra * 6) for storing high-order nodes of + // tetrahedra (only used when -o2 switch is selected). + point *highordertable; // Other variables. REAL xmax, xmin, ymax, ymin, zmax, zmin; // Bounding box of points. @@ -1358,12 +1320,13 @@ public: long meshedges; // Number of output mesh edges. long meshhulledges; // Number of hull mesh edges. int steinerleft; // Number of Steiner points not yet used. + int numpointattrib; // Number of point attributes. int sizeoftensor; // Number of REALs per metric tensor. int pointmtrindex; // Index to find the metric tensor of a point. int pointparamindex; // Index to find the u,v coordinates of a point. int point2simindex; // Index to find a simplex adjacent to a point. int pointmarkindex; // Index to find boundary marker of a point. - int point2pbcptindex; // Index to find a pbc point to a point. + int numelemattrib; // Number of tetrahedron attributes. int elemattribindex; // Index to find attributes of a tetrahedron. int volumeboundindex; // Index to find volume bound of a tetrahedron. int elemmarkerindex; // Index to find marker of a tetrahedron. @@ -1372,7 +1335,6 @@ public: int checksubsegflag; // Are there segments in the tetrahedralization yet? int checksubfaceflag; // Are there subfaces in the tetrahedralization yet? int checkinverttetflag; // Are there inverted (degenerated) tets yet? - int checkpbcs; // Are there periodic boundary conditions? int checkconstraints; // Are there variant (node, seg, facet) constraints? int nonconvex; // Is current mesh non-convex? int dupverts; // Are there duplicated vertices? @@ -1380,14 +1342,18 @@ public: long samples; // Number of random samples for point location. unsigned long randomseed; // Current random number seed. REAL cosmaxdihed, cosmindihed; // The cosine values of max/min dihedral. - REAL cossmtdihed; - REAL cosslidihed; // The cosine value of max dihedral of a sliver. + REAL cossmtdihed; // The cosine value of a bad dihedral tobe smoothed. + REAL cosslidihed; // The cosine value of the max dihedral of a sliver. REAL minfaceang, minfacetdihed; // The minimum input (dihedral) angles. REAL sintheta_tol; // The tolerance for sin(small angle). + int autofliplinklevel; // The increasement of link levels, default is 1. + int calc_tetprism_vol; // Flag to calculate the tetrahedral-prism'volume. + REAL tetprism_vol_sum; // The total volume of tetrahedral-prisms (in 4D). // Algorithm statistical counters. + int max_hcurve_depth_count; long ptloc_count, ptloc_max_count; - long orient3dcount, inspherecount, insphere_sos_count; + long insphere_sos_count, orient4d_sos_count; long flip14count, flip26count, flipn2ncount; long flip23count, flip32count, flip44count, flip22count; long maxbowatcavsize, totalbowatcavsize, totaldeadtets; @@ -1403,42 +1369,27 @@ public: long maxfliplinklevel, maxflipstarsize; long flipstarcount, sucflipstarcount, skpflipstarcount; long st_segref_count, st_facref_count, st_volref_count; - + long nonregularcount; long rejrefinetetcount, rejrefineshcount; -#ifdef WITH_RUNTIME_COUNTERS - clock_t t_ptloc, t_ptinsert; // Time counters for DT operations. -#endif /////////////////////////////////////////////////////////////////////////////// // // // Mesh manipulation primitives // // // -// A serial of mesh operations such as topological maintenance, navigation, // -// local modification, etc., is accomplished through a set of mesh manipul- // -// ation primitives. These primitives are indeed very simple functions which // -// take one or two handles ('triface's and 'face's) as parameters, perform // -// basic operations such as "glue two tetrahedra at a face", "return the // -// origin of a tetrahedron", "return the subface adjoining at the face of a // -// tetrahedron", and so on. // +// Mesh manipulation primitives are indeed very simple functions which take // +// one or two handles as parameters, perform basic operations such as "glue // +// two tetrahedra at a face", "return the origin of a tetrahedron", "return // +// the subface adjoining at the face of a tetrahedron", and so on. // // // /////////////////////////////////////////////////////////////////////////////// // Fast lookup tables for mesh manipulation primitives. - static int mod12[36]; - static int mod6[18]; - static int edgepivot[12]; - static int orgpivot [12]; - static int destpivot[12]; - static int apexpivot[12]; - static int oppopivot[12]; - static int ver2edge[12]; - static int edge2ver[6]; - static int snextpivot[6]; - static int sorgpivot [6]; - static int sdestpivot[6]; - static int sapexpivot[6]; - static int epivot[4]; + static int mod12[36], mod6[18]; + static int orgpivot[12], destpivot[12], apexpivot[12], oppopivot[12]; + static int edgepivot[12], ver2edge[12], edge2ver[6]; + static int sorgpivot [6], sdestpivot[6], sapexpivot[6]; + static int snextpivot[6], epivot[4]; // Primitives for tetrahedra. inline void decode(tetrahedron ptr, triface& t); @@ -1460,8 +1411,6 @@ public: inline void eprevesymself(triface& t); inline void fnext(triface& t1, triface& t2); inline void fnextself(triface& t); - inline void fprev(triface& t1, triface& t2); - inline void fprevself(triface& t); inline point org (triface& t); inline point dest(triface& t); inline point apex(triface& t); @@ -1529,8 +1478,6 @@ public: inline void setshellmark(face& s, int value); inline enum shestype shelltype(face& s); inline void setshelltype(face& s, enum shestype value); - inline int shellpbcgroup(face& s); - inline void setshellpbcgroup(face& s, int value); inline void sinfect(face& s); inline void suninfect(face& s); inline bool sinfected(face& s); @@ -1594,8 +1541,6 @@ public: inline void setpoint2ppt(point pt, point value); inline tetrahedron point2bgmtet(point pt); inline void setpoint2bgmtet(point pt, tetrahedron value); - inline point point2pbcpt(point pt); - inline void setpoint2pbcpt(point pt, point value); // Advanced primitives. inline void point2tetorg(point pt, triface& t); @@ -1618,12 +1563,12 @@ public: badface *badfacetraverse(memorypool*); void pointdealloc(point); point pointtraverse(); - void maketetrahedron(triface*); - void makeshellface(memorypool*, face*); - void makepoint(point*, enum verttype); void makeindex2pointmap(point*&); void makepoint2submap(memorypool*, int*&, face*&); + void maketetrahedron(triface*); + void makeshellface(memorypool*, face*); + void makepoint(point*, enum verttype); void initializepools(); @@ -1668,6 +1613,7 @@ public: void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume); REAL tetaspectratio(point, point, point, point); bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius); + bool orthosphere(REAL*,REAL*,REAL*,REAL*,REAL,REAL,REAL,REAL,REAL*,REAL*); void planelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*); REAL tetprismvol(REAL* pa, REAL* pb, REAL* pc, REAL* pd); @@ -1704,15 +1650,17 @@ public: void transfernodes(); // Point sorting. - void btree_sort(point*, int, int, REAL, REAL, REAL, REAL, REAL, REAL, int); - void btree_insert(point insertpt); - void btree_search(point searchpt, triface* searchtet); - void ordervertices(point* vertexarray, int arraysize); + int transgc[8][3][8], tsb1mod3[8]; + void hilbert_init(int n); + int hilbert_split(point* vertexarray, int arraysize, int gc0, int gc1, + REAL, REAL, REAL, REAL, REAL, REAL); + void hilbert_sort3(point* vertexarray, int arraysize, int e, int d, + REAL, REAL, REAL, REAL, REAL, REAL, int depth); // Point location. unsigned long randomnation(unsigned int choices); void randomsample(point searchpt, triface *searchtet); - enum locateresult locate(point searchpt, triface*, int, int); + enum locateresult locate(point searchpt, triface *searchtet, int); // Incremental Delaunay construction. void initialdelaunay(point pa, point pb, point pc, point pd); @@ -1746,8 +1694,7 @@ public: void meshsurface(); void interecursive(shellface** subfacearray, int arraysize, int axis, - REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, - REAL bzmin, REAL bzmax, int* internum); + REAL, REAL, REAL, REAL, REAL, REAL, int* internum); void detectinterfaces(); /////////////////////////////////////////////////////////////////////////////// @@ -1760,36 +1707,27 @@ public: void reportselfintersect(face *seg, face *shface); - enum interresult finddirection(triface* searchtet, point endpt, int); + enum interresult finddirection(triface* searchtet, point endpt); enum interresult scoutsegment(point, point, triface*, point*, arraypool*); void getsteinerptonsegment(face* seg, point refpt, point steinpt); void delaunizesegments(); enum interresult scoutsubface(face* searchsh, triface* searchtet); - void formmissingregion(face* missh, arraypool* missingshs, - arraypool* missingshbds, arraypool* missingshverts, - arraypool *adjtets); - int scoutcrossedge(triface& crosstet, arraypool*, arraypool* missingshs); - bool formcavity(triface* searchtet, arraypool* missingshs, - arraypool* crosstets, arraypool* topfaces, - arraypool* botfaces, arraypool* toppoints, - arraypool* botpoints); + void formmissingregion(face*, arraypool*, arraypool*, arraypool*, arraypool*); + int scoutcrossedge(triface& crosstet, arraypool*, arraypool*); + bool formcavity(triface*, arraypool*, arraypool*, arraypool*, arraypool*, + arraypool*, arraypool*); // Facet recovery by local re-tetrahedralization [Si and Gaertner'05,'11]. - void delaunizecavity(arraypool *cavpoints, arraypool *cavfaces, - arraypool *cavshells, arraypool *newtets, - arraypool *crosstets, arraypool *misfaces); - bool fillcavity(arraypool* topshells, arraypool* botshells, - arraypool* midfaces, arraypool* missingshs); - void carvecavity(arraypool *crosstets, arraypool *topnewtets, - arraypool *botnewtets); - void restorecavity(arraypool *crosstets, arraypool *topnewtets, - arraypool *botnewtets); + void delaunizecavity(arraypool*, arraypool*, arraypool*, arraypool*, + arraypool*, arraypool*); + bool fillcavity(arraypool*, arraypool*, arraypool*, arraypool*); + void carvecavity(arraypool*, arraypool*, arraypool*); + void restorecavity(arraypool*, arraypool*, arraypool*); // Facet recovery by flips [Shewchuk'03]. void flipcertify(triface *chkface, badface **pqueue); - void flipinsertfacet(arraypool *crosstets, arraypool *toppoints, - arraypool *botpoints, arraypool *midpoints); + void flipinsertfacet(arraypool*, arraypool*, arraypool*, arraypool*); bool fillregion(arraypool* missingshs, arraypool*, arraypool* newshs); void refineregion(); @@ -1804,7 +1742,6 @@ public: // // /////////////////////////////////////////////////////////////////////////////// - // A call back function. int checkflipeligibility(int fliptype, point, point, point, point, point, int level, int edgepivot, flipconstraints* fc); @@ -1840,7 +1777,7 @@ public: void reconstructmesh(); int scoutpoint(point, triface*, int randflag); - REAL getpointmeshsize(point, triface*, int iloc, int posflag); + REAL getpointmeshsize(point, triface*, int iloc); void interpolatemeshsize(); void insertconstrainedpoints(tetgenio *addio); @@ -1868,6 +1805,7 @@ public: int checktet4split(triface *chktet, int& qflag, REAL *ccent); int splittetrahedron(triface* splittet,int qflag,REAL *ccent,int chkencflag); void repairbadtets(int chkencflag); + void insertsinks(); void delaunayrefinement(); @@ -1888,7 +1826,7 @@ public: int splitsliver(triface *, REAL, int); long removeslivers(int); - void optimizemesh(int optflag); + void optimizemesh(); /////////////////////////////////////////////////////////////////////////////// // // @@ -1940,8 +1878,8 @@ public: tetgenmesh() { + in = addin = NULL; b = NULL; - in = NULL; bgm = NULL; tetrahedrons = subfaces = subsegs = points = NULL; @@ -1952,7 +1890,6 @@ public: dummypoint = NULL; flipstack = NULL; unflipqueue = NULL; - btreenode_list = NULL; cavetetlist = cavebdrylist = caveoldtetlist = NULL; cavetetshlist = cavetetseglist = cavetetvertlist = NULL; @@ -1963,6 +1900,8 @@ public: suppsteinerptlist = NULL; encseglist = encshlist = NULL; + highordertable = NULL; + plane_pa = plane_pb = plane_pc = (point) NULL; xmax = xmin = ymax = ymin = zmax = zmin = 0.0; @@ -1971,11 +1910,13 @@ public: insegments = 0l; meshedges = meshhulledges = 0l; steinerleft = -1; + numpointattrib = 0; + sizeoftensor = 0; pointmtrindex = 0; pointparamindex = 0; pointmarkindex = 0; point2simindex = 0; - point2pbcptindex = 0; + numelemattrib = 0; elemattribindex = 0; volumeboundindex = 0; shmarkindex = 0; @@ -1983,7 +1924,6 @@ public: checksubsegflag = 0; checksubfaceflag = 0; checkinverttetflag = 0; - checkpbcs = 0; checkconstraints = 0; nonconvex = 0; dupverts = 0; @@ -1992,15 +1932,12 @@ public: randomseed = 1l; minfaceang = minfacetdihed = PI; sintheta_tol = sin(0.001 * PI / 180.0); - autofliplinklevel = 1; - - tetprism_vol_sum = 0.0; calc_tetprism_vol = 0; + tetprism_vol_sum = 0.0; ptloc_count = ptloc_max_count = 0l; - orient3dcount = 0l; - inspherecount = insphere_sos_count = 0l; + insphere_sos_count = orient4d_sos_count = 0l; flip14count = flip26count = flipn2ncount = 0l; flip23count = flip32count = flip44count = flip22count = 0l; maxbowatcavsize = totalbowatcavsize = totaldeadtets = 0l; @@ -2015,15 +1952,12 @@ public: opt_sliver_peels = 0l; r1count = r2count = r3count = 0l; st_segref_count = st_facref_count = st_volref_count = 0l; + nonregularcount = 0l; maxfliplinklevel = maxflipstarsize = 0l; flipstarcount = sucflipstarcount = skpflipstarcount = 0l; rejrefinetetcount = rejrefineshcount = 0l; - -#ifdef WITH_RUNTIME_COUNTERS - t_ptloc = t_ptinsert = (clock_t) 0; -#endif } // tetgenmesh() ~tetgenmesh() @@ -2084,6 +2018,10 @@ public: if (suppsteinerptlist != NULL) { delete suppsteinerptlist; } + + if (highordertable != NULL) { + delete [] highordertable; + } } // ~tetgenmesh() }; // End of class tetgenmesh. @@ -2188,17 +2126,26 @@ inline tetgenmesh::tetrahedron tetgenmesh::encode2(tetrahedron* ptr, int ver) { // choose to bond the edge of t2 which is symmetric to the 0-th edge of // t1, and vice versa. Now assume t1 is at i-th edge and t2 is at j-th // edge, where i, j in {0, 1, 2}. The edge in t2 symmetric to 0-th edge -// of t1 is mod3[i + j]. -// Since the edge number is coded in the two higher bits of the version, -// both i, j are in {0, 4, 8}. The edge in t2 symmetric to 0-th edge -// of t1 is mod12[i + j]. - +// of t1 is (i + j) modulo 3, and vice versa. Since the edge number is +// coded in the two higher bits of the version, i.e., i, j in {0, 4, 8}. +// Therefore the edge in t2 symmetric to 0-th edge of t1 becomes +// (i + j) modulo 12, and vice versa. +/* inline void tetgenmesh::bond(triface& t1, triface& t2) { (t1).tet[(t1).ver & 3] = encode2((t2).tet, ((t2).ver & 3) + mod12[((t1).ver & 12) + ((t2).ver & 12)]); (t2).tet[(t2).ver & 3] = encode2((t1).tet, ((t1).ver & 3) + mod12[((t1).ver & 12) + ((t2).ver & 12)]); } +*/ +// Comment: The following code seems faster than the above code when +// it is compiled with the optimization option, e.g., -O3. +inline void tetgenmesh::bond(triface& t1, triface& t2) { + (t1).tet[(t1).ver & 3] = encode2((t2).tet, + ((t2).ver & 3) + (((t1).ver & 12) + ((t2).ver & 12)) % 12); + (t2).tet[(t2).ver & 3] = encode2((t1).tet, + ((t1).ver & 3) + (((t1).ver & 12) + ((t2).ver & 12)) % 12); +} // dissolve() a bond (from one side). @@ -2209,20 +2156,17 @@ inline void tetgenmesh::dissolve(triface& t) { // fsym() finds the adjacent tetrahedron at the same face and the same edge. inline void tetgenmesh::fsym(triface& t1, triface& t2) { - tetrahedron ptr = (t1).tet[(t1).ver & 3]; - int offset = 12 - ((t1).ver & 12); - decode(ptr, t2); - (t2).ver = mod12[(t2).ver + offset]; + decode((t1).tet[(t1).ver & 3], t2); + (t2).ver = mod12[(t2).ver + 12 - ((t1).ver & 12)]; } inline void tetgenmesh::fsymself(triface& t) { - tetrahedron ptr = (t).tet[(t).ver & 3]; int offset = 12 - ((t).ver & 12); - decode(ptr, t); + decode((t).tet[(t).ver & 3], t); (t).ver = mod12[(t).ver + offset]; } -// enext() finds the next edge (counterclockwise) on the same face. +// enext() finds the next edge (counterclockwise) in the same face. inline void tetgenmesh::enext(triface& t1, triface& t2) { (t2).tet = (t1).tet; @@ -2233,7 +2177,7 @@ inline void tetgenmesh::enextself(triface& t) { (t).ver = mod12[(t).ver + 4]; } -// eprev() finds the next edge (clockwise) on the same face. +// eprev() finds the next edge (clockwise) in the same face. inline void tetgenmesh::eprev(triface& t1, triface& t2) { (t2).tet = (t1).tet; @@ -2244,7 +2188,7 @@ inline void tetgenmesh::eprevself(triface& t) { (t).ver = mod12[(t).ver + 8]; } -// esym() finds the reversed edge. It is on the other face of the +// esym() finds the reversed edge. It is in the other face of the // same tetrahedron. inline void tetgenmesh::esym(triface& t1, triface& t2) { @@ -2256,8 +2200,8 @@ inline void tetgenmesh::esymself(triface& t) { (t).ver = edgepivot[(t).ver]; } -// enextesym() finds the reversed edge of the next edge. It is on the other -// face of the same tetrahedron. +// enextesym() finds the reversed edge of the next edge. It is in the other +// face of the same tetrahedron. It is the combination esym() * enext(). inline void tetgenmesh::enextesym(triface& t1, triface& t2) { enext(t1, t2); @@ -2269,8 +2213,7 @@ inline void tetgenmesh::enextesymself(triface& t) { esymself(t); } -// eprevesym() finds the reversed edge of the previous edge. It is on the -// other face of the same tetrahedron. +// eprevesym() finds the reversed edge of the previous edge. inline void tetgenmesh::eprevesym(triface& t1, triface& t2) { eprev(t1, t2); @@ -2284,7 +2227,7 @@ inline void tetgenmesh::eprevesymself(triface& t) { // fnext() finds the next face while rotating about an edge according to // a right-hand rule. The face is in the adjacent tetrahedron. It is -// equivalent to the combination: fsym() * esym(). +// the combination: fsym() * esym(). inline void tetgenmesh::fnext(triface& t1, triface& t2) { esym(t1, t2); @@ -2296,19 +2239,6 @@ inline void tetgenmesh::fnextself(triface& t) { fsymself(t); } -// fprev() finds the next face while rotating about an edge according to -// a left-hand rule. The face is in the adjacent tetrahedron. It is -// equivalent to the combination: esym() * fsym(). - -inline void tetgenmesh::fprev(triface& t1, triface& t2) { - fsym(t1, t2); - esymself(t2); -} - -inline void tetgenmesh::fprevself(triface& t) { - fsymself(t); - esymself(t); -} // The following primtives get or set the origin, destination, face apex, // or face opposite of an ordered tetrahedron. @@ -2415,10 +2345,7 @@ inline bool tetgenmesh::infected(triface& t) { } // marktest(), marktested(), unmarktest() -- primitives to flag or unflag a -// tetrahedron. The last second bit of the element marker is marked (1) -// or unmarked (0). -// One needs them in forming Bowyer-Watson cavity, to mark a tetrahedron if -// it has been checked (for Delaunay case) so later check can be avoided. +// tetrahedron. Use the second lowerest bit of the element marker. inline void tetgenmesh::marktest(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= 2; @@ -2435,8 +2362,6 @@ inline bool tetgenmesh::marktested(triface& t) { // markface(), unmarkface(), facemarked() -- primitives to flag or unflag a // face of a tetrahedron. From the last 3rd to 6th bits are used for // face markers, e.g., the last third bit corresponds to loc = 0. -// One use of the face marker is in flip algorithm. Each queued face (check -// for locally Delaunay) is marked. inline void tetgenmesh::markface(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= (4 << (t.ver & 3)); @@ -2453,7 +2378,7 @@ inline bool tetgenmesh::facemarked(triface& t) { // markedge(), unmarkedge(), edgemarked() -- primitives to flag or unflag an // edge of a tetrahedron. From the last 7th to 12th bits are used for // edge markers, e.g., the last 7th bit corresponds to the 0th edge, etc. -// Remark: The last 7th bit is marked by 2^6 = 64. +// Remark: The last 7th bit is marked by 2^6 = 64. inline void tetgenmesh::markedge(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= (int) (64 << ver2edge[(t).ver]); @@ -2540,7 +2465,7 @@ inline bool tetgenmesh::isdeadtet(triface& t) { inline void tetgenmesh::sdecode(shellface sptr, face& s) { s.shver = (int) ((uintptr_t) (sptr) & (uintptr_t) 7); - s.sh = (shellface *) ((uintptr_t) (sptr) & ~ (uintptr_t) 7); + s.sh = (shellface *) ((uintptr_t) (sptr) ^ (uintptr_t) (s.shver)); } inline tetgenmesh::shellface tetgenmesh::sencode(face& s) { @@ -2775,17 +2700,6 @@ inline void tetgenmesh::setshelltype(face& s, enum shestype value) ((((int *) ((s).sh))[shmarkindex + 1]) & 255); } -// These two primitives set or read the pbc group of the subface. - -inline int tetgenmesh::shellpbcgroup(face& s) -{ - return ((int *) (s.sh))[shmarkindex + 2]; -} - -inline void tetgenmesh::setshellpbcgroup(face& s, int value) -{ - ((int *) (s.sh))[shmarkindex + 2] = value; -} // sinfect(), sinfected(), suninfect() -- primitives to flag or unflag a // subface. The last bit of ((int *) ((s).sh))[shmarkindex+1] is flaged. @@ -2810,8 +2724,7 @@ inline bool tetgenmesh::sinfected(face& s) } // smarktest(), smarktested(), sunmarktest() -- primitives to flag or unflag -// a subface. -// The last 2nd bit of ((int *) ((s).sh))[shmarkindex+1] is flaged. +// a subface.The last 2nd bit of the integer is flaged. inline void tetgenmesh::smarktest(face& s) { @@ -2831,8 +2744,7 @@ inline bool tetgenmesh::smarktested(face& s) } // smarktest2(), smarktest2ed(), sunmarktest2() -- primitives to flag or -// unflag a subface. -// The last 3rd bit of ((int *) ((s).sh))[shmarkindex+1] is flaged. +// unflag a subface. The last 3rd bit of the integer is flaged. inline void tetgenmesh::smarktest2(face& s) { @@ -3213,15 +3125,6 @@ inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) { ((tetrahedron *) (pt))[point2simindex + 3] = value; } -// These primitives set and read a pointer to its pbc point. - -inline tetgenmesh::point tetgenmesh::point2pbcpt(point pt) { - return (point) ((tetrahedron *) (pt))[point2pbcptindex]; -} - -inline void tetgenmesh::setpoint2pbcpt(point pt, point value) { - ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value; -} // point2tetorg() Get the tetrahedron whose origin is the point.