diff --git a/contrib/Tetgen1.5/predicates.cxx b/contrib/Tetgen1.5/predicates.cxx index a4b77b69fe546cf1cf43491ab064963dfc842a60..4120704c3521a80f27aa144feb1387ccf78c66a2 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,24 +375,6 @@ 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. */ @@ -678,7 +660,7 @@ float uniformfloatrand() /* */ /*****************************************************************************/ -void exactinit(int noexact, int nofilter, REAL maxx, REAL maxy, REAL maxz) +REAL exactinit() { REAL half; REAL check, lastcheck; @@ -740,36 +722,7 @@ void exactinit(int noexact, int nofilter, REAL maxx, REAL maxy, REAL maxz) isperrboundB = (5.0 + 72.0 * epsilon) * epsilon; isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon; - _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 + return epsilon; /* Added by H. Si 30 Juli, 2004. */ } /*****************************************************************************/ @@ -1916,6 +1869,16 @@ 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; @@ -1953,10 +1916,6 @@ 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]); @@ -2304,6 +2263,31 @@ 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; @@ -2311,10 +2295,6 @@ 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]; @@ -2338,19 +2318,6 @@ 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); @@ -2362,6 +2329,8 @@ 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. */ @@ -3393,10 +3362,6 @@ 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]); @@ -3973,10 +3938,6 @@ 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]); @@ -4153,6 +4114,52 @@ 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; @@ -4163,11 +4170,12 @@ 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; - -#ifndef NDEBUG - insphcount++; -#endif // #ifndef NDEBUG + REAL permanent, errbound; aex = pa[0] - pe[0]; bex = pb[0] - pe[0]; @@ -4214,25 +4222,6 @@ 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); @@ -4273,6 +4262,8 @@ 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 */ @@ -4336,10 +4327,6 @@ 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]); @@ -4553,10 +4540,6 @@ 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]); @@ -4716,135 +4699,108 @@ 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; - -#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); -} + 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++; -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); - } - if (!_use_inexact_arith) { - printf(" Number of orient3dadapt tests: %ld\n", ori3dadaptcount); + 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); + + if (0) { //if (noexact) { + return det; } - 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); + + 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; } -#endif // #ifndef NDEBUG -} + return orient4dadapt(pa, pb, pc, pd, pe, + aheight, bheight, cheight, dheight, eheight, permanent); +} diff --git a/contrib/Tetgen1.5/tetgen.cxx b/contrib/Tetgen1.5/tetgen.cxx index 305d61b60a420fa4be0c1064abc5375a5b2d3aac..0a66de153c7e2825e01c02a2f1fdb01be35381ed 100644 --- a/contrib/Tetgen1.5/tetgen.cxx +++ b/contrib/Tetgen1.5/tetgen.cxx @@ -5,7 +5,11 @@ // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // // // // Version 1.5 // -// October 06, 2012 // +// February 21, 2012 // +// // +// PRE-RELEASE TEST CODE. // +// PLEASE DO NOT DISTRIBUTE !! // +// PLEASE HELP ME TO IMPROVE IT !! // // // // Copyright (C) 2002--2012 // // Hang Si // @@ -331,10 +335,6 @@ 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,12 +419,6 @@ 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); @@ -633,6 +627,7 @@ 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; } @@ -745,6 +740,7 @@ bool tetgenio::load_mtr(char* filebasename) if (infile != (FILE *) NULL) { printf("Opening %s.\n", mtrfilename); } else { + // No such file. Return. return false; } @@ -1385,11 +1381,14 @@ 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); @@ -1604,11 +1603,14 @@ 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); @@ -2387,7 +2389,6 @@ 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); @@ -2414,7 +2415,6 @@ 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,7 +2422,6 @@ bool tetgenio::load_tetmesh(char* filebasename, int object) } if (success) { - // Try to load the following files (.var, .mtr). load_var(filebasename); load_mtr(filebasename); } @@ -2903,22 +2902,16 @@ char* tetgenio::findnextnumber(char *string) void tetgenbehavior::syntax() { - printf(" tetgen [-pYq_Aa_mriO_S_T_XMwcdzfenvgKJBNEFICQVh] input_file\n"); + printf(" tetgen [-pYrq_a_AiS_T_dzfenvgKJBNEFICQVh] input_file\n"); printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n"); - printf(" -Y Preserves the input surface mesh (does not modify it).\n"); + printf(" -Y No splitting of input boundaries (facets and segments).\n"); + printf(" -r Reconstructs a previously generated mesh.\n"); printf(" -q Refines mesh (to improve mesh quality).\n"); - printf(" -A Assigns attributes to tetrahedra in different regions.\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(" -A Assigns attributes to tetrahedra in different regions.\n"); + printf(" -i Inserts a list of additional points into mesh.\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"); @@ -3011,6 +3004,19 @@ 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) @@ -3018,6 +3024,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) int startindex; int increment; int meshnumber; + int scount, ocount; int i, j, k; char workstring[1024]; @@ -3031,9 +3038,12 @@ 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 for output. + // Remember the command line switches. strcat(commandline, argv[i]); strcat(commandline, " "); if (startindex == 1) { @@ -3041,6 +3051,7 @@ 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; } } @@ -3061,17 +3072,11 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) facet_ang_tol = (REAL) strtod(workstring, (char **) NULL); } } else if (argv[i][j] == 's') { - 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++; - } + psc = 1; } else if (argv[i][j] == 'r') { - refine = 1; + refine++; } else if (argv[i][j] == 'q') { - quality = 1; + quality++; if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { k = 0; @@ -3082,56 +3087,42 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) k++; } workstring[k] = '\0'; - 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'; + if (quality == 1) { // -q# + minratio = (REAL) strtod(workstring, (char **) NULL); + } else if (quality == 2) { // -qq# mindihedral = (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'; - optmaxdihedral = (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++; } + 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')) { - 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++; + 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); } - } 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] == '.')) { @@ -3150,32 +3141,71 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) varvolume = 1; } } else if (argv[i][j] == 'A') { - 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++; + 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; + } + } 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++; + facesout = 1; } else if (argv[i][j] == 'e') { edgesout++; } else if (argv[i][j] == 'n') { @@ -3184,8 +3214,10 @@ 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') { @@ -3194,6 +3226,10 @@ 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') { @@ -3213,36 +3249,65 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) steinerleft = (int) strtol(workstring, (char **) NULL, 0); } } else if (argv[i][j] == '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); + 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# + 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') { - if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { - optlevel = (argv[i][j + 1] - '0'); - j++; + 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] == '/') || (argv[i][j + 1] == ',')) { - j++; - if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) { - optscheme = (argv[i][j + 1] - '0'); + } 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] == '+')) { 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')) || @@ -3258,8 +3323,6 @@ 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') { @@ -3332,10 +3395,6 @@ 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) { @@ -3371,16 +3430,18 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv) } } } - // 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; + 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; + } } } @@ -3439,8 +3500,10 @@ 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. @@ -3479,6 +3542,8 @@ 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. // @@ -3961,6 +4026,8 @@ void* tetgenmesh::memorypool::traverse() return newitem; } + + /////////////////////////////////////////////////////////////////////////////// // // // makeindex2pointmap() Create a map from index to vertices. // @@ -3992,6 +4059,7 @@ void tetgenmesh::makeindex2pointmap(point*& idx2verlist) } } + /////////////////////////////////////////////////////////////////////////////// // // // makesubfacemap() Create a map from vertex to subfaces incident at it. // @@ -4095,13 +4163,15 @@ void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron) // dead tetrahedra when traversing the list of all tetrahedra. dyingtetrahedron[4] = (tetrahedron) NULL; - // Dealloc the space to subfaces/subsegments. - if (dyingtetrahedron[8] != NULL) { - tet2segpool->dealloc((shellface *) dyingtetrahedron[8]); - } - if (dyingtetrahedron[9] != NULL) { - tet2subpool->dealloc((shellface *) dyingtetrahedron[9]); - } + //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]); + } + //} tetrahedrons->dealloc((void *) dyingtetrahedron); } @@ -4249,7 +4319,6 @@ 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; @@ -4263,9 +4332,9 @@ void tetgenmesh::maketetrahedron(triface *newtet) // No attached segments and sbfaces yet. newtet->tet[8] = NULL; newtet->tet[9] = NULL; - // Initialize the marker (clear all flags). + // Initialize the marker (for flags). setelemmarker(newtet->tet, 0); - for (int i = 0; i < numelemattrib; i++) { + for (int i = 0; i < in->numberoftetrahedronattributes; i++) { setelemattribute(newtet->tet, i, 0.0); } if (b->varvolume) { @@ -4286,7 +4355,6 @@ 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; @@ -4314,7 +4382,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; } @@ -4326,14 +4394,9 @@ void tetgenmesh::makeshellface(memorypool *pool, face *newface) void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype) { - int i; + int ptmark, 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; @@ -4348,8 +4411,8 @@ void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype) } } // Initialize the point marker (starting from in->firstnumber). - i = (int) points->items - (in->firstnumber == 1 ? 0 : 1); - setpointmark(*pnewpoint, i); + ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); + setpointmark(*pnewpoint, ptmark); // Initialize the point type. setpointtype(*pnewpoint, vtype); // Clear the point flags. @@ -4384,43 +4447,22 @@ 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) { - // '-s' option (PSC), the u,v coordinates are provided. - pointmtrindex = 5 + numpointattrib; + // For '-s' option (PSC), the u,v coordinates are provided. It is + // saved directly after the list of point attributes. + pointmtrindex = 6 + in->numberofpointattributes; } else { - pointmtrindex = 3 + numpointattrib; + pointmtrindex = 4 + in->numberofpointattributes; } // The index within each point at which its u, v coordinates are found. - pointparamindex = 3 + (numpointattrib > 0); + pointparamindex = pointmtrindex - 2; // 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. @@ -4449,11 +4491,19 @@ 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 into the background mesh, point2bgmtet(). + // Increase one pointer to 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(); @@ -4467,6 +4517,7 @@ 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. @@ -4507,21 +4558,19 @@ 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. - volumeboundindex = elemattribindex + numelemattrib; + // 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); // 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 (numelemattrib > 0) { + } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) { elesize = volumeboundindex * sizeof(REAL); } @@ -4555,7 +4604,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) * sizeof(shellface); + shsize = (shmarkindex + 2 + checkpbcs) * 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 @@ -4599,7 +4648,7 @@ void tetgenmesh::initializepools() caveencseglist = new arraypool(sizeof(face), 8); } - // Initialize the pools for flips. + // Initialize the pool for flips. flippool = new memorypool(sizeof(badface), 1024, memorypool::POINTER, 0); unflipqueue = new arraypool(sizeof(badface), 10); @@ -5823,6 +5872,8 @@ 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; @@ -5896,13 +5947,15 @@ 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; } - orient4d_sos_count++; + insphere_sos_count++; // Symbolic perturbation. point pt[5], swappt; @@ -5947,6 +6000,7 @@ REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, return oriB; } + /////////////////////////////////////////////////////////////////////////////// // // // facenormal() Calculate the normal of the face. // @@ -6054,6 +6108,7 @@ 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. // @@ -6150,7 +6205,9 @@ 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; @@ -6192,6 +6249,7 @@ 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 // @@ -6501,59 +6559,7 @@ 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; -} /////////////////////////////////////////////////////////////////////////////// // // @@ -6601,6 +6607,8 @@ void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2, } } + + /////////////////////////////////////////////////////////////////////////////// // // // tetprismvol() Calculate the volume of a tetrahedral prism in 4D. // @@ -6703,7 +6711,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 ([Edelsbrunner & Shah'1996] and [M\"ucke'1998]). // +// e] needs to be queued, see [Edelsbrunner & Shah'1996] and [M\"ucke'1998]. // // // /////////////////////////////////////////////////////////////////////////////// @@ -6717,7 +6725,6 @@ 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; @@ -6772,7 +6779,6 @@ 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) { @@ -6797,15 +6803,6 @@ 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. @@ -7042,13 +7039,17 @@ 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); } } @@ -7081,18 +7082,8 @@ 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 ( [Edelsbrunner & Shah'1996] and [M\"ucke'1998]). // +// be queued, refer to [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). // // // /////////////////////////////////////////////////////////////////////////////// @@ -7106,9 +7097,8 @@ 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, j; + int i; // For 2-to-2 flip (subfaces). face flipshs[3], flipfaces[2]; @@ -7196,28 +7186,6 @@ 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) { @@ -7718,7 +7686,6 @@ 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) { @@ -8710,7 +8677,9 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot, } } if (!rejflag && (fc != NULL)) { - // Here we must exchange 'a' and 'b'. Since in the check... function, + //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, // 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]. @@ -8839,7 +8808,9 @@ 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++) { @@ -9054,6 +9025,11 @@ 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) { @@ -9085,6 +9061,8 @@ 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] @@ -9214,7 +9192,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); + ori = orient3d(ppt[4], ppt[5], ppt[6], newpt); orient3dcount++; if (ori < 0) { // Visible. Perform a 2-to-3 flip on the flip face. fliptets[0] = fliptet; // [a,b,c,d], d = newpt. @@ -9318,7 +9296,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); + ori = orient3d(p1, p2, pd, pe); orient3dcount++; if (ori < 0) { // A locally non-convex edge. convflag = -1; @@ -9626,14 +9604,14 @@ long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, // // // insertvertex() Insert a point into current tetrahedralization. // // // -// 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. // +// 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. // // // // // /////////////////////////////////////////////////////////////////////////////// @@ -9660,6 +9638,9 @@ 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)); @@ -9674,12 +9655,17 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, } if (loc == OUTSIDE) { - tetcount = ptloc_count; // Count the number of visited tets. +#ifdef WITH_RUNTIME_COUNTERS + tstart = clock(); +#endif + tetcount = ptloc_count; // Count the number of walked tets. if (searchtet->tet == NULL) { if (!b->weighted) { - if (b->brio_hilbert) { // -b + if (b->btree) { + btree_search(insertpt, searchtet); + } else if (b->hilbertcurve) { // -U *searchtet = recenttet; - } else { // -b0 + } else { // -u0 randomsample(insertpt, searchtet); } } else { @@ -9687,14 +9673,18 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, *searchtet = recenttet; } } - // Locate the point. - loc = locate(insertpt, searchtet, ivf->chkencflag); + // Locate the point. Use 'randflag' if the mesh is non-convex. + loc = locate(insertpt, searchtet, ivf->chkencflag, checksubfaceflag); 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) { @@ -9703,6 +9693,9 @@ 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) { @@ -9714,19 +9707,21 @@ 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 > 1) { - printf(" Point #%d is non-regular, skipped.\n", - pointmark(insertpt)); - } - setpointtype(insertpt, NREGULARVERTEX); - nonregularcount++; - return NONREGULAR; + if (b->verbose > 2) { + printf(" The point is above the lower hull, skipped.\n"); + } + return OUTSIDE; } } } // 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. @@ -9902,39 +9897,9 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, return (int) loc; } else if (loc == ENCSUBFACE) { if (b->verbose > 3) { - printf(" Beyond boundary.\n"); + printf(" Encroached.\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; @@ -9951,12 +9916,13 @@ 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] = - bgm->getpointmeshsize(insertpt, &neightet, bgmloc); + insertpt[pointmtrindex] = // posflag = 1 + bgm->getpointmeshsize(insertpt, &neightet, bgmloc, 1); setpoint2bgmtet(insertpt, bgm->encode(neightet)); } } else { - insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc); + insertpt[pointmtrindex] = // posflag = 1 + getpointmeshsize(insertpt, searchtet, (int) loc, 1); } } // if (assignmeshsize) @@ -9977,6 +9943,7 @@ 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)); @@ -9994,6 +9961,11 @@ 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); @@ -10054,6 +10026,7 @@ 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) { @@ -10287,7 +10260,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", - encshlist->objects); + caveencshlist->objects); } for (i = 0; i < caveoldtetlist->objects; i++) { cavetet = (triface *) fastlookup(caveoldtetlist, i); @@ -10336,21 +10309,14 @@ 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)) { - // 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; - } + smarktest(neighsh); + caveshlist->newindex((void **) &parysh); + *parysh = neighsh; } } } @@ -10534,7 +10500,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); + ori = orient3d(pa, pb, pc, insertpt); orient3dcount++; enqflag = (ori > 0); // Comment: if ori == 0 (coplanar case), we also cut the tet. } else { @@ -10615,27 +10581,8 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // The cavity should contain at least one tet. if (caveoldtetlist->objects == 0l) { - 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; + printf("Invalid cavity of Steiner point %d.\n", pointmark(insertpt)); + assert(0); } if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) { @@ -11087,6 +11034,15 @@ 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++; @@ -11098,15 +11054,6 @@ 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. @@ -11115,8 +11062,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // Set a handle for speeding point location. recenttet = newtet; - //setpoint2tet(insertpt, encode(newtet)); - setpoint2tet(insertpt, (tetrahedron) (newtet.tet)); + setpoint2tet(insertpt, encode(newtet)); if (ivf->lawson > 1) { // if (lawson == 2 || lawson == 3) { // Re-use this list to save new interior cavity faces. @@ -11152,8 +11098,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, *parytet = neightet; } } - //setpoint2tet(org(newtet), encode(newtet)); - setpoint2tet(org(newtet), (tetrahedron) (newtet.tet)); + setpoint2tet(org(newtet), encode(newtet)); enextself(newtet); enextself(oldtet); } @@ -11302,7 +11247,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, pa = sorg(checkseg); pb = sdest(checkseg); point2tetorg(pa, neightet); - finddirection(&neightet, pb); + finddirection(&neightet, pb, 1); assert(dest(neightet) == pb); } assert(!infected(neightet)); @@ -11373,12 +11318,11 @@ 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 > 1) { - printf(" Point #%d is non-regular after the insertion of #%d.\n", - pointmark(*pts), pointmark(insertpt)); - } - setpointtype(*pts, NREGULARVERTEX); - nonregularcount++; + if (b->verbose > 2) { + printf(" Point #%d is removed from the hull.\n", + pointmark(*pts)); + } + setpointtype(*pts, UNUSEDVERTEX); } else { if (b->verbose > 3) { printf(" Queue a dangling vertex %d.\n", pointmark(*pts)); @@ -11524,7 +11468,14 @@ 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. @@ -11567,10 +11518,10 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh, // // // transfernodes() Read the vertices from the input (tetgenio). // // // -// 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. // +// 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. // // // /////////////////////////////////////////////////////////////////////////////// @@ -11583,6 +11534,9 @@ void tetgenmesh::transfernodes() int mtrindex; int i, j; + if (b->psc) { + assert(in->pointparamlist != NULL); + } // Read the points. coordindex = 0; @@ -11593,32 +11547,30 @@ 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++]; - // 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++]; - } + z = pointloop[2] = in->pointlist[coordindex++]; if (b->weighted) { // -w option if (in->numberofpointattributes > 0) { - // The first point attribute is its weight. - //w = in->pointattributelist[in->numberofpointattributes * i]; - w = pointloop[3]; + // The first point attribute is weight. + w = in->pointattributelist[in->numberofpointattributes * i]; } else { - // 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); + // No given weight available. + w = 0; } 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) { @@ -11668,239 +11620,293 @@ void tetgenmesh::transfernodes() /////////////////////////////////////////////////////////////////////////////// // // -// 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. // +// btree_sort() Sort vertices using a binary space partition (bsp) tree. // // // /////////////////////////////////////////////////////////////////////////////// -int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1, - REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, - REAL bzmin, REAL bzmax) +void tetgenmesh::btree_sort(point* vertexarray, int arraysize, int axis, + REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, + REAL bzmin, REAL bzmax, int depth) { - point swapvert; - int axis, d; + point *leftarray, *rightarray; + point **pptary, swapvert; REAL split; - int i, j; + bool lflag, rflag; + int i, j, k; // *iptr, + 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")); + } - // 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; + if (depth > max_btree_depth) { + max_btree_depth = depth; + } - // 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 { // == 2 + } else { + // Split along z-axis. 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. - 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; + 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); } - for (; j >= 0; j--) { - if (vertexarray[j][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); } - // 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 { + 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; } +} - return i; +/////////////////////////////////////////////////////////////////////////////// +// // +// 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); } -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) +/////////////////////////////////////////////////////////////////////////////// +// // +// btree_search() Search a near point for an inserting point. // +// // +/////////////////////////////////////////////////////////////////////////////// + +void tetgenmesh::btree_search(point insertpt, triface* searchtet) { - 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]; - } - 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); - } - if (transgc[e][d][w] & 2) { // y-axis - y1 = 0.5 * (bymin + bymax); - y2 = bymax; - } else { - y1 = bymin; - y2 = 0.5 * (bymin + bymax); + 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++; } - if (transgc[e][d][w] & 4) { // z-axis - z1 = 0.5 * (bzmin + bzmax); - z2 = bzmax; - } else { - z1 = bzmin; - z2 = 0.5 * (bzmin + bzmax); + } + + // 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; } - 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 + } + + } 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); } /////////////////////////////////////////////////////////////////////////////// @@ -11932,10 +11938,13 @@ unsigned long tetgenmesh::randomnation(unsigned int choices) // // // randomsample() Randomly sample the tetrahedra for point loation. // // // -// 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. // +// 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. // // // /////////////////////////////////////////////////////////////////////////////// @@ -12062,15 +12071,19 @@ 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 face which is visible by the search point. // +// hull tetrahedron whose base face 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) + tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag, + int randflag) { triface neightet; face checksh; @@ -12078,7 +12091,8 @@ enum tetgenmesh::locateresult enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove; REAL ori, oriorg, oridest, oriapex; enum locateresult loc; - int s; + int s; // i; + if (searchtet->tet == NULL) { // A null tet. Choose the recenttet as the starting tet. @@ -12100,11 +12114,13 @@ enum tetgenmesh::locateresult torg = org(*searchtet); tdest = dest(*searchtet); tapex = apex(*searchtet); - ori = orient3d(torg, tdest, tapex, searchpt); + ori = orient3d(torg, tdest, tapex, searchpt); orient3dcount++; if (ori < 0.0) break; } - if (searchtet->ver == 4) { // SELF_CHECK - assert(0); + 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; } loc = OUTSIDE; // Set a default return value. @@ -12112,7 +12128,7 @@ enum tetgenmesh::locateresult // Walk through tetrahedra to locate the point. while (true) { - ptloc_count++; // Count the number of visited tets. + ptloc_count++; // Algorithimic count. toppo = oppo(*searchtet); @@ -12125,43 +12141,58 @@ enum tetgenmesh::locateresult break; } - // We enter from one of serarchtet's faces, which face do we exit? + // We enter from serarchtet's base face. There are three other faces in + // searchtet (all connecting to toppo), which one is the 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. If so, randomly choose 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. if (oriorg < 0) { if (oridest < 0) { if (oriapex < 0) { - // 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; + if (0) { //if (!randflag) { } else { - nextmove = APEXMOVE; - } + // 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) } else { // Two faces, opposite to origin and destination, are viable. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = ORGMOVE; + if (0) { // if (!randflag) { } else { - nextmove = DESTMOVE; - } + // Randomly choose a direction. + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = ORGMOVE; + } else { + nextmove = DESTMOVE; + } + } // if (randflag) } } else { if (oriapex < 0) { // Two faces, opposite to origin and apex, are viable. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = ORGMOVE; + if (0) { // if (!randflag) { } else { - nextmove = APEXMOVE; - } + // Randomly choose a direction. + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = ORGMOVE; + } else { + nextmove = APEXMOVE; + } + } // if (randflag) } else { // Only the face opposite to origin is viable. nextmove = ORGMOVE; @@ -12171,12 +12202,16 @@ enum tetgenmesh::locateresult if (oridest < 0) { if (oriapex < 0) { // Two faces, opposite to destination and apex, are viable. - s = randomnation(2); // 's' is in {0,1}. - if (s == 0) { - nextmove = DESTMOVE; + if (0) { // if (!randflag) { } else { - nextmove = APEXMOVE; - } + // Randomly choose a direction. + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = DESTMOVE; + } else { + nextmove = APEXMOVE; + } + } // if (randflag) } else { // Only the face opposite to destination is viable. nextmove = DESTMOVE; @@ -12271,6 +12306,7 @@ enum tetgenmesh::locateresult return loc; } + /////////////////////////////////////////////////////////////////////////////// // // // initialdelaunay() Create an initial Delaunay tetrahedralization. // @@ -12347,6 +12383,13 @@ 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)); @@ -12371,45 +12414,56 @@ 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->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->btree) { // -u option + for (i = 0; i < in->numberofpoints; i++) { + permutarray[i] = (point) points->traverse(); + } if (b->verbose) { - printf(" Sort the points using simple BRIO and Hilbert curve L(%d).\n", - b->hilbert_limit); + printf(" Sorting vertices by a bsp-tree.\n"); } - 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; + // 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(" Sorting vertices by hilbert curve.\n"); } + // To be done... + for (i = 0; i < in->numberofpoints; i++) { + permutarray[i] = (point) points->traverse(); + } + } else { if (b->verbose) { - printf(" Number of sorted subsets: %d.\n", ngroup); - printf(" Maximum curve order: %d.\n", max_hcurve_depth_count); + printf(" Permuting vertices.\n"); + } + for (i = 0; i < in->numberofpoints; i++) { + randindex = randomnation(i + 1); + permutarray[i] = permutarray[randindex]; + permutarray[randindex] = (point) points->traverse(); } } @@ -12501,7 +12555,7 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv) printf(" Incrementally inserting vertices.\n"); } - // Choose algorithm: Bowyer-Watson (default) or Incremental Flip + // Choose algorithm: Bowyer-Watson (default) or Incremental Flip (-l). if (b->incrflip) { ivf.bowywat = 0; ivf.lawson = 1; @@ -12510,7 +12564,6 @@ 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) { @@ -12535,20 +12588,22 @@ 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) { - // Perform flip to recover Delaunayness. + // If -l option. Perform flip to recover Delaunayness. lawsonflip3d(permutarray[i], ivf.lawson, 0, 0, 0); } } - - - if (b->brio_hilbert) { - b->brio_hilbert = 0; // Disable it. + 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. } delete [] permutarray; @@ -13467,7 +13522,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) { setshelltype(aseg, shelltype(*splitseg)); setshelltype(bseg, shelltype(*splitseg)); if (checkconstraints) { - setareabound(aseg, areabound(*splitseg)); + setareabound(bseg, areabound(*splitseg)); setareabound(bseg, areabound(*splitseg)); } @@ -14426,9 +14481,6 @@ 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); @@ -14514,19 +14566,6 @@ 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); @@ -14594,9 +14633,14 @@ 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) { @@ -14643,6 +14687,10 @@ 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) { @@ -14695,9 +14743,6 @@ void tetgenmesh::unifysegments() int *idx2faclist; int idx, k, m; - int e1, e2; - REAL len; - if (b->verbose > 1) { printf(" Unifying segments.\n"); } @@ -14895,23 +14940,11 @@ 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); } @@ -15030,13 +15063,12 @@ 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. @@ -15047,7 +15079,6 @@ 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++) { @@ -15120,21 +15151,6 @@ 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) { @@ -15426,7 +15442,9 @@ 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++; @@ -15626,7 +15644,7 @@ void tetgenmesh::markacutevertices() printf(" Marking acute vertices.\n"); } anglimit = PI / 3.0; // 60 degree. - sharpanglimit = 5.0 / 180.0 * PI; // 5 degree. + sharpanglimit = 10.0 / 180.0 * PI; // 10 degree. minfaceang = PI; // 180 degree. acutecount = sharpsegcount = 0; @@ -15651,9 +15669,11 @@ 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; } @@ -15751,7 +15771,7 @@ void tetgenmesh::reportselfintersect(face *checkseg, face *checksh) /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult - tetgenmesh::finddirection(triface* searchtet, point endpt) + tetgenmesh::finddirection(triface* searchtet, point endpt, int randflag) { triface neightet; point pa, pb, pc, pd; @@ -15759,6 +15779,7 @@ enum tetgenmesh::interresult REAL hori, rori, lori; int s; + // The origin is fixed. pa = org(*searchtet); if ((point) searchtet->tet[7] == dummypoint) { @@ -15773,7 +15794,7 @@ enum tetgenmesh::interresult } else if ((point) searchtet->tet[6] == pa) { searchtet->ver = 7; } else { - assert((point) searchtet->tet[7] == pa); + assert((point) searchtet->tet[7] == pa); // SELF_CHECK searchtet->ver = 0; } } @@ -15825,39 +15846,54 @@ 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 - // tets are viable moves. Is so, randomly choose 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'. if (hori > 0) { if (rori > 0) { if (lori > 0) { // Any of the three neighbors is a viable move. - s = randomnation(3); - if (s == 0) { - nextmove = HMOVE; - } else if (s == 1) { - nextmove = RMOVE; + if (0) { // if (!randflag) { } else { - nextmove = LMOVE; - } + // 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) } else { // Two tets, below horizon and below right, are viable. - s = randomnation(2); - if (s == 0) { - nextmove = HMOVE; + if (0) { // if (!randflag) { } else { - nextmove = RMOVE; - } + // Randomly choose a direction. + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = HMOVE; + } else { + nextmove = RMOVE; + } + } // if (randflag) } } else { if (lori > 0) { // Two tets, below horizon and below left, are viable. - s = randomnation(2); - if (s == 0) { - nextmove = HMOVE; + if (0) { // if (!randflag) { } else { - nextmove = LMOVE; - } + // Randomly choose a direction. + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = HMOVE; + } else { + nextmove = LMOVE; + } + } // if (randflag) } else { // The tet below horizon is chosen. nextmove = HMOVE; @@ -15867,12 +15903,16 @@ enum tetgenmesh::interresult if (rori > 0) { if (lori > 0) { // Two tets, below right and below left, are viable. - s = randomnation(2); - if (s == 0) { - nextmove = RMOVE; + if (0) { // if (!randflag) { } else { - nextmove = LMOVE; - } + // Randomly choose a direction. + s = randomnation(2); // 's' is in {0,1}. + if (s == 0) { + nextmove = RMOVE; + } else { + nextmove = LMOVE; + } + } // if (randflag) } else { // The tet below right is chosen. nextmove = RMOVE; @@ -15932,7 +15972,7 @@ enum tetgenmesh::interresult fsymself(*searchtet); enextself(*searchtet); } - assert(org(*searchtet) == pa); + assert(org(*searchtet) == pa); // SELF_CHECK pb = dest(*searchtet); pc = apex(*searchtet); @@ -15983,7 +16023,7 @@ enum tetgenmesh::interresult } point2tetorg(startpt, *searchtet); - dir = finddirection(searchtet, endpt); + dir = finddirection(searchtet, endpt, 0); if (dir == ACROSSVERT) { pd = dest(*searchtet); @@ -16449,12 +16489,13 @@ void tetgenmesh::delaunizesegments() psseg = (face *) fastlookup(subsegstack, subsegstack->objects); sseg = *psseg; - assert(!sinfected(sseg)); + assert(!sinfected(sseg)); // FOR DEBUG // 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); // SELF_CHECK + tsspivot1(searchtet, checkseg); assert(checkseg.sh == sseg.sh); continue; // Not a missing segment. } @@ -16497,7 +16538,7 @@ void tetgenmesh::delaunizesegments() ivf.splitbdflag = 0; // ivf.validflag ivf.respectbdflag = 0; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; // Insert the new point into the tetrahedralization T. // Missing segments and subfaces are queued for recovery. // Note that T is convex (nonconvex = 0). @@ -16510,7 +16551,7 @@ void tetgenmesh::delaunizesegments() // For CDT, use flips to reocver Delaunayness. lawsonflip3d(newpt, ivf.lawson, 0, 0, 0); } - st_segref_count++; + st_segref_count++; //st_segpro_count++; if (steinerleft > 0) steinerleft--; } else { // The new point is either ON or VERY CLOSE to an existing point. @@ -16655,7 +16696,7 @@ enum tetgenmesh::interresult // Get a tet whose origin is a. point2tetorg(pa, *searchtet); // Search the edge [a,b]. - dir = finddirection(searchtet, pb); + dir = finddirection(searchtet, pb, 0); if (dir == ACROSSVERT) { // Check validity of a PLC. if (dest(*searchtet) != pb) { @@ -16751,7 +16792,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); + dir = finddirection(&searchtet, pb, 0); if (dir != ACROSSVERT) { // This edge is missing. Its neighbor is a missing subface. spivot(*missh, neighsh); @@ -16816,6 +16857,7 @@ void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs, } + /////////////////////////////////////////////////////////////////////////////// // // // scoutcrossedge() Search an edge that crosses the missing region. // @@ -16927,6 +16969,22 @@ 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 // @@ -16959,6 +17017,8 @@ 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; @@ -16982,6 +17042,8 @@ 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); @@ -18232,7 +18294,12 @@ 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]); - ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[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]); + } if (b->verbose > 2) { printf(" Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]); @@ -18265,7 +18332,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) { @@ -18275,7 +18342,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue) break; } } - //} // if (!b->flipinsert_random) + } // if (!b->flipinsert_random) // -L1 // Insert the new item between prev and next items. if (prevbf == NULL) { *pqueue = parybf; @@ -18389,6 +18456,7 @@ 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. @@ -18477,19 +18545,9 @@ 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)); @@ -18597,7 +18655,7 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints, flipcertify(parytet, &pqueue); } crossfaces->restart(); - if (1) { // if (!b->flipinsert_random) { + if (!b->flipinsert_random) { // Insert all queued unflipped faces. for (i = 0; i < bfacearray->objects; i++) { parytet = (triface *) fastlookup(bfacearray, i); @@ -18625,6 +18683,18 @@ 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 ??). @@ -18708,7 +18778,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]); + dir = finddirection(&searchtet, ppt[1], 0); assert(dir == ACROSSVERT); // SELF_CHECK insideflag = false; @@ -18856,7 +18926,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]); + dir = finddirection(&searchtet, ppt[1], 0); assert(dir == ACROSSVERT); // SELF_CHECK tsspivot1(searchtet, checkseg); if (checkseg.sh == NULL) { @@ -19126,7 +19196,7 @@ void tetgenmesh::refineregion() ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 0; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; loc = insertvertex(steinpt, &searchtet, &splitsh, NULL, &ivf); assert((loc != OUTSIDE) && (loc != ONVERTEX)); @@ -19173,7 +19243,7 @@ void tetgenmesh::refineregion() ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 0; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; loc = insertvertex(steinpt, &searchtet, &splitsh, &sseg, &ivf); if (loc == NEARVERTEX) { @@ -19525,8 +19595,10 @@ void tetgenmesh::constraineddelaunay(clock_t& tv) printf("Constrained Delaunay...\n"); } - // Identify acute vertex for PLC inputs. - markacutevertices(); + //if (!b->psc) { + // Only identify acute vertex for PLC inputs. + markacutevertices(); + //} if (b->verbose) { printf(" Delaunizing segments.\n"); @@ -19535,6 +19607,16 @@ 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++) { @@ -19548,6 +19630,7 @@ void tetgenmesh::constraineddelaunay(clock_t& tv) paryseg = (face *) fastlookup(subsegstack, s); *paryseg = searchseg; } + } // Recover non-Delaunay segments. delaunizesegments(); @@ -19628,6 +19711,10 @@ 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, @@ -19659,6 +19746,20 @@ 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); @@ -19674,7 +19775,12 @@ 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]; @@ -19684,6 +19790,11 @@ 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 @@ -19723,7 +19834,12 @@ 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] @@ -19732,6 +19848,11 @@ 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. + } } } } @@ -19739,6 +19860,18 @@ 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, @@ -19752,6 +19885,11 @@ 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. @@ -19798,6 +19936,11 @@ 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]. @@ -19807,6 +19950,11 @@ 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) @@ -19830,7 +19978,11 @@ 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. @@ -19971,7 +20123,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,#,#] to be removed. // +// 'flipedge' is a non-convex or flat edge [a,b,#,#]. // // // // 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 // @@ -19984,15 +20136,23 @@ 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))); } - fc->clearcounters(); + //if (fc != NULL) { + fc->clearcounters(); + //} if (checksubsegflag) { // Do not flip a segment. @@ -20002,22 +20162,24 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) printf(" Can't flip a segment (%d, %d).\n", pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); } - fc->encsegcount++; - if (fc->collectencsegflag) { - if (!sinfected(checkseg)) { - // Queue this segment in list. - sinfect(checkseg); - caveencseglist->newindex((void **) &paryseg); - *paryseg = 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; + } } - } + //} return 0; } } // Count the number of tets at edge [a,b]. n = 0; - int counter = 0; // Sum of star counters. // SELF_CHECK. + counter = 0; // Sum of star counters; spintet = *flipedge; i = 0; while (1) { @@ -20042,7 +20204,7 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) maxflipstarsize = n; } if ((b->flipstarsize > 0) && (n > b->flipstarsize)) { - // The star size exceeds the limit. + // The star size exceeds the given limit (-YY__). skpflipstarcount++; return 0; // Do not flip it. } @@ -20054,7 +20216,8 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc) i = 0; while (1) { abtets[i] = spintet; - setelemcounter(abtets[i], 1); // Marktest it (in Star(ab)). + //marktest(abtets[i]); // Marktest it (in Star(ab)). + setelemcounter(abtets[i], 1); i++; fnextself(spintet); if (spintet.tet == flipedge->tet) break; @@ -20071,26 +20234,29 @@ 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; @@ -20111,8 +20277,12 @@ 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); @@ -20126,6 +20296,10 @@ 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]); @@ -20169,14 +20343,99 @@ 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 { - // 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"); + 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; } - return 1; } } @@ -20202,19 +20461,22 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc) int tetgenmesh::recoveredgebyflips(point startpt, point endpt, triface* searchtet, int fullsearch) { - triface neightet, spintet; + triface neightet, spintet; // *abtets; point pa, pb, pc, pd; badface bakface; enum interresult dir, dir1; flipconstraints fc; int types[2], poss[4], pos = 0; int success; - int i, j; + //int n, endi; + int i, j; //, k; if (b->verbose > 2) { printf(" Recovering edge (%d, %d)\n", pointmark(startpt), pointmark(endpt)); } + + fc.seg[0] = startpt; fc.seg[1] = endpt; @@ -20223,13 +20485,14 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt, // Search the edge from 'startpt'. point2tetorg(startpt, *searchtet); - dir = finddirection(searchtet, endpt); + assert(org(*searchtet) == startpt); // SELF_CHECK + dir = finddirection(searchtet, endpt, 1); if (dir == ACROSSVERT) { if (dest(*searchtet) == endpt) { return 1; // Edge is recovered. } else { // A PLC problem, or there is a Steiner point. - terminatetetgen(3); + terminatetetgen(3); //assert(0); // Debug } } @@ -20255,165 +20518,168 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt, if (fullsearch) { - // Try to flip one of the faces/edges which intersects the edge. - success = 0; + if (1) { + // 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); - dir = finddirection(searchtet, endpt); - //assert(dir != ACROSSVERT); + // 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); - // 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); - 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); - } + // 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)) { + if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) { dir = (enum interresult) types[0]; pos = poss[0]; - break; // for loop + break; } 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 - } + // 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 + } - // 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); - 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. + // 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) { 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 + } // while (1) // Loop I-I - if (success) { - // One of intersecting faces/edges is flipped. - continue; - } + if (success) { + // One of intersecting faces/edges is flipped. + continue; + } + } // if (0) } // if (fullsearch) @@ -20435,13 +20701,24 @@ 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. // // // -// 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. // +// 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. // +// // // // /////////////////////////////////////////////////////////////////////////////// @@ -20597,7 +20874,7 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n, ivf.splitbdflag = 0; ivf.validflag = 0; ivf.respectbdflag = 0; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; // Insert the new point into the tetrahedralization T. // Note that T is convex (nonconvex = 0). @@ -20605,7 +20882,7 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n, if (loc == (int) INSTAR) { // The vertex has been inserted. - st_volref_count++; + st_volref_count++; //st_inpoly_count++; if (steinerleft > 0) steinerleft--; return 1; } else { @@ -20646,7 +20923,8 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) // Try to recover the edge by adding Steiner points. point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, endpt); + assert(org(searchtet) == startpt); // SELF_CHECK + dir = finddirection(&searchtet, endpt, 1); assert(dir != ACROSSVERT); // Get the first intersecting face/edge. @@ -20853,7 +21131,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; loc = insertvertex(steinerpt, &searchtet, &splitsh, misseg, &ivf); if (loc != ivf.iloc) { @@ -20889,7 +21167,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; loc = insertvertex(steinerpt, &searchtet, &splitsh, misseg, &ivf); assert(loc != (int) ONVERTEX); @@ -20911,11 +21189,17 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag) // // // recoversegments() Recover all segments. // // // -// All segments need to be recovered are in 'subsegstack'. // +// 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. // // // -// 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. // +// 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'. // // // /////////////////////////////////////////////////////////////////////////////// @@ -20927,7 +21211,7 @@ int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch, point startpt, endpt; int success; - long bak_inpoly_count = st_volref_count; + long bak_inpoly_count = st_volref_count; //st_inpoly_count; if (b->verbose > 1) { printf(" Recover segments [%s level = %2d] #: %ld.\n", @@ -21050,6 +21334,7 @@ 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; @@ -21059,7 +21344,8 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc, while (1) { // Get a tet containing the edge [a,b]. point2tetorg(fc.fac[i], *searchtet); - dir = finddirection(searchtet, fc.fac[(i+1)%3]); + assert(org(*searchtet) == fc.fac[i]); // SELF_CHECK + dir = finddirection(searchtet, fc.fac[(i+1)%3], 1); //assert(dir == ACROSSVERT); assert(dest(*searchtet) == fc.fac[(i+1)%3]); // Search the face [a,b,c] @@ -21267,7 +21553,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag) endpt = sdest(searchsh); point2tetorg(startpt, searchtet); assert(org(searchtet) == startpt); // SELF_CHECK - dir = finddirection(&searchtet, endpt); + dir = finddirection(&searchtet, endpt, 1); if (dir == ACROSSVERT) { if (dest(searchtet) == endpt) { success = 1; @@ -21367,7 +21653,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf); assert(loc != (int) OUTSIDE); @@ -21457,7 +21743,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag) ivf.splitbdflag = 0; ivf.validflag = 1; ivf.respectbdflag = 1; - ivf.assignmeshsize = b->metric; + ivf.assignmeshsize = 0; loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf); assert(loc != (int) OUTSIDE); @@ -21696,13 +21982,13 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge) // Search for the edge [e1, e2]. point2tetorg(e1, *tedge); - finddirection(tedge, e2); + finddirection(tedge, e2, 1); if (dest(*tedge) == e2) { return 1; } else { // Search for the edge [e2, e1]. point2tetorg(e2, *tedge); - finddirection(tedge, e1); + finddirection(tedge, e1, 1); if (dest(*tedge) == e1) { esymself(*tedge); return 1; @@ -21835,7 +22121,7 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist) } } else { point2tetorg(startpt, searchtet); - dir = finddirection(&searchtet, *pendpt); + dir = finddirection(&searchtet, *pendpt, 1); } if (dir == ACROSSVERT) { if (dest(searchtet) == *pendpt) { @@ -21890,6 +22176,21 @@ 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. // // // @@ -21940,11 +22241,13 @@ 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. @@ -21973,7 +22276,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt) // Inverted elements. getvertexstar(1, steinerpt, cavetetlist, NULL, NULL); if (cavetetlist->objects == 2) { - printf("to be continued...\n"); + printf("to be continued..."); assert(0); } else { assert(0); // Unknown cases. @@ -22096,7 +22399,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt) if (!removeflag) { if (vt == FREESEGVERTEX) { - // Check if the edge [lpt, rpt] exists. + // Check if the edge [lpr, 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. @@ -22233,6 +22536,14 @@ 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); @@ -22353,7 +22664,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt) // Insert the new segment. point2tetorg(lpt, searchtet); - finddirection(&searchtet, rpt); + finddirection(&searchtet, rpt, 1); assert(dest(searchtet) == rpt); sstbond1(rightseg, searchtet); spintet = searchtet; @@ -22938,6 +23249,7 @@ void tetgenmesh::recoverboundary(clock_t& tv) printf(" Flip link level = %d\n", b->fliplinklevel); } + //markacutevertices(); if (b->verbose) { printf(" Recovering segments.\n"); @@ -22949,6 +23261,16 @@ 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++) { @@ -22962,6 +23284,7 @@ void tetgenmesh::recoverboundary(clock_t& tv) paryseg = (face *) fastlookup(subsegstack, s); *paryseg = searchseg; } + } // The init number of missing segments. ms = subsegs->items; @@ -22971,6 +23294,7 @@ void tetgenmesh::recoverboundary(clock_t& tv) } while (1) { + recoversegments(misseglist, 0, 0); if (misseglist->objects > 0) { @@ -23275,11 +23599,10 @@ void tetgenmesh::recoverboundary(clock_t& tv) // // /////////////////////////////////////////////////////////////////////////////// - void tetgenmesh::carveholes() { - arraypool *tetarray, *hullarray; - triface tetloop, neightet, hulltet, *parytet, *parytet1; + arraypool *tetarray; + triface tetloop, neightet, hulltet, *parytet; triface openface, casface; triface *regiontets; face checksh, casingout, casingin, *parysh; @@ -23291,27 +23614,20 @@ void tetgenmesh::carveholes() int regioncount; int attrnum, attr, maxattr; int remflag; - int i, j, k; + int i, j; tetrahedron ptr; - shellface sptr; if (!b->quiet) { printf("Removing exterior tetrahedra ...\n"); } - // Initialize the pool of exterior tets. tetarray = new arraypool(sizeof(triface), 10); - hullarray = new arraypool(sizeof(triface), 10); - regiontets = NULL; - regioncount = 0; + maxattr = 0; // Choose a small number here. - //attrnum = in->numberoftetrahedronattributes; - attrnum = numelemattrib - (b->regionattrib > 0); - // Comment: The element region marker is at the end of the list of - // the element attributes. + attrnum = in->numberoftetrahedronattributes; // Mark as infected any unprotected hull tets. tetrahedrons->traversalinit(); @@ -23325,73 +23641,24 @@ 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); + loc = locate(&(in->holelist[i]), &neightet, 0, 1); // randflag = 1; if (loc != OUTSIDE) { - // 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)) + infect(neightet); + tetarray->newindex((void **) &parytet); + *parytet = neightet; } else { // A hole point locates outside of the convex hull. if (!b->quiet) { @@ -23399,7 +23666,7 @@ void tetgenmesh::carveholes() printf("lies outside the convex hull.\n"); } } - } // i + } } if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option. @@ -23411,7 +23678,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); + loc = locate(&(in->regionlist[i]), &neightet, 0, 1); // randflag = 1; if (loc != OUTSIDE) { regiontets[i/5] = neightet; if ((int) in->regionlist[i + 3] > maxattr) { @@ -23427,62 +23694,58 @@ 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); - // 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 + 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)) { infect(neightet); - 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--; - } + 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; + } + hullsize--; } else { - // Both sides of this face are in exterior. - // Check if there is a subface. - tspivot(neightet, checksh); - if (checksh.sh != NULL) { + 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). 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. @@ -23497,76 +23760,65 @@ void tetgenmesh::carveholes() } } - -if (!b->convex) { - - // Create new hull tets. - // Update point-to-tet map, segment-to-tet map, and subface-to-tet map. - 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; - } - } - } // j - } - } // 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); + 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(); + tetarray->restart(); // Re-use it for new hull tets. + // 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); + } + 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); + } + tetloop.tet = tetrahedrontraverse(); + } if (subfacstack->objects > 0) { // Remove all subfaces which do not attach to any tetrahedron. @@ -23631,7 +23883,6 @@ if (!b->convex) { subfacstack->restart(); } - // Some vertices may be not belong to any tet. Mark them. delvertcount = unuverts; delsteinercount = 0l; @@ -23699,10 +23950,12 @@ if (!b->convex) { } } + // Update the hull size. + hullsize += tetarray->objects; // Connect new hull tets. - for (i = 0; i < hullarray->objects; i++) { - parytet = (triface *) fastlookup(hullarray, i); + for (i = 0; i < tetarray->objects; i++) { + parytet = (triface *) fastlookup(tetarray, i); hulltet = *parytet; for (j = 0; j < 3; j++) { esym(hulltet, neightet); @@ -23727,118 +23980,13 @@ if (!b->convex) { } } -} 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); - } - } - + // Set region attributes (when has -A and -AA options). 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) { @@ -23859,61 +24007,81 @@ if (!b->convex) { if (b->varvolume) { // If has -a option. setvolumebound(tetloop.tet, volume); } - 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) { + 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)) { 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); + } + } } - } // k + } // ver } // j regioncount++; } // if (regiontets[i/5].tet != NULL) } // i } - // 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)) { + 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); // Is this side protected by a subface? - tspivot(neightet, checksh); + tspivot(tetloop, checksh); if (checksh.sh == NULL) { - infect(neightet); - tetarray->newindex((void **) &parytet); - *parytet = neightet; + // 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); + } } - } - } // k - } // j - attr++; // Increase the attribute. - regioncount++; + } // loc + } + attr++; // Increase the attribute. + regioncount++; + } // if (!infected(tetloop)) + tetloop.tet = tetrahedrontraverse(); } - tetloop.tet = tetrahedrontraverse(); + // Until here, every tet has a region attribute. } - // Until here, every tet has a region attribute. // Uninfect processed tets. tetrahedrons->traversalinit(); @@ -23923,6 +24091,8 @@ if (!b->convex) { tetloop.tet = tetrahedrontraverse(); } + // Mesh elements contain region attributes now. + in->numberoftetrahedronattributes++; if (b->verbose) { assert(regioncount > 0); @@ -23932,20 +24102,17 @@ if (!b->convex) { 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. @@ -23963,9 +24130,6 @@ if (!b->convex) { if (b->verbose && (opt_sliver_peels > 0l)) { printf(" Peeled %ld hull slivers.\n", opt_sliver_peels); } - -} - } /////////////////////////////////////////////////////////////////////////////// @@ -24508,7 +24672,7 @@ int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag) if (randflag) { randomsample(searchpt, searchtet); } - loc = locate(searchpt, searchtet, 0); + loc = locate(searchpt, searchtet, 0, 1); if (loc == OUTSIDE) { // Not found. This happens when the mesh is not convex. if (!randflag) break; @@ -24660,9 +24824,13 @@ 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) +REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc, + int posflag) { point *pts, pa, pb, pc; REAL volume, vol[4], wei[4]; @@ -24674,9 +24842,9 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc) if (iloc == (int) INTETRAHEDRON) { pts = (point *) &(searchtet->tet[4]); assert(pts[3] != dummypoint); - // 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)) { + if (!posflag || + ((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]); @@ -24692,8 +24860,9 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc) pa = org(*searchtet); pb = dest(*searchtet); pc = apex(*searchtet); - if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) && - (pc[pointmtrindex] > 0)) { + if (!posflag || + ((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); @@ -24705,7 +24874,7 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc) } else if (iloc == (int) ONEDGE) { pa = org(*searchtet); pb = dest(*searchtet); - if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) { + if (!posflag || ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0))) { volume = distance(pa, pb); vol[0] = distance(searchpt, pb); vol[1] = distance(pa, searchpt); @@ -24714,7 +24883,7 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc) } } else if (iloc == (int) ONVERTEX) { pa = org(*searchtet); - if (pa[pointmtrindex] > 0) { + if (!posflag || (pa[pointmtrindex] > 0)) { size = pa[pointmtrindex]; } } @@ -24750,8 +24919,8 @@ void tetgenmesh::interpolatemeshsize() searchtet.tet = NULL; iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1 if (iloc != (int) OUTSIDE) { - // Interpolate the mesh size. - ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc); + // Interpolate the mesh size (posflag = 0) + ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc, 0); setpoint2bgmtet(ploop, bgm->encode(searchtet)); if (count == 0) { // This is the first interpolated point. @@ -24793,8 +24962,7 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) face checkseg, *splitseg; point newpt; insertvertexflags ivf; - REAL x, y, z, w; - int attribindex, mtrindex; + REAL *attr, x, y, z, w; int randflag; int count, index; int loc; @@ -24807,39 +24975,42 @@ 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, UNUSEDVERTEX); + makepoint(&newpt, VOLVERTEX); 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 its weight. - w = newpt[3]; + // The first point attribute is weight. + w = addio->pointattributelist[addio->numberofpointattributes * i]; } else { - // 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); + // No given weight available. + w = 0; } 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; @@ -24854,14 +25025,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 = b->metric; + ivf.assignmeshsize = 1; splitsh = NULL; splitseg = NULL; @@ -24894,8 +25065,6 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio) setpointtype(newpt, FACETVERTEX); splitsh = &checksh; } - } else { - setpointtype(newpt, VOLVERTEX); } // Insert the vertex. @@ -24936,6 +25105,8 @@ 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. // // // @@ -24968,7 +25139,7 @@ void tetgenmesh::marksharpsegments() minfacetdihed = PI; smallang = 65.0 * PI / 180.0; // 65 degree. - exsmallang = 5.0 * PI / 180.0; // 5 degree. + exsmallang = 15.0 * PI / 180.0; // 15 degree. sharpcount = exsharpcount = 0; // A segment s may have been split into many subsegments. Operate the one @@ -25126,8 +25297,13 @@ 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 size. It // -// is used to prevent creating too close Steiner points. // +// 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. // // // /////////////////////////////////////////////////////////////////////////////// @@ -25158,8 +25334,9 @@ void tetgenmesh::decidefeaturepointsizes() maxlen = pow(6.0 * b->maxvolume, 1.0 / 3.0); } - // First, assign a size of p if p is a feature point or an input point and - // the -Y option is used. + // 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. featurecount = 0; points->traversalinit(); ploop = pointtraverse(); @@ -25332,9 +25509,9 @@ void tetgenmesh::decidefeaturepointsizes() printf(" %d feature points.\n", featurecount); } - // Second only assign sizes for all Steiner points which were inserted on - // sharp segments. The sizes are interpolated from the endpoints of - // the segments. + // 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. featurecount = 0; points->traversalinit(); ploop = pointtraverse(); @@ -25364,7 +25541,67 @@ 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(); } @@ -25374,8 +25611,7 @@ void tetgenmesh::decidefeaturepointsizes() } if (checkconstraints) { - // A .var file exists. Adjust feature sizes. And make sure that every - // corner of a constraining facet get a size. + // A .var file exists. Adjust feature sizes. if (in->facetconstraintlist) { // Have facet area constrains. subfaces->traversalinit(); @@ -25391,9 +25627,6 @@ void tetgenmesh::decidefeaturepointsizes() if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } - } else { - // This corner has no size yet. Set it. - ploop[pointmtrindex] = varlen; } } // j } @@ -25414,8 +25647,6 @@ void tetgenmesh::decidefeaturepointsizes() if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } - } else { - ploop[pointmtrindex] = varlen; } } // j } @@ -25425,7 +25656,6 @@ void tetgenmesh::decidefeaturepointsizes() } // if (checkconstraints) } - /////////////////////////////////////////////////////////////////////////////// // // // checkseg4encroach() Check if an edge is encroached upon by a point. // @@ -25477,7 +25707,6 @@ 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 // @@ -25631,19 +25860,21 @@ 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) { - // 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) && (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; } } @@ -25651,20 +25882,26 @@ int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag, getsteinerptonsegment(splitseg, encpt, newpt); - // Split the segment by the Bowyer-Watson algorithm. + // 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. 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; // Preserve subsegments and subfaces; + ivf.bowywat = 3; // Use the "Bowyer-Watson" algorithm to form cavity. ivf.validflag = 1; // Validate the B-W cavity. } - ivf.lawson = b->conforming ? 3 : 1; // Check flip for internal new faces?. - ivf.rejflag = 0; // Do not check encroachment of new segments/facets. + ivf.lawson = 3; + ivf.rejflag = 0; if ((encpt == NULL) && (qflag == 0)) { - ivf.rejflag |= 4; // Do check encroachment of protecting balls. + // Do not insert the point if it lies inside some protecting balls. + ivf.rejflag |= 4; } ivf.chkencflag = chkencflag; ivf.sloc = ivf.iloc; @@ -25672,22 +25909,35 @@ 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); - 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. + // 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'. lawsonflip3d(newpt, 4, 0, chkencflag, 0); st_segref_count++; if (steinerleft > 0) steinerleft--; return 1; } else { - pointdealloc(newpt); - return 0; + // The vertex was not inserted. For unknown reasons. + //pointdealloc(newpt); + assert(0); } + + // Should not be here. + return 0; } /////////////////////////////////////////////////////////////////////////////// @@ -25873,9 +26123,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 > 3) { - printf(" circent: (%g, %g, %g)\n", cent[0], cent[1], cent[2]); - printf(" cirradi: %g\n", rd); + if (b->verbose > 2) { + 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. @@ -25892,8 +26142,8 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, D = sqrt(D); - if (b->verbose > 3) { - printf(" shortest edge length = %g\n", D); + if (b->verbose > 2) { + printf(" shortest edge length = %g\n", D); } rhs[3] = rd / D; // The radius-edge ratio. @@ -25949,7 +26199,9 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, } sesymself(*chkfac); } - } + } else { + assert(0); + } // if (!lu_decomp) return 0; } @@ -26006,6 +26258,9 @@ 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; } } @@ -26013,6 +26268,8 @@ 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'. @@ -26031,15 +26288,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; // Preserve segments and subfaces. - ivf.lawson = b->conforming ? 3 : 1; - ivf.rejflag = 1; // Do check the encroachment of segments. + // 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. if (qflag == 0) { ivf.rejflag |= 4; // Reject it if it encroached upon any vertex. } @@ -26056,54 +26313,57 @@ int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag, loc = insertvertex(newpt, &searchtet, &searchsh, NULL, &ivf); - if (loc == (int) ivf.iloc) { - if (b->verbose > 2) { - printf(" Point inserted successfully on facet.\n"); - } - // Flip not locally Delaunay link facets. - lawsonflip3d(newpt, 4, 0, chkencflag, 0); - st_facref_count++; - if (steinerleft > 0) steinerleft--; - return 1; - } else { - // 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; - } + 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. - } + } + 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; } + 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. + } else { + // Unknown error. + assert(0); } + // Should not be here. + return 0; } /////////////////////////////////////////////////////////////////////////////// @@ -26168,7 +26428,6 @@ void tetgenmesh::repairencfacs(int chkencflag) // // /////////////////////////////////////////////////////////////////////////////// - int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) { point pa, pb, pc, pd, *ppt; @@ -26209,8 +26468,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 > 3) { - printf(" Min dihed = 0 (degree)\n"); + if (b->verbose > 2) { + printf(" Min dihed = 0 (degree)\n"); } // Return its barycenter. for (i = 0; i < 3; i++) { @@ -26222,8 +26481,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 > 3) { - printf(" volume = %g.\n", vol); + if (b->verbose > 2) { + printf(" volume = %g.\n", vol); } if (b->fixedvolume) { if (vol > b->maxvolume) { @@ -26286,8 +26545,8 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) } smlen = sqrt(smlen); D = rd / smlen; - if (b->verbose > 3) { - printf(" Ratio-edge ratio = %g, smlen = %g\n", D, smlen); + if (b->verbose > 2) { + printf(" Ratio-edge ratio = %g, smlen = %g\n", D, smlen); } if (D > b->minratio) { // A bad radius-edge ratio. @@ -26327,8 +26586,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 > 3) { - printf(" Min dihed = %g (degree)\n", acos(maxcosd) / PI * 180.0); + if (b->verbose > 2) { + printf(" Min dihed = %g (degree)\n", acos(maxcosd) / PI * 180.0); } if (maxcosd > cosmindihed) { // Calculate the circumcenter of this tet. @@ -26413,12 +26672,17 @@ 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; - ivf.bowywat = 3; // Preserve subsegments and subfaces; - ivf.lawson = b->conforming ? 3 : 1; - ivf.rejflag = 3; // Do check for encroached segments and subfaces. + // 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; if (qflag == 0) { ivf.rejflag |= 4; // Reject it if it lies in some protecting balls. } @@ -26435,10 +26699,7 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, loc = insertvertex(newpt, &searchtet, NULL, NULL, &ivf); if (loc == (int) ENCSEGMENT) { - if (b->verbose > 2) { - printf(" Point encroached upon %ld segments.\n", - encseglist->objects); - } + // There are encroached segments. pointdealloc(newpt); assert(encseglist->objects > 0); splitflag = 0; @@ -26470,10 +26731,7 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, } return splitflag; } else if (loc == (int) ENCSUBFACE) { - if (b->verbose > 2) { - printf(" Point encroached upon %ld subfaces.\n", - encshlist->objects); - } + // There are encroached subfaces. pointdealloc(newpt); assert(encshlist->objects > 0); splitflag = 0; @@ -26524,9 +26782,6 @@ 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. @@ -26595,7 +26850,6 @@ void tetgenmesh::repairbadtets(int chkencflag) } } - /////////////////////////////////////////////////////////////////////////////// // // // enforcequality() Refine the mesh. // @@ -26612,16 +26866,13 @@ 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(" Min radiu-edge ratio = %g.\n", b->minratio); - printf(" Min dihedral angle = %g.\n", b->mindihedral); - //printf(" Min Edge length = %g.\n", b->minedgelength); + printf(" Edge length limit = %g.\n", b->minedgelength); } steinerleft = b->steinerleft; // Upperbound of # Steiner points (by -S#). @@ -26633,7 +26884,7 @@ void tetgenmesh::delaunayrefinement() } else { if (!b->quiet) { printf("\nWarning: "); - printf("The desired number of Steiner points (%d) has reached.\n\n", + printf("The desired number of Steiner points (%d) is reached.\n\n", b->steinerleft); } return; // No more Steiner points. @@ -26648,7 +26899,6 @@ void tetgenmesh::delaunayrefinement() decidefeaturepointsizes(); - encseglist = new arraypool(sizeof(face), 8); encshlist = new arraypool(sizeof(badface), 8); @@ -26758,8 +27008,6 @@ 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) @@ -26812,10 +27060,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. @@ -26873,7 +27121,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 = 10; //b->optmaxflipstarsize; + b->flipstarsize = b->optmaxflipstarsize; flipqueue = new arraypool(sizeof(badface), 10); nextflipqueue = new arraypool(sizeof(badface), 10); @@ -27038,15 +27286,14 @@ long tetgenmesh::improvequalitybyflips() flipqueue = new arraypool(sizeof(badface), 10); nextflipqueue = new arraypool(sizeof(badface), 10); - // Backup flip edge options. - int bakautofliplinklevel = autofliplinklevel; - int bakfliplinklevel = b->fliplinklevel; - int bakmaxflipstarsize = b->flipstarsize; - - // Set flip edge options. - autofliplinklevel = 1; + // Flip edge options. b->fliplinklevel = -1; - b->flipstarsize = 10; // b->optmaxflipstarsize; + autofliplinklevel = 1; // Init value. + + // 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; fc.remove_large_angle = 1; fc.unflip = 1; @@ -27073,7 +27320,6 @@ 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. @@ -27167,12 +27413,12 @@ long tetgenmesh::improvequalitybyflips() totalremcount += remcount; if (unflipqueue->objects > 0l) { - //if (autofliplinklevel >= b->optmaxfliplevel) { - if (autofliplinklevel >= b->optlevel) { + // 'b->optmaxfliplevel' is set by -OOO, default is 2. + if (autofliplinklevel >= b->optmaxfliplevel) { + // For efficiency reason, we do not search too far. break; } autofliplinklevel+=b->fliplinklevelinc; - //b->flipstarsize = 10 + (1 << (b->optlevel - 1)); } // Swap the two flip queues. @@ -27181,9 +27427,6 @@ long tetgenmesh::improvequalitybyflips() unflipqueue = swapqueue; } // while (flipqueues->objects > 0) - // Restore original flip edge options. - autofliplinklevel = bakautofliplinklevel; - b->fliplinklevel = bakfliplinklevel; b->flipstarsize = bakmaxflipstarsize; delete flipqueue; @@ -27612,7 +27855,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 dihedral angle. + // 'slitet' is [c,d,a,b], where [c,d] has a big hihedral angle. // Go to the opposite edge [a,b]. eprev(*slitet, searchtet); esymself(searchtet); @@ -27625,18 +27868,13 @@ 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]. @@ -27883,12 +28121,11 @@ long tetgenmesh::removeslivers(int chkencflag) // // /////////////////////////////////////////////////////////////////////////////// -void tetgenmesh::optimizemesh() +void tetgenmesh::optimizemesh(int optflag) { badface *parybface; triface checktet; point *ppt; - int optpasses; optparameters opm; REAL ncosdd[6], maxdd; long totalremcount, remcount; @@ -27902,16 +28139,18 @@ void tetgenmesh::optimizemesh() printf("Optimizing mesh...\n"); } - 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); + 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); } - - optpasses = ((1 << b->optlevel) - 1); - totalsmtcount = totalsptcount = totalremcount = 0l; + if (b->verbose > 1) { + printf(" Removing large angles (> %g degree).\n", b->optmaxdihedral); + } + cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI); cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI); cosslidihed = cos(b->optminslidihed / 180.0 * PI); @@ -27942,7 +28181,7 @@ void tetgenmesh::optimizemesh() totalremcount = improvequalitybyflips(); if ((unflipqueue->objects > 0l) && - ((b->optscheme & 2) || (b->optscheme & 4))) { + ((b->optlevel & 2) || (b->optlevel & 4))) { // -O2 | -O4 badtetrahedrons = new memorypool(sizeof(badface), b->tetrahedraperblock, memorypool::POINTER, 0); @@ -27956,9 +28195,9 @@ void tetgenmesh::optimizemesh() chkencflag = 4; // Queue affected tets after splitting a sliver. iter = 0; - while (iter < optpasses) { + while (iter < b->optpasses) { smtcount = sptcount = remcount = 0l; - if (b->optscheme & 2) { + if (b->optlevel & 2) { smtcount += improvequalitybysmoothing(&opm); totalsmtcount += smtcount; if (smtcount > 0l) { @@ -27967,7 +28206,7 @@ void tetgenmesh::optimizemesh() } } if (unflipqueue->objects > 0l) { - if (b->optscheme & 4) { + if (b->optlevel & 4) { sptcount += removeslivers(chkencflag); totalsptcount += sptcount; if (sptcount > 0l) { @@ -27989,7 +28228,7 @@ void tetgenmesh::optimizemesh() delete badtetrahedrons; - } + } // // -O2 | -O4 if (unflipqueue->objects > 0l) { if (b->verbose > 1) { @@ -28197,10 +28436,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) spinsh.sh, + printf(" First: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); - printf(" Second: x%lx (DEAD)\n", (unsigned long) nextsh.sh); + printf(" Second: x%lx (DEAD)\n", (unsigned long long) nextsh.sh); horrors++; break; } @@ -28208,10 +28447,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) spinsh.sh, + printf(" First: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); - printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh, + printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long long) nextsh.sh, pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), pointmark(sapex(nextsh))); horrors++; @@ -28220,10 +28459,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) spinsh.sh, + printf(" First: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); - printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh, + printf(" Scond: x%lx (%d, %d, %d).\n", (unsigned long long) nextsh.sh, pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), pointmark(sapex(nextsh))); horrors++; @@ -28237,19 +28476,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) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); - printf(" Sub: x%lx (Dead)\n", (unsigned long) checkseg.sh); + printf(" Sub: x%lx (Dead)\n", (unsigned long 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) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); - printf(" Seg: x%lx (%d, %d).\n", (unsigned long) checkseg.sh, + printf(" Seg: x%lx (%d, %d).\n", (unsigned long long) checkseg.sh, pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); horrors++; } @@ -28263,20 +28502,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) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); - printf(" Tet: x%lx (DEAD)\n", (unsigned long) neightet.tet); + printf(" Tet: x%lx (DEAD)\n", (unsigned long 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) shloop.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) shloop.sh, pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); printf(" Tet: x%lx (%d, %d, %d, %d).\n", - (unsigned long) neightet.tet, pointmark(org(neightet)), + (unsigned long long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet))); horrors++; @@ -28285,11 +28524,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) spinsh.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); printf(" Tet: x%lx (%d, %d, %d, %d).\n", - (unsigned long) neightet.tet, pointmark(org(neightet)), + (unsigned long long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet))); horrors++; @@ -28300,11 +28539,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) spinsh.sh, + printf(" Sub: x%lx (%d, %d, %d).\n", (unsigned long long) spinsh.sh, pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), pointmark(sapex(spinsh))); printf(" Tet: x%lx (%d, %d, %d, %d).\n", - (unsigned long) symtet.tet, pointmark(org(symtet)), + (unsigned long long) symtet.tet, pointmark(org(symtet)), pointmark(dest(symtet)), pointmark(apex(symtet)), pointmark(oppo(symtet))); horrors++; @@ -28384,9 +28623,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) tetloop.tet, pointmark(org(tetloop)), + (unsigned long long) tetloop.tet, pointmark(org(tetloop)), pointmark(dest(tetloop)), pointmark(apex(tetloop)), - pointmark(oppo(tetloop)), (unsigned long) sseg.sh, + pointmark(oppo(tetloop)), (unsigned long long) sseg.sh, pointmark(pa), pointmark(pb)); horrors++; } else { @@ -28397,11 +28636,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) neightet.tet, pointmark(org(neightet)), + (unsigned long 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) checkseg.sh, + printf("Seg x%lx (%d, %d).\n", (unsigned long long) checkseg.sh, pointmark(sorg(checkseg)),pointmark(sdest(checkseg))); } else { printf("Seg: NULL.\n"); @@ -28421,9 +28660,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) neightet.tet, pointmark(org(neightet)), + (unsigned long long) neightet.tet, pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), - pointmark(oppo(neightet)), (unsigned long) sseg.sh, + pointmark(oppo(neightet)), (unsigned long long) sseg.sh, pointmark(pa), pointmark(pb)); horrors++; } @@ -28440,7 +28679,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) neightet.tet, neightet.ver); + (unsigned long long) neightet.tet, neightet.ver); // Check if all tets at the edge are marked. spintet = neightet; while (1) { @@ -28449,7 +28688,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) spintet.tet, spintet.ver); + (unsigned long long) spintet.tet, spintet.ver); horrors++; } if (spintet.tet == neightet.tet) break; @@ -28482,7 +28721,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) spinsh.sh, + // pointmark(sapex(spinsh)), (unsigned long long) spinsh.sh, // spinsh.shver); // horrors++; //} @@ -28495,7 +28734,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) spintet.tet, spintet.ver); + (unsigned long long) spintet.tet, spintet.ver); horrors++; } if (checkseg.sh != sseg.sh) { @@ -28514,7 +28753,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) spinsh.sh, + pointmark(sapex(spinsh)), (unsigned long long) spinsh.sh, spinsh.shver); horrors++; break; @@ -29336,11 +29575,7 @@ void tetgenmesh::statistics() tetnumber = tetrahedrons->items - hullsize; facenumber = (tetnumber * 4l + hullsize) / 2l; - if (b->weighted) { // -w option - printf("\n Mesh points: %ld\n", points->items - nonregularcount); - } else { - printf("\n Mesh points: %ld\n", points->items); - } + 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); @@ -29349,10 +29584,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 on boundary edges: %ld\n", st_segref_count); + printf(" Steiner points in boundary edges: %ld\n", st_segref_count); } if (st_facref_count > 0l) { - printf(" Steiner points on boundary faces: %ld\n", st_facref_count); + printf(" Steiner points in boundary faces: %ld\n", st_facref_count); } if (st_volref_count > 0l) { printf(" Steiner points in mesh domain: %ld\n", st_volref_count); @@ -29361,9 +29596,6 @@ 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"); @@ -29415,7 +29647,7 @@ void tetgenmesh::jettisonnodes() jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || (pointtype(pointloop) == UNUSEDVERTEX); if (jetflag) { - // It is a duplicated or unused point, delete it. + // It is a duplicated point, delete it. pointdealloc(pointloop); remcount++; } else { @@ -29430,6 +29662,12 @@ 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) { @@ -29445,100 +29683,6 @@ 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(); - } -} /////////////////////////////////////////////////////////////////////////////// // // @@ -29614,7 +29758,7 @@ void tetgenmesh::outnodes(tetgenio* out) char outnodefilename[FILENAMESIZE]; face parentsh; point pointloop; - int nextras, bmark, marker = 0, weightDT = 0; + int nextras, bmark, marker = 0; int coordindex, attribindex; int pointnumber, firstindex; int index, i; @@ -29632,11 +29776,7 @@ void tetgenmesh::outnodes(tetgenio* out) } } - nextras = numpointattrib; - if (b->weighted) { // -w - if (b->weighted_param == 0) weightDT = 1; // Weighted DT. - } - + nextras = in->numberofpointattributes; bmark = !b->nobound && in->pointmarkerlist; if (out == (tetgenio *) NULL) { @@ -29720,13 +29860,7 @@ void tetgenmesh::outnodes(tetgenio* out) pointloop[0], pointloop[1], pointloop[2]); for (i = 0; i < nextras; i++) { // Write an attribute. - 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]); - } + fprintf(outfile, " %.17g", pointloop[4 + i]); } if (bmark) { // Write the boundary marker. @@ -29758,13 +29892,7 @@ void tetgenmesh::outnodes(tetgenio* out) // Point attributes. for (i = 0; i < nextras; i++) { // Output an attribute. - 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]; - } + out->pointattributelist[attribindex++] = pointloop[4 + i]; } if (bmark) { // Output the boundary marker. @@ -29892,7 +30020,7 @@ void tetgenmesh::outelements(tetgenio* out) long ntets; int firstindex, shift; int pointindex, attribindex; - int highorderindex = 11; + int highorderindex = 10; // The reserved pointer. int elementnumber; int eextras; int ishulledge; @@ -29914,7 +30042,7 @@ void tetgenmesh::outelements(tetgenio* out) // The number of tets excluding hull tets. ntets = tetrahedrons->items - hullsize; - eextras = numelemattrib; + eextras = in->numberoftetrahedronattributes; if (out == (tetgenio *) NULL) { outfile = fopen(outelefilename, "w"); if (outfile == (FILE *) NULL) { @@ -29958,13 +30086,8 @@ void tetgenmesh::outelements(tetgenio* out) tptr = tetrahedrontraverse(); elementnumber = firstindex; // in->firstnumber; while (tptr != (tetrahedron *) NULL) { - if (!b->reversetetori) { - p1 = (point) tptr[4]; - p2 = (point) tptr[5]; - } else { - p1 = (point) tptr[5]; - p2 = (point) tptr[4]; - } + p1 = (point) tptr[4]; + p2 = (point) tptr[5]; p3 = (point) tptr[6]; p4 = (point) tptr[7]; if (out == (tetgenio *) NULL) { @@ -29972,9 +30095,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 (b->order == 2) { + if (0) { // if (b->order == 2) { extralist = (point *) tptr[highorderindex]; - // indices for six extra points. + // Tetrahedron number, indices for four points plus 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, @@ -29989,7 +30112,7 @@ void tetgenmesh::outelements(tetgenio* out) tlist[pointindex++] = pointmark(p2) - shift; tlist[pointindex++] = pointmark(p3) - shift; tlist[pointindex++] = pointmark(p4) - shift; - if (b->order == 2) { + if (0) { // if (b->order == 2) { extralist = (point *) tptr[highorderindex]; tlist[pointindex++] = pointmark(extralist[0]) - shift; tlist[pointindex++] = pointmark(extralist[1]) - shift; @@ -30002,8 +30125,10 @@ void tetgenmesh::outelements(tetgenio* out) talist[attribindex++] = elemattribute(tptr, i); } } - // Remember the index of this element (for counting edges). - setelemindex(tptr, elementnumber); + //if (b->neighout) { + // Remember the index of this element. + setelemindex(tptr, elementnumber); + //} tptr = tetrahedrontraverse(); elementnumber++; } @@ -30049,6 +30174,11 @@ 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) @@ -30066,12 +30196,6 @@ 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"); @@ -30087,6 +30211,7 @@ 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"); @@ -30097,8 +30222,7 @@ 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 * (b->order == 1 ? 3 : 6)]; + out->trifacelist = new int[faces * 3]; if (out->trifacelist == (int *) NULL) { printf("Error: Out of memory.\n"); terminatetetgen(1); @@ -30147,15 +30271,6 @@ 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) { @@ -30191,10 +30306,6 @@ 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); @@ -30208,11 +30319,6 @@ 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; } @@ -30348,12 +30454,6 @@ 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"); @@ -30367,6 +30467,8 @@ void tetgenmesh::outsubfaces(tetgenio* out) } } + //bmark = !b->nobound && in->facetmarkerlist; + if (out == (tetgenio *) NULL) { outfile = fopen(facefilename, "w"); if (outfile == (FILE *) NULL) { @@ -30377,8 +30479,7 @@ 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 * (b->order == 1 ? 3 : 6)]; + out->trifacelist = new int[subfaces->items * 3]; if (out->trifacelist == (int *) NULL) { terminatetetgen(1); } @@ -30413,39 +30514,18 @@ 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) { @@ -30472,10 +30552,6 @@ 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); } @@ -30488,11 +30564,6 @@ 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; } @@ -30534,10 +30605,6 @@ 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"); @@ -30561,8 +30628,7 @@ 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 * (b->order == 1 ? 2 : 3)]; + out->edgelist = new int[meshedges * 2]; if (out->edgelist == (int *) NULL) { printf("Error: Out of memory.\n"); terminatetetgen(1); @@ -30608,24 +30674,13 @@ 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) { @@ -30682,11 +30737,6 @@ 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"); @@ -30710,8 +30760,7 @@ 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 * (b->order == 1 ? 2 : 3)]; + out->edgelist = new int[subsegs->items * 2]; if (out->edgelist == (int *) NULL) { terminatetetgen(1); } @@ -30738,45 +30787,17 @@ 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", edgenumber, - pointmark(torg) - shift, pointmark(tdest) - shift); - if (b->order == 2) { // -o2 - fprintf(outfile, " %4d", pointmark(pp) - shift); - } - fprintf(outfile, " %d\n", marker); + fprintf(outfile, "%5d %4d %4d %d\n", edgenumber, + pointmark(torg) - shift, pointmark(tdest) - shift, 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++; @@ -30891,12 +30912,6 @@ 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. // // // /////////////////////////////////////////////////////////////////////////////// @@ -30989,12 +31004,7 @@ void tetgenmesh::outvoronoi(tetgenio* out) pt[i] = (point) tetloop.tet[4 + i]; setpoint2tet(pt[i], encode(tetloop)); } - 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); - } + 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]); @@ -31267,8 +31277,7 @@ void tetgenmesh::outvoronoi(tetgenio* out) vpointcount = 0; while (ploop != (point) NULL) { if ((pointtype(ploop) != UNUSEDVERTEX) && - (pointtype(ploop) != DUPLICATEDVERTEX) && - (pointtype(ploop) != NREGULARVERTEX)) { + (pointtype(ploop) != DUPLICATEDVERTEX)) { getvertexstar(1, ploop, tetlist, ptlist, NULL); // Mark all vertices. Check if it is a hull vertex. ishullvert = 0; @@ -31328,6 +31337,14 @@ 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++; @@ -31566,18 +31583,13 @@ void tetgenmesh::outmesh2medit(char* mfilename) tetrahedrons->traversalinit(); tetptr = tetrahedrontraverse(); while (tetptr != (tetrahedron *) NULL) { - if (!b->reversetetori) { - p1 = (point) tetptr[4]; - p2 = (point) tetptr[5]; - } else { - p1 = (point) tetptr[5]; - p2 = (point) tetptr[4]; - } + p1 = (point) tetptr[4]; + p2 = (point) tetptr[5]; p3 = (point) tetptr[6]; p4 = (point) tetptr[7]; fprintf(outfile, "%5d %5d %5d %5d", pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); - if (numelemattrib > 0) { + if (in->numberoftetrahedronattributes > 0) { fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); } else { fprintf(outfile, " 0"); @@ -31627,7 +31639,7 @@ void tetgenmesh::outmesh2vtk(char* ofilename) { FILE *outfile; char vtkfilename[FILENAMESIZE]; - point pointloop, p1, p2, p3, p4; + point pointloop; tetrahedron* tptr; double x, y, z; int n1, n2, n3, n4; @@ -31686,15 +31698,10 @@ void tetgenmesh::outmesh2vtk(char* ofilename) return; } while (tptr != (tetrahedron *) NULL) { - 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]; + point p1 = (point) tptr[4]; + point p2 = (point) tptr[5]; + point p3 = (point) tptr[6]; + point p4 = (point) tptr[7]; n1 = pointmark(p1) - in->firstnumber; n2 = pointmark(p2) - in->firstnumber; n3 = pointmark(p3) - in->firstnumber; @@ -31749,149 +31756,186 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, tetgenio *addin, tetgenio *bgmin) { tetgenmesh m; - clock_t tv[10], ts[5]; // Timing informations (defined in time.h) - REAL cps = (REAL) CLOCKS_PER_SEC; + clock_t tv[17]; // Timing informations (defined in time.h) tv[0] = clock(); m.b = b; m.in = in; - m.addin = addin; - if ((b->metric) && (bgmin->numberofpoints > 0)) { + if ((bgmin != NULL) && + ((bgmin->numberofpoints > 0) && (bgmin->pointmtrlist != NULL))) { 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 - m.incrementaldelaunay(ts[0]); + if (!b->diagnose) { + m.incrementaldelaunay(tv[16]); + } } tv[2] = clock(); if (!b->quiet) { if (b->refine) { - printf("Mesh reconstruction seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps); + printf("Mesh reconstruction seconds: %g\n", + (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC); } else { - 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->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 + } } } } - if (b->plc) { // -p + if (b->plc) { m.meshsurface(); + } - ts[0] = clock(); - - 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); - } + tv[3] = clock(); - return; + if (!b->quiet) { + if (b->plc) { + printf("Surface mesh seconds: %g\n", + (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC); } } - tv[3] = clock(); - - if ((b->metric) && (m.bgm != NULL)) { // -m - m.bgm->initializepools(); - m.bgm->transfernodes(); - m.bgm->reconstructmesh(); + if (b->plc && b->diagnose) { // -d + m.detectinterfaces(); - ts[0] = clock(); + tv[4] = clock(); if (!b->quiet) { - printf("Background mesh reconstruct seconds: %g\n", - ((REAL)(ts[0] - tv[3])) / cps); + printf("Self-intersection seconds: %g\n", + (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC); } - if (b->metric) { // -m - m.interpolatemeshsize(); - - ts[1] = clock(); - - if (!b->quiet) { - printf("Size interpolating 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); } - } - tv[4] = clock(); + return; + } - if (b->plc) { // -p - if (b->nobisect) { // -Y - m.recoverboundary(ts[0]); + if (b->plc) { + if (b->nobisect) { // with -Y option + m.recoverboundary(tv[15]); } else { - m.constraineddelaunay(ts[0]); + m.constraineddelaunay(tv[15]); } + } - ts[1] = clock(); + tv[4] = clock(); - if (!b->quiet) { - printf("Boundary recovery seconds: %g\n", ((REAL)(ts[1]-tv[4])) / cps); + if (!b->quiet) { + if (b->plc) { + printf("Boundary recovery seconds: %g\n", + (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC); if (b->verbose) { - printf(" Segment recovery seconds: %g\n",((REAL)(ts[0]-tv[4]))/ cps); - printf(" Facet recovery seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps); + 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); } } + } + if (b->plc && !b->convex) { m.carveholes(); + } - ts[2] = clock(); + tv[5] = clock(); - if (!b->quiet) { + if (!b->quiet) { + if (b->plc && !b->convex) { printf("Exterior tets removal seconds: %g\n", - ((REAL)(ts[2]-ts[1])) / cps); + (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC); } + } - if (b->nobisect) { // -Y - m.suppresssteinerpoints(); + if (b->plc && b->nobisect) { + m.suppresssteinerpoints(); + } - ts[3] = clock(); + tv[6] = clock(); - if (!b->quiet) { - printf("Steiner suppression seconds: %g\n",((REAL)(ts[3]-ts[2]))/cps); - } + if (!b->quiet) { + if (b->plc && b->nobisect) { + printf("Steiner suppression seconds: %g\n", + (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC); + } + } - m.recoverdelaunay(); + if (b->plc && b->nobisect) { + m.recoverdelaunay(); + } - ts[4] = clock(); + tv[7] = clock(); - if (!b->quiet) { - printf("Delaunay recovery seconds: %g\n", ((REAL)(ts[4]-ts[3])) / cps); - } + if (!b->quiet) { + if (b->plc && b->nobisect) { + printf("Delaunay recovery seconds: %g\n", + (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC); } } - tv[5] = clock(); + if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) { + m.bgm->initializepools(); + m.bgm->transfernodes(); + m.bgm->reconstructmesh(); + } + + tv[8] = 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->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); + } + } if ((b->plc || b->refine) && b->insertaddpoints) { // -i if ((addin != NULL) && (addin->numberofpoints > 0)) { @@ -31899,38 +31943,44 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, } } - tv[6] = clock(); + tv[10] = clock(); if (!b->quiet) { if ((b->plc || b->refine) && b->insertaddpoints) { if ((addin != NULL) && (addin->numberofpoints > 0)) { - printf("Constrained points seconds: %g\n", ((REAL)(tv[6]-tv[5]))/cps); + printf("Constrained points seconds: %g\n", + (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC); } } } - if (b->quality) { + tv[11] = clock(); + + + if ((b->plc || b->refine) && b->quality) { m.delaunayrefinement(); } - tv[7] = clock(); + tv[12] = clock(); if (!b->quiet) { - if (b->quality) { - printf("Refinement seconds: %g\n", ((REAL)(tv[7] - tv[6])) / cps); + if ((b->plc || b->refine) && b->quality) { + printf("Refinement seconds: %g\n", + (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC); } } - if ((b->plc || b->refine) && (b->optlevel > 0) && !b->conforming) { - m.optimizemesh(); + if ((b->plc || b->refine) && (b->optlevel > 0)) { + m.optimizemesh(1); } - tv[8] = clock(); + tv[13] = clock(); if (!b->quiet) { - if ((b->plc || b->refine) && (b->optlevel > 0) && !b->conforming) { - printf("Optimization seconds: %g\n", ((REAL)(tv[8] - tv[7])) / cps); + if ((b->plc || b->refine) && (b->optlevel > 0)) { + printf("Optimization seconds: %g\n", + (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC); } } @@ -31939,9 +31989,6 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, m.jettisonnodes(); } - if (b->order == 2) { - m.highorder(); - } if (!b->quiet) { printf("\n"); @@ -31960,7 +32007,7 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, m.outnodes(out); } - if (b->noelewritten) { + if (b->noelewritten == 1) { if (!b->quiet) { printf("NOT writing an .ele file.\n"); } @@ -31994,17 +32041,11 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, } - 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. + if (b->edgesout) { + if (b->edgesout > 1) { + m.outedges(out); // -ee, output all mesh edges. } else { - if (b->plc || b->refine) { - m.outsubsegments(out); // output subsegments. - } + m.outsubsegments(out); // -e, only output subsegments. } } @@ -32037,11 +32078,13 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, } - tv[9] = clock(); + tv[14] = clock(); if (!b->quiet) { - printf("\nOutput seconds: %g\n", ((REAL)(tv[9] - tv[8])) / cps); - printf("Total running seconds: %g\n", ((REAL)(tv[9] - tv[0])) / cps); + 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); } if (b->docheck) { diff --git a/contrib/Tetgen1.5/tetgen.h b/contrib/Tetgen1.5/tetgen.h index e02cbefa45c0b1b4e275a04869d725849b35b8b0..41634d03f49ee9d805eb18e5511c672f8d23478a 100644 --- a/contrib/Tetgen1.5/tetgen.h +++ b/contrib/Tetgen1.5/tetgen.h @@ -5,7 +5,11 @@ // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // // // // Version 1.5 // -// October 06, 2012 // +// February 21, 2012 // +// // +// PRE-RELEASE TEST CODE. // +// PLEASE DO NOT DISTRIBUTE !! // +// PLEASE HELP ME TO IMPROVE IT !! // // // // Copyright (C) 2002--2012 // // Hang Si // @@ -36,27 +40,34 @@ // #define TETLIBRARY -// 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. +// Uncomment the following line to disable assert macros. These macros are +// inserted in places where I hope to catch bugs. // #define NDEBUG -// TetGen uses the double precision for a real number. +// 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. #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++ 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 +// 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 -// 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. +// Define the _WIN64 symbol if you are running TetGen on Win64. + +// #define _WIN64 #ifdef _MSC_VER // Microsoft Visual C++ # ifdef _WIN64 @@ -82,7 +93,7 @@ // // // tetgenio // // // -// A structure for transfering data into and out of TetGen's mesh structure. // +// A structure for transfering data into and out of TetGen. // // // // 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) // @@ -103,18 +114,18 @@ class tetgenio { public: // A "polygon" describes a simple polygon (no holes). It is not necessarily - // 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. + // 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. typedef struct { int *vertexlist; int numberofvertices; } polygon; - // 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). + // A "facet" describes a facet. Each facet is a polygonal region possibly + // with holes, edges, and points in it. typedef struct { polygon *polygonlist; int numberofpolygons; @@ -195,73 +206,68 @@ 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 (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; + // `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; 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 (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. + // `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. REAL *holelist; int numberofholes; - // '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' + // `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' // 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 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. + // `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. REAL *facetconstraintlist; int numberoffacetconstraints; - // '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. + // `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. REAL *segmentconstraintlist; int numberofsegmentconstraints; @@ -269,14 +275,15 @@ public: pbcgroup *pbcgrouplist; int numberofpbcgroups; - // '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. + // `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. int *trifacelist; int *adjtetlist; int *trifacemarkerlist; @@ -438,7 +445,7 @@ public: pbcgroup *pg; int i, j; - // Notice that this routine assumes that the memory was allocated by + // Notince that this routine assumes that the memory was allocated by // C++ memory allocation operator 'new'. if (pointlist != (REAL *) NULL) { @@ -556,13 +563,12 @@ public: // // // tetgenbehavior // // // -// A structure for maintaining the switches and parameters used by TetGen's // -// meshing algorithms. They are specified by the command line arguments. // +// A structure to maintain the switches and parameters of TetGen. // // // -// 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. // +// 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. // // // /////////////////////////////////////////////////////////////////////////////// @@ -570,81 +576,94 @@ class tetgenbehavior { public: - // 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. + // 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. char commandline[1024]; char infilename[1024]; char outfilename[1024]; char addinfilename[1024]; char bgmeshfilename[1024]; - // The input object of TetGen. They are recognized by either the input - // file extensions or by the specified options. + // 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. enum objecttype {NODES, POLY, OFF, PLY, STL, MEDIT, VTK, MESH} object; @@ -662,18 +681,17 @@ public: { plc = 0; psc = 0; - refine = 0; quality = 0; - nobisect = 0; + refine = 0; metric = 0; + nobisect = 0; weighted = 0; - brio_hilbert = 1; - incrflip = 0; - flipinsert = 0; varvolume = 0; fixedvolume = 0; - noexact = 0; - nostaticfilter = 0; + incrflip = 0; + flipinsert = 0; + btree = 0; + hilbertcurve = 0; insertaddpoints = 0; regionattrib = 0; conforming = 0; @@ -693,7 +711,6 @@ public: noiterationnum = 0; nomerge = 0; nojettison = 0; - reversetetori = 0; docheck = 0; quiet = 0; verbose = 0; @@ -703,21 +720,24 @@ public: shellfaceperblock = 4092; nobisect_param = 1; weighted_param = 0; - hilbert_order = -1; - hilbert_limit = 8; + flipinsert_random = 0; + flipinsert_ori4dexact = 0; 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; - optscheme = 7; // 1 & 2 & 4, // min_max_dihedral. - optlevel = 2; + optlevel = 7; // 1 & 2 & 4, // min_max_dihedral. + optpasses = 3; + optmaxfliplevel = 2; delmaxfliplevel = 1; + optmaxflipstarsize = 10; order = 1; steinerleft = -1; facet_ang_tol = 179.9; maxvolume = -1.0; minratio = 2.0; - mindihedral = 5.0; + mindihedral = 0.0; // 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 @@ -737,44 +757,45 @@ public: /////////////////////////////////////////////////////////////////////////////// // // -// 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". // +// 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". // // // /////////////////////////////////////////////////////////////////////////////// -void exactinit(int, int, REAL, REAL, REAL); +REAL exactinit(); 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); -void predicates_statistics(int weighted); +REAL orient4dexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, + REAL ah, REAL bh, REAL ch, REAL dh, REAL eh); /////////////////////////////////////////////////////////////////////////////// // // // tetgenmesh // // // -// A structure containing the mesh data structure and the implementations of // -// tetrahedral meshing algorithms of TetGen. // +// The object to generate tetrahedral meshes. // // // /////////////////////////////////////////////////////////////////////////////// @@ -785,7 +806,7 @@ public: // Labels that signify the type of a vertex. enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, RIDGEVERTEX, ACUTEVERTEX, FACETVERTEX, VOLVERTEX, FREESEGVERTEX, FREEFACETVERTEX, - FREEVOLVERTEX, NREGULARVERTEX, DEADVERTEX}; + FREEVOLVERTEX, HIDDENVERTEX, DEADVERTEX}; // Labels that signify the type of a subsegment. enum shestype {NSHARP, SHARP, FAKESH}; @@ -797,8 +818,7 @@ public: // Labels that signify the result of point location. enum locateresult {OUTSIDE, INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, INSTAR, - ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX, - NONREGULAR, BADELEMENT}; + ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX,BADELEMENT}; /////////////////////////////////////////////////////////////////////////////// // // @@ -811,23 +831,25 @@ public: // and edges in S and L are respectivly called subfaces and segments to dis- // // tinguish them from others in T. // // // -// 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. // +// 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. // // // /////////////////////////////////////////////////////////////////////////////// @@ -838,7 +860,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 (and flags); + // - an integer of element marker; // The structure of a tetrahedron is an array of pointers. Its actual size // (the length of the array) is determined at runtime. @@ -862,11 +884,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; + // - a pointer to a parent (or a duplicate) point, or a bsp_tree node; // - 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 (and flags). + // - an integer for point type. // - 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. @@ -890,8 +912,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. 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. // +// 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. // // // // 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 // @@ -928,9 +950,6 @@ 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 { @@ -1032,7 +1051,9 @@ 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. @@ -1041,12 +1062,16 @@ 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. - // Internal counters. + // Counters. int maxflippedlinklevelcount; // Maximal flipped link levels. int misfliplinklevelcount; // Number of missed flip possibilities. int chrismastreecount; // Number of Chrismas trees (unflippable case). @@ -1067,6 +1092,7 @@ public: seg[0] = NULL; fac[0] = NULL; remvert = NULL; + //remedge[0] = NULL; unflip = 0; collectnewtets = 0; @@ -1074,6 +1100,7 @@ public: remove_ndelaunay_edge = 0; bak_tetprism_vol = 0.0; + remove_large_angle = 0; cosdihed_in = 0.0; cosdihed_out = 0.0; @@ -1139,8 +1166,8 @@ public: // Arraypool // // // // A dynamic linear array. // -// (It is from Shewchuk's Starbase.c, which is provided as part of Stellar, // -// a program for improving tetrahedral meshes.) // +// (It is simply copied 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 // @@ -1189,7 +1216,7 @@ public: // Memorypool // // // // A type used to allocate memory. // -// (It is from Shewchuk's triangle.c.) // +// (It is simply copied 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 // @@ -1256,7 +1283,7 @@ public: /////////////////////////////////////////////////////////////////////////////// // Pointer to the input data (a set of nodes, a PLC, or a mesh). - tetgenio *in, *addin; + tetgenio *in; // Pointer to the switches and parameters. tetgenbehavior *b; @@ -1277,8 +1304,15 @@ public: memorypool *flippool; // A stack of faces to be flipped. badface *flipstack; - // A queue to store unflippable elements. - arraypool *unflipqueue; + // 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; // Arrays used for point insertion (the Bowyer-Watson algorithm). arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist; @@ -1295,6 +1329,7 @@ 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; @@ -1308,9 +1343,12 @@ public: // PI is the ratio of a circle's circumference to its diameter. static REAL PI; - // Array (size = numberoftetrahedra * 6) for storing high-order nodes of - // tetrahedra (only used when -o2 switch is selected). - point *highordertable; + // 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; // Other variables. REAL xmax, xmin, ymax, ymin, zmax, zmin; // Bounding box of points. @@ -1320,13 +1358,12 @@ 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 numelemattrib; // Number of tetrahedron attributes. + int point2pbcptindex; // Index to find a pbc point to a point. 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. @@ -1335,6 +1372,7 @@ 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? @@ -1342,18 +1380,14 @@ 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; // The cosine value of a bad dihedral tobe smoothed. - REAL cosslidihed; // The cosine value of the max dihedral of a sliver. + REAL cossmtdihed; + REAL cosslidihed; // The cosine value of 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 insphere_sos_count, orient4d_sos_count; + long orient3dcount, inspherecount, insphere_sos_count; long flip14count, flip26count, flipn2ncount; long flip23count, flip32count, flip44count, flip22count; long maxbowatcavsize, totalbowatcavsize, totaldeadtets; @@ -1369,27 +1403,42 @@ 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 // // // -// 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. // +// 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. // // // /////////////////////////////////////////////////////////////////////////////// // Fast lookup tables for mesh manipulation primitives. - 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]; + 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]; // Primitives for tetrahedra. inline void decode(tetrahedron ptr, triface& t); @@ -1411,6 +1460,8 @@ 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); @@ -1478,6 +1529,8 @@ 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); @@ -1541,6 +1594,8 @@ 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); @@ -1563,13 +1618,13 @@ public: badface *badfacetraverse(memorypool*); void pointdealloc(point); point pointtraverse(); - - void makeindex2pointmap(point*&); - void makepoint2submap(memorypool*, int*&, face*&); void maketetrahedron(triface*); void makeshellface(memorypool*, face*); void makepoint(point*, enum verttype); + void makeindex2pointmap(point*&); + void makepoint2submap(memorypool*, int*&, face*&); + void initializepools(); /////////////////////////////////////////////////////////////////////////////// @@ -1613,7 +1668,6 @@ 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); @@ -1650,17 +1704,15 @@ public: void transfernodes(); // Point sorting. - 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); + 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); // Point location. unsigned long randomnation(unsigned int choices); void randomsample(point searchpt, triface *searchtet); - enum locateresult locate(point searchpt, triface *searchtet, int); + enum locateresult locate(point searchpt, triface*, int, int); // Incremental Delaunay construction. void initialdelaunay(point pa, point pb, point pc, point pd); @@ -1694,7 +1746,8 @@ public: void meshsurface(); void interecursive(shellface** subfacearray, int arraysize, int axis, - REAL, REAL, REAL, REAL, REAL, REAL, int* internum); + REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, + REAL bzmin, REAL bzmax, int* internum); void detectinterfaces(); /////////////////////////////////////////////////////////////////////////////// @@ -1707,27 +1760,36 @@ public: void reportselfintersect(face *seg, face *shface); - enum interresult finddirection(triface* searchtet, point endpt); + enum interresult finddirection(triface* searchtet, point endpt, int); 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*, arraypool*, arraypool*, arraypool*, arraypool*); - int scoutcrossedge(triface& crosstet, arraypool*, arraypool*); - bool formcavity(triface*, arraypool*, arraypool*, arraypool*, arraypool*, - arraypool*, arraypool*); + 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); // Facet recovery by local re-tetrahedralization [Si and Gaertner'05,'11]. - void delaunizecavity(arraypool*, arraypool*, arraypool*, arraypool*, - arraypool*, arraypool*); - bool fillcavity(arraypool*, arraypool*, arraypool*, arraypool*); - void carvecavity(arraypool*, arraypool*, arraypool*); - void restorecavity(arraypool*, arraypool*, arraypool*); + 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); // Facet recovery by flips [Shewchuk'03]. void flipcertify(triface *chkface, badface **pqueue); - void flipinsertfacet(arraypool*, arraypool*, arraypool*, arraypool*); + void flipinsertfacet(arraypool *crosstets, arraypool *toppoints, + arraypool *botpoints, arraypool *midpoints); bool fillregion(arraypool* missingshs, arraypool*, arraypool* newshs); void refineregion(); @@ -1742,6 +1804,7 @@ public: // // /////////////////////////////////////////////////////////////////////////////// + // A call back function. int checkflipeligibility(int fliptype, point, point, point, point, point, int level, int edgepivot, flipconstraints* fc); @@ -1777,7 +1840,7 @@ public: void reconstructmesh(); int scoutpoint(point, triface*, int randflag); - REAL getpointmeshsize(point, triface*, int iloc); + REAL getpointmeshsize(point, triface*, int iloc, int posflag); void interpolatemeshsize(); void insertconstrainedpoints(tetgenio *addio); @@ -1805,7 +1868,6 @@ 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(); @@ -1826,7 +1888,7 @@ public: int splitsliver(triface *, REAL, int); long removeslivers(int); - void optimizemesh(); + void optimizemesh(int optflag); /////////////////////////////////////////////////////////////////////////////// // // @@ -1878,8 +1940,8 @@ public: tetgenmesh() { - in = addin = NULL; b = NULL; + in = NULL; bgm = NULL; tetrahedrons = subfaces = subsegs = points = NULL; @@ -1890,6 +1952,7 @@ public: dummypoint = NULL; flipstack = NULL; unflipqueue = NULL; + btreenode_list = NULL; cavetetlist = cavebdrylist = caveoldtetlist = NULL; cavetetshlist = cavetetseglist = cavetetvertlist = NULL; @@ -1900,8 +1963,6 @@ public: suppsteinerptlist = NULL; encseglist = encshlist = NULL; - highordertable = NULL; - plane_pa = plane_pb = plane_pc = (point) NULL; xmax = xmin = ymax = ymin = zmax = zmin = 0.0; @@ -1910,13 +1971,11 @@ public: insegments = 0l; meshedges = meshhulledges = 0l; steinerleft = -1; - numpointattrib = 0; - sizeoftensor = 0; pointmtrindex = 0; pointparamindex = 0; pointmarkindex = 0; point2simindex = 0; - numelemattrib = 0; + point2pbcptindex = 0; elemattribindex = 0; volumeboundindex = 0; shmarkindex = 0; @@ -1924,6 +1983,7 @@ public: checksubsegflag = 0; checksubfaceflag = 0; checkinverttetflag = 0; + checkpbcs = 0; checkconstraints = 0; nonconvex = 0; dupverts = 0; @@ -1932,12 +1992,15 @@ public: randomseed = 1l; minfaceang = minfacetdihed = PI; sintheta_tol = sin(0.001 * PI / 180.0); + autofliplinklevel = 1; - calc_tetprism_vol = 0; + tetprism_vol_sum = 0.0; + calc_tetprism_vol = 0; ptloc_count = ptloc_max_count = 0l; - insphere_sos_count = orient4d_sos_count = 0l; + orient3dcount = 0l; + inspherecount = insphere_sos_count = 0l; flip14count = flip26count = flipn2ncount = 0l; flip23count = flip32count = flip44count = flip22count = 0l; maxbowatcavsize = totalbowatcavsize = totaldeadtets = 0l; @@ -1952,12 +2015,15 @@ 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() @@ -2018,10 +2084,6 @@ public: if (suppsteinerptlist != NULL) { delete suppsteinerptlist; } - - if (highordertable != NULL) { - delete [] highordertable; - } } // ~tetgenmesh() }; // End of class tetgenmesh. @@ -2126,26 +2188,17 @@ 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 (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. -/* +// 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]. + 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). @@ -2156,17 +2209,20 @@ 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) { - decode((t1).tet[(t1).ver & 3], t2); - (t2).ver = mod12[(t2).ver + 12 - ((t1).ver & 12)]; + tetrahedron ptr = (t1).tet[(t1).ver & 3]; + int offset = 12 - ((t1).ver & 12); + decode(ptr, t2); + (t2).ver = mod12[(t2).ver + offset]; } inline void tetgenmesh::fsymself(triface& t) { + tetrahedron ptr = (t).tet[(t).ver & 3]; int offset = 12 - ((t).ver & 12); - decode((t).tet[(t).ver & 3], t); + decode(ptr, t); (t).ver = mod12[(t).ver + offset]; } -// enext() finds the next edge (counterclockwise) in the same face. +// enext() finds the next edge (counterclockwise) on the same face. inline void tetgenmesh::enext(triface& t1, triface& t2) { (t2).tet = (t1).tet; @@ -2177,7 +2233,7 @@ inline void tetgenmesh::enextself(triface& t) { (t).ver = mod12[(t).ver + 4]; } -// eprev() finds the next edge (clockwise) in the same face. +// eprev() finds the next edge (clockwise) on the same face. inline void tetgenmesh::eprev(triface& t1, triface& t2) { (t2).tet = (t1).tet; @@ -2188,7 +2244,7 @@ inline void tetgenmesh::eprevself(triface& t) { (t).ver = mod12[(t).ver + 8]; } -// esym() finds the reversed edge. It is in the other face of the +// esym() finds the reversed edge. It is on the other face of the // same tetrahedron. inline void tetgenmesh::esym(triface& t1, triface& t2) { @@ -2200,8 +2256,8 @@ inline void tetgenmesh::esymself(triface& t) { (t).ver = edgepivot[(t).ver]; } -// 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(). +// enextesym() finds the reversed edge of the next edge. It is on the other +// face of the same tetrahedron. inline void tetgenmesh::enextesym(triface& t1, triface& t2) { enext(t1, t2); @@ -2213,7 +2269,8 @@ inline void tetgenmesh::enextesymself(triface& t) { esymself(t); } -// eprevesym() finds the reversed edge of the previous edge. +// eprevesym() finds the reversed edge of the previous edge. It is on the +// other face of the same tetrahedron. inline void tetgenmesh::eprevesym(triface& t1, triface& t2) { eprev(t1, t2); @@ -2227,7 +2284,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 -// the combination: fsym() * esym(). +// equivalent to the combination: fsym() * esym(). inline void tetgenmesh::fnext(triface& t1, triface& t2) { esym(t1, t2); @@ -2239,6 +2296,19 @@ 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. @@ -2345,7 +2415,10 @@ inline bool tetgenmesh::infected(triface& t) { } // marktest(), marktested(), unmarktest() -- primitives to flag or unflag a -// tetrahedron. Use the second lowerest bit of the element marker. +// 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. inline void tetgenmesh::marktest(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= 2; @@ -2362,6 +2435,8 @@ 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)); @@ -2378,7 +2453,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]); @@ -2465,7 +2540,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) (s.shver)); + s.sh = (shellface *) ((uintptr_t) (sptr) & ~ (uintptr_t) 7); } inline tetgenmesh::shellface tetgenmesh::sencode(face& s) { @@ -2700,6 +2775,17 @@ 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. @@ -2724,7 +2810,8 @@ inline bool tetgenmesh::sinfected(face& s) } // smarktest(), smarktested(), sunmarktest() -- primitives to flag or unflag -// a subface.The last 2nd bit of the integer is flaged. +// a subface. +// The last 2nd bit of ((int *) ((s).sh))[shmarkindex+1] is flaged. inline void tetgenmesh::smarktest(face& s) { @@ -2744,7 +2831,8 @@ inline bool tetgenmesh::smarktested(face& s) } // smarktest2(), smarktest2ed(), sunmarktest2() -- primitives to flag or -// unflag a subface. The last 3rd bit of the integer is flaged. +// unflag a subface. +// The last 3rd bit of ((int *) ((s).sh))[shmarkindex+1] is flaged. inline void tetgenmesh::smarktest2(face& s) { @@ -3125,6 +3213,15 @@ 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.