Chaste Release::3.1
|
00001 00008 // This include is here so that the chaste_libs=0 build correctly links predicates.o. 00009 #include "predicates.hpp" 00010 00012 // // 00013 // TetGen // 00014 // // 00015 // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // 00016 // // 00017 // Version 1.4 // 00018 // April 16, 2007 // 00019 // // 00020 // Copyright (C) 2002--2007 // 00021 // Hang Si // 00022 // Research Group Numerical Mathematics and Scientific Computing // 00023 // Weierstrass Institute for Applied Analysis and Stochastics // 00024 // Mohrenstr. 39, 10117 Berlin, Germany // 00025 // si@wias-berlin.de // 00026 // // 00027 // TetGen is freely available through the website: http://tetgen.berlios.de. // 00028 // It may be copied, modified, and redistributed for non-commercial use. // 00029 // Please consult the file LICENSE for the detailed copyright notices. // 00030 // // 00032 00034 // // 00035 // tetgen.cxx // 00036 // // 00037 // The TetGen library and program. // 00038 // // 00040 00041 #include "tetgen.h" 00042 namespace tetgen 00043 { //Added namespace to avoid clash with triangle 00044 00046 // // 00047 // terminatetetgen() Terminate TetGen with a given exit code. // 00048 // // 00050 00051 void terminatetetgen(int x) 00052 { 00053 #ifdef TETLIBRARY 00054 throw x; 00055 #else 00056 exit(x); 00057 #endif // #ifdef TETLIBRARY 00058 } 00059 00060 // 00061 // Begin of class 'tetgenio' implementation 00062 // 00063 00065 // // 00066 // initialize() Initialize all variables of 'tetgenio'. // 00067 // // 00068 // It is called by the only class constructor 'tetgenio()' implicitly. Thus, // 00069 // all variables are guaranteed to be initialized. Each array is initialized // 00070 // to be a 'NULL' pointer, and its length is equal zero. Some variables have // 00071 // their default value, 'firstnumber' equals zero, 'mesh_dim' equals 3, and // 00072 // 'numberofcorners' equals 4. Another possible use of this routine is to // 00073 // call it before to re-use an object. // 00074 // // 00076 00077 void tetgenio::initialize() 00078 { 00079 firstnumber = 0; // Default item index is numbered from Zero. 00080 mesh_dim = 3; // Default mesh dimension is 3. 00081 useindex = true; 00082 00083 pointlist = (REAL *) NULL; 00084 pointattributelist = (REAL *) NULL; 00085 pointmtrlist = (REAL *) NULL; 00086 pointmarkerlist = (int *) NULL; 00087 numberofpoints = 0; 00088 numberofpointattributes = 0; 00089 numberofpointmtrs = 0; 00090 00091 tetrahedronlist = (int *) NULL; 00092 tetrahedronattributelist = (REAL *) NULL; 00093 tetrahedronvolumelist = (REAL *) NULL; 00094 neighborlist = (int *) NULL; 00095 numberoftetrahedra = 0; 00096 numberofcorners = 4; // Default is 4 nodes per element. 00097 numberoftetrahedronattributes = 0; 00098 00099 trifacelist = (int *) NULL; 00100 adjtetlist = (int *) NULL; 00101 trifacemarkerlist = (int *) NULL; 00102 numberoftrifaces = 0; 00103 00104 facetlist = (facet *) NULL; 00105 facetmarkerlist = (int *) NULL; 00106 numberoffacets = 0; 00107 00108 edgelist = (int *) NULL; 00109 edgemarkerlist = (int *) NULL; 00110 numberofedges = 0; 00111 00112 holelist = (REAL *) NULL; 00113 numberofholes = 0; 00114 00115 regionlist = (REAL *) NULL; 00116 numberofregions = 0; 00117 00118 facetconstraintlist = (REAL *) NULL; 00119 numberoffacetconstraints = 0; 00120 segmentconstraintlist = (REAL *) NULL; 00121 numberofsegmentconstraints = 0; 00122 00123 pbcgrouplist = (pbcgroup *) NULL; 00124 numberofpbcgroups = 0; 00125 00126 vpointlist = (REAL *) NULL; 00127 vedgelist = (voroedge *) NULL; 00128 vfacetlist = (vorofacet *) NULL; 00129 vcelllist = (int **) NULL; 00130 numberofvpoints = 0; 00131 numberofvedges = 0; 00132 numberofvfacets = 0; 00133 numberofvcells = 0; 00134 } 00135 00137 // // 00138 // deinitialize() Free the memory allocated in 'tetgenio'. // 00139 // // 00140 // It is called by the class destructor '~tetgenio()' implicitly. Hence, the // 00141 // occupied memory by arrays of an object will be automatically released on // 00142 // the deletion of the object. However, this routine assumes that the memory // 00143 // is allocated by C++ memory allocation operator 'new', thus it is freed by // 00144 // the C++ array deletor 'delete []'. If one uses the C/C++ library function // 00145 // 'malloc()' to allocate memory for arrays, one has to free them with the // 00146 // 'free()' function, and call routine 'initialize()' once to disable this // 00147 // routine on deletion of the object. // 00148 // // 00150 00151 void tetgenio::deinitialize() 00152 { 00153 facet *f; 00154 polygon *p; 00155 pbcgroup *pg; 00156 int i, j; 00157 00158 if (pointlist != (REAL *) NULL) { 00159 delete [] pointlist; 00160 } 00161 if (pointattributelist != (REAL *) NULL) { 00162 delete [] pointattributelist; 00163 } 00164 if (pointmtrlist != (REAL *) NULL) { 00165 delete [] pointmtrlist; 00166 } 00167 if (pointmarkerlist != (int *) NULL) { 00168 delete [] pointmarkerlist; 00169 } 00170 00171 if (tetrahedronlist != (int *) NULL) { 00172 delete [] tetrahedronlist; 00173 } 00174 if (tetrahedronattributelist != (REAL *) NULL) { 00175 delete [] tetrahedronattributelist; 00176 } 00177 if (tetrahedronvolumelist != (REAL *) NULL) { 00178 delete [] tetrahedronvolumelist; 00179 } 00180 if (neighborlist != (int *) NULL) { 00181 delete [] neighborlist; 00182 } 00183 00184 if (trifacelist != (int *) NULL) { 00185 delete [] trifacelist; 00186 } 00187 if (adjtetlist != (int *) NULL) { 00188 delete [] adjtetlist; 00189 } 00190 if (trifacemarkerlist != (int *) NULL) { 00191 delete [] trifacemarkerlist; 00192 } 00193 00194 if (edgelist != (int *) NULL) { 00195 delete [] edgelist; 00196 } 00197 if (edgemarkerlist != (int *) NULL) { 00198 delete [] edgemarkerlist; 00199 } 00200 00201 if (facetlist != (facet *) NULL) { 00202 for (i = 0; i < numberoffacets; i++) { 00203 f = &facetlist[i]; 00204 for (j = 0; j < f->numberofpolygons; j++) { 00205 p = &f->polygonlist[j]; 00206 delete [] p->vertexlist; 00207 } 00208 delete [] f->polygonlist; 00209 if (f->holelist != (REAL *) NULL) { 00210 delete [] f->holelist; 00211 } 00212 } 00213 delete [] facetlist; 00214 } 00215 if (facetmarkerlist != (int *) NULL) { 00216 delete [] facetmarkerlist; 00217 } 00218 00219 if (holelist != (REAL *) NULL) { 00220 delete [] holelist; 00221 } 00222 if (regionlist != (REAL *) NULL) { 00223 delete [] regionlist; 00224 } 00225 if (facetconstraintlist != (REAL *) NULL) { 00226 delete [] facetconstraintlist; 00227 } 00228 if (segmentconstraintlist != (REAL *) NULL) { 00229 delete [] segmentconstraintlist; 00230 } 00231 if (pbcgrouplist != (pbcgroup *) NULL) { 00232 for (i = 0; i < numberofpbcgroups; i++) { 00233 pg = &(pbcgrouplist[i]); 00234 if (pg->pointpairlist != (int *) NULL) { 00235 delete [] pg->pointpairlist; 00236 } 00237 } 00238 delete [] pbcgrouplist; 00239 } 00240 if (vpointlist != (REAL *) NULL) { 00241 delete [] vpointlist; 00242 } 00243 if (vedgelist != (voroedge *) NULL) { 00244 delete [] vedgelist; 00245 } 00246 if (vfacetlist != (vorofacet *) NULL) { 00247 for (i = 0; i < numberofvfacets; i++) { 00248 delete [] vfacetlist[i].elist; 00249 } 00250 delete [] vfacetlist; 00251 } 00252 if (vcelllist != (int **) NULL) { 00253 for (i = 0; i < numberofvcells; i++) { 00254 delete [] vcelllist[i]; 00255 } 00256 delete [] vcelllist; 00257 } 00258 } 00259 00261 // // 00262 // load_node_call() Load a list of nodes. // 00263 // // 00264 // It is a support routine for routines: 'load_nodes()', 'load_poly()', and // 00265 // 'load_tetmesh()'. 'infile' is the file handle contains the node list. It // 00266 // may point to a .node, or .poly or .smesh file. 'markers' indicates each // 00267 // node contains an additional marker (integer) or not. 'infilename' is the // 00268 // name of the file being read, it is only appeared in error message. // 00269 // // 00270 // The 'firstnumber' (0 or 1) is automatically determined by the number of // 00271 // the first index of the first point. // 00272 // // 00274 00275 bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename) 00276 { 00277 char inputline[INPUTLINESIZE]; 00278 char *stringptr; 00279 REAL x, y, z, attrib; 00280 int firstnode, currentmarker; 00281 int index, attribindex; 00282 int i, j; 00283 00284 // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'. 00285 pointlist = new REAL[numberofpoints * 3]; 00286 if (pointlist == (REAL *) NULL) { 00287 printf("Error: Out of memory.\n"); 00288 terminatetetgen(1); 00289 } 00290 if (numberofpointattributes > 0) { 00291 pointattributelist = new REAL[numberofpoints * numberofpointattributes]; 00292 if (pointattributelist == (REAL *) NULL) { 00293 printf("Error: Out of memory.\n"); 00294 terminatetetgen(1); 00295 } 00296 } 00297 if (markers) { 00298 pointmarkerlist = new int[numberofpoints]; 00299 if (pointmarkerlist == (int *) NULL) { 00300 printf("Error: Out of memory.\n"); 00301 terminatetetgen(1); 00302 } 00303 } 00304 00305 // Read the point section. 00306 index = 0; 00307 attribindex = 0; 00308 for (i = 0; i < numberofpoints; i++) { 00309 stringptr = readnumberline(inputline, infile, infilename); 00310 if (useindex) { 00311 if (i == 0) { 00312 firstnode = (int) strtol (stringptr, &stringptr, 0); 00313 if ((firstnode == 0) || (firstnode == 1)) { 00314 firstnumber = firstnode; 00315 } 00316 } 00317 stringptr = findnextnumber(stringptr); 00318 } // if (useindex) 00319 if (*stringptr == '\0') { 00320 printf("Error: Point %d has no x coordinate.\n", firstnumber + i); 00321 break; 00322 } 00323 x = (REAL) strtod(stringptr, &stringptr); 00324 stringptr = findnextnumber(stringptr); 00325 if (*stringptr == '\0') { 00326 printf("Error: Point %d has no y coordinate.\n", firstnumber + i); 00327 break; 00328 } 00329 y = (REAL) strtod(stringptr, &stringptr); 00330 if (mesh_dim == 3) { 00331 stringptr = findnextnumber(stringptr); 00332 if (*stringptr == '\0') { 00333 printf("Error: Point %d has no z coordinate.\n", firstnumber + i); 00334 break; 00335 } 00336 z = (REAL) strtod(stringptr, &stringptr); 00337 } else { 00338 z = 0.0; // mesh_dim == 2; 00339 } 00340 pointlist[index++] = x; 00341 pointlist[index++] = y; 00342 pointlist[index++] = z; 00343 // Read the point attributes. 00344 for (j = 0; j < numberofpointattributes; j++) { 00345 stringptr = findnextnumber(stringptr); 00346 if (*stringptr == '\0') { 00347 attrib = 0.0; 00348 } else { 00349 attrib = (REAL) strtod(stringptr, &stringptr); 00350 } 00351 pointattributelist[attribindex++] = attrib; 00352 } 00353 if (markers) { 00354 // Read a point marker. 00355 stringptr = findnextnumber(stringptr); 00356 if (*stringptr == '\0') { 00357 currentmarker = 0; 00358 } else { 00359 currentmarker = (int) strtol (stringptr, &stringptr, 0); 00360 } 00361 pointmarkerlist[i] = currentmarker; 00362 } 00363 } 00364 if (i < numberofpoints) { 00365 // Failed to read points due to some error. 00366 delete [] pointlist; 00367 pointlist = (REAL *) NULL; 00368 if (markers) { 00369 delete [] pointmarkerlist; 00370 pointmarkerlist = (int *) NULL; 00371 } 00372 if (numberofpointattributes > 0) { 00373 delete [] pointattributelist; 00374 pointattributelist = (REAL *) NULL; 00375 } 00376 numberofpoints = 0; 00377 return false; 00378 } 00379 return true; 00380 } 00381 00383 // // 00384 // load_node() Load a list of nodes from a .node file. // 00385 // // 00386 // 'filename' is the inputfile without suffix. The node list is in 'filename.// 00387 // node'. On completion, the node list is returned in 'pointlist'. // 00388 // // 00390 00391 bool tetgenio::load_node(char* filename) 00392 { 00393 FILE *infile; 00394 char innodefilename[FILENAMESIZE]; 00395 char inputline[INPUTLINESIZE]; 00396 char *stringptr; 00397 int markers; 00398 00399 markers = 0; 00400 // Assembling the actual file names we want to open. 00401 strcpy(innodefilename, filename); 00402 strcat(innodefilename, ".node"); 00403 00404 // Try to open a .node file. 00405 infile = fopen(innodefilename, "r"); 00406 if (infile == (FILE *) NULL) { 00407 printf("File I/O Error: Cannot access file %s.\n", innodefilename); 00408 return false; 00409 } 00410 printf("Opening %s.\n", innodefilename); 00411 // Read the first line of the file. 00412 stringptr = readnumberline(inputline, infile, innodefilename); 00413 // Is this list of points generated from rbox? 00414 stringptr = strstr(inputline, "rbox"); 00415 if (stringptr == NULL) { 00416 // Read number of points, number of dimensions, number of point 00417 // attributes, and number of boundary markers. 00418 stringptr = inputline; 00419 numberofpoints = (int) strtol (stringptr, &stringptr, 0); 00420 stringptr = findnextnumber(stringptr); 00421 if (*stringptr == '\0') { 00422 mesh_dim = 3; 00423 } else { 00424 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 00425 } 00426 stringptr = findnextnumber(stringptr); 00427 if (*stringptr == '\0') { 00428 numberofpointattributes = 0; 00429 } else { 00430 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); 00431 } 00432 stringptr = findnextnumber(stringptr); 00433 if (*stringptr == '\0') { 00434 markers = 0; 00435 } else { 00436 markers = (int) strtol (stringptr, &stringptr, 0); 00437 } 00438 } else { 00439 // It is a rbox (qhull) input file. 00440 stringptr = inputline; 00441 // Get the dimension. 00442 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 00443 // Get the number of points. 00444 stringptr = readnumberline(inputline, infile, innodefilename); 00445 numberofpoints = (int) strtol (stringptr, &stringptr, 0); 00446 // There is no index column. 00447 useindex = 0; 00448 } 00449 00450 // if ((mesh_dim != 3) && (mesh_dim != 2)) { 00451 // printf("Input error: TetGen only works for 2D & 3D point sets.\n"); 00452 // fclose(infile); 00453 // return false; 00454 // } 00455 if (numberofpoints < (mesh_dim + 1)) { 00456 printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1); 00457 fclose(infile); 00458 return false; 00459 } 00460 00461 // Load the list of nodes. 00462 if (!load_node_call(infile, markers, innodefilename)) { 00463 fclose(infile); 00464 return false; 00465 } 00466 fclose(infile); 00467 return true; 00468 } 00469 00471 // // 00472 // load_pbc() Load a list of pbc groups into 'pbcgrouplist'. // 00473 // // 00474 // 'filename' is the filename of the original inputfile without suffix. The // 00475 // pbc groups are found in file 'filename.pbc'. // 00476 // // 00477 // This routine will be called both in load_poly() and load_tetmesh(). // 00478 // // 00480 00481 bool tetgenio::load_pbc(char* filename) 00482 { 00483 FILE *infile; 00484 char pbcfilename[FILENAMESIZE]; 00485 char inputline[INPUTLINESIZE]; 00486 char *stringptr; 00487 pbcgroup *pg; 00488 int index, p1, p2; 00489 int i, j, k; 00490 00491 // Pbc groups are saved in file "filename.pbc". 00492 strcpy(pbcfilename, filename); 00493 strcat(pbcfilename, ".pbc"); 00494 infile = fopen(pbcfilename, "r"); 00495 if (infile != (FILE *) NULL) { 00496 printf("Opening %s.\n", pbcfilename); 00497 } else { 00498 // No such file. Return. 00499 return false; 00500 } 00501 00502 // Read the number of pbc groups. 00503 stringptr = readnumberline(inputline, infile, pbcfilename); 00504 numberofpbcgroups = (int) strtol (stringptr, &stringptr, 0); 00505 if (numberofpbcgroups == 0) { 00506 // It looks this file contains no point. 00507 fclose(infile); 00508 return false; 00509 } 00510 // Initialize 'pbcgrouplist'; 00511 pbcgrouplist = new pbcgroup[numberofpbcgroups]; 00512 00513 // Read the list of pbc groups. 00514 for (i = 0; i < numberofpbcgroups; i++) { 00515 pg = &(pbcgrouplist[i]); 00516 // Initialize pbcgroup i; 00517 pg->numberofpointpairs = 0; 00518 pg->pointpairlist = (int *) NULL; 00519 // Read 'fmark1', 'fmark2'. 00520 stringptr = readnumberline(inputline, infile, pbcfilename); 00521 if (*stringptr == '\0') break; 00522 pg->fmark1 = (int) strtol(stringptr, &stringptr, 0); 00523 stringptr = findnextnumber(stringptr); 00524 if (*stringptr == '\0') break; 00525 pg->fmark2 = (int) strtol(stringptr, &stringptr, 0); 00526 // Read 'transmat'. 00527 do { 00528 stringptr = readline(inputline, infile, NULL); 00529 } while ((*stringptr != '[') && (*stringptr != '\0')); 00530 if (*stringptr == '\0') break; 00531 for (j = 0; j < 4; j++) { 00532 for (k = 0; k < 4; k++) { 00533 // Read the entry of [j, k]. 00534 stringptr = findnextnumber(stringptr); 00535 if (*stringptr == '\0') { 00536 // Try to read another line. 00537 stringptr = readnumberline(inputline, infile, pbcfilename); 00538 if (*stringptr == '\0') break; 00539 } 00540 pg->transmat[j][k] = (REAL) strtod(stringptr, &stringptr); 00541 } 00542 if (k < 4) break; // Not complete! 00543 } 00544 if (j < 4) break; // Not complete! 00545 // Read 'numberofpointpairs'. 00546 stringptr = readnumberline(inputline, infile, pbcfilename); 00547 if (*stringptr == '\0') break; 00548 pg->numberofpointpairs = (int) strtol(stringptr, &stringptr, 0); 00549 if (pg->numberofpointpairs > 0) { 00550 pg->pointpairlist = new int[pg->numberofpointpairs * 2]; 00551 // Read the point pairs. 00552 index = 0; 00553 for (j = 0; j < pg->numberofpointpairs; j++) { 00554 stringptr = readnumberline(inputline, infile, pbcfilename); 00555 p1 = (int) strtol(stringptr, &stringptr, 0); 00556 stringptr = findnextnumber(stringptr); 00557 p2 = (int) strtol(stringptr, &stringptr, 0); 00558 pg->pointpairlist[index++] = p1; 00559 pg->pointpairlist[index++] = p2; 00560 } 00561 } 00562 } 00563 fclose(infile); 00564 00565 if (i < numberofpbcgroups) { 00566 // Failed to read to additional points due to some error. 00567 delete [] pbcgrouplist; 00568 pbcgrouplist = (pbcgroup *) NULL; 00569 numberofpbcgroups = 0; 00570 return false; 00571 } 00572 return true; 00573 } 00574 00576 // // 00577 // load_var() Load variant constraints applied on facets, segments, nodes.// 00578 // // 00579 // 'filename' is the filename of the original inputfile without suffix. The // 00580 // constraints are found in file 'filename.var'. // 00581 // // 00583 00584 bool tetgenio::load_var(char* filename) 00585 { 00586 FILE *infile; 00587 char varfilename[FILENAMESIZE]; 00588 char inputline[INPUTLINESIZE]; 00589 char *stringptr; 00590 int index; 00591 int i; 00592 00593 // Variant constraints are saved in file "filename.var". 00594 strcpy(varfilename, filename); 00595 strcat(varfilename, ".var"); 00596 infile = fopen(varfilename, "r"); 00597 if (infile != (FILE *) NULL) { 00598 printf("Opening %s.\n", varfilename); 00599 } else { 00600 // No such file. Return. 00601 return false; 00602 } 00603 00604 // Read the facet constraint section. 00605 stringptr = readnumberline(inputline, infile, varfilename); 00606 if (*stringptr != '\0') { 00607 numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0); 00608 } else { 00609 numberoffacetconstraints = 0; 00610 } 00611 if (numberoffacetconstraints > 0) { 00612 // Initialize 'facetconstraintlist'. 00613 facetconstraintlist = new REAL[numberoffacetconstraints * 2]; 00614 index = 0; 00615 for (i = 0; i < numberoffacetconstraints; i++) { 00616 stringptr = readnumberline(inputline, infile, varfilename); 00617 stringptr = findnextnumber(stringptr); 00618 if (*stringptr == '\0') { 00619 printf("Error: facet constraint %d has no facet marker.\n", 00620 firstnumber + i); 00621 break; 00622 } else { 00623 facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); 00624 } 00625 stringptr = findnextnumber(stringptr); 00626 if (*stringptr == '\0') { 00627 printf("Error: facet constraint %d has no maximum area bound.\n", 00628 firstnumber + i); 00629 break; 00630 } else { 00631 facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); 00632 } 00633 } 00634 if (i < numberoffacetconstraints) { 00635 // This must be caused by an error. 00636 fclose(infile); 00637 return false; 00638 } 00639 } 00640 00641 // Read the segment constraint section. 00642 stringptr = readnumberline(inputline, infile, varfilename); 00643 if (*stringptr != '\0') { 00644 numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0); 00645 } else { 00646 numberofsegmentconstraints = 0; 00647 } 00648 if (numberofsegmentconstraints > 0) { 00649 // Initialize 'segmentconstraintlist'. 00650 segmentconstraintlist = new REAL[numberofsegmentconstraints * 3]; 00651 index = 0; 00652 for (i = 0; i < numberofsegmentconstraints; i++) { 00653 stringptr = readnumberline(inputline, infile, varfilename); 00654 stringptr = findnextnumber(stringptr); 00655 if (*stringptr == '\0') { 00656 printf("Error: segment constraint %d has no frist endpoint.\n", 00657 firstnumber + i); 00658 break; 00659 } else { 00660 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); 00661 } 00662 stringptr = findnextnumber(stringptr); 00663 if (*stringptr == '\0') { 00664 printf("Error: segment constraint %d has no second endpoint.\n", 00665 firstnumber + i); 00666 break; 00667 } else { 00668 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); 00669 } 00670 stringptr = findnextnumber(stringptr); 00671 if (*stringptr == '\0') { 00672 printf("Error: segment constraint %d has no maximum length bound.\n", 00673 firstnumber + i); 00674 break; 00675 } else { 00676 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); 00677 } 00678 } 00679 if (i < numberofsegmentconstraints) { 00680 // This must be caused by an error. 00681 fclose(infile); 00682 return false; 00683 } 00684 } 00685 00686 fclose(infile); 00687 return true; 00688 } 00689 00691 // // 00692 // load_mtr() Load a size specification map from file. // 00693 // // 00694 // 'filename' is the filename of the original inputfile without suffix. The // 00695 // size map is found in file 'filename.mtr'. // 00696 // // 00698 00699 bool tetgenio::load_mtr(char* filename) 00700 { 00701 FILE *infile; 00702 char mtrfilename[FILENAMESIZE]; 00703 char inputline[INPUTLINESIZE]; 00704 char *stringptr; 00705 REAL mtr; 00706 int mtrindex; 00707 int i, j; 00708 00709 strcpy(mtrfilename, filename); 00710 strcat(mtrfilename, ".mtr"); 00711 infile = fopen(mtrfilename, "r"); 00712 if (infile != (FILE *) NULL) { 00713 printf("Opening %s.\n", mtrfilename); 00714 } else { 00715 // No such file. Return. 00716 return false; 00717 } 00718 00719 // Read number of points, number of columns (1, 3, or 6). 00720 stringptr = readnumberline(inputline, infile, mtrfilename); 00721 stringptr = findnextnumber(stringptr); // Skip number of points. 00722 if (*stringptr != '\0') { 00723 numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0); 00724 } 00725 if (numberofpointmtrs == 0) { 00726 // Column number doesn't match. Set a default number (1). 00727 numberofpointmtrs = 1; 00728 } 00729 00730 // Allocate space for pointmtrlist. 00731 pointmtrlist = new REAL[numberofpoints * numberofpointmtrs]; 00732 if (pointmtrlist == (REAL *) NULL) { 00733 printf("Error: Out of memory.\n"); 00734 terminatetetgen(1); 00735 } 00736 mtrindex = 0; 00737 for (i = 0; i < numberofpoints; i++) { 00738 // Read metrics. 00739 stringptr = readnumberline(inputline, infile, mtrfilename); 00740 for (j = 0; j < numberofpointmtrs; j++) { 00741 if (*stringptr == '\0') { 00742 printf("Error: Metric %d is missing value #%d in %s.\n", 00743 i + firstnumber, j + 1, mtrfilename); 00744 terminatetetgen(1); 00745 } 00746 mtr = (REAL) strtod(stringptr, &stringptr); 00747 pointmtrlist[mtrindex++] = mtr; 00748 stringptr = findnextnumber(stringptr); 00749 } 00750 } 00751 00752 fclose(infile); 00753 return true; 00754 } 00755 00757 // // 00758 // load_poly() Load a piecewise linear complex from a .poly or .smesh. // 00759 // // 00760 // 'filename' is the inputfile without suffix. The PLC is in 'filename.poly' // 00761 // or 'filename.smesh', and possibly plus 'filename.node' (when the first // 00762 // line of the file starts with a zero). // 00763 // // 00765 00766 bool tetgenio::load_poly(char* filename) 00767 { 00768 FILE *infile, *polyfile; 00769 char innodefilename[FILENAMESIZE]; 00770 char inpolyfilename[FILENAMESIZE]; 00771 char insmeshfilename[FILENAMESIZE]; 00772 char inputline[INPUTLINESIZE]; 00773 char *stringptr, *infilename; 00774 int smesh, markers, currentmarker; 00775 int readnodefile, index; 00776 int i, j, k; 00777 00778 // Assembling the actual file names we want to open. 00779 strcpy(innodefilename, filename); 00780 strcpy(inpolyfilename, filename); 00781 strcpy(insmeshfilename, filename); 00782 strcat(innodefilename, ".node"); 00783 strcat(inpolyfilename, ".poly"); 00784 strcat(insmeshfilename, ".smesh"); 00785 00786 // First assume it is a .poly file. 00787 smesh = 0; 00788 // Try to open a .poly file. 00789 polyfile = fopen(inpolyfilename, "r"); 00790 if (polyfile == (FILE *) NULL) { 00791 // .poly doesn't exist! Try to open a .smesh file. 00792 polyfile = fopen(insmeshfilename, "r"); 00793 if (polyfile == (FILE *) NULL) { 00794 printf("File I/O Error: Cannot access file %s and %s.\n", 00795 inpolyfilename, insmeshfilename); 00796 return false; 00797 } else { 00798 printf("Opening %s.\n", insmeshfilename); 00799 } 00800 smesh = 1; 00801 } else { 00802 printf("Opening %s.\n", inpolyfilename); 00803 } 00804 // Initialize the default values. 00805 mesh_dim = 3; // Three-dimemsional accoordinates. 00806 numberofpointattributes = 0; // no point attribute. 00807 markers = 0; // no boundary marker. 00808 // Read number of points, number of dimensions, number of point 00809 // attributes, and number of boundary markers. 00810 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 00811 numberofpoints = (int) strtol (stringptr, &stringptr, 0); 00812 stringptr = findnextnumber(stringptr); 00813 if (*stringptr != '\0') { 00814 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 00815 } 00816 stringptr = findnextnumber(stringptr); 00817 if (*stringptr != '\0') { 00818 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); 00819 } 00820 stringptr = findnextnumber(stringptr); 00821 if (*stringptr != '\0') { 00822 markers = (int) strtol (stringptr, &stringptr, 0); 00823 } 00824 if (numberofpoints > 0) { 00825 readnodefile = 0; 00826 if (smesh) { 00827 infilename = insmeshfilename; 00828 } else { 00829 infilename = inpolyfilename; 00830 } 00831 infile = polyfile; 00832 } else { 00833 // If the .poly or .smesh file claims there are zero points, that 00834 // means the points should be read from a separate .node file. 00835 readnodefile = 1; 00836 infilename = innodefilename; 00837 } 00838 00839 if (readnodefile) { 00840 // Read the points from the .node file. 00841 printf("Opening %s.\n", innodefilename); 00842 infile = fopen(innodefilename, "r"); 00843 if (infile == (FILE *) NULL) { 00844 printf("File I/O Error: Cannot access file %s.\n", innodefilename); 00845 return false; 00846 } 00847 // Initialize the default values. 00848 mesh_dim = 3; // Three-dimemsional accoordinates. 00849 numberofpointattributes = 0; // no point attribute. 00850 markers = 0; // no boundary marker. 00851 // Read number of points, number of dimensions, number of point 00852 // attributes, and number of boundary markers. 00853 stringptr = readnumberline(inputline, infile, innodefilename); 00854 numberofpoints = (int) strtol (stringptr, &stringptr, 0); 00855 stringptr = findnextnumber(stringptr); 00856 if (*stringptr != '\0') { 00857 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 00858 } 00859 stringptr = findnextnumber(stringptr); 00860 if (*stringptr != '\0') { 00861 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); 00862 } 00863 stringptr = findnextnumber(stringptr); 00864 if (*stringptr != '\0') { 00865 markers = (int) strtol (stringptr, &stringptr, 0); 00866 } 00867 } 00868 00869 if ((mesh_dim != 3) && (mesh_dim != 2)) { 00870 printf("Input error: TetGen only works for 2D & 3D point sets.\n"); 00871 fclose(infile); 00872 return false; 00873 } 00874 if (numberofpoints < (mesh_dim + 1)) { 00875 printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1); 00876 fclose(infile); 00877 return false; 00878 } 00879 00880 // Load the list of nodes. 00881 if (!load_node_call(infile, markers, infilename)) { 00882 fclose(infile); 00883 return false; 00884 } 00885 00886 if (readnodefile) { 00887 fclose(infile); 00888 } 00889 00890 facet *f; 00891 polygon *p; 00892 00893 if (mesh_dim == 3) { 00894 00895 // Read number of facets and number of boundary markers. 00896 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 00897 numberoffacets = (int) strtol (stringptr, &stringptr, 0); 00898 if (numberoffacets <= 0) { 00899 // No facet list, return. 00900 fclose(polyfile); 00901 return true; 00902 } 00903 stringptr = findnextnumber(stringptr); 00904 if (*stringptr == '\0') { 00905 markers = 0; // no boundary marker. 00906 } else { 00907 markers = (int) strtol (stringptr, &stringptr, 0); 00908 } 00909 00910 // Initialize the 'facetlist', 'facetmarkerlist'. 00911 facetlist = new facet[numberoffacets]; 00912 if (markers == 1) { 00913 facetmarkerlist = new int[numberoffacets]; 00914 } 00915 00916 // Read data into 'facetlist', 'facetmarkerlist'. 00917 if (smesh == 0) { 00918 // Facets are in .poly file format. 00919 for (i = 1; i <= numberoffacets; i++) { 00920 f = &(facetlist[i - 1]); 00921 init(f); 00922 f->numberofholes = 0; 00923 currentmarker = 0; 00924 // Read number of polygons, number of holes, and a boundary marker. 00925 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 00926 f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0); 00927 stringptr = findnextnumber(stringptr); 00928 if (*stringptr != '\0') { 00929 f->numberofholes = (int) strtol (stringptr, &stringptr, 0); 00930 if (markers == 1) { 00931 stringptr = findnextnumber(stringptr); 00932 if (*stringptr != '\0') { 00933 currentmarker = (int) strtol(stringptr, &stringptr, 0); 00934 } 00935 } 00936 } 00937 // Initialize facetmarker if it needs. 00938 if (markers == 1) { 00939 facetmarkerlist[i - 1] = currentmarker; 00940 } 00941 // Each facet should has at least one polygon. 00942 if (f->numberofpolygons <= 0) { 00943 printf("Error: Wrong number of polygon in %d facet.\n", i); 00944 break; 00945 } 00946 // Initialize the 'f->polygonlist'. 00947 f->polygonlist = new polygon[f->numberofpolygons]; 00948 // Go through all polygons, read in their vertices. 00949 for (j = 1; j <= f->numberofpolygons; j++) { 00950 p = &(f->polygonlist[j - 1]); 00951 init(p); 00952 // Read number of vertices of this polygon. 00953 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 00954 p->numberofvertices = (int) strtol(stringptr, &stringptr, 0); 00955 if (p->numberofvertices < 1) { 00956 printf("Error: Wrong polygon %d in facet %d\n", j, i); 00957 break; 00958 } 00959 // Initialize 'p->vertexlist'. 00960 p->vertexlist = new int[p->numberofvertices]; 00961 // Read all vertices of this polygon. 00962 for (k = 1; k <= p->numberofvertices; k++) { 00963 stringptr = findnextnumber(stringptr); 00964 if (*stringptr == '\0') { 00965 // Try to load another non-empty line and continue to read the 00966 // rest of vertices. 00967 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 00968 if (*stringptr == '\0') { 00969 printf("Error: Missing %d endpoints of polygon %d in facet %d", 00970 p->numberofvertices - k, j, i); 00971 break; 00972 } 00973 } 00974 p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0); 00975 } 00976 } 00977 if (j <= f->numberofpolygons) { 00978 // This must be caused by an error. However, there're j - 1 00979 // polygons have been read. Reset the 'f->numberofpolygon'. 00980 if (j == 1) { 00981 // This is the first polygon. 00982 delete [] f->polygonlist; 00983 } 00984 f->numberofpolygons = j - 1; 00985 // No hole will be read even it exists. 00986 f->numberofholes = 0; 00987 break; 00988 } 00989 // If this facet has hole pints defined, read them. 00990 if (f->numberofholes > 0) { 00991 // Initialize 'f->holelist'. 00992 f->holelist = new REAL[f->numberofholes * 3]; 00993 // Read the holes' coordinates. 00994 index = 0; 00995 for (j = 1; j <= f->numberofholes; j++) { 00996 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 00997 for (k = 1; k <= 3; k++) { 00998 stringptr = findnextnumber(stringptr); 00999 if (*stringptr == '\0') { 01000 printf("Error: Hole %d in facet %d has no coordinates", j, i); 01001 break; 01002 } 01003 f->holelist[index++] = (REAL) strtod (stringptr, &stringptr); 01004 } 01005 if (k <= 3) { 01006 // This must be caused by an error. 01007 break; 01008 } 01009 } 01010 if (j <= f->numberofholes) { 01011 // This must be caused by an error. 01012 break; 01013 } 01014 } 01015 } 01016 if (i <= numberoffacets) { 01017 // This must be caused by an error. 01018 numberoffacets = i - 1; 01019 fclose(polyfile); 01020 return false; 01021 } 01022 } else { // poly == 0 01023 // Read the facets from a .smesh file. 01024 for (i = 1; i <= numberoffacets; i++) { 01025 f = &(facetlist[i - 1]); 01026 init(f); 01027 // Initialize 'f->facetlist'. In a .smesh file, each facetlist only 01028 // contains exactly one polygon, no hole. 01029 f->numberofpolygons = 1; 01030 f->polygonlist = new polygon[f->numberofpolygons]; 01031 p = &(f->polygonlist[0]); 01032 init(p); 01033 // Read number of vertices of this polygon. 01034 stringptr = readnumberline(inputline, polyfile, insmeshfilename); 01035 p->numberofvertices = (int) strtol (stringptr, &stringptr, 0); 01036 if (p->numberofvertices < 1) { 01037 printf("Error: Wrong number of vertex in facet %d\n", i); 01038 break; 01039 } 01040 // Initialize 'p->vertexlist'. 01041 p->vertexlist = new int[p->numberofvertices]; 01042 for (k = 1; k <= p->numberofvertices; k++) { 01043 stringptr = findnextnumber(stringptr); 01044 if (*stringptr == '\0') { 01045 // Try to load another non-empty line and continue to read the 01046 // rest of vertices. 01047 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01048 if (*stringptr == '\0') { 01049 printf("Error: Missing %d endpoints in facet %d", 01050 p->numberofvertices - k, i); 01051 break; 01052 } 01053 } 01054 p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0); 01055 } 01056 if (k <= p->numberofvertices) { 01057 // This must be caused by an error. 01058 break; 01059 } 01060 // Read facet's boundary marker at last. 01061 if (markers == 1) { 01062 stringptr = findnextnumber(stringptr); 01063 if (*stringptr == '\0') { 01064 currentmarker = 0; 01065 } else { 01066 currentmarker = (int) strtol(stringptr, &stringptr, 0); 01067 } 01068 facetmarkerlist[i - 1] = currentmarker; 01069 } 01070 } 01071 if (i <= numberoffacets) { 01072 // This must be caused by an error. 01073 numberoffacets = i - 1; 01074 fclose(polyfile); 01075 return false; 01076 } 01077 } 01078 01079 // Read the hole section. 01080 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01081 if (*stringptr != '\0') { 01082 numberofholes = (int) strtol (stringptr, &stringptr, 0); 01083 } else { 01084 numberofholes = 0; 01085 } 01086 if (numberofholes > 0) { 01087 // Initialize 'holelist'. 01088 holelist = new REAL[numberofholes * 3]; 01089 for (i = 0; i < 3 * numberofholes; i += 3) { 01090 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01091 stringptr = findnextnumber(stringptr); 01092 if (*stringptr == '\0') { 01093 printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3)); 01094 break; 01095 } else { 01096 holelist[i] = (REAL) strtod(stringptr, &stringptr); 01097 } 01098 stringptr = findnextnumber(stringptr); 01099 if (*stringptr == '\0') { 01100 printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3)); 01101 break; 01102 } else { 01103 holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); 01104 } 01105 stringptr = findnextnumber(stringptr); 01106 if (*stringptr == '\0') { 01107 printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3)); 01108 break; 01109 } else { 01110 holelist[i + 2] = (REAL) strtod(stringptr, &stringptr); 01111 } 01112 } 01113 if (i < 3 * numberofholes) { 01114 // This must be caused by an error. 01115 fclose(polyfile); 01116 return false; 01117 } 01118 } 01119 01120 // Read the region section. The 'region' section is optional, if we 01121 // don't reach the end-of-file, try read it in. 01122 stringptr = readnumberline(inputline, polyfile, NULL); 01123 if (stringptr != (char *) NULL && *stringptr != '\0') { 01124 numberofregions = (int) strtol (stringptr, &stringptr, 0); 01125 } else { 01126 numberofregions = 0; 01127 } 01128 if (numberofregions > 0) { 01129 // Initialize 'regionlist'. 01130 regionlist = new REAL[numberofregions * 5]; 01131 index = 0; 01132 for (i = 0; i < numberofregions; i++) { 01133 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01134 stringptr = findnextnumber(stringptr); 01135 if (*stringptr == '\0') { 01136 printf("Error: Region %d has no x coordinate.\n", firstnumber + i); 01137 break; 01138 } else { 01139 regionlist[index++] = (REAL) strtod(stringptr, &stringptr); 01140 } 01141 stringptr = findnextnumber(stringptr); 01142 if (*stringptr == '\0') { 01143 printf("Error: Region %d has no y coordinate.\n", firstnumber + i); 01144 break; 01145 } else { 01146 regionlist[index++] = (REAL) strtod(stringptr, &stringptr); 01147 } 01148 stringptr = findnextnumber(stringptr); 01149 if (*stringptr == '\0') { 01150 printf("Error: Region %d has no z coordinate.\n", firstnumber + i); 01151 break; 01152 } else { 01153 regionlist[index++] = (REAL) strtod(stringptr, &stringptr); 01154 } 01155 stringptr = findnextnumber(stringptr); 01156 if (*stringptr == '\0') { 01157 printf("Error: Region %d has no region attrib.\n", firstnumber + i); 01158 break; 01159 } else { 01160 regionlist[index++] = (REAL) strtod(stringptr, &stringptr); 01161 } 01162 stringptr = findnextnumber(stringptr); 01163 if (*stringptr == '\0') { 01164 regionlist[index] = regionlist[index - 1]; 01165 } else { 01166 regionlist[index] = (REAL) strtod(stringptr, &stringptr); 01167 } 01168 index++; 01169 } 01170 if (i < numberofregions) { 01171 // This must be caused by an error. 01172 fclose(polyfile); 01173 return false; 01174 } 01175 } 01176 01177 } else { 01178 01179 // Read a PSLG from Triangle's poly file. 01180 assert(mesh_dim == 2); 01181 // A PSLG is a facet of a PLC. 01182 numberoffacets = 1; 01183 // Initialize the 'facetlist'. 01184 facetlist = new facet[numberoffacets]; 01185 facetmarkerlist = (int *) NULL; // No facet markers. 01186 f = &(facetlist[0]); 01187 init(f); 01188 // Read number of segments. 01189 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01190 // Segments are degenerate polygons. 01191 f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0); 01192 if (f->numberofpolygons > 0) { 01193 f->polygonlist = new polygon[f->numberofpolygons]; 01194 } 01195 // Go through all segments, read in their vertices. 01196 for (j = 0; j < f->numberofpolygons; j++) { 01197 p = &(f->polygonlist[j]); 01198 init(p); 01199 // Read in a segment. 01200 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01201 stringptr = findnextnumber(stringptr); // Skip its index. 01202 p->numberofvertices = 2; // A segment always has two vertices. 01203 p->vertexlist = new int[p->numberofvertices]; 01204 p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0); 01205 stringptr = findnextnumber(stringptr); 01206 p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0); 01207 } 01208 // Read number of holes. 01209 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01210 f->numberofholes = (int) strtol (stringptr, &stringptr, 0); 01211 if (f->numberofholes > 0) { 01212 // Initialize 'f->holelist'. 01213 f->holelist = new REAL[f->numberofholes * 3]; 01214 // Read the holes' coordinates. 01215 for (j = 0; j < f->numberofholes; j++) { 01216 // Read a 2D hole point. 01217 stringptr = readnumberline(inputline, polyfile, inpolyfilename); 01218 stringptr = findnextnumber(stringptr); // Skip its index. 01219 f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr); 01220 stringptr = findnextnumber(stringptr); 01221 f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr); 01222 f->holelist[j * 3 + 2] = 0.0; // The z-coord. 01223 } 01224 } 01225 // The regions are skipped. 01226 01227 } 01228 01229 // End of reading poly/smesh file. 01230 fclose(polyfile); 01231 01232 // Try to load a .var file if it exists. 01233 load_var(filename); 01234 // Try to load a .mtr file if it exists. 01235 load_mtr(filename); 01236 // Try to read a .pbc file if it exists. 01237 load_pbc(filename); 01238 01239 return true; 01240 } 01241 01243 // // 01244 // load_off() Load a polyhedron described in a .off file. // 01245 // // 01246 // The .off format is one of file formats of the Geomview, an interactive // 01247 // program for viewing and manipulating geometric objects. More information // 01248 // is available form: http://www.geomview.org. // 01249 // // 01250 // 'filename' is a input filename with extension .off or without extension ( // 01251 // the .off will be added in this case). On completion, the polyhedron is // 01252 // returned in 'pointlist' and 'facetlist'. // 01253 // // 01255 01256 bool tetgenio::load_off(char* filename) 01257 { 01258 FILE *fp; 01259 tetgenio::facet *f; 01260 tetgenio::polygon *p; 01261 char infilename[FILENAMESIZE]; 01262 char buffer[INPUTLINESIZE]; 01263 char *bufferp; 01264 double *coord; 01265 int nverts = 0, iverts = 0; 01266 int nfaces = 0, ifaces = 0; 01267 int nedges = 0; 01268 int line_count = 0, i; 01269 01270 strncpy(infilename, filename, 1024 - 1); 01271 infilename[FILENAMESIZE - 1] = '\0'; 01272 if (infilename[0] == '\0') { 01273 printf("Error: No filename.\n"); 01274 return false; 01275 } 01276 if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) { 01277 strcat(infilename, ".off"); 01278 } 01279 01280 if (!(fp = fopen(infilename, "r"))) { 01281 printf("File I/O Error: Unable to open file %s\n", infilename); 01282 return false; 01283 } 01284 printf("Opening %s.\n", infilename); 01285 01286 // OFF requires the index starts from '0'. 01287 firstnumber = 0; 01288 01289 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { 01290 // Check section 01291 if (nverts == 0) { 01292 // Read header 01293 bufferp = strstr(bufferp, "OFF"); 01294 if (bufferp != NULL) { 01295 // Read mesh counts 01296 bufferp = findnextnumber(bufferp); // Skip field "OFF". 01297 if (*bufferp == '\0') { 01298 // Read a non-empty line. 01299 bufferp = readline(buffer, fp, &line_count); 01300 } 01301 if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3) 01302 || (nverts == 0)) { 01303 printf("Syntax error reading header on line %d in file %s\n", 01304 line_count, infilename); 01305 fclose(fp); 01306 return false; 01307 } 01308 // Allocate memory for 'tetgenio' 01309 if (nverts > 0) { 01310 numberofpoints = nverts; 01311 pointlist = new REAL[nverts * 3]; 01312 } 01313 if (nfaces > 0) { 01314 numberoffacets = nfaces; 01315 facetlist = new tetgenio::facet[nfaces]; 01316 } 01317 } 01318 } else if (iverts < nverts) { 01319 // Read vertex coordinates 01320 coord = &pointlist[iverts * 3]; 01321 for (i = 0; i < 3; i++) { 01322 if (*bufferp == '\0') { 01323 printf("Syntax error reading vertex coords on line %d in file %s\n", 01324 line_count, infilename); 01325 fclose(fp); 01326 return false; 01327 } 01328 coord[i] = (REAL) strtod(bufferp, &bufferp); 01329 bufferp = findnextnumber(bufferp); 01330 } 01331 iverts++; 01332 } else if (ifaces < nfaces) { 01333 // Get next face 01334 f = &facetlist[ifaces]; 01335 init(f); 01336 // In .off format, each facet has one polygon, no hole. 01337 f->numberofpolygons = 1; 01338 f->polygonlist = new tetgenio::polygon[1]; 01339 p = &f->polygonlist[0]; 01340 init(p); 01341 // Read the number of vertices, it should be greater than 0. 01342 p->numberofvertices = (int) strtol(bufferp, &bufferp, 0); 01343 if (p->numberofvertices == 0) { 01344 printf("Syntax error reading polygon on line %d in file %s\n", 01345 line_count, infilename); 01346 fclose(fp); 01347 return false; 01348 } 01349 // Allocate memory for face vertices 01350 p->vertexlist = new int[p->numberofvertices]; 01351 for (i = 0; i < p->numberofvertices; i++) { 01352 bufferp = findnextnumber(bufferp); 01353 if (*bufferp == '\0') { 01354 printf("Syntax error reading polygon on line %d in file %s\n", 01355 line_count, infilename); 01356 fclose(fp); 01357 return false; 01358 } 01359 p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0); 01360 } 01361 ifaces++; 01362 } else { 01363 // Should never get here 01364 printf("Found extra text starting at line %d in file %s\n", line_count, 01365 infilename); 01366 break; 01367 } 01368 } 01369 01370 // Close file 01371 fclose(fp); 01372 01373 // Check whether read all points 01374 if (iverts != nverts) { 01375 printf("Expected %d vertices, but read only %d vertices in file %s\n", 01376 nverts, iverts, infilename); 01377 return false; 01378 } 01379 01380 // Check whether read all faces 01381 if (ifaces != nfaces) { 01382 printf("Expected %d faces, but read only %d faces in file %s\n", 01383 nfaces, ifaces, infilename); 01384 return false; 01385 } 01386 01387 return true; 01388 } 01389 01391 // // 01392 // load_ply() Load a polyhedron described in a .ply file. // 01393 // // 01394 // 'filename' is the file name with extension .ply or without extension (the // 01395 // .ply will be added in this case). // 01396 // // 01397 // This is a simplified version of reading .ply files, which only reads the // 01398 // set of vertices and the set of faces. Other informations (such as color, // 01399 // material, texture, etc) in .ply file are ignored. Complete routines for // 01400 // reading and writing ,ply files are available from: http://www.cc.gatech. // 01401 // edu/projects/large_models/ply.html. Except the header section, ply file // 01402 // format has exactly the same format for listing vertices and polygons as // 01403 // off file format. // 01404 // // 01405 // On completion, 'pointlist' and 'facetlist' together return the polyhedron.// 01406 // // 01408 01409 bool tetgenio::load_ply(char* filename) 01410 { 01411 FILE *fp; 01412 tetgenio::facet *f; 01413 tetgenio::polygon *p; 01414 char infilename[FILENAMESIZE]; 01415 char buffer[INPUTLINESIZE]; 01416 char *bufferp, *str; 01417 double *coord; 01418 int endheader = 0, format = 0; 01419 int nverts = 0, iverts = 0; 01420 int nfaces = 0, ifaces = 0; 01421 int line_count = 0, i; 01422 01423 strncpy(infilename, filename, FILENAMESIZE - 1); 01424 infilename[FILENAMESIZE - 1] = '\0'; 01425 if (infilename[0] == '\0') { 01426 printf("Error: No filename.\n"); 01427 return false; 01428 } 01429 if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) { 01430 strcat(infilename, ".ply"); 01431 } 01432 01433 if (!(fp = fopen(infilename, "r"))) { 01434 printf("Error: Unable to open file %s\n", infilename); 01435 return false; 01436 } 01437 printf("Opening %s.\n", infilename); 01438 01439 // PLY requires the index starts from '0'. 01440 firstnumber = 0; 01441 01442 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { 01443 if (!endheader) { 01444 // Find if it is the keyword "end_header". 01445 str = strstr(bufferp, "end_header"); 01446 // strstr() is case sensitive. 01447 if (!str) str = strstr(bufferp, "End_header"); 01448 if (!str) str = strstr(bufferp, "End_Header"); 01449 if (str) { 01450 // This is the end of the header section. 01451 endheader = 1; 01452 continue; 01453 } 01454 // Parse the number of vertices and the number of faces. 01455 if (nverts == 0 || nfaces == 0) { 01456 // Find if it si the keyword "element". 01457 str = strstr(bufferp, "element"); 01458 if (!str) str = strstr(bufferp, "Element"); 01459 if (str) { 01460 bufferp = findnextfield(str); 01461 if (*bufferp == '\0') { 01462 printf("Syntax error reading element type on line%d in file %s\n", 01463 line_count, infilename); 01464 fclose(fp); 01465 return false; 01466 } 01467 if (nverts == 0) { 01468 // Find if it is the keyword "vertex". 01469 str = strstr(bufferp, "vertex"); 01470 if (!str) str = strstr(bufferp, "Vertex"); 01471 if (str) { 01472 bufferp = findnextnumber(str); 01473 if (*bufferp == '\0') { 01474 printf("Syntax error reading vertex number on line"); 01475 printf(" %d in file %s\n", line_count, infilename); 01476 fclose(fp); 01477 return false; 01478 } 01479 nverts = (int) strtol(bufferp, &bufferp, 0); 01480 // Allocate memory for 'tetgenio' 01481 if (nverts > 0) { 01482 numberofpoints = nverts; 01483 pointlist = new REAL[nverts * 3]; 01484 } 01485 } 01486 } 01487 if (nfaces == 0) { 01488 // Find if it is the keyword "face". 01489 str = strstr(bufferp, "face"); 01490 if (!str) str = strstr(bufferp, "Face"); 01491 if (str) { 01492 bufferp = findnextnumber(str); 01493 if (*bufferp == '\0') { 01494 printf("Syntax error reading face number on line"); 01495 printf(" %d in file %s\n", line_count, infilename); 01496 fclose(fp); 01497 return false; 01498 } 01499 nfaces = (int) strtol(bufferp, &bufferp, 0); 01500 // Allocate memory for 'tetgenio' 01501 if (nfaces > 0) { 01502 numberoffacets = nfaces; 01503 facetlist = new tetgenio::facet[nfaces]; 01504 } 01505 } 01506 } 01507 } // It is not the string "element". 01508 } 01509 if (format == 0) { 01510 // Find the keyword "format". 01511 str = strstr(bufferp, "format"); 01512 if (!str) str = strstr(bufferp, "Format"); 01513 if (str) { 01514 format = 1; 01515 bufferp = findnextfield(str); 01516 // Find if it is the string "ascii". 01517 str = strstr(bufferp, "ascii"); 01518 if (!str) str = strstr(bufferp, "ASCII"); 01519 if (!str) { 01520 printf("This routine only reads ascii format of ply files.\n"); 01521 printf("Hint: You can convert the binary to ascii format by\n"); 01522 printf(" using the provided ply tools:\n"); 01523 printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename); 01524 fclose(fp); 01525 return false; 01526 } 01527 } 01528 } 01529 } else if (iverts < nverts) { 01530 // Read vertex coordinates 01531 coord = &pointlist[iverts * 3]; 01532 for (i = 0; i < 3; i++) { 01533 if (*bufferp == '\0') { 01534 printf("Syntax error reading vertex coords on line %d in file %s\n", 01535 line_count, infilename); 01536 fclose(fp); 01537 return false; 01538 } 01539 coord[i] = (REAL) strtod(bufferp, &bufferp); 01540 bufferp = findnextnumber(bufferp); 01541 } 01542 iverts++; 01543 } else if (ifaces < nfaces) { 01544 // Get next face 01545 f = &facetlist[ifaces]; 01546 init(f); 01547 // In .off format, each facet has one polygon, no hole. 01548 f->numberofpolygons = 1; 01549 f->polygonlist = new tetgenio::polygon[1]; 01550 p = &f->polygonlist[0]; 01551 init(p); 01552 // Read the number of vertices, it should be greater than 0. 01553 p->numberofvertices = (int) strtol(bufferp, &bufferp, 0); 01554 if (p->numberofvertices == 0) { 01555 printf("Syntax error reading polygon on line %d in file %s\n", 01556 line_count, infilename); 01557 fclose(fp); 01558 return false; 01559 } 01560 // Allocate memory for face vertices 01561 p->vertexlist = new int[p->numberofvertices]; 01562 for (i = 0; i < p->numberofvertices; i++) { 01563 bufferp = findnextnumber(bufferp); 01564 if (*bufferp == '\0') { 01565 printf("Syntax error reading polygon on line %d in file %s\n", 01566 line_count, infilename); 01567 fclose(fp); 01568 return false; 01569 } 01570 p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0); 01571 } 01572 ifaces++; 01573 } else { 01574 // Should never get here 01575 printf("Found extra text starting at line %d in file %s\n", line_count, 01576 infilename); 01577 break; 01578 } 01579 } 01580 01581 // Close file 01582 fclose(fp); 01583 01584 // Check whether read all points 01585 if (iverts != nverts) { 01586 printf("Expected %d vertices, but read only %d vertices in file %s\n", 01587 nverts, iverts, infilename); 01588 return false; 01589 } 01590 01591 // Check whether read all faces 01592 if (ifaces != nfaces) { 01593 printf("Expected %d faces, but read only %d faces in file %s\n", 01594 nfaces, ifaces, infilename); 01595 return false; 01596 } 01597 01598 return true; 01599 } 01600 01602 // // 01603 // load_stl() Load a surface mesh described in a .stl file. // 01604 // // 01605 // 'filename' is the file name with extension .stl or without extension (the // 01606 // .stl will be added in this case). // 01607 // // 01608 // The .stl or stereolithography format is an ASCII or binary file used in // 01609 // manufacturing. It is a list of the triangular surfaces that describe a // 01610 // computer generated solid model. This is the standard input for most rapid // 01611 // prototyping machines. // 01612 // // 01613 // On completion, 'pointlist' and 'facetlist' together return the polyhedron.// 01614 // Note: After load_stl(), there exist many duplicated points in 'pointlist'.// 01615 // They will be unified during the Delaunay tetrahedralization process. // 01616 // // 01618 01619 bool tetgenio::load_stl(char* filename) 01620 { 01621 FILE *fp; 01622 tetgenmesh::list *plist; 01623 tetgenio::facet *f; 01624 tetgenio::polygon *p; 01625 char infilename[FILENAMESIZE]; 01626 char buffer[INPUTLINESIZE]; 01627 char *bufferp, *str; 01628 double *coord; 01629 int solid = 0; 01630 int nverts = 0, iverts = 0; 01631 int nfaces = 0; 01632 int line_count = 0, i; 01633 01634 strncpy(infilename, filename, FILENAMESIZE - 1); 01635 infilename[FILENAMESIZE - 1] = '\0'; 01636 if (infilename[0] == '\0') { 01637 printf("Error: No filename.\n"); 01638 return false; 01639 } 01640 if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) { 01641 strcat(infilename, ".stl"); 01642 } 01643 01644 if (!(fp = fopen(infilename, "r"))) { 01645 printf("Error: Unable to open file %s\n", infilename); 01646 return false; 01647 } 01648 printf("Opening %s.\n", infilename); 01649 01650 // STL file has no number of points available. Use a list to read points. 01651 plist = new tetgenmesh::list(sizeof(double) * 3, NULL, 1024); 01652 01653 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { 01654 // The ASCII .stl file must start with the lower case keyword solid and 01655 // end with endsolid. 01656 if (solid == 0) { 01657 // Read header 01658 bufferp = strstr(bufferp, "solid"); 01659 if (bufferp != NULL) { 01660 solid = 1; 01661 } 01662 } else { 01663 // We're inside the block of the solid. 01664 str = bufferp; 01665 // Is this the end of the solid. 01666 bufferp = strstr(bufferp, "endsolid"); 01667 if (bufferp != NULL) { 01668 solid = 0; 01669 } else { 01670 // Read the XYZ coordinates if it is a vertex. 01671 bufferp = str; 01672 bufferp = strstr(bufferp, "vertex"); 01673 if (bufferp != NULL) { 01674 coord = (double *) plist->append(NULL); 01675 for (i = 0; i < 3; i++) { 01676 bufferp = findnextnumber(bufferp); 01677 if (*bufferp == '\0') { 01678 printf("Syntax error reading vertex coords on line %d\n", 01679 line_count); 01680 delete plist; 01681 fclose(fp); 01682 return false; 01683 } 01684 coord[i] = (REAL) strtod(bufferp, &bufferp); 01685 } 01686 } 01687 } 01688 } 01689 } 01690 fclose(fp); 01691 01692 nverts = plist->len(); 01693 // nverts should be an integer times 3 (every 3 vertices denote a face). 01694 if (nverts == 0 || (nverts % 3 != 0)) { 01695 printf("Error: Wrong number of vertices in file %s.\n", infilename); 01696 delete plist; 01697 return false; 01698 } 01699 numberofpoints = nverts; 01700 pointlist = new REAL[nverts * 3]; 01701 for (i = 0; i < nverts; i++) { 01702 coord = (double *) (* plist)[i]; 01703 iverts = i * 3; 01704 pointlist[iverts] = (REAL) coord[0]; 01705 pointlist[iverts + 1] = (REAL) coord[1]; 01706 pointlist[iverts + 2] = (REAL) coord[2]; 01707 } 01708 01709 nfaces = (int) (nverts / 3); 01710 numberoffacets = nfaces; 01711 facetlist = new tetgenio::facet[nfaces]; 01712 01713 // Default use '1' as the array starting index. 01714 firstnumber = 1; 01715 iverts = firstnumber; 01716 for (i = 0; i < nfaces; i++) { 01717 f = &facetlist[i]; 01718 init(f); 01719 // In .stl format, each facet has one polygon, no hole. 01720 f->numberofpolygons = 1; 01721 f->polygonlist = new tetgenio::polygon[1]; 01722 p = &f->polygonlist[0]; 01723 init(p); 01724 // Each polygon has three vertices. 01725 p->numberofvertices = 3; 01726 p->vertexlist = new int[p->numberofvertices]; 01727 p->vertexlist[0] = iverts; 01728 p->vertexlist[1] = iverts + 1; 01729 p->vertexlist[2] = iverts + 2; 01730 iverts += 3; 01731 } 01732 01733 delete plist; 01734 return true; 01735 } 01736 01738 // // 01739 // load_medit() Load a surface mesh described in .mesh file. // 01740 // // 01741 // 'filename' is the file name with extension .mesh or without entension ( // 01742 // the .mesh will be added in this case). .mesh is the file format of Medit, // 01743 // a user-friendly interactive mesh viewing program. // 01744 // // 01745 // This routine ONLY reads the sections containing vertices, triangles, and // 01746 // quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.// 01747 // // 01749 01750 bool tetgenio::load_medit(char* filename) 01751 { 01752 FILE *fp; 01753 tetgenio::facet *tmpflist, *f; 01754 tetgenio::polygon *p; 01755 char infilename[FILENAMESIZE]; 01756 char buffer[INPUTLINESIZE]; 01757 char *bufferp, *str; 01758 double *coord; 01759 int *tmpfmlist; 01760 int dimension = 0; 01761 int nverts = 0; 01762 int nfaces = 0; 01763 int line_count = 0; 01764 int corners = 0; // 3 (triangle) or 4 (quad). 01765 int i, j; 01766 01767 strncpy(infilename, filename, FILENAMESIZE - 1); 01768 infilename[FILENAMESIZE - 1] = '\0'; 01769 if (infilename[0] == '\0') { 01770 printf("Error: No filename.\n"); 01771 return false; 01772 } 01773 if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) { 01774 strcat(infilename, ".mesh"); 01775 } 01776 01777 if (!(fp = fopen(infilename, "r"))) { 01778 printf("Error: Unable to open file %s\n", infilename); 01779 return false; 01780 } 01781 printf("Opening %s.\n", infilename); 01782 01783 // Default uses the index starts from '1'. 01784 firstnumber = 1; 01785 01786 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { 01787 if (*bufferp == '#') continue; // A comment line is skipped. 01788 if (dimension == 0) { 01789 // Find if it is the keyword "Dimension". 01790 str = strstr(bufferp, "Dimension"); 01791 if (!str) str = strstr(bufferp, "dimension"); 01792 if (!str) str = strstr(bufferp, "DIMENSION"); 01793 if (str) { 01794 // Read the dimensions 01795 bufferp = findnextnumber(str); // Skip field "Dimension". 01796 if (*bufferp == '\0') { 01797 // Read a non-empty line. 01798 bufferp = readline(buffer, fp, &line_count); 01799 } 01800 dimension = (int) strtol(bufferp, &bufferp, 0); 01801 if (dimension != 2 && dimension != 3) { 01802 printf("Unknown dimension in file on line %d in file %s\n", 01803 line_count, infilename); 01804 fclose(fp); 01805 return false; 01806 } 01807 mesh_dim = dimension; 01808 } 01809 } 01810 if (nverts == 0) { 01811 // Find if it is the keyword "Vertices". 01812 str = strstr(bufferp, "Vertices"); 01813 if (!str) str = strstr(bufferp, "vertices"); 01814 if (!str) str = strstr(bufferp, "VERTICES"); 01815 if (str) { 01816 // Read the number of vertices. 01817 bufferp = findnextnumber(str); // Skip field "Vertices". 01818 if (*bufferp == '\0') { 01819 // Read a non-empty line. 01820 bufferp = readline(buffer, fp, &line_count); 01821 } 01822 nverts = (int) strtol(bufferp, &bufferp, 0); 01823 // Allocate memory for 'tetgenio' 01824 if (nverts > 0) { 01825 numberofpoints = nverts; 01826 pointlist = new REAL[nverts * 3]; 01827 } 01828 // Read the follwoing node list. 01829 for (i = 0; i < nverts; i++) { 01830 bufferp = readline(buffer, fp, &line_count); 01831 if (bufferp == NULL) { 01832 printf("Unexpected end of file on line %d in file %s\n", 01833 line_count, infilename); 01834 fclose(fp); 01835 return false; 01836 } 01837 // Read vertex coordinates 01838 coord = &pointlist[i * 3]; 01839 for (j = 0; j < 3; j++) { 01840 if (*bufferp == '\0') { 01841 printf("Syntax error reading vertex coords on line"); 01842 printf(" %d in file %s\n", line_count, infilename); 01843 fclose(fp); 01844 return false; 01845 } 01846 if ((j < 2) || (dimension == 3)) { 01847 coord[j] = (REAL) strtod(bufferp, &bufferp); 01848 } else { 01849 assert((j == 2) && (dimension == 2)); 01850 coord[j] = 0.0; 01851 } 01852 bufferp = findnextnumber(bufferp); 01853 } 01854 } 01855 continue; 01856 } 01857 } 01858 if (nfaces == 0) { 01859 // Find if it is the keyword "Triangles" or "Quadrilaterals". 01860 corners = 0; 01861 str = strstr(bufferp, "Triangles"); 01862 if (!str) str = strstr(bufferp, "triangles"); 01863 if (!str) str = strstr(bufferp, "TRIANGLES"); 01864 if (str) { 01865 corners = 3; 01866 } else { 01867 str = strstr(bufferp, "Quadrilaterals"); 01868 if (!str) str = strstr(bufferp, "quadrilaterals"); 01869 if (!str) str = strstr(bufferp, "QUADRILATERALS"); 01870 if (str) { 01871 corners = 4; 01872 } 01873 } 01874 if (corners == 3 || corners == 4) { 01875 // Read the number of triangles (or quadrilaterals). 01876 bufferp = findnextnumber(str); // Skip field "Triangles". 01877 if (*bufferp == '\0') { 01878 // Read a non-empty line. 01879 bufferp = readline(buffer, fp, &line_count); 01880 } 01881 nfaces = strtol(bufferp, &bufferp, 0); 01882 // Allocate memory for 'tetgenio' 01883 if (nfaces > 0) { 01884 if (numberoffacets > 0) { 01885 // facetlist has already been allocated. Enlarge arrays. 01886 tmpflist = new tetgenio::facet[numberoffacets + nfaces]; 01887 tmpfmlist = new int[numberoffacets + nfaces]; 01888 // Copy the data of old arrays into new arrays. 01889 for (i = 0; i < numberoffacets; i++) { 01890 f = &(tmpflist[i]); 01891 tetgenio::init(f); 01892 *f = facetlist[i]; 01893 tmpfmlist[i] = facetmarkerlist[i]; 01894 } 01895 // Release old arrays. 01896 delete [] facetlist; 01897 delete [] facetmarkerlist; 01898 // Remember the new arrays. 01899 facetlist = tmpflist; 01900 facetmarkerlist = tmpfmlist; 01901 } else { 01902 // This is the first time to allocate facetlist. 01903 facetlist = new tetgenio::facet[nfaces]; 01904 facetmarkerlist = new int[nfaces]; 01905 } 01906 } 01907 // Read the following list of faces. 01908 for (i = numberoffacets; i < numberoffacets + nfaces; i++) { 01909 bufferp = readline(buffer, fp, &line_count); 01910 if (bufferp == NULL) { 01911 printf("Unexpected end of file on line %d in file %s\n", 01912 line_count, infilename); 01913 fclose(fp); 01914 return false; 01915 } 01916 f = &facetlist[i]; 01917 tetgenio::init(f); 01918 // In .mesh format, each facet has one polygon, no hole. 01919 f->numberofpolygons = 1; 01920 f->polygonlist = new tetgenio::polygon[1]; 01921 p = &f->polygonlist[0]; 01922 tetgenio::init(p); 01923 p->numberofvertices = corners; 01924 // Allocate memory for face vertices 01925 p->vertexlist = new int[p->numberofvertices]; 01926 // Read the vertices of the face. 01927 for (j = 0; j < corners; j++) { 01928 if (*bufferp == '\0') { 01929 printf("Syntax error reading face on line %d in file %s\n", 01930 line_count, infilename); 01931 fclose(fp); 01932 return false; 01933 } 01934 p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0); 01935 if (firstnumber == 1) { 01936 // Check if a '0' index appears. 01937 if (p->vertexlist[j] == 0) { 01938 // The first index is set to be 0. 01939 firstnumber = 0; 01940 } 01941 } 01942 bufferp = findnextnumber(bufferp); 01943 } 01944 // Read the marker of the face if it exists. 01945 facetmarkerlist[i] = 0; 01946 if (*bufferp != '\0') { 01947 facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0); 01948 } 01949 } 01950 // Have read in a list of triangles/quads. 01951 numberoffacets += nfaces; 01952 nfaces = 0; 01953 } 01954 } 01955 // if (nverts > 0 && nfaces > 0) break; // Ignore other data. 01956 } 01957 01958 // Close file 01959 fclose(fp); 01960 01961 return true; 01962 } 01963 01965 // // 01966 // load_plc() Load a piecewise linear complex from file. // 01967 // // 01968 // This is main entrance for loading plcs from different file formats into // 01969 // tetgenio. 'filename' is the input file name without extention. 'object' // 01970 // indicates which file format is used to describ the plc. // 01971 // // 01973 01974 bool tetgenio::load_plc(char* filename, int object) 01975 { 01976 enum tetgenbehavior::objecttype type; 01977 01978 type = (enum tetgenbehavior::objecttype) object; 01979 switch (type) { 01980 case tetgenbehavior::NODES: 01981 return load_node(filename); 01982 case tetgenbehavior::POLY: 01983 return load_poly(filename); 01984 case tetgenbehavior::OFF: 01985 return load_off(filename); 01986 case tetgenbehavior::PLY: 01987 return load_ply(filename); 01988 case tetgenbehavior::STL: 01989 return load_stl(filename); 01990 case tetgenbehavior::MEDIT: 01991 return load_medit(filename); 01992 default: 01993 return load_poly(filename); 01994 } 01995 } 01996 01998 // // 01999 // load_tetmesh() Load a tetrahedral mesh from files. // 02000 // // 02001 // 'filename' is the inputfile without suffix. The nodes of the tetrahedral // 02002 // mesh is in "filename.node", the elements is in "filename.ele", if the // 02003 // "filename.face" and "filename.vol" exists, they will also be read. // 02004 // // 02006 02007 bool tetgenio::load_tetmesh(char* filename) 02008 { 02009 FILE *infile; 02010 char innodefilename[FILENAMESIZE]; 02011 char inelefilename[FILENAMESIZE]; 02012 char infacefilename[FILENAMESIZE]; 02013 char inedgefilename[FILENAMESIZE]; 02014 char involfilename[FILENAMESIZE]; 02015 char inputline[INPUTLINESIZE]; 02016 char *stringptr, *infilename; 02017 REAL attrib, volume; 02018 int volelements; 02019 int markers, corner; 02020 int index, attribindex; 02021 int i, j; 02022 02023 markers = 0; 02024 02025 // Assembling the actual file names we want to open. 02026 strcpy(innodefilename, filename); 02027 strcpy(inelefilename, filename); 02028 strcpy(infacefilename, filename); 02029 strcpy(inedgefilename, filename); 02030 strcpy(involfilename, filename); 02031 strcat(innodefilename, ".node"); 02032 strcat(inelefilename, ".ele"); 02033 strcat(infacefilename, ".face"); 02034 strcat(inedgefilename, ".edge"); 02035 strcat(involfilename, ".vol"); 02036 02037 // Read the points from a .node file. 02038 infilename = innodefilename; 02039 printf("Opening %s.\n", infilename); 02040 infile = fopen(infilename, "r"); 02041 if (infile == (FILE *) NULL) { 02042 printf("File I/O Error: Cannot access file %s.\n", infilename); 02043 return false; 02044 } 02045 // Read the first line of the file. 02046 stringptr = readnumberline(inputline, infile, infilename); 02047 // Is this list of points generated from rbox? 02048 stringptr = strstr(inputline, "rbox"); 02049 if (stringptr == NULL) { 02050 // Read number of points, number of dimensions, number of point 02051 // attributes, and number of boundary markers. 02052 stringptr = inputline; 02053 numberofpoints = (int) strtol (stringptr, &stringptr, 0); 02054 stringptr = findnextnumber(stringptr); 02055 if (*stringptr == '\0') { 02056 mesh_dim = 3; 02057 } else { 02058 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 02059 } 02060 stringptr = findnextnumber(stringptr); 02061 if (*stringptr == '\0') { 02062 numberofpointattributes = 0; 02063 } else { 02064 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); 02065 } 02066 stringptr = findnextnumber(stringptr); 02067 if (*stringptr == '\0') { 02068 markers = 0; // Default value. 02069 } else { 02070 markers = (int) strtol (stringptr, &stringptr, 0); 02071 } 02072 } else { 02073 // It is a rbox (qhull) input file. 02074 stringptr = inputline; 02075 // Get the dimension. 02076 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 02077 // Get the number of points. 02078 stringptr = readnumberline(inputline, infile, infilename); 02079 numberofpoints = (int) strtol (stringptr, &stringptr, 0); 02080 // There is no index column. 02081 useindex = 0; 02082 } 02083 02084 // Load the list of nodes. 02085 if (!load_node_call(infile, markers, infilename)) { 02086 fclose(infile); 02087 return false; 02088 } 02089 fclose(infile); 02090 02091 // Read the elements from an .ele file. 02092 if (mesh_dim == 3) { 02093 infilename = inelefilename; 02094 infile = fopen(infilename, "r"); 02095 if (infile != (FILE *) NULL) { 02096 printf("Opening %s.\n", infilename); 02097 // Read number of elements, number of corners (4 or 10), number of 02098 // element attributes. 02099 stringptr = readnumberline(inputline, infile, infilename); 02100 numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0); 02101 stringptr = findnextnumber(stringptr); 02102 if (*stringptr == '\0') { 02103 numberofcorners = 4; // Default read 4 nodes per element. 02104 } else { 02105 numberofcorners = (int) strtol(stringptr, &stringptr, 0); 02106 } 02107 stringptr = findnextnumber(stringptr); 02108 if (*stringptr == '\0') { 02109 numberoftetrahedronattributes = 0; // Default no attribute. 02110 } else { 02111 numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0); 02112 } 02113 if (numberofcorners != 4 && numberofcorners != 10) { 02114 printf("Error: Wrong number of corners %d (should be 4 or 10).\n", 02115 numberofcorners); 02116 fclose(infile); 02117 return false; 02118 } 02119 // Allocate memory for tetrahedra. 02120 if (numberoftetrahedra > 0) { 02121 tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; 02122 if (tetrahedronlist == (int *) NULL) { 02123 printf("Error: Out of memory.\n"); 02124 terminatetetgen(1); 02125 } 02126 // Allocate memory for output tetrahedron attributes if necessary. 02127 if (numberoftetrahedronattributes > 0) { 02128 tetrahedronattributelist = new REAL[numberoftetrahedra * 02129 numberoftetrahedronattributes]; 02130 if (tetrahedronattributelist == (REAL *) NULL) { 02131 printf("Error: Out of memory.\n"); 02132 terminatetetgen(1); 02133 } 02134 } 02135 } 02136 // Read the list of tetrahedra. 02137 index = 0; 02138 attribindex = 0; 02139 for (i = 0; i < numberoftetrahedra; i++) { 02140 // Read tetrahedron index and the tetrahedron's corners. 02141 stringptr = readnumberline(inputline, infile, infilename); 02142 for (j = 0; j < numberofcorners; j++) { 02143 stringptr = findnextnumber(stringptr); 02144 if (*stringptr == '\0') { 02145 printf("Error: Tetrahedron %d is missing vertex %d in %s.\n", 02146 i + firstnumber, j + 1, infilename); 02147 terminatetetgen(1); 02148 } 02149 corner = (int) strtol(stringptr, &stringptr, 0); 02150 if (corner < firstnumber || corner >= numberofpoints + firstnumber) { 02151 printf("Error: Tetrahedron %d has an invalid vertex index.\n", 02152 i + firstnumber); 02153 terminatetetgen(1); 02154 } 02155 tetrahedronlist[index++] = corner; 02156 } 02157 // Read the tetrahedron's attributes. 02158 for (j = 0; j < numberoftetrahedronattributes; j++) { 02159 stringptr = findnextnumber(stringptr); 02160 if (*stringptr == '\0') { 02161 attrib = 0.0; 02162 } else { 02163 attrib = (REAL) strtod(stringptr, &stringptr); 02164 } 02165 tetrahedronattributelist[attribindex++] = attrib; 02166 } 02167 } 02168 fclose(infile); 02169 } 02170 } // if (meshdim == 3) 02171 02172 // Read the hullfaces or subfaces from a .face file if it exists. 02173 if (mesh_dim == 3) { 02174 infilename = infacefilename; 02175 } else { 02176 infilename = inelefilename; 02177 } 02178 infile = fopen(infilename, "r"); 02179 if (infile != (FILE *) NULL) { 02180 printf("Opening %s.\n", infilename); 02181 // Read number of faces, boundary markers. 02182 stringptr = readnumberline(inputline, infile, infilename); 02183 numberoftrifaces = (int) strtol (stringptr, &stringptr, 0); 02184 stringptr = findnextnumber(stringptr); 02185 if (mesh_dim == 2) { 02186 // Skip a number. 02187 stringptr = findnextnumber(stringptr); 02188 } 02189 if (*stringptr == '\0') { 02190 markers = 0; // Default there is no marker per face. 02191 } else { 02192 markers = (int) strtol (stringptr, &stringptr, 0); 02193 } 02194 if (numberoftrifaces > 0) { 02195 trifacelist = new int[numberoftrifaces * 3]; 02196 if (trifacelist == (int *) NULL) { 02197 printf("Error: Out of memory.\n"); 02198 terminatetetgen(1); 02199 } 02200 if (markers) { 02201 trifacemarkerlist = new int[numberoftrifaces * 3]; 02202 if (trifacemarkerlist == (int *) NULL) { 02203 printf("Error: Out of memory.\n"); 02204 terminatetetgen(1); 02205 } 02206 } 02207 } 02208 // Read the list of faces. 02209 index = 0; 02210 for (i = 0; i < numberoftrifaces; i++) { 02211 // Read face index and the face's three corners. 02212 stringptr = readnumberline(inputline, infile, infilename); 02213 for (j = 0; j < 3; j++) { 02214 stringptr = findnextnumber(stringptr); 02215 if (*stringptr == '\0') { 02216 printf("Error: Face %d is missing vertex %d in %s.\n", 02217 i + firstnumber, j + 1, infilename); 02218 terminatetetgen(1); 02219 } 02220 corner = (int) strtol(stringptr, &stringptr, 0); 02221 if (corner < firstnumber || corner >= numberofpoints + firstnumber) { 02222 printf("Error: Face %d has an invalid vertex index.\n", 02223 i + firstnumber); 02224 terminatetetgen(1); 02225 } 02226 trifacelist[index++] = corner; 02227 } 02228 // Read the boundary marker if it exists. 02229 if (markers) { 02230 stringptr = findnextnumber(stringptr); 02231 if (*stringptr == '\0') { 02232 attrib = 0.0; 02233 } else { 02234 attrib = (REAL) strtod(stringptr, &stringptr); 02235 } 02236 trifacemarkerlist[i] = (int) attrib; 02237 } 02238 } 02239 fclose(infile); 02240 } 02241 02242 // Read the boundary edges from a .edge file if it exists. 02243 infilename = inedgefilename; 02244 infile = fopen(infilename, "r"); 02245 if (infile != (FILE *) NULL) { 02246 printf("Opening %s.\n", infilename); 02247 // Read number of boundary edges. 02248 stringptr = readnumberline(inputline, infile, infilename); 02249 numberofedges = (int) strtol (stringptr, &stringptr, 0); 02250 if (numberofedges > 0) { 02251 edgelist = new int[numberofedges * 2]; 02252 if (edgelist == (int *) NULL) { 02253 printf("Error: Out of memory.\n"); 02254 terminatetetgen(1); 02255 } 02256 } 02257 // Read the list of faces. 02258 index = 0; 02259 for (i = 0; i < numberofedges; i++) { 02260 // Read face index and the edge's two endpoints. 02261 stringptr = readnumberline(inputline, infile, infilename); 02262 for (j = 0; j < 2; j++) { 02263 stringptr = findnextnumber(stringptr); 02264 if (*stringptr == '\0') { 02265 printf("Error: Edge %d is missing vertex %d in %s.\n", 02266 i + firstnumber, j + 1, infilename); 02267 terminatetetgen(1); 02268 } 02269 corner = (int) strtol(stringptr, &stringptr, 0); 02270 if (corner < firstnumber || corner >= numberofpoints + firstnumber) { 02271 printf("Error: Edge %d has an invalid vertex index.\n", 02272 i + firstnumber); 02273 terminatetetgen(1); 02274 } 02275 edgelist[index++] = corner; 02276 } 02277 } 02278 fclose(infile); 02279 } 02280 02281 // Read the volume constraints from a .vol file if it exists. 02282 infilename = involfilename; 02283 infile = fopen(infilename, "r"); 02284 if (infile != (FILE *) NULL) { 02285 printf("Opening %s.\n", infilename); 02286 // Read number of tetrahedra. 02287 stringptr = readnumberline(inputline, infile, infilename); 02288 volelements = (int) strtol (stringptr, &stringptr, 0); 02289 if (volelements != numberoftetrahedra) { 02290 printf("Warning: %s and %s disagree on number of tetrahedra.\n", 02291 inelefilename, involfilename); 02292 volelements = 0; 02293 } 02294 if (volelements > 0) { 02295 tetrahedronvolumelist = new REAL[volelements]; 02296 if (tetrahedronvolumelist == (REAL *) NULL) { 02297 printf("Error: Out of memory.\n"); 02298 terminatetetgen(1); 02299 } 02300 } 02301 // Read the list of volume constraints. 02302 for (i = 0; i < volelements; i++) { 02303 stringptr = readnumberline(inputline, infile, infilename); 02304 stringptr = findnextnumber(stringptr); 02305 if (*stringptr == '\0') { 02306 volume = -1.0; // No constraint on this tetrahedron. 02307 } else { 02308 volume = (REAL) strtod(stringptr, &stringptr); 02309 } 02310 tetrahedronvolumelist[i] = volume; 02311 } 02312 fclose(infile); 02313 } 02314 02315 // Try to load a .mtr file if it exists. 02316 load_mtr(filename); 02317 // Try to read a .pbc file if it exists. 02318 load_pbc(filename); 02319 02320 return true; 02321 } 02322 02324 // // 02325 // load_voronoi() Load a Voronoi diagram from files. // 02326 // // 02327 // 'filename' is the inputfile without suffix. The Voronoi diagram is read // 02328 // from files: filename.v.node, filename.v.edge, and filename.v.face. // 02329 // // 02331 02332 bool tetgenio::load_voronoi(char* filename) 02333 { 02334 FILE *infile; 02335 char innodefilename[FILENAMESIZE]; 02336 char inedgefilename[FILENAMESIZE]; 02337 char inputline[INPUTLINESIZE]; 02338 char *stringptr, *infilename; 02339 voroedge *vedge; 02340 REAL x, y, z; 02341 int firstnode, corner; 02342 int index; 02343 int i, j; 02344 02345 // Assembling the actual file names we want to open. 02346 strcpy(innodefilename, filename); 02347 strcpy(inedgefilename, filename); 02348 strcat(innodefilename, ".v.node"); 02349 strcat(inedgefilename, ".v.edge"); 02350 02351 // Read the points from a .v.node file. 02352 infilename = innodefilename; 02353 printf("Opening %s.\n", infilename); 02354 infile = fopen(infilename, "r"); 02355 if (infile == (FILE *) NULL) { 02356 printf("File I/O Error: Cannot access file %s.\n", infilename); 02357 return false; 02358 } 02359 // Read the first line of the file. 02360 stringptr = readnumberline(inputline, infile, infilename); 02361 // Is this list of points generated from rbox? 02362 stringptr = strstr(inputline, "rbox"); 02363 if (stringptr == NULL) { 02364 // Read number of points, number of dimensions, number of point 02365 // attributes, and number of boundary markers. 02366 stringptr = inputline; 02367 numberofvpoints = (int) strtol (stringptr, &stringptr, 0); 02368 stringptr = findnextnumber(stringptr); 02369 if (*stringptr == '\0') { 02370 mesh_dim = 3; // Default. 02371 } else { 02372 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 02373 } 02374 useindex = 1; // There is an index column. 02375 } else { 02376 // It is a rbox (qhull) input file. 02377 stringptr = inputline; 02378 // Get the dimension. 02379 mesh_dim = (int) strtol (stringptr, &stringptr, 0); 02380 // Get the number of points. 02381 stringptr = readnumberline(inputline, infile, infilename); 02382 numberofvpoints = (int) strtol (stringptr, &stringptr, 0); 02383 useindex = 0; // No index column. 02384 } 02385 // Initialize 'vpointlist'. 02386 vpointlist = new REAL[numberofvpoints * 3]; 02387 if (vpointlist == (REAL *) NULL) { 02388 printf("Error: Out of memory.\n"); 02389 terminatetetgen(1); 02390 } 02391 // Read the point section. 02392 index = 0; 02393 for (i = 0; i < numberofvpoints; i++) { 02394 stringptr = readnumberline(inputline, infile, infilename); 02395 if (useindex) { 02396 if (i == 0) { 02397 firstnode = (int) strtol (stringptr, &stringptr, 0); 02398 if ((firstnode == 0) || (firstnode == 1)) { 02399 firstnumber = firstnode; 02400 } 02401 } 02402 stringptr = findnextnumber(stringptr); 02403 } // if (useindex) 02404 if (*stringptr == '\0') { 02405 printf("Error: Point %d has no x coordinate.\n", firstnumber + i); 02406 terminatetetgen(1); 02407 } 02408 x = (REAL) strtod(stringptr, &stringptr); 02409 stringptr = findnextnumber(stringptr); 02410 if (*stringptr == '\0') { 02411 printf("Error: Point %d has no y coordinate.\n", firstnumber + i); 02412 terminatetetgen(1); 02413 } 02414 y = (REAL) strtod(stringptr, &stringptr); 02415 if (mesh_dim == 3) { 02416 stringptr = findnextnumber(stringptr); 02417 if (*stringptr == '\0') { 02418 printf("Error: Point %d has no z coordinate.\n", firstnumber + i); 02419 terminatetetgen(1); 02420 } 02421 z = (REAL) strtod(stringptr, &stringptr); 02422 } else { 02423 z = 0.0; // mesh_dim == 2; 02424 } 02425 vpointlist[index++] = x; 02426 vpointlist[index++] = y; 02427 vpointlist[index++] = z; 02428 } 02429 fclose(infile); 02430 02431 // Read the Voronoi edges from a .v.edge file if it exists. 02432 infilename = inedgefilename; 02433 infile = fopen(infilename, "r"); 02434 if (infile != (FILE *) NULL) { 02435 printf("Opening %s.\n", infilename); 02436 // Read number of boundary edges. 02437 stringptr = readnumberline(inputline, infile, infilename); 02438 numberofvedges = (int) strtol (stringptr, &stringptr, 0); 02439 if (numberofvedges > 0) { 02440 vedgelist = new voroedge[numberofvedges]; 02441 } 02442 // Read the list of faces. 02443 index = 0; 02444 for (i = 0; i < numberofvedges; i++) { 02445 // Read edge index and the edge's two endpoints. 02446 stringptr = readnumberline(inputline, infile, infilename); 02447 vedge = &(vedgelist[i]); 02448 for (j = 0; j < 2; j++) { 02449 stringptr = findnextnumber(stringptr); 02450 if (*stringptr == '\0') { 02451 printf("Error: Edge %d is missing vertex %d in %s.\n", 02452 i + firstnumber, j + 1, infilename); 02453 terminatetetgen(1); 02454 } 02455 corner = (int) strtol(stringptr, &stringptr, 0); 02456 j == 0 ? vedge->v1 = corner : vedge->v2 = corner; 02457 } 02458 if (vedge->v2 < 0) { 02459 for (j = 0; j < mesh_dim; j++) { 02460 stringptr = findnextnumber(stringptr); 02461 if (*stringptr == '\0') { 02462 printf("Error: Edge %d is missing normal in %s.\n", 02463 i + firstnumber, infilename); 02464 terminatetetgen(1); 02465 } 02466 vedge->vnormal[j] = (REAL) strtod(stringptr, &stringptr); 02467 } 02468 if (mesh_dim == 2) { 02469 vedge->vnormal[2] = 0.0; 02470 } 02471 } else { 02472 vedge->vnormal[0] = 0.0; 02473 vedge->vnormal[1] = 0.0; 02474 vedge->vnormal[2] = 0.0; 02475 } 02476 } 02477 fclose(infile); 02478 } 02479 02480 return true; 02481 } 02482 02484 // // 02485 // save_nodes() Save points to a .node file. // 02486 // // 02487 // 'filename' is a string containing the file name without suffix. // 02488 // // 02490 02491 void tetgenio::save_nodes(char* filename) 02492 { 02493 FILE *fout; 02494 char outnodefilename[FILENAMESIZE]; 02495 char outmtrfilename[FILENAMESIZE]; 02496 int i, j; 02497 02498 sprintf(outnodefilename, "%s.node", filename); 02499 printf("Saving nodes to %s\n", outnodefilename); 02500 fout = fopen(outnodefilename, "w"); 02501 fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim, 02502 numberofpointattributes, pointmarkerlist != NULL ? 1 : 0); 02503 for (i = 0; i < numberofpoints; i++) { 02504 if (mesh_dim == 2) { 02505 fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 2], 02506 pointlist[i * 2 + 1]); 02507 } else { 02508 fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber, 02509 pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]); 02510 } 02511 for (j = 0; j < numberofpointattributes; j++) { 02512 fprintf(fout, " %.16g", 02513 pointattributelist[i * numberofpointattributes + j]); 02514 } 02515 if (pointmarkerlist != NULL) { 02516 fprintf(fout, " %d", pointmarkerlist[i]); 02517 } 02518 fprintf(fout, "\n"); 02519 } 02520 fclose(fout); 02521 02522 // If the point metrics exist, output them to a .mtr file. 02523 if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) { 02524 sprintf(outmtrfilename, "%s.mtr", filename); 02525 printf("Saving metrics to %s\n", outmtrfilename); 02526 fout = fopen(outmtrfilename, "w"); 02527 fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs); 02528 for (i = 0; i < numberofpoints; i++) { 02529 for (j = 0; j < numberofpointmtrs; j++) { 02530 fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]); 02531 } 02532 fprintf(fout, "\n"); 02533 } 02534 fclose(fout); 02535 } 02536 } 02537 02539 // // 02540 // save_elements() Save elements to a .ele file. // 02541 // // 02542 // 'filename' is a string containing the file name without suffix. // 02543 // // 02545 02546 void tetgenio::save_elements(char* filename) 02547 { 02548 FILE *fout; 02549 char outelefilename[FILENAMESIZE]; 02550 int i, j; 02551 02552 sprintf(outelefilename, "%s.ele", filename); 02553 printf("Saving elements to %s\n", outelefilename); 02554 fout = fopen(outelefilename, "w"); 02555 fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners, 02556 numberoftetrahedronattributes); 02557 for (i = 0; i < numberoftetrahedra; i++) { 02558 fprintf(fout, "%d", i + firstnumber); 02559 for (j = 0; j < numberofcorners; j++) { 02560 fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]); 02561 } 02562 for (j = 0; j < numberoftetrahedronattributes; j++) { 02563 fprintf(fout, " %g", 02564 tetrahedronattributelist[i * numberoftetrahedronattributes + j]); 02565 } 02566 fprintf(fout, "\n"); 02567 } 02568 02569 fclose(fout); 02570 } 02571 02573 // // 02574 // save_faces() Save faces to a .face file. // 02575 // // 02576 // 'filename' is a string containing the file name without suffix. // 02577 // // 02579 02580 void tetgenio::save_faces(char* filename) 02581 { 02582 FILE *fout; 02583 char outfacefilename[FILENAMESIZE]; 02584 int i; 02585 02586 sprintf(outfacefilename, "%s.face", filename); 02587 printf("Saving faces to %s\n", outfacefilename); 02588 fout = fopen(outfacefilename, "w"); 02589 fprintf(fout, "%d %d\n", numberoftrifaces, 02590 trifacemarkerlist != NULL ? 1 : 0); 02591 for (i = 0; i < numberoftrifaces; i++) { 02592 fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3], 02593 trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]); 02594 if (trifacemarkerlist != NULL) { 02595 fprintf(fout, " %d", trifacemarkerlist[i]); 02596 } 02597 fprintf(fout, "\n"); 02598 } 02599 02600 fclose(fout); 02601 } 02602 02604 // // 02605 // save_edges() Save egdes to a .edge file. // 02606 // // 02607 // 'filename' is a string containing the file name without suffix. // 02608 // // 02610 02611 void tetgenio::save_edges(char* filename) 02612 { 02613 FILE *fout; 02614 char outedgefilename[FILENAMESIZE]; 02615 int i; 02616 02617 sprintf(outedgefilename, "%s.edge", filename); 02618 printf("Saving edges to %s\n", outedgefilename); 02619 fout = fopen(outedgefilename, "w"); 02620 fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0); 02621 for (i = 0; i < numberofedges; i++) { 02622 fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2], 02623 edgelist[i * 2 + 1]); 02624 if (edgemarkerlist != NULL) { 02625 fprintf(fout, " %d", edgemarkerlist[i]); 02626 } 02627 fprintf(fout, "\n"); 02628 } 02629 02630 fclose(fout); 02631 } 02632 02634 // // 02635 // save_neighbors() Save egdes to a .neigh file. // 02636 // // 02637 // 'filename' is a string containing the file name without suffix. // 02638 // // 02640 02641 void tetgenio::save_neighbors(char* filename) 02642 { 02643 FILE *fout; 02644 char outneighborfilename[FILENAMESIZE]; 02645 int i; 02646 02647 sprintf(outneighborfilename, "%s.neigh", filename); 02648 printf("Saving neighbors to %s\n", outneighborfilename); 02649 fout = fopen(outneighborfilename, "w"); 02650 fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1); 02651 for (i = 0; i < numberoftetrahedra; i++) { 02652 if (mesh_dim == 2) { 02653 fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3], 02654 neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]); 02655 } else { 02656 fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber, 02657 neighborlist[i * 4], neighborlist[i * 4 + 1], 02658 neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]); 02659 } 02660 fprintf(fout, "\n"); 02661 } 02662 02663 fclose(fout); 02664 } 02665 02667 // // 02668 // save_poly() Save segments or facets to a .poly file. // 02669 // // 02670 // 'filename' is a string containing the file name without suffix. It only // 02671 // save the facets, holes and regions. The nodes are saved in a .node file // 02672 // by routine save_nodes(). // 02673 // // 02675 02676 void tetgenio::save_poly(char* filename) 02677 { 02678 FILE *fout; 02679 facet *f; 02680 polygon *p; 02681 char outpolyfilename[FILENAMESIZE]; 02682 int i, j, k; 02683 02684 sprintf(outpolyfilename, "%s.poly", filename); 02685 printf("Saving poly to %s\n", outpolyfilename); 02686 fout = fopen(outpolyfilename, "w"); 02687 02688 // The zero indicates that the vertices are in a separate .node file. 02689 // Followed by number of dimensions, number of vertex attributes, 02690 // and number of boundary markers (zero or one). 02691 fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes, 02692 pointmarkerlist != NULL ? 1 : 0); 02693 02694 // Save segments or facets. 02695 if (mesh_dim == 2) { 02696 // Number of segments, number of boundary markers (zero or one). 02697 fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0); 02698 for (i = 0; i < numberofedges; i++) { 02699 fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2], 02700 edgelist[i * 2 + 1]); 02701 if (edgemarkerlist != NULL) { 02702 fprintf(fout, " %d", edgemarkerlist[i]); 02703 } 02704 fprintf(fout, "\n"); 02705 } 02706 } else { 02707 // Number of facets, number of boundary markers (zero or one). 02708 fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0); 02709 for (i = 0; i < numberoffacets; i++) { 02710 f = &(facetlist[i]); 02711 fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes, 02712 facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber); 02713 // Output polygons of this facet. 02714 for (j = 0; j < f->numberofpolygons; j++) { 02715 p = &(f->polygonlist[j]); 02716 fprintf(fout, "%d ", p->numberofvertices); 02717 for (k = 0; k < p->numberofvertices; k++) { 02718 if (((k + 1) % 10) == 0) { 02719 fprintf(fout, "\n "); 02720 } 02721 fprintf(fout, " %d", p->vertexlist[k]); 02722 } 02723 fprintf(fout, "\n"); 02724 } 02725 // Output holes of this facet. 02726 for (j = 0; j < f->numberofholes; j++) { 02727 fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber, 02728 f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]); 02729 } 02730 } 02731 } 02732 02733 // Save holes. 02734 fprintf(fout, "%d\n", numberofholes); 02735 for (i = 0; i < numberofholes; i++) { 02736 // Output x, y coordinates. 02737 fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim], 02738 holelist[i * mesh_dim + 1]); 02739 if (mesh_dim == 3) { 02740 // Output z coordinate. 02741 fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]); 02742 } 02743 fprintf(fout, "\n"); 02744 } 02745 02746 // Save regions. 02747 fprintf(fout, "%d\n", numberofregions); 02748 for (i = 0; i < numberofregions; i++) { 02749 if (mesh_dim == 2) { 02750 // Output the index, x, y coordinates, attribute (region number) 02751 // and maximum area constraint (maybe -1). 02752 fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber, 02753 regionlist[i * 4], regionlist[i * 4 + 1], 02754 regionlist[i * 4 + 2], regionlist[i * 4 + 3]); 02755 } else { 02756 // Output the index, x, y, z coordinates, attribute (region number) 02757 // and maximum volume constraint (maybe -1). 02758 fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber, 02759 regionlist[i * 5], regionlist[i * 5 + 1], 02760 regionlist[i * 5 + 2], regionlist[i * 5 + 3], 02761 regionlist[i * 5 + 4]); 02762 } 02763 } 02764 02765 fclose(fout); 02766 } 02767 02769 // // 02770 // readline() Read a nonempty line from a file. // 02771 // // 02772 // A line is considered "nonempty" if it contains something more than white // 02773 // spaces. If a line is considered empty, it will be dropped and the next // 02774 // line will be read, this process ends until reaching the end-of-file or a // 02775 // non-empty line. Return NULL if it is the end-of-file, otherwise, return // 02776 // a pointer to the first non-whitespace character of the line. // 02777 // // 02779 02780 char* tetgenio::readline(char *string, FILE *infile, int *linenumber) 02781 { 02782 char *result; 02783 02784 // Search for a non-empty line. 02785 do { 02786 result = fgets(string, INPUTLINESIZE - 1, infile); 02787 if (linenumber) (*linenumber)++; 02788 if (result == (char *) NULL) { 02789 return (char *) NULL; 02790 } 02791 // Skip white spaces. 02792 while ((*result == ' ') || (*result == '\t')) result++; 02793 // If it's end of line, read another line and try again. 02794 } while (*result == '\0'); 02795 return result; 02796 } 02797 02799 // // 02800 // findnextfield() Find the next field of a string. // 02801 // // 02802 // Jumps past the current field by searching for whitespace or a comma, then // 02803 // jumps past the whitespace or the comma to find the next field. // 02804 // // 02806 02807 char* tetgenio::findnextfield(char *string) 02808 { 02809 char *result; 02810 02811 result = string; 02812 // Skip the current field. Stop upon reaching whitespace or a comma. 02813 while ((*result != '\0') && (*result != ' ') && (*result != '\t') && 02814 (*result != ',') && (*result != ';')) { 02815 result++; 02816 } 02817 // Now skip the whitespace or the comma, stop at anything else that looks 02818 // like a character, or the end of a line. 02819 while ((*result == ' ') || (*result == '\t') || (*result == ',') || 02820 (*result == ';')) { 02821 result++; 02822 } 02823 return result; 02824 } 02825 02827 // // 02828 // readnumberline() Read a nonempty number line from a file. // 02829 // // 02830 // A line is considered "nonempty" if it contains something that looks like // 02831 // a number. Comments (prefaced by `#') are ignored. // 02832 // // 02834 02835 char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename) 02836 { 02837 char *result; 02838 02839 // Search for something that looks like a number. 02840 do { 02841 result = fgets(string, INPUTLINESIZE, infile); 02842 if (result == (char *) NULL) { 02843 if (infilename != (char *) NULL) { 02844 printf(" Error: Unexpected end of file in %s.\n", infilename); 02845 terminatetetgen(1); 02846 } 02847 return result; 02848 } 02849 // Skip anything that doesn't look like a number, a comment, 02850 // or the end of a line. 02851 while ((*result != '\0') && (*result != '#') 02852 && (*result != '.') && (*result != '+') && (*result != '-') 02853 && ((*result < '0') || (*result > '9'))) { 02854 result++; 02855 } 02856 // If it's a comment or end of line, read another line and try again. 02857 } while ((*result == '#') || (*result == '\0')); 02858 return result; 02859 } 02860 02862 // // 02863 // findnextnumber() Find the next field of a number string. // 02864 // // 02865 // Jumps past the current field by searching for whitespace or a comma, then // 02866 // jumps past the whitespace or the comma to find the next field that looks // 02867 // like a number. // 02868 // // 02870 02871 char* tetgenio::findnextnumber(char *string) 02872 { 02873 char *result; 02874 02875 result = string; 02876 // Skip the current field. Stop upon reaching whitespace or a comma. 02877 while ((*result != '\0') && (*result != '#') && (*result != ' ') && 02878 (*result != '\t') && (*result != ',')) { 02879 result++; 02880 } 02881 // Now skip the whitespace and anything else that doesn't look like a 02882 // number, a comment, or the end of a line. 02883 while ((*result != '\0') && (*result != '#') 02884 && (*result != '.') && (*result != '+') && (*result != '-') 02885 && ((*result < '0') || (*result > '9'))) { 02886 result++; 02887 } 02888 // Check for a comment (prefixed with `#'). 02889 if (*result == '#') { 02890 *result = '\0'; 02891 } 02892 return result; 02893 } 02894 02895 // 02896 // End of class 'tetgenio' implementation 02897 // 02898 02899 static REAL PI = 3.14159265358979323846264338327950288419716939937510582; 02900 02901 // 02902 // Begin of class 'tetgenbehavior' implementation 02903 // 02904 02906 // // 02907 // tetgenbehavior() Initialize veriables of 'tetgenbehavior'. // 02908 // // 02910 02911 tetgenbehavior::tetgenbehavior() 02912 { 02913 // Initialize command line switches. 02914 plc = 0; 02915 quality = 0; 02916 refine = 0; 02917 coarse = 0; 02918 metric = 0; 02919 minratio = 2.0; 02920 goodratio = 0.0; 02921 minangle = 20.0; 02922 goodangle = 0.0; 02923 maxdihedral = 165.0; 02924 mindihedral = 5.0; 02925 varvolume = 0; 02926 fixedvolume = 0; 02927 maxvolume = -1.0; 02928 regionattrib = 0; 02929 insertaddpoints = 0; 02930 diagnose = 0; 02931 offcenter = 0; 02932 conformdel = 0; 02933 alpha1 = sqrt(2.0); 02934 alpha2 = 1.0; 02935 alpha3 = 0.6; 02936 zeroindex = 0; 02937 facesout = 0; 02938 edgesout = 0; 02939 neighout = 0; 02940 voroout = 0; 02941 meditview = 0; 02942 gidview = 0; 02943 geomview = 0; 02944 optlevel = 3; 02945 optpasses = 3; 02946 order = 1; 02947 nojettison = 0; 02948 nobound = 0; 02949 nonodewritten = 0; 02950 noelewritten = 0; 02951 nofacewritten = 0; 02952 noiterationnum = 0; 02953 nobisect = 0; 02954 noflip = 0; 02955 steiner = -1; 02956 fliprepair = 1; 02957 nomerge = 0; 02958 docheck = 0; 02959 quiet = 0; 02960 verbose = 0; 02961 useshelles = 0; 02962 epsilon = 1.0e-8; 02963 epsilon2 = 1.0e-5; 02964 object = NONE; 02965 // Initialize strings 02966 commandline[0] = '\0'; 02967 infilename[0] = '\0'; 02968 outfilename[0] = '\0'; 02969 addinfilename[0] = '\0'; 02970 bgmeshfilename[0] = '\0'; 02971 } 02972 02974 // // 02975 // versioninfo() Print the version information of TetGen. // 02976 // // 02978 02979 void tetgenbehavior::versioninfo() 02980 { 02981 printf("Version 1.4.2 (April 16, 2007).\n"); 02982 printf("\n"); 02983 printf("Copyright (C) 2002 - 2007\n"); 02984 printf("Hang Si\n"); 02985 printf("Mohrenstr. 39, 10117 Berlin, Germany\n"); 02986 printf("si@wias-berlin.de\n"); 02987 } 02988 02990 // // 02991 // syntax() Print list of command line switches and exit the program. // 02992 // // 02994 02995 void tetgenbehavior::syntax() 02996 { 02997 printf(" tetgen [-prq_Ra_AiMYS_T_dzo_fenvgGOJBNEFICQVh] input_file\n"); 02998 printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n"); 02999 printf(" -r Reconstructs a previously generated mesh.\n"); 03000 printf(" -q Quality mesh generation (adding new mesh points to "); 03001 printf("improve mesh quality).\n"); 03002 printf(" -R Mesh coarsening (deleting redundant mesh points).\n"); 03003 printf(" -a Applies a maximum tetrahedron volume constraint.\n"); 03004 printf(" -A Assigns attributes to identify tetrahedra in different "); 03005 printf("regions.\n"); 03006 printf(" -i Inserts a list of additional points into mesh.\n"); 03007 printf(" -M Does not merge coplanar facets.\n"); 03008 printf(" -Y Suppresses boundary facets/segments splitting.\n"); 03009 printf(" -S Specifies maximum number of added points.\n"); 03010 printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n"); 03011 printf(" -d Detects self-intersections of facets of the PLC.\n"); 03012 printf(" -z Numbers all output items starting from zero.\n"); 03013 printf(" -o2 Generates second-order subparametric elements.\n"); 03014 printf(" -f Outputs all faces to .face file."); 03015 printf("file.\n"); 03016 printf(" -e Outputs all edges to .edge file.\n"); 03017 printf(" -n Outputs tetrahedra neighbors to .neigh file.\n"); 03018 printf(" -v Outputs Voronoi diagram to files.\n"); 03019 printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n"); 03020 printf(" -G Outputs mesh to .msh file for viewing by Gid.\n"); 03021 printf(" -O Outputs mesh to .off file for viewing by Geomview.\n"); 03022 printf(" -J No jettison of unused vertices from output .node file.\n"); 03023 printf(" -B Suppresses output of boundary information.\n"); 03024 printf(" -N Suppresses output of .node file.\n"); 03025 printf(" -E Suppresses output of .ele file.\n"); 03026 printf(" -F Suppresses output of .face file.\n"); 03027 printf(" -I Suppresses mesh iteration numbers.\n"); 03028 printf(" -C Checks the consistency of the final mesh.\n"); 03029 printf(" -Q Quiet: No terminal output except errors.\n"); 03030 printf(" -V Verbose: Detailed information, more terminal output.\n"); 03031 printf(" -h Help: A brief instruction for using TetGen.\n"); 03032 } 03033 03035 // // 03036 // usage() Print a brief instruction for using TetGen. // 03037 // // 03039 03040 void tetgenbehavior::usage() 03041 { 03042 printf("TetGen\n"); 03043 printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay "); 03044 printf("Triangulator\n"); 03045 versioninfo(); 03046 printf("\n"); 03047 printf("What Can TetGen Do?\n"); 03048 printf("\n"); 03049 printf(" TetGen generates exact Delaunay tetrahedralizations, exact\n"); 03050 printf(" constrained Delaunay tetrahedralizations, and quality "); 03051 printf("tetrahedral\n meshes. The latter are nicely graded and whose "); 03052 printf("tetrahedra have\n radius-edge ratio bounded, thus are suitable "); 03053 printf("for finite element and\n finite volume analysis.\n"); 03054 printf("\n"); 03055 printf("Command Line Syntax:\n"); 03056 printf("\n"); 03057 printf(" Below is the command line syntax of TetGen with a list of "); 03058 printf("short\n"); 03059 printf(" descriptions. Underscores indicate that numbers may optionally\n"); 03060 printf(" follow certain switches. Do not leave any space between a "); 03061 printf("switch\n"); 03062 printf(" and its numeric parameter. \'input_file\' contains input data\n"); 03063 printf(" depending on the switches you supplied which may be a "); 03064 printf(" piecewise\n"); 03065 printf(" linear complex or a list of nodes. File formats and detailed\n"); 03066 printf(" description of command line switches are found in user's "); 03067 printf("manual.\n"); 03068 printf("\n"); 03069 syntax(); 03070 printf("\n"); 03071 printf("Examples of How to Use TetGen:\n"); 03072 printf("\n"); 03073 printf(" \'tetgen object\' reads vertices from object.node, and writes "); 03074 printf("their\n Delaunay tetrahedralization to object.1.node and "); 03075 printf("object.1.ele.\n"); 03076 printf("\n"); 03077 printf(" \'tetgen -p object\' reads a PLC from object.poly or object."); 03078 printf("smesh (and\n possibly object.node) and writes its constrained "); 03079 printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele and "); 03080 printf("object.1.face.\n"); 03081 printf("\n"); 03082 printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n"); 03083 printf(" object.smesh (and possibly object.node), generates a mesh "); 03084 printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and "); 03085 printf("have volume\n of 0.1 or less, and writes the mesh to "); 03086 printf("object.1.node, object.1.ele\n and object.1.face.\n"); 03087 printf("\n"); 03088 printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n"); 03089 } 03090 03092 // // 03093 // parse_commandline() Read the command line, identify switches, and set // 03094 // up options and file names. // 03095 // // 03096 // 'argc' and 'argv' are the same parameters passed to the function main() // 03097 // of a C/C++ program. They together represent the command line user invoked // 03098 // from an environment in which TetGen is running. // 03099 // // 03100 // When TetGen is invoked from an environment. 'argc' is nonzero, switches // 03101 // and input filename should be supplied as zero-terminated strings in // 03102 // argv[0] through argv[argc - 1] and argv[0] shall be the name used to // 03103 // invoke TetGen, i.e. "tetgen". Switches are previously started with a // 03104 // dash '-' to identify them from the input filename. // 03105 // // 03106 // When TetGen is called from within another program. 'argc' is set to zero. // 03107 // switches are given in one zero-terminated string (no previous dash is // 03108 // required.), and 'argv' is a pointer points to this string. No input // 03109 // filename is required (usually the input data has been directly created by // 03110 // user in the 'tetgenio' structure). A default filename 'tetgen-tmpfile' // 03111 // will be created for debugging output purpose. // 03112 // // 03114 03115 bool tetgenbehavior::parse_commandline(int argc, char **argv) 03116 { 03117 int startindex; 03118 int increment; 03119 int meshnumber; 03120 int scount; 03121 int i, j, k; 03122 char workstring[1024]; 03123 03124 // First determine the input style of the switches. 03125 if (argc == 0) { 03126 startindex = 0; // Switches are given without a dash. 03127 argc = 1; // For running the following for-loop once. 03128 commandline[0] = '\0'; 03129 } else { 03130 startindex = 1; 03131 strcpy(commandline, argv[0]); 03132 strcat(commandline, " "); 03133 } 03134 03135 // Rcount used to count the number of '-R' be used. 03136 scount = 0; 03137 03138 for (i = startindex; i < argc; i++) { 03139 // Remember the command line switches. 03140 strcat(commandline, argv[i]); 03141 strcat(commandline, " "); 03142 if (startindex == 1) { 03143 // Is this string a filename? 03144 if (argv[i][0] != '-') { 03145 strncpy(infilename, argv[i], 1024 - 1); 03146 infilename[1024 - 1] = '\0'; 03147 // Go to the next string directly. 03148 continue; 03149 } 03150 } 03151 // Parse the individual switch from the string. 03152 for (j = startindex; argv[i][j] != '\0'; j++) { 03153 if (argv[i][j] == 'p') { 03154 plc = 1; 03155 } else if (argv[i][j] == 'r') { 03156 refine = 1; 03157 } else if (argv[i][j] == 'R') { 03158 coarse = 1; 03159 } else if (argv[i][j] == 'q') { 03160 quality++; 03161 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03162 (argv[i][j + 1] == '.')) { 03163 k = 0; 03164 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03165 (argv[i][j + 1] == '.')) { 03166 j++; 03167 workstring[k] = argv[i][j]; 03168 k++; 03169 } 03170 workstring[k] = '\0'; 03171 if (quality == 1) { 03172 minratio = (REAL) strtod(workstring, (char **) NULL); 03173 } else if (quality == 2) { 03174 mindihedral = (REAL) strtod(workstring, (char **) NULL); 03175 } else if (quality == 3) { 03176 maxdihedral = (REAL) strtod(workstring, (char **) NULL); 03177 } else if (quality == 4) { 03178 alpha2 = (REAL) strtod(workstring, (char **) NULL); 03179 } else if (quality == 5) { 03180 alpha1 = (REAL) strtod(workstring, (char **) NULL); 03181 } 03182 } 03183 } else if (argv[i][j] == 'm') { 03184 metric++; 03185 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03186 (argv[i][j + 1] == '.')) { 03187 k = 0; 03188 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03189 (argv[i][j + 1] == '.')) { 03190 j++; 03191 workstring[k] = argv[i][j]; 03192 k++; 03193 } 03194 workstring[k] = '\0'; 03195 if (metric == 1) { 03196 alpha1 = (REAL) strtod(workstring, (char **) NULL); 03197 } else if (metric == 2) { 03198 alpha2 = (REAL) strtod(workstring, (char **) NULL); 03199 } 03200 } 03201 } else if (argv[i][j] == 'a') { 03202 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03203 (argv[i][j + 1] == '.')) { 03204 fixedvolume = 1; 03205 k = 0; 03206 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03207 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || 03208 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { 03209 j++; 03210 workstring[k] = argv[i][j]; 03211 k++; 03212 } 03213 workstring[k] = '\0'; 03214 maxvolume = (REAL) strtod(workstring, (char **) NULL); 03215 } else { 03216 varvolume = 1; 03217 } 03218 } else if (argv[i][j] == 'A') { 03219 regionattrib++; 03220 } else if (argv[i][j] == 'i') { 03221 insertaddpoints = 1; 03222 } else if (argv[i][j] == 'd') { 03223 diagnose = 1; 03224 } else if (argv[i][j] == 'z') { 03225 zeroindex = 1; 03226 } else if (argv[i][j] == 'f') { 03227 facesout = 1; 03228 } else if (argv[i][j] == 'e') { 03229 edgesout++; 03230 } else if (argv[i][j] == 'n') { 03231 neighout++; 03232 } else if (argv[i][j] == 'v') { 03233 voroout = 1; 03234 } else if (argv[i][j] == 'g') { 03235 meditview = 1; 03236 } else if (argv[i][j] == 'G') { 03237 gidview = 1; 03238 } else if (argv[i][j] == 'O') { 03239 geomview = 1; 03240 } else if (argv[i][j] == 'M') { 03241 nomerge = 1; 03242 } else if (argv[i][j] == 'Y') { 03243 nobisect++; 03244 } else if (argv[i][j] == 'J') { 03245 nojettison = 1; 03246 } else if (argv[i][j] == 'B') { 03247 nobound = 1; 03248 } else if (argv[i][j] == 'N') { 03249 nonodewritten = 1; 03250 } else if (argv[i][j] == 'E') { 03251 noelewritten = 1; 03252 } else if (argv[i][j] == 'F') { 03253 nofacewritten = 1; 03254 } else if (argv[i][j] == 'I') { 03255 noiterationnum = 1; 03256 } else if (argv[i][j] == 'o') { 03257 if (argv[i][j + 1] == '2') { 03258 j++; 03259 order = 2; 03260 } 03261 } else if (argv[i][j] == 'S') { 03262 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03263 (argv[i][j + 1] == '.')) { 03264 k = 0; 03265 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03266 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || 03267 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { 03268 j++; 03269 workstring[k] = argv[i][j]; 03270 k++; 03271 } 03272 workstring[k] = '\0'; 03273 steiner = (int) strtol(workstring, (char **) NULL, 0); 03274 } 03275 } else if (argv[i][j] == 's') { 03276 scount++; 03277 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03278 (argv[i][j + 1] == '.')) { 03279 k = 0; 03280 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03281 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || 03282 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { 03283 j++; 03284 workstring[k] = argv[i][j]; 03285 k++; 03286 } 03287 workstring[k] = '\0'; 03288 if (scount == 1) { 03289 optlevel = (int) strtol(workstring, (char **) NULL, 0); 03290 } else if (scount == 2) { 03291 optpasses = (int) strtol(workstring, (char **) NULL, 0); 03292 } 03293 } 03294 } else if (argv[i][j] == 'D') { 03295 conformdel++; 03296 } else if (argv[i][j] == 'T') { 03297 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03298 (argv[i][j + 1] == '.')) { 03299 k = 0; 03300 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || 03301 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || 03302 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { 03303 j++; 03304 workstring[k] = argv[i][j]; 03305 k++; 03306 } 03307 workstring[k] = '\0'; 03308 epsilon = (REAL) strtod(workstring, (char **) NULL); 03309 } 03310 } else if (argv[i][j] == 'C') { 03311 docheck++; 03312 } else if (argv[i][j] == 'X') { 03313 fliprepair = 0; 03314 } else if (argv[i][j] == 'Q') { 03315 quiet = 1; 03316 } else if (argv[i][j] == 'V') { 03317 verbose++; 03318 // } else if (argv[i][j] == 'v') { 03319 // versioninfo(); 03320 // terminatetetgen(0); 03321 } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || 03322 (argv[i][j] == '?')) { 03323 usage(); 03324 terminatetetgen(0); 03325 } else { 03326 printf("Warning: Unknown switch -%c.\n", argv[i][j]); 03327 } 03328 } 03329 } 03330 03331 if (startindex == 0) { 03332 // Set a temporary filename for debugging output. 03333 strcpy(infilename, "tetgen-tmpfile"); 03334 } else { 03335 if (infilename[0] == '\0') { 03336 // No input file name. Print the syntax and exit. 03337 syntax(); 03338 terminatetetgen(0); 03339 } 03340 // Recognize the object from file extension if it is available. 03341 if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) { 03342 infilename[strlen(infilename) - 5] = '\0'; 03343 object = NODES; 03344 } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) { 03345 infilename[strlen(infilename) - 5] = '\0'; 03346 object = POLY; 03347 plc = 1; 03348 } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) { 03349 infilename[strlen(infilename) - 6] = '\0'; 03350 object = POLY; 03351 plc = 1; 03352 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) { 03353 infilename[strlen(infilename) - 4] = '\0'; 03354 object = OFF; 03355 plc = 1; 03356 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) { 03357 infilename[strlen(infilename) - 4] = '\0'; 03358 object = PLY; 03359 plc = 1; 03360 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) { 03361 infilename[strlen(infilename) - 4] = '\0'; 03362 object = STL; 03363 plc = 1; 03364 } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) { 03365 infilename[strlen(infilename) - 5] = '\0'; 03366 object = MEDIT; 03367 plc = 1; 03368 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) { 03369 infilename[strlen(infilename) - 4] = '\0'; 03370 object = MESH; 03371 refine = 1; 03372 } 03373 } 03374 plc = plc || diagnose; 03375 useshelles = plc || refine || coarse || quality; 03376 goodratio = minratio; 03377 goodratio *= goodratio; 03378 03379 // Detect improper combinations of switches. 03380 if (plc && refine) { 03381 printf("Error: Switch -r cannot use together with -p.\n"); 03382 return false; 03383 } 03384 if (refine && (plc || noiterationnum)) { 03385 printf("Error: Switches %s cannot use together with -r.\n", 03386 "-p, -d, and -I"); 03387 return false; 03388 } 03389 if (diagnose && (quality || insertaddpoints || (order == 2) || neighout 03390 || docheck)) { 03391 printf("Error: Switches %s cannot use together with -d.\n", 03392 "-q, -i, -o2, -n, and -C"); 03393 return false; 03394 } 03395 03396 // Be careful not to allocate space for element area constraints that 03397 // will never be assigned any value (other than the default -1.0). 03398 if (!refine && !plc) { 03399 varvolume = 0; 03400 } 03401 // Be careful not to add an extra attribute to each element unless the 03402 // input supports it (PLC in, but not refining a preexisting mesh). 03403 if (refine || !plc) { 03404 regionattrib = 0; 03405 } 03406 // If '-a' or '-aa' is in use, enable '-q' option too. 03407 if (fixedvolume || varvolume) { 03408 if (quality == 0) { 03409 quality = 1; 03410 } 03411 } 03412 // Calculate the goodangle for testing bad subfaces. 03413 goodangle = cos(minangle * PI / 180.0); 03414 goodangle *= goodangle; 03415 03416 increment = 0; 03417 strcpy(workstring, infilename); 03418 j = 1; 03419 while (workstring[j] != '\0') { 03420 if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { 03421 increment = j + 1; 03422 } 03423 j++; 03424 } 03425 meshnumber = 0; 03426 if (increment > 0) { 03427 j = increment; 03428 do { 03429 if ((workstring[j] >= '0') && (workstring[j] <= '9')) { 03430 meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); 03431 } else { 03432 increment = 0; 03433 } 03434 j++; 03435 } while (workstring[j] != '\0'); 03436 } 03437 if (noiterationnum) { 03438 strcpy(outfilename, infilename); 03439 } else if (increment == 0) { 03440 strcpy(outfilename, infilename); 03441 strcat(outfilename, ".1"); 03442 } else { 03443 workstring[increment] = '%'; 03444 workstring[increment + 1] = 'd'; 03445 workstring[increment + 2] = '\0'; 03446 sprintf(outfilename, workstring, meshnumber + 1); 03447 } 03448 // Additional input file name has the end ".a". 03449 strcpy(addinfilename, infilename); 03450 strcat(addinfilename, ".a"); 03451 // Background filename has the form "*.b.ele", "*.b.node", ... 03452 strcpy(bgmeshfilename, infilename); 03453 strcat(bgmeshfilename, ".b"); 03454 03455 return true; 03456 } 03457 03458 // 03459 // End of class 'tetgenbehavior' implementation 03460 // 03461 03462 // 03463 // Begin of class 'tetgenmesh' implementation 03464 // 03465 03466 // 03467 // Begin of class 'list', 'memorypool' and 'link' implementation 03468 // 03469 03470 // Following are predefined compare functions for primitive data types. 03471 // These functions take two pointers of the corresponding date type, 03472 // perform the comparation. Return -1, 0 or 1 indicating the default 03473 // linear order of two operators. 03474 03475 // Compare two 'integers'. 03476 int tetgenmesh::compare_2_ints(const void* x, const void* y) { 03477 if (* (int *) x < * (int *) y) { 03478 return -1; 03479 } else if (* (int *) x > * (int *) y) { 03480 return 1; 03481 } else { 03482 return 0; 03483 } 03484 } 03485 03486 // Compare two 'longs'. Note: in 64-bit machine the 'long' type is 64-bit 03487 // (8-byte) where the 'int' only 32-bit (4-byte). 03488 int tetgenmesh::compare_2_longs(const void* x, const void* y) { 03489 if (* (long *) x < * (long *) y) { 03490 return -1; 03491 } else if (* (long *) x > * (long *) y) { 03492 return 1; 03493 } else { 03494 return 0; 03495 } 03496 } 03497 03498 // Compare two 'unsigned longs'. 03499 int tetgenmesh::compare_2_unsignedlongs(const void* x, const void* y) { 03500 if (* (unsigned long *) x < * (unsigned long *) y) { 03501 return -1; 03502 } else if (* (unsigned long *) x > * (unsigned long *) y) { 03503 return 1; 03504 } else { 03505 return 0; 03506 } 03507 } 03508 03510 // // 03511 // set_compfunc() Determine the size of primitive data types and set the // 03512 // corresponding predefined linear order functions. // 03513 // // 03514 // 'str' is a zero-end string indicating a primitive data type, like 'int', // 03515 // 'long' or 'unsigned long'. Every string ending with a '*' is though as a // 03516 // type of pointer and the type 'unsign long' is used for it. // 03517 // // 03518 // When the type of 'str' is determined, the size of this type (in byte) is // 03519 // returned in 'itbytes', and the pointer of corresponding predefined linear // 03520 // order functions is returned in 'pcomp'. // 03521 // // 03523 03524 void tetgenmesh::set_compfunc(char* str, int* itbytes, compfunc* pcomp) 03525 { 03526 // First figure out whether it is a pointer or not. 03527 if (str[strlen(str) - 1] == '*') { 03528 *itbytes = sizeof(unsigned long); 03529 *pcomp = &compare_2_unsignedlongs; 03530 return; 03531 } 03532 // Then determine other types. 03533 if (strcmp(str, "int") == 0) { 03534 *itbytes = sizeof(int); 03535 *pcomp = &compare_2_ints; 03536 } else if (strcmp(str, "long") == 0) { 03537 *itbytes = sizeof(long); 03538 *pcomp = &compare_2_longs; 03539 } else if (strcmp(str, "unsigned long") == 0) { 03540 *itbytes = sizeof(unsigned long); 03541 *pcomp = &compare_2_unsignedlongs; 03542 } else { 03543 // It is an unknown type. 03544 printf("Error in set_compfunc(): unknown type %s.\n", str); 03545 terminatetetgen(1); 03546 } 03547 } 03548 03550 // // 03551 // listinit() Initialize a list for storing a data type. // 03552 // // 03553 // Determine the size of each item, set the maximum size allocated at onece, // 03554 // set the expand size in case the list is full, and set the linear order // 03555 // function if it is provided (default is NULL). // 03556 // // 03558 03559 void tetgenmesh::list:: 03560 listinit(int itbytes, compfunc pcomp, int mitems,int exsize) 03561 { 03562 #ifdef SELF_CHECK 03563 assert(itbytes > 0 && mitems > 0 && exsize > 0); 03564 #endif 03565 itembytes = itbytes; 03566 comp = pcomp; 03567 maxitems = mitems; 03568 expandsize = exsize; 03569 base = (char *) malloc(maxitems * itembytes); 03570 if (base == (char *) NULL) { 03571 printf("Error: Out of memory.\n"); 03572 terminatetetgen(1); 03573 } 03574 items = 0; 03575 } 03576 03578 // // 03579 // append() Add a new item at the end of the list. // 03580 // // 03581 // A new space at the end of this list will be allocated for storing the new // 03582 // item. If the memory is not sufficient, reallocation will be performed. If // 03583 // 'appitem' is not NULL, the contents of this pointer will be copied to the // 03584 // new allocated space. Returns the pointer to the new allocated space. // 03585 // // 03587 03588 void* tetgenmesh::list::append(void *appitem) 03589 { 03590 // Do we have enough space? 03591 if (items == maxitems) { 03592 char* newbase = (char *) realloc(base, (maxitems + expandsize) * 03593 itembytes); 03594 if (newbase == (char *) NULL) { 03595 printf("Error: Out of memory.\n"); 03596 terminatetetgen(1); 03597 } 03598 base = newbase; 03599 maxitems += expandsize; 03600 } 03601 if (appitem != (void *) NULL) { 03602 memcpy(base + items * itembytes, appitem, itembytes); 03603 } 03604 items++; 03605 return (void *) (base + (items - 1) * itembytes); 03606 } 03607 03609 // // 03610 // insert() Insert an item before 'pos' (range from 0 to items - 1). // 03611 // // 03612 // A new space will be inserted at the position 'pos', that is, items lie // 03613 // after pos (including the item at pos) will be moved one space downwords. // 03614 // If 'insitem' is not NULL, its contents will be copied into the new // 03615 // inserted space. Return a pointer to the new inserted space. // 03616 // // 03618 03619 void* tetgenmesh::list::insert(int pos, void* insitem) 03620 { 03621 if (pos >= items) { 03622 return append(insitem); 03623 } 03624 // Do we have enough space. 03625 if (items == maxitems) { 03626 char* newbase = (char *) realloc(base, (maxitems + expandsize) * 03627 itembytes); 03628 if (newbase == (char *) NULL) { 03629 printf("Error: Out of memory.\n"); 03630 terminatetetgen(1); 03631 } 03632 base = newbase; 03633 maxitems += expandsize; 03634 } 03635 // Do block move. 03636 memmove(base + (pos + 1) * itembytes, // dest 03637 base + pos * itembytes, // src 03638 (items - pos) * itembytes); // size in bytes 03639 // Insert the item. 03640 if (insitem != (void *) NULL) { 03641 memcpy(base + pos * itembytes, insitem, itembytes); 03642 } 03643 items++; 03644 return (void *) (base + pos * itembytes); 03645 } 03646 03648 // // 03649 // del() Delete an item at 'pos' (range from 0 to items - 1). // 03650 // // 03651 // The space at 'pos' will be overlapped by other item. If 'order' is 1, the // 03652 // remaining items of the list have the same order as usual, i.e., items lie // 03653 // after pos will be moved one space upwords. If 'order' is 0, the last item // 03654 // of the list will be moved up to pos. // 03655 // // 03657 03658 void tetgenmesh::list::del(int pos, int order) 03659 { 03660 // If 'pos' is the last item of the list, nothing need to do. 03661 if (pos >= 0 && pos < items - 1) { 03662 if (order == 1) { 03663 // Do block move. 03664 memmove(base + pos * itembytes, // dest 03665 base + (pos + 1) * itembytes, // src 03666 (items - pos - 1) * itembytes); 03667 } else { 03668 // Use the last item to overlap the del item. 03669 memcpy(base + pos * itembytes, // item at pos 03670 base + (items - 1) * itembytes, // item at last 03671 itembytes); 03672 } 03673 } 03674 if (items > 0) { 03675 items--; 03676 } 03677 } 03678 03680 // // 03681 // hasitem() Search in this list to find if 'checkitem' exists. // 03682 // // 03683 // This routine assumes that a linear order function has been set. It loops // 03684 // through the entire list, compares each item to 'checkitem'. If it exists, // 03685 // return its position (between 0 to items - 1), otherwise, return -1. // 03686 // // 03688 03689 int tetgenmesh::list::hasitem(void* checkitem) 03690 { 03691 int i; 03692 03693 for (i = 0; i < items; i++) { 03694 if (comp != (compfunc) NULL) { 03695 if ((* comp)((void *)(base + i * itembytes), checkitem) == 0) { 03696 return i; 03697 } 03698 } 03699 } 03700 return -1; 03701 } 03702 03704 // // 03705 // sort() Sort the items with respect to a linear order function. // 03706 // // 03707 // Uses QuickSort routines (qsort) of the standard C/C++ library (stdlib.h). // 03708 // // 03710 03711 void tetgenmesh::list::sort() 03712 { 03713 qsort((void *) base, (size_t) items, (size_t) itembytes, comp); 03714 } 03715 03717 // // 03718 // memorypool() The constructors of memorypool. // 03719 // // 03721 03722 tetgenmesh::memorypool::memorypool() 03723 { 03724 firstblock = nowblock = (void **) NULL; 03725 nextitem = (void *) NULL; 03726 deaditemstack = (void *) NULL; 03727 pathblock = (void **) NULL; 03728 pathitem = (void *) NULL; 03729 itemwordtype = POINTER; 03730 alignbytes = 0; 03731 itembytes = itemwords = 0; 03732 itemsperblock = 0; 03733 items = maxitems = 0l; 03734 unallocateditems = 0; 03735 pathitemsleft = 0; 03736 } 03737 03738 tetgenmesh::memorypool:: 03739 memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment) 03740 { 03741 poolinit(bytecount, itemcount, wtype, alignment); 03742 } 03743 03745 // // 03746 // ~memorypool() Free to the operating system all memory taken by a pool. // 03747 // // 03749 03750 tetgenmesh::memorypool::~memorypool() 03751 { 03752 while (firstblock != (void **) NULL) { 03753 nowblock = (void **) *(firstblock); 03754 free(firstblock); 03755 firstblock = nowblock; 03756 } 03757 } 03758 03760 // // 03761 // poolinit() Initialize a pool of memory for allocation of items. // 03762 // // 03763 // A `pool' is created whose records have size at least `bytecount'. Items // 03764 // will be allocated in `itemcount'-item blocks. Each item is assumed to be // 03765 // a collection of words, and either pointers or floating-point values are // 03766 // assumed to be the "primary" word type. (The "primary" word type is used // 03767 // to determine alignment of items.) If `alignment' isn't zero, all items // 03768 // will be `alignment'-byte aligned in memory. `alignment' must be either a // 03769 // multiple or a factor of the primary word size; powers of two are safe. // 03770 // `alignment' is normally used to create a few unused bits at the bottom of // 03771 // each item's pointer, in which information may be stored. // 03772 // // 03774 03775 void tetgenmesh::memorypool:: 03776 poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment) 03777 { 03778 int wordsize; 03779 03780 // Initialize values in the pool. 03781 itemwordtype = wtype; 03782 wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL); 03783 // Find the proper alignment, which must be at least as large as: 03784 // - The parameter `alignment'. 03785 // - The primary word type, to avoid unaligned accesses. 03786 // - sizeof(void *), so the stack of dead items can be maintained 03787 // without unaligned accesses. 03788 if (alignment > wordsize) { 03789 alignbytes = alignment; 03790 } else { 03791 alignbytes = wordsize; 03792 } 03793 if ((int) sizeof(void *) > alignbytes) { 03794 alignbytes = (int) sizeof(void *); 03795 } 03796 itemwords = ((bytecount + alignbytes - 1) / alignbytes) 03797 * (alignbytes / wordsize); 03798 itembytes = itemwords * wordsize; 03799 itemsperblock = itemcount; 03800 03801 // Allocate a block of items. Space for `itemsperblock' items and one 03802 // pointer (to point to the next block) are allocated, as well as space 03803 // to ensure alignment of the items. 03804 firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) 03805 + alignbytes); 03806 if (firstblock == (void **) NULL) { 03807 printf("Error: Out of memory.\n"); 03808 terminatetetgen(1); 03809 } 03810 // Set the next block pointer to NULL. 03811 *(firstblock) = (void *) NULL; 03812 restart(); 03813 } 03814 03816 // // 03817 // restart() Deallocate all items in this pool. // 03818 // // 03819 // The pool is returned to its starting state, except that no memory is // 03820 // freed to the operating system. Rather, the previously allocated blocks // 03821 // are ready to be reused. // 03822 // // 03824 03825 void tetgenmesh::memorypool::restart() 03826 { 03827 unsigned long alignptr; 03828 03829 items = 0; 03830 maxitems = 0; 03831 03832 // Set the currently active block. 03833 nowblock = firstblock; 03834 // Find the first item in the pool. Increment by the size of (void *). 03835 alignptr = (unsigned long) (nowblock + 1); 03836 // Align the item on an `alignbytes'-byte boundary. 03837 nextitem = (void *) 03838 (alignptr + (unsigned long) alignbytes - 03839 (alignptr % (unsigned long) alignbytes)); 03840 // There are lots of unallocated items left in this block. 03841 unallocateditems = itemsperblock; 03842 // The stack of deallocated items is empty. 03843 deaditemstack = (void *) NULL; 03844 } 03845 03847 // // 03848 // alloc() Allocate space for an item. // 03849 // // 03851 03852 void* tetgenmesh::memorypool::alloc() 03853 { 03854 void *newitem; 03855 void **newblock; 03856 unsigned long alignptr; 03857 03858 // First check the linked list of dead items. If the list is not 03859 // empty, allocate an item from the list rather than a fresh one. 03860 if (deaditemstack != (void *) NULL) { 03861 newitem = deaditemstack; // Take first item in list. 03862 deaditemstack = * (void **) deaditemstack; 03863 } else { 03864 // Check if there are any free items left in the current block. 03865 if (unallocateditems == 0) { 03866 // Check if another block must be allocated. 03867 if (*nowblock == (void *) NULL) { 03868 // Allocate a new block of items, pointed to by the previous block. 03869 newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) 03870 + alignbytes); 03871 if (newblock == (void **) NULL) { 03872 printf("Error: Out of memory.\n"); 03873 terminatetetgen(1); 03874 } 03875 *nowblock = (void *) newblock; 03876 // The next block pointer is NULL. 03877 *newblock = (void *) NULL; 03878 } 03879 // Move to the new block. 03880 nowblock = (void **) *nowblock; 03881 // Find the first item in the block. 03882 // Increment by the size of (void *). 03883 alignptr = (unsigned long) (nowblock + 1); 03884 // Align the item on an `alignbytes'-byte boundary. 03885 nextitem = (void *) 03886 (alignptr + (unsigned long) alignbytes - 03887 (alignptr % (unsigned long) alignbytes)); 03888 // There are lots of unallocated items left in this block. 03889 unallocateditems = itemsperblock; 03890 } 03891 // Allocate a new item. 03892 newitem = nextitem; 03893 // Advance `nextitem' pointer to next free item in block. 03894 if (itemwordtype == POINTER) { 03895 nextitem = (void *) ((void **) nextitem + itemwords); 03896 } else { 03897 nextitem = (void *) ((REAL *) nextitem + itemwords); 03898 } 03899 unallocateditems--; 03900 maxitems++; 03901 } 03902 items++; 03903 return newitem; 03904 } 03905 03907 // // 03908 // dealloc() Deallocate space for an item. // 03909 // // 03910 // The deallocated space is stored in a queue for later reuse. // 03911 // // 03913 03914 void tetgenmesh::memorypool::dealloc(void *dyingitem) 03915 { 03916 // Push freshly killed item onto stack. 03917 *((void **) dyingitem) = deaditemstack; 03918 deaditemstack = dyingitem; 03919 items--; 03920 } 03921 03923 // // 03924 // traversalinit() Prepare to traverse the entire list of items. // 03925 // // 03926 // This routine is used in conjunction with traverse(). // 03927 // // 03929 03930 void tetgenmesh::memorypool::traversalinit() 03931 { 03932 unsigned long alignptr; 03933 03934 // Begin the traversal in the first block. 03935 pathblock = firstblock; 03936 // Find the first item in the block. Increment by the size of (void *). 03937 alignptr = (unsigned long) (pathblock + 1); 03938 // Align with item on an `alignbytes'-byte boundary. 03939 pathitem = (void *) 03940 (alignptr + (unsigned long) alignbytes - 03941 (alignptr % (unsigned long) alignbytes)); 03942 // Set the number of items left in the current block. 03943 pathitemsleft = itemsperblock; 03944 } 03945 03947 // // 03948 // traverse() Find the next item in the list. // 03949 // // 03950 // This routine is used in conjunction with traversalinit(). Be forewarned // 03951 // that this routine successively returns all items in the list, including // 03952 // deallocated ones on the deaditemqueue. It's up to you to figure out which // 03953 // ones are actually dead. It can usually be done more space-efficiently by // 03954 // a routine that knows something about the structure of the item. // 03955 // // 03957 03958 void* tetgenmesh::memorypool::traverse() 03959 { 03960 void *newitem; 03961 unsigned long alignptr; 03962 03963 // Stop upon exhausting the list of items. 03964 if (pathitem == nextitem) { 03965 return (void *) NULL; 03966 } 03967 // Check whether any untraversed items remain in the current block. 03968 if (pathitemsleft == 0) { 03969 // Find the next block. 03970 pathblock = (void **) *pathblock; 03971 // Find the first item in the block. Increment by the size of (void *). 03972 alignptr = (unsigned long) (pathblock + 1); 03973 // Align with item on an `alignbytes'-byte boundary. 03974 pathitem = (void *) 03975 (alignptr + (unsigned long) alignbytes - 03976 (alignptr % (unsigned long) alignbytes)); 03977 // Set the number of items left in the current block. 03978 pathitemsleft = itemsperblock; 03979 } 03980 newitem = pathitem; 03981 // Find the next item in the block. 03982 if (itemwordtype == POINTER) { 03983 pathitem = (void *) ((void **) pathitem + itemwords); 03984 } else { 03985 pathitem = (void *) ((REAL *) pathitem + itemwords); 03986 } 03987 pathitemsleft--; 03988 return newitem; 03989 } 03990 03992 // // 03993 // linkinit() Initialize a link for storing items. // 03994 // // 03995 // The input parameters are the size of each item, a pointer of a linear // 03996 // order function and the number of items allocating in one memory bulk. // 03997 // // 03999 04000 void tetgenmesh::link::linkinit(int bytecount, compfunc pcomp, int itemcount) 04001 { 04002 #ifdef SELF_CHECK 04003 assert(bytecount > 0 && itemcount > 0); 04004 #endif 04005 // Remember the real size of each item. 04006 linkitembytes = bytecount; 04007 // Set the linear order function for this link. 04008 comp = pcomp; 04009 04010 // Call the constructor of 'memorypool' to initialize its variables. 04011 // like: itembytes, itemwords, items, ... Each node has size 04012 // bytecount + 2 * sizeof(void **), and total 'itemcount + 2' (because 04013 // link has additional two nodes 'head' and 'tail'). 04014 poolinit(bytecount + 2 * sizeof(void **), itemcount + 2, POINTER, 0); 04015 04016 // Initial state of this link. 04017 head = (void **) alloc(); 04018 tail = (void **) alloc(); 04019 *head = (void *) tail; 04020 *(head + 1) = NULL; 04021 *tail = NULL; 04022 *(tail + 1) = (void *) head; 04023 nextlinkitem = *head; 04024 curpos = 1; 04025 linkitems = 0; 04026 } 04027 04029 // // 04030 // clear() Deallocate all nodes in this link. // 04031 // // 04032 // The link is returned to its starting state, except that no memory is // 04033 // freed to the operating system. Rather, the previously allocated blocks // 04034 // are ready to be reused. // 04035 // // 04037 04038 void tetgenmesh::link::clear() 04039 { 04040 // Reset the pool. 04041 restart(); 04042 04043 // Initial state of this link. 04044 head = (void **) alloc(); 04045 tail = (void **) alloc(); 04046 *head = (void *) tail; 04047 *(head + 1) = NULL; 04048 *tail = NULL; 04049 *(tail + 1) = (void *) head; 04050 nextlinkitem = *head; 04051 curpos = 1; 04052 linkitems = 0; 04053 } 04054 04056 // // 04057 // move() Causes 'nextlinkitem' to traverse the specified number of nodes,// 04058 // updates 'curpos' to be the node to which 'nextlinkitem' points. // 04059 // // 04060 // 'numberofnodes' is a number indicating how many nodes need be traversed // 04061 // (not counter the current node) need be traversed. It may be positive(move // 04062 // forward) or negative (move backward). Return TRUE if it is successful. // 04063 // // 04065 04066 bool tetgenmesh::link::move(int numberofnodes) 04067 { 04068 void **nownode; 04069 int i; 04070 04071 nownode = (void **) nextlinkitem; 04072 if (numberofnodes > 0) { 04073 // Move forward. 04074 i = 0; 04075 while ((i < numberofnodes) && *nownode) { 04076 nownode = (void **) *nownode; 04077 i++; 04078 } 04079 if (*nownode == NULL) return false; 04080 nextlinkitem = (void *) nownode; 04081 curpos += numberofnodes; 04082 } else if (numberofnodes < 0) { 04083 // Move backward. 04084 i = 0; 04085 numberofnodes = -numberofnodes; 04086 while ((i < numberofnodes) && *(nownode + 1)) { 04087 nownode = (void **) *(nownode + 1); 04088 i++; 04089 } 04090 if (*(nownode + 1) == NULL) return false; 04091 nextlinkitem = (void *) nownode; 04092 curpos -= numberofnodes; 04093 } 04094 return true; 04095 } 04096 04098 // // 04099 // locate() Locates the node at the specified position. // 04100 // // 04101 // The number 'pos' (between 1 and 'linkitems') indicates the location. This // 04102 // routine first decides the shortest path traversing from 'curpos' to 'pos',// 04103 // i.e., from head, tail or 'curpos'. Routine 'move()' is called to really // 04104 // traverse the link. If success, 'nextlinkitem' points to the node, 'curpos'// 04105 // and 'pos' are equal. Otherwise, return FALSE. // 04106 // // 04108 04109 bool tetgenmesh::link::locate(int pos) 04110 { 04111 int headdist, taildist, curdist; 04112 int abscurdist, mindist; 04113 04114 if (pos < 1 || pos > linkitems) return false; 04115 04116 headdist = pos - 1; 04117 taildist = linkitems - pos; 04118 curdist = pos - curpos; 04119 abscurdist = curdist >= 0 ? curdist : -curdist; 04120 04121 if (headdist > taildist) { 04122 if (taildist > abscurdist) { 04123 mindist = curdist; 04124 } else { 04125 // taildist <= abs(curdist) 04126 mindist = -taildist; 04127 goend(); 04128 } 04129 } else { 04130 // headdist <= taildist 04131 if (headdist > abscurdist) { 04132 mindist = curdist; 04133 } else { 04134 // headdist <= abs(curdist) 04135 mindist = headdist; 04136 rewind(); 04137 } 04138 } 04139 04140 return move(mindist); 04141 } 04142 04144 // // 04145 // add() Add a node at the end of this link. // 04146 // // 04147 // A new node is appended to the end of the link. If 'newitem' is not NULL, // 04148 // its conents will be copied to the data slot of the new node. Returns the // 04149 // pointer to the newest added node. // 04150 // // 04152 04153 void* tetgenmesh::link::add(void* newitem) 04154 { 04155 void **newnode = tail; 04156 if (newitem != (void *) NULL) { 04157 memcpy((void *)(newnode + 2), newitem, linkitembytes); 04158 } 04159 tail = (void **) alloc(); 04160 *tail = NULL; 04161 *newnode = (void*) tail; 04162 *(tail + 1) = (void*) newnode; 04163 linkitems++; 04164 return (void *)(newnode + 2); 04165 } 04166 04168 // // 04169 // insert() Inserts a node before the specified position. // 04170 // // 04171 // 'pos' (between 1 and 'linkitems') indicates the inserting position. This // 04172 // routine inserts a new node before the node of 'pos'. If 'newitem' is not // 04173 // NULL, its conents will be copied into the data slot of the new node. If // 04174 // 'pos' is larger than 'linkitems', it is equal as 'add()'. A pointer to // 04175 // the newest inserted item is returned. // 04176 // // 04178 04179 void* tetgenmesh::link::insert(int pos, void* insitem) 04180 { 04181 if (!locate(pos)) { 04182 return add(insitem); 04183 } 04184 04185 void **nownode = (void **) nextlinkitem; 04186 04187 // Insert a node before 'nownode'. 04188 void **newnode = (void **) alloc(); 04189 if (insitem != (void *) NULL) { 04190 memcpy((void *)(newnode + 2), insitem, linkitembytes); 04191 } 04192 04193 *(void **)(*(nownode + 1)) = (void *) newnode; 04194 *newnode = (void *) nownode; 04195 *(newnode + 1) = *(nownode + 1); 04196 *(nownode + 1) = (void *) newnode; 04197 04198 linkitems++; 04199 04200 nextlinkitem = (void *) newnode; 04201 return (void *)(newnode + 2); 04202 } 04203 04205 // // 04206 // del() Delete a node. // 04207 // // 04208 // Returns a pointer of the deleted data. If you try to delete a non-existed // 04209 // node (e.g. link is empty or a wrong index is given) return NULL. // 04210 // // 04212 04213 void* tetgenmesh::link::deletenode(void** deadnode) 04214 { 04215 void **nextnode = (void **) *deadnode; 04216 void **prevnode = (void **) *(deadnode + 1); 04217 *prevnode = (void *) nextnode; 04218 *(nextnode + 1) = (void *) prevnode; 04219 04220 dealloc((void *) deadnode); 04221 linkitems--; 04222 04223 nextlinkitem = (void *) nextnode; 04224 return (void *)(deadnode + 2); 04225 } 04226 04228 // // 04229 // del() Delete a node at the specified position. // 04230 // // 04231 // 'pos' between 1 and 'linkitems'. Returns a pointer of the deleted data. // 04232 // If you try to delete a non-existed node (e.g. link is empty or a wrong // 04233 // index is given) return NULL. // 04234 // // 04236 04237 void* tetgenmesh::link::del(int pos) 04238 { 04239 if (!locate(pos) || (linkitems == 0)) { 04240 return (void *) NULL; 04241 } 04242 return deletenode((void **) nextlinkitem); 04243 } 04244 04246 // // 04247 // getitem() The link traversal routine. // 04248 // // 04249 // Returns the node to which 'nextlinkitem' points. Returns a 'NULL' if the // 04250 // end of the link is reaching. Both 'nextlinkitem' and 'curpos' will be // 04251 // updated after this operation. // 04252 // // 04254 04255 void* tetgenmesh::link::getitem() 04256 { 04257 if (nextlinkitem == (void *) tail) return NULL; 04258 void **nownode = (void **) nextlinkitem; 04259 nextlinkitem = *nownode; 04260 curpos += 1; 04261 return (void *)(nownode + 2); 04262 } 04263 04265 // // 04266 // getnitem() Returns the node at a specified position. // 04267 // // 04268 // 'pos' between 1 and 'linkitems'. After this operation, 'nextlinkitem' and // 04269 // 'curpos' will be updated to indicate this node. // 04270 // // 04272 04273 void* tetgenmesh::link::getnitem(int pos) 04274 { 04275 if (!locate(pos)) return NULL; 04276 return (void *)((void **) nextlinkitem + 2); 04277 } 04278 04280 // // 04281 // hasitem() Search in this link to find if 'checkitem' exists. // 04282 // // 04283 // If 'checkitem' exists, return its position (between 1 to 'linkitems'), // 04284 // otherwise, return -1. This routine requires the linear order function has // 04285 // been set. // 04286 // // 04288 04289 int tetgenmesh::link::hasitem(void* checkitem) 04290 { 04291 void *pathitem; 04292 int count; 04293 04294 rewind(); 04295 pathitem = getitem(); 04296 count = 0; 04297 while (pathitem) { 04298 count ++; 04299 if (comp) { 04300 if ((* comp)(pathitem, checkitem) == 0) { 04301 return count; 04302 } 04303 } 04304 pathitem = getitem(); 04305 } 04306 return -1; 04307 } 04308 04309 // 04310 // End of class 'list', 'memorypool' and 'link' implementation 04311 // 04312 04313 // 04314 // Begin of mesh manipulation primitives 04315 // 04316 04317 // 04318 // Begin of tables initialization. 04319 // 04320 04321 // For enumerating three edges of a triangle. 04322 04323 int tetgenmesh::plus1mod3[3] = {1, 2, 0}; 04324 int tetgenmesh::minus1mod3[3] = {2, 0, 1}; 04325 04326 // Table 've' takes an edge version as input, returns the next edge version 04327 // in the same edge ring. 04328 04329 int tetgenmesh::ve[6] = { 2, 5, 4, 1, 0, 3 }; 04330 04331 // Tables 'vo', 'vd' and 'va' take an edge version, return the positions of 04332 // the origin, destination and apex in the triangle. 04333 04334 int tetgenmesh::vo[6] = { 0, 1, 1, 2, 2, 0 }; 04335 int tetgenmesh::vd[6] = { 1, 0, 2, 1, 0, 2 }; 04336 int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 }; 04337 04338 // The following tables are for tetrahedron primitives (operate on trifaces). 04339 04340 // For 'org()', 'dest()' and 'apex()'. Use 'loc' as the first index and 04341 // 'ver' as the second index. 04342 04343 int tetgenmesh::locver2org[4][6] = { 04344 {0, 1, 1, 2, 2, 0}, 04345 {0, 3, 3, 1, 1, 0}, 04346 {1, 3, 3, 2, 2, 1}, 04347 {2, 3, 3, 0, 0, 2} 04348 }; 04349 int tetgenmesh::locver2dest[4][6] = { 04350 {1, 0, 2, 1, 0, 2}, 04351 {3, 0, 1, 3, 0, 1}, 04352 {3, 1, 2, 3, 1, 2}, 04353 {3, 2, 0, 3, 2, 0} 04354 }; 04355 int tetgenmesh::locver2apex[4][6] = { 04356 {2, 2, 0, 0, 1, 1}, 04357 {1, 1, 0, 0, 3, 3}, 04358 {2, 2, 1, 1, 3, 3}, 04359 {0, 0, 2, 2, 3, 3} 04360 }; 04361 04362 // For oppo() primitives, use 'loc' as the index. 04363 04364 int tetgenmesh::loc2oppo[4] = { 3, 2, 0, 1 }; 04365 04366 // For fnext() primitive. Use 'loc' as the first index and 'ver' as the 04367 // second index. Returns a new 'loc' and new 'ver' in an array. (It is 04368 // only valid for edge version equals one of {0, 2, 4}.) 04369 04370 int tetgenmesh::locver2nextf[4][6][2] = { 04371 { {1, 5}, {-1, -1}, {2, 5}, {-1, -1}, {3, 5}, {-1, -1} }, 04372 { {3, 3}, {-1, -1}, {2, 1}, {-1, -1}, {0, 1}, {-1, -1} }, 04373 { {1, 3}, {-1, -1}, {3, 1}, {-1, -1}, {0, 3}, {-1, -1} }, 04374 { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} } 04375 }; 04376 04377 // The edge number (from 0 to 5) of a tet is defined as follows: 04378 // 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0) 04379 // 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2). 04380 04381 int tetgenmesh::locver2edge[4][6] = { 04382 {0, 0, 1, 1, 2, 2}, 04383 {3, 3, 4, 4, 0, 0}, 04384 {4, 4, 5, 5, 1, 1}, 04385 {5, 5, 3, 3, 2, 2} 04386 }; 04387 04388 int tetgenmesh::edge2locver[6][2] = { 04389 {0, 0}, // 0 v0 -> v1 04390 {0, 2}, // 1 v1 -> v2 04391 {0, 4}, // 2 v2 -> v1 04392 {1, 0}, // 3 v0 -> v3 04393 {1, 2}, // 4 v1 -> v3 04394 {2, 2} // 5 v2 -> v3 04395 }; 04396 04397 // 04398 // End of tables initialization. 04399 // 04400 04401 // Some macros for convenience 04402 04403 #define Div2 >> 1 04404 #define Mod2 & 01 04405 04406 // NOTE: These bit operators should only be used in macros below. 04407 04408 // Get orient(Range from 0 to 2) from face version(Range from 0 to 5). 04409 04410 #define Orient(V) ((V) Div2) 04411 04412 // Determine edge ring(0 or 1) from face version(Range from 0 to 5). 04413 04414 #define EdgeRing(V) ((V) Mod2) 04415 04416 // 04417 // Begin of primitives for tetrahedra 04418 // 04419 04420 // Each tetrahedron contains four pointers to its neighboring tetrahedra, 04421 // with face indices. To save memory, both information are kept in a 04422 // single pointer. To make this possible, all tetrahedra are aligned to 04423 // eight-byte boundaries, so that the last three bits of each pointer are 04424 // zeros. A face index (in the range 0 to 3) is compressed into the last 04425 // two bits of each pointer by the function 'encode()'. The function 04426 // 'decode()' decodes a pointer, extracting a face index and a pointer to 04427 // the beginning of a tetrahedron. 04428 04429 inline void tetgenmesh::decode(tetrahedron ptr, triface& t) { 04430 t.loc = (int) ((unsigned long) (ptr) & (unsigned long) 3l); 04431 t.tet = (tetrahedron *) ((unsigned long) (ptr) & ~(unsigned long) 7l); 04432 } 04433 04434 inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) { 04435 return (tetrahedron) ((unsigned long) t.tet | (unsigned long) t.loc); 04436 } 04437 04438 // sym() finds the abutting tetrahedron on the same face. 04439 04440 inline void tetgenmesh::sym(triface& t1, triface& t2) { 04441 tetrahedron ptr = t1.tet[t1.loc]; 04442 decode(ptr, t2); 04443 } 04444 04445 inline void tetgenmesh::symself(triface& t) { 04446 tetrahedron ptr = t.tet[t.loc]; 04447 decode(ptr, t); 04448 } 04449 04450 // Bond two tetrahedra together at their faces. 04451 04452 inline void tetgenmesh::bond(triface& t1, triface& t2) { 04453 t1.tet[t1.loc] = encode(t2); 04454 t2.tet[t2.loc] = encode(t1); 04455 } 04456 04457 // Dissolve a bond (from one side). Note that the other tetrahedron will 04458 // still think it is connected to this tetrahedron. Usually, however, 04459 // the other tetrahedron is being deleted entirely, or bonded to another 04460 // tetrahedron, so it doesn't matter. 04461 04462 inline void tetgenmesh::dissolve(triface& t) { 04463 t.tet[t.loc] = (tetrahedron) dummytet; 04464 } 04465 04466 // These primitives determine or set the origin, destination, apex or 04467 // opposition of a tetrahedron with respect to 'loc' and 'ver'. 04468 04469 inline tetgenmesh::point tetgenmesh::org(triface& t) { 04470 return (point) t.tet[locver2org[t.loc][t.ver] + 4]; 04471 } 04472 04473 inline tetgenmesh::point tetgenmesh::dest(triface& t) { 04474 return (point) t.tet[locver2dest[t.loc][t.ver] + 4]; 04475 } 04476 04477 inline tetgenmesh::point tetgenmesh::apex(triface& t) { 04478 return (point) t.tet[locver2apex[t.loc][t.ver] + 4]; 04479 } 04480 04481 inline tetgenmesh::point tetgenmesh::oppo(triface& t) { 04482 return (point) t.tet[loc2oppo[t.loc] + 4]; 04483 } 04484 04485 inline void tetgenmesh::setorg(triface& t, point pointptr) { 04486 t.tet[locver2org[t.loc][t.ver] + 4] = (tetrahedron) pointptr; 04487 } 04488 04489 inline void tetgenmesh::setdest(triface& t, point pointptr) { 04490 t.tet[locver2dest[t.loc][t.ver] + 4] = (tetrahedron) pointptr; 04491 } 04492 04493 inline void tetgenmesh::setapex(triface& t, point pointptr) { 04494 t.tet[locver2apex[t.loc][t.ver] + 4] = (tetrahedron) pointptr; 04495 } 04496 04497 inline void tetgenmesh::setoppo(triface& t, point pointptr) { 04498 t.tet[loc2oppo[t.loc] + 4] = (tetrahedron) pointptr; 04499 } 04500 04501 // These primitives were drived from Mucke's triangle-edge data structure 04502 // to change face-edge relation in a tetrahedron (esym, enext and enext2) 04503 // or between two tetrahedra (fnext). 04504 04505 // If e0 = e(i, j), e1 = e(j, i), that is e0 and e1 are the two directions 04506 // of the same undirected edge of a face. e0.sym() = e1 and vice versa. 04507 04508 inline void tetgenmesh::esym(triface& t1, triface& t2) { 04509 t2.tet = t1.tet; 04510 t2.loc = t1.loc; 04511 t2.ver = t1.ver + (EdgeRing(t1.ver) ? -1 : 1); 04512 } 04513 04514 inline void tetgenmesh::esymself(triface& t) { 04515 t.ver += (EdgeRing(t.ver) ? -1 : 1); 04516 } 04517 04518 // If e0 and e1 are both in the same edge ring of a face, e1 = e0.enext(). 04519 04520 inline void tetgenmesh::enext(triface& t1, triface& t2) { 04521 t2.tet = t1.tet; 04522 t2.loc = t1.loc; 04523 t2.ver = ve[t1.ver]; 04524 } 04525 04526 inline void tetgenmesh::enextself(triface& t) { 04527 t.ver = ve[t.ver]; 04528 } 04529 04530 // enext2() is equal to e2 = e0.enext().enext() 04531 04532 inline void tetgenmesh::enext2(triface& t1, triface& t2) { 04533 t2.tet = t1.tet; 04534 t2.loc = t1.loc; 04535 t2.ver = ve[ve[t1.ver]]; 04536 } 04537 04538 inline void tetgenmesh::enext2self(triface& t) { 04539 t.ver = ve[ve[t.ver]]; 04540 } 04541 04542 // If f0 and f1 are both in the same face ring of a face, f1 = f0.fnext(). 04543 // If f1 exists, return true. Otherwise, return false, i.e., f0 is a 04544 // boundary or hull face. 04545 04546 inline bool tetgenmesh::fnext(triface& t1, triface& t2) 04547 { 04548 // Get the next face. 04549 t2.loc = locver2nextf[t1.loc][t1.ver][0]; 04550 // Is the next face in the same tet? 04551 if (t2.loc != -1) { 04552 // It's in the same tet. Get the edge version. 04553 t2.ver = locver2nextf[t1.loc][t1.ver][1]; 04554 t2.tet = t1.tet; 04555 } else { 04556 // The next face is in the neigbhour of 't1'. 04557 sym(t1, t2); 04558 if (t2.tet != dummytet) { 04559 // Find the corresponding edge in t2. 04560 point torg; 04561 int tloc, tver, i; 04562 t2.ver = 0; 04563 torg = org(t1); 04564 for (i = 0; (i < 3) && (org(t2) != torg); i++) { 04565 enextself(t2); 04566 } 04567 // Go to the next face in t2. 04568 tloc = t2.loc; 04569 tver = t2.ver; 04570 t2.loc = locver2nextf[tloc][tver][0]; 04571 t2.ver = locver2nextf[tloc][tver][1]; 04572 } 04573 } 04574 return t2.tet != dummytet; 04575 } 04576 04577 inline bool tetgenmesh::fnextself(triface& t1) 04578 { 04579 triface t2; 04580 04581 // Get the next face. 04582 t2.loc = locver2nextf[t1.loc][t1.ver][0]; 04583 // Is the next face in the same tet? 04584 if (t2.loc != -1) { 04585 // It's in the same tet. Get the edge version. 04586 t2.ver = locver2nextf[t1.loc][t1.ver][1]; 04587 t1.loc = t2.loc; 04588 t1.ver = t2.ver; 04589 } else { 04590 // The next face is in the neigbhour of 't1'. 04591 sym(t1, t2); 04592 if (t2.tet != dummytet) { 04593 // Find the corresponding edge in t2. 04594 point torg; 04595 int i; 04596 t2.ver = 0; 04597 torg = org(t1); 04598 for (i = 0; (i < 3) && (org(t2) != torg); i++) { 04599 enextself(t2); 04600 } 04601 t1.loc = locver2nextf[t2.loc][t2.ver][0]; 04602 t1.ver = locver2nextf[t2.loc][t2.ver][1]; 04603 t1.tet = t2.tet; 04604 } 04605 } 04606 return t2.tet != dummytet; 04607 } 04608 04609 // enextfnext() and enext2fnext() are combination primitives of enext(), 04610 // enext2() and fnext(). 04611 04612 inline void tetgenmesh::enextfnext(triface& t1, triface& t2) { 04613 enext(t1, t2); 04614 fnextself(t2); 04615 } 04616 04617 inline void tetgenmesh::enextfnextself(triface& t) { 04618 enextself(t); 04619 fnextself(t); 04620 } 04621 04622 inline void tetgenmesh::enext2fnext(triface& t1, triface& t2) { 04623 enext2(t1, t2); 04624 fnextself(t2); 04625 } 04626 04627 inline void tetgenmesh::enext2fnextself(triface& t) { 04628 enext2self(t); 04629 fnextself(t); 04630 } 04631 04632 // Primitives to infect or cure a tetrahedron with the virus. The last 04633 // third bit of the pointer is marked for infection. These rely on the 04634 // assumption that all tetrahedron are aligned to eight-byte boundaries. 04635 04636 inline void tetgenmesh::infect(triface& t) { 04637 t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] | (unsigned long) 4l); 04638 } 04639 04640 inline void tetgenmesh::uninfect(triface& t) { 04641 t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] & ~ (unsigned long) 4l); 04642 } 04643 04644 // Test a tetrahedron for viral infection. 04645 04646 inline bool tetgenmesh::infected(triface& t) { 04647 return (((unsigned long) t.tet[0] & (unsigned long) 4l) != 0); 04648 } 04649 04650 // Check or set a tetrahedron's attributes. 04651 04652 inline REAL tetgenmesh::elemattribute(tetrahedron* ptr, int attnum) { 04653 return ((REAL *) (ptr))[elemattribindex + attnum]; 04654 } 04655 04656 inline void tetgenmesh:: 04657 setelemattribute(tetrahedron* ptr, int attnum, REAL value){ 04658 ((REAL *) (ptr))[elemattribindex + attnum] = value; 04659 } 04660 04661 // Check or set a tetrahedron's maximum volume bound. 04662 04663 inline REAL tetgenmesh::volumebound(tetrahedron* ptr) { 04664 return ((REAL *) (ptr))[volumeboundindex]; 04665 } 04666 04667 inline void tetgenmesh::setvolumebound(tetrahedron* ptr, REAL value) { 04668 ((REAL *) (ptr))[volumeboundindex] = value; 04669 } 04670 04671 // 04672 // End of primitives for tetrahedra 04673 // 04674 04675 // 04676 // Begin of primitives for subfaces/subsegments 04677 // 04678 04679 // Each subface contains three pointers to its neighboring subfaces, with 04680 // edge versions. To save memory, both information are kept in a single 04681 // pointer. To make this possible, all subfaces are aligned to eight-byte 04682 // boundaries, so that the last three bits of each pointer are zeros. An 04683 // edge version (in the range 0 to 5) is compressed into the last three 04684 // bits of each pointer by 'sencode()'. 'sdecode()' decodes a pointer, 04685 // extracting an edge version and a pointer to the beginning of a subface. 04686 04687 inline void tetgenmesh::sdecode(shellface sptr, face& s) { 04688 s.shver = (int) ((unsigned long) (sptr) & (unsigned long) 7l); 04689 s.sh = (shellface *) ((unsigned long) (sptr) & ~ (unsigned long) 7l); 04690 } 04691 04692 inline tetgenmesh::shellface tetgenmesh::sencode(face& s) { 04693 return (shellface) ((unsigned long) s.sh | (unsigned long) s.shver); 04694 } 04695 04696 // spivot() finds the other subface (from this subface) that shares the 04697 // same edge. 04698 04699 inline void tetgenmesh::spivot(face& s1, face& s2) { 04700 shellface sptr = s1.sh[Orient(s1.shver)]; 04701 sdecode(sptr, s2); 04702 } 04703 04704 inline void tetgenmesh::spivotself(face& s) { 04705 shellface sptr = s.sh[Orient(s.shver)]; 04706 sdecode(sptr, s); 04707 } 04708 04709 // sbond() bonds two subfaces together, i.e., after bonding, both faces 04710 // are pointing to each other. 04711 04712 inline void tetgenmesh::sbond(face& s1, face& s2) { 04713 s1.sh[Orient(s1.shver)] = sencode(s2); 04714 s2.sh[Orient(s2.shver)] = sencode(s1); 04715 } 04716 04717 // sbond1() only bonds s2 to s1, i.e., after bonding, s1 is pointing to s2, 04718 // but s2 is not pointing to s1. 04719 04720 inline void tetgenmesh::sbond1(face& s1, face& s2) { 04721 s1.sh[Orient(s1.shver)] = sencode(s2); 04722 } 04723 04724 // Dissolve a subface bond (from one side). Note that the other subface 04725 // will still think it's connected to this subface. 04726 04727 inline void tetgenmesh::sdissolve(face& s) { 04728 s.sh[Orient(s.shver)] = (shellface) dummysh; 04729 } 04730 04731 // These primitives determine or set the origin, destination, or apex 04732 // of a subface with respect to the edge version. 04733 04734 inline tetgenmesh::point tetgenmesh::sorg(face& s) { 04735 return (point) s.sh[3 + vo[s.shver]]; 04736 } 04737 04738 inline tetgenmesh::point tetgenmesh::sdest(face& s) { 04739 return (point) s.sh[3 + vd[s.shver]]; 04740 } 04741 04742 inline tetgenmesh::point tetgenmesh::sapex(face& s) { 04743 return (point) s.sh[3 + va[s.shver]]; 04744 } 04745 04746 inline void tetgenmesh::setsorg(face& s, point pointptr) { 04747 s.sh[3 + vo[s.shver]] = (shellface) pointptr; 04748 } 04749 04750 inline void tetgenmesh::setsdest(face& s, point pointptr) { 04751 s.sh[3 + vd[s.shver]] = (shellface) pointptr; 04752 } 04753 04754 inline void tetgenmesh::setsapex(face& s, point pointptr) { 04755 s.sh[3 + va[s.shver]] = (shellface) pointptr; 04756 } 04757 04758 // These primitives were drived from Mucke[2]'s triangle-edge data structure 04759 // to change face-edge relation in a subface (sesym, senext and senext2). 04760 04761 inline void tetgenmesh::sesym(face& s1, face& s2) { 04762 s2.sh = s1.sh; 04763 s2.shver = s1.shver + (EdgeRing(s1.shver) ? -1 : 1); 04764 } 04765 04766 inline void tetgenmesh::sesymself(face& s) { 04767 s.shver += (EdgeRing(s.shver) ? -1 : 1); 04768 } 04769 04770 inline void tetgenmesh::senext(face& s1, face& s2) { 04771 s2.sh = s1.sh; 04772 s2.shver = ve[s1.shver]; 04773 } 04774 04775 inline void tetgenmesh::senextself(face& s) { 04776 s.shver = ve[s.shver]; 04777 } 04778 04779 inline void tetgenmesh::senext2(face& s1, face& s2) { 04780 s2.sh = s1.sh; 04781 s2.shver = ve[ve[s1.shver]]; 04782 } 04783 04784 inline void tetgenmesh::senext2self(face& s) { 04785 s.shver = ve[ve[s.shver]]; 04786 } 04787 04788 // If f0 and f1 are both in the same face ring, then f1 = f0.fnext(), 04789 04790 inline void tetgenmesh::sfnext(face& s1, face& s2) { 04791 getnextsface(&s1, &s2); 04792 } 04793 04794 inline void tetgenmesh::sfnextself(face& s) { 04795 getnextsface(&s, NULL); 04796 } 04797 04798 // These primitives read or set a pointer of the badface structure. The 04799 // pointer is stored sh[11]. 04800 04801 inline tetgenmesh::badface* tetgenmesh::shell2badface(face& s) { 04802 return (badface*) s.sh[11]; 04803 } 04804 04805 inline void tetgenmesh::setshell2badface(face& s, badface* value) { 04806 s.sh[11] = (shellface) value; 04807 } 04808 04809 // Check or set a subface's maximum area bound. 04810 04811 inline REAL tetgenmesh::areabound(face& s) { 04812 return ((REAL *) (s.sh))[areaboundindex]; 04813 } 04814 04815 inline void tetgenmesh::setareabound(face& s, REAL value) { 04816 ((REAL *) (s.sh))[areaboundindex] = value; 04817 } 04818 04819 // These two primitives read or set a shell marker. Shell markers are used 04820 // to hold user boundary information. 04821 04822 inline int tetgenmesh::shellmark(face& s) { 04823 return ((int *) (s.sh))[shmarkindex]; 04824 } 04825 04826 inline void tetgenmesh::setshellmark(face& s, int value) { 04827 ((int *) (s.sh))[shmarkindex] = value; 04828 } 04829 04830 // These two primitives set or read the type of the subface or subsegment. 04831 04832 inline enum tetgenmesh::shestype tetgenmesh::shelltype(face& s) { 04833 return (enum shestype) ((int *) (s.sh))[shmarkindex + 1]; 04834 } 04835 04836 inline void tetgenmesh::setshelltype(face& s, enum shestype value) { 04837 ((int *) (s.sh))[shmarkindex + 1] = (int) value; 04838 } 04839 04840 // These two primitives set or read the pbc group of the subface. 04841 04842 inline int tetgenmesh::shellpbcgroup(face& s) { 04843 return ((int *) (s.sh))[shmarkindex + 2]; 04844 } 04845 04846 inline void tetgenmesh::setshellpbcgroup(face& s, int value) { 04847 ((int *) (s.sh))[shmarkindex + 2] = value; 04848 } 04849 04850 // Primitives to infect or cure a subface with the virus. These rely on the 04851 // assumption that all tetrahedra are aligned to eight-byte boundaries. 04852 04853 inline void tetgenmesh::sinfect(face& s) { 04854 s.sh[6] = (shellface) ((unsigned long) s.sh[6] | (unsigned long) 4l); 04855 } 04856 04857 inline void tetgenmesh::suninfect(face& s) { 04858 s.sh[6] = (shellface)((unsigned long) s.sh[6] & ~(unsigned long) 4l); 04859 } 04860 04861 // Test a subface for viral infection. 04862 04863 inline bool tetgenmesh::sinfected(face& s) { 04864 return (((unsigned long) s.sh[6] & (unsigned long) 4l) != 0); 04865 } 04866 04867 // 04868 // End of primitives for subfaces/subsegments 04869 // 04870 04871 // 04872 // Begin of primitives for interacting between tetrahedra and subfaces 04873 // 04874 04875 // tspivot() finds a subface abutting on this tetrahdera. 04876 04877 inline void tetgenmesh::tspivot(triface& t, face& s) { 04878 shellface sptr = (shellface) t.tet[8 + t.loc]; 04879 sdecode(sptr, s); 04880 } 04881 04882 // stpivot() finds a tetrahedron abutting a subface. 04883 04884 inline void tetgenmesh::stpivot(face& s, triface& t) { 04885 tetrahedron ptr = (tetrahedron) s.sh[6 + EdgeRing(s.shver)]; 04886 decode(ptr, t); 04887 } 04888 04889 // tsbond() bond a tetrahedron to a subface. 04890 04891 inline void tetgenmesh::tsbond(triface& t, face& s) { 04892 t.tet[8 + t.loc] = (tetrahedron) sencode(s); 04893 s.sh[6 + EdgeRing(s.shver)] = (shellface) encode(t); 04894 } 04895 04896 // tsdissolve() dissolve a bond (from the tetrahedron side). 04897 04898 inline void tetgenmesh::tsdissolve(triface& t) { 04899 t.tet[8 + t.loc] = (tetrahedron) dummysh; 04900 } 04901 04902 // stdissolve() dissolve a bond (from the subface side). 04903 04904 inline void tetgenmesh::stdissolve(face& s) { 04905 s.sh[6 + EdgeRing(s.shver)] = (shellface) dummytet; 04906 } 04907 04908 // 04909 // End of primitives for interacting between tetrahedra and subfaces 04910 // 04911 04912 // 04913 // Begin of primitives for interacting between subfaces and subsegs 04914 // 04915 04916 // sspivot() finds a subsegment abutting a subface. 04917 04918 inline void tetgenmesh::sspivot(face& s, face& edge) { 04919 shellface sptr = (shellface) s.sh[8 + Orient(s.shver)]; 04920 sdecode(sptr, edge); 04921 } 04922 04923 // ssbond() bond a subface to a subsegment. 04924 04925 inline void tetgenmesh::ssbond(face& s, face& edge) { 04926 s.sh[8 + Orient(s.shver)] = sencode(edge); 04927 edge.sh[0] = sencode(s); 04928 } 04929 04930 // ssdisolve() dissolve a bond (from the subface side) 04931 04932 inline void tetgenmesh::ssdissolve(face& s) { 04933 s.sh[8 + Orient(s.shver)] = (shellface) dummysh; 04934 } 04935 04936 // 04937 // End of primitives for interacting between subfaces and subsegs 04938 // 04939 04940 // 04941 // Begin of primitives for interacting between tet and subsegs. 04942 // 04943 04944 inline void tetgenmesh::tsspivot1(triface& t, face& seg) 04945 { 04946 shellface sptr = (shellface) t.tet[8 + locver2edge[t.loc][t.ver]]; 04947 sdecode(sptr, seg); 04948 } 04949 04950 // Only bond/dissolve at tet's side, but not vice versa. 04951 04952 inline void tetgenmesh::tssbond1(triface& t, face& seg) 04953 { 04954 t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) sencode(seg); 04955 } 04956 04957 inline void tetgenmesh::tssdissolve1(triface& t) 04958 { 04959 t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) dummysh; 04960 } 04961 04962 // 04963 // End of primitives for interacting between tet and subsegs. 04964 // 04965 04966 // 04967 // Begin of primitives for points 04968 // 04969 04970 inline int tetgenmesh::pointmark(point pt) { 04971 return ((int *) (pt))[pointmarkindex]; 04972 } 04973 04974 inline void tetgenmesh::setpointmark(point pt, int value) { 04975 ((int *) (pt))[pointmarkindex] = value; 04976 } 04977 04978 // These two primitives set and read the type of the point. 04979 04980 inline enum tetgenmesh::verttype tetgenmesh::pointtype(point pt) { 04981 return (enum verttype) ((int *) (pt))[pointmarkindex + 1]; 04982 } 04983 04984 inline void tetgenmesh::setpointtype(point pt, enum verttype value) { 04985 ((int *) (pt))[pointmarkindex + 1] = (int) value; 04986 } 04987 04988 // These following primitives set and read a pointer to a tetrahedron 04989 // a subface/subsegment, a point, or a tet of background mesh. 04990 04991 inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) { 04992 return ((tetrahedron *) (pt))[point2simindex]; 04993 } 04994 04995 inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) { 04996 ((tetrahedron *) (pt))[point2simindex] = value; 04997 } 04998 04999 inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) { 05000 return (shellface) ((tetrahedron *) (pt))[point2simindex + 1]; 05001 } 05002 05003 inline void tetgenmesh::setpoint2sh(point pt, shellface value) { 05004 ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value; 05005 } 05006 05007 inline tetgenmesh::point tetgenmesh::point2ppt(point pt) { 05008 return (point) ((tetrahedron *) (pt))[point2simindex + 2]; 05009 } 05010 05011 inline void tetgenmesh::setpoint2ppt(point pt, point value) { 05012 ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value; 05013 } 05014 05015 inline tetgenmesh::tetrahedron tetgenmesh::point2bgmtet(point pt) { 05016 return ((tetrahedron *) (pt))[point2simindex + 3]; 05017 } 05018 05019 inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) { 05020 ((tetrahedron *) (pt))[point2simindex + 3] = value; 05021 } 05022 05023 // These primitives set and read a pointer to its pbc point. 05024 05025 inline tetgenmesh::point tetgenmesh::point2pbcpt(point pt) { 05026 return (point) ((tetrahedron *) (pt))[point2pbcptindex]; 05027 } 05028 05029 inline void tetgenmesh::setpoint2pbcpt(point pt, point value) { 05030 ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value; 05031 } 05032 05033 // 05034 // End of primitives for points 05035 // 05036 05037 // 05038 // Begin of advanced primitives 05039 // 05040 05041 // adjustedgering() adjusts the edge version so that it belongs to the 05042 // indicated edge ring. The 'direction' only can be 0(CCW) or 1(CW). 05043 // If the edge is not in the wanted edge ring, reverse it. 05044 05045 inline void tetgenmesh::adjustedgering(triface& t, int direction) { 05046 if (EdgeRing(t.ver) != direction) { 05047 esymself(t); 05048 } 05049 } 05050 05051 inline void tetgenmesh::adjustedgering(face& s, int direction) { 05052 if (EdgeRing(s.shver) != direction) { 05053 sesymself(s); 05054 } 05055 } 05056 05057 // isdead() returns TRUE if the tetrahedron or subface has been dealloced. 05058 05059 inline bool tetgenmesh::isdead(triface* t) { 05060 if (t->tet == (tetrahedron *) NULL) return true; 05061 else return t->tet[4] == (tetrahedron) NULL; 05062 } 05063 05064 inline bool tetgenmesh::isdead(face* s) { 05065 if (s->sh == (shellface *) NULL) return true; 05066 else return s->sh[3] == (shellface) NULL; 05067 } 05068 05069 // isfacehaspoint() returns TRUE if the 'testpoint' is one of the vertices 05070 // of the tetface 't' subface 's'. 05071 05072 inline bool tetgenmesh::isfacehaspoint(triface* t, point testpoint) { 05073 return ((org(*t) == testpoint) || (dest(*t) == testpoint) || 05074 (apex(*t) == testpoint)); 05075 } 05076 05077 inline bool tetgenmesh::isfacehaspoint(face* s, point testpoint) { 05078 return (s->sh[3] == (shellface) testpoint) || 05079 (s->sh[4] == (shellface) testpoint) || 05080 (s->sh[5] == (shellface) testpoint); 05081 } 05082 05083 // isfacehasedge() returns TRUE if the edge (given by its two endpoints) is 05084 // one of the three edges of the subface 's'. 05085 05086 inline bool tetgenmesh::isfacehasedge(face* s, point tend1, point tend2) { 05087 return (isfacehaspoint(s, tend1) && isfacehaspoint(s, tend2)); 05088 } 05089 05090 // issymexist() returns TRUE if the adjoining tetrahedron is not 'duumytet'. 05091 05092 inline bool tetgenmesh::issymexist(triface* t) { 05093 tetrahedron *ptr = (tetrahedron *) 05094 ((unsigned long)(t->tet[t->loc]) & ~(unsigned long)7l); 05095 return ptr != dummytet; 05096 } 05097 05099 // // 05100 // getnextsface() Finds the next subface in the face ring. // 05101 // // 05102 // For saving space in the data structure of subface, there only exists one // 05103 // face ring around a segment (see programming manual). This routine imple- // 05104 // ments the double face ring as desired in Muecke's data structure. // 05105 // // 05107 05108 void tetgenmesh::getnextsface(face* s1, face* s2) 05109 { 05110 face neighsh, spinsh; 05111 face testseg; 05112 05113 sspivot(*s1, testseg); 05114 if (testseg.sh != dummysh) { 05115 testseg.shver = 0; 05116 if (sorg(testseg) == sorg(*s1)) { 05117 spivot(*s1, neighsh); 05118 } else { 05119 spinsh = *s1; 05120 do { 05121 neighsh = spinsh; 05122 spivotself(spinsh); 05123 } while (spinsh.sh != s1->sh); 05124 } 05125 } else { 05126 spivot(*s1, neighsh); 05127 } 05128 if (sorg(neighsh) != sorg(*s1)) { 05129 sesymself(neighsh); 05130 } 05131 if (s2 != (face *) NULL) { 05132 *s2 = neighsh; 05133 } else { 05134 *s1 = neighsh; 05135 } 05136 } 05137 05139 // // 05140 // tsspivot() Finds a subsegment abutting on a tetrahderon's edge. // 05141 // // 05142 // The edge is represented in the primary edge of 'checkedge'. If there is a // 05143 // subsegment bonded at this edge, it is returned in handle 'checkseg', the // 05144 // edge direction of 'checkseg' is conformed to 'checkedge'. If there isn't, // 05145 // set 'checkseg.sh = dummysh' to indicate it is not a subsegment. // 05146 // // 05147 // To find whether an edge of a tetrahedron is a subsegment or not. First we // 05148 // need find a subface around this edge to see if it contains a subsegment. // 05149 // The reason is there is no direct connection between a tetrahedron and its // 05150 // adjoining subsegments. // 05151 // // 05153 05154 void tetgenmesh::tsspivot(triface* checkedge, face* checkseg) 05155 { 05156 triface spintet; 05157 face parentsh; 05158 point tapex; 05159 int hitbdry; 05160 05161 spintet = *checkedge; 05162 tapex = apex(*checkedge); 05163 hitbdry = 0; 05164 do { 05165 tspivot(spintet, parentsh); 05166 // Does spintet have a (non-fake) subface attached? 05167 if ((parentsh.sh != dummysh) && (sapex(parentsh) != NULL)) { 05168 // Find a subface! Find the edge in it. 05169 findedge(&parentsh, org(*checkedge), dest(*checkedge)); 05170 sspivot(parentsh, *checkseg); 05171 if (checkseg->sh != dummysh) { 05172 // Find a subsegment! Correct its edge direction before return. 05173 if (sorg(*checkseg) != org(*checkedge)) { 05174 sesymself(*checkseg); 05175 } 05176 } 05177 return; 05178 } 05179 if (!fnextself(spintet)) { 05180 hitbdry++; 05181 if (hitbdry < 2) { 05182 esym(*checkedge, spintet); 05183 if (!fnextself(spintet)) { 05184 hitbdry++; 05185 } 05186 } 05187 } 05188 } while ((apex(spintet) != tapex) && (hitbdry < 2)); 05189 // Not find. 05190 checkseg->sh = dummysh; 05191 } 05192 05194 // // 05195 // sstpivot() Finds a tetrahedron abutting a subsegment. // 05196 // // 05197 // This is the inverse operation of 'tsspivot()'. One subsegment shared by // 05198 // arbitrary number of tetrahedron, the returned tetrahedron is not unique. // 05199 // The edge direction of the returned tetrahedron is conformed to the given // 05200 // subsegment. // 05201 // // 05203 05204 void tetgenmesh::sstpivot(face* checkseg, triface* retedge) 05205 { 05206 face parentsh; 05207 05208 // Get the subface which holds the subsegment. 05209 sdecode(checkseg->sh[0], parentsh); 05210 #ifdef SELF_CHECK 05211 assert(parentsh.sh != dummysh); 05212 #endif 05213 // Get a tetraheron to which the subface attches. 05214 stpivot(parentsh, *retedge); 05215 if (retedge->tet == dummytet) { 05216 sesymself(parentsh); 05217 stpivot(parentsh, *retedge); 05218 #ifdef SELF_CHECK 05219 assert(retedge->tet != dummytet); 05220 #endif 05221 } 05222 // Correct the edge direction before return. 05223 findedge(retedge, sorg(*checkseg), sdest(*checkseg)); 05224 } 05225 05227 // // 05228 // findorg() Finds a point in the given handle (tetrahedron or subface). // 05229 // // 05230 // If 'dorg' is a one of vertices of the given handle, set the origin of // 05231 // this handle be that point and return TRUE. Otherwise, return FALSE and // 05232 // 'tface' remains unchanged. // 05233 // // 05235 05236 bool tetgenmesh::findorg(triface* tface, point dorg) 05237 { 05238 if (org(*tface) == dorg) { 05239 return true; 05240 } else { 05241 if (dest(*tface) == dorg) { 05242 enextself(*tface); 05243 return true; 05244 } else { 05245 if (apex(*tface) == dorg) { 05246 enext2self(*tface); 05247 return true; 05248 } else { 05249 if (oppo(*tface) == dorg) { 05250 // Keep 'tface' referring to the same tet after fnext(). 05251 adjustedgering(*tface, CCW); 05252 fnextself(*tface); 05253 enext2self(*tface); 05254 return true; 05255 } 05256 } 05257 } 05258 } 05259 return false; 05260 } 05261 05262 bool tetgenmesh::findorg(face* sface, point dorg) 05263 { 05264 if (sorg(*sface) == dorg) { 05265 return true; 05266 } else { 05267 if (sdest(*sface) == dorg) { 05268 senextself(*sface); 05269 return true; 05270 } else { 05271 if (sapex(*sface) == dorg) { 05272 senext2self(*sface); 05273 return true; 05274 } 05275 } 05276 } 05277 return false; 05278 } 05279 05281 // // 05282 // findedge() Find an edge in the given handle (tetrahedron or subface). // 05283 // // 05284 // The edge is given in two points 'eorg' and 'edest'. It is assumed that // 05285 // the edge must exist in the given handle (tetrahedron or subface). This // 05286 // routine sets the right edge version for the input handle. // 05287 // // 05289 05290 void tetgenmesh::findedge(triface* tface, point eorg, point edest) 05291 { 05292 int i; 05293 05294 for (i = 0; i < 3; i++) { 05295 if (org(*tface) == eorg) { 05296 if (dest(*tface) == edest) { 05297 // Edge is found, return. 05298 return; 05299 } 05300 } else { 05301 if (org(*tface) == edest) { 05302 if (dest(*tface) == eorg) { 05303 // Edge is found, inverse the direction and return. 05304 esymself(*tface); 05305 return; 05306 } 05307 } 05308 } 05309 enextself(*tface); 05310 } 05311 // It should never be here. 05312 printf("Internalerror in findedge(): Unable to find an edge in tet.\n"); 05313 internalerror(); 05314 } 05315 05316 void tetgenmesh::findedge(face* sface, point eorg, point edest) 05317 { 05318 int i; 05319 05320 for (i = 0; i < 3; i++) { 05321 if (sorg(*sface) == eorg) { 05322 if (sdest(*sface) == edest) { 05323 // Edge is found, return. 05324 return; 05325 } 05326 } else { 05327 if (sorg(*sface) == edest) { 05328 if (sdest(*sface) == eorg) { 05329 // Edge is found, inverse the direction and return. 05330 sesymself(*sface); 05331 return; 05332 } 05333 } 05334 } 05335 senextself(*sface); 05336 } 05337 printf("Internalerror in findedge(): Unable to find an edge in subface.\n"); 05338 internalerror(); 05339 } 05340 05342 // // 05343 // findface() Find the face has the given origin, destination and apex. // 05344 // // 05345 // On input, 'fface' is a handle which may contain the three corners or may // 05346 // not or may be dead. On return, it represents exactly the face with the // 05347 // given origin, destination and apex. // 05348 // // 05350 05351 void tetgenmesh::findface(triface *fface, point forg, point fdest, point fapex) 05352 { 05353 triface spintet; 05354 enum finddirectionresult collinear; 05355 int hitbdry; 05356 05357 if (!isdead(fface)) { 05358 // First check the easiest case, that 'fface' is just the right one. 05359 if (org(*fface) == forg && dest(*fface) == fdest && 05360 apex(*fface) == fapex) return; 05361 } else { 05362 // The input handle is dead, use the 'recenttet' if it is alive. 05363 if (!isdead(&recenttet)) *fface = recenttet; 05364 } 05365 05366 if (!isdead(fface)) { 05367 if (!findorg(fface, forg)) { 05368 // 'forg' is not a corner of 'fface', locate it. 05369 preciselocate(forg, fface, tetrahedrons->items); 05370 } 05371 // It is possible that forg is not found in a non-convex mesh. 05372 if (org(*fface) == forg) { 05373 collinear = finddirection(fface, fdest, tetrahedrons->items); 05374 if (collinear == RIGHTCOLLINEAR) { 05375 // fdest is just the destination. 05376 } else if (collinear == LEFTCOLLINEAR) { 05377 enext2self(*fface); 05378 esymself(*fface); 05379 } else if (collinear == TOPCOLLINEAR) { 05380 fnextself(*fface); 05381 enext2self(*fface); 05382 esymself(*fface); 05383 } 05384 } 05385 // It is possible taht fdest is not found in a non-convex mesh. 05386 if ((org(*fface) == forg) && (dest(*fface) == fdest)) { 05387 // Find the apex of 'fapex'. 05388 spintet = *fface; 05389 hitbdry = 0; 05390 do { 05391 if (apex(spintet) == fapex) { 05392 // We have done. Be careful the edge direction of 'spintet', 05393 // it may reversed because of hitting boundary once. 05394 if (org(spintet) != org(*fface)) { 05395 esymself(spintet); 05396 } 05397 *fface = spintet; 05398 return; 05399 } 05400 if (!fnextself(spintet)) { 05401 hitbdry ++; 05402 if (hitbdry < 2) { 05403 esym(*fface, spintet); 05404 if (!fnextself(spintet)) { 05405 hitbdry ++; 05406 } 05407 } 05408 } 05409 } while (hitbdry < 2 && apex(spintet) != apex(*fface)); 05410 // It is possible that fapex is not found in a non-convex mesh. 05411 } 05412 } 05413 05414 if (isdead(fface) || (org(*fface) != forg) || (dest(*fface) != fdest) || 05415 (apex(*fface) != fapex)) { 05416 // Too bad, the input handle is useless. We have to find a handle 05417 // for 'fface' contains the 'forg' and 'fdest'. Here a brute force 05418 // search is performed. 05419 if (b->verbose > 1) { 05420 printf("Warning in findface(): Perform a brute-force searching.\n"); 05421 } 05422 enum verttype forgty, fdestty, fapexty; 05423 int share, i; 05424 forgty = pointtype(forg); 05425 fdestty = pointtype(fdest); 05426 fapexty = pointtype(fapex); 05427 setpointtype(forg, DEADVERTEX); 05428 setpointtype(fdest, DEADVERTEX); 05429 setpointtype(fapex, DEADVERTEX); 05430 tetrahedrons->traversalinit(); 05431 fface->tet = tetrahedrontraverse(); 05432 while (fface->tet != (tetrahedron *) NULL) { 05433 share = 0; 05434 for (i = 0; i < 4; i++) { 05435 if (pointtype((point) fface->tet[4 + i]) == DEADVERTEX) share ++; 05436 } 05437 if (share == 3) { 05438 // Found! Set the correct face and desired corners. 05439 if (pointtype((point) fface->tet[4]) != DEADVERTEX) { 05440 fface->loc = 2; 05441 } else if (pointtype((point) fface->tet[5]) != DEADVERTEX) { 05442 fface->loc = 3; 05443 } else if (pointtype((point) fface->tet[6]) != DEADVERTEX) { 05444 fface->loc = 1; 05445 } else { // pointtype((point) fface->tet[7]) != DEADVERTEX 05446 fface->loc = 0; 05447 } 05448 findedge(fface, forg, fdest); 05449 break; 05450 } 05451 fface->tet = tetrahedrontraverse(); 05452 } 05453 setpointtype(forg, forgty); 05454 setpointtype(fdest, fdestty); 05455 setpointtype(fapex, fapexty); 05456 if (fface->tet == (tetrahedron *) NULL) { 05457 // It is impossible to reach here. 05458 printf("Internal error: Fail to find the indicated face.\n"); 05459 internalerror(); 05460 } 05461 } 05462 } 05463 05465 // // 05466 // getonextseg() Get the next SEGMENT counterclockwise with the same org. // 05467 // // 05468 // 's' is a subface. This routine reteuns the segment which is counterclock- // 05469 // wise with the origin of s. // 05470 // // 05472 05473 void tetgenmesh::getonextseg(face* s, face* lseg) 05474 { 05475 face checksh, checkseg; 05476 point forg; 05477 05478 forg = sorg(*s); 05479 checksh = *s; 05480 do { 05481 // Go to the edge at forg's left side. 05482 senext2self(checksh); 05483 // Check if there is a segment attaching this edge. 05484 sspivot(checksh, checkseg); 05485 if (checkseg.sh != dummysh) break; 05486 // No segment! Go to the neighbor of this subface. 05487 spivotself(checksh); 05488 #ifdef SELF_CHECK 05489 // It should always meet a segment before come back. 05490 assert(checksh.sh != s->sh); 05491 #endif 05492 if (sorg(checksh) != forg) { 05493 sesymself(checksh); 05494 #ifdef SELF_CHECK 05495 assert(sorg(checksh) == forg); 05496 #endif 05497 } 05498 } while (true); 05499 if (sorg(checkseg) != forg) sesymself(checkseg); 05500 *lseg = checkseg; 05501 } 05502 05504 // // 05505 // getseghasorg() Get the segment containing the given point. // 05506 // // 05507 // 'dorg' is an endpoint of a segment S. 'sseg' is a subsegment of S. This // 05508 // routine search a subsegment (along sseg) of S containing dorg. On return, // 05509 // 'sseg' contains 'dorg' as its origin. // 05510 // // 05512 05513 void tetgenmesh::getseghasorg(face* sseg, point dorg) 05514 { 05515 face nextseg; 05516 point checkpt; 05517 05518 nextseg = *sseg; 05519 checkpt = sorg(nextseg); 05520 while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) { 05521 // Search dorg along the original direction of sseg. 05522 senext2self(nextseg); 05523 spivotself(nextseg); 05524 nextseg.shver = 0; 05525 if (sdest(nextseg) != checkpt) sesymself(nextseg); 05526 checkpt = sorg(nextseg); 05527 } 05528 if (checkpt == dorg) { 05529 *sseg = nextseg; 05530 return; 05531 } 05532 nextseg = *sseg; 05533 checkpt = sdest(nextseg); 05534 while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) { 05535 // Search dorg along the destinational direction of sseg. 05536 senextself(nextseg); 05537 spivotself(nextseg); 05538 nextseg.shver = 0; 05539 if (sorg(nextseg) != checkpt) sesymself(nextseg); 05540 checkpt = sdest(nextseg); 05541 } 05542 if (checkpt == dorg) { 05543 sesym(nextseg, *sseg); 05544 return; 05545 } 05546 // Should never be here. 05547 printf("Internalerror in getseghasorg(): Unable to find the subseg.\n"); 05548 internalerror(); 05549 } 05550 05552 // // 05553 // getsubsegfarorg() Get the origin of the parent segment of a subseg. // 05554 // // 05556 05557 tetgenmesh::point tetgenmesh::getsubsegfarorg(face* sseg) 05558 { 05559 face prevseg; 05560 point checkpt; 05561 05562 checkpt = sorg(*sseg); 05563 senext2(*sseg, prevseg); 05564 spivotself(prevseg); 05565 // Search dorg along the original direction of sseg. 05566 while (prevseg.sh != dummysh) { 05567 prevseg.shver = 0; 05568 if (sdest(prevseg) != checkpt) sesymself(prevseg); 05569 checkpt = sorg(prevseg); 05570 senext2self(prevseg); 05571 spivotself(prevseg); 05572 } 05573 return checkpt; 05574 } 05575 05577 // // 05578 // getsubsegfardest() Get the dest. of the parent segment of a subseg. // 05579 // // 05581 05582 tetgenmesh::point tetgenmesh::getsubsegfardest(face* sseg) 05583 { 05584 face nextseg; 05585 point checkpt; 05586 05587 checkpt = sdest(*sseg); 05588 senext(*sseg, nextseg); 05589 spivotself(nextseg); 05590 // Search dorg along the destinational direction of sseg. 05591 while (nextseg.sh != dummysh) { 05592 nextseg.shver = 0; 05593 if (sorg(nextseg) != checkpt) sesymself(nextseg); 05594 checkpt = sdest(nextseg); 05595 senextself(nextseg); 05596 spivotself(nextseg); 05597 } 05598 return checkpt; 05599 } 05600 05602 // // 05603 // printtet() Print out the details of a tetrahedron on screen. // 05604 // // 05605 // It's also used when the highest level of verbosity (`-VVV') is specified. // 05606 // // 05608 05609 void tetgenmesh::printtet(triface* tface) 05610 { 05611 triface tmpface, prtface; 05612 point tmppt; 05613 face tmpsh; 05614 int facecount; 05615 05616 printf("Tetra x%lx with loc(%i) and ver(%i):", 05617 (unsigned long)(tface->tet), tface->loc, tface->ver); 05618 if (infected(*tface)) { 05619 printf(" (infected)"); 05620 } 05621 printf("\n"); 05622 05623 tmpface = *tface; 05624 facecount = 0; 05625 while(facecount < 4) { 05626 tmpface.loc = facecount; 05627 sym(tmpface, prtface); 05628 if(prtface.tet == dummytet) { 05629 printf(" [%i] Outer space.\n", facecount); 05630 } else { 05631 printf(" [%i] x%lx loc(%i).", facecount, 05632 (unsigned long)(prtface.tet), prtface.loc); 05633 if (infected(prtface)) { 05634 printf(" (infected)"); 05635 } 05636 printf("\n"); 05637 } 05638 facecount ++; 05639 } 05640 05641 tmppt = org(*tface); 05642 if(tmppt == (point) NULL) { 05643 printf(" Org [%i] NULL\n", locver2org[tface->loc][tface->ver]); 05644 } else { 05645 printf(" Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n", 05646 locver2org[tface->loc][tface->ver], (unsigned long)(tmppt), 05647 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); 05648 } 05649 tmppt = dest(*tface); 05650 if(tmppt == (point) NULL) { 05651 printf(" Dest[%i] NULL\n", locver2dest[tface->loc][tface->ver]); 05652 } else { 05653 printf(" Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n", 05654 locver2dest[tface->loc][tface->ver], (unsigned long)(tmppt), 05655 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); 05656 } 05657 tmppt = apex(*tface); 05658 if(tmppt == (point) NULL) { 05659 printf(" Apex[%i] NULL\n", locver2apex[tface->loc][tface->ver]); 05660 } else { 05661 printf(" Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n", 05662 locver2apex[tface->loc][tface->ver], (unsigned long)(tmppt), 05663 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); 05664 } 05665 tmppt = oppo(*tface); 05666 if(tmppt == (point) NULL) { 05667 printf(" Oppo[%i] NULL\n", loc2oppo[tface->loc]); 05668 } else { 05669 printf(" Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n", 05670 loc2oppo[tface->loc], (unsigned long)(tmppt), 05671 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); 05672 } 05673 05674 if (b->useshelles) { 05675 tmpface = *tface; 05676 facecount = 0; 05677 while(facecount < 6) { 05678 tmpface.loc = facecount; 05679 tspivot(tmpface, tmpsh); 05680 if(tmpsh.sh != dummysh) { 05681 printf(" [%i] x%lx ID(%i) ", facecount, 05682 (unsigned long)(tmpsh.sh), shellmark(tmpsh)); 05683 if (sorg(tmpsh) == (point) NULL) { 05684 printf("(fake)"); 05685 } 05686 printf("\n"); 05687 } 05688 facecount ++; 05689 } 05690 } 05691 } 05692 05694 // // 05695 // printsh() Print out the details of a subface or subsegment on screen. // 05696 // // 05697 // It's also used when the highest level of verbosity (`-VVV') is specified. // 05698 // // 05700 05701 void tetgenmesh::printsh(face* sface) 05702 { 05703 face prtsh; 05704 triface prttet; 05705 point printpoint; 05706 05707 if (sapex(*sface) != NULL) { 05708 printf("subface x%lx, ver %d, mark %d:", 05709 (unsigned long)(sface->sh), sface->shver, shellmark(*sface)); 05710 } else { 05711 printf("Subsegment x%lx, ver %d, mark %d:", 05712 (unsigned long)(sface->sh), sface->shver, shellmark(*sface)); 05713 } 05714 if (sinfected(*sface)) { 05715 printf(" (infected)"); 05716 } 05717 if (shell2badface(*sface)) { 05718 printf(" (queued)"); 05719 } 05720 if (sapex(*sface) != NULL) { 05721 if (shelltype(*sface) == SHARP) { 05722 printf(" (sharp)"); 05723 } 05724 } else { 05725 if (shelltype(*sface) == SHARP) { 05726 printf(" (sharp)"); 05727 } 05728 } 05729 if (checkpbcs) { 05730 if (shellpbcgroup(*sface) >= 0) { 05731 printf(" (pbc %d)", shellpbcgroup(*sface)); 05732 } 05733 } 05734 printf("\n"); 05735 05736 sdecode(sface->sh[0], prtsh); 05737 if (prtsh.sh == dummysh) { 05738 printf(" [0] = No shell\n"); 05739 } else { 05740 printf(" [0] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver); 05741 } 05742 sdecode(sface->sh[1], prtsh); 05743 if (prtsh.sh == dummysh) { 05744 printf(" [1] = No shell\n"); 05745 } else { 05746 printf(" [1] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver); 05747 } 05748 sdecode(sface->sh[2], prtsh); 05749 if (prtsh.sh == dummysh) { 05750 printf(" [2] = No shell\n"); 05751 } else { 05752 printf(" [2] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver); 05753 } 05754 05755 printpoint = sorg(*sface); 05756 if (printpoint == (point) NULL) 05757 printf(" Org [%d] = NULL\n", vo[sface->shver]); 05758 else 05759 printf(" Org [%d] = x%lx (%.12g,%.12g,%.12g) %d\n", 05760 vo[sface->shver], (unsigned long)(printpoint), printpoint[0], 05761 printpoint[1], printpoint[2], pointmark(printpoint)); 05762 printpoint = sdest(*sface); 05763 if (printpoint == (point) NULL) 05764 printf(" Dest[%d] = NULL\n", vd[sface->shver]); 05765 else 05766 printf(" Dest[%d] = x%lx (%.12g,%.12g,%.12g) %d\n", 05767 vd[sface->shver], (unsigned long)(printpoint), printpoint[0], 05768 printpoint[1], printpoint[2], pointmark(printpoint)); 05769 05770 if (sapex(*sface) != NULL) { 05771 printpoint = sapex(*sface); 05772 if (printpoint == (point) NULL) 05773 printf(" Apex[%d] = NULL\n", va[sface->shver]); 05774 else 05775 printf(" Apex[%d] = x%lx (%.12g,%.12g,%.12g) %d\n", 05776 va[sface->shver], (unsigned long)(printpoint), printpoint[0], 05777 printpoint[1], printpoint[2], pointmark(printpoint)); 05778 05779 decode(sface->sh[6], prttet); 05780 if (prttet.tet == dummytet) { 05781 printf(" [6] = Outer space\n"); 05782 } else { 05783 printf(" [6] = x%lx %d\n", 05784 (unsigned long)(prttet.tet), prttet.loc); 05785 } 05786 decode(sface->sh[7], prttet); 05787 if (prttet.tet == dummytet) { 05788 printf(" [7] = Outer space\n"); 05789 } else { 05790 printf(" [7] = x%lx %d\n", 05791 (unsigned long)(prttet.tet), prttet.loc); 05792 } 05793 05794 sdecode(sface->sh[8], prtsh); 05795 if (prtsh.sh == dummysh) { 05796 printf(" [8] = No subsegment\n"); 05797 } else { 05798 printf(" [8] = x%lx %d\n", 05799 (unsigned long)(prtsh.sh), prtsh.shver); 05800 } 05801 sdecode(sface->sh[9], prtsh); 05802 if (prtsh.sh == dummysh) { 05803 printf(" [9] = No subsegment\n"); 05804 } else { 05805 printf(" [9] = x%lx %d\n", 05806 (unsigned long)(prtsh.sh), prtsh.shver); 05807 } 05808 sdecode(sface->sh[10], prtsh); 05809 if (prtsh.sh == dummysh) { 05810 printf(" [10]= No subsegment\n"); 05811 } else { 05812 printf(" [10]= x%lx %d\n", 05813 (unsigned long)(prtsh.sh), prtsh.shver); 05814 } 05815 } 05816 } 05817 05818 // 05819 // End of advanced primitives 05820 // 05821 05822 // 05823 // End of mesh manipulation primitives 05824 // 05825 05826 // 05827 // Begin of mesh items searching routines 05828 // 05829 05831 // // 05832 // makepoint2tetmap() Construct a mapping from points to tetrahedra. // 05833 // // 05834 // Traverses all the tetrahedra, provides each corner of each tetrahedron // 05835 // with a pointer to that tetrahedera. Some pointers will be overwritten by // 05836 // other pointers because each point may be a corner of several tetrahedra, // 05837 // but in the end every point will point to a tetrahedron that contains it. // 05838 // // 05840 05841 void tetgenmesh::makepoint2tetmap() 05842 { 05843 triface tetloop; 05844 point pointptr; 05845 05846 if (b->verbose > 0) { 05847 printf(" Constructing mapping from points to tetrahedra.\n"); 05848 } 05849 05850 // Initialize the point2tet field of each point. 05851 points->traversalinit(); 05852 pointptr = pointtraverse(); 05853 while (pointptr != (point) NULL) { 05854 setpoint2tet(pointptr, (tetrahedron) NULL); 05855 pointptr = pointtraverse(); 05856 } 05857 05858 tetrahedrons->traversalinit(); 05859 tetloop.tet = tetrahedrontraverse(); 05860 while (tetloop.tet != (tetrahedron *) NULL) { 05861 // Check all four points of the tetrahedron. 05862 tetloop.loc = 0; 05863 pointptr = org(tetloop); 05864 setpoint2tet(pointptr, encode(tetloop)); 05865 pointptr = dest(tetloop); 05866 setpoint2tet(pointptr, encode(tetloop)); 05867 pointptr = apex(tetloop); 05868 setpoint2tet(pointptr, encode(tetloop)); 05869 pointptr = oppo(tetloop); 05870 setpoint2tet(pointptr, encode(tetloop)); 05871 // Get the next tetrahedron in the list. 05872 tetloop.tet = tetrahedrontraverse(); 05873 } 05874 } 05875 05877 // // 05878 // makeindex2pointmap() Create a map from index to vertices. // 05879 // // 05880 // 'idx2verlist' returns the created map. Traverse all vertices, a pointer // 05881 // to each vertex is set into the array. The pointer to the first vertex is // 05882 // saved in 'idx2verlist[0]'. Don't forget to minus 'in->firstnumber' when // 05883 // to get the vertex form its index. // 05884 // // 05886 05887 void tetgenmesh::makeindex2pointmap(point*& idx2verlist) 05888 { 05889 point pointloop; 05890 int idx; 05891 05892 if (b->verbose > 0) { 05893 printf(" Constructing mapping from indices to points.\n"); 05894 } 05895 05896 idx2verlist = new point[points->items]; 05897 05898 points->traversalinit(); 05899 pointloop = pointtraverse(); 05900 idx = 0; 05901 while (pointloop != (point) NULL) { 05902 idx2verlist[idx] = pointloop; 05903 idx++; 05904 pointloop = pointtraverse(); 05905 } 05906 } 05907 05909 // // 05910 // makesegmentmap() Create a map from vertices (their indices) to // 05911 // segments incident at the same vertices. // 05912 // // 05913 // Two arrays 'idx2seglist' and 'segsperverlist' together return the map. // 05914 // They form a sparse matrix structure with size (n + 1) x (n + 1), n is the // 05915 // number of segments. idx2seglist contains row information and // 05916 // segsperverlist contains all (non-zero) elements. The i-th entry of // 05917 // idx2seglist is the starting position of i-th row's (non-zero) elements in // 05918 // segsperverlist. The number of elements of i-th row is calculated by the // 05919 // (i+1)-th entry minus i-th entry of idx2seglist. // 05920 // // 05921 // NOTE: These two arrays will be created inside this routine, don't forget // 05922 // to free them after using. // 05923 // // 05925 05926 void tetgenmesh::makesegmentmap(int*& idx2seglist, shellface**& segsperverlist) 05927 { 05928 shellface *shloop; 05929 int i, j, k; 05930 05931 if (b->verbose > 0) { 05932 printf(" Constructing mapping from points to segments.\n"); 05933 } 05934 05935 // Create and initialize 'idx2seglist'. 05936 idx2seglist = new int[points->items + 1]; 05937 for (i = 0; i < points->items + 1; i++) idx2seglist[i] = 0; 05938 05939 // Loop the set of segments once, counter the number of segments sharing 05940 // each vertex. 05941 subsegs->traversalinit(); 05942 shloop = shellfacetraverse(subsegs); 05943 while (shloop != (shellface *) NULL) { 05944 // Increment the number of sharing segments for each endpoint. 05945 for (i = 0; i < 2; i++) { 05946 j = pointmark((point) shloop[3 + i]) - in->firstnumber; 05947 idx2seglist[j]++; 05948 } 05949 shloop = shellfacetraverse(subsegs); 05950 } 05951 05952 // Calculate the total length of array 'facesperverlist'. 05953 j = idx2seglist[0]; 05954 idx2seglist[0] = 0; // Array starts from 0 element. 05955 for (i = 0; i < points->items; i++) { 05956 k = idx2seglist[i + 1]; 05957 idx2seglist[i + 1] = idx2seglist[i] + j; 05958 j = k; 05959 } 05960 // The total length is in the last unit of idx2seglist. 05961 segsperverlist = new shellface*[idx2seglist[i]]; 05962 // Loop the set of segments again, set the info. of segments per vertex. 05963 subsegs->traversalinit(); 05964 shloop = shellfacetraverse(subsegs); 05965 while (shloop != (shellface *) NULL) { 05966 for (i = 0; i < 2; i++) { 05967 j = pointmark((point) shloop[3 + i]) - in->firstnumber; 05968 segsperverlist[idx2seglist[j]] = shloop; 05969 idx2seglist[j]++; 05970 } 05971 shloop = shellfacetraverse(subsegs); 05972 } 05973 // Contents in 'idx2seglist' are shifted, now shift them back. 05974 for (i = points->items - 1; i >= 0; i--) { 05975 idx2seglist[i + 1] = idx2seglist[i]; 05976 } 05977 idx2seglist[0] = 0; 05978 } 05979 05981 // // 05982 // makesubfacemap() Create a map from vertices (their indices) to // 05983 // subfaces incident at the same vertices. // 05984 // // 05985 // Two arrays 'idx2facelist' and 'facesperverlist' together return the map. // 05986 // They form a sparse matrix structure with size (n + 1) x (n + 1), n is the // 05987 // number of subfaces. idx2facelist contains row information and // 05988 // facesperverlist contains all (non-zero) elements. The i-th entry of // 05989 // idx2facelist is the starting position of i-th row's(non-zero) elements in // 05990 // facesperverlist. The number of elements of i-th row is calculated by the // 05991 // (i+1)-th entry minus i-th entry of idx2facelist. // 05992 // // 05993 // NOTE: These two arrays will be created inside this routine, don't forget // 05994 // to free them after using. // 05995 // // 05997 05998 void tetgenmesh:: 05999 makesubfacemap(int*& idx2facelist, shellface**& facesperverlist) 06000 { 06001 shellface *shloop; 06002 int i, j, k; 06003 06004 if (b->verbose > 0) { 06005 printf(" Constructing mapping from points to subfaces.\n"); 06006 } 06007 06008 // Create and initialize 'idx2facelist'. 06009 idx2facelist = new int[points->items + 1]; 06010 for (i = 0; i < points->items + 1; i++) idx2facelist[i] = 0; 06011 06012 // Loop the set of subfaces once, counter the number of subfaces sharing 06013 // each vertex. 06014 subfaces->traversalinit(); 06015 shloop = shellfacetraverse(subfaces); 06016 while (shloop != (shellface *) NULL) { 06017 // Increment the number of sharing segments for each endpoint. 06018 for (i = 0; i < 3; i++) { 06019 j = pointmark((point) shloop[3 + i]) - in->firstnumber; 06020 idx2facelist[j]++; 06021 } 06022 shloop = shellfacetraverse(subfaces); 06023 } 06024 06025 // Calculate the total length of array 'facesperverlist'. 06026 j = idx2facelist[0]; 06027 idx2facelist[0] = 0; // Array starts from 0 element. 06028 for (i = 0; i < points->items; i++) { 06029 k = idx2facelist[i + 1]; 06030 idx2facelist[i + 1] = idx2facelist[i] + j; 06031 j = k; 06032 } 06033 // The total length is in the last unit of idx2facelist. 06034 facesperverlist = new shellface*[idx2facelist[i]]; 06035 // Loop the set of segments again, set the info. of segments per vertex. 06036 subfaces->traversalinit(); 06037 shloop = shellfacetraverse(subfaces); 06038 while (shloop != (shellface *) NULL) { 06039 for (i = 0; i < 3; i++) { 06040 j = pointmark((point) shloop[3 + i]) - in->firstnumber; 06041 facesperverlist[idx2facelist[j]] = shloop; 06042 idx2facelist[j]++; 06043 } 06044 shloop = shellfacetraverse(subfaces); 06045 } 06046 // Contents in 'idx2facelist' are shifted, now shift them back. 06047 for (i = points->items - 1; i >= 0; i--) { 06048 idx2facelist[i + 1] = idx2facelist[i]; 06049 } 06050 idx2facelist[0] = 0; 06051 } 06052 06054 // // 06055 // maketetrahedronmap() Create a map from vertices (their indices) to // 06056 // tetrahedra incident at the same vertices. // 06057 // // 06058 // Two arrays 'idx2tetlist' and 'tetsperverlist' together return the map. // 06059 // They form a sparse matrix structure with size (n + 1) x (n + 1), n is the // 06060 // number of tetrahedra. idx2tetlist contains row information and // 06061 // tetsperverlist contains all (non-zero) elements. The i-th entry of // 06062 // idx2tetlist is the starting position of i-th row's (non-zero) elements in // 06063 // tetsperverlist. The number of elements of i-th row is calculated by the // 06064 // (i+1)-th entry minus i-th entry of idx2tetlist. // 06065 // // 06066 // NOTE: These two arrays will be created inside this routine, don't forget // 06067 // to free them after using. // 06068 // // 06070 06071 void tetgenmesh:: 06072 maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist) 06073 { 06074 tetrahedron *tetloop; 06075 int i, j, k; 06076 06077 if (b->verbose > 0) { 06078 printf(" Constructing mapping from points to tetrahedra.\n"); 06079 } 06080 06081 // Create and initialize 'idx2tetlist'. 06082 idx2tetlist = new int[points->items + 1]; 06083 for (i = 0; i < points->items + 1; i++) idx2tetlist[i] = 0; 06084 06085 // Loop the set of tetrahedra once, counter the number of tetrahedra 06086 // sharing each vertex. 06087 tetrahedrons->traversalinit(); 06088 tetloop = tetrahedrontraverse(); 06089 while (tetloop != (tetrahedron *) NULL) { 06090 // Increment the number of sharing tetrahedra for each endpoint. 06091 for (i = 0; i < 4; i++) { 06092 j = pointmark((point) tetloop[4 + i]) - in->firstnumber; 06093 idx2tetlist[j]++; 06094 } 06095 tetloop = tetrahedrontraverse(); 06096 } 06097 06098 // Calculate the total length of array 'tetsperverlist'. 06099 j = idx2tetlist[0]; 06100 idx2tetlist[0] = 0; // Array starts from 0 element. 06101 for (i = 0; i < points->items; i++) { 06102 k = idx2tetlist[i + 1]; 06103 idx2tetlist[i + 1] = idx2tetlist[i] + j; 06104 j = k; 06105 } 06106 // The total length is in the last unit of idx2tetlist. 06107 tetsperverlist = new tetrahedron*[idx2tetlist[i]]; 06108 // Loop the set of tetrahedra again, set the info. of tet. per vertex. 06109 tetrahedrons->traversalinit(); 06110 tetloop = tetrahedrontraverse(); 06111 while (tetloop != (tetrahedron *) NULL) { 06112 for (i = 0; i < 4; i++) { 06113 j = pointmark((point) tetloop[4 + i]) - in->firstnumber; 06114 tetsperverlist[idx2tetlist[j]] = tetloop; 06115 idx2tetlist[j]++; 06116 } 06117 tetloop = tetrahedrontraverse(); 06118 } 06119 // Contents in 'idx2tetlist' are shifted, now shift them back. 06120 for (i = points->items - 1; i >= 0; i--) { 06121 idx2tetlist[i + 1] = idx2tetlist[i]; 06122 } 06123 idx2tetlist[0] = 0; 06124 } 06125 06126 // 06127 // End of mesh items searching routines 06128 // 06129 06130 // 06131 // Begin of linear algebra functions 06132 // 06133 06134 // dot() returns the dot product: v1 dot v2. 06135 06136 inline REAL tetgenmesh::dot(REAL* v1, REAL* v2) 06137 { 06138 return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; 06139 } 06140 06141 // cross() computes the cross product: n = v1 cross v2. 06142 06143 inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n) 06144 { 06145 n[0] = v1[1] * v2[2] - v2[1] * v1[2]; 06146 n[1] = -(v1[0] * v2[2] - v2[0] * v1[2]); 06147 n[2] = v1[0] * v2[1] - v2[0] * v1[1]; 06148 } 06149 06150 // initm44() initializes a 4x4 matrix. 06151 static void initm44(REAL a00, REAL a01, REAL a02, REAL a03, 06152 REAL a10, REAL a11, REAL a12, REAL a13, 06153 REAL a20, REAL a21, REAL a22, REAL a23, 06154 REAL a30, REAL a31, REAL a32, REAL a33, 06155 REAL M[4][4]) 06156 { 06157 M[0][0] = a00; M[0][1] = a01; M[0][2] = a02; M[0][3] = a03; 06158 M[1][0] = a10; M[1][1] = a11; M[1][2] = a12; M[1][3] = a13; 06159 M[2][0] = a20; M[2][1] = a21; M[2][2] = a22; M[2][3] = a23; 06160 M[3][0] = a30; M[3][1] = a31; M[3][2] = a32; M[3][3] = a33; 06161 } 06162 06163 // m4xm4() multiplies 2 4x4 matrics: m1 = m1 * m2. 06164 static void m4xm4(REAL m1[4][4], REAL m2[4][4]) 06165 { 06166 REAL tmp[4]; 06167 int i, j; 06168 06169 for (i = 0; i < 4; i++) { // i-th row 06170 for (j = 0; j < 4; j++) { // j-th col 06171 tmp[j] = m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j] 06172 + m1[i][2] * m2[2][j] + m1[i][3] * m2[3][j]; 06173 } 06174 for (j = 0; j < 4; j++) 06175 m1[i][j] = tmp[j]; 06176 } 06177 } 06178 06179 // m4xv4() multiplies a 4x4 matrix and 4x1 vector: v2 = m * v1 06180 static void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4]) 06181 { 06182 v2[0] = m[0][0]*v1[0] + m[0][1]*v1[1] + m[0][2]*v1[2] + m[0][3]*v1[3]; 06183 v2[1] = m[1][0]*v1[0] + m[1][1]*v1[1] + m[1][2]*v1[2] + m[1][3]*v1[3]; 06184 v2[2] = m[2][0]*v1[0] + m[2][1]*v1[1] + m[2][2]*v1[2] + m[2][3]*v1[3]; 06185 v2[3] = m[3][0]*v1[0] + m[3][1]*v1[1] + m[3][2]*v1[2] + m[3][3]*v1[3]; 06186 } 06187 06189 // // 06190 // lu_decmp() Compute the LU decomposition of a matrix. // 06191 // // 06192 // Compute the LU decomposition of a (non-singular) square matrix A using // 06193 // partial pivoting and implicit row exchanges. The result is: // 06194 // A = P * L * U, // 06195 // where P is a permutation matrix, L is unit lower triangular, and U is // 06196 // upper triangular. The factored form of A is used in combination with // 06197 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. // 06198 // // 06199 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.// 06200 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- // 06201 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row // 06202 // permutation effected by the partial pivoting, effectively, 'ps' array // 06203 // tells the user what the permutation matrix P is; 'd' is output as +1/-1 // 06204 // depending on whether the number of row interchanges was even or odd, // 06205 // respectively. // 06206 // // 06207 // Return true if the LU decomposition is successfully computed, otherwise, // 06208 // return false in case that A is a singular matrix. // 06209 // // 06211 06212 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N) 06213 { 06214 REAL scales[4]; 06215 REAL pivot, biggest, mult, tempf; 06216 int pivotindex = 0; 06217 int i, j, k; 06218 06219 *d = 1.0; // No row interchanges yet. 06220 06221 for (i = N; i < n + N; i++) { // For each row. 06222 // Find the largest element in each row for row equilibration 06223 biggest = 0.0; 06224 for (j = N; j < n + N; j++) 06225 if (biggest < (tempf = fabs(lu[i][j]))) 06226 biggest = tempf; 06227 if (biggest != 0.0) 06228 scales[i] = 1.0 / biggest; 06229 else { 06230 scales[i] = 0.0; 06231 return false; // Zero row: singular matrix. 06232 } 06233 ps[i] = i; // Initialize pivot sequence. 06234 } 06235 06236 for (k = N; k < n + N - 1; k++) { // For each column. 06237 // Find the largest element in each column to pivot around. 06238 biggest = 0.0; 06239 for (i = k; i < n + N; i++) { 06240 if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) { 06241 biggest = tempf; 06242 pivotindex = i; 06243 } 06244 } 06245 if (biggest == 0.0) { 06246 return false; // Zero column: singular matrix. 06247 } 06248 if (pivotindex != k) { // Update pivot sequence. 06249 j = ps[k]; 06250 ps[k] = ps[pivotindex]; 06251 ps[pivotindex] = j; 06252 *d = -(*d); // ...and change the parity of d. 06253 } 06254 06255 // Pivot, eliminating an extra variable each time 06256 pivot = lu[ps[k]][k]; 06257 for (i = k + 1; i < n + N; i++) { 06258 lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot; 06259 if (mult != 0.0) { 06260 for (j = k + 1; j < n + N; j++) 06261 lu[ps[i]][j] -= mult * lu[ps[k]][j]; 06262 } 06263 } 06264 } 06265 06266 // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular. 06267 return lu[ps[n + N - 1]][n + N - 1] != 0.0; 06268 } 06269 06271 // // 06272 // lu_solve() Solves the linear equation: Ax = b, after the matrix A // 06273 // has been decomposed into the lower and upper triangular // 06274 // matrices L and U, where A = LU. // 06275 // // 06276 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as // 06277 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' // 06278 // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' // 06279 // is input as the right-hand side vector, and returns with the solution // 06280 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be // 06281 // left in place for successive calls with different right-hand sides 'b'. // 06282 // // 06284 06285 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N) 06286 { 06287 int i, j; 06288 REAL X[4], dot; 06289 06290 for (i = N; i < n + N; i++) X[i] = 0.0; 06291 06292 // Vector reduction using U triangular matrix. 06293 for (i = N; i < n + N; i++) { 06294 dot = 0.0; 06295 for (j = N; j < i + N; j++) 06296 dot += lu[ps[i]][j] * X[j]; 06297 X[i] = b[ps[i]] - dot; 06298 } 06299 06300 // Back substitution, in L triangular matrix. 06301 for (i = n + N - 1; i >= N; i--) { 06302 dot = 0.0; 06303 for (j = i + 1; j < n + N; j++) 06304 dot += lu[ps[i]][j] * X[j]; 06305 X[i] = (X[i] - dot) / lu[ps[i]][i]; 06306 } 06307 06308 for (i = N; i < n + N; i++) b[i] = X[i]; 06309 } 06310 06311 // 06312 // End of linear algebra functions 06313 // 06314 06315 // 06316 // Begin of geometric tests 06317 // 06318 06319 // All the following routines require the input objects are not degenerate. 06320 // i.e., a triangle must has three non-collinear corners; an edge must 06321 // has two identical endpoints. Degenerate cases should have to detect 06322 // first and then handled as special cases. 06323 06325 // // 06326 // edge_vert_col_inter() Test whether an edge (ab) and a collinear vertex // 06327 // (p) are intersecting or not. // 06328 // // 06329 // Possible cases are p is coincident to a (p = a), or to b (p = b), or p is // 06330 // inside ab (a < p < b), or outside ab (p < a or p > b). These cases can be // 06331 // quickly determined by comparing the corresponding coords of a, b, and p // 06332 // (which are not all equal). // 06333 // // 06334 // The return value indicates one of the three cases: DISJOINT, SHAREVERTEX // 06335 // (p = a or p = b), and INTERSECT (a < p < b). // 06336 // // 06338 06339 enum tetgenmesh::interresult tetgenmesh::edge_vert_col_inter(REAL* A, REAL* B, 06340 REAL* P) 06341 { 06342 int i = 0; 06343 do { 06344 if (A[i] < B[i]) { 06345 if (P[i] < A[i]) { 06346 return DISJOINT; 06347 } else if (P[i] > A[i]) { 06348 if (P[i] < B[i]) { 06349 return INTERSECT; 06350 } else if (P[i] > B[i]) { 06351 return DISJOINT; 06352 } else { 06353 // assert(P[i] == B[i]); 06354 return SHAREVERTEX; 06355 } 06356 } else { 06357 // assert(P[i] == A[i]); 06358 return SHAREVERTEX; 06359 } 06360 } else if (A[i] > B[i]) { 06361 if (P[i] < B[i]) { 06362 return DISJOINT; 06363 } else if (P[i] > B[i]) { 06364 if (P[i] < A[i]) { 06365 return INTERSECT; 06366 } else if (P[i] > A[i]) { 06367 return DISJOINT; 06368 } else { 06369 // assert(P[i] == A[i]); 06370 return SHAREVERTEX; 06371 } 06372 } else { 06373 // assert(P[i] == B[i]); 06374 return SHAREVERTEX; 06375 } 06376 } 06377 // i-th coordinates are equal, try i+1-th; 06378 i++; 06379 } while (i < 3); 06380 // Should never be here. 06381 return DISJOINT; 06382 } 06383 06385 // // 06386 // edge_edge_cop_inter() Test whether two coplanar edges (ab, and pq) are // 06387 // intersecting or not. // 06388 // // 06389 // Possible cases are ab and pq are disjointed, or proper intersecting (int- // 06390 // ersect at a point other than their endpoints), or both collinear and int- // 06391 // ersecting, or sharing at a common endpoint, or are coincident. // 06392 // // 06393 // A reference point R is required, which is exactly not coplanar with these // 06394 // two edges. Since the caller knows these two edges are coplanar, it must // 06395 // be able to provide (or calculate) such a point. // 06396 // // 06397 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // 06398 // SHAREEDGE, and INTERSECT. // 06399 // // 06401 06402 enum tetgenmesh::interresult tetgenmesh:: edge_edge_cop_inter(REAL* A, REAL* B, 06403 REAL* P, REAL* Q, REAL* R) 06404 { 06405 REAL s1, s2, s3, s4; 06406 06407 #ifdef SELF_CHECK 06408 assert(R != NULL); 06409 #endif 06410 s1 = orient3d(A, B, R, P); 06411 s2 = orient3d(A, B, R, Q); 06412 if (s1 * s2 > 0.0) { 06413 // Both p and q are at the same side of ab. 06414 return DISJOINT; 06415 } 06416 s3 = orient3d(P, Q, R, A); 06417 s4 = orient3d(P, Q, R, B); 06418 if (s3 * s4 > 0.0) { 06419 // Both a and b are at the same side of pq. 06420 return DISJOINT; 06421 } 06422 06423 // Possible degenerate cases are: 06424 // (1) Only one of p and q is collinear with ab; 06425 // (2) Both p and q are collinear with ab; 06426 // (3) Only one of a and b is collinear with pq. 06427 enum interresult abp, abq; 06428 enum interresult pqa, pqb; 06429 06430 if (s1 == 0.0) { 06431 // p is collinear with ab. 06432 abp = edge_vert_col_inter(A, B, P); 06433 if (abp == INTERSECT) { 06434 // p is inside ab. 06435 return INTERSECT; 06436 } 06437 if (s2 == 0.0) { 06438 // q is collinear with ab. Case (2). 06439 abq = edge_vert_col_inter(A, B, Q); 06440 if (abq == INTERSECT) { 06441 // q is inside ab. 06442 return INTERSECT; 06443 } 06444 if (abp == SHAREVERTEX && abq == SHAREVERTEX) { 06445 // ab and pq are identical. 06446 return SHAREEDGE; 06447 } 06448 pqa = edge_vert_col_inter(P, Q, A); 06449 if (pqa == INTERSECT) { 06450 // a is inside pq. 06451 return INTERSECT; 06452 } 06453 pqb = edge_vert_col_inter(P, Q, B); 06454 if (pqb == INTERSECT) { 06455 // b is inside pq. 06456 return INTERSECT; 06457 } 06458 if (abp == SHAREVERTEX || abq == SHAREVERTEX) { 06459 // either p or q is coincident with a or b. 06460 #ifdef SELF_CHECK 06461 // ONLY one case is possible, otherwise, shoule be SHAREEDGE. 06462 assert(abp ^ abq); 06463 #endif 06464 return SHAREVERTEX; 06465 } 06466 // The last case. They are disjointed. 06467 #ifdef SELF_CHECK 06468 assert((abp == DISJOINT) && (abp == abq && abq == pqa && pqa == pqb)); 06469 #endif 06470 return DISJOINT; 06471 } else { 06472 // p is collinear with ab. Case (1). 06473 #ifdef SELF_CHECK 06474 assert(abp == SHAREVERTEX || abp == DISJOINT); 06475 #endif 06476 return abp; 06477 } 06478 } 06479 // p is NOT collinear with ab. 06480 if (s2 == 0.0) { 06481 // q is collinear with ab. Case (1). 06482 abq = edge_vert_col_inter(A, B, Q); 06483 #ifdef SELF_CHECK 06484 assert(abq == SHAREVERTEX || abq == DISJOINT || abq == INTERSECT); 06485 #endif 06486 return abq; 06487 } 06488 06489 // We have found p and q are not collinear with ab. However, it is still 06490 // possible that a or b is collinear with pq (ONLY one of a and b). 06491 if (s3 == 0.0) { 06492 // a is collinear with pq. Case (3). 06493 #ifdef SELF_CHECK 06494 assert(s4 != 0.0); 06495 #endif 06496 pqa = edge_vert_col_inter(P, Q, A); 06497 #ifdef SELF_CHECK 06498 // This case should have been detected in above. 06499 assert(pqa != SHAREVERTEX); 06500 assert(pqa == INTERSECT || pqa == DISJOINT); 06501 #endif 06502 return pqa; 06503 } 06504 if (s4 == 0.0) { 06505 // b is collinear with pq. Case (3). 06506 #ifdef SELF_CHECK 06507 assert(s3 != 0.0); 06508 #endif 06509 pqb = edge_vert_col_inter(P, Q, B); 06510 #ifdef SELF_CHECK 06511 // This case should have been detected in above. 06512 assert(pqb != SHAREVERTEX); 06513 assert(pqb == INTERSECT || pqb == DISJOINT); 06514 #endif 06515 return pqb; 06516 } 06517 06518 // ab and pq are intersecting properly. 06519 return INTERSECT; 06520 } 06521 06523 // // 06524 // Notations // 06525 // // 06526 // Let ABC be the plane passes through a, b, and c; ABC+ be the halfspace // 06527 // including the set of all points x, such that orient3d(a, b, c, x) > 0; // 06528 // ABC- be the other halfspace, such that for each point x in ABC-, // 06529 // orient3d(a, b, c, x) < 0. For the set of x which are on ABC, orient3d(a, // 06530 // b, c, x) = 0. // 06531 // // 06533 06535 // // 06536 // tri_vert_copl_inter() Test whether a triangle (abc) and a coplanar // 06537 // point (p) are intersecting or not. // 06538 // // 06539 // Possible cases are p is inside abc, or on an edge of, or coincident with // 06540 // a vertex of, or outside abc. // 06541 // // 06542 // A reference point R is required. R is exactly not coplanar with abc and p.// 06543 // Since the caller knows they are coplanar, it must be able to provide (or // 06544 // calculate) such a point. // 06545 // // 06546 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // 06547 // and INTERSECT. // 06548 // // 06550 06551 enum tetgenmesh::interresult tetgenmesh::tri_vert_cop_inter(REAL* A, REAL* B, 06552 REAL* C, REAL* P, REAL* R) 06553 { 06554 REAL s1, s2, s3; 06555 int sign; 06556 06557 #ifdef SELF_CHECK 06558 assert(R != (REAL *) NULL); 06559 #endif 06560 // Adjust the orientation of a, b, c and r, so that we can assume that 06561 // r is strictly in ABC- (i.e., r is above ABC wrt. right-hand rule). 06562 s1 = orient3d(A, B, C, R); 06563 #ifdef SELF_CHECK 06564 assert(s1 != 0.0); 06565 #endif 06566 sign = s1 < 0.0 ? 1 : -1; 06567 06568 // Test starts from here. 06569 s1 = orient3d(A, B, R, P) * sign; 06570 if (s1 < 0.0) { 06571 // p is in ABR-. 06572 return DISJOINT; 06573 } 06574 s2 = orient3d(B, C, R, P) * sign; 06575 if (s2 < 0.0) { 06576 // p is in BCR-. 06577 return DISJOINT; 06578 } 06579 s3 = orient3d(C, A, R, P) * sign; 06580 if (s3 < 0.0) { 06581 // p is in CAR-. 06582 return DISJOINT; 06583 } 06584 if (s1 == 0.0) { 06585 // p is on ABR. 06586 if (s2 == 0.0) { 06587 // p is on BCR. 06588 #ifdef SELF_CHECK 06589 assert(s3 > 0.0); 06590 #endif 06591 // p is coincident with b. 06592 return SHAREVERTEX; 06593 } 06594 if (s3 == 0.0) { 06595 // p is on CAR. 06596 // p is coincident with a. 06597 return SHAREVERTEX; 06598 } 06599 // p is on edge ab. 06600 return INTERSECT; 06601 } 06602 // p is in ABR+. 06603 if (s2 == 0.0) { 06604 // p is on BCR. 06605 if (s3 == 0.0) { 06606 // p is on CAR. 06607 // p is coincident with c. 06608 return SHAREVERTEX; 06609 } 06610 // p is on edge bc. 06611 return INTERSECT; 06612 } 06613 if (s3 == 0.0) { 06614 // p is on CAR. 06615 // p is on edge ca. 06616 return INTERSECT; 06617 } 06618 06619 // p is strictly inside abc. 06620 return INTERSECT; 06621 } 06622 06624 // // 06625 // tri_edge_cop_inter() Test whether a triangle (abc) and a coplanar edge // 06626 // (pq) are intersecting or not. // 06627 // // 06628 // A reference point R is required. R is exactly not coplanar with abc and // 06629 // pq. Since the caller knows they are coplanar, it must be able to provide // 06630 // (or calculate) such a point. // 06631 // // 06632 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // 06633 // SHAREEDGE, and INTERSECT. // 06634 // // 06636 06637 enum tetgenmesh::interresult tetgenmesh::tri_edge_cop_inter(REAL* A, REAL* B, 06638 REAL* C, REAL* P, REAL* Q, REAL* R) 06639 { 06640 enum interresult abpq, bcpq, capq; 06641 enum interresult abcp, abcq; 06642 06643 // Test if pq is intersecting one of edges of abc. 06644 abpq = edge_edge_cop_inter(A, B, P, Q, R); 06645 if (abpq == INTERSECT || abpq == SHAREEDGE) { 06646 return abpq; 06647 } 06648 bcpq = edge_edge_cop_inter(B, C, P, Q, R); 06649 if (bcpq == INTERSECT || bcpq == SHAREEDGE) { 06650 return bcpq; 06651 } 06652 capq = edge_edge_cop_inter(C, A, P, Q, R); 06653 if (capq == INTERSECT || capq == SHAREEDGE) { 06654 return capq; 06655 } 06656 06657 // Test if p and q is inside abc. 06658 abcp = tri_vert_cop_inter(A, B, C, P, R); 06659 if (abcp == INTERSECT) { 06660 return INTERSECT; 06661 } 06662 abcq = tri_vert_cop_inter(A, B, C, Q, R); 06663 if (abcq == INTERSECT) { 06664 return INTERSECT; 06665 } 06666 06667 // Combine the test results of edge intersectings and triangle insides 06668 // to detect whether abc and pq are sharing vertex or disjointed. 06669 if (abpq == SHAREVERTEX) { 06670 // p or q is coincident with a or b. 06671 #ifdef SELF_CHECK 06672 assert(abcp ^ abcq); 06673 #endif 06674 return SHAREVERTEX; 06675 } 06676 if (bcpq == SHAREVERTEX) { 06677 // p or q is coincident with b or c. 06678 #ifdef SELF_CHECK 06679 assert(abcp ^ abcq); 06680 #endif 06681 return SHAREVERTEX; 06682 } 06683 if (capq == SHAREVERTEX) { 06684 // p or q is coincident with c or a. 06685 #ifdef SELF_CHECK 06686 assert(abcp ^ abcq); 06687 #endif 06688 return SHAREVERTEX; 06689 } 06690 06691 // They are disjointed. 06692 return DISJOINT; 06693 } 06694 06696 // // 06697 // tri_edge_inter_tail() Test whether a triangle (abc) and an edge (pq) // 06698 // are intersecting or not. // 06699 // // 06700 // s1 and s2 are results of pre-performed orientation tests. s1 = orient3d( // 06701 // a, b, c, p); s2 = orient3d(a, b, c, q). To separate this routine from // 06702 // tri_edge_inter() can save two orientation tests in tri_tri_inter(). // 06703 // // 06704 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // 06705 // SHAREEDGE, and INTERSECT. // 06706 // // 06708 06709 enum tetgenmesh::interresult tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, 06710 REAL* C, REAL* P, REAL* Q, REAL s1, REAL s2) 06711 { 06712 REAL s3, s4, s5; 06713 int sign; 06714 06715 if (s1 * s2 > 0.0) { 06716 // p, q are at the same halfspace of ABC, no intersection. 06717 return DISJOINT; 06718 } 06719 06720 if (s1 * s2 < 0.0) { 06721 // p, q are both not on ABC (and not sharing vertices, edges of abc). 06722 // Adjust the orientation of a, b, c and p, so that we can assume that 06723 // p is strictly in ABC-, and q is strictly in ABC+. 06724 sign = s1 < 0.0 ? 1 : -1; 06725 s3 = orient3d(A, B, P, Q) * sign; 06726 if (s3 < 0.0) { 06727 // q is at ABP-. 06728 return DISJOINT; 06729 } 06730 s4 = orient3d(B, C, P, Q) * sign; 06731 if (s4 < 0.0) { 06732 // q is at BCP-. 06733 return DISJOINT; 06734 } 06735 s5 = orient3d(C, A, P, Q) * sign; 06736 if (s5 < 0.0) { 06737 // q is at CAP-. 06738 return DISJOINT; 06739 } 06740 if (s3 == 0.0) { 06741 // q is on ABP. 06742 if (s4 == 0.0) { 06743 // q is on BCP (and q must in CAP+). 06744 #ifdef SELF_CHECK 06745 assert(s5 > 0.0); 06746 #endif 06747 // pq intersects abc at vertex b. 06748 return SHAREVERTEX; 06749 } 06750 if (s5 == 0.0) { 06751 // q is on CAP (and q must in BCP+). 06752 // pq intersects abc at vertex a. 06753 return SHAREVERTEX; 06754 } 06755 // q in both BCP+ and CAP+. 06756 // pq crosses ab properly. 06757 return INTERSECT; 06758 } 06759 // q is in ABP+; 06760 if (s4 == 0.0) { 06761 // q is on BCP. 06762 if (s5 == 0.0) { 06763 // q is on CAP. 06764 // pq intersects abc at vertex c. 06765 return SHAREVERTEX; 06766 } 06767 // pq crosses bc properly. 06768 return INTERSECT; 06769 } 06770 // q is in BCP+; 06771 if (s5 == 0.0) { 06772 // q is on CAP. 06773 // pq crosses ca properly. 06774 return INTERSECT; 06775 } 06776 // q is in CAP+; 06777 // pq crosses abc properly. 06778 return INTERSECT; 06779 } 06780 06781 if (s1 != 0.0 || s2 != 0.0) { 06782 // Either p or q is coplanar with abc. ONLY one of them is possible. 06783 if (s1 == 0.0) { 06784 // p is coplanar with abc, q can be used as reference point. 06785 #ifdef SELF_CHECK 06786 assert(s2 != 0.0); 06787 #endif 06788 return tri_vert_cop_inter(A, B, C, P, Q); 06789 } else { 06790 // q is coplanar with abc, p can be used as reference point. 06791 #ifdef SELF_CHECK 06792 assert(s2 == 0.0); 06793 #endif 06794 return tri_vert_cop_inter(A, B, C, Q, P); 06795 } 06796 } 06797 06798 // pq is coplanar with abc. Calculate a point which is exactly not 06799 // coplanar with a, b, and c. 06800 REAL R[3], N[3]; 06801 REAL ax, ay, az, bx, by, bz; 06802 06803 ax = A[0] - B[0]; 06804 ay = A[1] - B[1]; 06805 az = A[2] - B[2]; 06806 bx = A[0] - C[0]; 06807 by = A[1] - C[1]; 06808 bz = A[2] - C[2]; 06809 N[0] = ay * bz - by * az; 06810 N[1] = az * bx - bz * ax; 06811 N[2] = ax * by - bx * ay; 06812 // The normal should not be a zero vector (otherwise, abc are collinear). 06813 #ifdef SELF_CHECK 06814 assert((fabs(N[0]) + fabs(N[1]) + fabs(N[2])) > 0.0); 06815 #endif 06816 // The reference point R is lifted from A to the normal direction with 06817 // a distance d = average edge length of the triangle abc. 06818 R[0] = N[0] + A[0]; 06819 R[1] = N[1] + A[1]; 06820 R[2] = N[2] + A[2]; 06821 // Becareful the case: if the non-zero component(s) in N is smaller than 06822 // the machine epsilon (i.e., 2^(-16) for double), R will exactly equal 06823 // to A due to the round-off error. Do check if it is. 06824 if (R[0] == A[0] && R[1] == A[1] && R[2] == A[2]) { 06825 int i, j; 06826 for (i = 0; i < 3; i++) { 06827 #ifdef SELF_CHECK 06828 assert (R[i] == A[i]); 06829 #endif 06830 j = 2; 06831 do { 06832 if (N[i] > 0.0) { 06833 N[i] += (j * macheps); 06834 } else { 06835 N[i] -= (j * macheps); 06836 } 06837 R[i] = N[i] + A[i]; 06838 j *= 2; 06839 } while (R[i] == A[i]); 06840 } 06841 } 06842 06843 return tri_edge_cop_inter(A, B, C, P, Q, R); 06844 } 06845 06847 // // 06848 // tri_edge_inter() Test whether a triangle (abc) and an edge (pq) are // 06849 // intersecting or not. // 06850 // // 06851 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // 06852 // SHAREEDGE, and INTERSECT. // 06853 // // 06855 06856 enum tetgenmesh::interresult tetgenmesh::tri_edge_inter(REAL* A, REAL* B, 06857 REAL* C, REAL* P, REAL* Q) 06858 { 06859 REAL s1, s2; 06860 06861 // Test the locations of p and q with respect to ABC. 06862 s1 = orient3d(A, B, C, P); 06863 s2 = orient3d(A, B, C, Q); 06864 06865 return tri_edge_inter_tail(A, B, C, P, Q, s1, s2); 06866 } 06867 06869 // // 06870 // tri_tri_inter() Test whether two triangle (abc) and (opq) are // 06871 // intersecting or not. // 06872 // // 06873 // The return value indicates one of the five cases: DISJOINT, SHAREVERTEX, // 06874 // SHAREEDGE, SHAREFACE, and INTERSECT. // 06875 // // 06877 06878 enum tetgenmesh::interresult tetgenmesh::tri_tri_inter(REAL* A, REAL* B, 06879 REAL* C, REAL* O, REAL* P, REAL* Q) 06880 { 06881 REAL s_o, s_p, s_q; 06882 REAL s_a, s_b, s_c; 06883 06884 s_o = orient3d(A, B, C, O); 06885 s_p = orient3d(A, B, C, P); 06886 s_q = orient3d(A, B, C, Q); 06887 if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) { 06888 // o, p, q are all in the same halfspace of ABC. 06889 return DISJOINT; 06890 } 06891 06892 s_a = orient3d(O, P, Q, A); 06893 s_b = orient3d(O, P, Q, B); 06894 s_c = orient3d(O, P, Q, C); 06895 if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) { 06896 // a, b, c are all in the same halfspace of OPQ. 06897 return DISJOINT; 06898 } 06899 06900 enum interresult abcop, abcpq, abcqo; 06901 int shareedge = 0; 06902 06903 abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p); 06904 if (abcop == INTERSECT) { 06905 return INTERSECT; 06906 } else if (abcop == SHAREEDGE) { 06907 shareedge++; 06908 } 06909 abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q); 06910 if (abcpq == INTERSECT) { 06911 return INTERSECT; 06912 } else if (abcpq == SHAREEDGE) { 06913 shareedge++; 06914 } 06915 abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o); 06916 if (abcqo == INTERSECT) { 06917 return INTERSECT; 06918 } else if (abcqo == SHAREEDGE) { 06919 shareedge++; 06920 } 06921 if (shareedge == 3) { 06922 // opq are coincident with abc. 06923 return SHAREFACE; 06924 } 06925 #ifdef SELF_CHECK 06926 // It is only possible either no share edge or one. 06927 assert(shareedge == 0 || shareedge == 1); 06928 #endif 06929 06930 // Continue to detect whether opq and abc are intersecting or not. 06931 enum interresult opqab, opqbc, opqca; 06932 06933 opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b); 06934 if (opqab == INTERSECT) { 06935 return INTERSECT; 06936 } 06937 opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c); 06938 if (opqbc == INTERSECT) { 06939 return INTERSECT; 06940 } 06941 opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a); 06942 if (opqca == INTERSECT) { 06943 return INTERSECT; 06944 } 06945 06946 // At this point, two triangles are not intersecting and not coincident. 06947 // They may be share an edge, or share a vertex, or disjoint. 06948 if (abcop == SHAREEDGE) { 06949 #ifdef SELF_CHECK 06950 assert(abcpq == SHAREVERTEX && abcqo == SHAREVERTEX); 06951 #endif 06952 // op is coincident with an edge of abc. 06953 return SHAREEDGE; 06954 } 06955 if (abcpq == SHAREEDGE) { 06956 #ifdef SELF_CHECK 06957 assert(abcop == SHAREVERTEX && abcqo == SHAREVERTEX); 06958 #endif 06959 // pq is coincident with an edge of abc. 06960 return SHAREEDGE; 06961 } 06962 if (abcqo == SHAREEDGE) { 06963 #ifdef SELF_CHECK 06964 assert(abcop == SHAREVERTEX && abcpq == SHAREVERTEX); 06965 #endif 06966 // qo is coincident with an edge of abc. 06967 return SHAREEDGE; 06968 } 06969 06970 // They may share a vertex or disjoint. 06971 if (abcop == SHAREVERTEX) { 06972 // o or p is coincident with a vertex of abc. 06973 if (abcpq == SHAREVERTEX) { 06974 // p is the coincident vertex. 06975 #ifdef SELF_CHECK 06976 assert(abcqo != SHAREVERTEX); 06977 #endif 06978 } else { 06979 // o is the coincident vertex. 06980 #ifdef SELF_CHECK 06981 assert(abcqo == SHAREVERTEX); 06982 #endif 06983 } 06984 return SHAREVERTEX; 06985 } 06986 if (abcpq == SHAREVERTEX) { 06987 // q is the coincident vertex. 06988 #ifdef SELF_CHECK 06989 assert(abcqo == SHAREVERTEX); 06990 #endif 06991 return SHAREVERTEX; 06992 } 06993 06994 // They are disjoint. 06995 return DISJOINT; 06996 } 06997 06999 // // 07000 // insphere_sos() Insphere test with symbolic perturbation. // 07001 // // 07002 // The input points a, b, c, and d should be non-coplanar. They must be ord- // 07003 // ered so that they have a positive orientation (as defined by orient3d()), // 07004 // or the sign of the result will be reversed. // 07005 // // 07006 // Return a positive value if the point e lies inside the circumsphere of a, // 07007 // b, c, and d; a negative value if it lies outside. // 07008 // // 07010 07011 REAL tetgenmesh::insphere_sos(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe, 07012 int ia, int ib, int ic, int id, int ie) 07013 { 07014 REAL det; 07015 07016 det = insphere(pa, pb, pc, pd, pe); 07017 if (det != 0.0) { 07018 return det; 07019 } 07020 07021 // det = 0.0, use symbolic perturbation. 07022 REAL *p[5], *tmpp; 07023 REAL sign, det_c, det_d; 07024 int idx[5], perm, tmp; 07025 int n, i, j; 07026 07027 p[0] = pa; idx[0] = ia; 07028 p[1] = pb; idx[1] = ib; 07029 p[2] = pc; idx[2] = ic; 07030 p[3] = pd; idx[3] = id; 07031 p[4] = pe; idx[4] = ie; 07032 07033 // Bubble sort the points by the increasing order of the indices. 07034 n = 5; 07035 perm = 0; // The number of total swaps. 07036 for (i = 0; i < n - 1; i++) { 07037 for (j = 0; j < n - 1 - i; j++) { 07038 if (idx[j + 1] < idx[j]) { // compare the two neighbors. 07039 tmp = idx[j]; // swap idx[j] and idx[j + 1] 07040 idx[j] = idx[j + 1]; 07041 idx[j + 1] = tmp; 07042 tmpp = p[j]; // swap p[j] and p[j + 1] 07043 p[j] = p[j + 1]; 07044 p[j + 1] = tmpp; 07045 perm++; 07046 } 07047 } 07048 } 07049 07050 sign = (perm % 2 == 0) ? 1.0 : -1.0; 07051 det_c = orient3d(p[1], p[2], p[3], p[4]); // orient3d(b, c, d, e) 07052 if (det_c != 0.0) { 07053 return sign * det_c; 07054 } 07055 det_d = orient3d(p[0], p[2], p[3], p[4]); // orient3d(a, c, d, e) 07056 return -sign * det_d; 07057 } 07058 07060 // // 07061 // iscollinear() Check if three points are approximately collinear. // 07062 // // 07063 // 'eps' is a relative error tolerance. The collinearity is determined by // 07064 // the value q = cos(theta), where theta is the angle between two vectors // 07065 // A->B and A->C. They're collinear if 1.0 - q <= epspp. // 07066 // // 07068 07069 bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL eps) 07070 { 07071 REAL abx, aby, abz; 07072 REAL acx, acy, acz; 07073 REAL Lv, Lw, dd; 07074 REAL d, q; 07075 07076 // Limit of two closed points. 07077 q = longest * eps; 07078 q *= q; 07079 07080 abx = A[0] - B[0]; 07081 aby = A[1] - B[1]; 07082 abz = A[2] - B[2]; 07083 acx = A[0] - C[0]; 07084 acy = A[1] - C[1]; 07085 acz = A[2] - C[2]; 07086 Lv = abx * abx + aby * aby + abz * abz; 07087 // Is AB (nearly) indentical? 07088 if (Lv < q) return true; 07089 Lw = acx * acx + acy * acy + acz * acz; 07090 // Is AC (nearly) indentical? 07091 if (Lw < q) return true; 07092 dd = abx * acx + aby * acy + abz * acz; 07093 07094 d = (dd * dd) / (Lv * Lw); 07095 if (d > 1.0) d = 1.0; // Rounding. 07096 q = 1.0 - sqrt(d); // Notice 0 < q < 1.0. 07097 07098 return q <= eps; 07099 } 07100 07102 // // 07103 // iscoplanar() Check if four points are approximately coplanar. // 07104 // // 07105 // 'vol6' is six times of the signed volume of the tetrahedron formed by the // 07106 // four points. 'eps' is the relative error tolerance. The coplanarity is // 07107 // determined by the value: q = fabs(vol6) / L^3, where L is the average // 07108 // edge length of the tet. They're coplanar if q <= eps. // 07109 // // 07111 07112 bool tetgenmesh:: 07113 iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL eps) 07114 { 07115 REAL L, q; 07116 REAL x, y, z; 07117 07118 if (vol6 == 0.0) return true; 07119 07120 x = k[0] - l[0]; 07121 y = k[1] - l[1]; 07122 z = k[2] - l[2]; 07123 L = sqrt(x * x + y * y + z * z); 07124 x = l[0] - m[0]; 07125 y = l[1] - m[1]; 07126 z = l[2] - m[2]; 07127 L += sqrt(x * x + y * y + z * z); 07128 x = m[0] - k[0]; 07129 y = m[1] - k[1]; 07130 z = m[2] - k[2]; 07131 L += sqrt(x * x + y * y + z * z); 07132 x = k[0] - n[0]; 07133 y = k[1] - n[1]; 07134 z = k[2] - n[2]; 07135 L += sqrt(x * x + y * y + z * z); 07136 x = l[0] - n[0]; 07137 y = l[1] - n[1]; 07138 z = l[2] - n[2]; 07139 L += sqrt(x * x + y * y + z * z); 07140 x = m[0] - n[0]; 07141 y = m[1] - n[1]; 07142 z = m[2] - n[2]; 07143 L += sqrt(x * x + y * y + z * z); 07144 #ifdef SELF_CHECK 07145 assert(L > 0.0); 07146 #endif 07147 L /= 6.0; 07148 q = fabs(vol6) / (L * L * L); 07149 07150 return q <= eps; 07151 } 07152 07154 // // 07155 // iscospheric() Check if five points are approximately coplanar. // 07156 // // 07157 // 'vol24' is the 24 times of the signed volume of the 4-dimensional simplex // 07158 // formed by the five points. 'eps' is the relative tolerance. The cosphere // 07159 // case is determined by the value: q = fabs(vol24) / L^4, where L is the // 07160 // average edge length of the simplex. They're cosphere if q <= eps. // 07161 // // 07163 07164 bool tetgenmesh:: 07165 iscospheric(REAL* k, REAL* l, REAL* m, REAL* n, REAL* o, REAL vol24, REAL eps) 07166 { 07167 REAL L, q; 07168 07169 // A 4D simplex has 10 edges. 07170 L = distance(k, l); 07171 L += distance(l, m); 07172 L += distance(m, k); 07173 L += distance(k, n); 07174 L += distance(l, n); 07175 L += distance(m, n); 07176 L += distance(k, o); 07177 L += distance(l, o); 07178 L += distance(m, o); 07179 L += distance(n, o); 07180 #ifdef SELF_CHECK 07181 assert(L > 0.0); 07182 #endif 07183 L /= 10.0; 07184 q = fabs(vol24) / (L * L * L * L); 07185 07186 return q < eps; 07187 } 07188 07189 // 07190 // End of geometric tests 07191 // 07192 07193 // 07194 // Begin of Geometric quantities calculators 07195 // 07196 07197 // distance() computs the Euclidean distance between two points. 07198 inline REAL tetgenmesh::distance(REAL* p1, REAL* p2) 07199 { 07200 return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + 07201 (p2[1] - p1[1]) * (p2[1] - p1[1]) + 07202 (p2[2] - p1[2]) * (p2[2] - p1[2])); 07203 } 07204 07206 // // 07207 // shortdistance() Returns the shortest distance from point p to a line // 07208 // defined by two points e1 and e2. // 07209 // // 07210 // First compute the projection length l_p of the vector v1 = p - e1 along // 07211 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the // 07212 // shortest distance. // 07213 // // 07214 // This routine allows that p is collinear with the line. In this case, the // 07215 // return value is zero. The two points e1 and e2 should not be identical. // 07216 // // 07218 07219 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2) 07220 { 07221 REAL v1[3], v2[3]; 07222 REAL len, l_p; 07223 07224 v1[0] = e2[0] - e1[0]; 07225 v1[1] = e2[1] - e1[1]; 07226 v1[2] = e2[2] - e1[2]; 07227 v2[0] = p[0] - e1[0]; 07228 v2[1] = p[1] - e1[1]; 07229 v2[2] = p[2] - e1[2]; 07230 07231 len = sqrt(dot(v1, v1)); 07232 #ifdef SELF_CHECK 07233 assert(len != 0.0); 07234 #endif 07235 v1[0] /= len; 07236 v1[1] /= len; 07237 v1[2] /= len; 07238 l_p = dot(v1, v2); 07239 07240 return sqrt(dot(v2, v2) - l_p * l_p); 07241 } 07242 07244 // // 07245 // shortdistance() Returns the shortest distance from point p to a face. // 07246 // // 07248 07249 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3) 07250 { 07251 REAL prj[3]; 07252 07253 projpt2face(p, e1, e2, e3, prj); 07254 return distance(p, prj); 07255 } 07256 07258 // // 07259 // interiorangle() Return the interior angle (0 - 2 * PI) between vectors // 07260 // o->p1 and o->p2. // 07261 // // 07262 // 'n' is the normal of the plane containing face (o, p1, p2). The interior // 07263 // angle is the total angle rotating from o->p1 around n to o->p2. Exchange // 07264 // the position of p1 and p2 will get the complement angle of the other one. // 07265 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set // 07266 // 'n' be NULL if you only want the interior angle between 0 - PI. // 07267 // // 07269 07270 REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n) 07271 { 07272 REAL v1[3], v2[3], np[3]; 07273 REAL theta, costheta, lenlen; 07274 REAL ori, len1, len2; 07275 07276 // Get the interior angle (0 - PI) between o->p1, and o->p2. 07277 v1[0] = p1[0] - o[0]; 07278 v1[1] = p1[1] - o[1]; 07279 v1[2] = p1[2] - o[2]; 07280 v2[0] = p2[0] - o[0]; 07281 v2[1] = p2[1] - o[1]; 07282 v2[2] = p2[2] - o[2]; 07283 len1 = sqrt(dot(v1, v1)); 07284 len2 = sqrt(dot(v2, v2)); 07285 lenlen = len1 * len2; 07286 #ifdef SELF_CHECK 07287 assert(lenlen != 0.0); 07288 #endif 07289 costheta = dot(v1, v2) / lenlen; 07290 if (costheta > 1.0) { 07291 costheta = 1.0; // Roundoff. 07292 } else if (costheta < -1.0) { 07293 costheta = -1.0; // Roundoff. 07294 } 07295 theta = acos(costheta); 07296 if (n != NULL) { 07297 // Get a point above the face (o, p1, p2); 07298 np[0] = o[0] + n[0]; 07299 np[1] = o[1] + n[1]; 07300 np[2] = o[2] + n[2]; 07301 // Adjust theta (0 - 2 * PI). 07302 ori = orient3d(p1, o, np, p2); 07303 if (ori > 0.0) { 07304 theta = 2 * PI - theta; 07305 } 07306 } 07307 07308 return theta; 07309 } 07310 07312 // // 07313 // projpt2edge() Return the projection point from a point to an edge. // 07314 // // 07316 07317 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj) 07318 { 07319 REAL v1[3], v2[3]; 07320 REAL len, l_p; 07321 07322 v1[0] = e2[0] - e1[0]; 07323 v1[1] = e2[1] - e1[1]; 07324 v1[2] = e2[2] - e1[2]; 07325 v2[0] = p[0] - e1[0]; 07326 v2[1] = p[1] - e1[1]; 07327 v2[2] = p[2] - e1[2]; 07328 07329 len = sqrt(dot(v1, v1)); 07330 #ifdef SELF_CHECK 07331 assert(len != 0.0); 07332 #endif 07333 v1[0] /= len; 07334 v1[1] /= len; 07335 v1[2] /= len; 07336 l_p = dot(v1, v2); 07337 07338 prj[0] = e1[0] + l_p * v1[0]; 07339 prj[1] = e1[1] + l_p * v1[1]; 07340 prj[2] = e1[2] + l_p * v1[2]; 07341 } 07342 07344 // // 07345 // projpt2face() Return the projection point from a point to a face. // 07346 // // 07348 07349 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj) 07350 { 07351 REAL fnormal[3], v1[3]; 07352 REAL len, dist; 07353 07354 // Get the unit face normal. 07355 facenormal(f1, f2, f3, fnormal, &len); 07356 #ifdef SELF_CHECK 07357 assert(len > 0.0); 07358 #endif 07359 fnormal[0] /= len; 07360 fnormal[1] /= len; 07361 fnormal[2] /= len; 07362 // Get the vector v1 = |p - f1|. 07363 v1[0] = p[0] - f1[0]; 07364 v1[1] = p[1] - f1[1]; 07365 v1[2] = p[2] - f1[2]; 07366 // Get the project distance. 07367 dist = dot(fnormal, v1); 07368 07369 // Get the project point. 07370 prj[0] = p[0] - dist * fnormal[0]; 07371 prj[1] = p[1] - dist * fnormal[1]; 07372 prj[2] = p[2] - dist * fnormal[2]; 07373 } 07374 07376 // // 07377 // facenormal() Calculate the normal of a face given by three points. // 07378 // // 07379 // In general, the face normal can be calculate by the cross product of any // 07380 // pair of the three edge vectors. However, if the three points are nearly // 07381 // collinear, the rounding error may harm the result. To choose a good pair // 07382 // of vectors is helpful to reduce the error. // 07383 // // 07385 07386 void tetgenmesh::facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen) 07387 { 07388 REAL v1[3], v2[3]; 07389 07390 v1[0] = pb[0] - pa[0]; 07391 v1[1] = pb[1] - pa[1]; 07392 v1[2] = pb[2] - pa[2]; 07393 v2[0] = pc[0] - pa[0]; 07394 v2[1] = pc[1] - pa[1]; 07395 v2[2] = pc[2] - pa[2]; 07396 07397 cross(v1, v2, n); 07398 if (nlen != (REAL *) NULL) { 07399 *nlen = sqrt(dot(n, n)); 07400 } 07401 } 07402 07404 // // 07405 // edgeorthonormal() Return the unit normal of an edge in a given plane. // 07406 // // 07407 // The edge is from e1 to e2, the plane is defined by given an additional // 07408 // point op, which is non-collinear with the edge. In addition, the side of // 07409 // the edge in which op lies defines the positive position of the normal. // 07410 // // 07411 // Let v1 be the unit vector from e1 to e2, v2 be the unit edge vector from // 07412 // e1 to op, fn be the unit face normal calculated by fn = v1 x v2. Then the // 07413 // unit edge normal of e1e2 pointing to op is n = fn x v1. Note, we should // 07414 // not change the position of fn and v1, otherwise, we get the edge normal // 07415 // pointing to the other side of op. // 07416 // // 07418 07419 void tetgenmesh::edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n) 07420 { 07421 REAL v1[3], v2[3], fn[3]; 07422 REAL len; 07423 07424 // Get the edge vector v1. 07425 v1[0] = e2[0] - e1[0]; 07426 v1[1] = e2[1] - e1[1]; 07427 v1[2] = e2[2] - e1[2]; 07428 // Get the edge vector v2. 07429 v2[0] = op[0] - e1[0]; 07430 v2[1] = op[1] - e1[1]; 07431 v2[2] = op[2] - e1[2]; 07432 // Get the face normal fn = v1 x v2. 07433 cross(v1, v2, fn); 07434 // Get the edge normal n pointing to op. n = fn x v1. 07435 cross(fn, v1, n); 07436 // Normalize the vector. 07437 len = sqrt(dot(n, n)); 07438 n[0] /= len; 07439 n[1] /= len; 07440 n[2] /= len; 07441 } 07442 07444 // // 07445 // facedihedral() Return the dihedral angle (in radian) between two // 07446 // adjoining faces. // 07447 // // 07448 // 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are // 07449 // apexes of these two faces. Return the angle (between 0 to 2*pi) between // 07450 // the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). // 07451 // // 07453 07454 REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2) 07455 { 07456 REAL n1[3], n2[3]; 07457 REAL n1len, n2len; 07458 REAL costheta, ori; 07459 REAL theta; 07460 07461 facenormal(pa, pb, pc1, n1, &n1len); 07462 facenormal(pa, pb, pc2, n2, &n2len); 07463 costheta = dot(n1, n2) / (n1len * n2len); 07464 // Be careful rounding error! 07465 if (costheta > 1.0) { 07466 costheta = 1.0; 07467 } else if (costheta < -1.0) { 07468 costheta = -1.0; 07469 } 07470 theta = acos(costheta); 07471 ori = orient3d(pa, pb, pc1, pc2); 07472 if (ori > 0.0) { 07473 theta = 2 * PI - theta; 07474 } 07475 07476 return theta; 07477 } 07478 07480 // // 07481 // tetalldihedral() Get all (six) dihedral angles of a tet. // 07482 // // 07483 // The tet is given by its four corners a, b, c, and d. If 'cosdd' is not // 07484 // NULL, it returns the cosines of the 6 dihedral angles, the corresponding // 07485 // edges are: ab, bc, ca, ad, bd, and cd. If 'cosmaxd' (or 'cosmind') is not // 07486 // NULL, it returns the cosine of the maximal (or minimal) dihedral angle. // 07487 // // 07489 07490 void tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd, 07491 REAL* cosdd, REAL* cosmaxd, REAL* cosmind) 07492 { 07493 REAL N[4][3], cosd, len; 07494 int f1, f2, i, j; 07495 07496 f1=0; 07497 f2=0; 07498 07499 // Get four normals of faces of the tet. 07500 tetallnormal(pa, pb, pc, pd, N, NULL); 07501 // Normalize the normals. 07502 for (i = 0; i < 4; i++) { 07503 len = sqrt(dot(N[i], N[i])); 07504 if (len != 0.0) { 07505 for (j = 0; j < 3; j++) N[i][j] /= len; 07506 } 07507 } 07508 07509 for (i = 0; i < 6; i++) { 07510 switch (i) { 07511 case 0: f1 = 2; f2 = 3; break; // edge ab. 07512 case 1: f1 = 0; f2 = 3; break; // edge bc. 07513 case 2: f1 = 1; f2 = 3; break; // edge ca. 07514 case 3: f1 = 1; f2 = 2; break; // edge ad. 07515 case 4: f1 = 2; f2 = 0; break; // edge bd. 07516 case 5: f1 = 0; f2 = 1; break; // edge cd. 07517 } 07518 cosd = -dot(N[f1], N[f2]); 07519 if (cosdd) cosdd[i] = cosd; 07520 if (i == 0) { 07521 if (cosmaxd) *cosmaxd = cosd; 07522 if (cosmind) *cosmind = cosd; 07523 } else { 07524 if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd; 07525 if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind; 07526 } 07527 } 07528 } 07529 07531 // // 07532 // tetallnormal() Get the in-noramls of the four faces of a given tet. // 07533 // // 07534 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, // 07535 // N[1] acd, N[2] bad, N[3] abc. These normals are unnormalized. // 07536 // // 07538 07539 void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd, 07540 REAL N[4][3], REAL* volume) 07541 { 07542 REAL A[4][4], rhs[4], D; 07543 int indx[4]; 07544 int i, j; 07545 07546 // get the entries of A[3][3]. 07547 for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec 07548 for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec 07549 for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec 07550 // Compute the inverse of matrix A, to get 3 normals of the 4 faces. 07551 lu_decmp(A, 3, indx, &D, 0); // Decompose the matrix just once. 07552 if (volume != NULL) { 07553 // Get the volume of the tet. 07554 *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0; 07555 } 07556 for (j = 0; j < 3; j++) { 07557 for (i = 0; i < 3; i++) rhs[i] = 0.0; 07558 rhs[j] = 1.0; // Positive means the inside direction 07559 lu_solve(A, 3, indx, rhs, 0); 07560 for (i = 0; i < 3; i++) N[j][i] = rhs[i]; 07561 } 07562 // Get the fourth normal by summing up the first three. 07563 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; 07564 } 07565 07567 // // 07568 // tetaspectratio() Calculate the aspect ratio of the tetrahedron. // 07569 // // 07570 // The aspect ratio of a tet is R/h, where R is the circumradius and h is // 07571 // the shortest height of the tet. // 07572 // // 07574 07575 REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd) 07576 { 07577 REAL vda[3], vdb[3], vdc[3]; 07578 REAL N[4][3], A[4][4], rhs[4], D; 07579 REAL H[4], volume, radius2, minheightinv; 07580 int indx[4]; 07581 int i, j; 07582 07583 // Set the matrix A = [vda, vdb, vdc]^T. 07584 for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i]; 07585 for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i]; 07586 for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i]; 07587 // Lu-decompose the matrix A. 07588 lu_decmp(A, 3, indx, &D, 0); 07589 // Get the volume of abcd. 07590 volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; 07591 // Check if it is zero. 07592 if (volume == 0.0) return 1.0e+200; // A degenerate tet. 07593 // if (volume < 0.0) volume = -volume; 07594 // Check the radiu-edge ratio of the tet. 07595 rhs[0] = 0.5 * dot(vda, vda); 07596 rhs[1] = 0.5 * dot(vdb, vdb); 07597 rhs[2] = 0.5 * dot(vdc, vdc); 07598 lu_solve(A, 3, indx, rhs, 0); 07599 // Get the circumcenter. 07600 // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i]; 07601 // Get the square of the circumradius. 07602 radius2 = dot(rhs, rhs); 07603 07604 // Compute the 4 face normals (N[0], ..., N[3]). 07605 for (j = 0; j < 3; j++) { 07606 for (i = 0; i < 3; i++) rhs[i] = 0.0; 07607 rhs[j] = 1.0; // Positive means the inside direction 07608 lu_solve(A, 3, indx, rhs, 0); 07609 for (i = 0; i < 3; i++) N[j][i] = rhs[i]; 07610 } 07611 // Get the fourth normal by summing up the first three. 07612 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; 07613 // Normalized the normals. 07614 for (i = 0; i < 4; i++) { 07615 // H[i] is the inverse of the height of its corresponding face. 07616 H[i] = sqrt(dot(N[i], N[i])); 07617 // if (H[i] > 0.0) { 07618 // for (j = 0; j < 3; j++) N[i][j] /= H[i]; 07619 // } 07620 } 07621 // Get the radius of the inscribed sphere. 07622 // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]); 07623 // Get the biggest H[i] (corresponding to the smallest height). 07624 minheightinv = H[0]; 07625 for (i = 1; i < 3; i++) { 07626 if (H[i] > minheightinv) minheightinv = H[i]; 07627 } 07628 07629 return sqrt(radius2) * minheightinv; 07630 } 07631 07633 // // 07634 // circumsphere() Calculate the smallest circumsphere (center and radius) // 07635 // of the given three or four points. // 07636 // // 07637 // The circumsphere of four points (a tetrahedron) is unique if they are not // 07638 // degenerate. If 'pd = NULL', the smallest circumsphere of three points is // 07639 // the diametral sphere of the triangle if they are not degenerate. // 07640 // // 07641 // Return TRUE if the input points are not degenerate and the circumcenter // 07642 // and circumradius are returned in 'cent' and 'radius' respectively if they // 07643 // are not NULLs. Otherwise, return FALSE indicated the points are degenrate.// 07644 // // 07646 07647 bool tetgenmesh:: 07648 circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius) 07649 { 07650 REAL A[4][4], rhs[4], D; 07651 int indx[4]; 07652 07653 // Compute the coefficient matrix A (3x3). 07654 A[0][0] = pb[0] - pa[0]; 07655 A[0][1] = pb[1] - pa[1]; 07656 A[0][2] = pb[2] - pa[2]; 07657 A[1][0] = pc[0] - pa[0]; 07658 A[1][1] = pc[1] - pa[1]; 07659 A[1][2] = pc[2] - pa[2]; 07660 if (pd != NULL) { 07661 A[2][0] = pd[0] - pa[0]; 07662 A[2][1] = pd[1] - pa[1]; 07663 A[2][2] = pd[2] - pa[2]; 07664 } else { 07665 cross(A[0], A[1], A[2]); 07666 } 07667 07668 // Compute the right hand side vector b (3x1). 07669 rhs[0] = 0.5 * dot(A[0], A[0]); 07670 rhs[1] = 0.5 * dot(A[1], A[1]); 07671 if (pd != NULL) { 07672 rhs[2] = 0.5 * dot(A[2], A[2]); 07673 } else { 07674 rhs[2] = 0.0; 07675 } 07676 07677 // Solve the 3 by 3 equations use LU decomposition with partial pivoting 07678 // and backward and forward substitute.. 07679 if (!lu_decmp(A, 3, indx, &D, 0)) { 07680 if (radius != (REAL *) NULL) *radius = 0.0; 07681 return false; 07682 } 07683 lu_solve(A, 3, indx, rhs, 0); 07684 if (cent != (REAL *) NULL) { 07685 cent[0] = pa[0] + rhs[0]; 07686 cent[1] = pa[1] + rhs[1]; 07687 cent[2] = pa[2] + rhs[2]; 07688 } 07689 if (radius != (REAL *) NULL) { 07690 *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); 07691 } 07692 return true; 07693 } 07694 07696 // // 07697 // inscribedsphere() Compute the radius and center of the biggest // 07698 // inscribed sphere of a given tetrahedron. // 07699 // // 07700 // The tetrahedron is given by its four points, it must not be degenerate. // 07701 // The center and radius are returned in 'cent' and 'radius' respectively if // 07702 // they are not NULLs. // 07703 // // 07704 // Geometrical fact. For any simplex in d dimension, // 07705 // r/h1 + r/h2 + ... r/hn = 1 (n <= d + 1); // 07706 // where r is the radius of inscribed ball, and h is the height of each side // 07707 // of the simplex. The value of 'r/h' is just the barycenter coordinates of // 07708 // each vertex of the simplex. Therefore, we can compute the radius and // 07709 // center of the smallest inscribed ball as following equations: // 07710 // r = 1.0 / (1/h1 + 1/h2 + ... + 1/hn); (1) // 07711 // C = r/h1 * P1 + r/h2 * P2 + ... + r/hn * Pn; (2) // 07712 // where C is the vector of center, P1, P2, .. Pn are vectors of vertices. // 07713 // Here (2) contains n linear equations with n variables. (h, P) must be a // 07714 // pair, h is the height from P to its opposite face. // 07715 // // 07717 07718 void tetgenmesh::inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, 07719 REAL* cent, REAL* radius) 07720 { 07721 REAL N[4][3], H[4]; // Normals (colume vectors) and heights of each face. 07722 REAL rd; 07723 int i; 07724 07725 // Get the all normals of the tet. 07726 tetallnormal(pa, pb, pc, pd, N, NULL); 07727 for (i = 0; i < 4; i++) { 07728 // H[i] is the inverse of height of its corresponding face. 07729 H[i] = sqrt(dot(N[i], N[i])); 07730 } 07731 // Compute the radius use eq. (1). 07732 rd = 1.0 / (H[0] + H[1] + H[2] + H[3]); 07733 if (radius != (REAL*) NULL) *radius = rd; 07734 if (cent != (REAL*) NULL) { 07735 // Compute the center use eq. (2). 07736 cent[0] = rd * (H[0] * pa[0] + H[1] * pb[0] + H[2] * pc[0] + H[3] * pd[0]); 07737 cent[1] = rd * (H[0] * pa[1] + H[1] * pb[1] + H[2] * pc[1] + H[3] * pd[1]); 07738 cent[2] = rd * (H[0] * pa[2] + H[1] * pb[2] + H[2] * pc[2] + H[3] * pd[2]); 07739 } 07740 } 07741 07743 // // 07744 // rotatepoint() Create a point by rotating an existing point. // 07745 // // 07746 // Create a 3D point by rotating point 'p' with an angle 'rotangle' (in arc // 07747 // degree) around a rotating axis given by a vector from point 'p1' to 'p2'. // 07748 // The rotation is according with right-hand rule, i.e., use your right-hand // 07749 // to grab the axis with your thumber pointing to its positive direction, // 07750 // your fingers indicate the rotating direction. // 07751 // // 07752 // The rotating steps are the following: // 07753 // 1. Translate vector 'p1->p2' to origin, M1; // 07754 // 2. Rotate vector around the Y-axis until it lies in the YZ plane, M2; // 07755 // 3. Rotate vector around the X-axis until it lies on the Z axis, M3; // 07756 // 4. Perform the rotation of 'p' around the z-axis, M4; // 07757 // 5. Undo Step 3, M5; // 07758 // 6. Undo Step 2, M6; // 07759 // 7. Undo Step 1, M7; // 07760 // Use matrix multiplication to combine the above sequences, we get: // 07761 // p0' = T * p0, where T = M7 * M6 * M5 * M4 * M3 * M2 * M1 // 07762 // // 07764 07765 void tetgenmesh::rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2) 07766 { 07767 REAL T[4][4], pp0[4], p0t[4], p2t[4]; 07768 REAL roty, rotx, alphaR, projlen; 07769 REAL dx, dy, dz; 07770 07771 initm44(1, 0, 0, -p1[0], 07772 0, 1, 0, -p1[1], 07773 0, 0, 1, -p1[2], 07774 0, 0, 0, 1, T); 07775 pp0[0] = p[0]; pp0[1] = p[1]; pp0[2] = p[2]; pp0[3] = 1.0; 07776 m4xv4(p0t, T, pp0); // Step 1 07777 pp0[0] = p2[0]; pp0[1] = p2[1]; pp0[2] = p2[2]; pp0[3] = 1.0; 07778 m4xv4(p2t, T, pp0); // Step 1 07779 07780 // Get the rotation angle around y-axis; 07781 dx = p2t[0]; 07782 dz = p2t[2]; 07783 projlen = sqrt(dx * dx + dz * dz); 07784 if (projlen <= (b->epsilon * 1e-2) * longest) { 07785 roty = 0; 07786 } else { 07787 roty = acos(dz / projlen); 07788 if (dx < 0) { 07789 roty = -roty; 07790 } 07791 } 07792 07793 initm44(cos(-roty), 0, sin(-roty), 0, 07794 0, 1, 0, 0, 07795 -sin(-roty), 0, cos(-roty), 0, 07796 0, 0, 0, 1, T); 07797 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; 07798 m4xv4(p0t, T, pp0); // Step 2 07799 pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0; 07800 m4xv4(p2t, T, pp0); // Step 2 07801 07802 // Get the rotation angle around x-axis 07803 dy = p2t[1]; 07804 dz = p2t[2]; 07805 projlen = sqrt(dy * dy + dz * dz); 07806 if (projlen <= (b->epsilon * 1e-2) * longest) { 07807 rotx = 0; 07808 } else { 07809 rotx = acos(dz / projlen); 07810 if (dy < 0) { 07811 rotx = -rotx; 07812 } 07813 } 07814 07815 initm44(1, 0, 0, 0, 07816 0, cos(rotx), -sin(rotx), 0, 07817 0, sin(rotx), cos(rotx), 0, 07818 0, 0, 0, 1, T); 07819 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; 07820 m4xv4(p0t, T, pp0); // Step 3 07821 // pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0; 07822 // m4xv4(p2t, T, pp0); // Step 3 07823 07824 alphaR = rotangle; 07825 initm44(cos(alphaR), -sin(alphaR), 0, 0, 07826 sin(alphaR), cos(alphaR), 0, 0, 07827 0, 0, 1, 0, 07828 0, 0, 0, 1, T); 07829 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; 07830 m4xv4(p0t, T, pp0); // Step 4 07831 07832 initm44(1, 0, 0, 0, 07833 0, cos(-rotx), -sin(-rotx), 0, 07834 0, sin(-rotx), cos(-rotx), 0, 07835 0, 0, 0, 1, T); 07836 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; 07837 m4xv4(p0t, T, pp0); // Step 5 07838 07839 initm44(cos(roty), 0, sin(roty), 0, 07840 0, 1, 0, 0, 07841 -sin(roty), 0, cos(roty), 0, 07842 0, 0, 0, 1, T); 07843 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; 07844 m4xv4(p0t, T, pp0); // Step 6 07845 07846 initm44(1, 0, 0, p1[0], 07847 0, 1, 0, p1[1], 07848 0, 0, 1, p1[2], 07849 0, 0, 0, 1, T); 07850 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; 07851 m4xv4(p0t, T, pp0); // Step 7 07852 07853 p[0] = p0t[0]; 07854 p[1] = p0t[1]; 07855 p[2] = p0t[2]; 07856 } 07857 07859 // // 07860 // spherelineint() 3D line sphere (or circle) intersection. // 07861 // // 07862 // The line is given by two points p1, and p2, the sphere is centered at c // 07863 // with radius r. This function returns a pointer array p which first index // 07864 // indicates the number of intersection point, followed by coordinate pairs. // 07865 // // 07866 // The following code are adapted from: http://astronomy.swin.edu.au/pbourke // 07867 // /geometry/sphereline. Paul Bourke pbourke@swin.edu.au // 07868 // // 07870 07871 void tetgenmesh::spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7]) 07872 { 07873 REAL x1, y1, z1; // P1 coordinates (point of line) 07874 REAL x2, y2, z2; // P2 coordinates (point of line) 07875 REAL x3, y3, z3, r; // P3 coordinates and radius (sphere) 07876 REAL a, b, c, mu, i ; 07877 07878 x1 = p1[0]; y1 = p1[1]; z1 = p1[2]; 07879 x2 = p2[0]; y2 = p2[1]; z2 = p2[2]; 07880 x3 = C[0]; y3 = C[1]; z3 = C[2]; 07881 r = R; 07882 07883 a = (x2 - x1) * (x2 - x1) 07884 + (y2 - y1) * (y2 - y1) 07885 + (z2 - z1) * (z2 - z1); 07886 b = 2 * ( (x2 - x1) * (x1 - x3) 07887 + (y2 - y1) * (y1 - y3) 07888 + (z2 - z1) * (z1 - z3) ) ; 07889 c = (x3 * x3) + (y3 * y3) + (z3 * z3) 07890 + (x1 * x1) + (y1 * y1) + (z1 * z1) 07891 - 2 * (x3 * x1 + y3 * y1 + z3 * z1) - (r * r) ; 07892 i = b * b - 4 * a * c ; 07893 07894 if (i < 0.0) { 07895 // no intersection 07896 p[0] = 0.0; 07897 } else if (i == 0.0) { 07898 // one intersection 07899 p[0] = 1.0; 07900 mu = -b / (2 * a) ; 07901 p[1] = x1 + mu * (x2 - x1); 07902 p[2] = y1 + mu * (y2 - y1); 07903 p[3] = z1 + mu * (z2 - z1); 07904 } else { 07905 // two intersections 07906 p[0] = 2.0; 07907 // first intersection 07908 mu = (-b + sqrt((b * b) - 4 * a * c)) / (2 * a); 07909 p[1] = x1 + mu * (x2 - x1); 07910 p[2] = y1 + mu * (y2 - y1); 07911 p[3] = z1 + mu * (z2 - z1); 07912 // second intersection 07913 mu = (-b - sqrt((b * b) - 4 * a * c)) / (2 * a); 07914 p[4] = x1 + mu * (x2 - x1); 07915 p[5] = y1 + mu * (y2 - y1); 07916 p[6] = z1 + mu * (z2 - z1); 07917 } 07918 } 07919 07921 // // 07922 // linelineint() Calculate the shortest line between two lines in 3D. // 07923 // // 07924 // Two 3D lines generally don't intersect at a point, they may be parallel ( // 07925 // no intersections), or coincident (infinite intersections) but most often // 07926 // only their projections onto a plane intersect. If they don't exactly int- // 07927 // ersect at a point they can be connected by a line segment, the shortest // 07928 // segment is unique and is often considered to be their intersection in 3D. // 07929 // // 07930 // The following code are adapted from: http://astronomy.swin.edu.au/pbourke // 07931 // /geometry/lineline3d. Paul Bourke pbourke@swin.edu.au // 07932 // // 07933 // Calculate the line segment PaPb that is the shortest route between two // 07934 // lines P1P2 and P3P4. This function returns a pointer array p which first // 07935 // index indicates there exists solution or not, 0 means no solution, 1 meas // 07936 // has solution followed by two coordinate pairs. // 07937 // // 07939 07940 void tetgenmesh::linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7]) 07941 { 07942 REAL p13[3], p43[3], p21[3]; 07943 REAL d1343, d4321, d1321, d4343, d2121; 07944 REAL numer, denom; 07945 REAL mua, mub; 07946 07947 p13[0] = p1[0] - p3[0]; 07948 p13[1] = p1[1] - p3[1]; 07949 p13[2] = p1[2] - p3[2]; 07950 p43[0] = p4[0] - p3[0]; 07951 p43[1] = p4[1] - p3[1]; 07952 p43[2] = p4[2] - p3[2]; 07953 if (p43[0] == 0.0 && p43[1] == 0.0 && p43[2] == 0.0) { 07954 p[0] = 0.0; 07955 return; 07956 } 07957 07958 p21[0] = p2[0] - p1[0]; 07959 p21[1] = p2[1] - p1[1]; 07960 p21[2] = p2[2] - p1[2]; 07961 if (p21[0] == 0.0 && p21[1] == 0.0 && p21[2] == 0.0) { 07962 p[0] = 0.0; 07963 return; 07964 } 07965 07966 d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2]; 07967 d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2]; 07968 d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2]; 07969 d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2]; 07970 d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2]; 07971 07972 denom = d2121 * d4343 - d4321 * d4321; 07973 if (denom == 0.0) { 07974 p[0] = 0.0; 07975 return; 07976 } 07977 numer = d1343 * d4321 - d1321 * d4343; 07978 mua = numer / denom; 07979 mub = (d1343 + d4321 * mua) / d4343; 07980 07981 p[0] = 1.0; 07982 p[1] = p1[0] + mua * p21[0]; 07983 p[2] = p1[1] + mua * p21[1]; 07984 p[3] = p1[2] + mua * p21[2]; 07985 p[4] = p3[0] + mub * p43[0]; 07986 p[5] = p3[1] + mub * p43[1]; 07987 p[6] = p3[2] + mub * p43[2]; 07988 } 07989 07991 // // 07992 // planelineint() Calculate the intersection of a line and a plane. // 07993 // // 07994 // The equation of a plane (points P are on the plane with normal N and P3 // 07995 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the // 07996 // line (points P on the line passing through P1 and P2) can be written as: // 07997 // P = P1 + u (P2 - P1). The intersection of these two occurs when: // 07998 // N dot (P1 + u (P2 - P1)) = N dot P3. // 07999 // Solving for u gives: // 08000 // N dot (P3 - P1) // 08001 // u = ------------------. // 08002 // N dot (P2 - P1) // 08003 // If the denominator is 0 then N (the normal to the plane) is perpendicular // 08004 // to the line. Thus the line is either parallel to the plane and there are // 08005 // no solutions or the line is on the plane in which case there are an infi- // 08006 // nite number of solutions. // 08007 // // 08008 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the // 08009 // line. If u is non-zero, The intersection point (if exists) returns in ip. // 08010 // // 08012 08013 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2, 08014 REAL* ip, REAL* u) 08015 { 08016 REAL n[3], det, det1; 08017 08018 // Calculate N. 08019 facenormal(pa, pb, pc, n, NULL); 08020 // Calculate N dot (e2 - e1). 08021 det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1]) 08022 + n[2] * (e2[2] - e1[2]); 08023 if (det != 0.0) { 08024 // Calculate N dot (pa - e1) 08025 det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1]) 08026 + n[2] * (pa[2] - e1[2]); 08027 *u = det1 / det; 08028 ip[0] = e1[0] + *u * (e2[0] - e1[0]); 08029 ip[1] = e1[1] + *u * (e2[1] - e1[1]); 08030 ip[2] = e1[2] + *u * (e2[2] - e1[2]); 08031 } else { 08032 *u = 0.0; 08033 } 08034 } 08035 08036 // 08037 // End of Geometric quantities calculators 08038 // 08039 08040 // 08041 // Begin of memory management routines 08042 // 08043 08045 // // 08046 // dummyinit() Initialize the tetrahedron that fills "outer space" and // 08047 // the omnipresent subface. // 08048 // // 08049 // The tetrahedron that fills "outer space" called 'dummytet', is pointed to // 08050 // by every tetrahedron and subface on a boundary (be it outer or inner) of // 08051 // the tetrahedralization. Also, 'dummytet' points to one of the tetrahedron // 08052 // on the convex hull(until the holes and concavities are carved), making it // 08053 // possible to find a starting tetrahedron for point location. // 08054 // // 08055 // The omnipresent subface,'dummysh', is pointed to by every tetrahedron or // 08056 // subface that doesn't have a full complement of real subface to point to. // 08057 // // 08059 08060 void tetgenmesh::dummyinit(int tetwords, int shwords) 08061 { 08062 unsigned long alignptr; 08063 08064 // Set up 'dummytet', the 'tetrahedron' that occupies "outer space". 08065 dummytetbase = (tetrahedron *) new char[tetwords * sizeof(tetrahedron) 08066 + tetrahedrons->alignbytes]; 08067 // Align 'dummytet' on a 'tetrahedrons->alignbytes'-byte boundary. 08068 alignptr = (unsigned long) dummytetbase; 08069 dummytet = (tetrahedron *) 08070 (alignptr + (unsigned long) tetrahedrons->alignbytes 08071 - (alignptr % (unsigned long) tetrahedrons->alignbytes)); 08072 // Initialize the four adjoining tetrahedra to be "outer space". These 08073 // will eventually be changed by various bonding operations, but their 08074 // values don't really matter, as long as they can legally be 08075 // dereferenced. 08076 dummytet[0] = (tetrahedron) dummytet; 08077 dummytet[1] = (tetrahedron) dummytet; 08078 dummytet[2] = (tetrahedron) dummytet; 08079 dummytet[3] = (tetrahedron) dummytet; 08080 // Four null vertex points. 08081 dummytet[4] = (tetrahedron) NULL; 08082 dummytet[5] = (tetrahedron) NULL; 08083 dummytet[6] = (tetrahedron) NULL; 08084 dummytet[7] = (tetrahedron) NULL; 08085 08086 if (b->useshelles) { 08087 // Set up 'dummysh', the omnipresent "subface" pointed to by any 08088 // tetrahedron side or subface end that isn't attached to a real 08089 // subface. 08090 dummyshbase = (shellface *) new char[shwords * sizeof(shellface) 08091 + subfaces->alignbytes]; 08092 // Align 'dummysh' on a 'subfaces->alignbytes'-byte boundary. 08093 alignptr = (unsigned long) dummyshbase; 08094 dummysh = (shellface *) 08095 (alignptr + (unsigned long) subfaces->alignbytes 08096 - (alignptr % (unsigned long) subfaces->alignbytes)); 08097 // Initialize the three adjoining subfaces to be the omnipresent 08098 // subface. These will eventually be changed by various bonding 08099 // operations, but their values don't really matter, as long as they 08100 // can legally be dereferenced. 08101 dummysh[0] = (shellface) dummysh; 08102 dummysh[1] = (shellface) dummysh; 08103 dummysh[2] = (shellface) dummysh; 08104 // Three null vertex points. 08105 dummysh[3] = (shellface) NULL; 08106 dummysh[4] = (shellface) NULL; 08107 dummysh[5] = (shellface) NULL; 08108 // Initialize the two adjoining tetrahedra to be "outer space". 08109 dummysh[6] = (shellface) dummytet; 08110 dummysh[7] = (shellface) dummytet; 08111 // Initialize the three adjoining subsegments to be "out boundary". 08112 dummysh[8] = (shellface) dummysh; 08113 dummysh[9] = (shellface) dummysh; 08114 dummysh[10] = (shellface) dummysh; 08115 // Initialize the pointer to badface structure. 08116 dummysh[11] = (shellface) NULL; 08117 // Initialize the four adjoining subfaces of 'dummytet' to be the 08118 // omnipresent subface. 08119 dummytet[8 ] = (tetrahedron) dummysh; 08120 dummytet[9 ] = (tetrahedron) dummysh; 08121 dummytet[10] = (tetrahedron) dummysh; 08122 dummytet[11] = (tetrahedron) dummysh; 08123 } 08124 } 08125 08127 // // 08128 // initializepools() Calculate the sizes of the point, tetrahedron, and // 08129 // subface. Initialize their memory pools. // 08130 // // 08131 // This routine also computes the indices 'pointmarkindex', 'point2simindex',// 08132 // and 'point2pbcptindex' used to find values within each point; computes // 08133 // indices 'highorderindex', 'elemattribindex', and 'volumeboundindex' used // 08134 // to find values within each tetrahedron. // 08135 // // 08136 // There are two types of boundary elements, which are subfaces and subsegs, // 08137 // they are stored in seperate pools. However, the data structures of them // 08138 // are the same. A subsegment can be regarded as a degenerate subface, i.e.,// 08139 // one of its three corners is not used. We set the apex of it be 'NULL' to // 08140 // distinguish it's a subsegment. // 08141 // // 08143 08144 void tetgenmesh::initializepools() 08145 { 08146 enum wordtype wtype; 08147 int pointsize, elesize, shsize; 08148 08149 // Default checkpbc = 0; 08150 if ((b->plc || b->refine) && (in->pbcgrouplist != NULL)) { 08151 checkpbcs = 1; 08152 } 08153 // Default varconstraint = 0; 08154 if (in->segmentconstraintlist || in->facetconstraintlist) { 08155 varconstraint = 1; 08156 } 08157 08158 // The index within each point at which its metric tensor is found. It is 08159 // saved directly after the list of point attributes. 08160 pointmtrindex = 3 + in->numberofpointattributes; 08161 // Decide the size (1, 3, or 6) of the metric tensor. 08162 if (b->metric) { 08163 // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file). 08164 if (bgm != (tetgenmesh *) NULL) { 08165 // A background mesh is allocated. It may not exist though. 08166 sizeoftensor = (bgm->in != (tetgenio *) NULL) ? 08167 bgm->in->numberofpointmtrs : in->numberofpointmtrs; 08168 } else { 08169 // No given background mesh - Itself is a background mesh. 08170 sizeoftensor = in->numberofpointmtrs; 08171 } 08172 // Make sure sizeoftensor is at least 1. 08173 sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1; 08174 } else { 08175 // For '-q' option. Make sure to have space for saving a scalar value. 08176 sizeoftensor = b->quality ? 1 : 0; 08177 } 08178 // The index within each point at which an element pointer is found, where 08179 // the index is measured in pointers. Ensure the index is aligned to a 08180 // sizeof(tetrahedron)-byte address. 08181 point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL) 08182 + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); 08183 if (b->plc || b->refine) { 08184 // Increase the point size by three pointers, which are: 08185 // - a pointer to a tet, read by point2tet(); 08186 // - a pointer to a subface/subsegment , read by point2sh(); 08187 // - a pointer to a parent point, read by point2ppt()). 08188 if (b->metric) { 08189 // Increase one pointer to a tet of the background mesh. 08190 pointsize = (point2simindex + 4) * sizeof(tetrahedron); 08191 } else { 08192 pointsize = (point2simindex + 3) * sizeof(tetrahedron); 08193 } 08194 // The index within each point at which a pbc point is found. 08195 point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1) 08196 / sizeof(tetrahedron); 08197 if (checkpbcs) { 08198 // Increase the size by one pointer to a corresponding pbc point, 08199 // read by point2pbcpt(). 08200 pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron); 08201 } 08202 } else { 08203 pointsize = point2simindex * sizeof(tetrahedron); 08204 } 08205 // The index within each point at which the boundary marker is found, 08206 // Ensure the point marker is aligned to a sizeof(int)-byte address. 08207 pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int); 08208 // Now point size is the ints (inidcated by pointmarkindex) plus: 08209 // - an integer for boundary marker; 08210 // - an integer for vertex type; 08211 pointsize = (pointmarkindex + 2) * sizeof(int); 08212 // Decide the wordtype used in vertex pool. 08213 wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER; 08214 // Initialize the pool of vertices. 08215 points = new memorypool(pointsize, VERPERBLOCK, wtype, 0); 08216 08217 // The number of bytes occupied by a tetrahedron. There are four pointers 08218 // to other tetrahedra, four pointers to corners, and possibly four 08219 // pointers to subfaces. 08220 elesize = (8 + b->useshelles * 6) * sizeof(tetrahedron); 08221 // If Voronoi diagram is wanted, make sure we have additional space. 08222 if (b->voroout && (b->useshelles == 0)) { 08223 elesize = (8 + 4) * sizeof(tetrahedron); 08224 } 08225 // The index within each element at which its attributes are found, where 08226 // the index is measured in REALs. 08227 elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL); 08228 // The index within each element at which the maximum voulme bound is 08229 // found, where the index is measured in REALs. Note that if the 08230 // `b->regionattrib' flag is set, an additional attribute will be added. 08231 volumeboundindex = elemattribindex + in->numberoftetrahedronattributes 08232 + (b->regionattrib > 0); 08233 // If element attributes or an constraint are needed, increase the number 08234 // of bytes occupied by an element. 08235 if (b->varvolume) { 08236 elesize = (volumeboundindex + 1) * sizeof(REAL); 08237 } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) { 08238 elesize = volumeboundindex * sizeof(REAL); 08239 } 08240 // If element neighbor graph is requested (-n switch), an additional 08241 // integer is allocated for each element. 08242 elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int); 08243 if (b->neighout || b->voroout) { 08244 elesize = (elemmarkerindex + 1) * sizeof(int); 08245 } 08246 // If -o2 switch is used, an additional pointer pointed to the list of 08247 // higher order nodes is allocated for each element. 08248 highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); 08249 if (b->order == 2) { 08250 elesize = (highorderindex + 1) * sizeof(tetrahedron); 08251 } 08252 // Having determined the memory size of an element, initialize the pool. 08253 tetrahedrons = new memorypool(elesize, ELEPERBLOCK, POINTER, 8); 08254 08255 if (b->useshelles) { 08256 // The number of bytes occupied by a subface. The list of pointers 08257 // stored in a subface are: three to other subfaces, three to corners, 08258 // three to subsegments, two to tetrahedra, and one to a badface. 08259 shsize = 12 * sizeof(shellface); 08260 // The index within each subface at which the maximum area bound is 08261 // found, where the index is measured in REALs. 08262 areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL); 08263 // If -q switch is in use, increase the number of bytes occupied by 08264 // a subface for saving maximum area bound. 08265 if (b->quality && varconstraint) { 08266 shsize = (areaboundindex + 1) * sizeof(REAL); 08267 } else { 08268 shsize = areaboundindex * sizeof(REAL); 08269 } 08270 // The index within subface at which the facet marker is found. Ensure 08271 // the marker is aligned to a sizeof(int)-byte address. 08272 shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int); 08273 // Increase the number of bytes by two or three integers, one for facet 08274 // marker, one for shellface type, and optionally one for pbc group. 08275 shsize = (shmarkindex + 2 + checkpbcs) * sizeof(int); 08276 // Initialize the pool of subfaces. Each subface record is eight-byte 08277 // aligned so it has room to store an edge version (from 0 to 5) in 08278 // the least three bits. 08279 subfaces = new memorypool(shsize, SUBPERBLOCK, POINTER, 8); 08280 // Initialize the pool of subsegments. The subsegment's record is same 08281 // with subface. 08282 subsegs = new memorypool(shsize, SUBPERBLOCK, POINTER, 8); 08283 // Initialize the "outer space" tetrahedron and omnipresent subface. 08284 dummyinit(tetrahedrons->itemwords, subfaces->itemwords); 08285 } else { 08286 // Initialize the "outer space" tetrahedron. 08287 dummyinit(tetrahedrons->itemwords, 0); 08288 } 08289 } 08290 08292 // // 08293 // tetrahedrondealloc() Deallocate space for a tet., marking it dead. // 08294 // // 08296 08297 void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron) 08298 { 08299 // Set tetrahedron's vertices to NULL. This makes it possible to detect 08300 // dead tetrahedra when traversing the list of all tetrahedra. 08301 dyingtetrahedron[4] = (tetrahedron) NULL; 08302 dyingtetrahedron[5] = (tetrahedron) NULL; 08303 dyingtetrahedron[6] = (tetrahedron) NULL; 08304 dyingtetrahedron[7] = (tetrahedron) NULL; 08305 tetrahedrons->dealloc((void *) dyingtetrahedron); 08306 } 08307 08309 // // 08310 // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. // 08311 // // 08313 08314 tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse() 08315 { 08316 tetrahedron *newtetrahedron; 08317 08318 do { 08319 newtetrahedron = (tetrahedron *) tetrahedrons->traverse(); 08320 if (newtetrahedron == (tetrahedron *) NULL) { 08321 return (tetrahedron *) NULL; 08322 } 08323 } while (newtetrahedron[7] == (tetrahedron) NULL); // Skip dead ones. 08324 return newtetrahedron; 08325 } 08326 08328 // // 08329 // shellfacedealloc() Deallocate space for a shellface, marking it dead. // 08330 // Used both for dealloc a subface and subsegment. // 08331 // // 08333 08334 void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh) 08335 { 08336 // Set shellface's vertices to NULL. This makes it possible to detect dead 08337 // shellfaces when traversing the list of all shellfaces. 08338 dyingsh[3] = (shellface) NULL; 08339 dyingsh[4] = (shellface) NULL; 08340 dyingsh[5] = (shellface) NULL; 08341 pool->dealloc((void *) dyingsh); 08342 } 08343 08345 // // 08346 // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used // 08347 // for both subfaces and subsegments pool traverse. // 08348 // // 08350 08351 tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool) 08352 { 08353 shellface *newshellface; 08354 08355 do { 08356 newshellface = (shellface *) pool->traverse(); 08357 if (newshellface == (shellface *) NULL) { 08358 return (shellface *) NULL; 08359 } 08360 } while (newshellface[3] == (shellface) NULL); // Skip dead ones. 08361 return newshellface; 08362 } 08363 08365 // // 08366 // badfacedealloc() Deallocate space for a badface, marking it dead. // 08367 // // 08369 08370 void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying) 08371 { 08372 // Set badface's forg to NULL. This makes it possible to detect dead 08373 // ones when traversing the list of all items. 08374 dying->forg = (point) NULL; 08375 pool->dealloc((void *) dying); 08376 } 08377 08379 // // 08380 // badfacetraverse() Traverse the pools, skipping dead ones. // 08381 // // 08383 08384 tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool) 08385 { 08386 badface *newsh; 08387 08388 do { 08389 newsh = (badface *) pool->traverse(); 08390 if (newsh == (badface *) NULL) { 08391 return (badface *) NULL; 08392 } 08393 } while (newsh->forg == (point) NULL); // Skip dead ones. 08394 return newsh; 08395 } 08396 08398 // // 08399 // pointdealloc() Deallocate space for a point, marking it dead. // 08400 // // 08402 08403 void tetgenmesh::pointdealloc(point dyingpoint) 08404 { 08405 // Mark the point as dead. This makes it possible to detect dead points 08406 // when traversing the list of all points. 08407 setpointtype(dyingpoint, DEADVERTEX); 08408 points->dealloc((void *) dyingpoint); 08409 } 08410 08412 // // 08413 // pointtraverse() Traverse the points, skipping dead ones. // 08414 // // 08416 08417 tetgenmesh::point tetgenmesh::pointtraverse() 08418 { 08419 point newpoint; 08420 08421 do { 08422 newpoint = (point) points->traverse(); 08423 if (newpoint == (point) NULL) { 08424 return (point) NULL; 08425 } 08426 } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones. 08427 return newpoint; 08428 } 08429 08431 // // 08432 // maketetrahedron() Create a new tetrahedron. // 08433 // // 08435 08436 void tetgenmesh::maketetrahedron(triface *newtet) 08437 { 08438 newtet->tet = (tetrahedron *) tetrahedrons->alloc(); 08439 // Initialize the four adjoining tetrahedra to be "outer space". 08440 newtet->tet[0] = (tetrahedron) dummytet; 08441 newtet->tet[1] = (tetrahedron) dummytet; 08442 newtet->tet[2] = (tetrahedron) dummytet; 08443 newtet->tet[3] = (tetrahedron) dummytet; 08444 // Four NULL vertices. 08445 newtet->tet[4] = (tetrahedron) NULL; 08446 newtet->tet[5] = (tetrahedron) NULL; 08447 newtet->tet[6] = (tetrahedron) NULL; 08448 newtet->tet[7] = (tetrahedron) NULL; 08449 // Initialize the four adjoining subfaces to be the omnipresent subface. 08450 if (b->useshelles) { 08451 newtet->tet[8 ] = (tetrahedron) dummysh; 08452 newtet->tet[9 ] = (tetrahedron) dummysh; 08453 newtet->tet[10] = (tetrahedron) dummysh; 08454 newtet->tet[11] = (tetrahedron) dummysh; 08455 newtet->tet[12] = (tetrahedron) dummysh; 08456 newtet->tet[13] = (tetrahedron) dummysh; 08457 } 08458 for (int i = 0; i < in->numberoftetrahedronattributes; i++) { 08459 setelemattribute(newtet->tet, i, 0.0); 08460 } 08461 if (b->varvolume) { 08462 setvolumebound(newtet->tet, -1.0); 08463 } 08464 // Initialize the location and version to be Zero. 08465 newtet->loc = 0; 08466 newtet->ver = 0; 08467 } 08468 08470 // // 08471 // makeshellface() Create a new shellface with version zero. Used for // 08472 // both subfaces and seusegments. // 08473 // // 08475 08476 void tetgenmesh::makeshellface(memorypool *pool, face *newface) 08477 { 08478 newface->sh = (shellface *) pool->alloc(); 08479 //Initialize the three adjoining subfaces to be the omnipresent subface. 08480 newface->sh[0] = (shellface) dummysh; 08481 newface->sh[1] = (shellface) dummysh; 08482 newface->sh[2] = (shellface) dummysh; 08483 // Three NULL vertices. 08484 newface->sh[3] = (shellface) NULL; 08485 newface->sh[4] = (shellface) NULL; 08486 newface->sh[5] = (shellface) NULL; 08487 // Initialize the two adjoining tetrahedra to be "outer space". 08488 newface->sh[6] = (shellface) dummytet; 08489 newface->sh[7] = (shellface) dummytet; 08490 // Initialize the three adjoining subsegments to be the omnipresent 08491 // subsegments. 08492 newface->sh [8] = (shellface) dummysh; 08493 newface->sh [9] = (shellface) dummysh; 08494 newface->sh[10] = (shellface) dummysh; 08495 // Initialize the pointer to badface structure. 08496 newface->sh[11] = (shellface) NULL; 08497 if (b->quality && varconstraint) { 08498 // Initialize the maximum area bound. 08499 setareabound(*newface, 0.0); 08500 } 08501 // Set the boundary marker to zero. 08502 setshellmark(*newface, 0); 08503 // Set the type. 08504 setshelltype(*newface, NSHARP); 08505 if (checkpbcs) { 08506 // Set the pbcgroup be ivalid. 08507 setshellpbcgroup(*newface, -1); 08508 } 08509 // Initialize the version to be Zero. 08510 newface->shver = 0; 08511 } 08512 08514 // // 08515 // makepoint() Create a new point. // 08516 // // 08518 08519 void tetgenmesh::makepoint(point* pnewpoint) 08520 { 08521 int ptmark, i; 08522 08523 *pnewpoint = (point) points->alloc(); 08524 // Initialize three coordinates. 08525 (*pnewpoint)[0] = 0.0; 08526 (*pnewpoint)[1] = 0.0; 08527 (*pnewpoint)[2] = 0.0; 08528 // Initialize the list of user-defined attributes. 08529 for (i = 0; i < in->numberofpointattributes; i++) { 08530 (*pnewpoint)[3 + i] = 0.0; 08531 } 08532 // Initialize the metric tensor. 08533 for (i = 0; i < sizeoftensor; i++) { 08534 (*pnewpoint)[pointmtrindex + i] = 0.0; 08535 } 08536 if (b->plc || b->refine) { 08537 // Initialize the point-to-simplex filed. 08538 setpoint2tet(*pnewpoint, NULL); 08539 setpoint2sh(*pnewpoint, NULL); 08540 setpoint2ppt(*pnewpoint, NULL); 08541 if (b->metric) { 08542 setpoint2bgmtet(*pnewpoint, NULL); 08543 } 08544 if (checkpbcs) { 08545 // Initialize the other pointer to its pbc point. 08546 setpoint2pbcpt(*pnewpoint, NULL); 08547 } 08548 } 08549 // Initialize the point marker (starting from in->firstnumber). 08550 ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); 08551 setpointmark(*pnewpoint, ptmark); 08552 // Initialize the point type. 08553 setpointtype(*pnewpoint, UNUSEDVERTEX); 08554 } 08555 08556 // 08557 // End of memory management routines 08558 // 08559 08560 // 08561 // Begin of point location routines 08562 // 08563 08565 // // 08566 // randomnation() Generate a random number between 0 and 'choices' - 1. // 08567 // // 08569 08570 unsigned long tetgenmesh::randomnation(unsigned int choices) 08571 { 08572 unsigned long newrandom; 08573 08574 if (choices >= 714025l) { 08575 newrandom = (randomseed * 1366l + 150889l) % 714025l; 08576 randomseed = (newrandom * 1366l + 150889l) % 714025l; 08577 newrandom = newrandom * (choices / 714025l) + randomseed; 08578 if (newrandom >= choices) { 08579 return newrandom - choices; 08580 } else { 08581 return newrandom; 08582 } 08583 } else { 08584 randomseed = (randomseed * 1366l + 150889l) % 714025l; 08585 return randomseed % choices; 08586 } 08587 // Old function. 08588 // randomseed = (randomseed * 1366l + 150889l) % 714025l; 08589 // return randomseed / (714025l / choices + 1); 08590 } 08591 08593 // // 08594 // distance2() Returns the square "distance" of a tetrahedron to point p. // 08595 // // 08597 08598 REAL tetgenmesh::distance2(tetrahedron* tetptr, point p) 08599 { 08600 point p1, p2, p3, p4; 08601 REAL dx, dy, dz; 08602 08603 p1 = (point) tetptr[4]; 08604 p2 = (point) tetptr[5]; 08605 p3 = (point) tetptr[6]; 08606 p4 = (point) tetptr[7]; 08607 08608 dx = p[0] - 0.25 * (p1[0] + p2[0] + p3[0] + p4[0]); 08609 dy = p[1] - 0.25 * (p1[1] + p2[1] + p3[1] + p4[1]); 08610 dz = p[2] - 0.25 * (p1[2] + p2[2] + p3[2] + p4[2]); 08611 08612 return dx * dx + dy * dy + dz * dz; 08613 } 08614 08616 // // 08617 // preciselocate() Find a simplex containing a given point. // 08618 // // 08619 // This routine implements the simple Walk-through point location algorithm. // 08620 // Begins its search from 'searchtet', assume there is a line segment L from // 08621 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk // 08622 // towards 'searchpt' by traversing all faces intersected by L. // 08623 // // 08624 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The // 08625 // returned value indicates one of the following cases: // 08626 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchtet' // 08627 // is a handle whose origin is the existing vertex. // 08628 // - Returns ONEDGE if the point lies on a mesh edge. 'searchtet' is a // 08629 // handle whose primary edge is the edge on which the point lies. // 08630 // - Returns ONFACE if the point lies strictly within a face. 'searchtet' // 08631 // is a handle whose primary face is the face on which the point lies. // 08632 // - Returns INTETRAHEDRON if the point lies strictly in a tetrahededron. // 08633 // 'searchtet' is a handle on the tetrahedron that contains the point. // 08634 // - Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a // 08635 // handle whose location is the face the point is to 'above' of. // 08636 // // 08637 // WARNING: This routine is designed for convex triangulations, and will not // 08638 // generally work after the holes and concavities have been carved. // 08639 // // 08640 // If 'maxtetnumber' > 0, stop the searching process if the number of passed // 08641 // tets is larger than it and return OUTSIDE. // 08642 // // 08644 08645 enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt, 08646 triface* searchtet, long maxtetnumber) 08647 { 08648 triface backtracetet; 08649 triface walkthroface; 08650 point forg, fdest, fapex, toppo; 08651 REAL ori1, ori2, ori3, ori4; 08652 long tetnumber; 08653 int side; 08654 08655 if (isdead(searchtet)) searchtet->tet = dummytet; 08656 if (searchtet->tet == dummytet) { 08657 searchtet->loc = 0; 08658 symself(*searchtet); 08659 } 08660 // 'searchtet' should be a valid tetrahedron now. 08661 #ifdef SELF_CHECK 08662 // assert(!isdead(searchtet) && (searchtet->tet != dummytet)); 08663 #endif 08664 if (isdead(searchtet)) { 08665 printf("Warning: Point location failed.\n"); 08666 return OUTSIDE; 08667 } 08668 08669 searchtet->ver = 0; // Keep in CCW edge ring. 08670 // Find a face of 'searchtet' such that the 'searchpt' lies strictly 08671 // above it. Such face should always exist. 08672 for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) { 08673 forg = org(*searchtet); 08674 fdest = dest(*searchtet); 08675 fapex = apex(*searchtet); 08676 ori1 = orient3d(forg, fdest, fapex, searchpt); 08677 if (ori1 < 0.0) break; 08678 } 08679 #ifdef SELF_CHECK 08680 assert(searchtet->loc < 4); 08681 #endif 08682 08683 // Define 'tetnumber' for exit the loop when it's running endless. 08684 tetnumber = 0l; 08685 while ((maxtetnumber > 0l) && (tetnumber <= maxtetnumber)) { 08686 // Check if we are reaching the boundary of the triangulation. 08687 if (searchtet->tet == dummytet) { 08688 *searchtet = backtracetet; 08689 return OUTSIDE; 08690 } 08691 // Initialize the face for returning the walk-through face. 08692 walkthroface.tet = (tetrahedron *) NULL; 08693 // Adjust the edge ring, so that 'ori1 < 0.0' holds. 08694 searchtet->ver = 0; 08695 // 'toppo' remains unchange for the following orientation tests. 08696 toppo = oppo(*searchtet); 08697 // Check the three sides of 'searchtet' to find the face through which 08698 // we can walk next. 08699 for (side = 0; side < 3; side++) { 08700 forg = org(*searchtet); 08701 fdest = dest(*searchtet); 08702 ori2 = orient3d(forg, fdest, toppo, searchpt); 08703 if (ori2 == 0.0) { 08704 // They are coplanar, check if 'searchpt' lies inside, or on an edge, 08705 // or coindice with a vertex of face (forg, fdest, toppo). 08706 fapex = apex(*searchtet); 08707 ori3 = orient3d(fdest, fapex, toppo, searchpt); 08708 if (ori3 < 0.0) { 08709 // Outside the face (fdest, fapex, toppo), walk through it. 08710 enextself(*searchtet); 08711 fnext(*searchtet, walkthroface); 08712 break; 08713 } 08714 ori4 = orient3d(fapex, forg, toppo, searchpt); 08715 if (ori4 < 0.0) { 08716 // Outside the face (fapex, forg, toppo), walk through it. 08717 enext2self(*searchtet); 08718 fnext(*searchtet, walkthroface); 08719 break; 08720 } 08721 // Remember, ori1 < 0.0, which means 'searchpt' will not on edge 08722 // (forg, fdest) or on vertex forg or fdest. 08723 #ifdef SELF_CHECK 08724 assert(ori1 < 0.0); 08725 #endif 08726 // The rest possible cases are: 08727 // (1) 'searchpt' lies on edge (fdest, toppo); 08728 // (2) 'searchpt' lies on edge (toppo, forg); 08729 // (3) 'searchpt' coincident with toppo; 08730 // (4) 'searchpt' lies inside face (forg, fdest, toppo). 08731 fnextself(*searchtet); 08732 if (ori3 == 0.0) { 08733 if (ori4 == 0.0) { 08734 // Case (4). 08735 enext2self(*searchtet); 08736 return ONVERTEX; 08737 } else { 08738 // Case (1). 08739 enextself(*searchtet); 08740 return ONEDGE; 08741 } 08742 } 08743 if (ori4 == 0.0) { 08744 // Case (2). 08745 enext2self(*searchtet); 08746 return ONEDGE; 08747 } 08748 // Case (4). 08749 return ONFACE; 08750 } else if (ori2 < 0.0) { 08751 // Outside the face (forg, fdest, toppo), walk through it. 08752 fnext(*searchtet, walkthroface); 08753 break; 08754 } 08755 // Go to check next side. 08756 enextself(*searchtet); 08757 } 08758 if (side >= 3) { 08759 // Found! Inside tetrahedron. 08760 return INTETRAHEDRON; 08761 } 08762 // We walk through the face 'walkthroface' and continue the searching. 08763 #ifdef SELF_CHECK 08764 assert(walkthroface.tet != (tetrahedron *) NULL); 08765 #endif 08766 // Store the face handle in 'backtracetet' before we take the real walk. 08767 // So we are able to restore the handle to 'searchtet' if we are 08768 // reaching the outer boundary. 08769 backtracetet = walkthroface; 08770 sym(walkthroface, *searchtet); 08771 tetnumber++; 08772 } 08773 08774 // Should never be here. 08775 // printf("Internal error in preciselocate(): Point location failed.\n"); 08776 // internalerror(); 08777 return OUTSIDE; 08778 } 08779 08781 // // 08782 // locate() Find a simplex containing a given point. // 08783 // // 08784 // This routine implements Muecke's Jump-and-walk point location algorithm. // 08785 // It improves the simple walk-through by "jumping" to a good starting point // 08786 // via random sampling. Searching begins from one of handles: the input // 08787 // 'searchtet', a recently encountered tetrahedron 'recenttet', or from one // 08788 // chosen from a random sample. The choice is made by determining which one // 08789 // 's barycenter is closest to the point we are searcing for. Having chosen // 08790 // the starting tetrahedron, the simple Walk-through algorithm is used to do // 08791 // the real walking. // 08792 // // 08793 // The return value indicates the location of the 'searchpt' (INTETRAHEDRON, // 08794 // or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding // 08795 // to that value. See the introduction part of preciselocate() for detail. // 08796 // // 08797 // WARNING: This routine is designed for convex triangulations, and will not // 08798 // generally work after the holes and concavities have been carved. // 08799 // // 08801 08802 enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt, 08803 triface *searchtet) 08804 { 08805 tetrahedron *firsttet, *tetptr; 08806 void **sampleblock; 08807 long sampleblocks, samplesperblock, samplenum; 08808 long tetblocks, i, j; 08809 unsigned long alignptr; 08810 REAL searchdist, dist; 08811 08812 // 'searchtet' should be a valid tetrahedron. 08813 if (isdead(searchtet)) { 08814 searchtet->tet = dummytet; 08815 } 08816 if (searchtet->tet == dummytet) { 08817 // This is an 'Outer Space' handle, get a hull tetrahedron. 08818 searchtet->loc = 0; 08819 symself(*searchtet); 08820 } 08821 #ifdef SELF_CHECK 08822 // assert(!isdead(searchtet)); 08823 #endif 08824 if (isdead(searchtet)) { 08825 printf("Warning: Point location failed.\n"); 08826 return OUTSIDE; 08827 } 08828 08829 // Get the distance from the suggested starting tet to the point we seek. 08830 searchdist = distance2(searchtet->tet, searchpt); 08831 08832 // If a recently encountered tetrahedron has been recorded and has not 08833 // been deallocated, test it as a good starting point. 08834 if (!isdead(&recenttet) && (recenttet.tet != searchtet->tet)) { 08835 dist = distance2(recenttet.tet, searchpt); 08836 if (dist < searchdist) { 08837 *searchtet = recenttet; 08838 searchdist = dist; 08839 } 08840 } 08841 08842 // Select "good" candidate using k random samples, taking the closest one. 08843 // The number of random samples taken is proportional to the fourth root 08844 // of the number of tetrahedra in the mesh. The next bit of code assumes 08845 // that the number of tetrahedra increases monotonically. 08846 while (SAMPLEFACTOR * samples * samples * samples * samples < 08847 tetrahedrons->items) { 08848 samples++; 08849 } 08850 // Find how much blocks in current tet pool. 08851 tetblocks = (tetrahedrons->maxitems + ELEPERBLOCK - 1) / ELEPERBLOCK; 08852 // Find the average samles per block. Each block at least have 1 sample. 08853 samplesperblock = 1 + (samples / tetblocks); 08854 sampleblocks = samples / samplesperblock; 08855 sampleblock = tetrahedrons->firstblock; 08856 for (i = 0; i < sampleblocks; i++) { 08857 alignptr = (unsigned long) (sampleblock + 1); 08858 firsttet = (tetrahedron *) 08859 (alignptr + (unsigned long) tetrahedrons->alignbytes 08860 - (alignptr % (unsigned long) tetrahedrons->alignbytes)); 08861 for (j = 0; j < samplesperblock; j++) { 08862 if (i == tetblocks - 1) { 08863 // This is the last block. 08864 samplenum = randomnation((int) 08865 (tetrahedrons->maxitems - (i * ELEPERBLOCK))); 08866 } else { 08867 samplenum = randomnation(ELEPERBLOCK); 08868 } 08869 tetptr = (tetrahedron *) 08870 (firsttet + (samplenum * tetrahedrons->itemwords)); 08871 if (tetptr[4] != (tetrahedron) NULL) { 08872 dist = distance2(tetptr, searchpt); 08873 if (dist < searchdist) { 08874 searchtet->tet = tetptr; 08875 searchdist = dist; 08876 } 08877 } 08878 } 08879 sampleblock = (void **) *sampleblock; 08880 } 08881 08882 // Call simple walk-through to locate the point. 08883 return preciselocate(searchpt, searchtet, tetrahedrons->items); 08884 } 08885 08887 // // 08888 // adjustlocate() Adjust the precise location of a vertex. // 08889 // // 08890 // 'precise' is the value returned from preciselocate(). It indicates the // 08891 // exact location of the point 'searchpt' with respect to the tetrahedron // 08892 // 'searchtet'. 'epspp' is a given relative tolerance. // 08893 // // 08894 // This routine re-evaluates the orientations of searchpt with respect to // 08895 // the four sides of searchtet. Detects the coplanarities by additinal tests // 08896 // which are based on the given tolerance. If 'precise' is ONFACE or ONEDGE, // 08897 // we can save one or two orientation tests. // 08898 // // 08899 // The return value indicates the location of the 'searchpt' (INTETRAHEDRON, // 08900 // or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding // 08901 // to that value. See the introduction part of preciselocate() for detail. // 08902 // // 08903 // WARNING: This routine detect degenerate case using relative tolerance. // 08904 // It is better used after locate() or preciselocate(). For general inputs, // 08905 // it may not able to tell the correct location. // 08906 // // 08908 08909 enum tetgenmesh::locateresult tetgenmesh::adjustlocate(point searchpt, 08910 triface* searchtet, enum locateresult precise, REAL epspp) 08911 { 08912 point torg, tdest, tapex, toppo; 08913 REAL s1, s2, s3, s4; 08914 08915 // For the given 'searchtet', the orientations tests are: 08916 // s1: (tdest, torg, tapex, searchpt); 08917 // s2: (torg, tdest, toppo, searchpt); 08918 // s3: (tdest, tapex, toppo, searchpt); 08919 // s4: (tapex, torg, toppo, searchpt); 08920 adjustedgering(*searchtet, CCW); 08921 torg = org(*searchtet); 08922 tdest = dest(*searchtet); 08923 tapex = apex(*searchtet); 08924 toppo = oppo(*searchtet); 08925 08926 switch (precise) { 08927 case ONVERTEX: 08928 // This case we don't need do any further test. 08929 return ONVERTEX; 08930 case ONEDGE: 08931 // (torg, tdest); 08932 s1 = 0.0; 08933 s2 = 0.0; 08934 break; 08935 case ONFACE: 08936 // (tdest, torg, tapex); 08937 s1 = 0.0; 08938 s2 = orient3d(torg, tdest, toppo, searchpt); 08939 break; 08940 default: // INTETRAHEDRON or OUTSIDE 08941 s1 = orient3d(tdest, torg, tapex, searchpt); 08942 s2 = orient3d(torg, tdest, toppo, searchpt); 08943 } 08944 08945 if (s1 != 0.0) { 08946 if (iscoplanar(tdest, torg, tapex, searchpt, s1, epspp)) { 08947 s1 = 0.0; 08948 } 08949 } 08950 if (s1 < 0.0) { 08951 return OUTSIDE; 08952 } 08953 08954 if (s2 != 0.0) { 08955 if (iscoplanar(torg, tdest, toppo, searchpt, s2, epspp)) { 08956 s2 = 0.0; 08957 } 08958 } 08959 if (s2 < 0.0) { 08960 fnextself(*searchtet); 08961 return OUTSIDE; 08962 } 08963 08964 s3 = orient3d(tdest, tapex, toppo, searchpt); 08965 if (s3 != 0.0) { 08966 if (iscoplanar(tdest, tapex, toppo, searchpt, s3, epspp)) { 08967 s3 = 0.0; 08968 } 08969 } 08970 if (s3 < 0.0) { 08971 enextfnextself(*searchtet); 08972 return OUTSIDE; 08973 } 08974 08975 s4 = orient3d(tapex, torg, toppo, searchpt); 08976 if (s4 != 0.0) { 08977 if (iscoplanar(tapex, torg, toppo, searchpt, s4, epspp)) { 08978 s4 = 0.0; 08979 } 08980 } 08981 if (s4 < 0.0) { 08982 enext2fnextself(*searchtet); 08983 return OUTSIDE; 08984 } 08985 08986 // Determine degenerate cases. 08987 if (s1 == 0.0) { 08988 if (s2 == 0.0) { 08989 if (s3 == 0.0) { 08990 // On tdest. 08991 enextself(*searchtet); 08992 return ONVERTEX; 08993 } 08994 if (s4 == 0.0) { 08995 // On torg. 08996 return ONVERTEX; 08997 } 08998 // On edge (torg, tdest). 08999 return ONEDGE; 09000 } 09001 if (s3 == 0.0) { 09002 if (s4 == 0.0) { 09003 // On tapex. 09004 enext2self(*searchtet); 09005 return ONVERTEX; 09006 } 09007 // On edge (tdest, tapex). 09008 enextself(*searchtet); 09009 return ONEDGE; 09010 } 09011 if (s4 == 0.0) { 09012 // On edge (tapex, torg). 09013 enext2self(*searchtet); 09014 return ONEDGE; 09015 } 09016 // On face (torg, tdest, tapex). 09017 return ONFACE; 09018 } 09019 if (s2 == 0.0) { 09020 fnextself(*searchtet); 09021 if (s3 == 0.0) { 09022 if (s4 == 0.0) { 09023 // On toppo. 09024 enext2self(*searchtet); 09025 return ONVERTEX; 09026 } 09027 // On edge (tdest, toppo). 09028 enextself(*searchtet); 09029 return ONEDGE; 09030 } 09031 if (s4 == 0.0) { 09032 // On edge (toppo, torg). 09033 enext2self(*searchtet); 09034 return ONEDGE; 09035 } 09036 // On face (torg, tdest, toppo). 09037 return ONFACE; 09038 } 09039 if (s3 == 0.0) { 09040 enextfnextself(*searchtet); 09041 if (s4 == 0.0) { 09042 // On edge (tapex, toppo). 09043 enextself(*searchtet); 09044 return ONEDGE; 09045 } 09046 // On face (tdest, tapex, toppo). 09047 return ONFACE; 09048 } 09049 if (s4 == 0.0) { 09050 enext2fnextself(*searchtet); 09051 // On face (tapex, torg, toppo). 09052 return ONFACE; 09053 } 09054 09055 // Inside tetrahedron. 09056 return INTETRAHEDRON; 09057 } 09058 09060 // // 09061 // hullwalk() Find a tetrahedron on the hull to continue search. // 09062 // // 09064 09065 enum tetgenmesh::locateresult tetgenmesh::hullwalk(point searchpt, 09066 triface *hulltet) 09067 { 09068 list* travtetlist; 09069 triface travtet, neightet; 09070 point pa, pb, pc; 09071 enum locateresult loc; 09072 REAL ori; 09073 int i; 09074 09075 travtetlist = new list(sizeof(triface), NULL, 256); 09076 travtet = *hulltet; 09077 infect(travtet); 09078 travtetlist->append(&travtet); 09079 09080 loc = OUTSIDE; 09081 for (i = 0; i < travtetlist->len(); i++) { 09082 travtet = * (triface *)(* travtetlist)[i]; 09083 // Choose the CCW-edgering in face. 09084 travtet.ver = 0; 09085 // Look for a side where pt lies below it. 09086 for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) { 09087 pa = org(travtet); 09088 pb = dest(travtet); 09089 pc = apex(travtet); 09090 ori = orient3d(pa, pb, pc, searchpt); 09091 if (ori > 0.0) break; 09092 } 09093 // Is pt above all (or coplanar with some of) the four sides? 09094 if (travtet.loc == 4) { 09095 hulltet->tet = travtet.tet; 09096 loc = adjustlocate(searchpt, hulltet, INTETRAHEDRON, b->epsilon); 09097 assert(loc != OUTSIDE); 09098 } else { // ori > 0.0 09099 // pt is below (behind) this side. We want to walk through it. 09100 sym(travtet, neightet); 09101 if (neightet.tet == dummytet) { 09102 // This is a hull side. Is p approximately on this side. 09103 loc = adjustlocate(searchpt, &travtet, OUTSIDE, b->epsilon); 09104 } 09105 if (loc == OUTSIDE) { 09106 // Let's collect all the neighbors for next searching. 09107 for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) { 09108 sym(travtet, neightet); 09109 if ((neightet.tet != dummytet) && !infected(neightet)) { 09110 // Neighbor exists and not visited. 09111 infect(neightet); 09112 travtetlist->append(&neightet); 09113 } 09114 } // for (travtet.loc = 0; 09115 } // if (loc == OUTSIDE) 09116 } // if (travtet.loc == 4) 09117 if (loc != OUTSIDE) break; 09118 } // for (i = 0; i < travtetlist->len(); i++) 09119 09120 // Uninfect traversed tets. 09121 for (i = 0; i < travtetlist->len(); i++) { 09122 travtet = * (triface *)(* travtetlist)[i]; 09123 uninfect(travtet); 09124 } 09125 09126 delete travtetlist; 09127 return loc; 09128 } 09129 09131 // // 09132 // locatesub() Find a point in the surface mesh of a facet. // 09133 // // 09134 // Searching begins from the input 'searchsh', it should be a handle on the // 09135 // convex hull of the facet triangulation. // 09136 // // 09137 // If 'stopatseg' is nonzero, the search will stop if it tries to walk // 09138 // through a subsegment, and will return OUTSIDE. // 09139 // // 09140 // On completion, 'searchsh' is a subface that contains 'searchpt'. // 09141 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' // 09142 // is a handle whose origin is the existing vertex. // 09143 // - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a // 09144 // handle whose primary edge is the edge on which the point lies. // 09145 // - Returns ONFACE if the point lies strictly within a subface. // 09146 // 'searchsh' is a handle on which the point lies. // 09147 // - Returns OUTSIDE if the point lies outside the triangulation. // 09148 // // 09149 // WARNING: This routine is designed for convex triangulations, and will not // 09150 // not generally work after the holes and concavities have been carved. // 09151 // // 09153 09154 enum tetgenmesh::locateresult tetgenmesh::locatesub(point searchpt, 09155 face* searchsh, int stopatseg, REAL epspp) 09156 { 09157 face backtracksh, spinsh, checkedge; 09158 point forg, fdest, fapex; 09159 REAL orgori, destori; 09160 REAL ori, sign; 09161 int moveleft, i; 09162 09163 if (searchsh->sh == dummysh) { 09164 searchsh->shver = 0; 09165 spivotself(*searchsh); 09166 #ifdef SELF_CHECK 09167 assert(searchsh->sh != dummysh); 09168 #endif 09169 } 09170 // Find the sign to simulate that abovepoint is 'above' the facet. 09171 adjustedgering(*searchsh, CCW); 09172 forg = sorg(*searchsh); 09173 fdest = sdest(*searchsh); 09174 fapex = sapex(*searchsh); 09175 ori = orient3d(forg, fdest, fapex, abovepoint); 09176 sign = ori > 0.0 ? -1 : 1; 09177 09178 // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has 09179 // CCW orientation with respect to searchsh in plane). Such edge 09180 // should always exist. Save it as (forg, fdest). 09181 for (i = 0; i < 3; i++) { 09182 forg = sorg(*searchsh); 09183 fdest = sdest(*searchsh); 09184 ori = orient3d(forg, fdest, abovepoint, searchpt) * sign; 09185 if (ori > 0.0) break; 09186 senextself(*searchsh); 09187 } 09188 #ifdef SELF_CHECK 09189 assert(i < 3); 09190 #endif 09191 09192 while (1) { 09193 fapex = sapex(*searchsh); 09194 // Check whether the apex is the point we seek. 09195 if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] && 09196 fapex[2] == searchpt[2]) { 09197 senext2self(*searchsh); 09198 return ONVERTEX; 09199 } 09200 // Does the point lie on the other side of the line defined by the 09201 // triangle edge opposite the triangle's destination? 09202 destori = orient3d(forg, fapex, abovepoint, searchpt) * sign; 09203 if (epspp > 0.0) { 09204 if (iscoplanar(forg, fapex, abovepoint, searchpt, destori, epspp)) { 09205 destori = 0.0; 09206 } 09207 } 09208 // Does the point lie on the other side of the line defined by the 09209 // triangle edge opposite the triangle's origin? 09210 orgori = orient3d(fapex, fdest, abovepoint, searchpt) * sign; 09211 if (epspp > 0.0) { 09212 if (iscoplanar(fapex, fdest, abovepoint, searchpt, orgori, epspp)) { 09213 orgori = 0.0; 09214 } 09215 } 09216 if (destori > 0.0) { 09217 moveleft = 1; 09218 } else { 09219 if (orgori > 0.0) { 09220 moveleft = 0; 09221 } else { 09222 // The point must be on the boundary of or inside this triangle. 09223 if (destori == 0.0) { 09224 senext2self(*searchsh); 09225 return ONEDGE; 09226 } 09227 if (orgori == 0.0) { 09228 senextself(*searchsh); 09229 return ONEDGE; 09230 } 09231 return ONFACE; 09232 } 09233 } 09234 // Move to another triangle. Leave a trace `backtracksh' in case 09235 // walking off a boundary of the triangulation. 09236 if (moveleft) { 09237 senext2(*searchsh, backtracksh); 09238 fdest = fapex; 09239 } else { 09240 senext(*searchsh, backtracksh); 09241 forg = fapex; 09242 } 09243 // Check if we meet a segment. 09244 sspivot(backtracksh, checkedge); 09245 if (checkedge.sh != dummysh) { 09246 if (stopatseg) { 09247 // The flag indicates we should not cross a segment. Stop. 09248 *searchsh = backtracksh; 09249 return OUTSIDE; 09250 } 09251 // Try to walk through a segment. We need to find a coplanar subface 09252 // sharing this segment to get into. 09253 spinsh = backtracksh; 09254 do { 09255 spivotself(spinsh); 09256 if (spinsh.sh == backtracksh.sh) { 09257 // Turn back, no coplanar subface is found. 09258 break; 09259 } 09260 // Are they belong to the same facet. 09261 if (shellmark(spinsh) == shellmark(backtracksh)) { 09262 // Find a coplanar subface. Walk into it. 09263 *searchsh = spinsh; 09264 break; 09265 } 09266 // Are they (nearly) coplanar? 09267 ori = orient3d(forg, fdest, sapex(backtracksh), sapex(spinsh)); 09268 if (iscoplanar(forg, fdest, sapex(backtracksh), sapex(spinsh), ori, 09269 b->epsilon)) { 09270 // Find a coplanar subface. Walk into it. 09271 *searchsh = spinsh; 09272 break; 09273 } 09274 } while (spinsh.sh != backtracksh.sh); 09275 } else { 09276 spivot(backtracksh, *searchsh); 09277 } 09278 // Check for walking right out of the triangulation. 09279 if ((searchsh->sh == dummysh) || (searchsh->sh == backtracksh.sh)) { 09280 // Go back to the last triangle. 09281 *searchsh = backtracksh; 09282 return OUTSIDE; 09283 } 09284 // To keep the same orientation wrt abovepoint. 09285 if (sorg(*searchsh) != forg) sesymself(*searchsh); 09286 #ifdef SELF_CHECK 09287 assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest)); 09288 #endif 09289 } 09290 } 09291 09293 // // 09294 // adjustlocatesub() Adjust the precise location of a vertex. // 09295 // // 09296 // 'precise' is the precise location (returned from locatesub()) of 'searcht'// 09297 // with respect to 'searchsh'. 'epspp' is the given relative tolerance. // 09298 // // 09299 // This routine re-evaluates the orientations of 'searchpt' with respect to // 09300 // the three edges of 'searchsh'. Detects the collinearities by additinal // 09301 // tests based on the given tolerance. If 'precise' is ONEDGE, one can save // 09302 // one orientation test for the current edge of 'searchsh'. // 09303 // // 09304 // On completion, 'searchsh' is a subface contains 'searchpt'. The returned // 09305 // value indicates one of the following cases: // 09306 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' // 09307 // is a handle whose origin is the existing vertex. // 09308 // - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a // 09309 // handle whose primary edge is the edge on which the point lies. // 09310 // - Returns ONFACE if the point lies strictly within a subface. // 09311 // 'searchsh' is a handle on which the point lies. // 09312 // - Returns OUTSIDE if the point lies outside 'searchsh'. // 09313 // // 09315 09316 enum tetgenmesh::locateresult tetgenmesh:: 09317 adjustlocatesub(point searchpt, face* searchsh, enum locateresult precise, 09318 REAL epspp) 09319 { 09320 point pa, pb, pc; 09321 bool s1, s2, s3; 09322 09323 pa = sorg(*searchsh); 09324 pb = sdest(*searchsh); 09325 pc = sapex(*searchsh); 09326 09327 if (precise == ONEDGE) { 09328 s1 = true; 09329 } else { 09330 s1 = iscollinear(pa, pb, searchpt, epspp); 09331 } 09332 s2 = iscollinear(pb, pc, searchpt, epspp); 09333 s3 = iscollinear(pc, pa, searchpt, epspp); 09334 if (s1) { 09335 if (s2) { 09336 // on vertex pb. 09337 #ifdef SELF_CHECK 09338 assert(!s3); 09339 #endif 09340 senextself(*searchsh); 09341 return ONVERTEX; 09342 } else if (s3) { 09343 // on vertex pa. 09344 return ONVERTEX; 09345 } else { 09346 // on edge pa->pb. 09347 return ONEDGE; 09348 } 09349 } else if (s2) { 09350 if (s3) { 09351 // on vertex pc. 09352 senext2self(*searchsh); 09353 return ONVERTEX; 09354 } else { 09355 // on edge pb->pc. 09356 senextself(*searchsh); 09357 return ONEDGE; 09358 } 09359 } else if (s3) { 09360 // on edge pc->pa. 09361 senext2self(*searchsh); 09362 return ONEDGE; 09363 } else { 09364 return precise; 09365 } 09366 } 09367 09369 // // 09370 // locateseg() Find a point in subsegments. // 09371 // // 09372 // Searching begins from the input 'searchseg', it should be a subsegment of // 09373 // the whole segment. // 09374 // // 09375 // On completion, 'searchseg' is a subsegment that contains 'searchpt'. // 09376 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchseg' // 09377 // is a handle whose origin is the existing vertex. // 09378 // - Returns ONEDGE if the point lies inside 'searchseg'. // 09379 // - Returns OUTSIDE if the point lies outside the segment. // 09380 // // 09382 09383 enum tetgenmesh::locateresult tetgenmesh:: 09384 locateseg(point searchpt, face* searchseg) 09385 { 09386 face backtraceseg; 09387 point pa, pb; 09388 REAL dx, dy, dz; 09389 int moveleft; 09390 int i; 09391 09392 moveleft = 0; 09393 while (1) { 09394 searchseg->shver = 0; 09395 pa = sorg(*searchseg); 09396 pb = sdest(*searchseg); 09397 // Find the biggest difference in x, y, and z coordinates of a and b. 09398 dx = fabs(pb[0] - pa[0]); 09399 dy = fabs(pb[1] - pa[1]); 09400 dz = fabs(pb[2] - pa[2]); 09401 if (dx > dy) { 09402 if (dx > dz) { 09403 i = 0; 09404 } else { 09405 i = 2; 09406 } 09407 } else { 09408 if (dy > dz) { 09409 i = 1; 09410 } else { 09411 i = 2; 09412 } 09413 } 09414 if (pa[i] < pb[i]) { 09415 if (searchpt[i] < pa[i]) { 09416 moveleft = 1; 09417 } else if (searchpt[i] > pa[i]) { 09418 if (searchpt[i] < pb[i]) { 09419 return ONEDGE; 09420 } else if (searchpt[i] > pb[i]) { 09421 moveleft = 0; 09422 } else { 09423 #ifdef SELF_CHECK 09424 assert(searchpt[i] == pb[i]); 09425 #endif 09426 sesymself(*searchseg); 09427 return ONVERTEX; 09428 } 09429 } else { 09430 #ifdef SELF_CHECK 09431 assert(searchpt[i] == pa[i]); 09432 #endif 09433 return ONVERTEX; 09434 } 09435 } else if (pa[i] > pb[i]) { 09436 if (searchpt[i] < pb[i]) { 09437 moveleft = 0; 09438 } else if (searchpt[i] > pb[i]) { 09439 if (searchpt[i] < pa[i]) { 09440 return ONEDGE; 09441 } else if (searchpt[i] > pa[i]) { 09442 moveleft = 1; 09443 } else { 09444 #ifdef SELF_CHECK 09445 assert(searchpt[i] == pa[i]); 09446 #endif 09447 return ONVERTEX; 09448 } 09449 } else { 09450 #ifdef SELF_CHECK 09451 assert(searchpt[i] == pb[i]); 09452 #endif 09453 sesymself(*searchseg); 09454 return ONVERTEX; 09455 } 09456 } 09457 backtraceseg = *searchseg; 09458 if (moveleft) { 09459 senext2self(*searchseg); 09460 } else { 09461 senextself(*searchseg); 09462 } 09463 spivotself(*searchseg); 09464 if (searchseg->sh == dummysh) { 09465 *searchseg = backtraceseg; 09466 break; 09467 } 09468 } 09469 09470 return OUTSIDE; 09471 } 09472 09474 // // 09475 // adjustlocateseg() Adjust the precise location of a vertex on segment. // 09476 // // 09477 // 'searchpt' is either inside or ouside the segment 'searchseg'. It will be // 09478 // adjusted to on vertex if it is very close to an endpoint of 'searchseg'. // 09479 // 'epspp' is the given relative tolerance. // 09480 // // 09482 09483 enum tetgenmesh::locateresult tetgenmesh:: 09484 adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise, 09485 REAL epspp) 09486 { 09487 point pa, pb; 09488 REAL L, d, r; 09489 09490 pa = sorg(*searchseg); 09491 pb = sdest(*searchseg); 09492 L = distance(pa, pb); 09493 09494 // Is searchpt approximate to pa? 09495 d = distance(pa, searchpt); 09496 r = d / L; 09497 if (r <= epspp) { 09498 return ONVERTEX; 09499 } 09500 // Is searchpt approximate to pb? 09501 d = distance(pb, searchpt); 09502 r = d / L; 09503 if (r <= epspp) { 09504 sesymself(*searchseg); 09505 return ONVERTEX; 09506 } 09507 09508 return precise; 09509 } 09510 09511 // 09512 // End of point location routines 09513 // 09514 09515 // 09516 // Begin of mesh transformation routines 09517 // 09518 09520 // // 09521 // Flip operations // 09522 // // 09523 // If abc is a hull face, it is unflipable, and is locally Delaunay. In the // 09524 // following, we assume abc is an interior face, and the other tetrahedron // 09525 // adjoining at abc is bace. // 09526 // // 09527 // If the convex hull CH of the set {a, b, c, d, e} only has four vertices, // 09528 // i.e., one vertex lies inside CH, then abc is unflipable, and is locally // 09529 // Delaunay. If CH is the vertex set itself, we have the following cases to // 09530 // determine whether abc is flipable or not. // 09531 // // 09532 // If no four points of {a, b, c, d, e} are coplanar, a 2-to-3 flip can be // 09533 // applied to abc if the edge de crosses the triangle abc; a 3-to-2 flip can // 09534 // be applied to abc if ab crosses cde, and abde exists, otherwise, face abc // 09535 // is unflipable, i.e., the tetrahedron abde is not present. // 09536 // // 09537 // If four points of {a, b, c, d, e} are coplanar (two faces are coplanar). // 09538 // Assume faces abd and abe are coplanar (it is impossible be abc). If a, b, // 09539 // d, e form a non-convex quadrilateral, then abc is unflipable, furthermore,// 09540 // it is locally Delaunay. Assume they are convex quadrilateral, if abd and // 09541 // abe are hull faces, a 2-to-2 flip can be applied to abc; if abd and abe // 09542 // are interior faces, assume two tetrahedra adjoining abd and abe at the // 09543 // opposite sides are abdg and abef, respectively. If g = f, a 4-to-4 flip // 09544 // can be applied to abc, otherwise, abc is unflipable. // 09545 // // 09546 // There are other cases which can cause abc unflipable. If abc is a subface,// 09547 // a 2-to-3 flip is forbidden; if ab is a subsegment, flips 3-to-2, 2-to-2, // 09548 // and 4-to-4 are forbidden. // 09549 // // 09551 09553 // // 09554 // categorizeface() Determine the flip type of a given face. // 09555 // // 09556 // On input, 'horiz' represents the face abc we want to flip (imagine it is // 09557 // parallel to the horizon). Let the tet above it be abcd. // 09558 // // 09559 // This routine determines the suitable type of flip operation for 'horiz'. // 09560 // - Returns T23 if a 2-to-3 flip is applicable. 'horiz' is same as input. // 09561 // - Returns T32 if a 3-to-2 flip is applicable. 'horiz' returns the edge // 09562 // of abc which is the flipable. // 09563 // - Returns T22 if a 2-to-2 or 4-to-4 flip is applicable. 'horiz' returns // 09564 // the edge of abc which is flipable. // 09565 // - Returns N32 indicates it is unflipable due to the absence of a tet. // 09566 // 'horize' returns the unflipable edge. // 09567 // - Returns N40 indicates it is unflipable and is locally Delaunay. // 09568 // - Returns FORBIDDENFACE indicates abc is a subface. // 09569 // - Returns FORBIDDENEDGE indicates the flipable edge of abc is a segment.// 09570 // 'horize' returns the flipable edge. // 09571 // // 09572 // Given a face abc, with two adjoining tetrahedra abcd and bace. If abc is // 09573 // flipable, i.e., T23, T32, T22 or T44, its flip type can be determined by // 09574 // doing five orientation tests: two tests for determining that d, e lie on // 09575 // the different sides of abc, three tests for determining if the edge de // 09576 // intersects the face abc. However, if we use the neighbor information of // 09577 // the mesh data structure, we can reduce the five orientation tests to at // 09578 // most three tests, that is, the two tests for determining whether d and e // 09579 // lie on the different sides of abc can be saved. // 09580 // // 09582 09583 enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz) 09584 { 09585 triface symhoriz, casing; 09586 face checksh, checkseg; 09587 face cassh1, cassh2; 09588 point pa, pb, pc, pd, pe, pf, pg; 09589 point abdoppo, bcdoppo, cadoppo; 09590 REAL ori1, ori2, ori3; 09591 int adjtet; 09592 09593 sym(horiz, symhoriz); 09594 if (symhoriz.tet == dummytet) { 09595 // A hull face is unflipable and locally Delaunay. 09596 return N40; 09597 } 09598 09599 adjustedgering(horiz, CCW); 09600 findedge(&symhoriz, dest(horiz), org(horiz)); 09601 pa = org(horiz); 09602 pb = dest(horiz); 09603 pc = apex(horiz); 09604 pd = oppo(horiz); 09605 pe = oppo(symhoriz); 09606 09607 // Find the number of adjacent tetrahedra of abc, which have d, e, and one 09608 // of corners of abc as their corners. This number can be 0, 1 and 2. 09609 abdoppo = bcdoppo = cadoppo = (point) NULL; 09610 adjtet = 0; 09611 fnext(horiz, casing); // at edge 'ab'. 09612 symself(casing); 09613 if (casing.tet != dummytet) { 09614 abdoppo = oppo(casing); 09615 if (abdoppo == pe) adjtet++; 09616 } 09617 enextfnext(horiz, casing); // at edge 'bc'. 09618 symself(casing); 09619 if (casing.tet != dummytet) { 09620 bcdoppo = oppo(casing); 09621 if (bcdoppo == pe) adjtet++; 09622 } 09623 enext2fnext(horiz, casing); // at edge 'ca'. 09624 symself(casing); 09625 if (casing.tet != dummytet) { 09626 cadoppo = oppo(casing); 09627 if (cadoppo == pe) adjtet++; 09628 } 09629 09630 if (adjtet == 0) { 09631 // No adjacent tetrahedron. Types T23, T22 and T44 are possible. 09632 ori1 = orient3d(pa, pb, pd, pe); 09633 if (checksubfaces && ori1 != 0.0) { 09634 // Check if abd and abe are both boundary faces? 09635 fnext(horiz, casing); 09636 tspivot(casing, cassh1); 09637 fnext(symhoriz, casing); 09638 tspivot(casing, cassh2); 09639 if ((cassh1.sh != dummysh) && (cassh2.sh != dummysh)) { 09640 // abd and abe are both boundary faces. Check if ab is a segment. 09641 findedge(&cassh1, pa, pb); 09642 sspivot(cassh1, checkseg); 09643 if (checkseg.sh == dummysh) { 09644 // ab is not a segment - abd and abe belong to the same facet. 09645 // The four points are forced to be coplanar. 09646 ori1 = 0.0; 09647 } else { 09648 // ab is a segment - abd and abe belong to two different facets. 09649 // In principle, a, b, c and d can form a tetrahedron (since 09650 // ori1 != 0.0). However, we should avoid to create a very 09651 // flat one which may form a sequence of extremely badly-shaped 09652 // or even wrong orientational tets. Test with a larger epsilon. 09653 if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon * 1e+2)) ori1 = 0.0; 09654 } 09655 } else { 09656 // abd and abe are not both boundary faces. Check if abd and bae 09657 // are approximately coplanar with respect to the epsilon. 09658 if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon)) ori1 = 0.0; 09659 } 09660 } 09661 if (ori1 < 0.0) { 09662 // e lies above abd, unflipable, tet abde is not present. 09663 #ifdef SELF_CHECK 09664 if (!nonconvex) { 09665 // abd and abe should not be hull faces, check it. 09666 fnext(horiz, casing); 09667 symself(casing); 09668 assert(casing.tet != dummytet); 09669 fnext(symhoriz, casing); 09670 symself(casing); 09671 assert(casing.tet != dummytet); 09672 } 09673 #endif 09674 if (checksubfaces) { 09675 // The nonconvexbility may be casued by existing an subsegment. 09676 tsspivot(&horiz, &checkseg); 09677 if (checkseg.sh != dummysh) { 09678 return FORBIDDENEDGE; 09679 } 09680 } 09681 return N32; 09682 } 09683 ori2 = orient3d(pb, pc, pd, pe); 09684 if (checksubfaces && ori2 != 0.0) { 09685 // Check if bcd and cbe are both boundary faces. 09686 enextfnext(horiz, casing); 09687 tspivot(casing, cassh1); 09688 enext2fnext(symhoriz, casing); 09689 tspivot(casing, cassh2); 09690 if (cassh1.sh != dummysh && cassh2.sh != dummysh) { 09691 // bcd and cbe are both boundary faces. Check if bc is a segment. 09692 findedge(&cassh1, pb, pc); 09693 sspivot(cassh1, checkseg); 09694 if (checkseg.sh == dummysh) { 09695 // bc is not a segment - bcd and cbe belong to the same facet. 09696 // The four points are forced to be coplanar. 09697 ori2 = 0.0; 09698 } else { 09699 if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon * 1e+2)) ori2 = 0.0; 09700 } 09701 } else { 09702 // bcd and cbe are not both boundary faces. Check if bcd and cbe 09703 // are approximately coplanar with respect to the epsilon. 09704 if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon)) ori2 = 0.0; 09705 } 09706 } 09707 if (ori2 < 0.0) { 09708 // e lies above bcd, unflipable, tet bcde is not present. 09709 #ifdef SELF_CHECK 09710 if (!nonconvex) { 09711 // bcd and cbe should not be hull faces, check it. 09712 enextfnext(horiz, casing); 09713 symself(casing); 09714 assert(casing.tet != dummytet); 09715 enext2fnext(symhoriz, casing); 09716 symself(casing); 09717 assert(casing.tet != dummytet); 09718 } 09719 #endif 09720 enextself(horiz); 09721 if (checksubfaces) { 09722 // The nonconvexbility may be casued by existing an subsegment. 09723 tsspivot(&horiz, &checkseg); 09724 if (checkseg.sh != dummysh) { 09725 return FORBIDDENEDGE; 09726 } 09727 } 09728 return N32; 09729 } 09730 ori3 = orient3d(pc, pa, pd, pe); 09731 if (checksubfaces && ori3 != 0.0) { 09732 // Check if cad and ace are both boundary faces. 09733 enext2fnext(horiz, casing); 09734 tspivot(casing, cassh1); 09735 enextfnext(symhoriz, casing); 09736 tspivot(casing, cassh2); 09737 if (cassh1.sh != dummysh && cassh2.sh != dummysh) { 09738 // cad and ace are both boundary faces. Check if ca is a segment. 09739 findedge(&cassh1, pc, pa); 09740 sspivot(cassh1, checkseg); 09741 if (checkseg.sh == dummysh) { 09742 // ca is not a segment - cad and ace belong to the same facet. 09743 // The four points are forced to be coplanar. 09744 ori3 = 0.0; 09745 } else { 09746 // ca is a segment - cad and ace belong to two different facets. 09747 // In principle, c, a, d and e can form a tetrahedron (since 09748 // ori3 != 0.0). Use a larger eps to test if they're coplanar. 09749 if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon * 1e+2)) ori3 = 0.0; 09750 } 09751 } else { 09752 // cad and ace are not both boundary faces. Check if cad and ace 09753 // are approximately coplanar with respect to the epsilon. 09754 if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon)) ori3 = 0.0; 09755 } 09756 } 09757 if (ori3 < 0.0) { 09758 // e lies above cad, unflipable, tet cade is not present. 09759 #ifdef SELF_CHECK 09760 if (!nonconvex) { 09761 // cad and ace should not be hull faces, check it. 09762 enext2fnext(horiz, casing); 09763 symself(casing); 09764 assert(casing.tet != dummytet); 09765 enextfnext(symhoriz, casing); 09766 symself(casing); 09767 assert(casing.tet != dummytet); 09768 } 09769 #endif 09770 enext2self(horiz); 09771 if (checksubfaces) { 09772 // The nonconvexbility may be casued by existing an subsegment. 09773 tsspivot(&horiz, &checkseg); 09774 if (checkseg.sh != dummysh) { 09775 return FORBIDDENEDGE; 09776 } 09777 } 09778 return N32; 09779 } 09780 if (ori1 == 0.0) { 09781 // e is coplanar with abd. 09782 if (ori2 * ori3 == 0.0) { 09783 // only one zero is possible. 09784 // assert(!(ori2 == 0.0 && ori3 == 0.0)); 09785 // Three points (d, e, and a or b) are collinear, abc is unflipable 09786 // and locally Delaunay. 09787 return N40; 09788 } 09789 } else if (ori2 == 0.0) { 09790 // e is coplanar with bcd. 09791 if (ori1 * ori3 == 0.0) { 09792 // only one zero is possible. 09793 // assert(!(ori1 == 0.0 && ori3 == 0.0)); 09794 // Three points (d, e, and b or c) are collinear, abc is unflipable 09795 // and locally Delaunay. 09796 return N40; 09797 } 09798 // Adjust 'horiz' and 'symhoriz' be the edge bc. 09799 enextself(horiz); 09800 enext2self(symhoriz); 09801 } else if (ori3 == 0.0) { 09802 // e is coplanar with cad. 09803 if (ori1 * ori2 == 0.0) { 09804 // only one zero is possible. 09805 // assert(!(ori1 == 0.0 && ori2 == 0.0)); 09806 // Three points (d, e, and c or a) are collinear, abc is unflipable 09807 // and locally Delaunay. 09808 return N40; 09809 } 09810 // Adjust 'horiz' and 'symhoriz' be the edge ca. 09811 enext2self(horiz); 09812 enextself(symhoriz); 09813 } else { 09814 // e lies below all three faces, flipable. 09815 if (checksubfaces) { 09816 tspivot(horiz, checksh); 09817 if (checksh.sh != dummysh) { 09818 // To flip a subface is forbidden. 09819 return FORBIDDENFACE; 09820 } 09821 } 09822 return T23; 09823 } 09824 // Four points are coplanar, T22 or T44 is possible. 09825 if (checksubfaces) { 09826 tsspivot(&horiz, &checkseg); 09827 if (checkseg.sh != dummysh) { 09828 // To flip a subsegment is forbidden. 09829 return FORBIDDENEDGE; 09830 } 09831 tspivot(horiz, checksh); 09832 if (checksh.sh != dummysh) { 09833 // To flip a subface is forbidden. 09834 return FORBIDDENFACE; 09835 } 09836 } 09837 // Assume the four coplanar points are a, b, d, e, abd and abe are two 09838 // coplanar faces. If both abd and abe are hull faces, flipable(T22). 09839 // If they are interior faces, get the opposite tetrahedra abdf and 09840 // abeg, if f = g, flipable (T44). Otherwise, unflipable. 09841 pf = pg = (point) NULL; 09842 fnext(horiz, casing); 09843 symself(casing); 09844 if (casing.tet != dummytet) { 09845 pf = oppo(casing); 09846 } 09847 fnext(symhoriz, casing); 09848 symself(casing); 09849 if (casing.tet != dummytet) { 09850 pg = oppo(casing); 09851 } 09852 if (pf == pg) { 09853 // Either T22 (pf == pg == NULL) or T44 (pf and pg) is possible. 09854 if (checksubfaces) { 09855 // Retreat the corner points a, b, and c. 09856 pa = org(horiz); 09857 pb = dest(horiz); 09858 pc = apex(horiz); 09859 // Be careful not to create an inverted tetrahedron. Check the case. 09860 ori1 = orient3d(pc, pd, pe, pa); 09861 if (ori1 <= 0) return N40; 09862 ori1 = orient3d(pd, pc, pe, pb); 09863 if (ori1 <= 0) return N40; 09864 if (pf != (point) NULL) { 09865 ori1 = orient3d(pd, pf, pe, pa); 09866 if (ori1 <= 0) return N40; 09867 ori1 = orient3d(pf, pd, pe, pb); 09868 if (ori1 <= 0) return N40; 09869 } 09870 } 09871 if (pf == (point) NULL) { 09872 // abd and abe are hull faces, flipable. 09873 return T22; 09874 } else { 09875 // abd and abe are interior faces, flipable. 09876 #ifdef SELF_CHECK 09877 assert(pf != (point) NULL); 09878 #endif 09879 return T44; 09880 } 09881 } else { 09882 // ab has more than four faces around it, unflipable. 09883 return N32; 09884 } 09885 } else if (adjtet == 1) { 09886 // One of its three edges is locally non-convex. Type T32 is possible. 09887 // Adjust current configuration so that edge ab is non-convex. 09888 if (bcdoppo == pe) { 09889 // Edge bc is non-convex. Adjust 'horiz' and 'symhoriz' be edge bc. 09890 enextself(horiz); 09891 enext2self(symhoriz); 09892 pa = org(horiz); 09893 pb = dest(horiz); 09894 pc = apex(horiz); 09895 } else if (cadoppo == pe) { 09896 // Edge ca is non-convex. Adjust 'horiz' and 'symhoriz' be edge ca. 09897 enext2self(horiz); 09898 enextself(symhoriz); 09899 pa = org(horiz); 09900 pb = dest(horiz); 09901 pc = apex(horiz); 09902 } else { 09903 // Edge ab is non-convex. 09904 #ifdef SELF_CHECK 09905 assert(abdoppo == pe); 09906 #endif 09907 } // Now ab is the non-convex edge. 09908 // In order to be flipable, ab should cross face cde. Check it. 09909 ori1 = orient3d(pc, pd, pe, pa); 09910 if (checksubfaces && ori1 != 0.0) { 09911 // Check if cad and ace are both boundary faces. 09912 enext2fnext(horiz, casing); 09913 tspivot(casing, cassh1); 09914 enextfnext(symhoriz, casing); 09915 tspivot(casing, cassh2); 09916 if (cassh1.sh != dummysh && cassh2.sh != dummysh) { 09917 // cad and ace are both boundary faces. Check if ca is a segment. 09918 findedge(&cassh1, pc, pa); 09919 sspivot(cassh1, checkseg); 09920 if (checkseg.sh == dummysh) { 09921 // ca is not a segment. cad and ace belong to the same facet. 09922 // The four points are forced to be coplanar. 09923 ori1 = 0.0; 09924 } else { 09925 // ca is a segment. cad and ace belong to different facets. 09926 // In principle, c, d, e, and a can form a tetrahedron (since 09927 // ori1 != 0.0). However, we should avoid to create a very 09928 // flat tet. Use a larger epsilon to test if they're coplanar. 09929 if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon * 1e+2)) ori1 = 0.0; 09930 } 09931 } else { 09932 // Check if c, d, e, and a are approximately coplanar. 09933 if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon)) ori1 = 0.0; 09934 } 09935 } 09936 if (ori1 <= 0.0) { 09937 // a lies above or is coplanar cde, abc is locally Delaunay. 09938 return N40; 09939 } 09940 ori2 = orient3d(pd, pc, pe, pb); 09941 if (checksubfaces && ori2 != 0.0) { 09942 // Check if bcd and cbe are both boundary faces. 09943 enextfnext(horiz, casing); 09944 tspivot(casing, cassh1); 09945 enext2fnext(symhoriz, casing); 09946 tspivot(casing, cassh2); 09947 if (cassh1.sh != dummysh && cassh2.sh != dummysh) { 09948 // bcd and cbe are both boundary faces. Check if bc is a segment. 09949 findedge(&cassh1, pb, pc); 09950 sspivot(cassh1, checkseg); 09951 if (checkseg.sh == dummysh) { 09952 // bc is not a segment. bcd and cbe belong to the same facet. 09953 // The four points are forced to be coplanar. 09954 ori2 = 0.0; 09955 } else { 09956 // bc is a segment. bcd and cbe belong to different facets. 09957 // In principle, d, c, e, and b can form a tetrahedron (since 09958 // ori2 != 0.0). However, we should avoid to create a very 09959 // flat tet. Use a larger epsilon to test if they're coplanar. 09960 if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon * 1e+2)) ori2 = 0.0; 09961 } 09962 } else { 09963 // Check if d, c, e, and b are approximately coplanar. 09964 if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon)) ori2 = 0.0; 09965 } 09966 } 09967 if (ori2 <= 0.0) { 09968 // b lies above dce, unflipable, and abc is locally Delaunay. 09969 return N40; 09970 } 09971 // Edge ab crosses face cde properly. 09972 if (checksubfaces) { 09973 // If abc is subface, then ab must be a subsegment (because abde is 09974 // a tetrahedron and ab crosses cde properly). 09975 tsspivot(&horiz, &checkseg); 09976 if (checkseg.sh != dummysh) { 09977 // To flip a subsegment is forbidden. 09978 return FORBIDDENEDGE; 09979 } 09980 // Both abd and bae should not be subfaces (because they're not 09981 // coplanar and ab is not a subsegment). However, they may be 09982 // subfaces and belong to a facet (created during facet recovery), 09983 // that is, abde is an invalid tetrahedron. Find this case out. 09984 fnext(horiz, casing); 09985 tspivot(casing, cassh1); 09986 fnext(symhoriz, casing); 09987 tspivot(casing, cassh2); 09988 if (cassh1.sh != dummysh || cassh2.sh != dummysh) { 09989 if (!b->quiet) { 09990 // Unfortunately, they're subfaces. Corrections need be done here. 09991 printf("Warning: A tetrahedron spans two subfaces of a facet.\n"); 09992 } 09993 // Temporarily, let it be there. 09994 return N32; 09995 } 09996 } 09997 return T32; 09998 } else { 09999 // The convex hull of {a, b, c, d, e} has only four vertices, abc is 10000 // unflipable, furthermore, it is locally Delaunay. 10001 return N40; 10002 } 10003 } 10004 10006 // // 10007 // enqueueflipface(), enqueueflipedge() Queue a face (or an edge). // 10008 // // 10009 // The face (or edge) may be non-locally Delaunay. It is queued for process- // 10010 // ing in flip() (or flipsub()). The vertices of the face (edge) are stored // 10011 // seperatly to ensure the face (or edge) is still the same one when we save // 10012 // it since other flips will cause this face (or edge) be changed or dead. // 10013 // // 10015 10016 void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue) 10017 { 10018 badface *queface; 10019 triface symface; 10020 10021 sym(checkface, symface); 10022 if (symface.tet != dummytet) { 10023 queface = (badface *) flipqueue->push((void *) NULL); 10024 queface->tt = checkface; 10025 queface->foppo = oppo(symface); 10026 } 10027 } 10028 10029 void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue) 10030 { 10031 badface *queface; 10032 10033 queface = (badface *) flipqueue->push((void *) NULL); 10034 queface->ss = checkedge; 10035 queface->forg = sorg(checkedge); 10036 queface->fdest = sdest(checkedge); 10037 } 10038 10040 // // 10041 // flip23() Perform a 2-to-3 flip. // 10042 // // 10043 // On input, 'flipface' represents the face will be flipped. Let it is abc, // 10044 // the two tetrahedra sharing abc are abcd, bace. abc is not a subface. // 10045 // // 10046 // A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra // 10047 // edab, edbc, and edca. As a result, face abc has been removed and three // 10048 // new faces eda, edb and edc have been created. // 10049 // // 10050 // On completion, 'flipface' returns edab. If 'flipqueue' is not NULL, all // 10051 // possibly non-Delaunay faces are added into it. // 10052 // // 10054 10055 void tetgenmesh::flip23(triface* flipface, queue* flipqueue) 10056 { 10057 triface abcd, bace; // Old configuration. 10058 triface oldabd, oldbcd, oldcad; 10059 triface abdcasing, bcdcasing, cadcasing; 10060 triface oldbae, oldcbe, oldace; 10061 triface baecasing, cbecasing, acecasing; 10062 triface worktet; 10063 face abdsh, bcdsh, cadsh; // The six subfaces on the CH. 10064 face baesh, cbesh, acesh; 10065 face abseg, bcseg, caseg; // The nine segs on the CH. 10066 face adseg, bdseg, cdseg; 10067 face aeseg, beseg, ceseg; 10068 triface edab, edbc, edca; // New configuration. 10069 point pa, pb, pc, pd, pe; 10070 REAL attrib, volume; 10071 int i; 10072 10073 abcd = *flipface; 10074 adjustedgering(abcd, CCW); // abcd represents edge ab. 10075 pa = org(abcd); 10076 pb = dest(abcd); 10077 pc = apex(abcd); 10078 pd = oppo(abcd); 10079 // sym(abcd, bace); 10080 // findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba. 10081 sym(abcd, bace); 10082 bace.ver = 0; // CCW. 10083 for (i = 0; (i < 3) && (org(bace) != pb); i++) { 10084 enextself(bace); 10085 } 10086 pe = oppo(bace); 10087 10088 if (b->verbose > 2) { 10089 printf(" Do T23 on face (%d, %d, %d) %d, %d.\n", pointmark(pa), 10090 pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe)); 10091 } 10092 flip23s++; 10093 10094 // Storing the old configuration outside the convex hull. 10095 fnext(abcd, oldabd); 10096 enextfnext(abcd, oldbcd); 10097 enext2fnext(abcd, oldcad); 10098 fnext(bace, oldbae); 10099 enext2fnext(bace, oldcbe); 10100 enextfnext(bace, oldace); 10101 sym(oldabd, abdcasing); 10102 sym(oldbcd, bcdcasing); 10103 sym(oldcad, cadcasing); 10104 sym(oldbae, baecasing); 10105 sym(oldcbe, cbecasing); 10106 sym(oldace, acecasing); 10107 if (checksubfaces) { 10108 tspivot(oldabd, abdsh); 10109 tspivot(oldbcd, bcdsh); 10110 tspivot(oldcad, cadsh); 10111 tspivot(oldbae, baesh); 10112 tspivot(oldcbe, cbesh); 10113 tspivot(oldace, acesh); 10114 } else if (checksubsegs) { 10115 tsspivot1(abcd, abseg); 10116 enext(abcd, worktet); 10117 tsspivot1(worktet, bcseg); 10118 enext2(abcd, worktet); 10119 tsspivot1(worktet, caseg); 10120 enext2(oldabd, worktet); 10121 tsspivot1(worktet, adseg); 10122 enext2(oldbcd, worktet); 10123 tsspivot1(worktet, bdseg); 10124 enext2(oldcad, worktet); 10125 tsspivot1(worktet, cdseg); 10126 enext(oldbae, worktet); 10127 tsspivot1(worktet, aeseg); 10128 enext(oldcbe, worktet); 10129 tsspivot1(worktet, beseg); 10130 enext(oldace, worktet); 10131 tsspivot1(worktet, ceseg); 10132 } 10133 10134 // Creating the new configuration inside the convex hull. 10135 edab.tet = abcd.tet; // Update abcd to be edab. 10136 setorg (edab, pe); 10137 setdest(edab, pd); 10138 setapex(edab, pa); 10139 setoppo(edab, pb); 10140 edbc.tet = bace.tet; // Update bace to be edbc. 10141 setorg (edbc, pe); 10142 setdest(edbc, pd); 10143 setapex(edbc, pb); 10144 setoppo(edbc, pc); 10145 maketetrahedron(&edca); // Create edca. 10146 setorg (edca, pe); 10147 setdest(edca, pd); 10148 setapex(edca, pc); 10149 setoppo(edca, pa); 10150 // Set the element attributes of the new tetrahedron 'edca'. 10151 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 10152 attrib = elemattribute(abcd.tet, i); 10153 setelemattribute(edca.tet, i, attrib); 10154 } 10155 // Set the volume constraint of the new tetrahedron 'edca' if the -ra 10156 // switches are not used together. In -ra case, the various volume 10157 // constraints can be spreaded very far. 10158 if (b->varvolume && !b->refine) { 10159 volume = volumebound(abcd.tet); 10160 setvolumebound(edca.tet, volume); 10161 } 10162 10163 // Clear old bonds in edab(was abcd) and edbc(was bace). 10164 for (i = 0; i < 4; i ++) { 10165 edab.tet[i] = (tetrahedron) dummytet; 10166 } 10167 for (i = 0; i < 4; i ++) { 10168 edbc.tet[i] = (tetrahedron) dummytet; 10169 } 10170 // Bond the faces inside the convex hull. 10171 edab.loc = 0; 10172 edca.loc = 1; 10173 bond(edab, edca); 10174 edab.loc = 1; 10175 edbc.loc = 0; 10176 bond(edab, edbc); 10177 edbc.loc = 1; 10178 edca.loc = 0; 10179 bond(edbc, edca); 10180 // Bond the faces on the convex hull. 10181 edab.loc = 2; 10182 bond(edab, abdcasing); 10183 edab.loc = 3; 10184 bond(edab, baecasing); 10185 edbc.loc = 2; 10186 bond(edbc, bcdcasing); 10187 edbc.loc = 3; 10188 bond(edbc, cbecasing); 10189 edca.loc = 2; 10190 bond(edca, cadcasing); 10191 edca.loc = 3; 10192 bond(edca, acecasing); 10193 // There may exist subfaces that need to be bonded to new configuarton. 10194 if (checksubfaces) { 10195 // Clear old flags in edab(was abcd) and edbc(was bace). 10196 for (i = 0; i < 4; i ++) { 10197 edab.loc = i; 10198 tsdissolve(edab); 10199 edbc.loc = i; 10200 tsdissolve(edbc); 10201 } 10202 if (abdsh.sh != dummysh) { 10203 edab.loc = 2; 10204 tsbond(edab, abdsh); 10205 } 10206 if (baesh.sh != dummysh) { 10207 edab.loc = 3; 10208 tsbond(edab, baesh); 10209 } 10210 if (bcdsh.sh != dummysh) { 10211 edbc.loc = 2; 10212 tsbond(edbc, bcdsh); 10213 } 10214 if (cbesh.sh != dummysh) { 10215 edbc.loc = 3; 10216 tsbond(edbc, cbesh); 10217 } 10218 if (cadsh.sh != dummysh) { 10219 edca.loc = 2; 10220 tsbond(edca, cadsh); 10221 } 10222 if (acesh.sh != dummysh) { 10223 edca.loc = 3; 10224 tsbond(edca, acesh); 10225 } 10226 } else if (checksubsegs) { 10227 for (i = 0; i < 6; i++) { 10228 edab.tet[8 + i] = (tetrahedron) dummysh; 10229 } 10230 for (i = 0; i < 6; i++) { 10231 edbc.tet[8 + i] = (tetrahedron) dummysh; 10232 } 10233 edab.loc = edab.ver = 0; 10234 edbc.loc = edab.ver = 0; 10235 edca.loc = edab.ver = 0; 10236 // Operate in tet edab (5 edges). 10237 enext(edab, worktet); 10238 tssbond1(worktet, adseg); 10239 enext2(edab, worktet); 10240 tssbond1(worktet, aeseg); 10241 fnext(edab, worktet); 10242 enextself(worktet); 10243 tssbond1(worktet, bdseg); 10244 enextself(worktet); 10245 tssbond1(worktet, beseg); 10246 enextfnext(edab, worktet); 10247 enextself(worktet); 10248 tssbond1(worktet, abseg); 10249 // Operate in tet edbc (5 edges) 10250 enext(edbc, worktet); 10251 tssbond1(worktet, bdseg); 10252 enext2(edbc, worktet); 10253 tssbond1(worktet, beseg); 10254 fnext(edbc, worktet); 10255 enextself(worktet); 10256 tssbond1(worktet, cdseg); 10257 enextself(worktet); 10258 tssbond1(worktet, ceseg); 10259 enextfnext(edbc, worktet); 10260 enextself(worktet); 10261 tssbond1(worktet, bcseg); 10262 // Operate in tet edca (5 edges) 10263 enext(edca, worktet); 10264 tssbond1(worktet, cdseg); 10265 enext2(edca, worktet); 10266 tssbond1(worktet, ceseg); 10267 fnext(edca, worktet); 10268 enextself(worktet); 10269 tssbond1(worktet, adseg); 10270 enextself(worktet); 10271 tssbond1(worktet, aeseg); 10272 enextfnext(edca, worktet); 10273 enextself(worktet); 10274 tssbond1(worktet, caseg); 10275 } 10276 10277 edab.loc = 0; 10278 edbc.loc = 0; 10279 edca.loc = 0; 10280 if (b->verbose > 3) { 10281 printf(" Updating edab "); 10282 printtet(&edab); 10283 printf(" Updating edbc "); 10284 printtet(&edbc); 10285 printf(" Creating edca "); 10286 printtet(&edca); 10287 } 10288 10289 if (flipqueue != (queue *) NULL) { 10290 enextfnext(edab, abdcasing); 10291 enqueueflipface(abdcasing, flipqueue); 10292 enext2fnext(edab, baecasing); 10293 enqueueflipface(baecasing, flipqueue); 10294 enextfnext(edbc, bcdcasing); 10295 enqueueflipface(bcdcasing, flipqueue); 10296 enext2fnext(edbc, cbecasing); 10297 enqueueflipface(cbecasing, flipqueue); 10298 enextfnext(edca, cadcasing); 10299 enqueueflipface(cadcasing, flipqueue); 10300 enext2fnext(edca, acecasing); 10301 enqueueflipface(acecasing, flipqueue); 10302 } 10303 10304 // Save a live handle in 'recenttet'. 10305 recenttet = edbc; 10306 // Set the return handle be edab. 10307 *flipface = edab; 10308 } 10309 10311 // // 10312 // flip32() Perform a 3-to-2 flip. // 10313 // // 10314 // On input, 'flipface' represents the face will be flipped. Let it is eda, // 10315 // where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,// 10316 // edbc, and edca. ed is not a subsegment. // 10317 // // 10318 // A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into // 10319 // another two tetrahedra abcd and bace. As a result, the edge ed has been // 10320 // removed and the face abc has been created. // 10321 // // 10322 // On completion, 'flipface' returns abcd. If 'flipqueue' is not NULL, all // 10323 // possibly non-Delaunay faces are added into it. // 10324 // // 10326 10327 void tetgenmesh::flip32(triface* flipface, queue* flipqueue) 10328 { 10329 triface edab, edbc, edca; // Old configuration. 10330 triface oldabd, oldbcd, oldcad; 10331 triface abdcasing, bcdcasing, cadcasing; 10332 triface oldbae, oldcbe, oldace; 10333 triface baecasing, cbecasing, acecasing; 10334 triface worktet; 10335 face abdsh, bcdsh, cadsh; 10336 face baesh, cbesh, acesh; 10337 face abseg, bcseg, caseg; // The nine segs on the CH. 10338 face adseg, bdseg, cdseg; 10339 face aeseg, beseg, ceseg; 10340 triface abcd, bace; // New configuration. 10341 point pa, pb, pc, pd, pe; 10342 int i; 10343 10344 edab = *flipface; 10345 adjustedgering(edab, CCW); 10346 pa = apex(edab); 10347 pb = oppo(edab); 10348 pd = dest(edab); 10349 pe = org(edab); 10350 fnext(edab, edbc); 10351 symself(edbc); 10352 edbc.ver = 0; 10353 for (i = 0; (i < 3) && (org(edbc) != pe); i++) { 10354 enextself(edbc); 10355 } 10356 pc = oppo(edbc); 10357 fnext(edbc, edca); 10358 symself(edca); 10359 edca.ver = 0; 10360 for (i = 0; (i < 3) && (org(edca) != pe); i++) { 10361 enextself(edca); 10362 } 10363 10364 if (b->verbose > 2) { 10365 printf(" Do T32 on edge (%d, %d) %d, %d, %d.\n", pointmark(pe), 10366 pointmark(pd), pointmark(pa), pointmark(pb), pointmark(pc)); 10367 } 10368 flip32s++; 10369 10370 // Storing the old configuration outside the convex hull. 10371 enextfnext(edab, oldabd); 10372 enext2fnext(edab, oldbae); 10373 enextfnext(edbc, oldbcd); 10374 enext2fnext(edbc, oldcbe); 10375 enextfnext(edca, oldcad); 10376 enext2fnext(edca, oldace); 10377 sym(oldabd, abdcasing); 10378 sym(oldbcd, bcdcasing); 10379 sym(oldcad, cadcasing); 10380 sym(oldbae, baecasing); 10381 sym(oldcbe, cbecasing); 10382 sym(oldace, acecasing); 10383 if (checksubfaces) { 10384 tspivot(oldabd, abdsh); 10385 tspivot(oldbcd, bcdsh); 10386 tspivot(oldcad, cadsh); 10387 tspivot(oldbae, baesh); 10388 tspivot(oldcbe, cbesh); 10389 tspivot(oldace, acesh); 10390 } else if (checksubsegs) { 10391 enext(edab, worktet); 10392 tsspivot1(worktet, adseg); 10393 enext2(edab, worktet); 10394 tsspivot1(worktet, aeseg); 10395 enext(edbc, worktet); 10396 tsspivot1(worktet, bdseg); 10397 enext2(edbc, worktet); 10398 tsspivot1(worktet, beseg); 10399 enext(edca, worktet); 10400 tsspivot1(worktet, cdseg); 10401 enext2(edca, worktet); 10402 tsspivot1(worktet, ceseg); 10403 enextfnext(edab, worktet); 10404 enextself(worktet); 10405 tsspivot1(worktet, abseg); 10406 enextfnext(edbc, worktet); 10407 enextself(worktet); 10408 tsspivot1(worktet, bcseg); 10409 enextfnext(edca, worktet); 10410 enextself(worktet); 10411 tsspivot1(worktet, caseg); 10412 } 10413 10414 // Creating the new configuration inside the convex hull. 10415 abcd.tet = edab.tet; // Update edab to be abcd. 10416 setorg (abcd, pa); 10417 setdest(abcd, pb); 10418 setapex(abcd, pc); 10419 setoppo(abcd, pd); 10420 bace.tet = edbc.tet; // Update edbc to be bace. 10421 setorg (bace, pb); 10422 setdest(bace, pa); 10423 setapex(bace, pc); 10424 setoppo(bace, pe); 10425 // Dealloc a redundant tetrahedron (edca). 10426 tetrahedrondealloc(edca.tet); 10427 10428 // Clear the old bonds in abcd (was edab) and bace (was edbc). 10429 for (i = 0; i < 4; i ++) { 10430 abcd.tet[i] = (tetrahedron) dummytet; 10431 } 10432 for (i = 0; i < 4; i ++) { 10433 bace.tet[i] = (tetrahedron) dummytet; 10434 } 10435 // Bond the inside face of the convex hull. 10436 abcd.loc = 0; 10437 bace.loc = 0; 10438 bond(abcd, bace); 10439 // Bond the outside faces of the convex hull. 10440 abcd.loc = 1; 10441 bond(abcd, abdcasing); 10442 abcd.loc = 2; 10443 bond(abcd, bcdcasing); 10444 abcd.loc = 3; 10445 bond(abcd, cadcasing); 10446 bace.loc = 1; 10447 bond(bace, baecasing); 10448 bace.loc = 3; 10449 bond(bace, cbecasing); 10450 bace.loc = 2; 10451 bond(bace, acecasing); 10452 if (checksubfaces) { 10453 // Clear old bonds in abcd(was edab) and bace(was edbc). 10454 for (i = 0; i < 4; i ++) { 10455 abcd.tet[8 + i] = (tetrahedron) dummysh; 10456 } 10457 for (i = 0; i < 4; i ++) { 10458 bace.tet[8 + i] = (tetrahedron) dummysh; 10459 } 10460 if (abdsh.sh != dummysh) { 10461 abcd.loc = 1; 10462 tsbond(abcd, abdsh); 10463 } 10464 if (bcdsh.sh != dummysh) { 10465 abcd.loc = 2; 10466 tsbond(abcd, bcdsh); 10467 } 10468 if (cadsh.sh != dummysh) { 10469 abcd.loc = 3; 10470 tsbond(abcd, cadsh); 10471 } 10472 if (baesh.sh != dummysh) { 10473 bace.loc = 1; 10474 tsbond(bace, baesh); 10475 } 10476 if (cbesh.sh != dummysh) { 10477 bace.loc = 3; 10478 tsbond(bace, cbesh); 10479 } 10480 if (acesh.sh != dummysh) { 10481 bace.loc = 2; 10482 tsbond(bace, acesh); 10483 } 10484 } else if (checksubsegs) { 10485 for (i = 0; i < 6; i++) { 10486 abcd.tet[8 + i] = (tetrahedron) dummysh; 10487 } 10488 for (i = 0; i < 6; i++) { 10489 bace.tet[8 + i] = (tetrahedron) dummysh; 10490 } 10491 abcd.loc = abcd.ver = 0; 10492 bace.loc = bace.ver = 0; 10493 tssbond1(abcd, abseg); // 1 10494 enext(abcd, worktet); 10495 tssbond1(worktet, bcseg); // 2 10496 enext2(abcd, worktet); 10497 tssbond1(worktet, caseg); // 3 10498 fnext(abcd, worktet); 10499 enext2self(worktet); 10500 tssbond1(worktet, adseg); // 4 10501 enextfnext(abcd, worktet); 10502 enext2self(worktet); 10503 tssbond1(worktet, bdseg); // 5 10504 enext2fnext(abcd, worktet); 10505 enext2self(worktet); 10506 tssbond1(worktet, cdseg); // 6 10507 tssbond1(bace, abseg); 10508 enext2(bace, worktet); 10509 tssbond1(worktet, bcseg); 10510 enext(bace, worktet); 10511 tssbond1(worktet, caseg); 10512 fnext(bace, worktet); 10513 enextself(worktet); 10514 tssbond1(worktet, aeseg); // 7 10515 enext2fnext(bace, worktet); 10516 enextself(worktet); 10517 tssbond1(worktet, beseg); // 8 10518 enextfnext(bace, worktet); 10519 enextself(worktet); 10520 tssbond1(worktet, ceseg); // 9 10521 } 10522 10523 abcd.loc = 0; 10524 bace.loc = 0; 10525 if (b->verbose > 3) { 10526 printf(" Updating abcd "); 10527 printtet(&abcd); 10528 printf(" Updating bace "); 10529 printtet(&bace); 10530 printf(" Deleting edca "); 10531 // printtet(&edca); 10532 } 10533 10534 if (flipqueue != (queue *) NULL) { 10535 fnext(abcd, abdcasing); 10536 enqueueflipface(abdcasing, flipqueue); 10537 fnext(bace, baecasing); 10538 enqueueflipface(baecasing, flipqueue); 10539 enextfnext(abcd, bcdcasing); 10540 enqueueflipface(bcdcasing, flipqueue); 10541 enextfnext(bace, cbecasing); 10542 enqueueflipface(cbecasing, flipqueue); 10543 enext2fnext(abcd, cadcasing); 10544 enqueueflipface(cadcasing, flipqueue); 10545 enext2fnext(bace, acecasing); 10546 enqueueflipface(acecasing, flipqueue); 10547 } 10548 10549 // Save a live handle in 'recenttet'. 10550 recenttet = abcd; 10551 // Set the return handle be abcd. 10552 *flipface = abcd; 10553 } 10554 10556 // // 10557 // flip22() Perform a 2-to-2 (or 4-to-4) flip. // 10558 // // 10559 // On input, 'flipface' represents the face will be flipped. Let it is abe, // 10560 // ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,// 10561 // hence a, b, c and d are coplanar. If abc, bad are interior faces, the two // 10562 // tetrahedra opposite to e are bacf and abdf. ab is not a subsegment. // 10563 // // 10564 // A 2-to-2 flip is to change two tetrahedra abce and bade into another two // 10565 // tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf // 10566 // and dcbf, thus a 4-to-4 flip. As a result, two or four tetrahedra have // 10567 // rotated counterclockwise (using right-hand rule with thumb points to e): // 10568 // abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf. // 10569 // // 10570 // If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by // 10571 // calling routine flip22sub(), hence abc->dca, bad->cdb. The edge rings of // 10572 // the flipped subfaces dca and cdb have the same orientation as abc and bad.// 10573 // Hence, they have the same orientation as other subfaces of the facet with // 10574 // respect to the lift point of this facet. // 10575 // // 10576 // On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue' // 10577 // contains all possibly non-Delaunay faces if it is not NULL. // 10578 // // 10580 10581 void tetgenmesh::flip22(triface* flipface, queue* flipqueue) 10582 { 10583 triface abce, bade; 10584 triface oldbce, oldcae, oldade, olddbe; 10585 triface bcecasing, caecasing, adecasing, dbecasing; 10586 face bcesh, caesh, adesh, dbesh; 10587 triface bacf, abdf; 10588 triface oldacf, oldcbf, oldbdf, olddaf; 10589 triface acfcasing, cbfcasing, bdfcasing, dafcasing; 10590 triface worktet; 10591 face acfsh, cbfsh, bdfsh, dafsh; 10592 face abc, bad; 10593 face adseg, dbseg, bcseg, caseg; // Coplanar segs. 10594 face aeseg, deseg, beseg, ceseg; // Above segs. 10595 face afseg, dfseg, bfseg, cfseg; // Below segs. 10596 point pa, pb, pc, pd; 10597 #ifdef SELF_CHECK 10598 point pe, pf; 10599 #endif 10600 int mirrorflag, i; 10601 10602 adjustedgering(*flipface, CCW); // 'flipface' is bae. 10603 fnext(*flipface, abce); 10604 esymself(abce); 10605 adjustedgering(*flipface, CW); // 'flipface' is abe. 10606 fnext(*flipface, bade); 10607 #ifdef SELF_CHECK 10608 assert(bade.tet != dummytet); 10609 #endif 10610 esymself(bade); 10611 pa = org(abce); 10612 pb = dest(abce); 10613 pc = apex(abce); 10614 pd = apex(bade); 10615 #ifdef SELF_CHECK 10616 pe = oppo(bade); 10617 assert(oppo(abce) == pe); 10618 #endif 10619 sym(abce, bacf); 10620 mirrorflag = bacf.tet != dummytet; 10621 if (mirrorflag) { 10622 // findedge(&bacf, pb, pa); 10623 bacf.ver = 0; 10624 for (i = 0; (i < 3) && (org(bacf) != pb); i++) { 10625 enextself(bacf); 10626 } 10627 sym(bade, abdf); 10628 #ifdef SELF_CHECK 10629 assert(abdf.tet != dummytet); 10630 #endif 10631 // findedge(&abdf, pa, pb); 10632 abdf.ver = 0; 10633 for (i = 0; (i < 3) && (org(abdf) != pa); i++) { 10634 enextself(abdf); 10635 } 10636 10637 #ifdef SELF_CHECK 10638 pf = oppo(bacf); 10639 assert(oppo(abdf) == pf); 10640 #endif 10641 } 10642 10643 if (b->verbose > 2) { 10644 printf(" Do %s on edge (%d, %d).\n", mirrorflag ? "T44" : "T22", 10645 pointmark(pa), pointmark(pb)); 10646 } 10647 mirrorflag ? flip44s++ : flip22s++; 10648 10649 // Save the old configuration at the convex hull. 10650 enextfnext(abce, oldbce); 10651 enext2fnext(abce, oldcae); 10652 enextfnext(bade, oldade); 10653 enext2fnext(bade, olddbe); 10654 sym(oldbce, bcecasing); 10655 sym(oldcae, caecasing); 10656 sym(oldade, adecasing); 10657 sym(olddbe, dbecasing); 10658 if (checksubfaces) { 10659 tspivot(oldbce, bcesh); 10660 tspivot(oldcae, caesh); 10661 tspivot(oldade, adesh); 10662 tspivot(olddbe, dbesh); 10663 tspivot(abce, abc); 10664 tspivot(bade, bad); 10665 } else if (checksubsegs) { 10666 // Coplanar segs: a->d->b->c. 10667 enext(bade, worktet); 10668 tsspivot1(worktet, adseg); 10669 enext2(bade, worktet); 10670 tsspivot1(worktet, dbseg); 10671 enext(abce, worktet); 10672 tsspivot1(worktet, bcseg); 10673 enext2(abce, worktet); 10674 tsspivot1(worktet, caseg); 10675 // Above segs: a->e, d->e, b->e, c->e. 10676 fnext(bade, worktet); 10677 enextself(worktet); 10678 tsspivot1(worktet, aeseg); 10679 enextfnext(bade, worktet); 10680 enextself(worktet); 10681 tsspivot1(worktet, deseg); 10682 enext2fnext(bade, worktet); 10683 enextself(worktet); 10684 tsspivot1(worktet, beseg); 10685 enextfnext(abce, worktet); 10686 enextself(worktet); 10687 tsspivot1(worktet, ceseg); 10688 } 10689 if (mirrorflag) { 10690 enextfnext(bacf, oldacf); 10691 enext2fnext(bacf, oldcbf); 10692 enextfnext(abdf, oldbdf); 10693 enext2fnext(abdf, olddaf); 10694 sym(oldacf, acfcasing); 10695 sym(oldcbf, cbfcasing); 10696 sym(oldbdf, bdfcasing); 10697 sym(olddaf, dafcasing); 10698 if (checksubfaces) { 10699 tspivot(oldacf, acfsh); 10700 tspivot(oldcbf, cbfsh); 10701 tspivot(oldbdf, bdfsh); 10702 tspivot(olddaf, dafsh); 10703 } else if (checksubsegs) { 10704 // Below segs: a->f, d->f, b->f, c->f. 10705 fnext(abdf, worktet); 10706 enext2self(worktet); 10707 tsspivot1(worktet, afseg); 10708 enext2fnext(abdf, worktet); 10709 enext2self(worktet); 10710 tsspivot1(worktet, dfseg); 10711 enextfnext(abdf, worktet); 10712 enext2self(worktet); 10713 tsspivot1(worktet, bfseg); 10714 enextfnext(bacf, worktet); 10715 enextself(worktet); 10716 tsspivot1(worktet, cfseg); 10717 } 10718 } 10719 10720 // Rotate abce, bade one-quarter turn counterclockwise. 10721 bond(oldbce, caecasing); 10722 bond(oldcae, adecasing); 10723 bond(oldade, dbecasing); 10724 bond(olddbe, bcecasing); 10725 if (checksubfaces) { 10726 // Check for subfaces and rebond them to the rotated tets. 10727 if (caesh.sh == dummysh) { 10728 tsdissolve(oldbce); 10729 } else { 10730 tsbond(oldbce, caesh); 10731 } 10732 if (adesh.sh == dummysh) { 10733 tsdissolve(oldcae); 10734 } else { 10735 tsbond(oldcae, adesh); 10736 } 10737 if (dbesh.sh == dummysh) { 10738 tsdissolve(oldade); 10739 } else { 10740 tsbond(oldade, dbesh); 10741 } 10742 if (bcesh.sh == dummysh) { 10743 tsdissolve(olddbe); 10744 } else { 10745 tsbond(olddbe, bcesh); 10746 } 10747 } else if (checksubsegs) { 10748 // 5 edges in abce are changed. 10749 enext(abce, worktet); // fit b->c into c->a. 10750 if (caseg.sh == dummysh) { 10751 tssdissolve1(worktet); 10752 } else { 10753 tssbond1(worktet, caseg); 10754 } 10755 enext2(abce, worktet); // fit c->a into a->d. 10756 if (adseg.sh == dummysh) { 10757 tssdissolve1(worktet); 10758 } else { 10759 tssbond1(worktet, adseg); 10760 } 10761 fnext(abce, worktet); // fit b->e into c->e. 10762 enextself(worktet); 10763 if (ceseg.sh == dummysh) { 10764 tssdissolve1(worktet); 10765 } else { 10766 tssbond1(worktet, ceseg); 10767 } 10768 enextfnext(abce, worktet); // fit c->e into a->e. 10769 enextself(worktet); 10770 if (aeseg.sh == dummysh) { 10771 tssdissolve1(worktet); 10772 } else { 10773 tssbond1(worktet, aeseg); 10774 } 10775 enext2fnext(abce, worktet); // fit a->e into d->e. 10776 enextself(worktet); 10777 if (deseg.sh == dummysh) { 10778 tssdissolve1(worktet); 10779 } else { 10780 tssbond1(worktet, deseg); 10781 } 10782 // 5 edges in bade are changed. 10783 enext(bade, worktet); // fit a->d into d->b. 10784 if (dbseg.sh == dummysh) { 10785 tssdissolve1(worktet); 10786 } else { 10787 tssbond1(worktet, dbseg); 10788 } 10789 enext2(bade, worktet); // fit d->b into b->c. 10790 if (bcseg.sh == dummysh) { 10791 tssdissolve1(worktet); 10792 } else { 10793 tssbond1(worktet, bcseg); 10794 } 10795 fnext(bade, worktet); // fit a->e into d->e. 10796 enextself(worktet); 10797 if (deseg.sh == dummysh) { 10798 tssdissolve1(worktet); 10799 } else { 10800 tssbond1(worktet, deseg); 10801 } 10802 enextfnext(bade, worktet); // fit d->e into b->e. 10803 enextself(worktet); 10804 if (beseg.sh == dummysh) { 10805 tssdissolve1(worktet); 10806 } else { 10807 tssbond1(worktet, beseg); 10808 } 10809 enext2fnext(bade, worktet); // fit b->e into c->e. 10810 enextself(worktet); 10811 if (ceseg.sh == dummysh) { 10812 tssdissolve1(worktet); 10813 } else { 10814 tssbond1(worktet, ceseg); 10815 } 10816 } 10817 if (mirrorflag) { 10818 // Rotate bacf, abdf one-quarter turn counterclockwise. 10819 bond(oldcbf, acfcasing); 10820 bond(oldacf, dafcasing); 10821 bond(olddaf, bdfcasing); 10822 bond(oldbdf, cbfcasing); 10823 if (checksubfaces) { 10824 // Check for subfaces and rebond them to the rotated tets. 10825 if (acfsh.sh == dummysh) { 10826 tsdissolve(oldcbf); 10827 } else { 10828 tsbond(oldcbf, acfsh); 10829 } 10830 if (dafsh.sh == dummysh) { 10831 tsdissolve(oldacf); 10832 } else { 10833 tsbond(oldacf, dafsh); 10834 } 10835 if (bdfsh.sh == dummysh) { 10836 tsdissolve(olddaf); 10837 } else { 10838 tsbond(olddaf, bdfsh); 10839 } 10840 if (cbfsh.sh == dummysh) { 10841 tsdissolve(oldbdf); 10842 } else { 10843 tsbond(oldbdf, cbfsh); 10844 } 10845 } else if (checksubsegs) { 10846 // 5 edges in bacf are changed. 10847 enext2(bacf, worktet); // fit b->c into c->a. 10848 if (caseg.sh == dummysh) { 10849 tssdissolve1(worktet); 10850 } else { 10851 tssbond1(worktet, caseg); 10852 } 10853 enext(bacf, worktet); // fit c->a into a->d. 10854 if (adseg.sh == dummysh) { 10855 tssdissolve1(worktet); 10856 } else { 10857 tssbond1(worktet, adseg); 10858 } 10859 fnext(bacf, worktet); // fit b->f into c->f. 10860 enext2self(worktet); 10861 if (cfseg.sh == dummysh) { 10862 tssdissolve1(worktet); 10863 } else { 10864 tssbond1(worktet, cfseg); 10865 } 10866 enext2fnext(bacf, worktet); // fit c->f into a->f. 10867 enext2self(worktet); 10868 if (afseg.sh == dummysh) { 10869 tssdissolve1(worktet); 10870 } else { 10871 tssbond1(worktet, afseg); 10872 } 10873 enextfnext(bacf, worktet); // fit a->f into d->f. 10874 enext2self(worktet); 10875 if (dfseg.sh == dummysh) { 10876 tssdissolve1(worktet); 10877 } else { 10878 tssbond1(worktet, dfseg); 10879 } 10880 // 5 edges in abdf are changed. 10881 enext2(abdf, worktet); // fit a->d into d->b. 10882 if (dbseg.sh == dummysh) { 10883 tssdissolve1(worktet); 10884 } else { 10885 tssbond1(worktet, dbseg); 10886 } 10887 enext(abdf, worktet); // fit d->b into b->c. 10888 if (bcseg.sh == dummysh) { 10889 tssdissolve1(worktet); 10890 } else { 10891 tssbond1(worktet, bcseg); 10892 } 10893 fnext(abdf, worktet); // fit a->f into d->f. 10894 enext2self(worktet); 10895 if (dfseg.sh == dummysh) { 10896 tssdissolve1(worktet); 10897 } else { 10898 tssbond1(worktet, dfseg); 10899 } 10900 enext2fnext(abdf, worktet); // fit d->f into b->f. 10901 enext2self(worktet); 10902 if (bfseg.sh == dummysh) { 10903 tssdissolve1(worktet); 10904 } else { 10905 tssbond1(worktet, bfseg); 10906 } 10907 enextfnext(abdf, worktet); // fit b->f into c->f. 10908 enext2self(worktet); 10909 if (cfseg.sh == dummysh) { 10910 tssdissolve1(worktet); 10911 } else { 10912 tssbond1(worktet, cfseg); 10913 } 10914 } 10915 } 10916 10917 // New vertex assignments for the rotated tetrahedra. 10918 setorg(abce, pd); // Update abce to dcae 10919 setdest(abce, pc); 10920 setapex(abce, pa); 10921 setorg(bade, pc); // Update bade to cdbe 10922 setdest(bade, pd); 10923 setapex(bade, pb); 10924 if (mirrorflag) { 10925 setorg(bacf, pc); // Update bacf to cdaf 10926 setdest(bacf, pd); 10927 setapex(bacf, pa); 10928 setorg(abdf, pd); // Update abdf to dcbf 10929 setdest(abdf, pc); 10930 setapex(abdf, pb); 10931 } 10932 10933 // Are there subfaces need to be flipped? 10934 if (checksubfaces && abc.sh != dummysh) { 10935 #ifdef SELF_CHECK 10936 assert(bad.sh != dummysh); 10937 #endif 10938 // Adjust the edge be ab, so the rotation of subfaces is according with 10939 // the rotation of tetrahedra. 10940 findedge(&abc, pa, pb); 10941 // Flip an edge of two subfaces, ignore non-Delaunay edges. 10942 flip22sub(&abc, NULL); 10943 } 10944 10945 if (b->verbose > 3) { 10946 printf(" Updating abce "); 10947 printtet(&abce); 10948 printf(" Updating bade "); 10949 printtet(&bade); 10950 if (mirrorflag) { 10951 printf(" Updating bacf "); 10952 printtet(&bacf); 10953 printf(" Updating abdf "); 10954 printtet(&abdf); 10955 } 10956 } 10957 10958 if (flipqueue != (queue *) NULL) { 10959 enextfnext(abce, bcecasing); 10960 enqueueflipface(bcecasing, flipqueue); 10961 enext2fnext(abce, caecasing); 10962 enqueueflipface(caecasing, flipqueue); 10963 enextfnext(bade, adecasing); 10964 enqueueflipface(adecasing, flipqueue); 10965 enext2fnext(bade, dbecasing); 10966 enqueueflipface(dbecasing, flipqueue); 10967 if (mirrorflag) { 10968 enextfnext(bacf, acfcasing); 10969 enqueueflipface(acfcasing, flipqueue); 10970 enext2fnext(bacf, cbfcasing); 10971 enqueueflipface(cbfcasing, flipqueue); 10972 enextfnext(abdf, bdfcasing); 10973 enqueueflipface(bdfcasing, flipqueue); 10974 enext2fnext(abdf, dafcasing); 10975 enqueueflipface(dafcasing, flipqueue); 10976 } 10977 // The two new faces dcae (abce), cdbe (bade) may still not be locally 10978 // Delaunay, and may need be flipped (flip23). On the other hand, in 10979 // conforming Delaunay algorithm, two new subfaces dca (abc), and cdb 10980 // (bad) may be non-conforming Delaunay, they need be queued if they 10981 // are locally Delaunay but non-conforming Delaunay. 10982 enqueueflipface(abce, flipqueue); 10983 enqueueflipface(bade, flipqueue); 10984 } 10985 10986 // Save a live handle in 'recenttet'. 10987 recenttet = abce; 10988 } 10989 10991 // // 10992 // flip22sub() Perform a 2-to-2 flip on a subface edge. // 10993 // // 10994 // The flip edge is given by subface 'flipedge'. Let it is abc, where ab is // 10995 // the flipping edge. The other subface is bad, where a, b, c, d form a // 10996 // convex quadrilateral. ab is not a subsegment. // 10997 // // 10998 // A 2-to-2 subface flip is to change two subfaces abc and bad to another // 10999 // two subfaces dca and cdb. Hence, edge ab has been removed and dc becomes // 11000 // an edge. If a point e is above abc, this flip is equal to rotate abc and // 11001 // bad counterclockwise using right-hand rule with thumb points to e. It is // 11002 // important to know that the edge rings of the flipped subfaces dca and cdb // 11003 // are keeping the same orientation as their original subfaces. So they have // 11004 // the same orientation with respect to the lift point of this facet. // 11005 // // 11006 // During rotating, the face rings of the four edges bc, ca, ad, and de need // 11007 // be re-connected. If the edge is not a subsegment, then its face ring has // 11008 // only two faces, a sbond() will bond them together. If it is a subsegment, // 11009 // one should use sbond1() twice to bond two different handles to the rotat- // 11010 // ing subface, one is predecssor (-casin), another is successor (-casout). // 11011 // // 11012 // If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which // 11013 // may be non-Delaunay. // 11014 // // 11016 11017 void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue) 11018 { 11019 face abc, bad; 11020 face oldbc, oldca, oldad, olddb; 11021 face bccasin, bccasout, cacasin, cacasout; 11022 face adcasin, adcasout, dbcasin, dbcasout; 11023 face bc, ca, ad, db; 11024 face spinsh; 11025 point pa, pb, pc, pd; 11026 11027 abc = *flipedge; 11028 spivot(abc, bad); 11029 if (sorg(bad) != sdest(abc)) { 11030 sesymself(bad); 11031 } 11032 pa = sorg(abc); 11033 pb = sdest(abc); 11034 pc = sapex(abc); 11035 pd = sapex(bad); 11036 11037 if (b->verbose > 2) { 11038 printf(" Flip sub edge (%d, %d).\n", pointmark(pa), pointmark(pb)); 11039 } 11040 11041 // Save the old configuration outside the quadrilateral. 11042 senext(abc, oldbc); 11043 senext2(abc, oldca); 11044 senext(bad, oldad); 11045 senext2(bad, olddb); 11046 // Get the outside connection. Becareful if there is a subsegment on the 11047 // quadrilateral, two casings (casin and casout) are needed to save for 11048 // keeping the face link. 11049 spivot(oldbc, bccasout); 11050 sspivot(oldbc, bc); 11051 if (bc.sh != dummysh) { 11052 // 'bc' is a subsegment. 11053 if (bccasout.sh != dummysh) { 11054 if (oldbc.sh != bccasout.sh) { 11055 // 'oldbc' is not self-bonded. 11056 spinsh = bccasout; 11057 do { 11058 bccasin = spinsh; 11059 spivotself(spinsh); 11060 } while (spinsh.sh != oldbc.sh); 11061 } else { 11062 bccasout.sh = dummysh; 11063 } 11064 } 11065 ssdissolve(oldbc); 11066 } 11067 spivot(oldca, cacasout); 11068 sspivot(oldca, ca); 11069 if (ca.sh != dummysh) { 11070 // 'ca' is a subsegment. 11071 if (cacasout.sh != dummysh) { 11072 if (oldca.sh != cacasout.sh) { 11073 // 'oldca' is not self-bonded. 11074 spinsh = cacasout; 11075 do { 11076 cacasin = spinsh; 11077 spivotself(spinsh); 11078 } while (spinsh.sh != oldca.sh); 11079 } else { 11080 cacasout.sh = dummysh; 11081 } 11082 } 11083 ssdissolve(oldca); 11084 } 11085 spivot(oldad, adcasout); 11086 sspivot(oldad, ad); 11087 if (ad.sh != dummysh) { 11088 // 'ad' is a subsegment. 11089 if (adcasout.sh != dummysh) { 11090 if (oldad.sh != adcasout.sh) { 11091 // 'adcasout' is not self-bonded. 11092 spinsh = adcasout; 11093 do { 11094 adcasin = spinsh; 11095 spivotself(spinsh); 11096 } while (spinsh.sh != oldad.sh); 11097 } else { 11098 adcasout.sh = dummysh; 11099 } 11100 } 11101 ssdissolve(oldad); 11102 } 11103 spivot(olddb, dbcasout); 11104 sspivot(olddb, db); 11105 if (db.sh != dummysh) { 11106 // 'db' is a subsegment. 11107 if (dbcasout.sh != dummysh) { 11108 if (olddb.sh != dbcasout.sh) { 11109 // 'dbcasout' is not self-bonded. 11110 spinsh = dbcasout; 11111 do { 11112 dbcasin = spinsh; 11113 spivotself(spinsh); 11114 } while (spinsh.sh != olddb.sh); 11115 } else { 11116 dbcasout.sh = dummysh; 11117 } 11118 } 11119 ssdissolve(olddb); 11120 } 11121 11122 // Rotate abc and bad one-quarter turn counterclockwise. 11123 if (ca.sh != dummysh) { 11124 if (cacasout.sh != dummysh) { 11125 sbond1(cacasin, oldbc); 11126 sbond1(oldbc, cacasout); 11127 } else { 11128 // Bond 'oldbc' to itself. 11129 sbond(oldbc, oldbc); 11130 // Make sure that dummysh always correctly bonded. 11131 dummysh[0] = sencode(oldbc); 11132 } 11133 ssbond(oldbc, ca); 11134 } else { 11135 sbond(oldbc, cacasout); 11136 } 11137 if (ad.sh != dummysh) { 11138 if (adcasout.sh != dummysh) { 11139 sbond1(adcasin, oldca); 11140 sbond1(oldca, adcasout); 11141 } else { 11142 // Bond 'oldca' to itself. 11143 sbond(oldca, oldca); 11144 // Make sure that dummysh always correctly bonded. 11145 dummysh[0] = sencode(oldca); 11146 } 11147 ssbond(oldca, ad); 11148 } else { 11149 sbond(oldca, adcasout); 11150 } 11151 if (db.sh != dummysh) { 11152 if (dbcasout.sh != dummysh) { 11153 sbond1(dbcasin, oldad); 11154 sbond1(oldad, dbcasout); 11155 } else { 11156 // Bond 'oldad' to itself. 11157 sbond(oldad, oldad); 11158 // Make sure that dummysh always correctly bonded. 11159 dummysh[0] = sencode(oldad); 11160 } 11161 ssbond(oldad, db); 11162 } else { 11163 sbond(oldad, dbcasout); 11164 } 11165 if (bc.sh != dummysh) { 11166 if (bccasout.sh != dummysh) { 11167 sbond1(bccasin, olddb); 11168 sbond1(olddb, bccasout); 11169 } else { 11170 // Bond 'olddb' to itself. 11171 sbond(olddb, olddb); 11172 // Make sure that dummysh always correctly bonded. 11173 dummysh[0] = sencode(olddb); 11174 } 11175 ssbond(olddb, bc); 11176 } else { 11177 sbond(olddb, bccasout); 11178 } 11179 11180 // New vertex assignments for the rotated subfaces. 11181 setsorg(abc, pd); // Update abc to dca. 11182 setsdest(abc, pc); 11183 setsapex(abc, pa); 11184 setsorg(bad, pc); // Update bad to cdb. 11185 setsdest(bad, pd); 11186 setsapex(bad, pb); 11187 11188 if (flipqueue != (queue *) NULL) { 11189 enqueueflipedge(bccasout, flipqueue); 11190 enqueueflipedge(cacasout, flipqueue); 11191 enqueueflipedge(adcasout, flipqueue); 11192 enqueueflipedge(dbcasout, flipqueue); 11193 } 11194 } 11195 11197 // // 11198 // flip() Flips non-locally Delaunay faces in flipqueue until it is empty.// 11199 // // 11200 // Assumpation: Current tetrahedralization is non-Delaunay after inserting // 11201 // a point or performing a flip operation, all possibly non-Delaunay faces // 11202 // are in 'flipqueue'. // 11203 // // 11204 // If 'plastflip' is not NULL, it is used to return a stack of recently // 11205 // flipped faces. This stack will be used to reverse the flips done in this // 11206 // routine later for removing a newly inserted point because it encroaches // 11207 // any subfaces or subsegments. // 11208 // // 11209 // The return value is the total number of flips done during this invocation.// 11210 // // 11212 11213 long tetgenmesh::flip(queue* flipqueue, badface **plastflip) 11214 { 11215 badface *qface, *newflip; 11216 triface flipface, symface; 11217 point pa, pb, pc, pd, pe; 11218 enum fliptype fc; 11219 REAL sign, bakepsilon; 11220 long flipcount; //, maxfaces; - commented out to get gcc4.6 working 11221 int epscount, fcount; 11222 int ia, ib, ic, id, ie; 11223 11224 if (b->verbose > 1) { 11225 printf(" Do flipface queue: %ld faces.\n", flipqueue->len()); 11226 } 11227 11228 flipcount = flip23s + flip32s + flip22s + flip44s; 11229 if (checksubfaces) { 11230 //maxfaces = (4l * tetrahedrons->items + hullsize) / 2l; // commented out to get gcc 4.6 working 11231 fcount = 0; 11232 } 11233 11234 if (plastflip != (badface **) NULL) { 11235 // Initialize the stack of the flip sequence. 11236 flipstackers->restart(); 11237 *plastflip = (badface *) NULL; 11238 } 11239 11240 // Loop until the queue is empty. 11241 while (!flipqueue->empty()) { 11242 qface = (badface *) flipqueue->pop(); 11243 flipface = qface->tt; 11244 if (isdead(&flipface)) continue; 11245 sym(flipface, symface); 11246 // Only do check when the adjacent tet exists and it's not a "fake" tet. 11247 if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) { 11248 // For positive orientation that insphere() test requires. 11249 adjustedgering(flipface, CW); 11250 pa = org(flipface); 11251 pb = dest(flipface); 11252 pc = apex(flipface); 11253 pd = oppo(flipface); 11254 pe = oppo(symface); 11255 if (symbolic) { 11256 ia = pointmark(pa); 11257 ib = pointmark(pb); 11258 ic = pointmark(pc); 11259 id = pointmark(pd); 11260 ie = pointmark(pe); 11261 sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie); 11262 assert(sign != 0.0); 11263 } else { 11264 sign = insphere(pa, pb, pc, pd, pe); 11265 } 11266 } else { 11267 sign = -1.0; // A hull face is locally Delaunay. 11268 } 11269 if (sign > 0.0) { 11270 // 'flipface' is non-locally Delaunay, try to flip it. 11271 if (checksubfaces) { 11272 fcount++; 11273 bakepsilon = b->epsilon; 11274 epscount = 0; 11275 while (epscount < 32) { 11276 fc = categorizeface(flipface); 11277 if (fc == N40) { 11278 b->epsilon *= 1e-1; 11279 epscount++; 11280 continue; 11281 } 11282 break; 11283 } 11284 b->epsilon = bakepsilon; 11285 if (epscount >= 32) { 11286 if (b->verbose > 0) { 11287 printf("Warning: Can't flip a degenerate tetrahedron.\n"); 11288 } 11289 fc = N40; 11290 } 11291 } else { 11292 fc = categorizeface(flipface); 11293 #ifdef SELF_CHECK 11294 assert(fc != N40); 11295 #endif 11296 } 11297 switch (fc) { 11298 // The following face types are flipable. 11299 case T44: 11300 case T22: 11301 flip22(&flipface, flipqueue); 11302 break; 11303 case T23: 11304 flip23(&flipface, flipqueue); 11305 break; 11306 case T32: 11307 flip32(&flipface, flipqueue); 11308 break; 11309 // The following face types are unflipable. 11310 case N32: 11311 break; 11312 case FORBIDDENFACE: 11313 break; 11314 case FORBIDDENEDGE: 11315 break; 11316 // This case is only possible when the domain is nonconvex. 11317 case N40: 11318 // assert(nonconvex); 11319 break; 11320 } 11321 if (plastflip != (badface **) NULL) { 11322 if ((fc == T44) || (fc == T22) || (fc == T23) || (fc == T32)) { 11323 // Push the flipped face into stack. 11324 newflip = (badface *) flipstackers->alloc(); 11325 newflip->tt = flipface; 11326 newflip->key = (REAL) fc; 11327 newflip->forg = org(flipface); 11328 newflip->fdest = dest(flipface); 11329 newflip->fapex = apex(flipface); 11330 newflip->previtem = *plastflip; 11331 *plastflip = newflip; 11332 } 11333 } 11334 } 11335 } 11336 11337 flipcount = flip23s + flip32s + flip22s + flip44s - flipcount; 11338 if (b->verbose > 1) { 11339 printf(" %ld flips.\n", flipcount); 11340 } 11341 11342 return flipcount; 11343 } 11344 11346 // // 11347 // lawson() Flip locally non-Delaunay faces by Lawson's algorithm. // 11348 // // 11350 11351 long tetgenmesh::lawson(list *misseglist, queue* flipqueue) 11352 { 11353 badface *qface, *misseg; 11354 triface flipface, symface; 11355 triface starttet, spintet; 11356 face checksh, checkseg; 11357 point pa, pb, pc, pd, pe; 11358 point swappt; 11359 REAL sign, ori; 11360 long flipcount; 11361 int ia, ib, ic, id, ie; 11362 int hitbdry, i; 11363 11364 if (b->verbose > 1) { 11365 printf(" Do flipface queue: %ld faces.\n", flipqueue->len()); 11366 } 11367 flipcount = flip23s + flip32s + flip22s + flip44s; 11368 11369 // Go through the stack of possible flips and decide whether to do them. 11370 // Note that during the loop new possible flips will be pushed onto 11371 // this stack, while they popped in this loop. 11372 while (!flipqueue->empty()) { 11373 qface = (badface *) flipqueue->pop(); 11374 flipface = qface->tt; 11375 // Check if tet has already been flipped out of existence. 11376 if (!isdead(&flipface)) { 11377 sym(flipface, symface); 11378 // Check if this tet is the same as the one which was stacked. 11379 if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) { 11380 flipface.ver = 0; // Select the CCW ring. 11381 pa = org(flipface); 11382 pb = dest(flipface); 11383 pc = apex(flipface); 11384 pd = oppo(flipface); 11385 pe = oppo(symface); 11386 if (symbolic) { 11387 ia = pointmark(pa); 11388 ib = pointmark(pb); 11389 ic = pointmark(pc); 11390 id = pointmark(pd); 11391 ie = pointmark(pe); 11392 sign = insphere_sos(pb, pa, pc, pd, pe, ib, ia, ic, id, ie); 11393 } else { 11394 sign = insphere(pb, pa, pc, pd, pe); 11395 } 11396 if (sign > 0.0) { 11397 for (i = 0; i < 3; i++) { 11398 ori = orient3d(pa, pb, pd, pe); 11399 if (ori > 0.0) { 11400 // Goto and check the next edge. 11401 swappt = pa; 11402 pa = pb; 11403 pb = pc; 11404 pc = swappt; 11405 enextself(flipface); 11406 } else { 11407 break; // either (ori < 0.0) or (ori == 0.0) 11408 } 11409 } // for (i = 0; ....) 11410 if (ori > 0.0) { 11411 // All three edges are convex, a 2-3 flip is possible. 11412 if (checksubfaces) { 11413 tspivot(flipface, checksh); 11414 if (checksh.sh != dummysh) { 11415 // A subface is not flipable. 11416 continue; 11417 } 11418 } 11419 flip23(&flipface, flipqueue); 11420 } else if (ori < 0.0) { 11421 // The edge (a, b) is non-convex, check for a 3-2 flip. 11422 fnext(flipface, symface); 11423 symself(symface); 11424 if (oppo(symface) == pe) { 11425 // Only three tets adjoining this edge. 11426 if (checksubfaces) { 11427 tsspivot(&flipface, &checkseg); 11428 if (checkseg.sh != dummysh) { 11429 // A subsegment is not flipable. 11430 continue; 11431 } 11432 } else if (checksubsegs) { 11433 tsspivot1(flipface, checkseg); 11434 if (checkseg.sh != dummysh) { 11435 if (b->verbose > 2) { 11436 printf(" Queuing missing segment (%d, %d).\n", 11437 pointmark(org(flipface)), pointmark(dest(flipface))); 11438 } 11439 misseg = (badface *) misseglist->append(NULL); 11440 misseg->ss = checkseg; 11441 misseg->forg = sorg(checkseg); 11442 misseg->fdest = sdest(checkseg); 11443 // Detach all tets having this seg. 11444 starttet = flipface; 11445 adjustedgering(starttet, CCW); 11446 fnextself(starttet); 11447 spintet = starttet; 11448 hitbdry = 0; 11449 do { 11450 tssdissolve1(spintet); 11451 if (!fnextself(spintet)) { 11452 hitbdry++; 11453 if (hitbdry < 2) { 11454 esym(starttet, spintet); 11455 if (!fnextself(spintet)) { 11456 hitbdry++; 11457 } 11458 } 11459 } 11460 } while ((apex(spintet) != apex(starttet)) && (hitbdry < 2)); 11461 } 11462 } // if (checksubfaces) 11463 flip32(&flipface, flipqueue); 11464 } 11465 } else { 11466 // Four points (a, b, d, e) are coplanar. 11467 fnext(flipface, symface); 11468 if (fnextself(symface)) { 11469 // Check for a 4-4 flip. 11470 fnextself(symface); 11471 if (apex(symface) == pe) { 11472 if (checksubfaces) { 11473 tsspivot(&flipface, &checkseg); 11474 if (checkseg.sh != dummysh) { 11475 // A subsegment is not flippable. 11476 continue; 11477 } 11478 } else if (checksubsegs) { 11479 tsspivot1(flipface, checkseg); 11480 if (checkseg.sh != dummysh) { 11481 if (b->verbose > 2) { 11482 printf(" Queuing missing segment (%d, %d).\n", 11483 pointmark(org(flipface)), pointmark(dest(flipface))); 11484 } 11485 misseg = (badface *) misseglist->append(NULL); 11486 misseg->ss = checkseg; 11487 misseg->forg = sorg(checkseg); 11488 misseg->fdest = sdest(checkseg); 11489 // Detach all tets having this seg. 11490 starttet = flipface; 11491 adjustedgering(starttet, CCW); 11492 fnextself(starttet); 11493 spintet = starttet; 11494 hitbdry = 0; 11495 do { 11496 tssdissolve1(spintet); 11497 if (!fnextself(spintet)) { 11498 hitbdry++; 11499 if (hitbdry < 2) { 11500 esym(starttet, spintet); 11501 if (!fnextself(spintet)) { 11502 hitbdry++; 11503 } 11504 } 11505 } 11506 } while ((apex(spintet) != apex(starttet)) && 11507 (hitbdry < 2)); 11508 } 11509 } // if (checksubfaces) 11510 flip22(&flipface, flipqueue); 11511 } 11512 } else { 11513 // Check for a 2-2 flip. 11514 esym(flipface, symface); 11515 fnextself(symface); 11516 symself(symface); 11517 if (symface.tet == dummytet) { 11518 if (checksubfaces) { 11519 tsspivot(&flipface, &checkseg); 11520 if (checkseg.sh != dummysh) { 11521 // A subsegment is not flipable. 11522 continue; 11523 } 11524 } else if (checksubsegs) { 11525 tsspivot1(flipface, checkseg); 11526 if (checkseg.sh != dummysh) { 11527 if (b->verbose > 2) { 11528 printf(" Queuing missing segment (%d, %d).\n", 11529 pointmark(org(flipface)), pointmark(dest(flipface))); 11530 } 11531 misseg = (badface *) misseglist->append(NULL); 11532 misseg->ss = checkseg; 11533 misseg->forg = sorg(checkseg); 11534 misseg->fdest = sdest(checkseg); 11535 // Detach all tets having this seg. 11536 starttet = flipface; 11537 adjustedgering(starttet, CCW); 11538 fnextself(starttet); 11539 spintet = starttet; 11540 hitbdry = 0; 11541 do { 11542 tssdissolve1(spintet); 11543 if (!fnextself(spintet)) { 11544 hitbdry++; 11545 if (hitbdry < 2) { 11546 esym(starttet, spintet); 11547 if (!fnextself(spintet)) { 11548 hitbdry++; 11549 } 11550 } 11551 } 11552 } while ((apex(spintet) != apex(starttet)) && 11553 (hitbdry < 2)); 11554 } 11555 } // if (checksubfaces) 11556 flip22(&flipface, flipqueue); 11557 } 11558 } 11559 } // if (ori > 0.0) 11560 } // if (sign > 0.0) 11561 } 11562 } // !isdead(&qface->tt) 11563 } // while (!flipqueue->empty()) 11564 11565 flipcount = flip23s + flip32s + flip22s + flip44s - flipcount; 11566 if (b->verbose > 1) { 11567 printf(" %ld flips.\n", flipcount); 11568 } 11569 return flipcount; 11570 } 11571 11573 // // 11574 // undoflip() Undo the most recent flip sequence induced by flip(). // 11575 // // 11576 // 'lastflip' is the stack of recently flipped faces. Walks through the list // 11577 // of flips, in the reverse of the order in which they were done, and undoes // 11578 // them. // 11579 // // 11581 11582 void tetgenmesh::undoflip(badface *lastflip) 11583 { 11584 enum fliptype fc; 11585 11586 while (lastflip != (badface *) NULL) { 11587 // Get the right flipped face. 11588 findface(&lastflip->tt, lastflip->forg, lastflip->fdest, lastflip->fapex); 11589 fc = (enum fliptype) (int) lastflip->key; 11590 switch (fc) { 11591 case T23: 11592 // The reverse operation of T23 is T32. 11593 flip32(&lastflip->tt, NULL); 11594 break; 11595 case T32: 11596 // The reverse operation of T32 is T23. 11597 flip23(&lastflip->tt, NULL); 11598 break; 11599 case T22: 11600 case T44: 11601 // The reverse operation of T22 or T44 is again T22 or T44. 11602 flip22(&lastflip->tt, NULL); 11603 break; 11604 default: // To omit compile warnings. 11605 break; 11606 } 11607 // Go on and process the next transformation. 11608 lastflip = lastflip->previtem; 11609 } 11610 } 11611 11613 // // 11614 // flipsub() Flip non-Delaunay edges in a queue of (coplanar) subfaces. // 11615 // // 11616 // Assumpation: Current triangulation T contains non-Delaunay edges (after // 11617 // inserting a point or performing a flip). Non-Delaunay edges are queued in // 11618 // 'facequeue'. Returns the total number of flips done during this call. // 11619 // // 11621 11622 long tetgenmesh::flipsub(queue* flipqueue) 11623 { 11624 badface *qedge; 11625 face flipedge, symedge; 11626 face checkseg; 11627 point pa, pb, pc, pd; 11628 REAL vab[3], vac[3], vad[3]; 11629 REAL dot1, dot2, lac, lad; 11630 REAL sign, ori; 11631 int edgeflips; 11632 int i; 11633 11634 if (b->verbose > 1) { 11635 printf(" Start do edge queue: %ld edges.\n", flipqueue->len()); 11636 } 11637 11638 edgeflips = 0; 11639 11640 while (!flipqueue->empty()) { 11641 qedge = (badface *) flipqueue->pop(); 11642 flipedge = qedge->ss; 11643 if (flipedge.sh == dummysh) continue; 11644 if ((sorg(flipedge) != qedge->forg) || 11645 (sdest(flipedge) != qedge->fdest)) continue; 11646 sspivot(flipedge, checkseg); 11647 if (checkseg.sh != dummysh) continue; // Can't flip a subsegment. 11648 spivot(flipedge, symedge); 11649 if (symedge.sh == dummysh) continue; // Can't flip a hull edge. 11650 pa = sorg(flipedge); 11651 pb = sdest(flipedge); 11652 pc = sapex(flipedge); 11653 pd = sapex(symedge); 11654 // Choose the triangle abc or abd as the base depending on the angle1 11655 // (Vac, Vab) and angle2 (Vad, Vab). 11656 for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i]; 11657 for (i = 0; i < 3; i++) vac[i] = pc[i] - pa[i]; 11658 for (i = 0; i < 3; i++) vad[i] = pd[i] - pa[i]; 11659 dot1 = dot(vac, vab); 11660 dot2 = dot(vad, vab); 11661 dot1 *= dot1; 11662 dot2 *= dot2; 11663 lac = dot(vac, vac); 11664 lad = dot(vad, vad); 11665 if (lad * dot1 <= lac * dot2) { 11666 // angle1 is closer to 90 than angle2, choose abc (flipedge). 11667 abovepoint = facetabovepointarray[shellmark(flipedge)]; 11668 if (abovepoint == (point) NULL) { 11669 getfacetabovepoint(&flipedge); 11670 } 11671 sign = insphere(pa, pb, pc, abovepoint, pd); 11672 ori = orient3d(pa, pb, pc, abovepoint); 11673 } else { 11674 // angle2 is closer to 90 than angle1, choose abd (symedge). 11675 abovepoint = facetabovepointarray[shellmark(symedge)]; 11676 if (abovepoint == (point) NULL) { 11677 getfacetabovepoint(&symedge); 11678 } 11679 sign = insphere(pa, pb, pd, abovepoint, pc); 11680 ori = orient3d(pa, pb, pd, abovepoint); 11681 } 11682 // Correct the sign. 11683 sign = ori > 0.0 ? sign : -sign; 11684 if (sign > 0.0) { 11685 // Flip the non-Delaunay edge. 11686 flip22sub(&flipedge, flipqueue); 11687 edgeflips++; 11688 } 11689 } 11690 11691 if (b->verbose > 1) { 11692 printf(" Total %d flips.\n", edgeflips); 11693 } 11694 11695 return edgeflips; 11696 } 11697 11699 // // 11700 // removetetbypeeloff() Remove a boundary tet by peeling it off. // 11701 // // 11702 // 'striptet' (abcd) is on boundary and can be removed by stripping it off. // 11703 // Let abc and bad are the external boundary faces. // 11704 // // 11705 // To strip 'abcd' from the mesh is to detach its two interal faces (dca and // 11706 // cdb) from their adjoining tets together with a 2-to-2 flip to transform // 11707 // two subfaces (abc and bad) into another two (dca and cdb). // 11708 // // 11709 // In mesh optimization. It is possible that ab is a segment and abcd is a // 11710 // sliver on the hull. Strip abcd will also delete the segment ab. // 11711 // // 11713 11714 bool tetgenmesh::removetetbypeeloff(triface *striptet) 11715 { 11716 triface abcd, badc; 11717 triface dcacasing, cdbcasing; 11718 face abc, bad; 11719 face abseg; 11720 REAL ang; 11721 11722 abcd = *striptet; 11723 adjustedgering(abcd, CCW); 11724 // Get the casing tets at the internal sides. 11725 enextfnext(abcd, cdbcasing); 11726 enext2fnext(abcd, dcacasing); 11727 symself(cdbcasing); 11728 symself(dcacasing); 11729 // Do the neighboring tets exist? During optimization. It is possible 11730 // that the neighboring tets are already dead. 11731 if ((cdbcasing.tet == dummytet) || (dcacasing.tet == dummytet)) { 11732 // Do not strip this tet. 11733 return false; 11734 } 11735 11736 // Are there subfaces? 11737 if (checksubfaces) { 11738 // Get the external subfaces abc, bad. 11739 fnext(abcd, badc); 11740 esymself(badc); 11741 tspivot(abcd, abc); 11742 tspivot(badc, bad); 11743 if (abc.sh != dummysh) { 11744 assert(bad.sh != dummysh); 11745 findedge(&abc, org(abcd), dest(abcd)); 11746 findedge(&bad, org(badc), dest(badc)); 11747 // Is ab a segment? 11748 sspivot(abc, abseg); 11749 if (abseg.sh != dummysh) { 11750 // Does a segment allow to be removed? 11751 if ((b->optlevel > 3) && (b->nobisect == 0)) { 11752 // Only remove this segment if the dihedal angle at ab is between 11753 // [b->maxdihedral-9, 180] (deg). This avoids mistakely fliping 11754 // ab when it has actually no big dihedral angle while cd has. 11755 ang = facedihedral(org(abcd), dest(abcd), apex(abcd), oppo(abcd)); 11756 ang = ang * 180.0 / PI; 11757 if ((ang + 9.0) > b->maxdihedral) { 11758 if (b->verbose > 1) { 11759 printf(" Remove a segment during peeling.\n"); 11760 } 11761 face prevseg, nextseg; 11762 // It is only shared by abc and bad (abcd is a tet). 11763 ssdissolve(abc); 11764 ssdissolve(bad); 11765 abseg.shver = 0; 11766 senext(abseg, nextseg); 11767 spivotself(nextseg); 11768 if (nextseg.sh != dummysh) { 11769 ssdissolve(nextseg); 11770 } 11771 senext2(abseg, prevseg); 11772 spivotself(prevseg); 11773 if (prevseg.sh != dummysh) { 11774 ssdissolve(prevseg); 11775 } 11776 shellfacedealloc(subsegs, abseg.sh); 11777 optcount[1]++; 11778 } else { 11779 return false; 11780 } 11781 } else { 11782 return false; 11783 } 11784 } 11785 // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb. 11786 flip22sub(&abc, NULL); 11787 // The two internal faces become boundary faces. 11788 tsbond(cdbcasing, bad); 11789 tsbond(dcacasing, abc); 11790 } 11791 } 11792 11793 // Detach abcd from the two internal faces. 11794 dissolve(cdbcasing); 11795 dissolve(dcacasing); 11796 // Delete abcd. 11797 tetrahedrondealloc(abcd.tet); 11798 return true; 11799 } 11800 11802 // // 11803 // removeedgebyflip22() Remove an edge by a 2-to-2 (or 4-to-4) flip. // 11804 // // 11805 // 'abtetlist' contains n tets (n is 2 or 4) sharing edge ab, abtetlist[0] // 11806 // and abtetlist[1] are tets abec and abde, respectively (NOTE, both are in // 11807 // CW edge ring), where a, b, c, and d are coplanar. If n = 4, abtetlist[2] // 11808 // and abtetlist[3] are tets abfd and abcf, respectively. This routine uses // 11809 // flip22() to replace edge ab with cd, the surrounding tets are rotated. // 11810 // // 11811 // If 'key' != NULL. The old tets are replaced by the new tets only if the // 11812 // local mesh quality is improved. Current 'key' = cos(\theta), where \theta // 11813 // is the maximum dihedral angle in the old tets. // 11814 // // 11816 11817 bool tetgenmesh::removeedgebyflip22(REAL *key, int n, triface *abtetlist, 11818 queue *flipque) 11819 { 11820 point pa, pb, pc, pd, pe, pf; 11821 REAL cosmaxd, d1, d2, d3; 11822 bool doflip; 11823 11824 cosmaxd = 0.0; 11825 pf = apex(abtetlist[2]); 11826 doflip = true; 11827 adjustedgering(abtetlist[0], CW); 11828 pa = org(abtetlist[0]); 11829 pb = dest(abtetlist[0]); 11830 pe = apex(abtetlist[0]); 11831 pc = oppo(abtetlist[0]); 11832 pd = apex(abtetlist[1]); 11833 if (n == 4) { 11834 pf = apex(abtetlist[2]); 11835 } 11836 if (key && (*key > -1.0)) { 11837 tetalldihedral(pc, pd, pe, pa, NULL, &d1, NULL); 11838 tetalldihedral(pd, pc, pe, pb, NULL, &d2, NULL); 11839 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. 11840 if (n == 4) { 11841 tetalldihedral(pd, pc, pf, pa, NULL, &d1, NULL); 11842 tetalldihedral(pc, pd, pf, pb, NULL, &d2, NULL); 11843 d3 = d1 < d2 ? d1 : d2; // Choose the bigger angle. 11844 cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle. 11845 } 11846 doflip = (*key < cosmaxd); // Can local quality be improved? 11847 } 11848 11849 if (doflip) { 11850 flip22(&abtetlist[0], NULL); 11851 // Return the improved quality value. 11852 if (key) *key = cosmaxd; 11853 } 11854 11855 return doflip; 11856 } 11857 11859 // // 11860 // removefacebyflip23() Remove a face by a 2-to-3 flip. // 11861 // // 11862 // 'abctetlist' contains 2 tets sharing abc, which are [0]abcd and [1]bace. // 11863 // This routine forms three new tets that abc is not a face anymore. Save // 11864 // them in 'newtetlist': [0]edab, [1]edbc, and [2]edca. Note that the new // 11865 // tets may not valid if one of them get inverted. return false if so. // 11866 // // 11867 // If 'key' != NULL. The old tets are replaced by the new tets only if the // 11868 // local mesh quality is improved. Current 'key' = cos(\theta), where \theta // 11869 // is the maximum dihedral angle in the old tets. // 11870 // // 11871 // If the face is flipped, 'newtetlist' returns the three new tets. The two // 11872 // tets in 'abctetlist' are NOT deleted. The caller has the right to either // 11873 // delete them or reverse the operation. // 11874 // // 11876 11877 bool tetgenmesh::removefacebyflip23(REAL *key, triface *abctetlist, 11878 triface *newtetlist, queue *flipque) 11879 { 11880 triface edab, edbc, edca; // new configuration. 11881 triface newfront, oldfront, adjfront; 11882 face checksh; 11883 point pa, pb, pc, pd, pe; 11884 REAL ori, cosmaxd, d1, d2, d3; 11885 REAL attrib, volume; 11886 bool doflip; 11887 int i; 11888 11889 cosmaxd = 0.0; 11890 11891 adjustedgering(abctetlist[0], CCW); 11892 pa = org(abctetlist[0]); 11893 pb = dest(abctetlist[0]); 11894 pc = apex(abctetlist[0]); 11895 pd = oppo(abctetlist[0]); 11896 pe = oppo(abctetlist[1]); 11897 11898 // Check if the flip creates valid new tets. 11899 ori = orient3d(pe, pd, pa, pb); 11900 if (ori < 0.0) { 11901 ori = orient3d(pe, pd, pb, pc); 11902 if (ori < 0.0) { 11903 ori = orient3d(pe, pd, pc, pa); 11904 } 11905 } 11906 doflip = (ori < 0.0); // Can abc be flipped away? 11907 if (doflip && (key != (REAL *) NULL)) { 11908 if (*key > -1.0) { 11909 // Test if the new tets reduce the maximal dihedral angle. 11910 tetalldihedral(pe, pd, pa, pb, NULL, &d1, NULL); 11911 tetalldihedral(pe, pd, pb, pc, NULL, &d2, NULL); 11912 tetalldihedral(pe, pd, pc, pa, NULL, &d3, NULL); 11913 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. 11914 cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle. 11915 doflip = (*key < cosmaxd); // Can local quality be improved? 11916 } 11917 } 11918 11919 if (doflip) { 11920 // A valid (2-to-3) flip is found. 11921 flip23s++; 11922 // Create the new tets. 11923 maketetrahedron(&edab); 11924 setorg(edab, pe); 11925 setdest(edab, pd); 11926 setapex(edab, pa); 11927 setoppo(edab, pb); 11928 maketetrahedron(&edbc); 11929 setorg(edbc, pe); 11930 setdest(edbc, pd); 11931 setapex(edbc, pb); 11932 setoppo(edbc, pc); 11933 maketetrahedron(&edca); 11934 setorg(edca, pe); 11935 setdest(edca, pd); 11936 setapex(edca, pc); 11937 setoppo(edca, pa); 11938 // Transfer the element attributes. 11939 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 11940 attrib = elemattribute(abctetlist[0].tet, i); 11941 setelemattribute(edab.tet, i, attrib); 11942 setelemattribute(edbc.tet, i, attrib); 11943 setelemattribute(edca.tet, i, attrib); 11944 } 11945 // Transfer the volume constraints. 11946 if (b->varvolume && !b->refine) { 11947 volume = volumebound(abctetlist[0].tet); 11948 setvolumebound(edab.tet, volume); 11949 setvolumebound(edbc.tet, volume); 11950 setvolumebound(edca.tet, volume); 11951 } 11952 // Return two new tets. 11953 newtetlist[0] = edab; 11954 newtetlist[1] = edbc; 11955 newtetlist[2] = edca; 11956 // Glue the three new tets. 11957 for (i = 0; i < 3; i++) { 11958 fnext(newtetlist[i], newfront); 11959 bond(newfront, newtetlist[(i + 1) % 3]); 11960 } 11961 // Substitute the three new tets into the old cavity. 11962 for (i = 0; i < 3; i++) { 11963 fnext(abctetlist[0], oldfront); 11964 sym(oldfront, adjfront); // may be outside. 11965 enextfnext(newtetlist[i], newfront); 11966 bond(newfront, adjfront); 11967 if (checksubfaces) { 11968 tspivot(oldfront, checksh); 11969 if (checksh.sh != dummysh) { 11970 tsbond(newfront, checksh); 11971 } 11972 } 11973 if (flipque != (queue *) NULL) { 11974 enqueueflipface(newfront, flipque); 11975 } 11976 enextself(abctetlist[0]); 11977 } 11978 findedge(&(abctetlist[1]), pb, pa); 11979 for (i = 0; i < 3; i++) { 11980 fnext(abctetlist[1], oldfront); 11981 sym(oldfront, adjfront); // may be outside. 11982 enext2fnext(newtetlist[i], newfront); 11983 bond(newfront, adjfront); 11984 if (checksubfaces) { 11985 tspivot(oldfront, checksh); 11986 if (checksh.sh != dummysh) { 11987 tsbond(newfront, checksh); 11988 } 11989 } 11990 if (flipque != (queue *) NULL) { 11991 enqueueflipface(newfront, flipque); 11992 } 11993 enext2self(abctetlist[1]); 11994 } 11995 // Do not delete the old tets. 11996 // for (i = 0; i < 2; i++) { 11997 // tetrahedrondealloc(abctetlist[i].tet); 11998 // } 11999 // Return the improved quality value. 12000 if (key != (REAL *) NULL) *key = cosmaxd; 12001 return true; 12002 } 12003 12004 return false; 12005 } 12006 12008 // // 12009 // removeedgebyflip32() Remove an edge by a 3-to-2 flip. // 12010 // // 12011 // 'abtetlist' contains 3 tets sharing ab. Imaging that ab is perpendicular // 12012 // to the screen, where a lies in front of and b lies behind it. The 3 tets // 12013 // of the list are: [0]abce, [1]abdc, and [2]abed, respectively. // 12014 // // 12015 // This routine forms two new tets that ab is not an edge of them. Save them // 12016 // in 'newtetlist', [0]dcea, [1]cdeb. Note that the new tets may not valid // 12017 // if one of them get inverted. return false if so. // 12018 // // 12019 // If 'key' != NULL. The old tets are replaced by the new tets only if the // 12020 // local mesh quality is improved. Current 'key' = cos(\theta), where \theta // 12021 // is the maximum dihedral angle in the old tets. // 12022 // // 12023 // If the edge is flipped, 'newtetlist' returns the two new tets. The three // 12024 // tets in 'abtetlist' are NOT deleted. The caller has the right to either // 12025 // delete them or reverse the operation. // 12026 // // 12028 12029 bool tetgenmesh::removeedgebyflip32(REAL *key, triface *abtetlist, 12030 triface *newtetlist, queue *flipque) 12031 { 12032 triface dcea, cdeb; // new configuration. 12033 triface newfront, oldfront, adjfront; 12034 face checksh; 12035 point pa, pb, pc, pd, pe; 12036 REAL ori, cosmaxd, d1, d2; 12037 REAL attrib, volume; 12038 bool doflip; 12039 int i; 12040 12041 pa = org(abtetlist[0]); 12042 pb = dest(abtetlist[0]); 12043 pc = apex(abtetlist[0]); 12044 pd = apex(abtetlist[1]); 12045 pe = apex(abtetlist[2]); 12046 12047 ori = orient3d(pd, pc, pe, pa); 12048 if (ori < 0.0) { 12049 ori = orient3d(pc, pd, pe, pb); 12050 } 12051 doflip = (ori < 0.0); // Can ab be flipped away? 12052 12053 // Does the caller ensure a valid configuration? 12054 if (doflip && (key != (REAL *) NULL)) { 12055 if (*key > -1.0) { 12056 // Test if the new tets reduce the maximal dihedral angle. 12057 tetalldihedral(pd, pc, pe, pa, NULL, &d1, NULL); 12058 tetalldihedral(pc, pd, pe, pb, NULL, &d2, NULL); 12059 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. 12060 doflip = (*key < cosmaxd); // Can local quality be improved? 12061 // Return the key 12062 *key = cosmaxd; 12063 } 12064 } 12065 12066 if (doflip) { 12067 // Create the new tets. 12068 maketetrahedron(&dcea); 12069 setorg(dcea, pd); 12070 setdest(dcea, pc); 12071 setapex(dcea, pe); 12072 setoppo(dcea, pa); 12073 maketetrahedron(&cdeb); 12074 setorg(cdeb, pc); 12075 setdest(cdeb, pd); 12076 setapex(cdeb, pe); 12077 setoppo(cdeb, pb); 12078 // Transfer the element attributes. 12079 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 12080 attrib = elemattribute(abtetlist[0].tet, i); 12081 setelemattribute(dcea.tet, i, attrib); 12082 setelemattribute(cdeb.tet, i, attrib); 12083 } 12084 // Transfer the volume constraints. 12085 if (b->varvolume && !b->refine) { 12086 volume = volumebound(abtetlist[0].tet); 12087 setvolumebound(dcea.tet, volume); 12088 setvolumebound(cdeb.tet, volume); 12089 } 12090 // Return two new tets. 12091 newtetlist[0] = dcea; 12092 newtetlist[1] = cdeb; 12093 // Glue the two new tets. 12094 bond(dcea, cdeb); 12095 // Substitute the two new tets into the old three-tets cavity. 12096 for (i = 0; i < 3; i++) { 12097 fnext(dcea, newfront); // face dca, cea, eda. 12098 esym(abtetlist[(i + 1) % 3], oldfront); 12099 enextfnextself(oldfront); 12100 // Get the adjacent tet at the face (may be a dummytet). 12101 sym(oldfront, adjfront); 12102 bond(newfront, adjfront); 12103 if (checksubfaces) { 12104 tspivot(oldfront, checksh); 12105 if (checksh.sh != dummysh) { 12106 tsbond(newfront, checksh); 12107 } 12108 } 12109 if (flipque != (queue *) NULL) { 12110 enqueueflipface(newfront, flipque); 12111 } 12112 enext2self(dcea); 12113 } 12114 for (i = 0; i < 3; i++) { 12115 fnext(cdeb, newfront); // face cdb, deb, ecb. 12116 esym(abtetlist[(i + 1) % 3], oldfront); 12117 enext2fnextself(oldfront); 12118 // Get the adjacent tet at the face (may be a dummytet). 12119 sym(oldfront, adjfront); 12120 bond(newfront, adjfront); 12121 if (checksubfaces) { 12122 tspivot(oldfront, checksh); 12123 if (checksh.sh != dummysh) { 12124 tsbond(newfront, checksh); 12125 } 12126 } 12127 if (flipque != (queue *) NULL) { 12128 enqueueflipface(newfront, flipque); 12129 } 12130 enextself(cdeb); 12131 } 12132 // Do not delete the old tets. 12133 // for (i = 0; i < 3; i++) { 12134 // tetrahedrondealloc(abtetlist[i].tet); 12135 // } 12136 return true; 12137 } // if (doflip) 12138 12139 return false; 12140 } 12141 12143 // // 12144 // removeedgebytranNM() Remove an edge by transforming n-to-m tets. // 12145 // // 12146 // This routine attempts to remove a given edge (ab) by transforming the set // 12147 // T of tets surrounding ab into another set T' of tets. T and T' have the // 12148 // same outer faces and ab is not an edge of T' anymore. Let |T|=n, and |T'| // 12149 // =m, it is actually a n-to-m flip for n > 3. The relation between n and m // 12150 // depends on the method, ours is found below. // 12151 // // 12152 // 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular // 12153 // to the screen, where a lies in front of and b lies behind it. Let the // 12154 // projections of the n apexes onto screen in clockwise order are: p_0, ... // 12155 // p_n-1, respectively. The tets in the list are: [0]abp_0p_n-1,[1]abp_1p_0, // 12156 // ..., [n-1]abp_n-1p_n-2, respectively. // 12157 // // 12158 // The principle of the approach is: Recursively reduce the link of ab by // 12159 // using flip23 until only three faces remain, hence a flip32 can be applied // 12160 // to remove ab. For a given face a.b.p_0, check a flip23 can be applied on // 12161 // it, i.e, edge p_1.p_n-1 crosses it. NOTE*** We do the flip even p_1.p_n-1 // 12162 // intersects with a.b (they are coplanar). If so, a degenerate tet (a.b.p_1.// 12163 // p_n-1) is temporarily created, but it will be eventually removed by the // 12164 // final flip32. This relaxation splits a flip44 into flip23 + flip32. *NOTE // 12165 // Now suppose a.b.p_0 gets flipped, p_0 is not on the link of ab anymore. // 12166 // The link is then reduced (by 1). 2 of the 3 new tets, p_n-1.p_1.p_0.a and // 12167 // p_1.p_n-1.p_0.b, will be part of the new configuration. The left new tet,// 12168 // a.b.p_1.p_n-1, goes into the new link of ab. A recurrence can be applied. // 12169 // // 12170 // If 'e1' and 'e2' are not NULLs, they specify an wanted edge to appear in // 12171 // the new tet configuration. In such case, only do flip23 if edge e1<->e2 // 12172 // can be recovered. It is used in removeedgebycombNM(). // 12173 // // 12174 // If ab gets removed. 'newtetlist' contains m new tets. By using the above // 12175 // approach, the pairs (n, m) can be easily enumerated. For example, (3, 2),// 12176 // (4, 4), (5, 6), (6, 8), (7, 10), (8, 12), (9, 14), (10, 16), and so on. // 12177 // It is easy to deduce, that m = (n - 2) * 2, when n >= 3. The n tets in // 12178 // 'abtetlist' are NOT deleted in this routine. The caller has the right to // 12179 // either delete them or reverse this operation. // 12180 // // 12182 12183 bool tetgenmesh::removeedgebytranNM(REAL *key, int n, triface *abtetlist, 12184 triface *newtetlist, point e1, point e2, queue *flipque) 12185 { 12186 triface tmpabtetlist[9]; // Temporary max 9 tets configuration. 12187 triface newfront, oldfront, adjfront; 12188 face checksh; 12189 point pa, pb, p[10]; 12190 REAL ori, cosmaxd, d1, d2; 12191 REAL tmpkey; 12192 REAL attrib, volume; 12193 bool doflip, copflag, success; 12194 int i, j, k; 12195 12196 cosmaxd = 0.0; 12197 // Maximum 10 tets. 12198 assert(n <= 10); 12199 // Two points a and b are fixed. 12200 pa = org(abtetlist[0]); 12201 pb = dest(abtetlist[0]); 12202 // The points p_0, p_1, ..., p_n-1 are permuted in each new configuration. 12203 // These permutations can be easily done in the following loop. 12204 // Loop through all the possible new tets configurations. Stop on finding 12205 // a valid new tet configuration which also immproves the quality value. 12206 for (i = 0; i < n; i++) { 12207 // Get other n points for the current configuration. 12208 for (j = 0; j < n; j++) { 12209 p[j] = apex(abtetlist[(i + j) % n]); 12210 } 12211 // Is there a wanted edge? 12212 if ((e1 != (point) NULL) && (e2 != (point) NULL)) { 12213 // Yes. Skip this face if p[1]<->p[n-1] is not the edge. 12214 if (!(((p[1] == e1) && (p[n - 1] == e2)) || 12215 ((p[1] == e2) && (p[n - 1] == e1)))) continue; 12216 } 12217 // Test if face a.b.p_0 can be flipped (by flip23), ie, to check if the 12218 // edge p_n-1.p_1 crosses face a.b.p_0 properly. 12219 // Note. It is possible that face a.b.p_0 has type flip44, ie, a,b,p_1, 12220 // and p_n-1 are coplanar. A trick is to split the flip44 into two 12221 // steps: frist a flip23, then a flip32. The first step creates a 12222 // degenerate tet (vol=0) which will be removed by the second flip. 12223 ori = orient3d(pa, pb, p[1], p[n - 1]); 12224 copflag = (ori == 0.0); // Are they coplanar? 12225 if (ori >= 0.0) { 12226 // Accept the coplanar case which supports flip44. 12227 ori = orient3d(pb, p[0], p[1], p[n - 1]); 12228 if (ori > 0.0) { 12229 ori = orient3d(p[0], pa, p[1], p[n - 1]); 12230 } 12231 } 12232 // Is face abc flipable? 12233 if (ori > 0.0) { 12234 // A valid (2-to-3) flip (or 4-to-4 flip) is found. 12235 copflag ? flip44s++ : flip23s++; 12236 doflip = true; 12237 if (key != (REAL *) NULL) { 12238 if (*key > -1.0) { 12239 // Test if the new tets reduce the maximal dihedral angle. Only 2 12240 // tets, p_n-1.p_1.p_0.a and p_1.p_n-1.p_0.b, need to be tested 12241 // The left one a.b.p_n-1.p_1 goes into the new link of ab. 12242 tetalldihedral(p[n - 1], p[1], p[0], pa, NULL, &d1, NULL); 12243 tetalldihedral(p[1], p[n - 1], p[0], pb, NULL, &d2, NULL); 12244 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. 12245 doflip = *key < cosmaxd; // Can the local quality be improved? 12246 } 12247 } 12248 if (doflip) { 12249 tmpkey = key != NULL ? *key : -1.0; 12250 // Create the two new tets. 12251 maketetrahedron(&(newtetlist[0])); 12252 setorg(newtetlist[0], p[n - 1]); 12253 setdest(newtetlist[0], p[1]); 12254 setapex(newtetlist[0], p[0]); 12255 setoppo(newtetlist[0], pa); 12256 maketetrahedron(&(newtetlist[1])); 12257 setorg(newtetlist[1], p[1]); 12258 setdest(newtetlist[1], p[n - 1]); 12259 setapex(newtetlist[1], p[0]); 12260 setoppo(newtetlist[1], pb); 12261 // Create the n - 1 temporary new tets (the new Star(ab)). 12262 maketetrahedron(&(tmpabtetlist[0])); 12263 setorg(tmpabtetlist[0], pa); 12264 setdest(tmpabtetlist[0], pb); 12265 setapex(tmpabtetlist[0], p[n - 1]); 12266 setoppo(tmpabtetlist[0], p[1]); 12267 for (j = 1; j < n - 1; j++) { 12268 maketetrahedron(&(tmpabtetlist[j])); 12269 setorg(tmpabtetlist[j], pa); 12270 setdest(tmpabtetlist[j], pb); 12271 setapex(tmpabtetlist[j], p[j]); 12272 setoppo(tmpabtetlist[j], p[j + 1]); 12273 } 12274 // Transfer the element attributes. 12275 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 12276 attrib = elemattribute(abtetlist[0].tet, j); 12277 setelemattribute(newtetlist[0].tet, j, attrib); 12278 setelemattribute(newtetlist[1].tet, j, attrib); 12279 for (k = 0; k < n - 1; k++) { 12280 setelemattribute(tmpabtetlist[k].tet, j, attrib); 12281 } 12282 } 12283 // Transfer the volume constraints. 12284 if (b->varvolume && !b->refine) { 12285 volume = volumebound(abtetlist[0].tet); 12286 setvolumebound(newtetlist[0].tet, volume); 12287 setvolumebound(newtetlist[1].tet, volume); 12288 for (k = 0; k < n - 1; k++) { 12289 setvolumebound(tmpabtetlist[k].tet, volume); 12290 } 12291 } 12292 // Glue the new tets at their internal faces: 2 + (n - 1). 12293 bond(newtetlist[0], newtetlist[1]); // p_n-1.p_1.p_0. 12294 fnext(newtetlist[0], newfront); 12295 enext2fnext(tmpabtetlist[0], adjfront); 12296 bond(newfront, adjfront); // p_n-1.p_1.a. 12297 fnext(newtetlist[1], newfront); 12298 enextfnext(tmpabtetlist[0], adjfront); 12299 bond(newfront, adjfront); // p_n-1.p_1.b. 12300 // Glue n - 1 internal faces around ab. 12301 for (j = 0; j < n - 1; j++) { 12302 fnext(tmpabtetlist[j], newfront); 12303 bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1 12304 } 12305 // Substitute the old tets with the new tets by connecting the new 12306 // tets to the adjacent tets in the mesh. There are n * 2 (outer) 12307 // faces of the new tets need to be operated. 12308 // Note, after the substitution, the old tets still have pointers to 12309 // their adjacent tets in the mesh. These pointers can be re-used 12310 // to inverse the substitution. 12311 for (j = 0; j < n; j++) { 12312 // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0). 12313 oldfront = abtetlist[(i + j) % n]; 12314 esymself(oldfront); 12315 enextfnextself(oldfront); 12316 // Get an adjacent tet at face: [0]a.p_0.p_n-1 or [j]a.p_j.p_j-1. 12317 sym(oldfront, adjfront); // adjfront may be dummy. 12318 // Get the corresponding face from the new tets. 12319 if (j == 0) { 12320 enext2fnext(newtetlist[0], newfront); // a.p_0.n_n-1 12321 } else if (j == 1) { 12322 enextfnext(newtetlist[0], newfront); // a.p_1.p_0 12323 } else { // j >= 2. 12324 enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1 12325 } 12326 bond(newfront, adjfront); 12327 if (checksubfaces) { 12328 tspivot(oldfront, checksh); 12329 if (checksh.sh != dummysh) { 12330 tsbond(newfront, checksh); 12331 } 12332 } 12333 if (flipque != (queue *) NULL) { 12334 // Only queue the faces of the two new tets. 12335 if (j < 2) enqueueflipface(newfront, flipque); 12336 } 12337 } 12338 for (j = 0; j < n; j++) { 12339 // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0). 12340 oldfront = abtetlist[(i + j) % n]; 12341 esymself(oldfront); 12342 enext2fnextself(oldfront); 12343 // Get an adjacent tet at face: [0]b.p_0.p_n-1 or [j]b.p_j.p_j-1. 12344 sym(oldfront, adjfront); // adjfront may be dummy. 12345 // Get the corresponding face from the new tets. 12346 if (j == 0) { 12347 enextfnext(newtetlist[1], newfront); // b.p_0.n_n-1 12348 } else if (j == 1) { 12349 enext2fnext(newtetlist[1], newfront); // b.p_1.p_0 12350 } else { // j >= 2. 12351 enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1 12352 } 12353 bond(newfront, adjfront); 12354 if (checksubfaces) { 12355 tspivot(oldfront, checksh); 12356 if (checksh.sh != dummysh) { 12357 tsbond(newfront, checksh); 12358 } 12359 } 12360 if (flipque != (queue *) NULL) { 12361 // Only queue the faces of the two new tets. 12362 if (j < 2) enqueueflipface(newfront, flipque); 12363 } 12364 } 12365 // Adjust the faces in the temporary new tets at ab for recursively 12366 // processing on the n-1 tets.(See the description at beginning) 12367 for (j = 0; j < n - 1; j++) { 12368 fnextself(tmpabtetlist[j]); 12369 } 12370 if (n > 4) { 12371 success = removeedgebytranNM(&tmpkey, n-1, tmpabtetlist, 12372 &(newtetlist[2]), NULL, NULL, flipque); 12373 } else { // assert(n == 4); 12374 success = removeedgebyflip32(&tmpkey, tmpabtetlist, 12375 &(newtetlist[2]), flipque); 12376 } 12377 // No matter it was success or not, delete the temporary tets. 12378 for (j = 0; j < n - 1; j++) { 12379 tetrahedrondealloc(tmpabtetlist[j].tet); 12380 } 12381 if (success) { 12382 // The new configuration is good. 12383 // Do not delete the old tets. 12384 // for (j = 0; j < n; j++) { 12385 // tetrahedrondealloc(abtetlist[j].tet); 12386 // } 12387 // Save the minimal improved quality value. 12388 if (key != (REAL *) NULL) { 12389 *key = (tmpkey < cosmaxd ? tmpkey : cosmaxd); 12390 } 12391 return true; 12392 } else { 12393 // The new configuration is bad, substitue back the old tets. 12394 for (j = 0; j < n; j++) { 12395 oldfront = abtetlist[(i + j) % n]; 12396 esymself(oldfront); 12397 enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1. 12398 sym(oldfront, adjfront); // adjfront may be dummy. 12399 bond(oldfront, adjfront); 12400 if (checksubfaces) { 12401 tspivot(oldfront, checksh); 12402 if (checksh.sh != dummysh) { 12403 tsbond(oldfront, checksh); 12404 } 12405 } 12406 } 12407 for (j = 0; j < n; j++) { 12408 oldfront = abtetlist[(i + j) % n]; 12409 esymself(oldfront); 12410 enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1. 12411 sym(oldfront, adjfront); // adjfront may be dummy 12412 bond(oldfront, adjfront); 12413 if (checksubfaces) { 12414 tspivot(oldfront, checksh); 12415 if (checksh.sh != dummysh) { 12416 tsbond(oldfront, checksh); 12417 } 12418 } 12419 } 12420 // Delete the new tets. 12421 tetrahedrondealloc(newtetlist[0].tet); 12422 tetrahedrondealloc(newtetlist[1].tet); 12423 // If tmpkey has been modified, then the failure was not due to 12424 // unflipable configuration, but the non-improvement. 12425 if (key && (tmpkey < *key)) { 12426 *key = tmpkey; 12427 return false; 12428 } 12429 } // if (success) 12430 } // if (doflip) 12431 } // if (ori > 0.0) 12432 } // for (i = 0; i < n; i++) 12433 12434 return false; 12435 } 12436 12438 // // 12439 // removeedgebycombNM() Remove an edge by combining two flipNMs. // 12440 // // 12441 // Given a set T of tets surrounding edge ab. The premise is that ab can not // 12442 // be removed by a flipNM. This routine attempts to remove ab by two flipNMs,// 12443 // i.e., first find and flip an edge af (or bf) by flipNM, then flip ab by // 12444 // flipNM. If it succeeds, two sets T(ab) and T(af) of tets are replaced by // 12445 // a new set T' and both ab and af are not edges in T' anymore. // 12446 // // 12447 // 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular // 12448 // to the screen, such that a lies in front of and b lies behind it. Let the // 12449 // projections of the n apexes on the screen in clockwise order are: p_0,...,// 12450 // p_n-1, respectively. So the list of tets are: [0]abp_0p_n-1, [1]abp_1p_0, // 12451 // ..., [n-1]abp_n-1p_n-2, respectively. // 12452 // // 12453 // The principle of the approach is: for a face a.b.p_0, check if edge b.p_0 // 12454 // is of type N32 (or N44). If it is, then try to do a flipNM on it. If the // 12455 // flip is successful, then try to do another flipNM on a.b. If one of the // 12456 // two flipNMs fails, restore the old tets as they have never been flipped. // 12457 // Then try the next face a.b.p_1. The process can be looped for all faces // 12458 // having ab. Stop if ab is removed or all faces have been visited. Note in // 12459 // the above description only b.p_0 is considered, a.p_0 is done by swapping // 12460 // the position of a and b. // 12461 // // 12462 // Similar operations have been described in [Joe,1995]. My approach checks // 12463 // more cases for finding flips than Joe's. For instance, the cases (1)-(7) // 12464 // of Joe only consider abf for finding a flip (T23/T32). My approach looks // 12465 // all faces at ab for finding flips. Moreover, the flipNM can flip an edge // 12466 // whose star may have more than 3 tets while Joe's only works on 3-tet case.// 12467 // // 12468 // If ab is removed, 'newtetlist' contains the new tets. Two sets 'abtetlist'// 12469 // (n tets) and 'bftetlist' (n1 tets) have been replaced. The number of new // 12470 // tets can be calculated by follows: the 1st flip transforms n1 tets into // 12471 // (n1 - 2) * 2 new tets, however,one of the new tets goes into the new link // 12472 // of ab, i.e., the reduced tet number in Star(ab) is n - 1; the 2nd flip // 12473 // transforms n - 1 tets into (n - 3) * 2 new tets. Hence the number of new // 12474 // tets are: m = ((n1 - 2) * 2 - 1) + (n - 3) * 2. The old tets are NOT del-// 12475 // eted. The caller has the right to delete them or reverse the operation. // 12476 // // 12478 12479 bool tetgenmesh::removeedgebycombNM(REAL *key, int n, triface *abtetlist, 12480 int *n1, triface *bftetlist, triface *newtetlist, queue *flipque) 12481 { 12482 triface tmpabtetlist[11]; 12483 triface newfront, oldfront, adjfront; 12484 face checksh; 12485 point pa, pb, p[10]; 12486 REAL ori, tmpkey, tmpkey2; 12487 REAL attrib, volume; 12488 bool doflip, success; 12489 int twice, count; 12490 int i, j, k, m; 12491 12492 // Maximal 10 tets in Star(ab). 12493 assert(n <= 10); 12494 12495 // Do the following procedure twice, one for flipping edge b.p_0 and the 12496 // other for p_0.a which is symmetric to the first. 12497 twice = 0; 12498 do { 12499 // Two points a and b are fixed. 12500 pa = org(abtetlist[0]); 12501 pb = dest(abtetlist[0]); 12502 // The points p_0, ..., p_n-1 are permuted in the following loop. 12503 for (i = 0; i < n; i++) { 12504 // Get the n points for the current configuration. 12505 for (j = 0; j < n; j++) { 12506 p[j] = apex(abtetlist[(i + j) % n]); 12507 } 12508 // Check if b.p_0 is of type N32 or N44. 12509 ori = orient3d(pb, p[0], p[1], p[n - 1]); 12510 if ((ori > 0) && (key != (REAL *) NULL)) { 12511 // b.p_0 is not N32. However, it is possible that the tet b.p_0.p_1. 12512 // p_n-1 has worse quality value than the key. In such case, also 12513 // try to flip b.p_0. 12514 tetalldihedral(pb, p[0], p[n - 1], p[1], NULL, &tmpkey, NULL); 12515 if (tmpkey < *key) ori = 0.0; 12516 } 12517 if (ori <= 0.0) { 12518 // b.p_0 is either N32 or N44. Try the 1st flipNM. 12519 bftetlist[0] = abtetlist[i]; 12520 enextself(bftetlist[0]);// go to edge b.p_0. 12521 adjustedgering(bftetlist[0], CW); // edge p_0.b. 12522 assert(apex(bftetlist[0]) == pa); 12523 // Form Star(b.p_0). 12524 doflip = true; 12525 *n1 = 0; 12526 do { 12527 // Is the list full? 12528 if (*n1 == 10) break; 12529 if (checksubfaces) { 12530 // Stop if a subface appears. 12531 tspivot(bftetlist[*n1], checksh); 12532 if (checksh.sh != dummysh) { 12533 doflip = false; break; 12534 } 12535 } 12536 // Get the next tet at p_0.b. 12537 fnext(bftetlist[*n1], bftetlist[(*n1) + 1]); 12538 (*n1)++; 12539 } while (apex(bftetlist[*n1]) != pa); 12540 // 2 <= n1 <= 10. 12541 if (doflip) { 12542 success = false; 12543 tmpkey = -1.0; // = acos(pi). 12544 if (key != (REAL *) NULL) tmpkey = *key; 12545 m = 0; 12546 if (*n1 == 3) { 12547 // Three tets case. Try flip32. 12548 success = removeedgebyflip32(&tmpkey,bftetlist,newtetlist,flipque); 12549 m = 2; 12550 } else if ((*n1 > 3) && (*n1 < 7)) { 12551 // Four or more tets case. Try flipNM. 12552 success = removeedgebytranNM(&tmpkey, *n1, bftetlist, newtetlist, 12553 p[1], p[n - 1], flipque); 12554 // If success, the number of new tets. 12555 m = ((*n1) - 2) * 2; 12556 } else { 12557 if (b->verbose > 1) { 12558 printf(" !! Unhandled case: n1 = %d.\n", *n1); 12559 } 12560 } 12561 if (success) { 12562 // b.p_0 is flipped. The link of ab is reduced (by 1), i.e., p_0 12563 // is not on the link of ab. Two old tets a.b.p_0.p_n-1 and 12564 // a.b.p_1.p_0 have been removed from the Star(ab) and one new 12565 // tet t = a.b.p_1.p_n-1 belongs to Star(ab). 12566 // Find t in the 'newtetlist' and remove it from the list. 12567 setpointmark(pa, -pointmark(pa) - 1); 12568 setpointmark(pb, -pointmark(pb) - 1); 12569 assert(m > 0); 12570 for (j = 0; j < m; j++) { 12571 tmpabtetlist[0] = newtetlist[j]; 12572 // Does it has ab? 12573 count = 0; 12574 for (k = 0; k < 4; k++) { 12575 if (pointmark((point)(tmpabtetlist[0].tet[4+k])) < 0) count++; 12576 } 12577 if (count == 2) { 12578 // It is. Adjust t to be the edge ab. 12579 for (tmpabtetlist[0].loc = 0; tmpabtetlist[0].loc < 4; 12580 tmpabtetlist[0].loc++) { 12581 if ((oppo(tmpabtetlist[0]) != pa) && 12582 (oppo(tmpabtetlist[0]) != pb)) break; 12583 } 12584 // The face of t must contain ab. 12585 assert(tmpabtetlist[0].loc < 4); 12586 findedge(&(tmpabtetlist[0]), pa, pb); 12587 break; 12588 } 12589 } 12590 assert(j < m); // The tet must exist. 12591 // Remove t from list. Fill t's position by the last tet. 12592 newtetlist[j] = newtetlist[m - 1]; 12593 setpointmark(pa, -(pointmark(pa) + 1)); 12594 setpointmark(pb, -(pointmark(pb) + 1)); 12595 // Create the temporary Star(ab) for the next flipNM. 12596 adjustedgering(tmpabtetlist[0], CCW); 12597 if (org(tmpabtetlist[0]) != pa) { 12598 fnextself(tmpabtetlist[0]); 12599 esymself(tmpabtetlist[0]); 12600 } 12601 #ifdef SELF_CHECK 12602 // Make sure current edge is a->b. 12603 assert(org(tmpabtetlist[0]) == pa); 12604 assert(dest(tmpabtetlist[0]) == pb); 12605 assert(apex(tmpabtetlist[0]) == p[n - 1]); 12606 assert(oppo(tmpabtetlist[0]) == p[1]); 12607 #endif // SELF_CHECK 12608 // There are n - 2 left temporary tets. 12609 for (j = 1; j < n - 1; j++) { 12610 maketetrahedron(&(tmpabtetlist[j])); 12611 setorg(tmpabtetlist[j], pa); 12612 setdest(tmpabtetlist[j], pb); 12613 setapex(tmpabtetlist[j], p[j]); 12614 setoppo(tmpabtetlist[j], p[j + 1]); 12615 } 12616 // Transfer the element attributes. 12617 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 12618 attrib = elemattribute(abtetlist[0].tet, j); 12619 for (k = 0; k < n - 1; k++) { 12620 setelemattribute(tmpabtetlist[k].tet, j, attrib); 12621 } 12622 } 12623 // Transfer the volume constraints. 12624 if (b->varvolume && !b->refine) { 12625 volume = volumebound(abtetlist[0].tet); 12626 for (k = 0; k < n - 1; k++) { 12627 setvolumebound(tmpabtetlist[k].tet, volume); 12628 } 12629 } 12630 // Glue n - 1 internal faces of Star(ab). 12631 for (j = 0; j < n - 1; j++) { 12632 fnext(tmpabtetlist[j], newfront); 12633 bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1 12634 } 12635 // Substitute the old tets with the new tets by connecting the 12636 // new tets to the adjacent tets in the mesh. There are (n-2) 12637 // * 2 (outer) faces of the new tets need to be operated. 12638 // Note that the old tets still have the pointers to their 12639 // adjacent tets in the mesh. These pointers can be re-used 12640 // to inverse the substitution. 12641 for (j = 2; j < n; j++) { 12642 // Get an old tet: [j]a.b.p_j.p_j-1, (j > 1). 12643 oldfront = abtetlist[(i + j) % n]; 12644 esymself(oldfront); 12645 enextfnextself(oldfront); 12646 // Get an adjacent tet at face: [j]a.p_j.p_j-1. 12647 sym(oldfront, adjfront); // adjfront may be dummy. 12648 // Get the corresponding face from the new tets. 12649 // j >= 2. 12650 enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1 12651 bond(newfront, adjfront); 12652 if (checksubfaces) { 12653 tspivot(oldfront, checksh); 12654 if (checksh.sh != dummysh) { 12655 tsbond(newfront, checksh); 12656 } 12657 } 12658 } 12659 for (j = 2; j < n; j++) { 12660 // Get an old tet: [j]a.b.p_j.p_j-1, (j > 2). 12661 oldfront = abtetlist[(i + j) % n]; 12662 esymself(oldfront); 12663 enext2fnextself(oldfront); 12664 // Get an adjacent tet at face: [j]b.p_j.p_j-1. 12665 sym(oldfront, adjfront); // adjfront may be dummy. 12666 // Get the corresponding face from the new tets. 12667 // j >= 2. 12668 enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1 12669 bond(newfront, adjfront); 12670 if (checksubfaces) { 12671 tspivot(oldfront, checksh); 12672 if (checksh.sh != dummysh) { 12673 tsbond(newfront, checksh); 12674 } 12675 } 12676 } 12677 // Adjust the faces in the temporary new tets at ab for 12678 // recursively processing on the n-1 tets. 12679 for (j = 0; j < n - 1; j++) { 12680 fnextself(tmpabtetlist[j]); 12681 } 12682 tmpkey2 = -1; 12683 if (key) tmpkey2 = *key; 12684 if ((n - 1) == 3) { 12685 success = removeedgebyflip32(&tmpkey2, tmpabtetlist, 12686 &(newtetlist[m - 1]), flipque); 12687 } else { // assert((n - 1) >= 4); 12688 success = removeedgebytranNM(&tmpkey2, n - 1, tmpabtetlist, 12689 &(newtetlist[m - 1]), NULL, NULL, flipque); 12690 } 12691 // No matter it was success or not, delete the temporary tets. 12692 for (j = 0; j < n - 1; j++) { 12693 tetrahedrondealloc(tmpabtetlist[j].tet); 12694 } 12695 if (success) { 12696 // The new configuration is good. 12697 // Do not delete the old tets. 12698 // for (j = 0; j < n; j++) { 12699 // tetrahedrondealloc(abtetlist[j].tet); 12700 // } 12701 // Return the bigger dihedral in the two sets of new tets. 12702 if (key != (REAL *) NULL) { 12703 *key = tmpkey2 < tmpkey ? tmpkey2 : tmpkey; 12704 } 12705 return true; 12706 } else { 12707 // The new configuration is bad, substitue back the old tets. 12708 for (j = 0; j < n; j++) { 12709 oldfront = abtetlist[(i + j) % n]; 12710 esymself(oldfront); 12711 enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1. 12712 sym(oldfront, adjfront); // adjfront may be dummy. 12713 bond(oldfront, adjfront); 12714 if (checksubfaces) { 12715 tspivot(oldfront, checksh); 12716 if (checksh.sh != dummysh) { 12717 tsbond(oldfront, checksh); 12718 } 12719 } 12720 } 12721 for (j = 0; j < n; j++) { 12722 oldfront = abtetlist[(i + j) % n]; 12723 esymself(oldfront); 12724 enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1. 12725 sym(oldfront, adjfront); // adjfront may be dummy 12726 bond(oldfront, adjfront); 12727 if (checksubfaces) { 12728 tspivot(oldfront, checksh); 12729 if (checksh.sh != dummysh) { 12730 tsbond(oldfront, checksh); 12731 } 12732 } 12733 } 12734 // Substitute back the old tets of the first flip. 12735 for (j = 0; j < *n1; j++) { 12736 oldfront = bftetlist[j]; 12737 esymself(oldfront); 12738 enextfnextself(oldfront); 12739 sym(oldfront, adjfront); // adjfront may be dummy. 12740 bond(oldfront, adjfront); 12741 if (checksubfaces) { 12742 tspivot(oldfront, checksh); 12743 if (checksh.sh != dummysh) { 12744 tsbond(oldfront, checksh); 12745 } 12746 } 12747 } 12748 for (j = 0; j < *n1; j++) { 12749 oldfront = bftetlist[j]; 12750 esymself(oldfront); 12751 enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1. 12752 sym(oldfront, adjfront); // adjfront may be dummy 12753 bond(oldfront, adjfront); 12754 if (checksubfaces) { 12755 tspivot(oldfront, checksh); 12756 if (checksh.sh != dummysh) { 12757 tsbond(oldfront, checksh); 12758 } 12759 } 12760 } 12761 // Delete the new tets of the first flip. Note that one new 12762 // tet has already been removed from the list. 12763 for (j = 0; j < m - 1; j++) { 12764 tetrahedrondealloc(newtetlist[j].tet); 12765 } 12766 } // if (success) 12767 } // if (success) 12768 } // if (doflip) 12769 } // if (ori <= 0.0) 12770 } // for (i = 0; i < n; i++) 12771 // Inverse a and b and the tets configuration. 12772 for (i = 0; i < n; i++) newtetlist[i] = abtetlist[i]; 12773 for (i = 0; i < n; i++) { 12774 oldfront = newtetlist[n - i - 1]; 12775 esymself(oldfront); 12776 fnextself(oldfront); 12777 abtetlist[i] = oldfront; 12778 } 12779 twice++; 12780 } while (twice < 2); 12781 12782 return false; 12783 } 12784 12786 // // 12787 // splittetrahedron() Insert a point into a tetrahedron, split it into // 12788 // four tetrahedra. // 12789 // // 12790 // The tetrahedron is given by 'splittet'. Let it is abcd. The inserting // 12791 // point 'newpoint' v should lie strictly inside abcd. // 12792 // // 12793 // Splitting a tetrahedron is to shrink abcd to abcv, and create three new // 12794 // tetrahedra badv, cbdv, and acdv. // 12795 // // 12796 // On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it // 12797 // contains all possibly non-locally Delaunay faces. // 12798 // // 12800 12801 void tetgenmesh::splittetrahedron(point newpoint, triface* splittet, 12802 queue* flipqueue) 12803 { 12804 triface oldabd, oldbcd, oldcad; // Old configuration. 12805 triface abdcasing, bcdcasing, cadcasing; 12806 face abdsh, bcdsh, cadsh; 12807 triface abcv, badv, cbdv, acdv; // New configuration. 12808 triface worktet; 12809 face abseg, bcseg, caseg; 12810 face adseg, bdseg, cdseg; 12811 point pa, pb, pc, pd; 12812 REAL attrib, volume; 12813 int i; 12814 12815 abcv = *splittet; 12816 abcv.ver = 0; 12817 // Set the changed vertices and new tetrahedron. 12818 pa = org(abcv); 12819 pb = dest(abcv); 12820 pc = apex(abcv); 12821 pd = oppo(abcv); 12822 12823 if (b->verbose > 1) { 12824 printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n", 12825 pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc), 12826 pointmark(pd)); 12827 } 12828 12829 fnext(abcv, oldabd); 12830 enextfnext(abcv, oldbcd); 12831 enext2fnext(abcv, oldcad); 12832 sym(oldabd, abdcasing); 12833 sym(oldbcd, bcdcasing); 12834 sym(oldcad, cadcasing); 12835 maketetrahedron(&badv); 12836 maketetrahedron(&cbdv); 12837 maketetrahedron(&acdv); 12838 12839 // Set 'badv' vertices. 12840 setorg (badv, pb); 12841 setdest(badv, pa); 12842 setapex(badv, pd); 12843 setoppo(badv, newpoint); 12844 // Set 'cbdv' vertices. 12845 setorg (cbdv, pc); 12846 setdest(cbdv, pb); 12847 setapex(cbdv, pd); 12848 setoppo(cbdv, newpoint); 12849 // Set 'acdv' vertices. 12850 setorg (acdv, pa); 12851 setdest(acdv, pc); 12852 setapex(acdv, pd); 12853 setoppo(acdv, newpoint); 12854 // Set 'abcv' vertices 12855 setoppo(abcv, newpoint); 12856 12857 // Set the element attributes of the new tetrahedra. 12858 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 12859 attrib = elemattribute(abcv.tet, i); 12860 setelemattribute(badv.tet, i, attrib); 12861 setelemattribute(cbdv.tet, i, attrib); 12862 setelemattribute(acdv.tet, i, attrib); 12863 } 12864 // Set the volume constraint of the new tetrahedra. 12865 if (b->varvolume) { 12866 volume = volumebound(abcv.tet); 12867 setvolumebound(badv.tet, volume); 12868 setvolumebound(cbdv.tet, volume); 12869 setvolumebound(acdv.tet, volume); 12870 } 12871 12872 // Bond the new triangles to the surrounding tetrahedron. 12873 bond(badv, abdcasing); 12874 bond(cbdv, bcdcasing); 12875 bond(acdv, cadcasing); 12876 // There may exist subfaces need to be bonded to the new tetrahedra. 12877 if (checksubfaces) { 12878 tspivot(oldabd, abdsh); 12879 if (abdsh.sh != dummysh) { 12880 tsdissolve(oldabd); 12881 tsbond(badv, abdsh); 12882 } 12883 tspivot(oldbcd, bcdsh); 12884 if (bcdsh.sh != dummysh) { 12885 tsdissolve(oldbcd); 12886 tsbond(cbdv, bcdsh); 12887 } 12888 tspivot(oldcad, cadsh); 12889 if (cadsh.sh != dummysh) { 12890 tsdissolve(oldcad); 12891 tsbond(acdv, cadsh); 12892 } 12893 } else if (checksubsegs) { 12894 tsspivot1(abcv, abseg); 12895 if (abseg.sh != dummysh) { 12896 tssbond1(badv, abseg); 12897 } 12898 enext(abcv, worktet); 12899 tsspivot1(worktet, bcseg); 12900 if (bcseg.sh != dummysh) { 12901 tssbond1(cbdv, bcseg); 12902 } 12903 enext2(abcv, worktet); 12904 tsspivot1(worktet, caseg); 12905 if (caseg.sh != dummysh) { 12906 tssbond1(acdv, caseg); 12907 } 12908 fnext(abcv, worktet); 12909 enext2self(worktet); 12910 tsspivot1(worktet, adseg); 12911 if (adseg.sh != dummysh) { 12912 tssdissolve1(worktet); 12913 enext(badv, worktet); 12914 tssbond1(worktet, adseg); 12915 enext2(acdv, worktet); 12916 tssbond1(worktet, adseg); 12917 } 12918 enextfnext(abcv, worktet); 12919 enext2self(worktet); 12920 tsspivot1(worktet, bdseg); 12921 if (bdseg.sh != dummysh) { 12922 tssdissolve1(worktet); 12923 enext(cbdv, worktet); 12924 tssbond1(worktet, bdseg); 12925 enext2(badv, worktet); 12926 tssbond1(worktet, bdseg); 12927 } 12928 enext2fnext(abcv, worktet); 12929 enext2self(worktet); 12930 tsspivot1(worktet, cdseg); 12931 if (cdseg.sh != dummysh) { 12932 tssdissolve1(worktet); 12933 enext(acdv, worktet); 12934 tssbond1(worktet, cdseg); 12935 enext2(cbdv, worktet); 12936 tssbond1(worktet, cdseg); 12937 } 12938 } 12939 badv.loc = 3; 12940 cbdv.loc = 2; 12941 bond(badv, cbdv); 12942 cbdv.loc = 3; 12943 acdv.loc = 2; 12944 bond(cbdv, acdv); 12945 acdv.loc = 3; 12946 badv.loc = 2; 12947 bond(acdv, badv); 12948 badv.loc = 1; 12949 bond(badv, oldabd); 12950 cbdv.loc = 1; 12951 bond(cbdv, oldbcd); 12952 acdv.loc = 1; 12953 bond(acdv, oldcad); 12954 12955 badv.loc = 0; 12956 cbdv.loc = 0; 12957 acdv.loc = 0; 12958 if (b->verbose > 3) { 12959 printf(" Updating abcv "); 12960 printtet(&abcv); 12961 printf(" Creating badv "); 12962 printtet(&badv); 12963 printf(" Creating cbdv "); 12964 printtet(&cbdv); 12965 printf(" Creating acdv "); 12966 printtet(&acdv); 12967 } 12968 12969 if (flipqueue != (queue *) NULL) { 12970 enqueueflipface(abcv, flipqueue); 12971 enqueueflipface(badv, flipqueue); 12972 enqueueflipface(cbdv, flipqueue); 12973 enqueueflipface(acdv, flipqueue); 12974 } 12975 12976 // Save a handle for quick point location. 12977 recenttet = abcv; 12978 // Set the return handle be abcv. 12979 *splittet = abcv; 12980 } 12981 12983 // // 12984 // unsplittetrahedron() Reverse the operation of inserting a point into a // 12985 // tetrahedron, so as to remove the newly inserted // 12986 // point from the mesh. // 12987 // // 12988 // Assume the origional tetrahedron is abcd, it was split by v into four // 12989 // tetrahedra abcv, badv, cbdv, and acdv. 'splittet' represents face abc of // 12990 // abcv (i.e., its opposite is v). // 12991 // // 12992 // Point v is removed by expanding abcv to abcd, deleting three tetrahedra // 12993 // badv, cbdv and acdv. On return, point v is not deleted in this routine. // 12994 // // 12996 12997 void tetgenmesh::unsplittetrahedron(triface* splittet) 12998 { 12999 triface abcv, badv, cbdv, acdv; 13000 triface oldabv, oldbcv, oldcav; 13001 triface badcasing, cbdcasing, acdcasing; 13002 face badsh, cbdsh, acdsh; 13003 13004 abcv = *splittet; 13005 adjustedgering(abcv, CCW); // for sure. 13006 fnext(abcv, oldabv); 13007 fnext(oldabv, badv); 13008 esymself(badv); 13009 enextfnext(abcv, oldbcv); 13010 fnext(oldbcv, cbdv); 13011 esymself(cbdv); 13012 enext2fnext(abcv, oldcav); 13013 fnext(oldcav, acdv); 13014 esymself(acdv); 13015 13016 if (b->verbose > 1) { 13017 printf(" Removing point %d in tetrahedron (%d, %d, %d, %d).\n", 13018 pointmark(oppo(abcv)), pointmark(org(abcv)), pointmark(dest(abcv)), 13019 pointmark(apex(abcv)), pointmark(apex(badv))); 13020 } 13021 13022 sym(badv, badcasing); 13023 tspivot(badv, badsh); 13024 sym(cbdv, cbdcasing); 13025 tspivot(cbdv, cbdsh); 13026 sym(acdv, acdcasing); 13027 tspivot(acdv, acdsh); 13028 13029 // Expanding abcv to abcd. 13030 setoppo(abcv, apex(badv)); 13031 bond(oldabv, badcasing); 13032 if (badsh.sh != dummysh) { 13033 tsbond(oldabv, badsh); 13034 } 13035 bond(oldbcv, cbdcasing); 13036 if (cbdsh.sh != dummysh) { 13037 tsbond(oldbcv, cbdsh); 13038 } 13039 bond(oldcav, acdcasing); 13040 if (acdsh.sh != dummysh) { 13041 tsbond(oldcav, acdsh); 13042 } 13043 13044 // Delete the three split-out tetrahedra. 13045 tetrahedrondealloc(badv.tet); 13046 tetrahedrondealloc(cbdv.tet); 13047 tetrahedrondealloc(acdv.tet); 13048 } 13049 13051 // // 13052 // splittetface() Insert a point on a face of a mesh. // 13053 // // 13054 // 'splittet' is the splitting face. Let it is abcd, where abc is the face // 13055 // will be split. If abc is not a hull face, abce is the tetrahedron at the // 13056 // opposite of d. // 13057 // // 13058 // To split face abc by a point v is to shrink the tetrahedra abcd to abvd, // 13059 // create two new tetrahedra bcvd, cavd. If abc is not a hull face, shrink // 13060 // the tetrahedra bace to bave, create two new tetrahedra cbve, acve. // 13061 // // 13062 // If abc is a subface, it is split into three subfaces simultaneously by // 13063 // calling routine splitsubface(), hence, abv, bcv, cav. The edge rings of // 13064 // the split subfaces have the same orientation as abc's. // 13065 // // 13066 // On completion, 'splittet' returns abvd. If 'flipqueue' is not NULL, it // 13067 // contains all possibly non-locally Delaunay faces. // 13068 // // 13070 13071 void tetgenmesh::splittetface(point newpoint, triface* splittet, 13072 queue* flipqueue) 13073 { 13074 triface abcd, bace; // Old configuration. 13075 triface oldbcd, oldcad, oldace, oldcbe; 13076 triface bcdcasing, cadcasing, acecasing, cbecasing; 13077 face abcsh, bcdsh, cadsh, acesh, cbesh; 13078 triface abvd, bcvd, cavd, bave, cbve, acve; // New configuration. 13079 triface worktet; 13080 face bcseg, caseg; 13081 face adseg, bdseg, cdseg; 13082 face aeseg, beseg, ceseg; 13083 point pa, pb, pc, pd, pe; 13084 REAL attrib, volume; 13085 bool mirrorflag; 13086 int i; 13087 13088 abcd = *splittet; 13089 // abcd.ver = 0; // Adjust to be CCW edge ring. 13090 adjustedgering(abcd, CCW); 13091 pa = org(abcd); 13092 pb = dest(abcd); 13093 pc = apex(abcd); 13094 pd = oppo(abcd); 13095 pe = (point) NULL; // avoid a compile warning. 13096 // Is there a second tetrahderon? 13097 mirrorflag = issymexist(&abcd); 13098 if (mirrorflag) { 13099 // This is an interior face. 13100 sym(abcd, bace); 13101 findedge(&bace, dest(abcd), org(abcd)); 13102 pe = oppo(bace); 13103 } 13104 if (checksubfaces) { 13105 // Is there a subface need to be split together? 13106 tspivot(abcd, abcsh); 13107 if (abcsh.sh != dummysh) { 13108 // Exists! Keep the edge ab of both handles be the same. 13109 findedge(&abcsh, org(abcd), dest(abcd)); 13110 } 13111 } 13112 13113 if (b->verbose > 1) { 13114 printf(" Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint), 13115 pointmark(pa), pointmark(pb), pointmark(pc)); 13116 } 13117 13118 // Save the old configuration at faces bcd and cad. 13119 enextfnext(abcd, oldbcd); 13120 enext2fnext(abcd, oldcad); 13121 sym(oldbcd, bcdcasing); 13122 sym(oldcad, cadcasing); 13123 // Create two new tetrahedra. 13124 maketetrahedron(&bcvd); 13125 maketetrahedron(&cavd); 13126 if (mirrorflag) { 13127 // Save the old configuration at faces bce and cae. 13128 enextfnext(bace, oldace); 13129 enext2fnext(bace, oldcbe); 13130 sym(oldace, acecasing); 13131 sym(oldcbe, cbecasing); 13132 // Create two new tetrahedra. 13133 maketetrahedron(&acve); 13134 maketetrahedron(&cbve); 13135 } else { 13136 // Splitting a boundary face increases the number of boundary faces. 13137 hullsize += 2; 13138 } 13139 13140 // Set vertices to the changed tetrahedron and new tetrahedra. 13141 abvd = abcd; // Update 'abcd' to 'abvd'. 13142 setapex(abvd, newpoint); 13143 setorg (bcvd, pb); // Set 'bcvd'. 13144 setdest(bcvd, pc); 13145 setapex(bcvd, newpoint); 13146 setoppo(bcvd, pd); 13147 setorg (cavd, pc); // Set 'cavd'. 13148 setdest(cavd, pa); 13149 setapex(cavd, newpoint); 13150 setoppo(cavd, pd); 13151 // Set the element attributes of the new tetrahedra. 13152 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 13153 attrib = elemattribute(abvd.tet, i); 13154 setelemattribute(bcvd.tet, i, attrib); 13155 setelemattribute(cavd.tet, i, attrib); 13156 } 13157 if (b->varvolume) { 13158 // Set the area constraint of the new tetrahedra. 13159 volume = volumebound(abvd.tet); 13160 setvolumebound(bcvd.tet, volume); 13161 setvolumebound(cavd.tet, volume); 13162 } 13163 if (mirrorflag) { 13164 bave = bace; // Update 'bace' to 'bave'. 13165 setapex(bave, newpoint); 13166 setorg (acve, pa); // Set 'acve'. 13167 setdest(acve, pc); 13168 setapex(acve, newpoint); 13169 setoppo(acve, pe); 13170 setorg (cbve, pc); // Set 'cbve'. 13171 setdest(cbve, pb); 13172 setapex(cbve, newpoint); 13173 setoppo(cbve, pe); 13174 // Set the element attributes of the new tetrahedra. 13175 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 13176 attrib = elemattribute(bave.tet, i); 13177 setelemattribute(acve.tet, i, attrib); 13178 setelemattribute(cbve.tet, i, attrib); 13179 } 13180 if (b->varvolume) { 13181 // Set the area constraint of the new tetrahedra. 13182 volume = volumebound(bave.tet); 13183 setvolumebound(acve.tet, volume); 13184 setvolumebound(cbve.tet, volume); 13185 } 13186 } 13187 13188 // Bond the new tetrahedra to the surrounding tetrahedra. 13189 bcvd.loc = 1; 13190 bond(bcvd, bcdcasing); 13191 cavd.loc = 1; 13192 bond(cavd, cadcasing); 13193 bcvd.loc = 3; 13194 bond(bcvd, oldbcd); 13195 cavd.loc = 2; 13196 bond(cavd, oldcad); 13197 bcvd.loc = 2; 13198 cavd.loc = 3; 13199 bond(bcvd, cavd); 13200 if (mirrorflag) { 13201 acve.loc = 1; 13202 bond(acve, acecasing); 13203 cbve.loc = 1; 13204 bond(cbve, cbecasing); 13205 acve.loc = 3; 13206 bond(acve, oldace); 13207 cbve.loc = 2; 13208 bond(cbve, oldcbe); 13209 acve.loc = 2; 13210 cbve.loc = 3; 13211 bond(acve, cbve); 13212 // Bond two new coplanar facets. 13213 bcvd.loc = 0; 13214 cbve.loc = 0; 13215 bond(bcvd, cbve); 13216 cavd.loc = 0; 13217 acve.loc = 0; 13218 bond(cavd, acve); 13219 } 13220 13221 // There may exist subface needed to be bonded to the new tetrahedra. 13222 if (checksubfaces) { 13223 tspivot(oldbcd, bcdsh); 13224 if (bcdsh.sh != dummysh) { 13225 tsdissolve(oldbcd); 13226 bcvd.loc = 1; 13227 tsbond(bcvd, bcdsh); 13228 } 13229 tspivot(oldcad, cadsh); 13230 if (cadsh.sh != dummysh) { 13231 tsdissolve(oldcad); 13232 cavd.loc = 1; 13233 tsbond(cavd, cadsh); 13234 } 13235 if (mirrorflag) { 13236 tspivot(oldace, acesh); 13237 if (acesh.sh != dummysh) { 13238 tsdissolve(oldace); 13239 acve.loc = 1; 13240 tsbond(acve, acesh); 13241 } 13242 tspivot(oldcbe, cbesh); 13243 if (cbesh.sh != dummysh) { 13244 tsdissolve(oldcbe); 13245 cbve.loc = 1; 13246 tsbond(cbve, cbesh); 13247 } 13248 } 13249 // Is there a subface needs to be split together? 13250 if (abcsh.sh != dummysh) { 13251 // Split this subface 'abc' into three i.e, abv, bcv, cav. 13252 splitsubface(newpoint, &abcsh, (queue *) NULL); 13253 } 13254 } else if (checksubsegs) { 13255 // abvd.loc = abvd.ver = 0; 13256 bcvd.loc = bcvd.ver = 0; 13257 cavd.loc = cavd.ver = 0; 13258 if (mirrorflag) { 13259 // bave.loc = bave.ver = 0; 13260 cbve.loc = cbve.ver = 0; 13261 acve.loc = acve.ver = 0; 13262 } 13263 enext(abvd, worktet); 13264 tsspivot1(worktet, bcseg); 13265 if (bcseg.sh != dummysh) { 13266 tssdissolve1(worktet); 13267 tssbond1(bcvd, bcseg); 13268 if (mirrorflag) { 13269 enext2(bave, worktet); 13270 tssdissolve1(worktet); 13271 tssbond1(cbve, bcseg); 13272 } 13273 } 13274 enext2(abvd, worktet); 13275 tsspivot1(worktet, caseg); 13276 if (caseg.sh != dummysh) { 13277 tssdissolve1(worktet); 13278 tssbond1(cavd, caseg); 13279 if (mirrorflag) { 13280 enext(bave, worktet); 13281 tssdissolve1(worktet); 13282 tssbond1(acve, caseg); 13283 } 13284 } 13285 fnext(abvd, worktet); 13286 enext2self(worktet); 13287 tsspivot1(worktet, adseg); 13288 if (adseg.sh != dummysh) { 13289 fnext(cavd, worktet); 13290 enextself(worktet); 13291 tssbond1(worktet, adseg); 13292 } 13293 fnext(abvd, worktet); 13294 enextself(worktet); 13295 tsspivot1(worktet, bdseg); 13296 if (bdseg.sh != dummysh) { 13297 fnext(bcvd, worktet); 13298 enext2self(worktet); 13299 tssbond1(worktet, bdseg); 13300 } 13301 enextfnext(abvd, worktet); 13302 enextself(worktet); 13303 tsspivot1(worktet, cdseg); 13304 if (cdseg.sh != dummysh) { 13305 tssdissolve1(worktet); 13306 fnext(bcvd, worktet); 13307 enextself(worktet); 13308 tssbond1(worktet, cdseg); 13309 fnext(cavd, worktet); 13310 enext2self(worktet); 13311 tssbond1(worktet, cdseg); 13312 } 13313 if (mirrorflag) { 13314 fnext(bave, worktet); 13315 enextself(worktet); 13316 tsspivot1(worktet, aeseg); 13317 if (aeseg.sh != dummysh) { 13318 fnext(acve, worktet); 13319 enext2self(worktet); 13320 tssbond1(worktet, aeseg); 13321 } 13322 fnext(bave, worktet); 13323 enext2self(worktet); 13324 tsspivot1(worktet, beseg); 13325 if (beseg.sh != dummysh) { 13326 fnext(cbve, worktet); 13327 enextself(worktet); 13328 tssbond1(worktet, beseg); 13329 } 13330 enextfnext(bave, worktet); 13331 enextself(worktet); 13332 tsspivot1(worktet, ceseg); 13333 if (ceseg.sh != dummysh) { 13334 tssdissolve1(worktet); 13335 fnext(cbve, worktet); 13336 enext2self(worktet); 13337 tssbond1(worktet, ceseg); 13338 fnext(acve, worktet); 13339 enextself(worktet); 13340 tssbond1(worktet, ceseg); 13341 } 13342 } 13343 } 13344 13345 // Save a handle for quick point location. 13346 recenttet = abvd; 13347 // Set the return handle be abvd. 13348 *splittet = abvd; 13349 13350 bcvd.loc = 0; 13351 cavd.loc = 0; 13352 if (mirrorflag) { 13353 cbve.loc = 0; 13354 acve.loc = 0; 13355 } 13356 if (b->verbose > 3) { 13357 printf(" Updating abvd "); 13358 printtet(&abvd); 13359 printf(" Creating bcvd "); 13360 printtet(&bcvd); 13361 printf(" Creating cavd "); 13362 printtet(&cavd); 13363 if (mirrorflag) { 13364 printf(" Updating bave "); 13365 printtet(&bave); 13366 printf(" Creating cbve "); 13367 printtet(&cbve); 13368 printf(" Creating acve "); 13369 printtet(&acve); 13370 } 13371 } 13372 13373 if (flipqueue != (queue *) NULL) { 13374 fnextself(abvd); 13375 enqueueflipface(abvd, flipqueue); 13376 fnextself(bcvd); 13377 enqueueflipface(bcvd, flipqueue); 13378 fnextself(cavd); 13379 enqueueflipface(cavd, flipqueue); 13380 if (mirrorflag) { 13381 fnextself(bave); 13382 enqueueflipface(bave, flipqueue); 13383 fnextself(cbve); 13384 enqueueflipface(cbve, flipqueue); 13385 fnextself(acve); 13386 enqueueflipface(acve, flipqueue); 13387 } 13388 } 13389 } 13390 13392 // // 13393 // unsplittetface() Reverse the operation of inserting a point on a face, // 13394 // so as to remove the newly inserted point. // 13395 // // 13396 // Assume the original face is abc, the tetrahedron containing abc is abcd. // 13397 // If abc is not a hull face, bace is the tetrahedron at the opposite of d. // 13398 // After face abc was split by a point v, tetrahedron abcd had been split // 13399 // into three tetrahedra, abvd, bcvd, cavd, and bace (if it exists) had been // 13400 // split into bave, cbve, acve. 'splittet' represents abvd (its apex is v). // 13401 // // 13402 // Point v is removed by expanding abvd to abcd, deleting two tetrahedra // 13403 // bcvd, cavd. Expanding bave(if it exists) to bace, deleting two tetrahedra // 13404 // cbve, acve. If abv is a subface, routine unsplitsubface() will be called // 13405 // to reverse the operation of splitting a subface. On completion, point v // 13406 // is not deleted in this routine. // 13407 // // 13409 13410 void tetgenmesh::unsplittetface(triface* splittet) 13411 { 13412 triface abvd, bcvd, cavd, bave, cbve, acve; 13413 triface oldbvd, oldvad, oldvbe, oldave; 13414 triface bcdcasing, cadcasing, cbecasing, acecasing; 13415 face bcdsh, cadsh, cbesh, acesh; 13416 face abvsh; 13417 bool mirrorflag; 13418 13419 abvd = *splittet; 13420 adjustedgering(abvd, CCW); // for sure. 13421 enextfnext(abvd, oldbvd); 13422 fnext(oldbvd, bcvd); 13423 esymself(bcvd); 13424 enextself(bcvd); 13425 enext2fnext(abvd, oldvad); 13426 fnext(oldvad, cavd); 13427 esymself(cavd); 13428 enext2self(cavd); 13429 // Is there a second tetrahedron? 13430 sym(abvd, bave); 13431 mirrorflag = bave.tet != dummytet; 13432 if (mirrorflag) { 13433 findedge(&bave, dest(abvd), org(abvd)); 13434 enextfnext(bave, oldave); 13435 fnext(oldave, acve); 13436 esymself(acve); 13437 enextself(acve); 13438 enext2fnext(bave, oldvbe); 13439 fnext(oldvbe, cbve); 13440 esymself(cbve); 13441 enext2self(cbve); 13442 } else { 13443 // Unsplit a hull face decrease the number of boundary faces. 13444 hullsize -= 2; 13445 } 13446 // Is there a subface at abv. 13447 tspivot(abvd, abvsh); 13448 if (abvsh.sh != dummysh) { 13449 // Exists! Keep the edge ab of both handles be the same. 13450 findedge(&abvsh, org(abvd), dest(abvd)); 13451 } 13452 13453 if (b->verbose > 1) { 13454 printf(" Removing point %d on face (%d, %d, %d).\n", 13455 pointmark(apex(abvd)), pointmark(org(abvd)), pointmark(dest(abvd)), 13456 pointmark(dest(bcvd))); 13457 } 13458 13459 fnextself(bcvd); // bcvd has changed to bcdv. 13460 sym(bcvd, bcdcasing); 13461 tspivot(bcvd, bcdsh); 13462 fnextself(cavd); // cavd has changed to cadv. 13463 sym(cavd, cadcasing); 13464 tspivot(cavd, cadsh); 13465 if (mirrorflag) { 13466 fnextself(acve); // acve has changed to acev. 13467 sym(acve, acecasing); 13468 tspivot(acve, acesh); 13469 fnextself(cbve); // cbve has changed to cbev. 13470 sym(cbve, cbecasing); 13471 tspivot(cbve, cbesh); 13472 } 13473 13474 // Expand abvd to abcd. 13475 setapex(abvd, dest(bcvd)); 13476 bond(oldbvd, bcdcasing); 13477 if (bcdsh.sh != dummysh) { 13478 tsbond(oldbvd, bcdsh); 13479 } 13480 bond(oldvad, cadcasing); 13481 if (cadsh.sh != dummysh) { 13482 tsbond(oldvad, cadsh); 13483 } 13484 if (mirrorflag) { 13485 // Expanding bave to bace. 13486 setapex(bave, dest(acve)); 13487 bond(oldave, acecasing); 13488 if (acesh.sh != dummysh) { 13489 tsbond(oldave, acesh); 13490 } 13491 bond(oldvbe, cbecasing); 13492 if (cbesh.sh != dummysh) { 13493 tsbond(oldvbe, cbesh); 13494 } 13495 } 13496 13497 // Unsplit a subface if there exists. 13498 if (abvsh.sh != dummysh) { 13499 unsplitsubface(&abvsh); 13500 } 13501 13502 // Delete the split-out tetrahedra. 13503 tetrahedrondealloc(bcvd.tet); 13504 tetrahedrondealloc(cavd.tet); 13505 if (mirrorflag) { 13506 tetrahedrondealloc(acve.tet); 13507 tetrahedrondealloc(cbve.tet); 13508 } 13509 } 13510 13512 // // 13513 // splitsubface() Insert a point on a subface, split it into three. // 13514 // // 13515 // The subface is 'splitface'. Let it is abc. The inserting point 'newpoint'// 13516 // v should lie inside abc. If the neighbor tetrahedra of abc exist, i.e., // 13517 // abcd and bace, they should have been split by routine splittetface() // 13518 // before calling this routine, so the connection between the new tetrahedra // 13519 // and new subfaces can be correctly set. // 13520 // // 13521 // To split subface abc by point v is to shrink abc to abv, create two new // 13522 // subfaces bcv and cav. Set the connection between updated and new created // 13523 // subfaces. If there is a subsegment at edge bc or ca, connection of new // 13524 // subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is // 13525 // the predecessor and 'casingout' is the successor. It is important to keep // 13526 // the orientations of the edge rings of the updated and created subfaces be // 13527 // the same as abc's. So they have the same orientation as other subfaces of // 13528 // this facet with respect to the lift point of this facet. // 13529 // // 13530 // On completion, 'splitface' returns abv. If 'flipqueue' is not NULL, it // 13531 // returns all possibly non-Delaunay edges. // 13532 // // 13534 13535 void tetgenmesh::splitsubface(point newpoint, face* splitface, 13536 queue* flipqueue) 13537 { 13538 triface abvd, bcvd, cavd, bave, cbve, acve; 13539 face abc, oldbc, oldca, bc, ca, spinsh; 13540 face bccasin, bccasout, cacasin, cacasout; 13541 face abv, bcv, cav; 13542 point pa, pb, pc; 13543 13544 abc = *splitface; 13545 // The newly created subfaces will have the same edge ring as abc. 13546 adjustedgering(abc, CCW); 13547 pa = sorg(abc); 13548 pb = sdest(abc); 13549 pc = sapex(abc); 13550 13551 if (b->verbose > 1) { 13552 printf(" Inserting point %d on subface (%d, %d, %d).\n", 13553 pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc)); 13554 } 13555 13556 // Save the old configuration at edge bc and ca. Subsegments may appear 13557 // at both sides, save the face links and dissolve them. 13558 senext(abc, oldbc); 13559 senext2(abc, oldca); 13560 spivot(oldbc, bccasout); 13561 sspivot(oldbc, bc); 13562 if (bc.sh != dummysh) { 13563 if (oldbc.sh != bccasout.sh) { 13564 // 'oldbc' is not self-bonded. 13565 spinsh = bccasout; 13566 do { 13567 bccasin = spinsh; 13568 spivotself(spinsh); 13569 } while (spinsh.sh != oldbc.sh); 13570 } else { 13571 bccasout.sh = dummysh; 13572 } 13573 ssdissolve(oldbc); 13574 } 13575 spivot(oldca, cacasout); 13576 sspivot(oldca, ca); 13577 if (ca.sh != dummysh) { 13578 if (oldca.sh != cacasout.sh) { 13579 // 'oldca' is not self-bonded. 13580 spinsh = cacasout; 13581 do { 13582 cacasin = spinsh; 13583 spivotself(spinsh); 13584 } while (spinsh.sh != oldca.sh); 13585 } else { 13586 cacasout.sh = dummysh; 13587 } 13588 ssdissolve(oldca); 13589 } 13590 // Create two new subfaces. 13591 makeshellface(subfaces, &bcv); 13592 makeshellface(subfaces, &cav); 13593 13594 // Set the vertices of changed and new subfaces. 13595 abv = abc; // Update 'abc' to 'abv'. 13596 setsapex(abv, newpoint); 13597 setsorg(bcv, pb); // Set 'bcv'. 13598 setsdest(bcv, pc); 13599 setsapex(bcv, newpoint); 13600 setsorg(cav, pc); // Set 'cav'. 13601 setsdest(cav, pa); 13602 setsapex(cav, newpoint); 13603 if (b->quality && varconstraint) { 13604 // Copy yhr area bound into the new subfaces. 13605 setareabound(bcv, areabound(abv)); 13606 setareabound(cav, areabound(abv)); 13607 } 13608 // Copy the boundary mark into the new subfaces. 13609 setshellmark(bcv, shellmark(abv)); 13610 setshellmark(cav, shellmark(abv)); 13611 // Copy the subface type into the new subfaces. 13612 setshelltype(bcv, shelltype(abv)); 13613 setshelltype(cav, shelltype(abv)); 13614 if (checkpbcs) { 13615 // Copy the pbcgroup into the new subfaces. 13616 setshellpbcgroup(bcv, shellpbcgroup(abv)); 13617 setshellpbcgroup(cav, shellpbcgroup(abv)); 13618 } 13619 // Bond the new subfaces to the surrounding subfaces. 13620 if (bc.sh != dummysh) { 13621 if (bccasout.sh != dummysh) { 13622 sbond1(bccasin, bcv); 13623 sbond1(bcv, bccasout); 13624 } else { 13625 // Bond 'bcv' to itsself. 13626 sbond(bcv, bcv); 13627 } 13628 ssbond(bcv, bc); 13629 } else { 13630 sbond(bcv, bccasout); 13631 } 13632 if (ca.sh != dummysh) { 13633 if (cacasout.sh != dummysh) { 13634 sbond1(cacasin, cav); 13635 sbond1(cav, cacasout); 13636 } else { 13637 // Bond 'cav' to itself. 13638 sbond(cav, cav); 13639 } 13640 ssbond(cav, ca); 13641 } else { 13642 sbond(cav, cacasout); 13643 } 13644 senext2self(bcv); 13645 sbond(bcv, oldbc); 13646 senextself(cav); 13647 sbond(cav, oldca); 13648 senext2self(bcv); 13649 senextself(cav); 13650 sbond(bcv, cav); 13651 13652 // Bond the new subfaces to the new tetrahedra if they exist. 13653 stpivot(abv, abvd); 13654 if (abvd.tet != dummytet) { 13655 // Get two new tetrahedra and their syms. 13656 findedge(&abvd, sorg(abv), sdest(abv)); 13657 enextfnext(abvd, bcvd); 13658 #ifdef SELF_CHECK 13659 assert(bcvd.tet != dummytet); 13660 #endif 13661 fnextself(bcvd); 13662 enext2fnext(abvd, cavd); 13663 #ifdef SELF_CHECK 13664 assert(cavd.tet != dummytet); 13665 #endif 13666 fnextself(cavd); 13667 // Bond two new subfaces to the two new tetrahedra. 13668 tsbond(bcvd, bcv); 13669 tsbond(cavd, cav); 13670 } 13671 // Set the connection at the other sides if the tetrahedra exist. 13672 sesymself(abv); // bav 13673 stpivot(abv, bave); 13674 if (bave.tet != dummytet) { 13675 sesymself(bcv); // cbv 13676 sesymself(cav); // acv 13677 // Get two new tetrahedra and their syms. 13678 findedge(&bave, sorg(abv), sdest(abv)); 13679 enextfnext(bave, acve); 13680 #ifdef SELF_CHECK 13681 assert(acve.tet != dummytet); 13682 #endif 13683 fnextself(acve); 13684 enext2fnext(bave, cbve); 13685 #ifdef SELF_CHECK 13686 assert(cbve.tet != dummytet); 13687 #endif 13688 fnextself(cbve); 13689 // Bond two new subfaces to the two new tetrahedra. 13690 tsbond(acve, cav); 13691 tsbond(cbve, bcv); 13692 } 13693 13694 bcv.shver = 0; 13695 cav.shver = 0; 13696 if (b->verbose > 3) { 13697 printf(" Updating abv "); 13698 printsh(&abv); 13699 printf(" Creating bcv "); 13700 printsh(&bcv); 13701 printf(" Creating cav "); 13702 printsh(&cav); 13703 } 13704 13705 if (flipqueue != (queue *) NULL) { 13706 enqueueflipedge(abv, flipqueue); 13707 enqueueflipedge(bcv, flipqueue); 13708 enqueueflipedge(cav, flipqueue); 13709 } 13710 13711 // Set the return handle be abv. 13712 *splitface = abv; 13713 } 13714 13716 // // 13717 // unsplitsubface() Reverse the operation of inserting a point on a // 13718 // subface, so as to remove the newly inserted point. // 13719 // // 13720 // Assume the original subface is abc, it was split by a point v into three // 13721 // subfaces abv, bcv and cav. 'splitsh' represents abv. // 13722 // // 13723 // To remove point v is to expand abv to abc, delete bcv and cav. If edge bc // 13724 // or ca is a subsegment, the connection at a subsegment is a subface link, // 13725 // '-casin' and '-casout' are used to save the predecessor and successor of // 13726 // bcv or cav. On completion, point v is not deleted in this routine. // 13727 // // 13729 13730 void tetgenmesh::unsplitsubface(face* splitsh) 13731 { 13732 face abv, bcv, cav; 13733 face oldbv, oldva, bc, ca, spinsh; 13734 face bccasin, bccasout, cacasin, cacasout; 13735 13736 abv = *splitsh; 13737 senext(abv, oldbv); 13738 spivot(oldbv, bcv); 13739 if (sorg(bcv) != sdest(oldbv)) { 13740 sesymself(bcv); 13741 } 13742 senextself(bcv); 13743 senext2(abv, oldva); 13744 spivot(oldva, cav); 13745 if (sorg(cav) != sdest(oldva)) { 13746 sesymself(cav); 13747 } 13748 senext2self(cav); 13749 13750 if (b->verbose > 1) { 13751 printf(" Removing point %d on subface (%d, %d, %d).\n", 13752 pointmark(sapex(abv)), pointmark(sorg(abv)), pointmark(sdest(abv)), 13753 pointmark(sdest(bcv))); 13754 } 13755 13756 spivot(bcv, bccasout); 13757 sspivot(bcv, bc); 13758 if (bc.sh != dummysh) { 13759 if (bcv.sh != bccasout.sh) { 13760 // 'bcv' is not self-bonded. 13761 spinsh = bccasout; 13762 do { 13763 bccasin = spinsh; 13764 spivotself(spinsh); 13765 } while (spinsh.sh != bcv.sh); 13766 } else { 13767 bccasout.sh = dummysh; 13768 } 13769 } 13770 spivot(cav, cacasout); 13771 sspivot(cav, ca); 13772 if (ca.sh != dummysh) { 13773 if (cav.sh != cacasout.sh) { 13774 // 'cav' is not self-bonded. 13775 spinsh = cacasout; 13776 do { 13777 cacasin = spinsh; 13778 spivotself(spinsh); 13779 } while (spinsh.sh != cav.sh); 13780 } else { 13781 cacasout.sh = dummysh; 13782 } 13783 } 13784 13785 // Expand abv to abc. 13786 setsapex(abv, sdest(bcv)); 13787 if (bc.sh != dummysh) { 13788 if (bccasout.sh != dummysh) { 13789 sbond1(bccasin, oldbv); 13790 sbond1(oldbv, bccasout); 13791 } else { 13792 // Bond 'oldbv' to itself. 13793 sbond(oldbv, oldbv); 13794 } 13795 ssbond(oldbv, bc); 13796 } else { 13797 sbond(oldbv, bccasout); 13798 } 13799 if (ca.sh != dummysh) { 13800 if (cacasout.sh != dummysh) { 13801 sbond1(cacasin, oldva); 13802 sbond1(oldva, cacasout); 13803 } else { 13804 // Bond 'oldva' to itself. 13805 sbond(oldva, oldva); 13806 } 13807 ssbond(oldva, ca); 13808 } else { 13809 sbond(oldva, cacasout); 13810 } 13811 13812 // Delete two split-out subfaces. 13813 shellfacedealloc(subfaces, bcv.sh); 13814 shellfacedealloc(subfaces, cav.sh); 13815 } 13816 13818 // // 13819 // splittetedge() Insert a point on an edge of the mesh. // 13820 // // 13821 // The edge is given by 'splittet'. Assume its four corners are a, b, n1 and // 13822 // n2, where ab is the edge will be split. Around ab may exist any number of // 13823 // tetrahedra. For convenience, they're ordered in a sequence following the // 13824 // right-hand rule with your thumb points from a to b. Let the vertex set of // 13825 // these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around // 13826 // ab may not connect to each other (can only happen when ab is a subsegment,// 13827 // hence some faces abn(i) are subfaces). If ab is a subsegment, abn1 must // 13828 // be a subface. // 13829 // // 13830 // To split edge ab by a point v is to split all tetrahedra containing ab by // 13831 // v. More specifically, for each such tetrahedron, an1n2b, it is shrunk to // 13832 // an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or // 13833 // some faces of the splitting tetrahedra are subfaces, they must be split // 13834 // either by calling routine 'splitsubedge()'. // 13835 // // 13836 // On completion, 'splittet' returns avn1n2. If 'flipqueue' is not NULL, it // 13837 // returns all faces which may become non-Delaunay after this operation. // 13838 // // 13840 13841 void tetgenmesh::splittetedge(point newpoint, triface* splittet, 13842 queue* flipqueue) 13843 { 13844 triface *bots, *newtops; 13845 triface oldtop, topcasing; 13846 triface spintet, tmpbond0, tmpbond1; 13847 face abseg, splitsh, topsh, spinsh; 13848 triface worktet; 13849 face n1n2seg, n2vseg, n1vseg; 13850 point pa, pb, n1, n2; 13851 REAL attrib, volume; 13852 int wrapcount, hitbdry; 13853 int i, j; 13854 13855 if (checksubfaces) { 13856 // Is there a subsegment need to be split together? 13857 tsspivot(splittet, &abseg); 13858 if (abseg.sh != dummysh) { 13859 abseg.shver = 0; 13860 // Orient the edge direction of 'splittet' be abseg. 13861 if (org(*splittet) != sorg(abseg)) { 13862 esymself(*splittet); 13863 } 13864 } 13865 } 13866 spintet = *splittet; 13867 pa = org(spintet); 13868 pb = dest(spintet); 13869 13870 if (b->verbose > 1) { 13871 printf(" Inserting point %d on edge (%d, %d).\n", 13872 pointmark(newpoint), pointmark(pa), pointmark(pb)); 13873 } 13874 13875 // Collect the tetrahedra containing the splitting edge (ab). 13876 n1 = apex(spintet); 13877 hitbdry = 0; 13878 wrapcount = 1; 13879 if (checksubfaces && abseg.sh != dummysh) { 13880 // It may happen that some tetrahedra containing ab (a subsegment) are 13881 // completely disconnected with others. If it happens, use the face 13882 // link of ab to cross the boundary. 13883 while (true) { 13884 if (!fnextself(spintet)) { 13885 // Meet a boundary, walk through it. 13886 hitbdry ++; 13887 tspivot(spintet, spinsh); 13888 #ifdef SELF_CHECK 13889 assert(spinsh.sh != dummysh); 13890 #endif 13891 findedge(&spinsh, pa, pb); 13892 sfnextself(spinsh); 13893 stpivot(spinsh, spintet); 13894 #ifdef SELF_CHECK 13895 assert(spintet.tet != dummytet); 13896 #endif 13897 findedge(&spintet, pa, pb); 13898 // Remember this position (hull face) in 'splittet'. 13899 *splittet = spintet; 13900 // Split two hull faces increase the hull size; 13901 hullsize += 2; 13902 } 13903 if (apex(spintet) == n1) break; 13904 wrapcount ++; 13905 } 13906 if (hitbdry > 0) { 13907 wrapcount -= hitbdry; 13908 } 13909 } else { 13910 // All the tetrahedra containing ab are connected together. If there 13911 // are subfaces, 'splitsh' keeps one of them. 13912 splitsh.sh = dummysh; 13913 while (hitbdry < 2) { 13914 if (checksubfaces && splitsh.sh == dummysh) { 13915 tspivot(spintet, splitsh); 13916 } 13917 if (fnextself(spintet)) { 13918 if (apex(spintet) == n1) break; 13919 wrapcount++; 13920 } else { 13921 hitbdry ++; 13922 if (hitbdry < 2) { 13923 esym(*splittet, spintet); 13924 } 13925 } 13926 } 13927 if (hitbdry > 0) { 13928 // ab is on the hull. 13929 wrapcount -= 1; 13930 // 'spintet' now is a hull face, inverse its edge direction. 13931 esym(spintet, *splittet); 13932 // Split two hull faces increases the number of hull faces. 13933 hullsize += 2; 13934 } 13935 } 13936 13937 // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra. 13938 bots = new triface[wrapcount]; 13939 newtops = new triface[wrapcount]; 13940 // Spin around ab, gather tetrahedra and set up new tetrahedra. 13941 spintet = *splittet; 13942 for (i = 0; i < wrapcount; i++) { 13943 // Get 'bots[i] = an1n2b'. 13944 enext2fnext(spintet, bots[i]); 13945 esymself(bots[i]); 13946 // Create 'newtops[i]'. 13947 maketetrahedron(&(newtops[i])); 13948 // Go to the next. 13949 fnextself(spintet); 13950 if (checksubfaces && abseg.sh != dummysh) { 13951 if (!issymexist(&spintet)) { 13952 // We meet a hull face, walk through it. 13953 tspivot(spintet, spinsh); 13954 #ifdef SELF_CHECK 13955 assert(spinsh.sh != dummysh); 13956 #endif 13957 findedge(&spinsh, pa, pb); 13958 sfnextself(spinsh); 13959 stpivot(spinsh, spintet); 13960 #ifdef SELF_CHECK 13961 assert(spintet.tet != dummytet); 13962 #endif 13963 findedge(&spintet, pa, pb); 13964 } 13965 } 13966 } 13967 13968 // Set the vertices of updated and new tetrahedra. 13969 for (i = 0; i < wrapcount; i++) { 13970 // Update 'bots[i] = an1n2v'. 13971 setoppo(bots[i], newpoint); 13972 // Set 'newtops[i] = bn2n1v'. 13973 n1 = dest(bots[i]); 13974 n2 = apex(bots[i]); 13975 // Set 'newtops[i]'. 13976 setorg(newtops[i], pb); 13977 setdest(newtops[i], n2); 13978 setapex(newtops[i], n1); 13979 setoppo(newtops[i], newpoint); 13980 // Set the element attributes of a new tetrahedron. 13981 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 13982 attrib = elemattribute(bots[i].tet, j); 13983 setelemattribute(newtops[i].tet, j, attrib); 13984 } 13985 if (b->varvolume) { 13986 // Set the area constraint of a new tetrahedron. 13987 volume = volumebound(bots[i].tet); 13988 setvolumebound(newtops[i].tet, volume); 13989 } 13990 #ifdef SELF_CHECK 13991 // Make sure no inversed tetrahedron has been created. 13992 // volume = orient3d(pa, n1, n2, newpoint); 13993 // if (volume >= 0.0) { 13994 // printf("Internal error in splittetedge(): volume = %.12g.\n", volume); 13995 // } 13996 // volume = orient3d(pb, n2, n1, newpoint); 13997 // if (volume >= 0.0) { 13998 // printf("Internal error in splittetedge(): volume = %.12g.\n", volume); 13999 // } 14000 #endif 14001 } 14002 14003 // Bond newtops to topcasings and bots. 14004 for (i = 0; i < wrapcount; i++) { 14005 // Get 'oldtop = n1n2va' from 'bots[i]'. 14006 enextfnext(bots[i], oldtop); 14007 sym(oldtop, topcasing); 14008 bond(newtops[i], topcasing); 14009 if (checksubfaces) { 14010 tspivot(oldtop, topsh); 14011 if (topsh.sh != dummysh) { 14012 tsdissolve(oldtop); 14013 tsbond(newtops[i], topsh); 14014 } 14015 } 14016 enextfnext(newtops[i], tmpbond0); 14017 bond(oldtop, tmpbond0); 14018 } 14019 // Bond between newtops. 14020 fnext(newtops[0], tmpbond0); 14021 enext2fnext(bots[0], spintet); 14022 for (i = 1; i < wrapcount; i ++) { 14023 if (issymexist(&spintet)) { 14024 enext2fnext(newtops[i], tmpbond1); 14025 bond(tmpbond0, tmpbond1); 14026 } 14027 fnext(newtops[i], tmpbond0); 14028 enext2fnext(bots[i], spintet); 14029 } 14030 // Bond the last to the first if no boundary. 14031 if (issymexist(&spintet)) { 14032 enext2fnext(newtops[0], tmpbond1); 14033 bond(tmpbond0, tmpbond1); 14034 } 14035 if (checksubsegs) { 14036 for (i = 0; i < wrapcount; i++) { 14037 enextfnext(bots[i], worktet); // edge n1->n2. 14038 tsspivot1(worktet, n1n2seg); 14039 if (n1n2seg.sh != dummysh) { 14040 enext(newtops[i], tmpbond0); 14041 tssbond1(tmpbond0, n1n2seg); 14042 } 14043 enextself(worktet); // edge n2->v ==> n2->b 14044 tsspivot1(worktet, n2vseg); 14045 if (n2vseg.sh != dummysh) { 14046 tssdissolve1(worktet); 14047 tssbond1(newtops[i], n2vseg); 14048 } 14049 enextself(worktet); // edge v->n1 ==> b->n1 14050 tsspivot1(worktet, n1vseg); 14051 if (n1vseg.sh != dummysh) { 14052 tssdissolve1(worktet); 14053 enext2(newtops[i], tmpbond0); 14054 tssbond1(tmpbond0, n1vseg); 14055 } 14056 } 14057 } 14058 14059 // Is there exist subfaces and subsegment need to be split? 14060 if (checksubfaces) { 14061 if (abseg.sh != dummysh) { 14062 // A subsegment needs be split. 14063 spivot(abseg, splitsh); 14064 #ifdef SELF_CHECK 14065 assert(splitsh.sh != dummysh); 14066 #endif 14067 } 14068 if (splitsh.sh != dummysh) { 14069 // Split subfaces (and subsegment). 14070 findedge(&splitsh, pa, pb); 14071 splitsubedge(newpoint, &splitsh, (queue *) NULL); 14072 } 14073 } 14074 14075 if (b->verbose > 3) { 14076 for (i = 0; i < wrapcount; i++) { 14077 printf(" Updating bots[%i] ", i); 14078 printtet(&(bots[i])); 14079 printf(" Creating newtops[%i] ", i); 14080 printtet(&(newtops[i])); 14081 } 14082 } 14083 14084 if (flipqueue != (queue *) NULL) { 14085 for (i = 0; i < wrapcount; i++) { 14086 enqueueflipface(bots[i], flipqueue); 14087 enqueueflipface(newtops[i], flipqueue); 14088 } 14089 } 14090 14091 // Set the return handle be avn1n2. It is got by transforming from 14092 // 'bots[0]' (which is an1n2v). 14093 fnext(bots[0], spintet); // spintet is an1vn2. 14094 esymself(spintet); // spintet is n1avn2. 14095 enextself(spintet); // spintet is avn1n2. 14096 *splittet = spintet; 14097 14098 delete [] bots; 14099 delete [] newtops; 14100 } 14101 14103 // // 14104 // unsplittetedge() Reverse the operation of splitting an edge, so as to // 14105 // remove the newly inserted point. // 14106 // // 14107 // Assume the original edge is ab, the tetrahedron containing ab is abn1n2. // 14108 // After ab was split by a point v, every tetrahedron containing ab (e.g., // 14109 // abn1n2) has been split into two (e.g., an1n2v and bn2n1v). 'splittet' // 14110 // represents avn1n2 (i.e., its destination is v). // 14111 // // 14112 // To remove point v is to expand each split tetrahedron containing ab (e.g.,// 14113 // (avn1n2 to abn1n2), then delete the redundant one(e.g., vbn1n2). If there // 14114 // exists any subface around ab, routine unsplitsubedge() will be called to // 14115 // reverse the operation of splitting a edge (or a subsegment) of subfaces. // 14116 // On completion, point v is not deleted in this routine. // 14117 // // 14119 14120 void tetgenmesh::unsplittetedge(triface* splittet) 14121 { 14122 triface *bots, *newtops; 14123 triface oldtop, topcasing; 14124 triface spintet; 14125 face avseg, splitsh, topsh, spinsh; 14126 point pa, pv, n1; 14127 int wrapcount, hitbdry; 14128 int i; 14129 14130 spintet = *splittet; 14131 pa = org(spintet); 14132 pv = dest(spintet); 14133 if (checksubfaces) { 14134 // Is there a subsegment need to be unsplit together? 14135 tsspivot(splittet, &avseg); 14136 if (avseg.sh != dummysh) { 14137 // The subsegment's direction should conform to 'splittet'. 14138 if (sorg(avseg) != pa) { 14139 sesymself(avseg); 14140 } 14141 } 14142 } 14143 14144 n1 = apex(spintet); 14145 hitbdry = 0; 14146 wrapcount = 1; 14147 if (checksubfaces && avseg.sh != dummysh) { 14148 // It may happen that some tetrahedra containing ab (a subsegment) are 14149 // completely disconnected with others. If it happens, use the face 14150 // link of ab to cross the boundary. 14151 while (true) { 14152 if (!fnextself(spintet)) { 14153 // Meet a boundary, walk through it. 14154 hitbdry ++; 14155 tspivot(spintet, spinsh); 14156 #ifdef SELF_CHECK 14157 assert(spinsh.sh != dummysh); 14158 #endif 14159 findedge(&spinsh, pa, pv); 14160 sfnextself(spinsh); 14161 stpivot(spinsh, spintet); 14162 #ifdef SELF_CHECK 14163 assert(spintet.tet != dummytet); 14164 #endif 14165 findedge(&spintet, pa, pv); 14166 // Remember this position (hull face) in 'splittet'. 14167 *splittet = spintet; 14168 // Split two hull faces increase the hull size; 14169 hullsize += 2; 14170 } 14171 if (apex(spintet) == n1) break; 14172 wrapcount ++; 14173 } 14174 if (hitbdry > 0) { 14175 wrapcount -= hitbdry; 14176 } 14177 } else { 14178 // All the tetrahedra containing ab are connected together. If there 14179 // are subfaces, 'splitsh' keeps one of them. 14180 splitsh.sh = dummysh; 14181 while (hitbdry < 2) { 14182 if (checksubfaces && splitsh.sh == dummysh) { 14183 tspivot(spintet, splitsh); 14184 } 14185 if (fnextself(spintet)) { 14186 if (apex(spintet) == n1) break; 14187 wrapcount++; 14188 } else { 14189 hitbdry ++; 14190 if (hitbdry < 2) { 14191 esym(*splittet, spintet); 14192 } 14193 } 14194 } 14195 if (hitbdry > 0) { 14196 // ab is on the hull. 14197 wrapcount -= 1; 14198 // 'spintet' now is a hull face, inverse its edge direction. 14199 esym(spintet, *splittet); 14200 // Split two hull faces increases the number of hull faces. 14201 hullsize += 2; 14202 } 14203 } 14204 14205 // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra. 14206 bots = new triface[wrapcount]; 14207 newtops = new triface[wrapcount]; 14208 // Spin around av, gather tetrahedra and set up new tetrahedra. 14209 spintet = *splittet; 14210 for (i = 0; i < wrapcount; i++) { 14211 // Get 'bots[i] = an1n2v'. 14212 enext2fnext(spintet, bots[i]); 14213 esymself(bots[i]); 14214 // Get 'oldtop = n1n2va'. 14215 enextfnext(bots[i], oldtop); 14216 // Get 'newtops[i] = 'bn1n2v' 14217 fnext(oldtop, newtops[i]); // newtop = n1n2bv 14218 esymself(newtops[i]); // newtop = n2n1bv 14219 enext2self(newtops[i]); // newtop = bn2n1v 14220 // Go to the next. 14221 fnextself(spintet); 14222 if (checksubfaces && avseg.sh != dummysh) { 14223 if (!issymexist(&spintet)) { 14224 // We meet a hull face, walk through it. 14225 tspivot(spintet, spinsh); 14226 #ifdef SELF_CHECK 14227 assert(spinsh.sh != dummysh); 14228 #endif 14229 findedge(&spinsh, pa, pv); 14230 sfnextself(spinsh); 14231 stpivot(spinsh, spintet); 14232 #ifdef SELF_CHECK 14233 assert(spintet.tet != dummytet); 14234 #endif 14235 findedge(&spintet, pa, pv); 14236 } 14237 } 14238 } 14239 14240 if (b->verbose > 1) { 14241 printf(" Removing point %d from edge (%d, %d).\n", 14242 pointmark(oppo(bots[0])), pointmark(org(bots[0])), 14243 pointmark(org(newtops[0]))); 14244 } 14245 14246 for (i = 0; i < wrapcount; i++) { 14247 // Expand an1n2v to an1n2b. 14248 setoppo(bots[i], org(newtops[i])); 14249 // Get 'oldtop = n1n2va' from 'bot[i]'. 14250 enextfnext(bots[i], oldtop); 14251 // Get 'topcasing' from 'newtop[i]' 14252 sym(newtops[i], topcasing); 14253 // Bond them. 14254 bond(oldtop, topcasing); 14255 if (checksubfaces) { 14256 tspivot(newtops[i], topsh); 14257 if (topsh.sh != dummysh) { 14258 tsbond(oldtop, topsh); 14259 } 14260 } 14261 // Delete the tetrahedron above an1n2v. 14262 tetrahedrondealloc(newtops[i].tet); 14263 } 14264 14265 // If there exists any subface, unsplit them. 14266 if (checksubfaces) { 14267 if (avseg.sh != dummysh) { 14268 spivot(avseg, splitsh); 14269 #ifdef SELF_CHECK 14270 assert(splitsh.sh != dummysh); 14271 #endif 14272 } 14273 if (splitsh.sh != dummysh) { 14274 findedge(&splitsh, pa, pv); 14275 unsplitsubedge(&splitsh); 14276 } 14277 } 14278 14279 delete [] bots; 14280 delete [] newtops; 14281 } 14282 14284 // // 14285 // splitsubedge() Insert a point on an edge of the surface mesh. // 14286 // // 14287 // The splitting edge is given by 'splitsh'. Assume its three corners are a, // 14288 // b, c, where ab is the edge will be split. ab may be a subsegment. // 14289 // // 14290 // To split edge ab is to split all subfaces conatining ab. If ab is not a // 14291 // subsegment, there are only two subfaces need be split, otherwise, there // 14292 // may have any number of subfaces need be split. Each splitting subface abc // 14293 // is shrunk to avc, a new subface vbc is created. It is important to keep // 14294 // the orientations of edge rings of avc and vbc be the same as abc's. If ab // 14295 // is a subsegment, it is shrunk to av and a new subsegment vb is created. // 14296 // // 14297 // If there are tetrahedra adjoining to the splitting subfaces, they should // 14298 // be split before calling this routine, so the connection between the new // 14299 // tetrahedra and the new subfaces can be correctly set. // 14300 // // 14301 // On completion, 'splitsh' returns avc. If 'flipqueue' is not NULL, it // 14302 // returns all edges which may be non-Delaunay. // 14303 // // 14305 14306 void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue) 14307 { 14308 triface abcd, bace, vbcd, bvce; 14309 face startabc, spinabc, spinsh; 14310 face oldbc, bccasin, bccasout; 14311 face ab, bc; 14312 face avc, vbc, vbc1; 14313 face av, vb; 14314 point pa, pb; 14315 14316 startabc = *splitsh; 14317 // Is there a subsegment? 14318 sspivot(startabc, ab); 14319 if (ab.sh != dummysh) { 14320 ab.shver = 0; 14321 if (sorg(startabc) != sorg(ab)) { 14322 sesymself(startabc); 14323 } 14324 } 14325 pa = sorg(startabc); 14326 pb = sdest(startabc); 14327 14328 if (b->verbose > 1) { 14329 printf(" Inserting point %d on subedge (%d, %d) %s.\n", 14330 pointmark(newpoint), pointmark(pa), pointmark(pb), 14331 (ab.sh != dummysh ? "(seg)" : " ")); 14332 } 14333 14334 // Spin arround ab, split every subface containing ab. 14335 spinabc = startabc; 14336 do { 14337 // Adjust spinabc be edge ab. 14338 if (sorg(spinabc) != pa) { 14339 sesymself(spinabc); 14340 } 14341 // Save old configuration at edge bc, if bc has a subsegment, save the 14342 // face link of it and dissolve it from bc. 14343 senext(spinabc, oldbc); 14344 spivot(oldbc, bccasout); 14345 sspivot(oldbc, bc); 14346 if (bc.sh != dummysh) { 14347 if (spinabc.sh != bccasout.sh) { 14348 // 'spinabc' is not self-bonded. 14349 spinsh = bccasout; 14350 do { 14351 bccasin = spinsh; 14352 spivotself(spinsh); 14353 } while (spinsh.sh != oldbc.sh); 14354 } else { 14355 bccasout.sh = dummysh; 14356 } 14357 ssdissolve(oldbc); 14358 } 14359 // Create a new subface. 14360 makeshellface(subfaces, &vbc); 14361 // Split abc. 14362 avc = spinabc; // Update 'abc' to 'avc'. 14363 setsdest(avc, newpoint); 14364 // Make 'vbc' be in the same edge ring as 'avc'. 14365 vbc.shver = avc.shver; 14366 setsorg(vbc, newpoint); // Set 'vbc'. 14367 setsdest(vbc, pb); 14368 setsapex(vbc, sapex(avc)); 14369 if (b->quality && varconstraint) { 14370 // Copy the area bound into the new subface. 14371 setareabound(vbc, areabound(avc)); 14372 } 14373 // Copy the shell marker and shell type into the new subface. 14374 setshellmark(vbc, shellmark(avc)); 14375 setshelltype(vbc, shelltype(avc)); 14376 if (checkpbcs) { 14377 // Copy the pbcgroup into the new subface. 14378 setshellpbcgroup(vbc, shellpbcgroup(avc)); 14379 } 14380 // Set the connection between updated and new subfaces. 14381 senext2self(vbc); 14382 sbond(vbc, oldbc); 14383 // Set the connection between new subface and casings. 14384 senext2self(vbc); 14385 if (bc.sh != dummysh) { 14386 if (bccasout.sh != dummysh) { 14387 // Insert 'vbc' into face link. 14388 sbond1(bccasin, vbc); 14389 sbond1(vbc, bccasout); 14390 } else { 14391 // Bond 'vbc' to itself. 14392 sbond(vbc, vbc); 14393 } 14394 ssbond(vbc, bc); 14395 } else { 14396 sbond(vbc, bccasout); 14397 } 14398 // Go to next subface at edge ab. 14399 spivotself(spinabc); 14400 if (spinabc.sh == dummysh) { 14401 break; // 'ab' is a hull edge. 14402 } 14403 } while (spinabc.sh != startabc.sh); 14404 14405 // Get the new subface vbc above the updated subface avc (= startabc). 14406 senext(startabc, oldbc); 14407 spivot(oldbc, vbc); 14408 if (sorg(vbc) == newpoint) { 14409 sesymself(vbc); 14410 } 14411 #ifdef SELF_CHECK 14412 assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc)); 14413 #endif 14414 senextself(vbc); 14415 // Set the face link for the new created subfaces around edge vb. 14416 spinabc = startabc; 14417 do { 14418 // Go to the next subface at edge av. 14419 spivotself(spinabc); 14420 if (spinabc.sh == dummysh) { 14421 break; // 'ab' is a hull edge. 14422 } 14423 if (sorg(spinabc) != pa) { 14424 sesymself(spinabc); 14425 } 14426 // Get the new subface vbc1 above the updated subface avc (= spinabc). 14427 senext(spinabc, oldbc); 14428 spivot(oldbc, vbc1); 14429 if (sorg(vbc1) == newpoint) { 14430 sesymself(vbc1); 14431 } 14432 #ifdef SELF_CHECK 14433 assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc)); 14434 #endif 14435 senextself(vbc1); 14436 // Set the connection: vbc->vbc1. 14437 sbond1(vbc, vbc1); 14438 // For the next connection. 14439 vbc = vbc1; 14440 } while (spinabc.sh != startabc.sh); 14441 14442 // Split ab if it is a subsegment. 14443 if (ab.sh != dummysh) { 14444 // Update subsegment ab to av. 14445 av = ab; 14446 setsdest(av, newpoint); 14447 // Create a new subsegment vb. 14448 makeshellface(subsegs, &vb); 14449 setsorg(vb, newpoint); 14450 setsdest(vb, pb); 14451 // vb gets the same mark and segment type as av. 14452 setshellmark(vb, shellmark(av)); 14453 setshelltype(vb, shelltype(av)); 14454 if (b->quality && varconstraint) { 14455 // Copy the area bound into the new subsegment. 14456 setareabound(vb, areabound(av)); 14457 } 14458 // Save the old connection at ab (re-use the handles oldbc, bccasout). 14459 senext(av, oldbc); 14460 spivot(oldbc, bccasout); 14461 // Bond av and vb (bonded at their "fake" edges). 14462 senext2(vb, bccasin); 14463 sbond(bccasin, oldbc); 14464 if (bccasout.sh != dummysh) { 14465 // There is a subsegment connecting with ab at b. It will connect 14466 // to vb at b after splitting. 14467 bccasout.shver = 0; 14468 if (sorg(bccasout) != pb) sesymself(bccasout); 14469 #ifdef SELF_CHECK 14470 assert(sorg(bccasout) == pb); 14471 #endif 14472 senext2self(bccasout); 14473 senext(vb, bccasin); 14474 sbond(bccasin, bccasout); 14475 } 14476 // Bond all new subfaces (vbc) to vb. 14477 spinabc = startabc; 14478 do { 14479 // Adjust spinabc be edge av. 14480 if (sorg(spinabc) != pa) { 14481 sesymself(spinabc); 14482 } 14483 // Get new subface vbc above the updated subface avc (= spinabc). 14484 senext(spinabc, oldbc); 14485 spivot(oldbc, vbc); 14486 if (sorg(vbc) == newpoint) { 14487 sesymself(vbc); 14488 } 14489 senextself(vbc); 14490 // Bond the new subface and the new subsegment. 14491 ssbond(vbc, vb); 14492 // Go to the next. 14493 spivotself(spinabc); 14494 #ifdef SELF_CHECK 14495 assert(spinabc.sh != dummysh); 14496 #endif 14497 } while (spinabc.sh != startabc.sh); 14498 } 14499 14500 // Bond the new subfaces to new tetrahedra if they exist. New tetrahedra 14501 // should have been created before calling this routine. 14502 spinabc = startabc; 14503 do { 14504 // Adjust spinabc be edge av. 14505 if (sorg(spinabc) != pa) { 14506 sesymself(spinabc); 14507 } 14508 // Get new subface vbc above the updated subface avc (= spinabc). 14509 senext(spinabc, oldbc); 14510 spivot(oldbc, vbc); 14511 if (sorg(vbc) == newpoint) { 14512 sesymself(vbc); 14513 } 14514 senextself(vbc); 14515 // Get the adjacent tetrahedra at 'spinabc'. 14516 stpivot(spinabc, abcd); 14517 if (abcd.tet != dummytet) { 14518 findedge(&abcd, sorg(spinabc), sdest(spinabc)); 14519 enextfnext(abcd, vbcd); 14520 fnextself(vbcd); 14521 #ifdef SELF_CHECK 14522 assert(vbcd.tet != dummytet); 14523 #endif 14524 tsbond(vbcd, vbc); 14525 sym(vbcd, bvce); 14526 sesymself(vbc); 14527 tsbond(bvce, vbc); 14528 } else { 14529 // One side is empty, check the other side. 14530 sesymself(spinabc); 14531 stpivot(spinabc, bace); 14532 if (bace.tet != dummytet) { 14533 findedge(&bace, sorg(spinabc), sdest(spinabc)); 14534 enext2fnext(bace, bvce); 14535 fnextself(bvce); 14536 #ifdef SELF_CHECK 14537 assert(bvce.tet != dummytet); 14538 #endif 14539 sesymself(vbc); 14540 tsbond(bvce, vbc); 14541 } 14542 } 14543 // Go to the next. 14544 spivotself(spinabc); 14545 if (spinabc.sh == dummysh) { 14546 break; // 'ab' is a hull edge. 14547 } 14548 } while (spinabc.sh != startabc.sh); 14549 14550 if (b->verbose > 3) { 14551 spinabc = startabc; 14552 do { 14553 // Adjust spinabc be edge av. 14554 if (sorg(spinabc) != pa) { 14555 sesymself(spinabc); 14556 } 14557 printf(" Updating abc:\n"); 14558 printsh(&spinabc); 14559 // Get new subface vbc above the updated subface avc (= spinabc). 14560 senext(spinabc, oldbc); 14561 spivot(oldbc, vbc); 14562 if (sorg(vbc) == newpoint) { 14563 sesymself(vbc); 14564 } 14565 senextself(vbc); 14566 printf(" Creating vbc:\n"); 14567 printsh(&vbc); 14568 // Go to the next. 14569 spivotself(spinabc); 14570 if (spinabc.sh == dummysh) { 14571 break; // 'ab' is a hull edge. 14572 } 14573 } while (spinabc.sh != startabc.sh); 14574 } 14575 14576 if (flipqueue != (queue *) NULL) { 14577 spinabc = startabc; 14578 do { 14579 // Adjust spinabc be edge av. 14580 if (sorg(spinabc) != pa) { 14581 sesymself(spinabc); 14582 } 14583 senext2(spinabc, oldbc); // Re-use oldbc. 14584 enqueueflipedge(oldbc, flipqueue); 14585 // Get new subface vbc above the updated subface avc (= spinabc). 14586 senext(spinabc, oldbc); 14587 spivot(oldbc, vbc); 14588 if (sorg(vbc) == newpoint) { 14589 sesymself(vbc); 14590 } 14591 senextself(vbc); 14592 senext(vbc, oldbc); // Re-use oldbc. 14593 enqueueflipedge(oldbc, flipqueue); 14594 // Go to the next. 14595 spivotself(spinabc); 14596 if (spinabc.sh == dummysh) { 14597 break; // 'ab' is a hull edge. 14598 } 14599 } while (spinabc.sh != startabc.sh); 14600 } 14601 } 14602 14604 // // 14605 // unsplitsubedge() Reverse the operation of splitting an edge of subface,// 14606 // so as to remove a point from the edge. // 14607 // // 14608 // Assume the original edge is ab, the subface containing it is abc. It was // 14609 // split by a point v into avc, and vbc. 'splitsh' represents avc, further- // 14610 // more, if av is a subsegment, av should be the zero version of the split // 14611 // subsegment (i.e., av.shver = 0), so we are sure that the destination (v) // 14612 // of both avc and av is the deleting point. // 14613 // // 14614 // To remove point v is to expand avc to abc, delete vbc, do the same for // 14615 // other subfaces containing av and vb. If av and vb are subsegments, expand // 14616 // av to ab, delete vb. On completion, point v is not deleted. // 14617 // // 14619 14620 void tetgenmesh::unsplitsubedge(face* splitsh) 14621 { 14622 face startavc, spinavc, spinbcv; 14623 face oldvc, bccasin, bccasout, spinsh; 14624 face av, vb, bc; 14625 point pa, pv, pb; 14626 14627 startavc = *splitsh; 14628 sspivot(startavc, av); 14629 if (av.sh != dummysh) { 14630 // Orient the direction of subsegment to conform the subface. 14631 if (sorg(av) != sorg(startavc)) { 14632 sesymself(av); 14633 } 14634 #ifdef SELF_CHECK 14635 assert(av.shver == 0); 14636 #endif 14637 } 14638 senext(startavc, oldvc); 14639 spivot(oldvc, vb); // vb is subface vbc 14640 if (sorg(vb) != sdest(oldvc)) { 14641 sesymself(vb); 14642 } 14643 senextself(vb); 14644 pa = sorg(startavc); 14645 pv = sdest(startavc); 14646 pb = sdest(vb); 14647 14648 if (b->verbose > 1) { 14649 printf(" Removing point %d from subedge (%d, %d).\n", 14650 pointmark(pv), pointmark(pa), pointmark(pb)); 14651 } 14652 14653 // Spin arround av, unsplit every subface containing av. 14654 spinavc = startavc; 14655 do { 14656 // Adjust spinavc be edge av. 14657 if (sorg(spinavc) != pa) { 14658 sesymself(spinavc); 14659 } 14660 // Save old configuration at edge bc, if bc has a subsegment, save the 14661 // face link of it. 14662 senext(spinavc, oldvc); 14663 spivot(oldvc, spinbcv); 14664 if (sorg(spinbcv) != sdest(oldvc)) { 14665 sesymself(spinbcv); 14666 } 14667 senext2self(spinbcv); 14668 spivot(spinbcv, bccasout); 14669 sspivot(spinbcv, bc); 14670 if (bc.sh != dummysh) { 14671 if (spinbcv.sh != bccasout.sh) { 14672 // 'spinbcv' is not self-bonded. 14673 spinsh = bccasout; 14674 do { 14675 bccasin = spinsh; 14676 spivotself(spinsh); 14677 } while (spinsh.sh != spinbcv.sh); 14678 } else { 14679 bccasout.sh = dummysh; 14680 } 14681 } 14682 // Expand avc to abc. 14683 setsdest(spinavc, pb); 14684 if (bc.sh != dummysh) { 14685 if (bccasout.sh != dummysh) { 14686 sbond1(bccasin, oldvc); 14687 sbond1(oldvc, bccasout); 14688 } else { 14689 // Bond 'oldbc' to itself. 14690 sbond(oldvc, oldvc); 14691 } 14692 ssbond(oldvc, bc); 14693 } else { 14694 sbond(oldvc, bccasout); 14695 } 14696 // Delete bcv. 14697 shellfacedealloc(subfaces, spinbcv.sh); 14698 // Go to next subface at edge av. 14699 spivotself(spinavc); 14700 if (spinavc.sh == dummysh) { 14701 break; // 'av' is a hull edge. 14702 } 14703 } while (spinavc.sh != startavc.sh); 14704 14705 // Is there a subsegment need to be unsplit? 14706 if (av.sh != dummysh) { 14707 senext(av, oldvc); // Re-use oldvc. 14708 spivot(oldvc, vb); 14709 vb.shver = 0; 14710 #ifdef SELF_CHECK 14711 assert(sdest(av) == sorg(vb)); 14712 #endif 14713 senext(vb, spinbcv); // Re-use spinbcv. 14714 spivot(spinbcv, bccasout); 14715 // Expand av to ab. 14716 setsdest(av, pb); 14717 sbond(oldvc, bccasout); 14718 // Delete vb. 14719 shellfacedealloc(subsegs, vb.sh); 14720 } 14721 } 14722 14724 // // 14725 // insertsite() Insert a point into the mesh. // 14726 // // 14727 // The 'newpoint' is located. If 'searchtet->tet' is not NULL, the search // 14728 // for the containing tetrahedron begins from 'searchtet', otherwise, a full // 14729 // point location procedure is called. If 'newpoint' is found inside a // 14730 // tetrahedron, the tetrahedron is split into four (by splittetrahedron()); // 14731 // if 'newpoint' lies on a face, the face is split into three, thereby // 14732 // splitting the two adjacent tetrahedra into six (by splittetface()); if // 14733 // 'newpoint' lies on an edge, the edge is split into two, thereby, every // 14734 // tetrahedron containing this edge is split into two. If 'newpoint' lies on // 14735 // an existing vertex, no action is taken, and the value DUPLICATEPOINT is // 14736 // returned and 'searchtet' is set to a handle whose origin is the vertex. // 14737 // // 14738 // If 'flipqueue' is not NULL, after 'newpoint' is inserted, it returns all // 14739 // faces which may become non-Delaunay due to the newly inserted point. Flip // 14740 // operations can be performed as necessary on them to maintain the Delaunay // 14741 // property. // 14742 // // 14744 14745 enum tetgenmesh::insertsiteresult tetgenmesh::insertsite(point newpoint, 14746 triface* searchtet, bool approx, queue* flipqueue) 14747 { 14748 enum locateresult intersect, exactloc; 14749 point checkpt; 14750 REAL epspp, checklen; 14751 int count; 14752 14753 if (b->verbose > 1) { 14754 printf(" Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n", 14755 newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint)); 14756 } 14757 14758 if (searchtet->tet == (tetrahedron *) NULL) { 14759 // Search for a tetrahedron containing 'newpoint'. 14760 searchtet->tet = dummytet; 14761 exactloc = locate(newpoint, searchtet); 14762 } else { 14763 // Start searching from the tetrahedron provided by the caller. 14764 exactloc = preciselocate(newpoint, searchtet, tetrahedrons->items); 14765 } 14766 intersect = exactloc; 14767 if (approx && (exactloc != ONVERTEX)) { 14768 // Adjust the exact location to an approx. location wrt. epsilon. 14769 epspp = b->epsilon; 14770 count = 0; 14771 while (count < 16) { 14772 intersect = adjustlocate(newpoint, searchtet, exactloc, epspp); 14773 if (intersect == ONVERTEX) { 14774 checkpt = org(*searchtet); 14775 checklen = distance(checkpt, newpoint); 14776 if (checklen / longest > b->epsilon) { 14777 epspp *= 1e-2; 14778 count++; 14779 continue; 14780 } 14781 } 14782 break; 14783 } 14784 } 14785 // Keep current search state for next searching. 14786 recenttet = *searchtet; 14787 14788 // Insert the point using the right routine 14789 switch (intersect) { 14790 case ONVERTEX: 14791 // There's already a vertex there. Return in 'searchtet' a tetrahedron 14792 // whose origin is the existing vertex. 14793 if (b->verbose > 1) { 14794 printf(" Not insert for duplicating point.\n"); 14795 } 14796 return DUPLICATEPOINT; 14797 14798 case OUTSIDE: 14799 if (b->verbose > 1) { 14800 printf(" Not insert for locating outside the mesh.\n"); 14801 } 14802 return OUTSIDEPOINT; 14803 14804 case ONEDGE: 14805 // 'newpoint' falls on an edge. 14806 splittetedge(newpoint, searchtet, flipqueue); 14807 return SUCCESSONEDGE; 14808 14809 case ONFACE: 14810 // 'newpoint' falls on a face. 14811 splittetface(newpoint, searchtet, flipqueue); 14812 return SUCCESSONFACE; 14813 14814 case INTETRAHEDRON: 14815 // 'newpoint' falls inside a tetrahedron. 14816 splittetrahedron(newpoint, searchtet, flipqueue); 14817 return SUCCESSINTET; 14818 14819 default: 14820 // Impossible case. 14821 return OUTSIDEPOINT; 14822 } 14823 } 14824 14826 // // 14827 // undosite() Undo the most recently point insertion. // 14828 // // 14829 // 'insresult' indicates in where the newpoint has been inserted, i.e., in a // 14830 // tetrahedron, on a face, or on an edge. A correspoding routine will be // 14831 // called to undo the point insertion. 'splittet' is a handle represent one // 14832 // of the resulting tetrahedra, but it may be changed after transformation, // 14833 // even may be dead. Four points 'torg', ... 'toppo' are the corners which // 14834 // 'splittet' should have. On finish, 'newpoint' is not removed. // 14835 // // 14837 14838 void tetgenmesh::undosite(enum insertsiteresult insresult, triface* splittet, 14839 point torg, point tdest, point tapex, point toppo) 14840 { 14841 // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'. 14842 findface(splittet, torg, tdest, tapex); 14843 if (oppo(*splittet) != toppo) { 14844 symself(*splittet); 14845 #ifdef SELF_CHECK 14846 assert(oppo(*splittet) == toppo); 14847 #endif 14848 // The sym() operation may inverse the edge, correct it if so. 14849 findedge(splittet, torg, tdest); 14850 } 14851 14852 // Unsplit the tetrahedron according to 'insresult'. 14853 switch (insresult) { 14854 case SUCCESSINTET: 14855 // 'splittet' should be the face with 'newpoint' as its opposite. 14856 unsplittetrahedron(splittet); 14857 break; 14858 case SUCCESSONFACE: 14859 // 'splittet' should be the one of three splitted face with 'newpoint' 14860 // as its apex. 14861 unsplittetface(splittet); 14862 break; 14863 case SUCCESSONEDGE: 14864 // 'splittet' should be the tet with destination is 'newpoint'. 14865 unsplittetedge(splittet); 14866 break; 14867 default: // To omit compile warnings. 14868 break; 14869 } 14870 } 14871 14873 // // 14874 // closeopenface() Close "open" faces recursively. // 14875 // // 14876 // This is the support routine of inserthullsite(). A point p which lies out-// 14877 // side of CH(T). p is inserted to T by forming a tet t from p and a visible // 14878 // CH face f. The three sides of f which have p as a vertex is called "open" // 14879 // face. Each open face will be closed by either creating a tet on top of it // 14880 // or become a new CH face. // 14881 // // 14883 14884 void tetgenmesh::closeopenface(triface* openface, queue* flipque) 14885 { 14886 triface newtet, oldhull; 14887 triface newopenface, closeface; 14888 point inspoint, pa, pb, pc; 14889 REAL attrib, volume; 14890 int i; 14891 14892 // Get the new point p. 14893 inspoint = apex(*openface); 14894 // Find the old CH face f_o (f and f_o share the same edge). 14895 esym(*openface, oldhull); 14896 while (fnextself(oldhull)) ; 14897 if (apex(oldhull) != inspoint) { 14898 // Is f_o visible by p? 14899 pa = org(oldhull); 14900 pb = dest(oldhull); 14901 pc = apex(oldhull); 14902 if (orient3d(pa, pb, pc, inspoint) < 0.0) { 14903 // Yes. Create a new tet t above f_o. 14904 maketetrahedron(&newtet); 14905 setorg(newtet, pa); 14906 setdest(newtet, pb); 14907 setapex(newtet, pc); 14908 setoppo(newtet, inspoint); 14909 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 14910 attrib = elemattribute(oldhull.tet, i); 14911 setelemattribute(newtet.tet, i, attrib); 14912 } 14913 if (b->varvolume) { 14914 volume = volumebound(oldhull.tet); 14915 setvolumebound(newtet.tet, volume); 14916 } 14917 // Connect t to T. 14918 bond(newtet, oldhull); 14919 // Close f. 14920 fnext(newtet, newopenface); 14921 bond(newopenface, *openface); 14922 // f_o becomes an interior face. 14923 enqueueflipface(oldhull, flipque); 14924 // Hull face number decreases. 14925 hullsize--; 14926 // Two faces of t become open face. 14927 enextself(newtet); 14928 for (i = 0; i < 2; i++) { 14929 fnext(newtet, newopenface); 14930 sym(newopenface, closeface); 14931 if (closeface.tet == dummytet) { 14932 closeopenface(&newopenface, flipque); 14933 } 14934 enextself(newtet); 14935 } 14936 } else { 14937 // Inivisible. f becomes a new CH face. 14938 hullsize++; 14939 // Let 'dummytet' holds f for the next point location. 14940 dummytet[0] = encode(*openface); 14941 } 14942 } else { 14943 // f_o is co-incident with f --> f is closed by f_o. 14944 bond(*openface, oldhull); 14945 // f is an interior face. 14946 enqueueflipface(*openface, flipque); 14947 } 14948 } 14949 14951 // // 14952 // inserthullsite() Insert a point which lies outside the convex hull. // 14953 // // 14954 // The 'inspoint' p lies outside the tetrahedralization T. The 'horiz' f is // 14955 // on the convex hull of T, CH(T), which is visible by p (Imagine f is para- // 14956 // llel to the horizon). To insert p into T we have to enlarge the CH(T) and // 14957 // update T so that p is on the new CH(T). // 14958 // // 14959 // To enlarge the CH(T). We need to find the set F of faces which are on CH // 14960 // (T) and visible by p (F can be formed by a depth-first search from f). p // 14961 // is then inserted into T by mounting new tets formed by p and these faces. // 14962 // Faces of F become interior faces and may non-locally Delaunay. They are // 14963 // queued in 'flipqueue' for flip tests. // 14964 // // 14966 14967 void tetgenmesh::inserthullsite(point inspoint, triface* horiz, queue* flipque) 14968 { 14969 triface firstnewtet; 14970 triface openface, closeface; 14971 REAL attrib, volume; 14972 int i; 14973 14974 // Let f face to p. 14975 adjustedgering(*horiz, CW); 14976 // Create the first tet t (from f and p). 14977 maketetrahedron(&firstnewtet); 14978 setorg (firstnewtet, org(*horiz)); 14979 setdest(firstnewtet, dest(*horiz)); 14980 setapex(firstnewtet, apex(*horiz)); 14981 setoppo(firstnewtet, inspoint); 14982 for (i = 0; i < in->numberoftetrahedronattributes; i++) { 14983 attrib = elemattribute(horiz->tet, i); 14984 setelemattribute(firstnewtet.tet, i, attrib); 14985 } 14986 if (b->varvolume) { 14987 volume = volumebound(horiz->tet); 14988 setvolumebound(firstnewtet.tet, volume); 14989 } 14990 // Connect t to T. 14991 bond(firstnewtet, *horiz); 14992 // f is not on CH(T) anymore. 14993 enqueueflipface(*horiz, flipque); 14994 // Hull face number decreases. 14995 hullsize--; 14996 14997 // Call the faces of t which have p as a vertex "open" face. 14998 for (i = 0; i < 3; i++) { 14999 // Get an open face f_i of t. 15000 fnext(firstnewtet, openface); 15001 // Close f_i if it is still open. 15002 sym(openface, closeface); 15003 if (closeface.tet == dummytet) { 15004 closeopenface(&openface, flipque); 15005 } 15006 // Go to the next open face of t. 15007 enextself(firstnewtet); 15008 } 15009 } 15010 15012 // // 15013 // Terminology: BC(p) and CBC(p), B(p) and C(p). // 15014 // // 15015 // Given an arbitrary point p, the Bowyer-Watson cavity BC(p) is formed by // 15016 // tets whose circumspheres containing p. The outer faces of BC(p) form a // 15017 // polyhedron B(p). // 15018 // // 15019 // If p is on a facet F, the constrained Bowyer-Watson cavity CBC(p) on F is // 15020 // formed by subfaces of F whose circumspheres containing p. The outer edges // 15021 // of CBC(p) form a polygon C(p). B(p) is separated into two parts by C(p), // 15022 // denoted as B_1(p) and B_2(p), one of them may be empty (F is on the hull).// 15023 // // 15024 // If p is on a segment S which is shared by n facets. There exist n C(p)s, // 15025 // each one is a non-closed polygon (without S). B(p) is split into n parts, // 15026 // each of them is denoted as B_i(p), some B_i(p) may be empty. // 15027 // // 15029 15031 // // 15032 // formbowatcavitysub() Form CBC(p) and C(p) on a facet F. // 15033 // // 15034 // Parameters: bp = p, bpseg = S, sublist = CBC(p), subceillist = C(p). // 15035 // // 15036 // CBC(p) contains at least one subface on input; S may be NULL which means // 15037 // that p is inside a facet. On output, all subfaces of CBC(p) are infected, // 15038 // and the edge rings are oriented to the same halfspace. // 15039 // // 15041 15042 void tetgenmesh::formbowatcavitysub(point bp, face* bpseg, list* sublist, 15043 list* subceillist) 15044 { 15045 triface adjtet; 15046 face startsh, neighsh; 15047 face checkseg; 15048 point pa, pb, pc, pd; 15049 REAL sign; 15050 int i, j; 15051 15052 // Form CBC(p) and C(p) by a broadth-first searching. 15053 for (i = 0; i < sublist->len(); i++) { 15054 startsh = * (face *)(* sublist)[i]; // startsh = f. 15055 // Look for three neighbors of f. 15056 for (j = 0; j < 3; j++) { 15057 sspivot(startsh, checkseg); 15058 if (checkseg.sh == dummysh) { 15059 // Get its neighbor n. 15060 spivot(startsh, neighsh); 15061 // Is n already in CBC(p)? 15062 if (!sinfected(neighsh)) { 15063 stpivot(neighsh, adjtet); 15064 if (adjtet.tet == dummytet) { 15065 sesymself(neighsh); 15066 stpivot(neighsh, adjtet); 15067 } 15068 // For positive orientation that insphere() test requires. 15069 adjustedgering(adjtet, CW); 15070 pa = org(adjtet); 15071 pb = dest(adjtet); 15072 pc = apex(adjtet); 15073 pd = oppo(adjtet); 15074 sign = insphere(pa, pb, pc, pd, bp); 15075 if (sign >= 0.0) { 15076 // Orient edge ring of n according to that of f. 15077 if (sorg(neighsh) != sdest(startsh)) sesymself(neighsh); 15078 // Collect it into CBC(p). 15079 sinfect(neighsh); 15080 sublist->append(&neighsh); 15081 } else { 15082 subceillist->append(&startsh); // Found an edge of C(p). 15083 } 15084 } 15085 } else { 15086 // Do not cross a segment. 15087 if (bpseg != (face *) NULL) { 15088 if (checkseg.sh != bpseg->sh) { 15089 subceillist->append(&startsh); // Found an edge of C(p). 15090 } 15091 } else { 15092 subceillist->append(&startsh); // Found an edge of C(p). 15093 } 15094 } 15095 senextself(startsh); 15096 } 15097 } 15098 15099 if (b->verbose > 2) { 15100 printf(" Collect CBC(%d): %d subfaces, %d edges.\n", pointmark(bp), 15101 sublist->len(), subceillist->len()); 15102 } 15103 } 15104 15106 // // 15107 // formbowatcavityquad() Form BC_i(p) and B_i(p) in a quadrant. // 15108 // // 15109 // Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). // 15110 // // 15111 // BC_i(p) contains at least one tet on input. On finish, all tets collected // 15112 // in BC_i(p) are infected. B_i(p) may not closed when p is on segment or in // 15113 // facet. C(p) must be formed before this routine. Check the infect flag of // 15114 // a subface to identify the unclosed side of B_i(p). These sides will be // 15115 // closed by new subfaces of C(p)s. // 15116 // // 15118 15119 void tetgenmesh::formbowatcavityquad(point bp, list* tetlist, list* ceillist) 15120 { 15121 triface starttet, neightet; 15122 face checksh; 15123 point pa, pb, pc, pd; 15124 REAL sign; 15125 int i; 15126 15127 // Form BC_i(p) and B_i(p) by a broadth-first searching. 15128 for (i = 0; i < tetlist->len(); i++) { 15129 starttet = * (triface *)(* tetlist)[i]; 15130 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { 15131 // Try to collect the neighbor of the face (f). 15132 tspivot(starttet, checksh); 15133 if (checksh.sh == dummysh) { 15134 // Get its neighbor n. 15135 sym(starttet, neightet); 15136 // Is n already in BC_i(p)? 15137 if (!infected(neightet)) { 15138 // For positive orientation that insphere() test requires. 15139 adjustedgering(neightet, CW); 15140 pa = org(neightet); 15141 pb = dest(neightet); 15142 pc = apex(neightet); 15143 pd = oppo(neightet); 15144 sign = insphere(pa, pb, pc, pd, bp); 15145 if (sign >= 0.0) { 15146 // Collect it into BC_i(p). 15147 infect(neightet); 15148 tetlist->append(&neightet); 15149 } else { 15150 ceillist->append(&starttet); // Found a face of B_i(p). 15151 } 15152 } 15153 } else { 15154 // Do not cross a boundary face. 15155 if (!sinfected(checksh)) { 15156 ceillist->append(&starttet); // Found a face of B_i(p). 15157 } 15158 } 15159 } 15160 } 15161 15162 if (b->verbose > 2) { 15163 printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp), 15164 tetlist->len(), ceillist->len()); 15165 } 15166 } 15167 15169 // // 15170 // formbowatcavitysegquad() Form BC_i(p) and B_i(p) in a segment quadrant.// 15171 // // 15172 // Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). // 15173 // // 15174 // BC_i(p) contains at least one tet on input. On finish, all tets collected // 15175 // in BC_i(p) are infected. B_i(p) is not closed. C(p) must be formed before // 15176 // this routine. Check the infect flag of a subface to identify the unclosed // 15177 // sides of B_i(p). These sides will be closed by new subfaces of C(p)s. // 15178 // // 15179 // During the repair of encroaching subsegments, there may exist locally non-// 15180 // Delaunay faces. These faces are collected in BC_i(p) either. B_i(p) has // 15181 // to be formed later than BC_i(p). // 15182 // // 15184 15185 void tetgenmesh::formbowatcavitysegquad(point bp, list* tetlist,list* ceillist) 15186 { 15187 triface starttet, neightet, cavtet; 15188 face checksh; 15189 point pa, pb, pc, pd, pe; 15190 REAL sign; 15191 int i; 15192 15193 // Form BC_i(p) by a broadth-first searching. 15194 for (i = 0; i < tetlist->len(); i++) { 15195 starttet = * (triface *)(* tetlist)[i]; 15196 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { 15197 // Try to collect the neighbor of the face f. 15198 tspivot(starttet, checksh); 15199 if (checksh.sh == dummysh) { 15200 // Get its neighbor n. 15201 sym(starttet, neightet); 15202 // Is n already in BC_i(p)? 15203 if (!infected(neightet)) { 15204 // For positive orientation that insphere() test requires. 15205 adjustedgering(neightet, CW); 15206 pa = org(neightet); 15207 pb = dest(neightet); 15208 pc = apex(neightet); 15209 pd = oppo(neightet); 15210 sign = insphere(pa, pb, pc, pd, bp); 15211 if (sign >= 0.0) { 15212 // Collect it into BC_i(p). 15213 infect(neightet); 15214 tetlist->append(&neightet); 15215 } else { 15216 // Check if the face is locally non-Delaunay. 15217 pe = oppo(starttet); 15218 sign = insphere(pa, pb, pc, pd, pe); 15219 if (sign >= 0.0) { 15220 // Collect it into BC_i(p). 15221 infect(neightet); 15222 tetlist->append(&neightet); 15223 } 15224 } 15225 } 15226 } 15227 } 15228 } 15229 15230 // Generate B_i(p). 15231 for (i = 0; i < tetlist->len(); i++) { 15232 cavtet = * (triface *)(* tetlist)[i]; 15233 for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) { 15234 tspivot(cavtet, checksh); 15235 if (checksh.sh == dummysh) { 15236 sym(cavtet, neightet); 15237 if (!infected(neightet)) { 15238 ceillist->append(&cavtet); // Found a face of B(p). 15239 } 15240 } else { 15241 // Do not cross a boundary face. 15242 if (!sinfected(checksh)) { 15243 ceillist->append(&cavtet); // Found a face of B(p). 15244 } 15245 } 15246 } 15247 } 15248 15249 if (b->verbose > 2) { 15250 printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp), 15251 tetlist->len(), ceillist->len()); 15252 } 15253 } 15254 15256 // // 15257 // formbowatcavity() Form BC(p), B(p), CBC(p)s, and C(p)s. // 15258 // // 15259 // If 'bpseg'(S) != NULL, p is on segment S, else, p is on facet containing // 15260 // 'bpsh' (F). 'n' returns the number of quadrants in BC(p). 'nmax' is the // 15261 // maximum pre-allocated array length for the lists. // 15262 // // 15264 15265 void tetgenmesh::formbowatcavity(point bp, face* bpseg, face* bpsh, int* n, 15266 int* nmax, list** sublists, list** subceillists, list** tetlists, 15267 list** ceillists) 15268 { 15269 list *sublist; 15270 triface adjtet; 15271 face startsh, spinsh; 15272 point pa, pb; 15273 int i, j; 15274 15275 *n = 0; 15276 if (bpseg != (face *) NULL) { 15277 // p is on segment S. 15278 bpseg->shver = 0; 15279 pa = sorg(*bpseg); 15280 pb = sdest(*bpseg); 15281 // Count the number of facets sharing at S. 15282 spivot(*bpseg, startsh); 15283 spinsh = startsh; 15284 do { 15285 (*n)++; // spinshlist->append(&spinsh); 15286 spivotself(spinsh); 15287 } while (spinsh.sh != startsh.sh); 15288 // *n is the number of quadrants around S. 15289 if (*n > *nmax) { 15290 // Reallocate arrays. Should not happen very often. 15291 delete [] tetlists; 15292 delete [] ceillists; 15293 delete [] sublists; 15294 delete [] subceillists; 15295 tetlists = new list*[*n]; 15296 ceillists = new list*[*n]; 15297 sublists = new list*[*n]; 15298 subceillists = new list*[*n]; 15299 *nmax = *n; 15300 } 15301 // Form CBC(p)s and C(p)s. 15302 spinsh = startsh; 15303 for (i = 0; i < *n; i++) { 15304 sublists[i] = new list(sizeof(face), NULL, 256); 15305 subceillists[i] = new list(sizeof(face), NULL, 256); 15306 // Set a subface f to start search. 15307 startsh = spinsh; 15308 // Let f face to the quadrant of interest (used in forming BC(p)). 15309 findedge(&startsh, pa, pb); 15310 sinfect(startsh); 15311 sublists[i]->append(&startsh); 15312 formbowatcavitysub(bp, bpseg, sublists[i], subceillists[i]); 15313 // Go to the next facet. 15314 spivotself(spinsh); 15315 } 15316 } else if (sublists != (list **) NULL) { 15317 // p is on a facet. 15318 *n = 2; 15319 // Form CBC(p) and C(p). 15320 sublists[0] = new list(sizeof(face), NULL, 256); 15321 subceillists[0] = new list(sizeof(face), NULL, 256); 15322 sinfect(*bpsh); 15323 sublists[0]->append(bpsh); 15324 formbowatcavitysub(bp, NULL, sublists[0], subceillists[0]); 15325 } else { 15326 // p is inside a tet. 15327 *n = 1; 15328 } 15329 15330 // Form BC_i(p) and B_i(p). 15331 for (i = 0; i < *n; i++) { 15332 tetlists[i] = new list(sizeof(triface), NULL, 256); 15333 ceillists[i] = new list(sizeof(triface), NULL, 256); 15334 if (sublists != (list **) NULL) { 15335 // There are C(p)s. 15336 sublist = ((bpseg == (face *) NULL) ? sublists[0] : sublists[i]); 15337 // Add all adjacent tets of C_i(p) into BC_i(p). 15338 for (j = 0; j < sublist->len(); j++) { 15339 startsh = * (face *)(* sublist)[j]; 15340 // Adjust the side facing to the right quadrant for C(p). 15341 if ((bpseg == (face *) NULL) && (i == 1)) sesymself(startsh); 15342 stpivot(startsh, adjtet); 15343 if (adjtet.tet != dummytet) { 15344 if (!infected(adjtet)) { 15345 infect(adjtet); 15346 tetlists[i]->append(&adjtet); 15347 } 15348 } 15349 } 15350 if (bpseg != (face *) NULL) { 15351 // The quadrant is bounded by another facet. 15352 sublist = ((i < *n - 1) ? sublists[i + 1] : sublists[0]); 15353 for (j = 0; j < sublist->len(); j++) { 15354 startsh = * (face *)(* sublist)[j]; 15355 // Adjust the side facing to the right quadrant for C(p). 15356 sesymself(startsh); 15357 stpivot(startsh, adjtet); 15358 if (adjtet.tet != dummytet) { 15359 if (!infected(adjtet)) { 15360 infect(adjtet); 15361 tetlists[i]->append(&adjtet); 15362 } 15363 } 15364 } 15365 } 15366 } 15367 // It is possible that BC_i(p) is empty. 15368 if (tetlists[i]->len() == 0) continue; 15369 // Collect the rest of tets of BC_i(p) and form B_i(p). 15370 // if (b->conformdel) { 15371 // formbowatcavitysegquad(bp, tetlists[i], ceillists[i]); 15372 // } else { 15373 formbowatcavityquad(bp, tetlists[i], ceillists[i]); 15374 // } 15375 } 15376 } 15377 15379 // // 15380 // releasebowatcavity() Undo and free the memory allocated in routine // 15381 // formbowatcavity(). // 15382 // // 15384 15385 void tetgenmesh::releasebowatcavity(face* bpseg, int n, list** sublists, 15386 list** subceillist, list** tetlists, list** ceillists) 15387 { 15388 triface oldtet; 15389 face oldsh; 15390 int i, j; 15391 15392 if (sublists != (list **) NULL) { 15393 // Release CBC(p)s. 15394 for (i = 0; i < n; i++) { 15395 // Uninfect subfaces of CBC(p). 15396 for (j = 0; j < sublists[i]->len(); j++) { 15397 oldsh = * (face *)(* (sublists[i]))[j]; 15398 #ifdef SELF_CHECK 15399 assert(sinfected(oldsh)); 15400 #endif 15401 suninfect(oldsh); 15402 } 15403 delete sublists[i]; 15404 delete subceillist[i]; 15405 sublists[i] = (list *) NULL; 15406 subceillist[i] = (list *) NULL; 15407 if (bpseg == (face *) NULL) break; 15408 } 15409 } 15410 // Release BC(p). 15411 for (i = 0; i < n; i++) { 15412 // Uninfect tets of BC_i(p). 15413 for (j = 0; j < tetlists[i]->len(); j++) { 15414 oldtet = * (triface *)(* (tetlists[i]))[j]; 15415 #ifdef SELF_CHECK 15416 assert(infected(oldtet)); 15417 #endif 15418 uninfect(oldtet); 15419 } 15420 delete tetlists[i]; 15421 delete ceillists[i]; 15422 tetlists[i] = (list *) NULL; 15423 ceillists[i] = (list *) NULL; 15424 } 15425 } 15426 15428 // // 15429 // validatebowatcavityquad() Valid B_i(p). // 15430 // // 15431 // B_i(p) is valid if all faces of B_i(p) are visible by p, else B_i(p) is // 15432 // invalid. Each tet of BC_i(p) which has such a face is marked (uninfect). // 15433 // They will be removed in updatebowatcavityquad(). // 15434 // // 15435 // Return TRUE if B(p) is valid, else, return FALSE. // 15436 // // 15438 15439 bool tetgenmesh::validatebowatcavityquad(point bp,list* ceillist,REAL maxcosd) 15440 { 15441 triface ceiltet; 15442 point pa, pb, pc; 15443 REAL ori, cosd; 15444 int remcount, i; 15445 15446 // Check the validate of B(p), cut tets having invisible faces. 15447 remcount = 0; 15448 for (i = 0; i < ceillist->len(); i++) { 15449 ceiltet = * (triface *)(* ceillist)[i]; 15450 if (infected(ceiltet)) { 15451 adjustedgering(ceiltet, CCW); 15452 pa = org(ceiltet); 15453 pb = dest(ceiltet); 15454 pc = apex(ceiltet); 15455 ori = orient3d(pa, pb, pc, bp); 15456 if (ori >= 0.0) { 15457 // Found an invisible face. 15458 uninfect(ceiltet); 15459 remcount++; 15460 continue; 15461 } 15462 // If a non-trival 'maxcosd' is given. 15463 if (maxcosd > -1.0) { 15464 // Get the maximal dihedral angle of tet abcp. 15465 tetalldihedral(pa, pb, pc, bp, NULL, &cosd, NULL); 15466 // Do not form the tet if the maximal dihedral angle is not reduced. 15467 if (cosd < maxcosd) { 15468 uninfect(ceiltet); 15469 remcount++; 15470 } 15471 } 15472 } 15473 } 15474 return remcount == 0; 15475 } 15476 15478 // // 15479 // updatebowatcavityquad() Update BC_i(p) and reform B_i(p). // 15480 // // 15481 // B_i(p) is invalid and some tets in BC_i(p) have been marked to be removed // 15482 // in validatebowatcavityquad(). This routine actually remove the cut tets // 15483 // of BC_i(p) and re-form the B_i(p). // 15484 // // 15486 15487 void tetgenmesh::updatebowatcavityquad(list* tetlist, list* ceillist) 15488 { 15489 triface cavtet, neightet; 15490 face checksh; 15491 int remcount, i; 15492 15493 remcount = 0; 15494 for (i = 0; i < tetlist->len(); i++) { 15495 cavtet = * (triface *)(* tetlist)[i]; 15496 if (!infected(cavtet)) { 15497 tetlist->del(i, 1); 15498 remcount++; 15499 i--; 15500 } 15501 } 15502 15503 // Are there tets have been cut in BC_i(p)? 15504 if (remcount > 0) { 15505 // Re-form B_i(p). 15506 ceillist->clear(); 15507 for (i = 0; i < tetlist->len(); i++) { 15508 cavtet = * (triface *)(* tetlist)[i]; 15509 for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) { 15510 tspivot(cavtet, checksh); 15511 if (checksh.sh == dummysh) { 15512 sym(cavtet, neightet); 15513 if (!infected(neightet)) { 15514 ceillist->append(&cavtet); // Found a face of B_i(p). 15515 } 15516 } else { 15517 // Do not cross a boundary face. 15518 if (!sinfected(checksh)) { 15519 ceillist->append(&cavtet); // Found a face of B_i(p). 15520 } 15521 } 15522 } 15523 } 15524 if (b->verbose > 2) { 15525 printf(" Update BC_i(p): %d tets, %d faces.\n", tetlist->len(), 15526 ceillist->len()); 15527 } 15528 } 15529 } 15530 15532 // // 15533 // updatebowatcavitysub() Check and update CBC(p) and C(p). // 15534 // // 15535 // A CBC(p) is valid if all its subfaces are inside or on the hull of BC(p). // 15536 // A subface s of CBC(p) is invalid if it is in one of the two cases: // 15537 // (1) s is completely outside BC(p); // 15538 // (2) s has two adjacent tets but only one of them is in BC(p); // 15539 // s is removed from CBC(p) if it is invalid. If there is an adjacent tet of // 15540 // s which is in BC(p), it gets removed from BC(p) too. If CBC(p) is updated,// 15541 // C(p) is re-formed. // 15542 // // 15543 // A C(p) is valid if all its edges are on the hull of BC(p). An edge e of // 15544 // C(p) may be inside BC(p) if e is a segment and belongs to only one facet. // 15545 // To correct C(p), a tet of BC(p) which shields e gets removed. // 15546 // // 15547 // If BC(p) is formed with locally non-Delaunay check (b->conformdel > 0). // 15548 // A boundary-consistent check is needed for non-segment edges of C(p). Let // 15549 // e be such an edge, the subface f contains e and outside C(p) may belong // 15550 // to B(p) due to the non-coplanarity of the facet definition. The tet of // 15551 // BC(p) containing f gets removed to avoid creating a degenerate new tet. // 15552 // // 15553 // 'cutcount' accumulates the total number of cuttets(not only by this call).// 15554 // // 15556 15557 void tetgenmesh::updatebowatcavitysub(list* sublist, list* subceillist, 15558 int* cutcount) 15559 { 15560 triface adjtet, rotface; 15561 face checksh, neighsh; 15562 face checkseg; 15563 point pa, pb, pc; 15564 REAL ori1, ori2; 15565 int remcount; 15566 int i, j; 15567 15568 remcount = 0; 15569 // Check the validity of CBC(p). 15570 for (i = 0; i < sublist->len(); i++) { 15571 checksh = * (face *)(* sublist)[i]; 15572 // Check two adjacent tets of s. 15573 for (j = 0; j < 2; j++) { 15574 stpivot(checksh, adjtet); 15575 if (adjtet.tet != dummytet) { 15576 if (!infected(adjtet)) { 15577 // Could be either case (1) or (2). 15578 suninfect(checksh); // s survives. 15579 // If the sym. adjtet exists, it should remove from BC(p) too. 15580 sesymself(checksh); 15581 stpivot(checksh, adjtet); 15582 if (adjtet.tet != dummytet) { 15583 if (infected(adjtet)) { 15584 // Found an adj. tet in BC(p), remove it. 15585 uninfect(adjtet); 15586 (*cutcount)++; 15587 } 15588 } 15589 // Remove s from C(p). 15590 sublist->del(i, 1); 15591 i--; 15592 remcount++; 15593 break; 15594 } 15595 } 15596 sesymself(checksh); 15597 } 15598 } 15599 if (remcount > 0) { 15600 if (b->verbose > 2) { 15601 printf(" Removed %d subfaces from CBC(p).\n", remcount); 15602 } 15603 // Re-generate C(p). 15604 subceillist->clear(); 15605 for (i = 0; i < sublist->len(); i++) { 15606 checksh = * (face *)(* sublist)[i]; 15607 for (j = 0; j < 3; j++) { 15608 spivot(checksh, neighsh); 15609 if (!sinfected(neighsh)) { 15610 subceillist->append(&checksh); 15611 } 15612 senextself(checksh); 15613 } 15614 } 15615 if (b->verbose > 2) { 15616 printf(" Update CBC(p): %d subs, %d edges.\n", sublist->len(), 15617 subceillist->len()); 15618 } 15619 } 15620 15621 // Check the validity of C(p). 15622 for (i = 0; i < subceillist->len(); i++) { 15623 checksh = * (face *)(* subceillist)[i]; 15624 sspivot(checksh, checkseg); 15625 if (checkseg.sh != dummysh) { 15626 // A segment. Check if it is inside BC(p). 15627 stpivot(checksh, adjtet); 15628 if (adjtet.tet == dummytet) { 15629 sesym(checksh, neighsh); 15630 stpivot(neighsh, adjtet); 15631 } 15632 findedge(&adjtet, sorg(checkseg), sdest(checkseg)); 15633 adjustedgering(adjtet, CCW); 15634 fnext(adjtet, rotface); // It's the same tet. 15635 // Rotate rotface (f), stop on either of the following cases: 15636 // (a) meet a subface, or 15637 // (b) enter an uninfected tet, or 15638 // (c) rewind back to adjtet. 15639 do { 15640 if (!infected(rotface)) break; // case (b) 15641 tspivot(rotface, neighsh); 15642 if (neighsh.sh != dummysh) break; // case (a) 15643 // Go to the next tet of the facing ring. 15644 fnextself(rotface); 15645 } while (apex(rotface) != apex(adjtet)); 15646 // Is it case (c)? 15647 if (apex(rotface) == apex(adjtet)) { 15648 // The segment is enclosed by BC(p), invalid cavity. 15649 pa = org(adjtet); 15650 pb = dest(adjtet); 15651 pc = apex(adjtet); 15652 // Find the shield tet and cut it. Notice that the shield tet may 15653 // not be unique when there are four coplanar points, ie., 15654 // ori1 * ori2 == 0.0. In such case, choose either of them. 15655 fnext(adjtet, rotface); 15656 do { 15657 fnextself(rotface); 15658 assert(infected(rotface)); 15659 ori1 = orient3d(pa, pb, pc, apex(rotface)); 15660 ori2 = orient3d(pa, pb, pc, oppo(rotface)); 15661 } while (ori1 * ori2 > 0.0); 15662 // Cut this tet from BC(p). 15663 uninfect(rotface); 15664 (*cutcount)++; 15665 } 15666 } else { 15667 /*// An edge. Check if boundary-consistency should be enforced. 15668 if (b->conformdel > 0) { 15669 // Get the adj-sub n at e, it must be outside C(p). 15670 spivot(checksh, neighsh); 15671 assert(!sinfected(neighsh)); 15672 // Check if n is on B(p). 15673 for (j = 0; j < 2; j++) { 15674 stpivot(neighsh, adjtet); 15675 if (adjtet.tet != dummytet) { 15676 if (infected(adjtet)) { 15677 uninfect(adjtet); 15678 (*cutcount)++; 15679 } 15680 } 15681 sesymself(neighsh); 15682 } 15683 } */ 15684 } 15685 } 15686 } 15687 15689 // // 15690 // trimbowatcavity() Validate B(p), CBC(p)s and C(p)s, update BC(p). // 15691 // // 15692 // A B(p) is valid if all its faces are visible by p. If a face f of B(p) is // 15693 // found invisible by p, the tet of BC(p) containing f gets removed and B(p) // 15694 // is refromed. The new B(p) may still contain invisible faces by p. Iterat- // 15695 // ively do the above procedure until B(p) is satisfied. // 15696 // // 15697 // A CBC(p) is valid if each subface of CBC(p) is either on the hull of BC(p)// 15698 // or completely inside BC(p). If a subface s of CBC(p) is not valid, it is // 15699 // removed from CBC(p) and C(p) is reformed. If there exists a tet t of BC(p)// 15700 // containg s, t is removed from BC(p). The process for validating BC(p) and // 15701 // B(p) is re-excuted. // 15702 // // 15703 // A C(p) is valid if each edge of C(p) is on the hull of BC(p). If an edge // 15704 // e of C(p) is invalid (e should be a subsegment which only belong to one // 15705 // facet), a tet of BC(p) which contains e and has two other faces shielding // 15706 // e is removed. The process for validating BC(p) and B(p) is re-excuted. // 15707 // // 15708 // If either BC(p) or CBC(p) becomes empty. No valid BC(p) is found, return // 15709 // FALSE. else, return TRUE. // 15710 // // 15712 15713 bool tetgenmesh::trimbowatcavity(point bp, face* bpseg, int n, list** sublists, 15714 list** subceillists, list** tetlists, list** ceillists, REAL maxcosd) 15715 { 15716 bool valflag; 15717 int oldnum, cutnum, cutcount; 15718 int i; 15719 15720 cutnum = 0; // Count the total number of cut-off tets of BC(p). 15721 valflag = true; 15722 15723 do { 15724 // Validate BC(p), B(p). 15725 for (i = 0; i < n && valflag; i++) { 15726 oldnum = tetlists[i]->len(); 15727 // Iteratively validate BC_i(p) and B_i(p). 15728 while (!validatebowatcavityquad(bp, ceillists[i], maxcosd)) { 15729 // Update BC_i(p) and B_i(p). 15730 updatebowatcavityquad(tetlists[i], ceillists[i]); 15731 valflag = tetlists[i]->len() > 0; 15732 } 15733 cutnum += (oldnum - tetlists[i]->len()); 15734 } 15735 if (valflag && (sublists != (list **) NULL)) { 15736 // Validate CBC(p), C(p). 15737 cutcount = 0; 15738 for (i = 0; i < n; i++) { 15739 updatebowatcavitysub(sublists[i], subceillists[i], &cutcount); 15740 // Only do once if p is on a facet. 15741 if (bpseg == (face *) NULL) break; 15742 } 15743 // Are there cut tets? 15744 if (cutcount > 0) { 15745 // Squeeze all cut tets in BC(p), keep valflag once it gets FLASE. 15746 for (i = 0; i < n; i++) { 15747 if (tetlists[i]->len() > 0) { 15748 updatebowatcavityquad(tetlists[i], ceillists[i]); 15749 if (valflag) { 15750 valflag = tetlists[i]->len() > 0; 15751 } 15752 } 15753 } 15754 cutnum += cutcount; 15755 // Go back to valid the updated BC(p). 15756 continue; 15757 } 15758 } 15759 break; // Leave the while-loop. 15760 } while (true); 15761 15762 // Check if any CBC(p) becomes non-empty. 15763 if (valflag && (sublists != (list **) NULL)) { 15764 for (i = 0; i < n && valflag; i++) { 15765 valflag = (sublists[i]->len() > 0); 15766 if (bpseg == (face *) NULL) break; 15767 } 15768 } 15769 15770 if (valflag && (cutnum > 0)) { 15771 // Accumulate counters. 15772 if (bpseg != (face *) NULL) { 15773 updsegcount++; 15774 } else if (sublists != (list **) NULL) { 15775 updsubcount++; 15776 } else { 15777 updvolcount++; 15778 } 15779 } 15780 15781 if (!valflag) { 15782 // Accumulate counters. 15783 if (bpseg != (face *) NULL) { 15784 failsegcount++; 15785 } else if (sublists != (list **) NULL) { 15786 failsubcount++; 15787 } else { 15788 failvolcount++; 15789 } 15790 } 15791 15792 return valflag; 15793 } 15794 15796 // // 15797 // bowatinsertsite() Insert a point using the Bowyer-Watson method. // 15798 // // 15799 // Parameters: 'bp' = p, 'splitseg' = S, 'n' = the number of quadrants, // 15800 // 'sublists', an array of CBC_i(p)s, 'subceillists', an array of C_i(p)s, // 15801 // 'tetlists', an array of BC_i(p)s, 'ceillists', an array of B_i(p)s. // 15802 // // 15803 // If p is inside the mesh domain, then S = NULL, n = 1, CBC(p) and C(p) are // 15804 // NULLs. 'tetlists[0]' = BC(p), 'ceillists[0]' = B(p). // 15805 // If p is on a facet F, then S = NULL, n = 2, and 'subceillists[0]' = C(p), // 15806 // 'subceillists[1]' is not needed (set it to NULL). B_1(p) and B_2(p) are // 15807 // in 'ceillists[0]' and 'ceillists[1]'. // 15808 // If p is on a segment S, then F(S) is a list of subfaces around S, and n = // 15809 // len(F(S)), there are n C_i(p)s and B_i(p)s supplied in 'subceillists[i]'// 15810 // and 'ceillists[i]'. // 15811 // // 15812 // If 'verlist' != NULL, it returns a list of vertices which connect to p. // 15813 // This vertices are used for interpolating size of p. // 15814 // // 15815 // If 'flipque' != NULL, it returns a list of internal faces of new tets in // 15816 // BC(p), faces on C(p)s are excluded. These faces may be locally non- // 15817 // Delaunay and will be flipped if they are flippable. Such non-Delaunay // 15818 // faces may exist when p is inserted to split an encroaching segment. // 15819 // // 15820 // 'chkencseg', 'chkencsub', and 'chkbadtet' are flags that indicate whether // 15821 // or not there should be checks for the creation of encroached subsegments, // 15822 // subfaces, or bad quality tets. If 'chkencseg' = TRUE, the encroached sub- // 15823 // segments are added to the list of subsegments to be split. // 15824 // // 15825 // On return, 'ceillists' returns Star(p). // 15826 // // 15828 15829 void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists, 15830 list** subceillists, list** tetlists, list** ceillists, list* verlist, 15831 queue* flipque, bool chkencseg, bool chkencsub, bool chkbadtet) 15832 { 15833 list *ceillist, *subceillist; 15834 triface oldtet, newtet, newface, rotface, neightet; 15835 face oldsh, newsh, newedge, checksh; 15836 face spinsh, casingin, casingout; 15837 face *apsegshs, *pbsegshs; 15838 face apseg, pbseg, checkseg; 15839 point pa, pb, pc; 15840 REAL attrib, volume; 15841 int idx, i, j, k; 15842 15843 apsegshs = NULL; 15844 pbsegshs = NULL; 15845 15846 if (b->verbose > 1) { 15847 printf(" Insert point %d (%.12g, %.12g, %.12g)", pointmark(bp), bp[0], 15848 bp[1], bp[2]); 15849 } 15850 if (splitseg != (face *) NULL) { 15851 if (b->verbose > 1) { 15852 printf(" on segment.\n"); 15853 } 15854 bowatsegcount++; 15855 } else { 15856 if (subceillists != (list **) NULL) { 15857 if (b->verbose > 1) { 15858 printf(" on facet.\n"); 15859 } 15860 bowatsubcount++; 15861 } else { 15862 if (b->verbose > 1) { 15863 printf(" in volume.\n"); 15864 } 15865 bowatvolcount++; 15866 } 15867 } 15868 15869 // Create new tets to fill B(p). 15870 for (k = 0; k < n; k++) { 15871 // Create new tets from each B_i(p). 15872 ceillist = ceillists[k]; 15873 for (i = 0; i < ceillist->len(); i++) { 15874 oldtet = * (triface *)(* ceillist)[i]; 15875 adjustedgering(oldtet, CCW); 15876 pa = org(oldtet); 15877 pb = dest(oldtet); 15878 pc = apex(oldtet); 15879 maketetrahedron(&newtet); 15880 setorg(newtet, pa); 15881 setdest(newtet, pb); 15882 setapex(newtet, pc); 15883 setoppo(newtet, bp); 15884 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 15885 attrib = elemattribute(oldtet.tet, j); 15886 setelemattribute(newtet.tet, j, attrib); 15887 } 15888 if (b->varvolume) { 15889 volume = volumebound(oldtet.tet); 15890 if (volume > 0.0) { 15891 if (!b->fixedvolume && b->refine) { 15892 // '-r -a' switches and a .vol file case. Enlarge the maximum 15893 // volume constraint for the new tets. Hence the new points 15894 // only spread near the original constrained tet. 15895 volume *= 1.2; 15896 } 15897 } 15898 setvolumebound(newtet.tet, volume); 15899 } 15900 sym(oldtet, neightet); 15901 tspivot(oldtet, checksh); 15902 if (neightet.tet != dummytet) { 15903 bond(newtet, neightet); 15904 } 15905 if (checksh.sh != dummysh) { 15906 tsbond(newtet, checksh); 15907 } 15908 if (verlist != (list *) NULL) { 15909 // Collect vertices connecting to p. 15910 idx = pointmark(pa); 15911 if (idx >= 0) { 15912 setpointmark(pa, -idx - 1); 15913 verlist->append(&pa); 15914 } 15915 idx = pointmark(pb); 15916 if (idx >= 0) { 15917 setpointmark(pb, -idx - 1); 15918 verlist->append(&pb); 15919 } 15920 idx = pointmark(pc); 15921 if (idx >= 0) { 15922 setpointmark(pc, -idx - 1); 15923 verlist->append(&pc); 15924 } 15925 } 15926 // Replace the tet by the newtet for checking the quality. 15927 * (triface *)(* ceillist)[i] = newtet; 15928 } 15929 } 15930 if (verlist != (list *) NULL) { 15931 // Uninfect collected vertices. 15932 for (i = 0; i < verlist->len(); i++) { 15933 pa = * (point *)(* verlist)[i]; 15934 idx = pointmark(pa); 15935 setpointmark(pa, -(idx + 1)); 15936 } 15937 } 15938 15939 // Connect new tets of B(p). Not all faces of new tets can be connected, 15940 // e.g., if there are empty B_i(p)s. 15941 for (k = 0; k < n; k++) { 15942 ceillist = ceillists[k]; 15943 for (i = 0; i < ceillist->len(); i++) { 15944 newtet = * (triface *)(* ceillist)[i]; 15945 newtet.ver = 0; 15946 for (j = 0; j < 3; j++) { 15947 fnext(newtet, newface); 15948 sym(newface, neightet); 15949 if (neightet.tet == dummytet) { 15950 // Find the neighbor face by rotating the faces at edge ab. 15951 esym(newtet, rotface); 15952 pa = org(rotface); 15953 pb = dest(rotface); 15954 while (fnextself(rotface)); 15955 // Do we meet a boundary face? 15956 tspivot(rotface, checksh); 15957 if (checksh.sh != dummysh) { 15958 // Walk through the boundary and continue to rotate faces. 15959 do { 15960 findedge(&checksh, pa, pb); 15961 sfnextself(checksh); 15962 assert((sorg(checksh) == pa) && (sdest(checksh) == pb)); 15963 stpivot(checksh, rotface); 15964 if (infected(rotface)) { 15965 // Meet an old tet of B_i(p). This side is on the hull and 15966 // will be connected to a new subface created in C(p). 15967 break; 15968 } 15969 findedge(&rotface, pa, pb); 15970 while (fnextself(rotface)); 15971 tspivot(rotface, checksh); 15972 } while (checksh.sh != dummysh); 15973 } 15974 // The rotface has edge ab, but it may not have newpt. 15975 if (apex(rotface) == apex(newface)) { 15976 // Bond the two tets together. 15977 bond(newface, rotface); 15978 // Queue (uniquely) this face if 'flipque' is given. 15979 if (flipque != (queue *) NULL) { 15980 enqueueflipface(newface, flipque); 15981 } 15982 } 15983 } 15984 enextself(newtet); 15985 } 15986 } 15987 } 15988 15989 if (subceillists != (list **) NULL) { 15990 // There are C(p)s. 15991 if (splitseg != (face *) NULL) { 15992 // S (ab) is split by p. 15993 splitseg->shver = 0; 15994 pa = sorg(*splitseg); 15995 pb = sdest(*splitseg); 15996 // Allcate two arrays for saving the subface rings of the two new 15997 // segments a->p and p->b. 15998 apsegshs = new face[n]; 15999 pbsegshs = new face[n]; 16000 } 16001 16002 // For each C_k(p), do the following: 16003 // (1) Create new subfaces to fill C_k(p), insert them into B(p); 16004 // (2) Connect new subfaces to each other; 16005 for (k = 0; k < n; k++) { 16006 subceillist = subceillists[k]; 16007 16008 // Check if 'hullsize' should be updated. 16009 oldsh = * (face *)(* subceillist)[0]; 16010 stpivot(oldsh, neightet); 16011 if (neightet.tet != dummytet) { 16012 sesymself(oldsh); 16013 stpivot(oldsh, neightet); 16014 } 16015 if (neightet.tet == dummytet) { 16016 // The hull size changes. 16017 hullsize += (subceillist->len() - sublists[k]->len()); 16018 } 16019 16020 // (1) Create new subfaces to fill C_k(p), insert them into B(p). 16021 for (i = 0; i < subceillist->len(); i++) { 16022 oldsh = * (face *)(* subceillist)[i]; 16023 makeshellface(subfaces, &newsh); 16024 setsorg(newsh, sorg(oldsh)); 16025 setsdest(newsh, sdest(oldsh)); 16026 setsapex(newsh, bp); 16027 if (b->quality && varconstraint) { 16028 setareabound(newsh, areabound(oldsh)); 16029 } 16030 setshellmark(newsh, shellmark(oldsh)); 16031 setshelltype(newsh, shelltype(oldsh)); 16032 if (checkpbcs) { 16033 setshellpbcgroup(newsh, shellpbcgroup(oldsh)); 16034 } 16035 // Replace oldsh by newsh at the edge. 16036 spivot(oldsh, casingout); 16037 sspivot(oldsh, checkseg); 16038 if (checkseg.sh != dummysh) { 16039 // A segment. Insert s into the face ring, ie, s_in -> s -> s_out. 16040 if (oldsh.sh != casingout.sh) { 16041 // s is not bonded to itself. 16042 spinsh = casingout; 16043 do { 16044 casingin = spinsh; 16045 spivotself(spinsh); 16046 } while (sapex(spinsh) != sapex(oldsh)); 16047 assert(casingin.sh != oldsh.sh); 16048 // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out). 16049 sbond1(casingin, newsh); 16050 sbond1(newsh, casingout); 16051 } else { 16052 // Bond newsh -> newsh. 16053 sbond(newsh, newsh); 16054 } 16055 // Bond the segment. 16056 ssbond(newsh, checkseg); 16057 } else { 16058 // Bond s <-> s_out (and dissolve s_out -> s_old). 16059 sbond(newsh, casingout); 16060 } 16061 16062 // Insert newsh into B(p). Use the coonections of oldsh. 16063 stpivot(oldsh, neightet); 16064 if (neightet.tet == dummytet) { 16065 sesymself(oldsh); 16066 sesymself(newsh); // Keep the same orientation as oldsh. 16067 stpivot(oldsh, neightet); 16068 } 16069 assert(infected(neightet)); 16070 // Set on the rotating edge. 16071 findedge(&neightet, sorg(oldsh), sdest(oldsh)); 16072 // Choose the rotating direction (to the inside of B(p)). 16073 adjustedgering(neightet, CCW); 16074 rotface = neightet; 16075 // Rotate face. Stop at a non-infected tet t (not in B(p)) or a 16076 // hull face f (on B(p)). Get the neighbor n of t or f. n is 16077 // a new tet that has just been created to fill B(p). 16078 do { 16079 fnextself(rotface); 16080 sym(rotface, neightet); 16081 if (neightet.tet == dummytet) { 16082 tspivot(rotface, checksh); 16083 assert(checksh.sh != dummysh); 16084 stpivot(checksh, newtet); 16085 break; 16086 } else if (!infected(neightet)) { 16087 sym(neightet, newtet); 16088 break; 16089 } 16090 } while (true); 16091 assert(newtet.tet != rotface.tet); 16092 // Set the rotating edge of n. 16093 findedge(&newtet, sorg(oldsh), sdest(oldsh)); 16094 // Choose the rotating direction (to the inside of B(p)). 16095 adjustedgering(newtet, CCW); 16096 fnext(newtet, newface); 16097 assert(apex(newface) == bp); 16098 // newsh has already been oriented toward n. 16099 tsbond(newface, newsh); 16100 sym(newface, neightet); // 'neightet' maybe outside. 16101 sesymself(newsh); 16102 tsbond(neightet, newsh); // Bond them anyway. 16103 16104 // Replace oldsh by newsh in list. 16105 * (face *)(* subceillist)[i] = newsh; 16106 } 16107 16108 // (2) Connect new subfaces to each other. 16109 for (i = 0; i < subceillist->len(); i++) { 16110 // Get a face cdp. 16111 newsh = * (face *)(* subceillist)[i]; 16112 // Get a new tet containing cdp. 16113 stpivot(newsh, newtet); 16114 if (newtet.tet == dummytet) { 16115 sesymself(newsh); 16116 stpivot(newsh, newtet); 16117 } 16118 for (j = 0; j < 2; j++) { 16119 if (j == 0) { 16120 senext(newsh, newedge); // edge dp. 16121 } else { 16122 senext2(newsh, newedge); // edge pc. 16123 sesymself(newedge); // edge cp. 16124 } 16125 if (splitseg != (face *) NULL) { 16126 // Don not operate on newedge if it is ap or pb. 16127 if (sorg(newedge) == pa) { 16128 apsegshs[k] = newedge; 16129 continue; 16130 } else if (sorg(newedge) == pb) { 16131 pbsegshs[k] = newedge; 16132 continue; 16133 } 16134 } 16135 // There should no segment inside the cavity. Check it. 16136 sspivot(newedge, checkseg); 16137 assert(checkseg.sh == dummysh); 16138 spivot(newedge, casingout); 16139 if (casingout.sh == dummysh) { 16140 rotface = newtet; 16141 findedge(&rotface, sorg(newedge), sdest(newedge)); 16142 // Rotate newtet until meeting a new subface which contains 16143 // newedge. It must exist since newedge is not a seg. 16144 adjustedgering(rotface, CCW); 16145 do { 16146 fnextself(rotface); 16147 tspivot(rotface, checksh); 16148 if (checksh.sh != dummysh) break; 16149 } while (true); 16150 findedge(&checksh, sorg(newedge), sdest(newedge)); 16151 sbond(newedge, checksh); 16152 } 16153 } 16154 } 16155 // Only do once if p is on a facet. 16156 if (splitseg == (face *) NULL) break; 16157 } // for (k = 0; k < n; k++) 16158 16159 if (splitseg != (face *) NULL) { 16160 // Update a->b to be a->p. 16161 apseg = *splitseg; 16162 setsdest(apseg, bp); 16163 // Create a new subsegment p->b. 16164 makeshellface(subsegs, &pbseg); 16165 setsorg(pbseg, bp); 16166 setsdest(pbseg, pb); 16167 // p->b gets the same mark and segment type as a->p. 16168 setshellmark(pbseg, shellmark(apseg)); 16169 setshelltype(pbseg, shelltype(apseg)); 16170 if (b->quality && varconstraint) { 16171 // Copy the area bound into the new subsegment. 16172 setareabound(pbseg, areabound(apseg)); 16173 } 16174 senext(apseg, checkseg); 16175 // Get the old connection at b of a->b. 16176 spivot(checkseg, casingout); 16177 // Bond a->p and p->b together. 16178 senext2(pbseg, casingin); 16179 sbond(casingin, checkseg); 16180 if (casingout.sh != dummysh) { 16181 // There is a subsegment connect at b of p->b. 16182 casingout.shver = 0; 16183 #ifdef SELF_CHECK 16184 assert(sorg(casingout) == pb); 16185 #endif 16186 senext2self(casingout); 16187 senext(pbseg, casingin); 16188 sbond(casingin, casingout); 16189 } 16190 16191 // Bond all new subfaces to a->p and p->b. 16192 for (i = 0; i < n; i++) { 16193 spinsh = apsegshs[i]; 16194 findedge(&spinsh, pa, bp); 16195 ssbond(spinsh, apseg); 16196 spinsh = pbsegshs[i]; 16197 findedge(&spinsh, bp, pb); 16198 ssbond(spinsh, pbseg); 16199 } 16200 // Bond all subfaces share at a->p together. 16201 for (i = 0; i < n; i++) { 16202 spinsh = apsegshs[i]; 16203 if (i < (n - 1)) { 16204 casingout = apsegshs[i + 1]; 16205 } else { 16206 casingout = apsegshs[0]; 16207 } 16208 sbond1(spinsh, casingout); 16209 } 16210 // Bond all subfaces share at p->b together. 16211 for (i = 0; i < n; i++) { 16212 spinsh = pbsegshs[i]; 16213 if (i < (n - 1)) { 16214 casingout = pbsegshs[i + 1]; 16215 } else { 16216 casingout = pbsegshs[0]; 16217 } 16218 sbond1(spinsh, casingout); 16219 } 16220 delete [] apsegshs; 16221 delete [] pbsegshs; 16222 16223 // Check for newly encroached subsegments if the flag is set. 16224 if (chkencseg) { 16225 // Check if a->p and p->b are encroached by other vertices. 16226 checkseg4encroach(&apseg, NULL, NULL, true); 16227 checkseg4encroach(&pbseg, NULL, NULL, true); 16228 // Check if the adjacent segments are encroached by p. 16229 tallencsegs(bp, n, ceillists); 16230 } 16231 } // if (splitseg != (face *) NULL) 16232 16233 // Delete subfaces of old CBC_i(p)s. 16234 for (k = 0; k < n; k++) { 16235 for (i = 0; i < sublists[k]->len(); i++) { 16236 oldsh = * (face *)(* (sublists[k]))[i]; 16237 shellfacedealloc(subfaces, oldsh.sh); 16238 } 16239 // Clear the list so that the subs will not get unmarked later in 16240 // routine releasebowatcavity() which only frees the memory. 16241 sublists[k]->clear(); 16242 // Only do once if p is on a facet. 16243 if (splitseg == (face *) NULL) break; 16244 } 16245 16246 // Check for newly encroached subfaces if the flag is set. 16247 if (chkencsub) { 16248 // Check if new subfaces of C_i(p) are encroached by other vertices. 16249 for (k = 0; k < n; k++) { 16250 subceillist = subceillists[k]; 16251 for (i = 0; i < subceillist->len(); i++) { 16252 newsh = * (face *)(* subceillist)[i]; 16253 checksub4encroach(&newsh, NULL, true); 16254 } 16255 // Only do once if p is on a facet. 16256 if (splitseg == (face *) NULL) break; 16257 } 16258 // Check if the adjacent subfaces are encroached by p. 16259 tallencsubs(bp, n, ceillists); 16260 } 16261 } // if (subceillists != (list **) NULL) 16262 16263 // Delete tets of old BC_i(p)s. 16264 for (k = 0; k < n; k++) { 16265 for (i = 0; i < tetlists[k]->len(); i++) { 16266 oldtet = * (triface *)(* (tetlists[k]))[i]; 16267 tetrahedrondealloc(oldtet.tet); 16268 } 16269 // Clear the list so that the tets will not get unmarked later in 16270 // routine releasebowatcavity() which only frees the memory. 16271 tetlists[k]->clear(); 16272 } 16273 16274 // check for bad quality tets if the flags is set. 16275 if (chkbadtet) { 16276 for (k = 0; k < n; k++) { 16277 ceillist = ceillists[k]; 16278 for (i = 0; i < ceillist->len(); i++) { 16279 newtet = * (triface *)(* ceillist)[i]; 16280 checktet4badqual(&newtet, true); 16281 } 16282 } 16283 } 16284 16285 if (flipque != (queue *) NULL) { 16286 // Newly created internal faces of BC(p) (excluding faces on C(p)s) are 16287 // in 'flipque'. Some of these faces may be locally non-Delaunay due, 16288 // to the existence of non-constrained tets. check and fix them. 16289 repairflipcount += flip(flipque, NULL); 16290 } 16291 } 16292 16293 // 16294 // End of mesh transformation routines 16295 // 16296 16297 // 16298 // Begin Delaunay tetrahedralization routines 16299 // 16300 16302 // // 16303 // formstarpolyhedron() Get the star ployhedron of a point 'pt'. // 16304 // // 16305 // The polyhedron P is formed by faces of tets having 'pt' as a vertex. If // 16306 // 'complete' is TRUE, P is the complete star of 'pt'. Otherwise, P is boun- // 16307 // ded by subfaces, i.e. P is only part of the star of 'pt'. // 16308 // // 16309 // 'tetlist' T returns the tets, it has one of such tets on input. Moreover, // 16310 // if t is in T, then oppo(t) = p. Topologically, T is the star of p; and // 16311 // the faces of T is the link of p. 'verlist' V returns the vertices of T. // 16312 // // 16314 16315 void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist, 16316 bool complete) 16317 { 16318 triface starttet, neightet; 16319 face checksh; 16320 point ver[3]; 16321 int idx, i, j; 16322 16323 // Get a tet t containing p. 16324 starttet = * (triface *)(* tetlist)[0]; 16325 // Let oppo(t) = p. 16326 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { 16327 if (oppo(starttet) == pt) break; 16328 } 16329 assert(starttet.loc < 4); 16330 // Add t into T. 16331 * (triface *)(* tetlist)[0] = starttet; 16332 infect(starttet); 16333 if (verlist != (list *) NULL) { 16334 // Add three verts of t into V. 16335 ver[0] = org(starttet); 16336 ver[1] = dest(starttet); 16337 ver[2] = apex(starttet); 16338 for (i = 0; i < 3; i++) { 16339 // Mark the vert by inversing the index of the vert. 16340 idx = pointmark(ver[i]); 16341 setpointmark(ver[i], -idx - 1); // -1 to distinguish the zero. 16342 verlist->append(&(ver[i])); 16343 } 16344 } 16345 16346 // Find other tets by a broadth-first search. 16347 for (i = 0; i < tetlist->len(); i++) { 16348 starttet = * (triface *)(* tetlist)[i]; 16349 starttet.ver = 0; 16350 for (j = 0; j < 3; j++) { 16351 fnext(starttet, neightet); 16352 tspivot(neightet, checksh); 16353 // Should we cross a subface. 16354 if ((checksh.sh == dummysh) || complete) { 16355 // Get the neighbor n. 16356 symself(neightet); 16357 if ((neightet.tet != dummytet) && !infected(neightet)) { 16358 // Let oppo(n) = p. 16359 for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { 16360 if (oppo(neightet) == pt) break; 16361 } 16362 assert(neightet.loc < 4); 16363 // Add n into T. 16364 infect(neightet); 16365 tetlist->append(&neightet); 16366 if (verlist != (list *) NULL) { 16367 // Add the apex vertex in n into V. 16368 ver[0] = org(starttet); 16369 ver[1] = dest(starttet); 16370 findedge(&neightet, ver[0], ver[1]); 16371 ver[2] = apex(neightet); 16372 idx = pointmark(ver[2]); 16373 if (idx >= 0) { 16374 setpointmark(ver[2], -idx - 1); 16375 verlist->append(&(ver[2])); 16376 } 16377 } 16378 } 16379 } 16380 enextself(starttet); 16381 } 16382 } 16383 16384 // Uninfect tets. 16385 for (i = 0; i < tetlist->len(); i++) { 16386 starttet = * (triface *)(* tetlist)[i]; 16387 uninfect(starttet); 16388 } 16389 if (verlist != (list *) NULL) { 16390 // Uninfect vertices. 16391 for (i = 0; i < verlist->len(); i++) { 16392 ver[0] = * (point *)(* verlist)[i]; 16393 idx = pointmark(ver[0]); 16394 setpointmark(ver[0], -(idx + 1)); 16395 } 16396 } 16397 } 16398 16400 // // 16401 // unifypoint() Unify two distinct points if they're very close. // 16402 // // 16403 // This function is used for dealing with inputs from CAD tools. Two points // 16404 // p and q are unified if: dist(p, q) / longest < eps. Where dist() is the // 16405 // Euclidean distance between p and q, longest is the maximum edge size of // 16406 // the input point set, eps is the tolerrence specified by user, default is // 16407 // 1e-6, it can be adjusted by '-T' switch. // 16408 // // 16410 16411 bool tetgenmesh::unifypoint(point testpt, triface *starttet, enum locateresult 16412 loc, REAL eps) 16413 { 16414 triface symtet, spintet; 16415 point checkpt, tapex; 16416 REAL tol; 16417 bool merged; 16418 int hitbdry; 16419 int i; 16420 16421 merged = false; 16422 tol = longest * eps; 16423 if ((loc == OUTSIDE) || (loc == INTETRAHEDRON) || (loc == ONFACE)) { 16424 // Check p is close to the four corners of the tet. 16425 for (i = 0; i < 4; i++) { 16426 checkpt = (point) starttet->tet[4 + i]; 16427 if (distance(testpt, checkpt) < tol) { 16428 merged = true; // Found a merge point p'. 16429 break; 16430 } 16431 } 16432 if (!merged && (loc == ONFACE)) { 16433 // Check the opposite point of the neighbor tet if it exists. 16434 sym(*starttet, symtet); 16435 if (symtet.tet != dummytet) { 16436 checkpt = oppo(symtet); 16437 if (distance(testpt, checkpt) < tol) { 16438 merged = true; // Found a merge point p'. 16439 } 16440 } 16441 } 16442 } else if (loc == ONEDGE) { 16443 // Check two endpoints of the edge. 16444 checkpt = org(*starttet); 16445 if (distance(testpt, checkpt) < tol) { 16446 merged = true; // Found a merge point p'. 16447 } 16448 if (!merged) { 16449 checkpt = dest(*starttet); 16450 if (distance(testpt, checkpt) < tol) { 16451 merged = true; // Found a merge point p'. 16452 } 16453 } 16454 if (!merged) { 16455 // Check apexes of the faces having the edge. 16456 spintet = *starttet; 16457 tapex = apex(*starttet); 16458 hitbdry = 0; 16459 do { 16460 checkpt = apex(spintet); 16461 if (distance(testpt, checkpt) < tol) { 16462 merged = true; // Found a merge point p'. 16463 break; 16464 } 16465 if (!fnextself(spintet)) { 16466 hitbdry++; 16467 if (hitbdry < 2) { 16468 esym(*starttet, spintet); 16469 if (!fnextself(spintet)) { 16470 hitbdry++; 16471 } 16472 } 16473 } 16474 } while ((apex(spintet) != tapex) && (hitbdry < 2)); 16475 } 16476 } 16477 if (merged) { 16478 if (b->object != tetgenbehavior::STL) { 16479 if (!b->quiet) { 16480 printf("Warning: Point %d is unified to point %d.\n", 16481 pointmark(testpt), pointmark(checkpt)); 16482 } 16483 // Count the number of duplicated points. 16484 dupverts++; 16485 } 16486 // Remember it is a duplicated point. 16487 setpointtype(testpt, DUPLICATEDVERTEX); 16488 // Set a pointer to the point it duplicates. 16489 setpoint2ppt(testpt, checkpt); 16490 } 16491 return merged; 16492 } 16493 16495 // // 16496 // incrflipdelaunay() Construct a delaunay tetrahedrization from a set of // 16497 // 3D points by the incremental flip algorithm. // 16498 // // 16499 // The incremental flip algorithm (by Edelsbrunner and Shah) can be describ- // 16500 // ed as follows: // 16501 // // 16502 // S be a set of points in 3D, Let 4 <= i <= n and assume that the // 16503 // Delaunay tetrahedralization of the first i-1 points in S is already // 16504 // constructed; call it D(i-1). Add the i-th point p_i (belong to S) to // 16505 // D(i-1), and restore Delaunayhood by flipping; this result in D(i). // 16506 // Repeat this procedure until i = n. // 16507 // // 16508 // This strategy always leads to the Delaunay triangulation of a point set. // 16509 // The return value is the number of convex hull faces of D. // 16510 // // 16512 16513 void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray, 16514 long arraysize, bool jump, bool merge, REAL eps, queue* flipque) 16515 { 16516 triface newtet, searchtet; 16517 point swappt, lastpt; 16518 enum locateresult loc; 16519 REAL det, n[3]; 16520 REAL attrib, volume; 16521 int i, j; 16522 #ifdef SELF_CHECK 16523 clock_t loc_start, loc_end; 16524 #endif 16525 16526 det = 0.0; 16527 if (b->verbose > 0) { 16528 printf(" Creating initial tetrahedralization.\n"); 16529 } 16530 16531 // The initial tetrahedralization T only has one tet formed by 4 affinely 16532 // linear independent vertices of the point set V = 'insertarray'. The 16533 // first point a = insertarray[0]. 16534 16535 // Get the second point b, that is not identical or very close to a. 16536 for (i = 1; i < arraysize; i++) { 16537 det = distance(insertarray[0], insertarray[i]); 16538 if (det > (longest * eps)) break; 16539 } 16540 if (i == arraysize) { 16541 printf("\nAll points seem to be identical.\n"); 16542 return; 16543 } else { 16544 // Swap to move b from index i to index 1. 16545 swappt = insertarray[i]; 16546 insertarray[i] = insertarray[1]; 16547 insertarray[1] = swappt; 16548 } 16549 // Get the third point c, that is not collinear with a and b. 16550 for (i++; i < arraysize; i++) { 16551 if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps)) 16552 break; 16553 } 16554 if (i == arraysize) { 16555 printf("\nAll points seem to be collinear.\n"); 16556 return; 16557 } else { 16558 // Swap to move c from index i to index 2. 16559 swappt = insertarray[i]; 16560 insertarray[i] = insertarray[2]; 16561 insertarray[2] = swappt; 16562 } 16563 // Get the fourth point d, that is not coplanar with a, b, and c. 16564 for (i++; i < arraysize; i++) { 16565 det = orient3d(insertarray[0], insertarray[1], insertarray[2], 16566 insertarray[i]); 16567 if (det == 0.0) continue; 16568 if (!iscoplanar(insertarray[0], insertarray[1], insertarray[2], 16569 insertarray[i], det, eps)) break; 16570 } 16571 if (i == arraysize) { 16572 // It's a 2D problem. 16573 in->mesh_dim = 2; 16574 // All points are coplanar. 16575 if (b->plc) { 16576 // Create an abovepoint. Maybe a surface triangulation can be formed. 16577 facenormal(insertarray[0], insertarray[1], insertarray[2], n, &det); 16578 if (det != 0.0) for (j = 0; j < 3; j++) n[j] /= det; 16579 // Take the average edge length of the bounding box. 16580 det = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0; 16581 // Temporarily create a point. It will be removed by jettison(); 16582 makepoint(&lastpt); 16583 for (j = 0; j < 3; j++) lastpt[j] = insertarray[0][j] + det * n[j]; 16584 abovepoint = lastpt; 16585 det = orient3d(insertarray[0], insertarray[1], insertarray[2], lastpt); 16586 // The index of the next inserting point is 3. 16587 i = 3; 16588 } else { 16589 printf("\nAll points seem to be coplanar.\n"); 16590 return; 16591 } 16592 } else { 16593 // Swap to move d from index i to index 3. 16594 swappt = insertarray[i]; 16595 insertarray[i] = insertarray[3]; 16596 insertarray[3] = swappt; 16597 lastpt = insertarray[3]; 16598 // The index of the next inserting point is 4. 16599 i = 4; 16600 } 16601 16602 // Create the initial tet. 16603 maketetrahedron(&newtet); 16604 if (det > 0.0) { 16605 // For keeping the positive orientation. 16606 swappt = insertarray[0]; 16607 insertarray[0] = insertarray[1]; 16608 insertarray[1] = swappt; 16609 } 16610 if (b->verbose > 2) { 16611 printf(" Create the first tet (%d, %d, %d, %d).\n", 16612 pointmark(insertarray[0]), pointmark(insertarray[1]), 16613 pointmark(insertarray[2]), pointmark(lastpt)); 16614 } 16615 setorg(newtet, insertarray[0]); 16616 setdest(newtet, insertarray[1]); 16617 setapex(newtet, insertarray[2]); 16618 setoppo(newtet, lastpt); 16619 if (oldtet != (triface *) NULL) { 16620 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 16621 attrib = elemattribute(oldtet->tet, j); 16622 setelemattribute(newtet.tet, j, attrib); 16623 } 16624 if (b->varvolume) { 16625 volume = volumebound(oldtet->tet); 16626 setvolumebound(newtet.tet, volume); 16627 } 16628 } 16629 // Set vertex type be FREEVOLVERTEX if it has no type yet. 16630 if (pointtype(insertarray[0]) == UNUSEDVERTEX) { 16631 setpointtype(insertarray[0], FREEVOLVERTEX); 16632 } 16633 if (pointtype(insertarray[1]) == UNUSEDVERTEX) { 16634 setpointtype(insertarray[1], FREEVOLVERTEX); 16635 } 16636 if (pointtype(insertarray[2]) == UNUSEDVERTEX) { 16637 setpointtype(insertarray[2], FREEVOLVERTEX); 16638 } 16639 if (pointtype(lastpt) == UNUSEDVERTEX) { 16640 setpointtype(lastpt, FREEVOLVERTEX); 16641 } 16642 // Bond to 'dummytet' for point location. 16643 dummytet[0] = encode(newtet); 16644 if (b->verbose > 3) { 16645 printf(" Creating tetra "); 16646 printtet(&newtet); 16647 } 16648 // At init, all faces of this tet are hull faces. 16649 hullsize = 4; 16650 16651 if (b->verbose > 0) { 16652 printf(" Incrementally inserting points.\n"); 16653 } 16654 16655 flip23s = flip32s = flip22s = flip44s = 0; 16656 searchtet.tet = (tetrahedron *) NULL; 16657 16658 // Insert the rest of points, one by one. 16659 for (; i < arraysize; i++) { 16660 // Locate p_i in T. 16661 #ifdef SELF_CHECK 16662 loc_start = clock(); 16663 #endif 16664 if (jump) { 16665 loc = locate(insertarray[i], &searchtet); 16666 } else { 16667 loc = preciselocate(insertarray[i], &searchtet, tetrahedrons->items); 16668 } 16669 #ifdef SELF_CHECK 16670 loc_end = clock(); 16671 tloctime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC; 16672 #endif 16673 // Keep current search state for next searching. 16674 recenttet = searchtet; 16675 if (loc == ONVERTEX) { 16676 if (b->object != tetgenbehavior::STL) { 16677 if (!b->quiet) { 16678 printf("Warning: Point %d is identical with point %d.\n", 16679 pointmark(insertarray[i]), pointmark(org(searchtet))); 16680 } 16681 } 16682 // Count the number of duplicated points. 16683 dupverts++; 16684 // Remember it is a duplicated point. 16685 setpointtype(insertarray[i], DUPLICATEDVERTEX); 16686 if (b->plc || b->refine) { 16687 // Set a pointer to the point it duplicates. 16688 setpoint2ppt(insertarray[i], org(searchtet)); 16689 } 16690 continue; // p_i is not inserted. 16691 } 16692 if (merge) { 16693 // Unify p_i if it is too close to a point of T. 16694 if (unifypoint(insertarray[i], &searchtet, loc, eps)) { 16695 continue; // p_i is not inserted. 16696 } 16697 } 16698 // Insert p_i in T. 16699 if (loc != OUTSIDE) { 16700 if (b->verbose > 1) { 16701 printf(" Insert point %d in tetrahedralization.\n", 16702 pointmark(insertarray[i])); 16703 } 16704 if (loc == INTETRAHEDRON) { 16705 splittetrahedron(insertarray[i], &searchtet, flipque); 16706 } else if (loc == ONFACE) { 16707 splittetface(insertarray[i], &searchtet, flipque); 16708 } else if (loc == ONEDGE) { 16709 splittetedge(insertarray[i], &searchtet, flipque); 16710 } 16711 } else { 16712 if (b->verbose > 1) { 16713 printf(" Insert point %d on convex hull.\n", 16714 pointmark(insertarray[i])); 16715 } 16716 inserthullsite(insertarray[i], &searchtet, flipque); 16717 } 16718 if (pointtype(insertarray[i]) == UNUSEDVERTEX) { 16719 // p_i becomes a (volume) vertex of T. 16720 setpointtype(insertarray[i], FREEVOLVERTEX); 16721 } 16722 #ifdef SELF_CHECK 16723 loc_start = clock(); 16724 #endif 16725 if (!b->noflip) { 16726 // Recover Delaunayness of T by flipping. 16727 flip(flipque, NULL); 16728 } else { 16729 lawson(NULL, flipque); 16730 // T remains regular. 16731 // flipque->clear(); 16732 } 16733 #ifdef SELF_CHECK 16734 loc_end = clock(); 16735 tfliptime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC; 16736 #endif 16737 } 16738 16739 if (b->verbose > 0) { 16740 printf(" %ld Flips (T23 %ld, T32 %ld, T22 %ld, T44 %ld)\n", 16741 flip23s+flip32s+flip22s+flip44s, flip23s, flip32s, flip22s, flip44s); 16742 } 16743 } 16744 16746 // // 16747 // delaunizevertices() Form a Delaunay tetrahedralization. // 16748 // // 16749 // Given a point set V (saved in 'points'). The Delaunay tetrahedralization // 16750 // D of V is created by incrementally inserting vertices. Returns the number // 16751 // of triangular faces bounding the convex hull of D. // 16752 // // 16754 16755 long tetgenmesh::delaunizevertices() 16756 { 16757 queue *flipque; 16758 point *insertarray; 16759 long arraysize; 16760 int i, j; 16761 16762 if (!b->quiet) { 16763 if (!b->noflip) { 16764 printf("Constructing Delaunay tetrahedralization.\n"); 16765 } else { 16766 printf("Constructing regular tetrahedralization.\n"); 16767 } 16768 } 16769 16770 flipque = new queue(sizeof(badface)); 16771 // Prepare the array of points for inserting. 16772 arraysize = points->items; 16773 insertarray = new point[arraysize]; 16774 points->traversalinit(); 16775 16776 // Randomize the point order. 16777 // randomseed = b->srandseed; 16778 for (i = 0; i < arraysize; i++) { 16779 j = (int) randomnation(i + 1); // 0 <= j <= i; 16780 insertarray[i] = insertarray[j]; 16781 insertarray[j] = pointtraverse(); 16782 } 16783 16784 // Use lawson flip. 16785 b->noflip = 1; 16786 16787 // Form the DT by incremental flip Delaunay algorithm. 16788 incrflipdelaunay(NULL, insertarray, arraysize, true, b->plc, b->epsilon, 16789 flipque); 16790 16791 b->noflip = 0; 16792 16793 delete [] insertarray; 16794 delete flipque; 16795 return hullsize; 16796 } 16797 16798 // 16799 // End Delaunay tetrahedralization routines 16800 // 16801 16802 // 16803 // Begin of surface triangulation routines 16804 // 16805 16807 // // 16808 // formstarpolygon() Form the star polygon of a point in facet. // 16809 // // 16810 // The polygon P is formed by all coplanar subfaces having 'pt' as a vertex. // 16811 // P is bounded by segments, e.g, if no segments, P is the full star of pt. // 16812 // // 16813 // 'trilist' T returns the subfaces, it has one of such subfaces on input. // 16814 // In addition, if f is in T, then sapex(f) = p. 'vertlist' V are verts of P.// 16815 // Topologically, T is the star of p; V and the edges of T are the link of p.// 16816 // // 16818 16819 void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist) 16820 { 16821 face steinsh, lnextsh, rnextsh; 16822 face checkseg; 16823 point pa, pb, pc, pd; 16824 int i; 16825 16826 // Get a subface f containing p. 16827 steinsh = * (face *)(* trilist)[0]; 16828 steinsh.shver = 0; // CCW 16829 // Let sapex(f) be p. 16830 for (i = 0; i < 3; i++) { 16831 if (sapex(steinsh) == pt) break; 16832 senextself(steinsh); 16833 } 16834 assert(i < 3); 16835 // Add the edge f into list. 16836 * (face *)(* trilist)[0] = steinsh; 16837 pa = sorg(steinsh); 16838 pb = sdest(steinsh); 16839 if (vertlist != (list *) NULL) { 16840 // Add two verts a, b into V, 16841 vertlist->append(&pa); 16842 vertlist->append(&pb); 16843 } 16844 16845 // Rotate edge pa to the left (CW) until meet pb or a segment. 16846 lnextsh = steinsh; 16847 pc = pa; 16848 do { 16849 senext2self(lnextsh); 16850 assert(sorg(lnextsh) == pt); 16851 sspivot(lnextsh, checkseg); 16852 if (checkseg.sh != dummysh) break; // Do not cross a segment. 16853 // Get neighbor subface n (must exist). 16854 spivotself(lnextsh); 16855 if (lnextsh.sh == dummysh) break; // It's a hull edge. 16856 // Go to the edge ca opposite to p. 16857 if (sdest(lnextsh) != pt) sesymself(lnextsh); 16858 assert(sdest(lnextsh) == pt); 16859 senext2self(lnextsh); 16860 // Add n (at edge ca) to T. 16861 trilist->append(&lnextsh); 16862 // Add edge ca to E. 16863 pc = sorg(lnextsh); 16864 if (pc == pb) break; // Rotate back. 16865 if (vertlist != (list *) NULL) { 16866 // Add vert c into V. 16867 vertlist->append(&pc); 16868 } 16869 } while (true); 16870 16871 if (pc != pb) { 16872 // Rotate edge bp to the right (CCW) until meet a segment. 16873 rnextsh = steinsh; 16874 do { 16875 senextself(rnextsh); 16876 assert(sdest(rnextsh) == pt); 16877 sspivot(rnextsh, checkseg); 16878 if (checkseg.sh != dummysh) break; // Do not cross a segment. 16879 // Get neighbor subface n (must exist). 16880 spivotself(rnextsh); 16881 if (rnextsh.sh == dummysh) break; // It's a hull edge. 16882 // Go to the edge bd opposite to p. 16883 if (sorg(rnextsh) != pt) sesymself(rnextsh); 16884 assert(sorg(rnextsh) == pt); 16885 senextself(rnextsh); 16886 // Add n (at edge bd) to T. 16887 trilist->append(&rnextsh); 16888 // Add edge bd to E. 16889 pd = sdest(rnextsh); 16890 if (pd == pa) break; // Rotate back. 16891 if (vertlist != (list *) NULL) { 16892 // Add vert d into V. 16893 vertlist->append(&pd); 16894 } 16895 } while (true); 16896 } 16897 } 16898 16900 // // 16901 // About the 'abovepoint' // 16902 // // 16903 // The 'abovepoint' of a facet is a point which is exactly non-coplanar with // 16904 // the plane containing that facet. With such an point, the 3D predicates: // 16905 // orient3d(), and insphere() can be used to substitute the corresponding 2D // 16906 // siblings, e.g. orient2d(), and incircle(). Its location is not critical, // 16907 // but floating-point accuracy is improved if it is nicely placed over the // 16908 // facet, not too close or too far away. // 16909 // // 16910 // We take the convention that the abovepoint of a facet always lies above // 16911 // the facet. By this convention, given three points a, b, and c in a facet, // 16912 // we say c has the counterclockwise order with ab is corresponding to say // 16913 // that c is below the plane abp, where p is the lift point. // 16914 // // 16916 16918 // // 16919 // getfacetabovepoint() Get a point above a plane pass through a facet. // 16920 // // 16921 // The calculcated point is saved in 'facetabovepointarray'. The 'abovepoint'// 16922 // is set on return. // 16923 // // 16925 16926 void tetgenmesh::getfacetabovepoint(face* facetsh) 16927 { 16928 list *verlist, *trilist, *tetlist; 16929 triface adjtet; 16930 face symsh; 16931 point p1, p2, p3, pa; 16932 enum locateresult loc; 16933 REAL smallcos, cosa; 16934 REAL largevol, volume; 16935 REAL v1[3], v2[3], len; 16936 int smallidx, largeidx; 16937 int shmark; 16938 int i, j; 16939 16940 abovecount++; 16941 // Initialize working lists. 16942 verlist = new list(sizeof(point *), NULL); 16943 trilist = new list(sizeof(face), NULL); 16944 tetlist = new list(sizeof(triface), NULL); 16945 16946 // Get three pivotal points p1, p2, and p3 in the facet as a base triangle 16947 // which is non-trivil and has good base angle (close to 90 degree). 16948 16949 // p1 is chosen as the one which has the smallest index in pa, pb, pc. 16950 p1 = sorg(*facetsh); 16951 pa = sdest(*facetsh); 16952 if (pointmark(pa) < pointmark(p1)) p1 = pa; 16953 pa = sapex(*facetsh); 16954 if (pointmark(pa) < pointmark(p1)) p1 = pa; 16955 // Form the star polygon of p1. 16956 trilist->append(facetsh); 16957 formstarpolygon(p1, trilist, verlist); 16958 16959 // Get the second pivotal point p2. 16960 p2 = * (point *)(* verlist)[0]; 16961 // Get vector v1 = p1->p2. 16962 for (i = 0; i < 3; i++) v1[i] = p2[i] - p1[i]; 16963 len = sqrt(dot(v1, v1)); 16964 assert(len > 0.0); // p2 != p1. 16965 for (i = 0; i < 3; i++) v1[i] /= len; 16966 16967 // Get the third pivotal point p3. p3 is chosen as the one in 'verlist' 16968 // which forms an angle with v1 closer to 90 degree than others do. 16969 smallcos = 1.0; // The cosine value of 0 degree. 16970 smallidx = 1; // Default value. 16971 for (i = 1; i < verlist->len(); i++) { 16972 p3 = * (point *)(* verlist)[i]; 16973 for (j = 0; j < 3; j++) v2[j] = p3[j] - p1[j]; 16974 len = sqrt(dot(v2, v2)); 16975 if (len > 0.0) { // v2 is not too small. 16976 cosa = fabs(dot(v1, v2)) / len; 16977 if (cosa < smallcos) { 16978 smallidx = i; 16979 smallcos = cosa; 16980 } 16981 } 16982 } 16983 assert(smallcos < 1.0); // p1->p3 != p1->p2. 16984 p3 = * (point *)(* verlist)[smallidx]; 16985 verlist->clear(); 16986 16987 if (tetrahedrons->items > 0l) { 16988 // Get a tet having p1 as a vertex. 16989 stpivot(*facetsh, adjtet); 16990 if (adjtet.tet == dummytet) { 16991 sesym(*facetsh, symsh); 16992 stpivot(symsh, adjtet); 16993 } 16994 if (adjtet.tet == dummytet) { 16995 decode(point2tet(p1), adjtet); 16996 if (isdead(&adjtet)) { 16997 adjtet.tet = dummytet; 16998 } else { 16999 if (!findorg(&adjtet, p1)) { 17000 adjtet.tet = dummytet; 17001 } 17002 } 17003 } 17004 if (adjtet.tet == dummytet) { 17005 loc = locate(p1, &adjtet); 17006 if (loc == ONVERTEX) { 17007 setpoint2tet(p1, encode(adjtet)); 17008 } else { 17009 adjtet.tet = dummytet; 17010 } 17011 } 17012 if (adjtet.tet != dummytet) { 17013 // Get the star polyhedron of p1. 17014 tetlist->append(&adjtet); 17015 formstarpolyhedron(p1, tetlist, verlist, false); 17016 } 17017 } 17018 17019 // Get the abovepoint in 'verlist'. It is the one form the largest valid 17020 // volumw with the base triangle over other points in 'verlist. 17021 largevol = 0.0; 17022 largeidx = 0; 17023 for (i = 0; i < verlist->len(); i++) { 17024 pa = * (point *)(* verlist)[i]; 17025 volume = orient3d(p1, p2, p3, pa); 17026 if (!iscoplanar(p1, p2, p3, pa, volume, b->epsilon * 1e+2)) { 17027 if (fabs(volume) > largevol) { 17028 largevol = fabs(volume); 17029 largeidx = i; 17030 } 17031 } 17032 } 17033 17034 // Do we have the abovepoint? 17035 if (largevol > 0.0) { 17036 abovepoint = * (point *)(* verlist)[largeidx]; 17037 if (b->verbose > 1) { 17038 printf(" Chosen abovepoint %d for facet %d.\n", pointmark(abovepoint), 17039 shellmark(*facetsh)); 17040 } 17041 } else { 17042 // Calculate an abovepoint for this facet. 17043 facenormal(p1, p2, p3, v1, &len); 17044 if (len != 0.0) for (i = 0; i < 3; i++) v1[i] /= len; 17045 // Take the average edge length of the bounding box. 17046 len = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0; 17047 // Temporarily create a point. It will be removed by jettison(); 17048 makepoint(&abovepoint); 17049 setpointtype(abovepoint, UNUSEDVERTEX); 17050 unuverts++; 17051 for (i = 0; i < 3; i++) abovepoint[i] = p1[i] + len * v1[i]; 17052 if (b->verbose > 1) { 17053 printf(" Calculated abovepoint %d for facet %d.\n", 17054 pointmark(abovepoint), shellmark(*facetsh)); 17055 } 17056 } 17057 // Save the abovepoint in 'facetabovepointarray'. 17058 shmark = shellmark(*facetsh); 17059 facetabovepointarray[shmark] = abovepoint; 17060 17061 delete trilist; 17062 delete tetlist; 17063 delete verlist; 17064 } 17065 17067 // // 17068 // collectcavsubs() Collect non-locally Delaunay subfaces wrt a point. // 17069 // // 17070 // 'cavsublist' returns the list of subfaces. On input, it conatins at least // 17071 // one subface. // 17072 // // 17074 17075 void tetgenmesh::collectcavsubs(point newpoint, list* cavsublist) 17076 { 17077 face startsub, neighsub; 17078 face checkseg; 17079 point pa, pb, pc; 17080 REAL sign, ori; 17081 int i, j; 17082 17083 // First infect subfaces in 'cavsublist'. 17084 for (i = 0; i < cavsublist->len(); i++) { 17085 startsub = * (face *)(* cavsublist)[i]; 17086 sinfect(startsub); 17087 } 17088 // Find the other subfaces by a broadth-first searching. 17089 for (i = 0; i < cavsublist->len(); i++) { 17090 startsub = * (face *)(* cavsublist)[i]; 17091 for (j = 0; j < 3; j++) { 17092 sspivot(startsub, checkseg); 17093 // Is there a segment? 17094 if (checkseg.sh == dummysh) { 17095 // No segment. Get the neighbor. 17096 spivot(startsub, neighsub); 17097 if (!sinfected(neighsub)) { 17098 pa = sorg(neighsub); 17099 pb = sdest(neighsub); 17100 pc = sapex(neighsub); 17101 sign = insphere(pa, pb, pc, abovepoint, newpoint); 17102 ori = orient3d(pa, pb, pc, abovepoint); 17103 if (sign != 0.0) { 17104 // Correct the sign. 17105 sign = ori > 0.0 ? sign : -sign; 17106 } 17107 if (sign > 0.0) { 17108 // neighsub is encroached by newpoint. 17109 sinfect(neighsub); 17110 cavsublist->append(&neighsub); 17111 } 17112 } 17113 } 17114 senextself(startsub); 17115 } 17116 } 17117 // Having found all subfaces, uninfect them before return. 17118 for (i = 0; i < cavsublist->len(); i++) { 17119 startsub = * (face *)(* cavsublist)[i]; 17120 suninfect(startsub); 17121 } 17122 } 17123 17125 // // 17126 // collectvisiblesubs() Collect convex hull edges which are visible from // 17127 // the inserting point. Construct new subfaces from // 17128 // these edges and the point. // 17129 // // 17130 // Let T be the current Delaunay triangulation (of vertices of a facet F). // 17131 // 'shmark', the index of F in 'in->facetlist' (starts from 1); 'inspoint' // 17132 // lies outside of T; 'horiz' is a hull edge of T which is visible by it. // 17133 // // 17135 17136 void tetgenmesh::collectvisiblesubs(int shmark, point inspoint, face* horiz, 17137 queue* flipqueue) 17138 { 17139 face newsh, hullsh; 17140 face rightsh, leftsh, spinedge; 17141 point horg, hdest; 17142 bool aboveflag; 17143 REAL ori, sign; 17144 17145 // Get the sign of abovepoint (so we can assume it is above the plane). 17146 adjustedgering(*horiz, CCW); 17147 horg = sorg(*horiz); 17148 hdest = sdest(*horiz); 17149 ori = orient3d(horg, hdest, sapex(*horiz), abovepoint); 17150 sign = ori > 0.0 ? -1 : 1; 17151 17152 // Create a new subface above 'horiz'. 17153 makeshellface(subfaces, &newsh); 17154 setsorg(newsh, hdest); 17155 setsdest(newsh, horg); 17156 setsapex(newsh, inspoint); 17157 setshellmark(newsh, shmark); 17158 if (b->quality && varconstraint) { 17159 setareabound(newsh, areabound(*horiz)); 17160 } 17161 if (checkpbcs) { 17162 setshellpbcgroup(newsh, shellpbcgroup(*horiz)); 17163 } 17164 // Make the connection. 17165 sbond(newsh, *horiz); 17166 // 'horiz' becomes interior edge. 17167 enqueueflipedge(*horiz, flipqueue); 17168 17169 // Finish the hull edges at the right side of the newsh. 17170 hullsh = *horiz; 17171 while (1) { 17172 senext(newsh, rightsh); 17173 // Get the right hull edge of 'horiz' by spinning inside edges around 17174 // 'horg' until reaching the 'dummysh'. 17175 spinedge = hullsh; 17176 do { 17177 hullsh = spinedge; 17178 senext2self(hullsh); 17179 spivot(hullsh, spinedge); 17180 if (spinedge.sh == dummysh) break; 17181 if (sorg(spinedge) != horg) sesymself(spinedge); 17182 assert(sorg(spinedge) == horg); 17183 } while (true); 17184 horg = sorg(hullsh); 17185 // Test whether 'inspoint' is visible by 'hullsh'. 17186 ori = orient3d(horg, sdest(hullsh), abovepoint, inspoint); 17187 ori *= sign; 17188 aboveflag = ori < 0.0; 17189 if (aboveflag) { 17190 // It's visible. 17191 makeshellface(subfaces, &newsh); 17192 setsorg(newsh, sdest(hullsh)); 17193 setsdest(newsh, horg); 17194 setsapex(newsh, inspoint); 17195 setshellmark(newsh, shmark); 17196 if (b->quality && varconstraint) { 17197 setareabound(newsh, areabound(hullsh)); 17198 } 17199 if (checkpbcs) { 17200 setshellpbcgroup(newsh, shellpbcgroup(hullsh)); 17201 } 17202 // Make the connection. 17203 sbond(newsh, hullsh); 17204 senext2(newsh, leftsh); 17205 sbond(leftsh, rightsh); 17206 // 'hullsh' becomes interior edge. 17207 enqueueflipedge(hullsh, flipqueue); 17208 } else { 17209 // 'rightsh' is a new hull edge. 17210 dummysh[0] = sencode(rightsh); 17211 break; 17212 } 17213 } 17214 17215 // Finish the hull edges at the left side of the newsh. 17216 hullsh = *horiz; 17217 spivot(*horiz, newsh); 17218 while (1) { 17219 senext2(newsh, leftsh); 17220 // Get the left hull edge of 'horiz' by spinning edges around 'hdest'. 17221 spinedge = hullsh; 17222 do { 17223 hullsh = spinedge; 17224 senextself(hullsh); 17225 spivot(hullsh, spinedge); 17226 if (spinedge.sh == dummysh) break; 17227 if (sdest(spinedge) != hdest) sesymself(spinedge); 17228 assert(sdest(spinedge) == hdest); 17229 } while (true); 17230 // Update 'hdest'. 17231 hdest = sdest(hullsh); 17232 // Test whether 'inspoint' is visible from 'hullsh'. 17233 ori = orient3d(sorg(hullsh), hdest, abovepoint, inspoint); 17234 ori *= sign; 17235 aboveflag = ori < 0.0; 17236 if (aboveflag) { 17237 // It's a visible hull edge. 17238 makeshellface(subfaces, &newsh); 17239 setsorg(newsh, hdest); 17240 setsdest(newsh, sorg(hullsh)); 17241 setsapex(newsh, inspoint); 17242 setshellmark(newsh, shmark); 17243 if (b->quality && varconstraint) { 17244 setareabound(newsh, areabound(hullsh)); 17245 } 17246 if (checkpbcs) { 17247 setshellpbcgroup(newsh, shellpbcgroup(hullsh)); 17248 } 17249 // Make the connection. 17250 sbond(newsh, hullsh); 17251 senext(newsh, rightsh); 17252 sbond(rightsh, leftsh); 17253 // 'horiz' becomes interior edge. 17254 enqueueflipedge(hullsh, flipqueue); 17255 } else { 17256 // 'leftsh' is a new hull edge. 17257 dummysh[0] = sencode(leftsh); 17258 break; 17259 } 17260 } 17261 } 17262 17264 // // 17265 // incrflipdelaunaysub() Create a DT from a 3D coplanar point set using // 17266 // the incremental flip algorithm. // 17267 // // 17268 // Let T be the current Delaunay triangulation (of vertices of a facet F). // 17269 // 'shmark', the index of F in 'in->facetlist' (starts from 1). // 17270 // // 17272 17273 void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist, 17274 int holes, REAL* holelist, queue* flipque) 17275 { 17276 face newsh, startsh; 17277 point *insertarray; 17278 point swappt; 17279 pbcdata *pd; 17280 enum locateresult loc; 17281 REAL det, area; 17282 bool aboveflag; 17283 int arraysize; 17284 int epscount; 17285 int fmarker; 17286 int idx, i, j, k; 17287 17288 // Get the point array (saved in 'ptlist'). 17289 insertarray = (point *) ptlist->base; 17290 arraysize = ptlist->len(); 17291 if (arraysize < 3) return; 17292 17293 // Do calculation of 'abovepoint' if number of points > 3. 17294 aboveflag = (arraysize > 3); 17295 17296 // The initial triangulation T only has one triangle formed by 3 not 17297 // cillinear points of the set V = 'insertarray'. The first point: 17298 // a = insertarray[0]. 17299 17300 epscount = 0; 17301 while (true) { 17302 for (i = 1; i < arraysize; i++) { 17303 det = distance(insertarray[0], insertarray[i]); 17304 if (det > (longest * eps)) break; 17305 } 17306 if (i < arraysize) { 17307 // Swap to move b from index i to index 1. 17308 swappt = insertarray[i]; 17309 insertarray[i] = insertarray[1]; 17310 insertarray[1] = swappt; 17311 } 17312 // Get the third point c, that is not collinear with a and b. 17313 for (i++; i < arraysize; i++) { 17314 if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps)) 17315 break; 17316 } 17317 if (i < arraysize) { 17318 // Swap to move c from index i to index 2. 17319 swappt = insertarray[i]; 17320 insertarray[i] = insertarray[2]; 17321 insertarray[2] = swappt; 17322 i = 3; // The next inserting point. 17323 } else { 17324 // The set of vertices is not good (or nearly degenerate). However, 17325 // a trivial triangulation can be formed (using 3 vertices). It may 17326 // be corrected (or deleted) by mergefacet(). 17327 if ((eps == 0.0) || (epscount > 16)) { 17328 printf("Error: Invalid PLC.\n"); 17329 printf(" Facet (%d, %d, %d", pointmark(insertarray[0]), 17330 pointmark(insertarray[1]), pointmark(insertarray[2])); 17331 if (ptlist->len() > 3) { 17332 printf(", ..."); 17333 } 17334 printf(") (%d) is not a valid polygon.\n", shmark); 17335 terminatetetgen(1); 17336 } 17337 // Decrease the eps, and continue to try. 17338 eps *= 1e-2; 17339 epscount++; 17340 continue; 17341 } 17342 break; 17343 } // while (true); 17344 17345 // Create the initial triangle. 17346 makeshellface(subfaces, &newsh); 17347 setsorg(newsh, insertarray[0]); 17348 setsdest(newsh, insertarray[1]); 17349 setsapex(newsh, insertarray[2]); 17350 // Remeber the facet it belongs to. 17351 setshellmark(newsh, shmark); 17352 // Set vertex type be FREESUBVERTEX if it has no type yet. 17353 if (pointtype(insertarray[0]) == FREEVOLVERTEX) { 17354 setpointtype(insertarray[0], FREESUBVERTEX); 17355 } 17356 if (pointtype(insertarray[1]) == FREEVOLVERTEX) { 17357 setpointtype(insertarray[1], FREESUBVERTEX); 17358 } 17359 if (pointtype(insertarray[2]) == FREEVOLVERTEX) { 17360 setpointtype(insertarray[2], FREESUBVERTEX); 17361 } 17362 // Let 'dummysh' point to it (for point location). 17363 dummysh[0] = sencode(newsh); 17364 17365 // Are there area constraints? 17366 if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) { 17367 idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker. 17368 for (k = 0; k < in->numberoffacetconstraints; k++) { 17369 fmarker = (int) in->facetconstraintlist[k * 2]; 17370 if (fmarker == idx) { 17371 area = in->facetconstraintlist[k * 2 + 1]; 17372 setareabound(newsh, area); 17373 break; 17374 } 17375 } 17376 } 17377 17378 // Are there pbc conditions? 17379 if (checkpbcs) { 17380 idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker. 17381 for (k = 0; k < in->numberofpbcgroups; k++) { 17382 pd = &subpbcgrouptable[k]; 17383 for (j = 0; j < 2; j++) { 17384 if (pd->fmark[j] == idx) { 17385 setshellpbcgroup(newsh, k); 17386 pd->ss[j] = newsh; 17387 } 17388 } 17389 } 17390 } 17391 17392 if (aboveflag) { 17393 // Compute the 'abovepoint' for orient3d(). 17394 abovepoint = facetabovepointarray[shmark]; 17395 if (abovepoint == (point) NULL) { 17396 getfacetabovepoint(&newsh); 17397 } 17398 } 17399 17400 if (holes > 0) { 17401 // Project hole points onto the plane containing the facet. 17402 REAL prj[3]; 17403 for (k = 0; k < holes; k++) { 17404 projpt2face(&(holelist[k * 3]), insertarray[0], insertarray[1], 17405 insertarray[2], prj); 17406 for (j = 0; j < 3; j++) holelist[k * 3 + j] = prj[j]; 17407 } 17408 } 17409 17410 // Incrementally insert the rest of points into T. 17411 for (; i < arraysize; i++) { 17412 // Insert p_i. 17413 startsh.sh = dummysh; 17414 loc = locatesub(insertarray[i], &startsh, 0, 0.0); 17415 if (loc == ONFACE) { 17416 splitsubface(insertarray[i], &startsh, flipque); 17417 } else if (loc == ONEDGE) { 17418 splitsubedge(insertarray[i], &startsh, flipque); 17419 } else if (loc == OUTSIDE) { 17420 collectvisiblesubs(shmark, insertarray[i], &startsh, flipque); 17421 } else if (loc == ONVERTEX) { 17422 // !should not happen! 17423 } 17424 // Set p_i's type FREESUBVERTEX if it has no type yet. 17425 if (pointtype(insertarray[i]) == FREEVOLVERTEX) { 17426 setpointtype(insertarray[i], FREESUBVERTEX); 17427 } 17428 flipsub(flipque); 17429 } 17430 } 17431 17433 // // 17434 // finddirectionsub() Find the first subface in a facet on the path from // 17435 // one point to another. // 17436 // // 17437 // Finds the subface in the facet that intersects a line segment drawn from // 17438 // the origin of `searchsh' to the point `tend', and returns the result in // 17439 // `searchsh'. The origin of `searchsh' does not change, even though the // 17440 // subface returned may differ from the one passed in. // 17441 // // 17442 // The return value notes whether the destination or apex of the found face // 17443 // is collinear with the two points in question. // 17444 // // 17446 17447 enum tetgenmesh::finddirectionresult tetgenmesh::finddirectionsub( 17448 face* searchsh, point tend) 17449 { 17450 face checksh; 17451 point startpoint, leftpoint, rightpoint; 17452 REAL leftccw, rightccw; 17453 REAL ori, sign; 17454 int leftflag, rightflag; 17455 17456 startpoint = sorg(*searchsh); 17457 // Find the sign to simulate that abovepoint is 'above' the facet. 17458 adjustedgering(*searchsh, CCW); 17459 // Make sure 'startpoint' is the origin. 17460 if (sorg(*searchsh) != startpoint) senextself(*searchsh); 17461 rightpoint = sdest(*searchsh); 17462 leftpoint = sapex(*searchsh); 17463 ori = orient3d(startpoint, rightpoint, leftpoint, abovepoint); 17464 sign = ori > 0.0 ? -1 : 1; 17465 17466 // Is `tend' to the left? 17467 ori = orient3d(tend, startpoint, abovepoint, leftpoint); 17468 leftccw = ori * sign; 17469 leftflag = leftccw > 0.0; 17470 // Is `tend' to the right? 17471 ori = orient3d(startpoint, tend, abovepoint, rightpoint); 17472 rightccw = ori * sign; 17473 rightflag = rightccw > 0.0; 17474 if (leftflag && rightflag) { 17475 // `searchsh' faces directly away from `tend'. We could go left or 17476 // right. Ask whether it's a triangle or a boundary on the left. 17477 senext2(*searchsh, checksh); 17478 spivotself(checksh); 17479 if (checksh.sh == dummysh) { 17480 leftflag = 0; 17481 } else { 17482 rightflag = 0; 17483 } 17484 } 17485 while (leftflag) { 17486 // Turn left until satisfied. 17487 senext2self(*searchsh); 17488 spivotself(*searchsh); 17489 if (searchsh->sh == dummysh) { 17490 printf("Internal error in finddirectionsub(): Unable to find a\n"); 17491 printf(" subface leading from %d to %d.\n", pointmark(startpoint), 17492 pointmark(tend)); 17493 internalerror(); 17494 } 17495 if (sorg(*searchsh) != startpoint) sesymself(*searchsh); 17496 assert(sorg(*searchsh) == startpoint); 17497 leftpoint = sapex(*searchsh); 17498 rightccw = leftccw; 17499 ori = orient3d(tend, startpoint, abovepoint, leftpoint); 17500 leftccw = ori * sign; 17501 leftflag = leftccw > 0.0; 17502 } 17503 while (rightflag) { 17504 // Turn right until satisfied. 17505 spivotself(*searchsh); 17506 if (searchsh->sh == dummysh) { 17507 printf("Internal error in finddirectionsub(): Unable to find a\n"); 17508 printf(" subface leading from %d to %d.\n", pointmark(startpoint), 17509 pointmark(tend)); 17510 internalerror(); 17511 } 17512 if (sdest(*searchsh) != startpoint) sesymself(*searchsh); 17513 assert(sdest(*searchsh) == startpoint); 17514 senextself(*searchsh); 17515 rightpoint = sdest(*searchsh); 17516 leftccw = rightccw; 17517 ori = orient3d(startpoint, tend, abovepoint, rightpoint); 17518 rightccw = ori * sign; 17519 rightflag = rightccw > 0.0; 17520 } 17521 if (leftccw == 0.0) { 17522 return LEFTCOLLINEAR; 17523 } else if (rightccw == 0.0) { 17524 return RIGHTCOLLINEAR; 17525 } else { 17526 return ACROSSEDGE; 17527 } 17528 } 17529 17531 // // 17532 // insertsubseg() Create a subsegment and insert it between two subfaces. // 17533 // // 17534 // The new subsegment ab is inserted at the edge of subface 'tri'. If ab is // 17535 // not a hull edge, it is inserted between two subfaces. If 'tri' is a hull // 17536 // face, the initial face ring of ab will be set only one face which is self-// 17537 // bonded. The final face ring will be constructed in 'unifysegments()'. // 17538 // // 17540 17541 void tetgenmesh::insertsubseg(face* tri) 17542 { 17543 face oppotri; 17544 face newsubseg; 17545 point pa, pb; 17546 REAL len; 17547 int e1, e2; 17548 int i; 17549 17550 // Check if there's already a subsegment here. 17551 sspivot(*tri, newsubseg); 17552 if (newsubseg.sh == dummysh) { 17553 // Make new subsegment and initialize its vertices. 17554 makeshellface(subsegs, &newsubseg); 17555 pa = sorg(*tri); 17556 pb = sdest(*tri); 17557 setsorg(newsubseg, pa); 17558 setsdest(newsubseg, pb); 17559 // Are there length constraints? 17560 if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) { 17561 for (i = 0; i < in->numberofsegmentconstraints; i++) { 17562 e1 = (int) in->segmentconstraintlist[i * 3]; 17563 e2 = (int) in->segmentconstraintlist[i * 3 + 1]; 17564 if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) || 17565 ((pointmark(pa) == e2) && (pointmark(pb) == e1))) { 17566 len = in->segmentconstraintlist[i * 3 + 2]; 17567 setareabound(newsubseg, len); 17568 break; 17569 } 17570 } 17571 } 17572 // Bond new subsegment to the two subfaces it is sandwiched between. 17573 ssbond(*tri, newsubseg); 17574 spivot(*tri, oppotri); 17575 // 'oppotri' might be "out space". 17576 if (oppotri.sh != dummysh) { 17577 ssbond(oppotri, newsubseg); 17578 } /* else { 17579 // Outside! Bond '*tri' to itself. 17580 sbond(*tri, *tri); 17581 } */ 17582 } 17583 } 17584 17586 // // 17587 // scoutsegmentsub() Scout the first triangle on the path from one point // 17588 // to another, and check for completion (reaching the // 17589 // second point), a collinear point,or the intersection // 17590 // of two segments. // 17591 // // 17592 // Returns true if the entire segment is successfully inserted, and false if // 17593 // the job must be finished by constrainededge(). // 17594 // // 17596 17597 bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend) 17598 { 17599 face newsubseg; 17600 face crosssub, crosssubseg; 17601 point leftpoint, rightpoint; 17602 enum finddirectionresult collinear; 17603 17604 collinear = finddirectionsub(searchsh, tend); 17605 rightpoint = sdest(*searchsh); 17606 leftpoint = sapex(*searchsh); 17607 if (rightpoint == tend || leftpoint == tend) { 17608 // The segment is already an edge. 17609 if (leftpoint == tend) { 17610 senext2self(*searchsh); 17611 } 17612 // Insert a subsegment. 17613 insertsubseg(searchsh); 17614 return true; 17615 } else if (collinear == LEFTCOLLINEAR) { 17616 // We've collided with a vertex between the segment's endpoints. 17617 // Make the collinear vertex be the triangle's origin. 17618 senextself(*searchsh); // lprevself(*searchtri); 17619 // Insert a subsegment. 17620 insertsubseg(searchsh); 17621 // Insert the remainder of the segment. 17622 return scoutsegmentsub(searchsh, tend); 17623 } else if (collinear == RIGHTCOLLINEAR) { 17624 // We've collided with a vertex between the segment's endpoints. 17625 // Insert a subsegment. 17626 insertsubseg(searchsh); 17627 // Make the collinear vertex be the triangle's origin. 17628 senextself(*searchsh); // lnextself(*searchtri); 17629 // Insert the remainder of the segment. 17630 return scoutsegmentsub(searchsh, tend); 17631 } else { 17632 senext(*searchsh, crosssub); // lnext(*searchtri, crosstri); 17633 // Check for a crossing segment. 17634 sspivot(crosssub, crosssubseg); 17635 #ifdef SELF_CHECK 17636 assert(crosssubseg.sh == dummysh); 17637 #endif 17638 return false; 17639 } 17640 } 17641 17643 // // 17644 // flipedgerecursive() Flip an edge. // 17645 // // 17646 // This is a support routine for inserting segments into a CDT. // 17647 // // 17648 // Let 'flipedge' be ab, and two triangles abc, abd share at it. ab may not // 17649 // flipable if the four vertices a, b, c, and d are non-convex. If it is the // 17650 // case, recursively flip ad or bd. Return when ab is flipped. // 17651 // // 17653 17654 void tetgenmesh::flipedgerecursive(face* flipedge, queue* flipqueue) 17655 { 17656 face fixupsh; 17657 point pa, pb, pc, pd; 17658 REAL oria, orib; 17659 bool doflip; 17660 17661 pa = sorg(*flipedge); 17662 pb = sdest(*flipedge); 17663 pc = sapex(*flipedge); 17664 do { 17665 spivot(*flipedge, fixupsh); 17666 pd = sapex(fixupsh); 17667 oria = orient3d(pc, pd, abovepoint, pa); 17668 orib = orient3d(pc, pd, abovepoint, pb); 17669 doflip = (oria * orib < 0.0); 17670 if (doflip) { 17671 // Flip the edge (a, b) away. 17672 flip22sub(flipedge, flipqueue); 17673 // Fix flipedge on edge e (c, d). 17674 findedge(flipedge, pc, pd); 17675 } else { 17676 // ab is unflipable. Get the next edge (bd, or da) to flip. 17677 if (sorg(fixupsh) != pb) sesymself(fixupsh); 17678 assert(sdest(fixupsh) == pa); 17679 if (fabs(oria) > fabs(orib)) { 17680 // acd has larger area. Choose da. 17681 senextself(fixupsh); 17682 } else { 17683 // bcd has larger area. Choose bd. 17684 senext2self(fixupsh); 17685 } 17686 // Flip the edge. 17687 flipedgerecursive(&fixupsh, flipqueue); 17688 } 17689 } while (!doflip); 17690 } 17691 17693 // // 17694 // constrainededge() Force a segment into a CDT. // 17695 // // 17696 // The segment s is recovered by flipping away the edges it intersects, and // 17697 // triangulating the polygons that form on each side of it. // 17698 // // 17699 // Generates a single subsegment connecting `tstart' to `tend'. The triangle // 17700 // `startsh' has `tstart' as its origin. // 17701 // // 17703 17704 void tetgenmesh::constrainededge(face* startsh, point tend, queue* flipqueue) 17705 { 17706 point tstart, tright, tleft; 17707 REAL rori, lori; 17708 bool collision; 17709 17710 tstart = sorg(*startsh); 17711 do { 17712 // Loop edges oppo to tstart until find one crosses the segment. 17713 do { 17714 tright = sdest(*startsh); 17715 tleft = sapex(*startsh); 17716 // Is edge (tright, tleft) corss the segment. 17717 rori = orient3d(tstart, tright, abovepoint, tend); 17718 collision = (rori == 0.0); 17719 if (collision) break; // tright is on the segment. 17720 lori = orient3d(tstart, tleft, abovepoint, tend); 17721 collision = (lori == 0.0); 17722 if (collision) { // tleft is on the segment. 17723 senext2self(*startsh); 17724 break; 17725 } 17726 if (rori * lori < 0.0) break; // Find the crossing edge. 17727 // Both points are at one side of the segment. 17728 finddirectionsub(startsh, tend); 17729 } while (true); 17730 if (collision) break; 17731 // Get the neighbor face at edge e (tright, tleft). 17732 senextself(*startsh); 17733 // Flip the crossing edge. 17734 flipedgerecursive(startsh, flipqueue); 17735 // After flip, sorg(*startsh) == tstart. 17736 assert(sorg(*startsh) == tstart); 17737 } while (sdest(*startsh) != tend); 17738 17739 // Insert a subsegment to make the segment permanent. 17740 insertsubseg(startsh); 17741 // If there was a collision with an interceding vertex, install another 17742 // segment connecting that vertex with endpoint2. 17743 if (collision) { 17744 // Insert the remainder of the segment. 17745 if (!scoutsegmentsub(startsh, tend)) { 17746 constrainededge(startsh, tend, flipqueue); 17747 } 17748 } 17749 } 17750 17752 // // 17753 // recoversegment() Recover a segment in the surface triangulation. // 17754 // // 17756 17757 void tetgenmesh::recoversegment(point tstart, point tend, queue* flipqueue) 17758 { 17759 face searchsh; 17760 17761 if (b->verbose > 2) { 17762 printf(" Insert seg (%d, %d).\n", pointmark(tstart), pointmark(tend)); 17763 } 17764 17765 // Find a triangle whose origin is the segment's first endpoint. 17766 searchsh.sh = dummysh; 17767 // Search for the segment's first endpoint by point location. 17768 if (locatesub(tstart, &searchsh, 0, 0.0) != ONVERTEX) { 17769 // Possibly caused by a degenerate subface. Do a brute-force search. 17770 list *newshlist; 17771 int i, j; 17772 newshlist = new list(sizeof(face), NULL, 256); 17773 // Get new subfaces, do not remove protected segments. 17774 retrievenewsubs(newshlist, false); 17775 // Search for a sub contain tstart. 17776 for (i = 0; i < newshlist->len(); i++) { 17777 searchsh = * (face *)(* newshlist)[i]; 17778 for (j = 0; j < 3; j++) { 17779 if (sorg(searchsh) == tstart) break; 17780 senextself(searchsh); 17781 } 17782 if (j < 3) break; 17783 } 17784 delete newshlist; 17785 if (sorg(searchsh) != tstart) { 17786 printf("Internal error in recoversegment(): Vertex location failed.\n"); 17787 internalerror(); 17788 } 17789 } 17790 // Scout the segment and insert it if it is found. 17791 if (scoutsegmentsub(&searchsh, tend)) { 17792 // The segment was easily inserted. 17793 return; 17794 } 17795 // Insert the segment into the triangulation by flips. 17796 constrainededge(&searchsh, tend, flipqueue); 17797 // Some edges may need flipping. 17798 flipsub(flipqueue); 17799 } 17800 17802 // // 17803 // infecthullsub() Virally infect all of the triangles of the convex hull // 17804 // that are not protected by subsegments. // 17805 // // 17807 17808 void tetgenmesh::infecthullsub(memorypool* viri) 17809 { 17810 face hulltri, nexttri, starttri; 17811 face hullsubseg; 17812 shellface **deadshellface; 17813 17814 // Find a triangle handle on the hull. 17815 hulltri.sh = dummysh; 17816 hulltri.shver = 0; 17817 spivotself(hulltri); 17818 adjustedgering(hulltri, CCW); 17819 // Remember where we started so we know when to stop. 17820 starttri = hulltri; 17821 // Go once counterclockwise around the convex hull. 17822 do { 17823 // Ignore triangles that are already infected. 17824 if (!sinfected(hulltri)) { 17825 // Is the triangle protected by a subsegment? 17826 sspivot(hulltri, hullsubseg); 17827 if (hullsubseg.sh == dummysh) { 17828 // The triangle is not protected; infect it. 17829 if (!sinfected(hulltri)) { 17830 sinfect(hulltri); 17831 deadshellface = (shellface **) viri->alloc(); 17832 *deadshellface = hulltri.sh; 17833 } 17834 } 17835 } 17836 // To find the next hull edge, go clockwise around the next vertex. 17837 senextself(hulltri); // lnextself(hulltri); 17838 spivot(hulltri, nexttri); // oprev(hulltri, nexttri); 17839 if (nexttri.sh == hulltri.sh) { 17840 nexttri.sh = dummysh; // 'hulltri' is self-bonded. 17841 } else { 17842 adjustedgering(nexttri, CCW); 17843 senextself(nexttri); 17844 } 17845 while (nexttri.sh != dummysh) { 17846 hulltri = nexttri; 17847 spivot(hulltri, nexttri); // oprev(hulltri, nexttri); 17848 if (nexttri.sh == hulltri.sh) { 17849 nexttri.sh = dummysh; // 'hulltri' is self-bonded. 17850 } else { 17851 adjustedgering(nexttri, CCW); 17852 senextself(nexttri); 17853 } 17854 } 17855 } while (hulltri != starttri); 17856 } 17857 17859 // // 17860 // plaguesub() Spread the virus from all infected triangles to any // 17861 // neighbors not protected by subsegments. Delete all // 17862 // infected triangles. // 17863 // // 17864 // This is the procedure that actually creates holes and concavities. // 17865 // // 17867 17868 void tetgenmesh::plaguesub(memorypool* viri) 17869 { 17870 face testtri, neighbor, ghostsh; 17871 face neighborsubseg; 17872 shellface **virusloop; 17873 shellface **deadshellface; 17874 int i; 17875 17876 // Loop through all the infected triangles, spreading the virus to 17877 // their neighbors, then to their neighbors' neighbors. 17878 viri->traversalinit(); 17879 virusloop = (shellface **) viri->traverse(); 17880 while (virusloop != (shellface **) NULL) { 17881 testtri.sh = *virusloop; 17882 // Check each of the triangle's three neighbors. 17883 for (i = 0; i < 3; i++) { 17884 // Find the neighbor. 17885 spivot(testtri, neighbor); 17886 // Check for a subsegment between the triangle and its neighbor. 17887 sspivot(testtri, neighborsubseg); 17888 // Check if the neighbor is nonexistent or already infected. 17889 if ((neighbor.sh == dummysh) || sinfected(neighbor)) { 17890 if (neighborsubseg.sh != dummysh) { 17891 // There is a subsegment separating the triangle from its 17892 // neighbor, but both triangles are dying, so the subsegment 17893 // dies too. 17894 shellfacedealloc(subsegs, neighborsubseg.sh); 17895 if (neighbor.sh != dummysh) { 17896 // Make sure the subsegment doesn't get deallocated again 17897 // later when the infected neighbor is visited. 17898 ssdissolve(neighbor); 17899 } 17900 } 17901 } else { // The neighbor exists and is not infected. 17902 if (neighborsubseg.sh == dummysh) { 17903 // There is no subsegment protecting the neighbor, so the 17904 // neighbor becomes infected. 17905 sinfect(neighbor); 17906 // Ensure that the neighbor's neighbors will be infected. 17907 deadshellface = (shellface **) viri->alloc(); 17908 *deadshellface = neighbor.sh; 17909 } else { // The neighbor is protected by a subsegment. 17910 // Remove this triangle from the subsegment. 17911 ssbond(neighbor, neighborsubseg); 17912 } 17913 } 17914 senextself(testtri); 17915 } 17916 virusloop = (shellface **) viri->traverse(); 17917 } 17918 17919 ghostsh.sh = dummysh; // A handle of outer space. 17920 viri->traversalinit(); 17921 virusloop = (shellface **) viri->traverse(); 17922 while (virusloop != (shellface **) NULL) { 17923 testtri.sh = *virusloop; 17924 // Record changes in the number of boundary edges, and disconnect 17925 // dead triangles from their neighbors. 17926 for (i = 0; i < 3; i++) { 17927 spivot(testtri, neighbor); 17928 if (neighbor.sh != dummysh) { 17929 // Disconnect the triangle from its neighbor. 17930 // sdissolve(neighbor); 17931 sbond(neighbor, ghostsh); 17932 } 17933 senextself(testtri); 17934 } 17935 // Return the dead triangle to the pool of triangles. 17936 shellfacedealloc(subfaces, testtri.sh); 17937 virusloop = (shellface **) viri->traverse(); 17938 } 17939 // Empty the virus pool. 17940 viri->restart(); 17941 } 17942 17944 // // 17945 // carveholessub() Find the holes and infect them. Find the area // 17946 // constraints and infect them. Infect the convex hull. // 17947 // Spread the infection and kill triangles. Spread the // 17948 // area constraints. // 17949 // // 17950 // This routine mainly calls other routines to carry out all these functions.// 17951 // // 17953 17954 void tetgenmesh::carveholessub(int holes, REAL* holelist, memorypool *viri) 17955 { 17956 face searchtri, triangleloop; 17957 shellface **holetri; 17958 enum locateresult intersect; 17959 int i; 17960 17961 // Mark as infected any unprotected triangles on the boundary. 17962 // This is one way by which concavities are created. 17963 infecthullsub(viri); 17964 17965 if (holes > 0) { 17966 // Infect each triangle in which a hole lies. 17967 for (i = 0; i < 3 * holes; i += 3) { 17968 // Ignore holes that aren't within the bounds of the mesh. 17969 if ((holelist[i] >= xmin) && (holelist[i] <= xmax) 17970 && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax) 17971 && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) { 17972 // Start searching from some triangle on the outer boundary. 17973 searchtri.sh = dummysh; 17974 // Find a triangle that contains the hole. 17975 intersect = locatesub(&holelist[i], &searchtri, 0, 0.0); 17976 if ((intersect != OUTSIDE) && (!sinfected(searchtri))) { 17977 // Infect the triangle. This is done by marking the triangle 17978 // as infected and including the triangle in the virus pool. 17979 sinfect(searchtri); 17980 holetri = (shellface **) viri->alloc(); 17981 *holetri = searchtri.sh; 17982 } 17983 } 17984 } 17985 } 17986 17987 if (viri->items > 0) { 17988 // Carve the holes and concavities. 17989 plaguesub(viri); 17990 } 17991 // The virus pool should be empty now. 17992 } 17993 17995 // // 17996 // triangulate() Triangulate a PSLG into a CDT. // 17997 // // 17998 // A Planar Straight Line Graph (PSLG) P is actually a 2D polygonal region, // 17999 // possibly contains holes, segments and vertices in its interior. P is tri- // 18000 // angulated into a set of _subfaces_ forming a CDT of P. // 18001 // // 18002 // The vertices and segments of P are found in 'ptlist' and 'conlist', resp- // 18003 // ectively. 'holelist' contains a list of hole points. 'shmark' will be set // 18004 // to all subfaces of P. // 18005 // // 18006 // The CDT is created directly in the pools 'subfaces' and 'subsegs'. It can // 18007 // be retrived by a broadth-first searching starting from 'dummysh[0]'(debug // 18008 // function 'outsurfmesh()' does it). // 18009 // // 18011 18012 void tetgenmesh::triangulate(int shmark, REAL eps, list* ptlist, list* conlist, 18013 int holes, REAL* holelist, memorypool* viri, queue* flipqueue) 18014 { 18015 face newsh; 18016 point *cons; 18017 int i; 18018 18019 if (b->verbose > 1) { 18020 printf(" %d vertices, %d segments", ptlist->len(), conlist->len()); 18021 if (holes > 0) { 18022 printf(", %d holes", holes); 18023 } 18024 printf(", shmark: %d.\n", shmark); 18025 } 18026 18027 // Create the DT of V by the 2D incremental flip algorithm. 18028 incrflipdelaunaysub(shmark, eps, ptlist, holes, holelist, flipqueue); 18029 // Recover boundary edges. 18030 if (ptlist->len() > 3) { 18031 // Insert segments into the DT. 18032 for (i = 0; i < conlist->len(); i++) { 18033 cons = (point *)(* conlist)[i]; 18034 recoversegment(cons[0], cons[1], flipqueue); 18035 } 18036 // Carve holes and concavities. 18037 carveholessub(holes, holelist, viri); 18038 } else if (ptlist->len() == 3) { 18039 // Insert 3 segments directly. 18040 newsh.sh = dummysh; 18041 newsh.shver = 0; 18042 spivotself(newsh); 18043 for (i = 0; i < 3; i++) { 18044 insertsubseg(&newsh); 18045 senextself(newsh); 18046 } 18047 } else if (ptlist->len() == 2) { 18048 // This facet is actually a segment. It is not support by the mesh data 18049 // strcuture. Hence the segment will not be maintained in the mesh. 18050 // However, during segment recovery, the segment can be processed. 18051 cons = (point *)(* conlist)[0]; 18052 makeshellface(subsegs, &newsh); 18053 setsorg(newsh, cons[0]); 18054 setsdest(newsh, cons[1]); 18055 } 18056 } 18057 18059 // // 18060 // retrievenewsubs() Retrieve newly created subfaces. // 18061 // // 18062 // The new subfaces created by triangulate() can be found by a broadth-first // 18063 // searching starting from 'dummysh[0]'. // 18064 // // 18065 // 'newshlist' (empty on input) returns the retrieved subfaces. Each edge on // 18066 // the hull is bound to 'dummysh' and protected by a segment. If 'removeseg' // 18067 // is TRUE, the segment is removed. // 18068 // // 18070 18071 void tetgenmesh::retrievenewsubs(list* newshlist, bool removeseg) 18072 { 18073 face startsh, neighsh; 18074 face deadseg; 18075 int i, j; 18076 18077 // The first new subface is found at dummysh[0]. 18078 startsh.sh = dummysh; 18079 startsh.shver = 0; 18080 spivotself(startsh); 18081 assert(startsh.sh != dummysh); 18082 sinfect(startsh); 18083 newshlist->append(&startsh); 18084 18085 // Find the rest of new subfaces by a broadth-first searching. 18086 for (i = 0; i < newshlist->len(); i++) { 18087 // Get a new subface s. 18088 startsh = * (face *)(* newshlist)[i]; 18089 for (j = 0; j < 3; j++) { 18090 spivot(startsh, neighsh); 18091 if (neighsh.sh != dummysh) { 18092 if (!sinfected(neighsh)) { 18093 // Discovered a new subface. 18094 sinfect(neighsh); 18095 newshlist->append(&neighsh); 18096 } 18097 } else { 18098 // Found a boundary edge. 18099 if (removeseg) { 18100 // This side of s may be protected by a segment. 18101 sspivot(startsh, deadseg); 18102 if (deadseg.sh != dummysh) { 18103 // Detach it from s. 18104 ssdissolve(startsh); 18105 // Delete the segment. 18106 shellfacedealloc(subsegs, deadseg.sh); 18107 } 18108 } 18109 } 18110 senextself(startsh); 18111 } 18112 } 18113 for (i = 0; i < newshlist->len(); i++) { 18114 startsh = * (face *)(* newshlist)[i]; 18115 suninfect(startsh); 18116 } 18117 } 18118 18120 // // 18121 // unifysegments() Unify identical segments and build facet connections. // 18122 // // 18123 // After creating the surface mesh. Each facet has its own segments. There // 18124 // are duplicated segments between adjacent facets. This routine has three // 18125 // purposes: // 18126 // (1) identify the set of segments which have the same endpoints and // 18127 // unify them into one segment, remove redundant ones; // 18128 // (2) create the face rings of the unified segments, hence setup the // 18129 // connections between facets; and // 18130 // (3) set a unique marker (1-based) for each segment. // 18131 // On finish, each segment is unique and the face ring around it (right-hand // 18132 // rule) is constructed. The connections between facets-facets are setup. // 18133 // // 18135 18136 void tetgenmesh::unifysegments() 18137 { 18138 list *sfacelist; 18139 shellface **facesperverlist; 18140 face subsegloop, testseg; 18141 face sface, sface1, sface2; 18142 point torg, tdest; 18143 REAL da1, da2; 18144 int *idx2facelist; 18145 int segmarker; 18146 int idx, k, m; 18147 18148 if (b->verbose > 0) { 18149 printf(" Unifying segments.\n"); 18150 } 18151 18152 // Compute a mapping from indices of vertices to subfaces. 18153 makesubfacemap(idx2facelist, facesperverlist); 18154 // Initialize 'sfacelist' for constructing the face link of each segment. 18155 sfacelist = new list(sizeof(face), NULL); 18156 18157 segmarker = 1; 18158 subsegs->traversalinit(); 18159 subsegloop.sh = shellfacetraverse(subsegs); 18160 while (subsegloop.sh != (shellface *) NULL) { 18161 subsegloop.shver = 0; // For sure. 18162 torg = sorg(subsegloop); 18163 tdest = sdest(subsegloop); 18164 idx = pointmark(torg) - in->firstnumber; 18165 // Loop through the set of subfaces containing 'torg'. Get all the 18166 // subfaces containing the edge (torg, tdest). Save and order them 18167 // in 'sfacelist', the ordering is defined by the right-hand rule 18168 // with thumb points from torg to tdest. 18169 for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) { 18170 sface.sh = facesperverlist[k]; 18171 sface.shver = 0; 18172 // sface may be died due to the removing of duplicated subfaces. 18173 if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) { 18174 // 'sface' contains this segment. 18175 findedge(&sface, torg, tdest); 18176 // Save it in 'sfacelist'. 18177 if (sfacelist->len() < 2) { 18178 sfacelist->append(&sface); 18179 } else { 18180 for (m = 0; m < sfacelist->len() - 1; m++) { 18181 sface1 = * (face *)(* sfacelist)[m]; 18182 sface2 = * (face *)(* sfacelist)[m + 1]; 18183 da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface)); 18184 da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2)); 18185 if (da1 < da2) { 18186 break; // Insert it after m. 18187 } 18188 } 18189 sfacelist->insert(m + 1, &sface); 18190 } 18191 } 18192 } 18193 if (b->verbose > 1) { 18194 printf(" Identifying %d segments of (%d %d).\n", sfacelist->len(), 18195 pointmark(torg), pointmark(tdest)); 18196 } 18197 // Set the connection between this segment and faces containing it, 18198 // at the same time, remove redundant segments. 18199 for (k = 0; k < sfacelist->len(); k++) { 18200 sface = *(face *)(* sfacelist)[k]; 18201 sspivot(sface, testseg); 18202 // If 'testseg' is not 'subsegloop', it is a redundant segment that 18203 // needs be removed. BE CAREFUL it may already be removed. Do not 18204 // remove it twice, i.e., do test 'isdead()' together. 18205 if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) { 18206 shellfacedealloc(subsegs, testseg.sh); 18207 } 18208 // 'ssbond' bonds the subface and the segment together, and dissloves 18209 // the old bond as well. 18210 ssbond(sface, subsegloop); 18211 } 18212 // Set connection between these faces. 18213 sface = *(face *)(* sfacelist)[0]; 18214 for (k = 1; k <= sfacelist->len(); k++) { 18215 if (k < sfacelist->len()) { 18216 sface1 = *(face *)(* sfacelist)[k]; 18217 } else { 18218 sface1 = *(face *)(* sfacelist)[0]; // Form a face loop. 18219 } 18220 /* 18221 // Check if these two subfaces are the same. It is possible when user 18222 // defines one facet (or polygon) two or more times. If they are, 18223 // they should not be bonded together, instead of that, one of them 18224 // should be delete from the surface mesh. 18225 if ((sfacelist->len() > 1) && sapex(sface) == sapex(sface1)) { 18226 // They are duplicated faces. 18227 if (b->verbose > 0) { 18228 printf(" A duplicated subface (%d, %d, %d) is removed.\n", 18229 pointmark(torg), pointmark(tdest), pointmark(sapex(sface))); 18230 } 18231 if (k == sfacelist->len()) { 18232 // 'sface' is the last face, however, it is same as the first one. 18233 // In order to form the ring, we have to let the second last 18234 // face bond to the first one 'sface1'. 18235 shellfacedealloc(subfaces, sface.sh); 18236 assert(sfacelist->len() >= 2); 18237 assert(k == sfacelist->len()); 18238 sface = *(face *)(* sfacelist)[k - 2]; 18239 } else { 18240 // 'sface1' is in the middle and may be the last one. 18241 shellfacedealloc(subfaces, sface1.sh); 18242 // Skip this face and go to the next one. 18243 continue; 18244 } 18245 } 18246 */ 18247 if (b->verbose > 2) { 18248 printf(" Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n", 18249 pointmark(torg), pointmark(tdest), pointmark(sapex(sface)), 18250 pointmark(torg), pointmark(tdest), pointmark(sapex(sface1))); 18251 } 18252 sbond1(sface, sface1); 18253 sface = sface1; 18254 } 18255 // Set the unique segment marker into the unified segment. 18256 setshellmark(subsegloop, segmarker); 18257 // Increase the marker. 18258 segmarker++; 18259 // Clear the working list. 18260 sfacelist->clear(); 18261 subsegloop.sh = shellfacetraverse(subsegs); 18262 } 18263 18264 delete [] idx2facelist; 18265 delete [] facesperverlist; 18266 delete sfacelist; 18267 } 18268 18270 // // 18271 // mergefacets() Merge adjacent facets to be one facet if they are // 18272 // coplanar and have the same boundary marker. // 18273 // // 18274 // Segments between two merged facets will be removed from the mesh. If all // 18275 // segments around a vertex have been removed, change its vertex type to be // 18276 // FREESUBVERTEX. Edge flips will be performed to ensure the Delaunayness of // 18277 // the triangulation of merged facets. // 18278 // // 18280 18281 void tetgenmesh::mergefacets(queue* flipqueue) 18282 { 18283 face parentsh, neighsh, neineighsh; 18284 face segloop; 18285 point eorg, edest; 18286 REAL ori; 18287 bool mergeflag, pbcflag; 18288 int* segspernodelist; 18289 int fidx1, fidx2; 18290 int i, j; 18291 18292 if (b->verbose > 0) { 18293 printf(" Merging coplanar facets.\n"); 18294 } 18295 // Create and initialize 'segspernodelist'. 18296 segspernodelist = new int[points->items + 1]; 18297 for (i = 0; i < points->items + 1; i++) segspernodelist[i] = 0; 18298 18299 // Loop the segments, counter the number of segments sharing each vertex. 18300 subsegs->traversalinit(); 18301 segloop.sh = shellfacetraverse(subsegs); 18302 while (segloop.sh != (shellface *) NULL) { 18303 // Increment the number of sharing segments for each endpoint. 18304 for (i = 0; i < 2; i++) { 18305 j = pointmark((point) segloop.sh[3 + i]); 18306 segspernodelist[j]++; 18307 } 18308 segloop.sh = shellfacetraverse(subsegs); 18309 } 18310 18311 // Loop the segments, find out dead segments. 18312 subsegs->traversalinit(); 18313 segloop.sh = shellfacetraverse(subsegs); 18314 while (segloop.sh != (shellface *) NULL) { 18315 eorg = sorg(segloop); 18316 edest = sdest(segloop); 18317 spivot(segloop, parentsh); 18318 spivot(parentsh, neighsh); 18319 spivot(neighsh, neineighsh); 18320 if (parentsh.sh != neighsh.sh && parentsh.sh == neineighsh.sh) { 18321 // Exactly two subfaces at this segment. 18322 fidx1 = shellmark(parentsh) - 1; 18323 fidx2 = shellmark(neighsh) - 1; 18324 pbcflag = false; 18325 if (checkpbcs) { 18326 pbcflag = (shellpbcgroup(parentsh) >= 0) 18327 || (shellpbcgroup(neighsh) >= 0); 18328 } 18329 // Possibly merge them if they are not in the same facet. 18330 if ((fidx1 != fidx2) && !pbcflag) { 18331 // Test if they are coplanar. 18332 ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh)); 18333 if (ori != 0.0) { 18334 if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori, 18335 b->epsilon)) { 18336 ori = 0.0; // They are assumed as coplanar. 18337 } 18338 } 18339 if (ori == 0.0) { 18340 mergeflag = (in->facetmarkerlist == (int *) NULL || 18341 in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]); 18342 if (mergeflag) { 18343 // This segment becomes dead. 18344 if (b->verbose > 1) { 18345 printf(" Removing segment (%d, %d).\n", pointmark(eorg), 18346 pointmark(edest)); 18347 } 18348 ssdissolve(parentsh); 18349 ssdissolve(neighsh); 18350 shellfacedealloc(subsegs, segloop.sh); 18351 j = pointmark(eorg); 18352 segspernodelist[j]--; 18353 if (segspernodelist[j] == 0) { 18354 setpointtype(eorg, FREESUBVERTEX); 18355 } 18356 j = pointmark(edest); 18357 segspernodelist[j]--; 18358 if (segspernodelist[j] == 0) { 18359 setpointtype(edest, FREESUBVERTEX); 18360 } 18361 // Add 'parentsh' to queue checking for flip. 18362 enqueueflipedge(parentsh, flipqueue); 18363 } 18364 } 18365 } 18366 } 18367 segloop.sh = shellfacetraverse(subsegs); 18368 } 18369 18370 if (!flipqueue->empty()) { 18371 // Restore the Delaunay property in the facet triangulation. 18372 flipsub(flipqueue); 18373 } 18374 18375 delete [] segspernodelist; 18376 } 18377 18379 // // 18380 // meshsurface() Create the surface mesh of a PLC. // 18381 // // 18382 // Let X be the PLC, the surface mesh S of X consists of triangulated facets.// 18383 // S is created mainly in the following steps: // 18384 // // 18385 // (1) Form the CDT of each facet of X separately (by routine triangulate()).// 18386 // After it is done, the subfaces of each facet are connected to each other, // 18387 // however there is no connection between facets yet. Notice each facet has // 18388 // its own segments, some of them are duplicated. // 18389 // // 18390 // (2) Remove the redundant segments created in step (1) (by routine unify- // 18391 // segment()). The subface ring of each segment is created, the connection // 18392 // between facets are established as well. // 18393 // // 18394 // The return value indicates the number of segments of X. // 18395 // // 18397 18398 long tetgenmesh::meshsurface() 18399 { 18400 list *ptlist, *conlist; 18401 queue *flipqueue; 18402 tetgenio::facet *f; 18403 tetgenio::polygon *p; 18404 memorypool *viri; 18405 point *idx2verlist; 18406 point tstart, tend, *cons; 18407 int *worklist; 18408 int end1, end2; 18409 int shmark, i, j; 18410 18411 if (!b->quiet) { 18412 printf("Creating surface mesh.\n"); 18413 } 18414 18415 // Compute a mapping from indices to points. 18416 makeindex2pointmap(idx2verlist); 18417 // Compute a mapping from points to tets for computing abovepoints. 18418 makepoint2tetmap(); 18419 // Initialize 'facetabovepointarray'. 18420 facetabovepointarray = new point[in->numberoffacets + 1]; 18421 for (i = 0; i < in->numberoffacets + 1; i++) { 18422 facetabovepointarray[i] = (point) NULL; 18423 } 18424 if (checkpbcs) { 18425 // Initialize the global array 'subpbcgrouptable'. 18426 createsubpbcgrouptable(); 18427 } 18428 18429 // Initialize working lists. 18430 viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0); 18431 flipqueue = new queue(sizeof(badface)); 18432 ptlist = new list(sizeof(point *), NULL, 256); 18433 conlist = new list(sizeof(point *) * 2, NULL, 256); 18434 worklist = new int[points->items + 1]; 18435 for (i = 0; i < points->items + 1; i++) worklist[i] = 0; 18436 18437 // Loop the facet list, triangulate each facet. On finish, all subfaces 18438 // are in 'subfaces', all segments are in 'subsegs'. Notice: there're 18439 // redundant segments. Remember: All facet indices count from 1. 18440 for (shmark = 1; shmark <= in->numberoffacets; shmark++) { 18441 // Get a facet F. 18442 f = &in->facetlist[shmark - 1]; 18443 18444 // Process the duplicated points first, they are marked with type 18445 // DUPLICATEDVERTEX by incrflipdelaunay(). Let p and q are dup. 18446 // and the index of p is larger than q's, p is substituted by q. 18447 // In a STL mesh, duplicated points are implicitly included. 18448 if ((b->object == tetgenbehavior::STL) || dupverts) { 18449 // Loop all polygons of this facet. 18450 for (i = 0; i < f->numberofpolygons; i++) { 18451 p = &(f->polygonlist[i]); 18452 // Loop other vertices of this polygon. 18453 for (j = 0; j < p->numberofvertices; j++) { 18454 end1 = p->vertexlist[j]; 18455 tstart = idx2verlist[end1 - in->firstnumber]; 18456 if (pointtype(tstart) == DUPLICATEDVERTEX) { 18457 // Reset the index of vertex-j. 18458 tend = point2ppt(tstart); 18459 end2 = pointmark(tend); 18460 p->vertexlist[j] = end2; 18461 } 18462 } 18463 } 18464 } 18465 18466 // Loop polygons of F, get the set V of vertices and S of segments. 18467 for (i = 0; i < f->numberofpolygons; i++) { 18468 // Get a polygon. 18469 p = &(f->polygonlist[i]); 18470 // Get the first vertex. 18471 end1 = p->vertexlist[0]; 18472 if ((end1 < in->firstnumber) || 18473 (end1 >= in->firstnumber + in->numberofpoints)) { 18474 if (!b->quiet) { 18475 printf("Warning: Invalid the 1st vertex %d of polygon", end1); 18476 printf(" %d in facet %d.\n", i + 1, shmark); 18477 } 18478 continue; // Skip this polygon. 18479 } 18480 tstart = idx2verlist[end1 - in->firstnumber]; 18481 // Add tstart to V if it haven't been added yet. 18482 if (worklist[end1] == 0) { 18483 ptlist->append(&tstart); 18484 worklist[end1] = 1; 18485 } 18486 // Loop other vertices of this polygon. 18487 for (j = 1; j <= p->numberofvertices; j++) { 18488 // get a vertex. 18489 if (j < p->numberofvertices) { 18490 end2 = p->vertexlist[j]; 18491 } else { 18492 end2 = p->vertexlist[0]; // Form a loop from last to first. 18493 } 18494 if ((end2 < in->firstnumber) || 18495 (end2 >= in->firstnumber + in->numberofpoints)) { 18496 if (!b->quiet) { 18497 printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1); 18498 printf(" in facet %d.\n", shmark); 18499 } 18500 } else { 18501 if (end1 != end2) { 18502 // 'end1' and 'end2' form a segment. 18503 tend = idx2verlist[end2 - in->firstnumber]; 18504 // Add tstart to V if it haven't been added yet. 18505 if (worklist[end2] == 0) { 18506 ptlist->append(&tend); 18507 worklist[end2] = 1; 18508 } 18509 // Save the segment in S (conlist). 18510 cons = (point *) conlist->append(NULL); 18511 cons[0] = tstart; 18512 cons[1] = tend; 18513 // Set the start for next continuous segment. 18514 end1 = end2; 18515 tstart = tend; 18516 } else { 18517 // Two identical vertices represent an isolated vertex of F. 18518 if (p->numberofvertices > 2) { 18519 // This may be an error in the input, anyway, we can continue 18520 // by simply skipping this segment. 18521 if (!b->quiet) { 18522 printf("Warning: Polygon %d has two identical verts", i + 1); 18523 printf(" in facet %d.\n", shmark); 18524 } 18525 } 18526 // Ignore this vertex. 18527 } 18528 } 18529 // Is the polygon degenerate (a segment or a vertex)? 18530 if (p->numberofvertices == 2) break; 18531 } 18532 } 18533 // Unmark vertices. 18534 for (i = 0; i < ptlist->len(); i++) { 18535 tstart = * (point *)(* ptlist)[i]; 18536 end1 = pointmark(tstart); 18537 assert(worklist[end1] == 1); 18538 worklist[end1] = 0; 18539 } 18540 18541 // Create a CDT of F. 18542 triangulate(shmark, b->epsilon * 1e+2, ptlist, conlist, f->numberofholes, 18543 f->holelist, viri, flipqueue); 18544 // Clear working lists. 18545 ptlist->clear(); 18546 conlist->clear(); 18547 viri->restart(); 18548 } 18549 18550 // Unify segments in 'subsegs', remove redundant segments. Face links 18551 // of segments are also built. 18552 unifysegments(); 18553 // Remember the number of input segments (for output). 18554 insegments = subsegs->items; 18555 18556 if (checkpbcs) { 18557 // Create the global array 'segpbcgrouptable'. 18558 createsegpbcgrouptable(); 18559 } 18560 18561 if (b->object == tetgenbehavior::STL) { 18562 // Remove redundant vertices (for .stl input mesh). 18563 jettisonnodes(); 18564 } 18565 18566 if (!b->nomerge && !b->nobisect && !checkpbcs) { 18567 // No '-M' switch - merge adjacent facets if they are coplanar. 18568 mergefacets(flipqueue); 18569 } 18570 18571 delete [] idx2verlist; 18572 delete [] worklist; 18573 delete ptlist; 18574 delete conlist; 18575 delete flipqueue; 18576 delete viri; 18577 18578 return subsegs->items; 18579 } 18580 18581 // 18582 // End of surface triangulation routines 18583 // 18584 18586 // // 18587 // interecursive() Recursively do intersection test on a set of triangles.// 18588 // // 18589 // Recursively split the set 'subfacearray' of subfaces into two sets using // 18590 // a cut plane parallel to x-, or, y-, or z-axies. The split criteria are // 18591 // follows. Assume the cut plane is H, and H+ denotes the left halfspace of // 18592 // H, and H- denotes the right halfspace of H; and s be a subface: // 18593 // // 18594 // (1) If all points of s lie at H+, put it into left array; // 18595 // (2) If all points of s lie at H-, put it into right array; // 18596 // (3) If some points of s lie at H+ and some of lie at H-, or some // 18597 // points lie on H, put it into both arraies. // 18598 // // 18599 // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis // 18600 // if axis == '2'. If current cut plane is parallel to the x-axis, the next // 18601 // one will be parallel to y-axis, and the next one after the next is z-axis,// 18602 // and then alternately return back to x-axis. // 18603 // // 18604 // Stop splitting when the number of triangles of the input array is not // 18605 // decreased anymore. Do tests on the current set. // 18606 // // 18608 18609 void tetgenmesh:: 18610 interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin, 18611 REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax, 18612 int* internum) 18613 { 18614 shellface **leftarray, **rightarray; 18615 face sface1, sface2; 18616 point p1, p2, p3; 18617 point p4, p5, p6; 18618 enum interresult intersect; 18619 REAL split; 18620 bool toleft, toright; 18621 int leftsize, rightsize; 18622 int i, j; 18623 18624 if (b->verbose > 1) { 18625 printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n", 18626 arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax, 18627 axis == 0 ? "x" : (axis == 1 ? "y" : "z")); 18628 } 18629 18630 leftarray = new shellface*[arraysize]; 18631 if (leftarray == NULL) { 18632 printf("Error in interecursive(): Insufficient memory.\n"); 18633 terminatetetgen(1); 18634 } 18635 rightarray = new shellface*[arraysize]; 18636 if (rightarray == NULL) { 18637 printf("Error in interecursive(): Insufficient memory.\n"); 18638 terminatetetgen(1); 18639 } 18640 leftsize = rightsize = 0; 18641 18642 if (axis == 0) { 18643 // Split along x-axis. 18644 split = 0.5 * (bxmin + bxmax); 18645 } else if (axis == 1) { 18646 // Split along y-axis. 18647 split = 0.5 * (bymin + bymax); 18648 } else { 18649 // Split along z-axis. 18650 split = 0.5 * (bzmin + bzmax); 18651 } 18652 18653 for (i = 0; i < arraysize; i++) { 18654 sface1.sh = subfacearray[i]; 18655 p1 = (point) sface1.sh[3]; 18656 p2 = (point) sface1.sh[4]; 18657 p3 = (point) sface1.sh[5]; 18658 toleft = toright = false; 18659 if (p1[axis] < split) { 18660 toleft = true; 18661 if (p2[axis] >= split || p3[axis] >= split) { 18662 toright = true; 18663 } 18664 } else if (p1[axis] > split) { 18665 toright = true; 18666 if (p2[axis] <= split || p3[axis] <= split) { 18667 toleft = true; 18668 } 18669 } else { 18670 // p1[axis] == split; 18671 toleft = true; 18672 toright = true; 18673 } 18674 // At least one is true; 18675 #ifdef SELF_CHECK 18676 assert(!(toleft == false && toright == false)); 18677 #endif 18678 if (toleft) { 18679 leftarray[leftsize] = sface1.sh; 18680 leftsize++; 18681 } 18682 if (toright) { 18683 rightarray[rightsize] = sface1.sh; 18684 rightsize++; 18685 } 18686 } 18687 18688 if (leftsize < arraysize && rightsize < arraysize) { 18689 // Continue to partition the input set. Now 'subfacearray' has been 18690 // split into two sets, it's memory can be freed. 'leftarray' and 18691 // 'rightarray' will be freed in the next recursive (after they're 18692 // partitioned again or performing tests). 18693 delete [] subfacearray; 18694 // Continue to split these two sets. 18695 if (axis == 0) { 18696 interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax, 18697 bzmin, bzmax, internum); 18698 interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax, 18699 bzmin, bzmax, internum); 18700 } else if (axis == 1) { 18701 interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split, 18702 bzmin, bzmax, internum); 18703 interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax, 18704 bzmin, bzmax, internum); 18705 } else { 18706 interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax, 18707 bzmin, split, internum); 18708 interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax, 18709 split, bzmax, internum); 18710 } 18711 } else { 18712 if (b->verbose > 1) { 18713 printf(" Checking intersecting faces.\n"); 18714 } 18715 // Perform a brute-force compare on the set. 18716 for (i = 0; i < arraysize; i++) { 18717 sface1.sh = subfacearray[i]; 18718 p1 = (point) sface1.sh[3]; 18719 p2 = (point) sface1.sh[4]; 18720 p3 = (point) sface1.sh[5]; 18721 for (j = i + 1; j < arraysize; j++) { 18722 sface2.sh = subfacearray[j]; 18723 p4 = (point) sface2.sh[3]; 18724 p5 = (point) sface2.sh[4]; 18725 p6 = (point) sface2.sh[5]; 18726 intersect = tri_tri_inter(p1, p2, p3, p4, p5, p6); 18727 if (intersect == INTERSECT || intersect == SHAREFACE) { 18728 if (!b->quiet) { 18729 if (intersect == INTERSECT) { 18730 printf(" Facet #%d intersects facet #%d at triangles:\n", 18731 shellmark(sface1), shellmark(sface2)); 18732 printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n", 18733 pointmark(p1), pointmark(p2), pointmark(p3), 18734 pointmark(p4), pointmark(p5), pointmark(p6)); 18735 } else { 18736 printf(" Facet #%d duplicates facet #%d at triangle:\n", 18737 shellmark(sface1), shellmark(sface2)); 18738 printf(" (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2), 18739 pointmark(p3)); 18740 } 18741 } 18742 // Increase the number of intersecting pairs. 18743 (*internum)++; 18744 // Infect these two faces (although they may already be infected). 18745 sinfect(sface1); 18746 sinfect(sface2); 18747 } 18748 } 18749 } 18750 // Don't forget to free all three arrays. No further partition. 18751 delete [] leftarray; 18752 delete [] rightarray; 18753 delete [] subfacearray; 18754 } 18755 } 18756 18758 // // 18759 // detectinterfaces() Detect intersecting triangles. // 18760 // // 18761 // Given a set of triangles, find the pairs of intersecting triangles from // 18762 // them. Here the set of triangles is in 'subfaces' which is a surface mesh // 18763 // of a PLC (.poly or .smesh). // 18764 // // 18765 // To detect whether two triangles are intersecting is done by the routine // 18766 // 'tri_tri_inter()'. The algorithm for the test is very simple and stable. // 18767 // It is based on geometric orientation test which uses exact arithmetics. // 18768 // // 18769 // Use divide-and-conquer algorithm for reducing the number of intersection // 18770 // tests. Start from the bounding box of the input point set, recursively // 18771 // partition the box into smaller boxes, until the number of triangles in a // 18772 // box is not decreased anymore. Then perform triangle-triangle tests on the // 18773 // remaining set of triangles. The memory allocated in the input set is // 18774 // freed immediately after it has been partitioned into two arrays. So it // 18775 // can be re-used for the consequent partitions. // 18776 // // 18777 // On return, the pool 'subfaces' will be cleared, and only the intersecting // 18778 // triangles remain for output (to a .face file). // 18779 // // 18781 18782 void tetgenmesh::detectinterfaces() 18783 { 18784 shellface **subfacearray; 18785 face shloop; 18786 int internum; 18787 int i; 18788 18789 if (!b->quiet) { 18790 printf("Detecting intersecting facets.\n"); 18791 } 18792 18793 // Construct a map from indices to subfaces; 18794 subfacearray = new shellface*[subfaces->items]; 18795 subfaces->traversalinit(); 18796 shloop.sh = shellfacetraverse(subfaces); 18797 i = 0; 18798 while (shloop.sh != (shellface *) NULL) { 18799 subfacearray[i] = shloop.sh; 18800 shloop.sh = shellfacetraverse(subfaces); 18801 i++; 18802 } 18803 18804 internum = 0; 18805 // Recursively split the set of triangles into two sets using a cut plane 18806 // parallel to x-, or, y-, or z-axies. Stop splitting when the number 18807 // of subfaces is not decreasing anymore. Do tests on the current set. 18808 interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax, 18809 zmin, zmax, &internum); 18810 18811 if (!b->quiet) { 18812 if (internum > 0) { 18813 printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum); 18814 } else { 18815 printf("\nNo faces are intersecting.\n\n"); 18816 } 18817 } 18818 18819 if (internum > 0) { 18820 // Traverse all subfaces, deallocate those have not been infected (they 18821 // are not intersecting faces). Uninfect those have been infected. 18822 // After this loop, only intersecting faces remain. 18823 subfaces->traversalinit(); 18824 shloop.sh = shellfacetraverse(subfaces); 18825 while (shloop.sh != (shellface *) NULL) { 18826 if (sinfected(shloop)) { 18827 suninfect(shloop); 18828 } else { 18829 shellfacedealloc(subfaces, shloop.sh); 18830 } 18831 shloop.sh = shellfacetraverse(subfaces); 18832 } 18833 } else { 18834 // Deallocate all subfaces. 18835 subfaces->restart(); 18836 } 18837 } 18838 18839 // 18840 // Begin of periodic boundary condition routines 18841 // 18842 18844 // // 18845 // createsubpbcgrouptable() Create the 'subpbcgrouptable'. // 18846 // // 18847 // Allocate the memory for 'subpbcgrouptable'. Each entry i (a pbcdata) of // 18848 // the table represents a pbcgroup. Most of the fields of a group-i are set // 18849 // in this routine. 'fmark[0]', 'fmark[1]', and 'transmat[0]' are directly // 18850 // copied from the corresponding data of 'in->numberofpbcgroups'. 'transmat // 18851 // [1]' is calculated as the inverse matrix of 'transmat[0]'. 'ss[0]' and // 18852 // 'ss[1]' are initilized be 'dummysh'. They are set in 'trangulatefacet()' // 18853 // (when -p is in use) or 'reconstructmesh()' (when -r is in use). // 18854 // // 18856 18857 void tetgenmesh::createsubpbcgrouptable() 18858 { 18859 tetgenio::pbcgroup *pg; 18860 pbcdata *pd; 18861 REAL A[4][4], rhs[4], D; 18862 int indx[4]; 18863 int i, j, k; 18864 18865 subpbcgrouptable = new pbcdata[in->numberofpbcgroups]; 18866 for (i = 0; i < in->numberofpbcgroups; i++) { 18867 pg = &(in->pbcgrouplist[i]); 18868 pd = &(subpbcgrouptable[i]); 18869 // Copy data from pg to pd. 18870 pd->fmark[0] = pg->fmark1; 18871 pd->fmark[1] = pg->fmark2; 18872 // Initialize array 'pd->ss'. 18873 pd->ss[0].sh = dummysh; 18874 pd->ss[1].sh = dummysh; 18875 // Copy the transform matrix from pg to pd->transmat[0]. 18876 for (j = 0; j < 4; j++) { 18877 for (k = 0; k < 4; k++) { 18878 pd->transmat[0][j][k] = pg->transmat[j][k]; 18879 // Prepare for inverting the matrix. 18880 A[j][k] = pg->transmat[j][k]; 18881 } 18882 } 18883 // Calculate the inverse matrix (pd->transmat[1]) of pd->transmat[0]. 18884 lu_decmp(A, 4, indx, &D, 0); 18885 for (j = 0; j < 4; j++) { 18886 for (k = 0; k < 4; k++) rhs[k] = 0.0; 18887 rhs[j] = 1.0; 18888 lu_solve(A, 4, indx, rhs, 0); 18889 for (k = 0; k < 4; k++) pd->transmat[1][k][j] = rhs[k]; 18890 } 18891 } 18892 } 18893 18895 // // 18896 // getsubpbcgroup() Get the pbcgroup of a subface. // 18897 // // 18898 // 'pbcsub' has pbc defined. Its pbcgroup is returned in 'pd'. In addition, // 18899 // 'f1' (0 or 1) indicates the position of 'pbcsub' in 'pd'; 'f2' (= 1 - f1) // 18900 // is the position where the symmetric subface of 'pbcsub' is found. // 18901 // // 18903 18904 void tetgenmesh::getsubpbcgroup(face* pbcsub, pbcdata** pd, int *f1, int *f2) 18905 { 18906 int groupid, fmark, idx; 18907 18908 groupid = shellpbcgroup(*pbcsub); 18909 *pd = &subpbcgrouptable[groupid]; 18910 18911 // Get the facet index (1 - based). 18912 idx = shellmark(*pbcsub); 18913 // Get the facet marker from array (0 - based). 18914 fmark = in->facetmarkerlist[idx - 1]; 18915 if ((*pd)->fmark[0] == fmark) { 18916 *f1 = 0; 18917 } else { 18918 #ifdef SELF_CHECK 18919 assert((*pd)->fmark[1] == fmark); 18920 #endif 18921 *f1 = 1; 18922 } 18923 *f2 = 1 - (*f1); 18924 } 18925 18927 // // 18928 // getsubpbcsympoint() Compute the symmetric point for a subface point. // 18929 // // 18930 // 'newpoint' lies on 'splitsub'. This routine calculates a 'sympoint' which // 18931 // locates on 'symsplitsub' and symmtric to 'newpoint'. Return the location // 18932 // of sympoint wrt. symsplitsub. // 18933 // // 18935 18936 enum tetgenmesh::locateresult tetgenmesh:: getsubpbcsympoint(point newpoint, 18937 face* splitsub, point sympoint, face* symsplitsub) 18938 { 18939 pbcdata *pd; 18940 face subloop; 18941 point pa, pb, pc; 18942 enum locateresult symloc; 18943 REAL ori; 18944 int f1, f2, i; 18945 18946 // Get the pbcgroup of 'splitsub'. 18947 getsubpbcgroup(splitsub, &pd, &f1, &f2); 18948 18949 // Transform newpoint from f1 -> f2. 18950 for (i = 0; i < 3; i++) { 18951 sympoint[i] = pd->transmat[f1][i][0] * newpoint[0] 18952 + pd->transmat[f1][i][1] * newpoint[1] 18953 + pd->transmat[f1][i][2] * newpoint[2] 18954 + pd->transmat[f1][i][3] * 1.0; 18955 } 18956 // Locate sympoint in f2. 18957 symloc = OUTSIDE; 18958 *symsplitsub = pd->ss[f2]; 18959 // Is the stored subface valid? Hole removal may delete the subface. 18960 if ((symsplitsub->sh != dummysh) && !isdead(symsplitsub)) { 18961 // 'symsplitsub' should lie on the symmetric facet. Check it. 18962 i = shellmark(*symsplitsub); 18963 if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) { 18964 // 'symsplitsub' has the symmetric boundary marker. 18965 pa = sorg(*symsplitsub); 18966 pb = sdest(*symsplitsub); 18967 pc = sapex(*symsplitsub); 18968 // Test if they are (nearly) coplanar. Some facets may have the 18969 // same boundary marker but not coplanar with this point. 18970 ori = orient3d(pa, pb, pc, sympoint); 18971 if (iscoplanar(pa, pb, pc, sympoint, ori, b->epsilon * 1e+2)) { 18972 // Locate sympoint in facet. Don't stop at subsegment. 18973 abovepoint = facetabovepointarray[shellmark(*symsplitsub)]; 18974 if (abovepoint == (point) NULL) { 18975 getfacetabovepoint(symsplitsub); 18976 } 18977 symloc = locatesub(sympoint, symsplitsub, 0, b->epsilon * 1e+2); 18978 } 18979 } 18980 } 18981 if (symloc == OUTSIDE) { 18982 // Do a brute-force searching for the symmetric subface. 18983 REAL epspp = b->epsilon * 1e+2; 18984 int lcount = 0; 18985 do { 18986 // Locate sympoint in the pool of subfaces (with fmark pd->fmark[f2]). 18987 subfaces->traversalinit(); 18988 subloop.sh = shellfacetraverse(subfaces); 18989 while (subloop.sh != (shellface *) NULL) { 18990 i = shellmark(subloop); 18991 if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) { 18992 // Found a facet have the symmetric boundary marker. 18993 pa = sorg(subloop); 18994 pb = sdest(subloop); 18995 pc = sapex(subloop); 18996 // Test if they are (nearly) coplanar. Some facets may have the 18997 // same boundary marker but not coplanar with this point. 18998 ori = orient3d(pa, pb, pc, sympoint); 18999 if (iscoplanar(pa, pb, pc, sympoint, ori, epspp)) { 19000 // Test if sympoint is (nearly) inside this facet. 19001 // Get the abovepoint of the facet. 19002 abovepoint = facetabovepointarray[shellmark(subloop)]; 19003 // Do we need to calculate the abovepoint? 19004 if (abovepoint == (point) NULL) { 19005 getfacetabovepoint(&subloop); 19006 } 19007 // subloop is on the facet, search sympoint. 19008 symloc = locatesub(sympoint, &subloop, 0, epspp); 19009 if (symloc != OUTSIDE) break; 19010 } 19011 } 19012 subloop.sh = shellfacetraverse(subfaces); 19013 } 19014 lcount++; 19015 epspp *= 10.0; 19016 } while ((symloc == OUTSIDE) && (lcount < 3)); 19017 #ifdef SELF_CHECK 19018 // sympoint should be inside the facet. 19019 assert(symloc != OUTSIDE); 19020 #endif 19021 // Set the returning subface. 19022 *symsplitsub = subloop; 19023 // Update the stored subface for next searching. 19024 pd->ss[f2] = *symsplitsub; 19025 } 19026 19027 return adjustlocatesub(sympoint, symsplitsub, symloc, b->epsilon); 19028 } 19029 19031 // // 19032 // createsegpbcgrouptable() Create the 'segpbcgrouptable'. // 19033 // // 19034 // Each segment may belong to more than one pbcgroups. For example, segment // 19035 // ab may need to be symmteric to both segments cd, and ef, then ab and cd, // 19036 // cd and ef, ef and ab form three pbcgroups. // 19037 // // 19038 // 'segpbcgrouptable' is implemented as a list of pbcdatas. Each item i is // 19039 // a pbcgroup. // 19040 // // 19042 19043 void tetgenmesh::createsegpbcgrouptable() 19044 { 19045 shellface** segsperverlist; 19046 pbcdata *pd, *ppd, pd1, pd2; 19047 face segloop, symseg; 19048 face startsh, spinsh, symsh; 19049 point pa, pb, syma, symb; 19050 enum locateresult symloc; 19051 REAL testpt[3], sympt[3]; 19052 bool inflag; 19053 int *idx2seglist; 19054 int segid1, segid2; 19055 int f1, f2; 19056 int i, j, k, l; 19057 19058 // Allocate memory for 'subpbcgrouptable'. 19059 segpbcgrouptable = new list(sizeof(pbcdata), NULL, 256); 19060 19061 if (b->refine) { 19062 // Create a point-to-seg map for quickly finding PBC seg pairs. 19063 makesegmentmap(idx2seglist, segsperverlist); 19064 } 19065 19066 // Loop through the segment list. 19067 subsegs->traversalinit(); 19068 segloop.sh = shellfacetraverse(subsegs); 19069 while (segloop.sh != (shellface *) NULL) { 19070 // Loop the subface ring of segloop ab. 19071 pa = sorg(segloop); 19072 pb = sdest(segloop); 19073 segid1 = shellmark(segloop); 19074 spivot(segloop, startsh); 19075 spinsh = startsh; 19076 do { 19077 // Adjust spinsh be edge ab. 19078 if (sorg(spinsh) != pa) { 19079 sesymself(spinsh); 19080 } 19081 // Does spinsh belong to a pbcgroup? 19082 if (shellpbcgroup(spinsh) != -1) { 19083 // Yes! There exists a segment cd. ab and cd form a pbcgroup. 19084 if (b->refine) { 19085 getsubpbcgroup(&spinsh, &pd, &f1, &f2); 19086 // Transform pa from f1 -> f2. 19087 for (i = 0; i < 3; i++) { 19088 sympt[i] = pd->transmat[f1][i][0] * pa[0] 19089 + pd->transmat[f1][i][1] * pa[1] 19090 + pd->transmat[f1][i][2] * pa[2] 19091 + pd->transmat[f1][i][3] * 1.0; 19092 } 19093 syma = point2pbcpt(pa); 19094 // Is 'sympt == syma'? 19095 if (distance(sympt, syma) > (longest * b->epsilon)) { 19096 // No. Search the symmetric vertex of pa. 19097 symloc = getsubpbcsympoint(pa, &spinsh, sympt, &symsh); 19098 syma = sorg(symsh); 19099 if (symloc != ONVERTEX) { 19100 // Do a brute force search. Not done yet. 19101 assert(0); 19102 } 19103 } 19104 // Transform pb from f1 -> f2. 19105 for (i = 0; i < 3; i++) { 19106 sympt[i] = pd->transmat[f1][i][0] * pb[0] 19107 + pd->transmat[f1][i][1] * pb[1] 19108 + pd->transmat[f1][i][2] * pb[2] 19109 + pd->transmat[f1][i][3] * 1.0; 19110 } 19111 // Search sym subface from the point-to-subface map. 19112 symseg.shver = 0; 19113 j = pointmark(syma) - in->firstnumber; 19114 for (i = idx2seglist[j]; i < idx2seglist[j + 1]; i++) { 19115 symseg.sh = segsperverlist[i]; 19116 if (sorg(symseg) == syma) symb = sdest(symseg); 19117 else symb = sorg(symseg); 19118 if (distance(sympt, symb) <= (longest * b->epsilon)) break; 19119 } 19120 assert(i < idx2seglist[j + 1]); 19121 } else { 19122 // 'testpt' is the midpoint of ab used to find cd. 19123 for (i = 0; i < 3; i++) testpt[i] = 0.5 * (pa[i] + pb[i]); 19124 symloc = getsubpbcsympoint(testpt, &spinsh, sympt, &symsh); 19125 #ifdef SELF_CHECK 19126 assert(symloc == ONEDGE); 19127 #endif 19128 sspivot(symsh, symseg); 19129 } 19130 #ifdef SELF_CHECK 19131 assert(symseg.sh != dummysh); 19132 #endif 19133 // Check whether this group has already been created in list. 19134 segid2 = shellmark(symseg); 19135 inflag = false; 19136 for (i = 0; i < segpbcgrouptable->len() && !inflag; i++) { 19137 pd = (pbcdata *)(* segpbcgrouptable)[i]; 19138 if (pd->segid[0] == segid1) { 19139 if (pd->segid[1] == segid2) inflag = true; 19140 } else if (pd->segid[0] == segid2) { 19141 if (pd->segid[1] == segid1) inflag = true; 19142 } 19143 } 19144 if (!inflag) { 19145 // Create a segment pbcgroup in list for ab and cd. 19146 pd = (pbcdata *) segpbcgrouptable->append(NULL); 19147 // Save the markers of ab and cd. 19148 pd->segid[0] = segid1; 19149 pd->segid[1] = segid2; 19150 // Save the handles of ab and cd. 19151 pd->ss[0] = segloop; 19152 pd->ss[1] = symseg; 19153 // Find the map from ab to cd. 19154 getsubpbcgroup(&spinsh, &ppd, &f1, &f2); 19155 pd->fmark[0] = ppd->fmark[f1]; 19156 pd->fmark[1] = ppd->fmark[f2]; 19157 // Set the map from ab to cd. 19158 for (i = 0; i < 4; i++) { 19159 for (j = 0; j < 4; j++) { 19160 pd->transmat[0][i][j] = ppd->transmat[f1][i][j]; 19161 } 19162 } 19163 // Set the map from cd to ab. 19164 for (i = 0; i < 4; i++) { 19165 for (j = 0; j < 4; j++) { 19166 pd->transmat[1][i][j] = ppd->transmat[f2][i][j]; 19167 } 19168 } 19169 } 19170 } 19171 // Go to the next subface in the ring of ab. 19172 spivotself(spinsh); 19173 } while (spinsh.sh != startsh.sh); 19174 segloop.sh = shellfacetraverse(subsegs); 19175 } 19176 19177 if (b->refine) { 19178 delete [] segsperverlist; 19179 delete [] idx2seglist; 19180 } 19181 19182 // Create the indirect segment pbcgroups. 19183 // Bug-fixed (08 Sept. 2006). The total size of 'segpbcgrouptable' may get 19184 // increased. Do not use pointers for 'pd1' and 'pd2'. The addresses may 19185 // be invaild after realloc(). 19186 for (i = 0; i < segpbcgrouptable->len(); i++) { 19187 pd1 = * (pbcdata *)(* segpbcgrouptable)[i]; 19188 for (f1 = 0; f1 < 2; f1++) { 19189 // Search for a group (except i) contains pd1.segid[f1]. 19190 for (j = 0; j < segpbcgrouptable->len(); j++) { 19191 if (j == i) continue; 19192 pd2 = * (pbcdata *)(* segpbcgrouptable)[j]; 19193 f2 = -1; 19194 if (pd1.segid[f1] == pd2.segid[0]) { 19195 f2 = 0; 19196 } else if (pd1.segid[f1] == pd2.segid[1]) { 19197 f2 = 1; 19198 } 19199 if (f2 != -1) { 19200 #ifdef SELF_CHECK 19201 assert(pd1.segid[f1] == pd2.segid[f2]); 19202 #endif 19203 segid1 = pd1.segid[1 - f1]; 19204 segid2 = pd2.segid[1 - f2]; 19205 // Search for the existence of segment pbcgroup (segid1, segid2). 19206 inflag = false; 19207 for (k = 0; k < segpbcgrouptable->len() && !inflag; k++) { 19208 pd = (pbcdata *)(* segpbcgrouptable)[k]; 19209 if (pd->segid[0] == segid1) { 19210 if (pd->segid[1] == segid2) inflag = true; 19211 } else if (pd->segid[0] == segid2) { 19212 if (pd->segid[1] == segid1) inflag = true; 19213 } 19214 } 19215 if (!inflag) { 19216 pd = (pbcdata *) segpbcgrouptable->append(NULL); 19217 pd->segid[0] = pd1.segid[1 - f1]; 19218 pd->segid[1] = pd2.segid[1 - f2]; 19219 pd->ss[0] = pd1.ss[1 - f1]; 19220 pd->ss[1] = pd2.ss[1 - f2]; 19221 // Invalid the fmark[0] == fmark[1]. 19222 pd->fmark[0] = pd->fmark[1] = 0; 19223 // Translate matrix pd->transmat[0] = m2 * m1, where m1 = 19224 // pd1.transmat[1 - f1], m2 = pd2.transmat[f2]. 19225 for (k = 0; k < 4; k++) { 19226 for (l = 0; l < 4; l++) { 19227 pd->transmat[0][k][l] = pd2.transmat[f2][k][l]; 19228 } 19229 } 19230 m4xm4(pd->transmat[0], pd1.transmat[1 - f1]); 19231 // Translate matrix pd->transmat[1] = m4 * m3, where m3 = 19232 // pd2.transmat[1 - f2], m4 = pd1.transmat[f1]. 19233 for (k = 0; k < 4; k++) { 19234 for (l = 0; l < 4; l++) { 19235 pd->transmat[1][k][l] = pd1.transmat[f1][k][l]; 19236 } 19237 } 19238 m4xm4(pd->transmat[1], pd2.transmat[1 - f2]); 19239 } 19240 } 19241 } 19242 } 19243 } 19244 19245 // Form a map from segment index to pbcgroup list of this segment. 19246 idx2segpglist = new int[subsegs->items + 1]; 19247 for (i = 0; i < subsegs->items + 1; i++) idx2segpglist[i] = 0; 19248 // Loop through 'segpbcgrouptable', counter the number of pbcgroups of 19249 // each segment. 19250 for (i = 0; i < segpbcgrouptable->len(); i++) { 19251 pd = (pbcdata *)(* segpbcgrouptable)[i]; 19252 for (j = 0; j < 2; j++) { 19253 k = pd->segid[j] - 1; 19254 idx2segpglist[k]++; 19255 } 19256 } 19257 // Calculate the total length of array 'segpglist'. 19258 j = idx2segpglist[0]; 19259 idx2segpglist[0] = 0; // Array starts from 0 element. 19260 for (i = 0; i < subsegs->items; i++) { 19261 k = idx2segpglist[i + 1]; 19262 idx2segpglist[i + 1] = idx2segpglist[i] + j; 19263 j = k; 19264 } 19265 // The total length is in the last unit of idx2segpglist. 19266 segpglist = new int[idx2segpglist[i]]; 19267 // Loop the set of pbcgroups again, set the data into segpglist. 19268 for (i = 0; i < segpbcgrouptable->len(); i++) { 19269 pd = (pbcdata *)(* segpbcgrouptable)[i]; 19270 for (j = 0; j < 2; j++) { 19271 k = pd->segid[j] - 1; 19272 segpglist[idx2segpglist[k]] = i; 19273 idx2segpglist[k]++; 19274 } 19275 } 19276 // Contents in 'idx2segpglist' are shifted, now shift them back. 19277 for (i = subsegs->items - 1; i >= 0; i--) { 19278 idx2segpglist[i + 1] = idx2segpglist[i]; 19279 } 19280 idx2segpglist[0] = 0; 19281 } 19282 19284 // // 19285 // getsegpbcsympoint() Compute the symmetric point for a segment point. // 19286 // // 19287 // 'newpoint' lies on 'splitseg'. This routine calculates a 'sympoint' which // 19288 // locates on 'symsplitseg' and symmtric to 'newpoint'. Return the location // 19289 // of sympoint wrt. symsplitseg. // 19290 // // 19292 19293 enum tetgenmesh::locateresult tetgenmesh:: 19294 getsegpbcsympoint(point newpoint, face* splitseg, point sympoint, 19295 face* symsplitseg, int groupid) 19296 { 19297 pbcdata *pd; 19298 enum locateresult symloc; 19299 int segid, f1, f2, i; 19300 19301 pd = (pbcdata *)(* segpbcgrouptable)[groupid]; 19302 segid = shellmark(*splitseg); 19303 if (pd->segid[0] == segid) { 19304 f1 = 0; 19305 } else { 19306 #ifdef SELF_CHECK 19307 assert(pd->segid[1] == segid); 19308 #endif 19309 f1 = 1; 19310 } 19311 f2 = 1 - f1; 19312 19313 // Transform newpoint from f1 -> f2. 19314 for (i = 0; i < 3; i++) { 19315 sympoint[i] = pd->transmat[f1][i][0] * newpoint[0] 19316 + pd->transmat[f1][i][1] * newpoint[1] 19317 + pd->transmat[f1][i][2] * newpoint[2] 19318 + pd->transmat[f1][i][3] * 1.0; 19319 } 19320 // Locate sympoint in f2. 19321 *symsplitseg = pd->ss[f2]; 19322 #ifdef SELF_CHECK 19323 assert(symsplitseg->sh != dummysh); 19324 #endif 19325 // Locate sympoint in facet. Stop at subsegment. 19326 symloc = locateseg(sympoint, symsplitseg); 19327 symloc = adjustlocateseg(sympoint, symsplitseg, symloc, b->epsilon * 1e+2); 19328 return symloc; 19329 } 19330 19331 // 19332 // End of periodic boundary condition routines 19333 // 19334 19335 // 19336 // Begin of vertex perturbation routines 19337 // 19338 19340 // // 19341 // randgenerator() Generate a random REAL number between (0, |range|). // 19342 // // 19344 19345 REAL tetgenmesh::randgenerator(REAL range) 19346 { 19347 REAL worknumber, result; 19348 int expo; 19349 19350 if (range == 0.0) return 0.0; 19351 19352 expo = 0; 19353 worknumber = fabs(range); 19354 // Normalize worknumber (i.e., 1.xxxExx) 19355 if (worknumber > 10.0) { 19356 while (worknumber > 10.0) { 19357 worknumber /= 10.0; 19358 expo++; 19359 } 19360 } else if (worknumber < 1.0) { 19361 while (worknumber < 1.0) { 19362 worknumber *= 10.0; 19363 expo--; 19364 } 19365 } 19366 #ifdef SELF_CHECK 19367 assert(worknumber >= 1.0 && worknumber <= 10.0); 19368 #endif 19369 19370 // Enlarge worknumber 1000 times. 19371 worknumber *= 1e+3; 19372 expo -= 3; 19373 // Generate a randome number between (0, worknumber). 19374 result = (double) randomnation((int) worknumber); 19375 19376 // Scale result back into the original size. 19377 if (expo > 0) { 19378 while (expo != 0) { 19379 result *= 10.0; 19380 expo--; 19381 } 19382 } else if (expo < 0) { 19383 while (expo != 0) { 19384 result /= 10.0; 19385 expo++; 19386 } 19387 } 19388 #ifdef SELF_CHECK 19389 assert((result >= 0.0) && (result <= fabs(range))); 19390 #endif 19391 19392 return result; 19393 } 19394 19396 // // 19397 // checksub4cocir() Test a subface to find co-circular pair of subfaces. // 19398 // // 19399 // 'eps' is a relative tolerance for testing approximately cospherical case. // 19400 // Set it to zero if only exact test is desired. // 19401 // // 19402 // An edge(not a segment) of 'testsub' is locally degenerate if the opposite // 19403 // vertex of the adjacent subface is cocircular with the vertices of testsub.// 19404 // If 'once' is TRUE, operate on the edge only if the pointer 'testsub->sh' // 19405 // is smaller than its neighbor (for each edge is considered only once). // 19406 // // 19407 // Return TRUE if find an edge of testsub is locally degenerate. // 19408 // // 19410 19411 bool tetgenmesh::checksub4cocir(face* testsub, REAL eps, bool once, 19412 bool enqflag) 19413 { 19414 badface *cocirsub; 19415 face subloop, neighsub; 19416 face checkseg; 19417 point pa, pb, pc, pd; 19418 REAL sign; 19419 int i; 19420 19421 subloop = *testsub; 19422 subloop.shver = 0; // Keep the CCW orientation. 19423 // Get the abovepoint of the facet. 19424 abovepoint = facetabovepointarray[shellmark(subloop)]; 19425 // Do we need to calculate the abovepoint? 19426 if (abovepoint == (point) NULL) { 19427 getfacetabovepoint(&subloop); 19428 } 19429 // Check the three edges of subloop. 19430 for (i = 0; i < 3; i++) { 19431 sspivot(subloop, checkseg); 19432 if (checkseg.sh == dummysh) { 19433 // It is not a segment, get the adjacent subface. 19434 spivot(subloop, neighsub); 19435 // assert(neighsub.sh != dummysh); 19436 if (!once || (once && (neighsub.sh > subloop.sh))) { 19437 pa = sorg(subloop); 19438 pb = sdest(subloop); 19439 pc = sapex(subloop); 19440 pd = sapex(neighsub); 19441 sign = insphere(pa, pb, pc, abovepoint, pd); 19442 if ((sign != 0.0) && (eps > 0.0)) { 19443 if (iscospheric(pa, pb, pc, abovepoint, pd, sign, eps)) sign = 0.0; 19444 } 19445 if (sign == 0.0) { 19446 // It's locally degenerate! 19447 if (enqflag && badsubfaces != (memorypool *) NULL) { 19448 // Save it. 19449 cocirsub = (badface *) badsubfaces->alloc(); 19450 cocirsub->ss = subloop; 19451 cocirsub->forg = pa; 19452 cocirsub->fdest = pb; 19453 cocirsub->fapex = pc; 19454 cocirsub->foppo = pd; 19455 setshell2badface(cocirsub->ss, cocirsub); 19456 } 19457 if (b->verbose > 1) { 19458 printf(" Found set (%d, %d, %d, %d).\n", pointmark(pa), 19459 pointmark(pb), pointmark(pc), pointmark(pd)); 19460 } 19461 return true; 19462 } 19463 } 19464 } 19465 senextself(subloop); 19466 } 19467 19468 return false; 19469 } 19470 19472 // // 19473 // tallcocirsubs() Find all co-circular subfaces and save them in list. // 19474 // // 19476 19477 void tetgenmesh::tallcocirsubs(REAL eps, bool enqflag) 19478 { 19479 face subloop; 19480 19481 // Loop over all subfaces. 19482 subfaces->traversalinit(); 19483 subloop.sh = shellfacetraverse(subfaces); 19484 while (subloop.sh != (shellface *) NULL) { 19485 checksub4cocir(&subloop, eps, true, enqflag); 19486 subloop.sh = shellfacetraverse(subfaces); 19487 } 19488 } 19489 19491 // // 19492 // tallencsegsfsubs() Check for encroached segs from a list of subfaces. // 19493 // // 19495 19496 bool tetgenmesh::tallencsegsfsubs(point testpt, list* cavsublist) 19497 { 19498 face startsub, checkseg; 19499 long oldencnum; 19500 int i, j; 19501 19502 // Remember the current number of encroached segments. 19503 oldencnum = badsubsegs->items; 19504 19505 // Check segments in the list of subfaces. 19506 for (i = 0; i < cavsublist->len(); i++) { 19507 startsub = * (face *)(* cavsublist)[i]; 19508 // Test all three edges of startsub. 19509 for (j = 0; j < 3; j++) { 19510 sspivot(startsub, checkseg); 19511 if (checkseg.sh != dummysh) { 19512 if (!shell2badface(checkseg)) { 19513 checkseg4encroach(&checkseg, testpt, NULL, true); 19514 } 19515 } 19516 senextself(startsub); 19517 } 19518 } 19519 19520 return (badsubsegs->items > oldencnum); 19521 } 19522 19524 // // 19525 // collectflipedges() Collect edges of split subfaces for flip checking. // 19526 // // 19527 // 'inspoint' is a newly inserted segment point (inserted by insertsite()). // 19528 // 'splitseg' is one of the two split subsegments. Some subfaces may be non- // 19529 // Delaunay since they're still not bonded to CDT. This routine collect all // 19530 // such possible subfaces in 'flipqueue'. // 19531 // // 19533 19534 void tetgenmesh:: 19535 collectflipedges(point inspoint, face* splitseg, queue* flipqueue) 19536 { 19537 face startsh, spinsh, checksh; 19538 face nextseg; 19539 point pa, pb; 19540 19541 // Let the dest of splitseg be inspoint. 19542 splitseg->shver = 0; 19543 if (sdest(*splitseg) != inspoint) { 19544 sesymself(*splitseg); 19545 } 19546 #ifdef SELF_CHECK 19547 assert(sdest(*splitseg) == inspoint); 19548 #endif 19549 pa = sorg(*splitseg); 19550 spivot(*splitseg, startsh); 19551 spinsh = startsh; 19552 do { 19553 findedge(&spinsh, pa, inspoint); 19554 senext2(spinsh, checksh); 19555 enqueueflipedge(checksh, flipqueue); 19556 spivotself(spinsh); 19557 } while (spinsh.sh != startsh.sh); 19558 19559 // Get the next subsegment. 19560 senext(*splitseg, nextseg); 19561 spivotself(nextseg); 19562 #ifdef SELF_CHECK 19563 assert(nextseg.sh != (shellface *) NULL); 19564 #endif 19565 19566 // Let the org of nextseg be inspoint. 19567 nextseg.shver = 0; 19568 if (sorg(nextseg) != inspoint) { 19569 sesymself(nextseg); 19570 } 19571 #ifdef SELF_CHECK 19572 assert(sorg(nextseg) == inspoint); 19573 #endif 19574 pb = sdest(nextseg); 19575 spivot(nextseg, startsh); 19576 spinsh = startsh; 19577 do { 19578 findedge(&spinsh, inspoint, pb); 19579 senext(spinsh, checksh); 19580 enqueueflipedge(checksh, flipqueue); 19581 spivotself(spinsh); 19582 } while (spinsh.sh != startsh.sh); 19583 } 19584 19586 // // 19587 // perturbrepairencsegs() Repair all encroached segments. // 19588 // // 19589 // All encroached segments are stored in 'badsubsegs'. Each segment will be // 19590 // split by adding a perturbed point near its circumcenter. // 19591 // // 19593 19594 void tetgenmesh::perturbrepairencsegs(queue* flipqueue) 19595 { 19596 badface *encloop; 19597 tetrahedron encodedtet; 19598 triface splittet; 19599 face splitsub, symsplitsub; 19600 face splitseg, symsplitseg; 19601 point newpoint, sympoint; 19602 point pa, pb, pc; 19603 enum insertsiteresult success; 19604 enum locateresult loc, symloc; 19605 REAL cent[3], d1, ps, rs; 19606 int i, j; 19607 19608 // Note that steinerleft == -1 if an unlimited number of Steiner points 19609 // is allowed. Loop until 'badsubsegs' is empty. 19610 badsubsegs->traversalinit(); 19611 encloop = badfacetraverse(badsubsegs); 19612 while ((encloop != (badface *) NULL) && (steinerleft != 0)) { 19613 splitseg = encloop->ss; 19614 #ifdef SELF_CHECK 19615 assert(shell2badface(splitseg) == encloop); 19616 #endif 19617 setshell2badface(splitseg, NULL); 19618 pa = sorg(splitseg); 19619 pb = sdest(splitseg); 19620 if ((pa == encloop->forg) && (pb == encloop->fdest)) { 19621 if (b->verbose > 1) { 19622 printf(" Get seg (%d, %d).\n", pointmark(pa), pointmark(pb)); 19623 } 19624 // Create the newpoint. 19625 makepoint(&newpoint); 19626 // Get the circumcenter and radius of ab. 19627 for (i = 0; i < 3; i++) cent[i] = 0.5 * (pa[i] + pb[i]); 19628 d1 = 0.5 * distance(pa, pb); 19629 // Add a random perturbation to newpoint along the vector ab. 19630 ps = randgenerator(d1 * 1.0e-3); 19631 rs = ps / d1; 19632 // Set newpoint (be at the perturbed circumcenter of ab). 19633 for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]); 19634 setpointtype(newpoint, FREESEGVERTEX); 19635 // Set splitseg into the newpoint. 19636 setpoint2sh(newpoint, sencode(splitseg)); 19637 19638 // Is there periodic boundary condition? 19639 if (checkpbcs) { 19640 // Insert points on other segments of incident pbcgroups. 19641 i = shellmark(splitseg) - 1; 19642 for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) { 19643 makepoint(&sympoint); 19644 symloc = getsegpbcsympoint(newpoint, &splitseg, sympoint, 19645 &symsplitseg, segpglist[j]); 19646 #ifdef SELF_CHECK 19647 assert(symloc != OUTSIDE); 19648 #endif 19649 // Note: the symsplitseg and splitseg may be identical, in case 19650 // when the the splitseg is the axis of the rotational sym. 19651 if ((symloc == ONEDGE) && (symsplitseg.sh != splitseg.sh)) { 19652 setpointtype(sympoint, FREESEGVERTEX); 19653 setpoint2sh(sympoint, sencode(symsplitseg)); 19654 // Insert sympoint into DT. 19655 pc = sorg(symsplitseg); 19656 splittet.tet = dummytet; 19657 // Find a good start point to search. 19658 encodedtet = point2tet(pc); 19659 if (encodedtet != (tetrahedron) NULL) { 19660 decode(encodedtet, splittet); 19661 if (isdead(&splittet)) { 19662 splittet.tet = dummytet; 19663 } 19664 } 19665 // Locate sympoint in DT. Do exact location. 19666 success = insertsite(sympoint, &splittet, false, flipqueue); 19667 #ifdef SELF_CHECK 19668 assert(success != DUPLICATEPOINT); 19669 #endif 19670 if (success == OUTSIDEPOINT) { 19671 inserthullsite(sympoint, &splittet, flipqueue); 19672 } 19673 if (steinerleft > 0) steinerleft--; 19674 // Let sympoint remember splittet. 19675 setpoint2tet(sympoint, encode(splittet)); 19676 // Do flip in DT. 19677 flip(flipqueue, NULL); 19678 // Insert sympoint into F. 19679 symloc = locateseg(sympoint, &symsplitseg); 19680 if (symloc == ONEDGE) { 19681 symsplitseg.shver = 0; 19682 spivot(symsplitseg, symsplitsub); 19683 // sympoint should on the edge of symsplitsub. 19684 splitsubedge(sympoint, &symsplitsub, flipqueue); 19685 } else { 19686 // insertsite() has done the whole job. 19687 #ifdef SELF_CHECK 19688 assert(symloc == ONVERTEX); 19689 assert(checksubfaces); 19690 #endif 19691 // Some edges may need to be flipped. 19692 collectflipedges(sympoint, &symsplitseg, flipqueue); 19693 } 19694 // Do flip in facet. 19695 flipsub(flipqueue); 19696 } else { // if (symloc == ONVERTEX) { 19697 // The symmtric point already exists. It is possible when two 19698 // pbc group are idebtical. Omit sympoint. 19699 pointdealloc(sympoint); 19700 } 19701 } 19702 } 19703 19704 // Insert newpoint into DT. 19705 splittet.tet = dummytet; 19706 // Find a good start point to search. 19707 encodedtet = point2tet(pa); 19708 if (encodedtet != (tetrahedron) NULL) { 19709 decode(encodedtet, splittet); 19710 if (isdead(&splittet)) { 19711 splittet.tet = dummytet; 19712 } 19713 } 19714 if (splittet.tet == dummytet) { // Try pb. 19715 encodedtet = point2tet(pb); 19716 if (encodedtet != (tetrahedron) NULL) { 19717 decode(encodedtet, splittet); 19718 if (isdead(&splittet)) { 19719 splittet.tet = dummytet; 19720 } 19721 } 19722 } 19723 // Locate the newpoint in DT. Do exact location. 19724 success = insertsite(newpoint, &splittet, false, flipqueue); 19725 #ifdef SELF_CHECK 19726 assert(success != DUPLICATEPOINT); 19727 #endif 19728 if (success == OUTSIDEPOINT) { 19729 // A convex hull edge is mssing, and the inserting point lies 19730 // (slightly) outside the convex hull due to the significant 19731 // digits lost in the calculation. Enlarge the convex hull. 19732 inserthullsite(newpoint, &splittet, flipqueue); 19733 } 19734 if (steinerleft > 0) steinerleft--; 19735 // Let newpoint remember splittet. 19736 setpoint2tet(newpoint, encode(splittet)); 19737 // Do flip in DT. 19738 flip(flipqueue, NULL); 19739 // Insert newpoint into F. 19740 loc = locateseg(newpoint, &splitseg); 19741 if (loc == ONEDGE) { 19742 splitseg.shver = 0; 19743 spivot(splitseg, splitsub); 19744 // newpoint should on the edge of splitsub. 19745 splitsubedge(newpoint, &splitsub, flipqueue); 19746 } else { 19747 // insertsite() has done the whole job. 19748 #ifdef SELF_CHECK 19749 assert(loc == ONVERTEX); 19750 assert(checksubfaces); 19751 #endif 19752 // Some edges may need to be flipped. 19753 collectflipedges(newpoint, &splitseg, flipqueue); 19754 } 19755 // Do flip in facet. 19756 flipsub(flipqueue); 19757 } 19758 // Remove this entry from list. 19759 badfacedealloc(badsubsegs, encloop); 19760 // Get the next encroached segments. 19761 encloop = badfacetraverse(badsubsegs); 19762 } 19763 } 19764 19766 // // 19767 // perturbrepairencsubs() Repair all encroached subfaces. // 19768 // // 19769 // All encroached subfaces are stored in 'badsubfaces'. Each subface will be // 19770 // split by adding a perturbed point near its circumcenter. However, if the // 19771 // point encroaches some segments, it will not be inserted. Instead, the // 19772 // encroached segments are split. // 19773 // // 19775 19776 void tetgenmesh::perturbrepairencsubs(list* cavsublist, queue* flipqueue) 19777 { 19778 badface *encloop, *encsubseg; 19779 tetrahedron encodedtet; 19780 triface splittet; 19781 face splitsub, symsplitsub; 19782 face checkseg, symsplitseg; 19783 point newpoint, sympoint; 19784 point pa, pb, pc, pd; 19785 enum insertsiteresult success; 19786 enum locateresult loc, symloc; 19787 REAL cent[3], d1, ps, rs; 19788 bool reject; 19789 int i; 19790 19791 // Note that steinerleft == -1 if an unlimited number of Steiner points 19792 // is allowed. Loop until the list 'badsubfaces' is empty. 19793 while ((badsubfaces->items > 0) && (steinerleft != 0)) { 19794 badsubfaces->traversalinit(); 19795 encloop = badfacetraverse(badsubfaces); 19796 while ((encloop != (badface *) NULL) && (steinerleft != 0)) { 19797 splitsub = encloop->ss; 19798 #ifdef SELF_CHECK 19799 assert(shell2badface(splitsub) == encloop); 19800 #endif 19801 setshell2badface(splitsub, NULL); 19802 pa = sorg(splitsub); 19803 pb = sdest(splitsub); 19804 pc = sapex(splitsub); 19805 // The subface may be not the same one when it was determined to be 19806 // encroached. If its adjacent encroached subface was split, the 19807 // consequent flips may change it into another subface. 19808 if ((pa == encloop->forg) && (pb == encloop->fdest) && 19809 (pc == encloop->fapex)) { 19810 if (b->verbose > 1) { 19811 printf(" Get subface (%d, %d, %d).\n", pointmark(pa), 19812 pointmark(pb), pointmark(pc)); 19813 } 19814 // Create the newpoint. 19815 makepoint(&newpoint); 19816 // Get the circumcenter of abc. 19817 circumsphere(pa, pb, pc, NULL, cent, &d1); 19818 #ifdef SELF_CHECK 19819 assert(d1 > 0.0); 19820 #endif 19821 // Add a random perturbation to newpoint along the vector a->cent. 19822 // This way, the perturbed point still lies in the plane of abc. 19823 ps = randgenerator(d1 * 1.0e-3); 19824 rs = ps / d1; 19825 // Set newpoint (be at the perturbed circumcenter of abc). 19826 for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]); 19827 // Get the abovepoint of the facet. 19828 abovepoint = facetabovepointarray[shellmark(splitsub)]; 19829 // Do we need to calculate the abovepoint? 19830 if (abovepoint == (point) NULL) { 19831 getfacetabovepoint(&splitsub); 19832 } 19833 loc = locatesub(newpoint, &splitsub, 1, 0.0); 19834 #ifdef SELF_CHECK 19835 assert(loc != ONVERTEX); 19836 #endif 19837 if (loc != OUTSIDE) { 19838 // Add 'splitsub' into 'cavsublist'. 19839 cavsublist->append(&splitsub); 19840 // Collect all subfaces that encroached by newpoint. 19841 collectcavsubs(newpoint, cavsublist); 19842 // Find if there are encroached segments. 19843 reject = tallencsegsfsubs(newpoint, cavsublist); 19844 // Clear cavsublist for the next use. 19845 cavsublist->clear(); 19846 } else { 19847 // newpoint lies outside. splitsub contains the boundary segment. 19848 sspivot(splitsub, checkseg); 19849 #ifdef SELF_CHECK 19850 assert(checkseg.sh != dummysh); 19851 #endif 19852 // Add this segment into list for splitting. 19853 if (b->verbose > 2) { 19854 printf(" Queuing boundary segment (%d, %d).\n", 19855 pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); 19856 } 19857 encsubseg = (badface *) badsubsegs->alloc(); 19858 encsubseg->ss = checkseg; 19859 encsubseg->forg = sorg(checkseg); 19860 encsubseg->fdest = sdest(checkseg); 19861 encsubseg->foppo = (point) NULL; 19862 setshell2badface(encsubseg->ss, encsubseg); 19863 // Reject newpoint. 19864 reject = true; 19865 } 19866 19867 if (!reject) { 19868 // newpoint is going to be inserted. 19869 19870 // Is there periodic boundary condition? 19871 if (checkpbcs) { 19872 if (shellpbcgroup(splitsub) >= 0) { 19873 // Insert a point on another facet of the pbcgroup. 19874 makepoint(&sympoint); 19875 // Note: 'abovepoint' will be changed. 19876 symloc = getsubpbcsympoint(newpoint, &splitsub, sympoint, 19877 &symsplitsub); 19878 #ifdef SELF_CHECK 19879 assert(symloc != ONVERTEX); 19880 #endif 19881 setpoint2pbcpt(newpoint, sympoint); 19882 setpoint2pbcpt(sympoint, newpoint); 19883 setpointtype(sympoint, FREESUBVERTEX); 19884 // setpoint2sh(sympoint, sencode(symsplitsub)); 19885 // Insert sympoint into DT. 19886 pd = sorg(symsplitsub); 19887 splittet.tet = dummytet; 19888 // Find a good start point to search. 19889 encodedtet = point2tet(pd); 19890 if (encodedtet != (tetrahedron) NULL) { 19891 decode(encodedtet, splittet); 19892 if (isdead(&splittet)) { 19893 splittet.tet = dummytet; 19894 } 19895 } 19896 // Locate sympoint in DT. Do exact location. 19897 success = insertsite(sympoint, &splittet, false, flipqueue); 19898 #ifdef SELF_CHECK 19899 assert(success != DUPLICATEPOINT); 19900 #endif 19901 if (success == OUTSIDEPOINT) { 19902 inserthullsite(sympoint, &splittet, flipqueue); 19903 } 19904 if (steinerleft > 0) steinerleft--; 19905 // Let sympoint remember splittet. 19906 setpoint2tet(sympoint, encode(splittet)); 19907 // Do flip in DT. 19908 flip(flipqueue, NULL); 19909 // Insert sympoint into F. 19910 // getabovepoint(&symsplitsub); 19911 // symloc = locatesub(sympoint, &symsplitsub, 1, 0.0); 19912 if (symloc == ONFACE) { 19913 splitsubface(sympoint, &symsplitsub, flipqueue); 19914 } else if (symloc == ONEDGE) { 19915 splitsubedge(sympoint, &symsplitsub, flipqueue); 19916 } else { 19917 // 'insertsite()' has done the whole job. 19918 #ifdef SELF_CHECK 19919 assert(symloc == ONVERTEX); 19920 assert(checksubfaces); 19921 #endif 19922 // Split subfaces have been flipped. 19923 flipqueue->clear(); 19924 } 19925 // Do flip in facet. 19926 flipsub(flipqueue); 19927 } 19928 } 19929 19930 // Insert newpoint into DT. 19931 splittet.tet = dummytet; 19932 // Find a good start point to search. 19933 encodedtet = point2tet(pa); 19934 if (encodedtet != (tetrahedron) NULL) { 19935 decode(encodedtet, splittet); 19936 if (isdead(&splittet)) { 19937 splittet.tet = dummytet; 19938 } 19939 } 19940 if (splittet.tet == dummytet) { // Try pb. 19941 encodedtet = point2tet(pb); 19942 if (encodedtet != (tetrahedron) NULL) { 19943 decode(encodedtet, splittet); 19944 if (isdead(&splittet)) { 19945 splittet.tet = dummytet; 19946 } 19947 } 19948 } 19949 // Locate the newpoint in DT. Do exact location. 19950 success = insertsite(newpoint, &splittet, false, flipqueue); 19951 #ifdef SELF_CHECK 19952 assert(success != DUPLICATEPOINT); 19953 #endif 19954 if (success == OUTSIDEPOINT) { 19955 inserthullsite(newpoint, &splittet, flipqueue); 19956 } 19957 if (steinerleft > 0) steinerleft--; 19958 // Let newpoint remember splittet. 19959 setpoint2tet(newpoint, encode(splittet)); 19960 // Do flip in DT. 19961 flip(flipqueue, NULL); 19962 // Insert newpoint into F. 19963 // if (checkpbcs) { 19964 // 'abovepoint' has been changed. 19965 // getabovepoint(&splitsub); 19966 // loc = locatesub(newpoint, &splitsub, 1, 0.0); 19967 // } 19968 if (loc == ONFACE) { 19969 // Insert the newpoint in facet. 19970 splitsubface(newpoint, &splitsub, flipqueue); 19971 } else if (loc == ONEDGE) { 19972 // Insert the newpoint in facet. 19973 splitsubedge(newpoint, &splitsub, flipqueue); 19974 } else { 19975 // 'insertsite()' has done the whole job. 19976 #ifdef SELF_CHECK 19977 assert(loc == ONVERTEX); 19978 assert(checksubfaces); 19979 #endif 19980 // Split subfaces have been flipped. 19981 flipqueue->clear(); 19982 } 19983 // Set the type of the newpoint. 19984 setpointtype(newpoint, FREESUBVERTEX); 19985 // Set splitsub into the newpoint. 19986 // setpoint2sh(newpoint, sencode(splitsub)); 19987 // Do flip in the facet. 19988 flipsub(flipqueue); 19989 19990 // Remove this entry from list. 19991 badfacedealloc(badsubfaces, encloop); 19992 } else { 19993 // newpoint is rejected. Remove it from points. 19994 pointdealloc(newpoint); 19995 // Repair all encroached segments. 19996 perturbrepairencsegs(flipqueue); 19997 // Do not remove 'encloop'. Later it will be tested again. 19998 setshell2badface(encloop->ss, encloop); 19999 } 20000 } else { 20001 // This subface has been changed. Remove this entry from list. 20002 badfacedealloc(badsubfaces, encloop); 20003 // It may be co-circular with its neighbors. 20004 // checksub4cocir(&splitsub, eps, false, true); 20005 } 20006 // Get the next encroached subfaces. 20007 encloop = badfacetraverse(badsubfaces); 20008 } 20009 } 20010 } 20011 20013 // // 20014 // incrperturbvertices() Remove the local degeneracies in DT. // 20015 // // 20016 // A local degeneracy of a DT D is a set of 5 or more vertices which share a // 20017 // common sphere S and no other vertex of D in S. D is not unique if it has // 20018 // local degeneracies. This routine removes the local degeneracies from D by // 20019 // inserting break points (as described in reference [2]). // 20020 // // 20021 // 'eps' is a user-provided error tolerance. It is used to detect whether or // 20022 // not five points are approximate cospherical (evaluated in iscospheric()). // 20023 // Set it to 0.0 to disable it, i.e., only test pure degenerate point set. // 20024 // // 20026 20027 void tetgenmesh::incrperturbvertices(REAL eps) 20028 { 20029 queue *flipqueue; 20030 list *cavsublist; 20031 long vertcount; 20032 20033 if (!b->quiet) { 20034 printf("Perturbing vertices.\n"); 20035 } 20036 20037 vertcount = points->items; 20038 // Create a map from points to tets for fastening search. 20039 // makepoint2tetmap(); // This has been done in meshsurface(). 20040 20041 // Initialize working queues, lists. 20042 flipqueue = new queue(sizeof(badface)); 20043 cavsublist = new list(sizeof(face), NULL, 256); 20044 // Initialize the pool of encroached subfaces and subsegments. 20045 badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); 20046 badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); 20047 // Find all pairs of co-circular subfaces. 20048 tallcocirsubs(eps, true); 20049 if (b->verbose && badsubfaces->items > 0) { 20050 printf(" Removing degenerate subfaces.\n"); 20051 } 20052 perturbrepairencsubs(cavsublist, flipqueue); 20053 20054 if (b->verbose > 0) { 20055 printf(" %ld break points.\n", points->items - vertcount); 20056 } 20057 20058 delete cavsublist; 20059 delete flipqueue; 20060 delete badsubfaces; 20061 delete badsubsegs; 20062 badsubsegs = (memorypool *) NULL; 20063 badsubfaces = (memorypool *) NULL; 20064 } 20065 20066 // 20067 // End of vertex perturbation routines 20068 // 20069 20070 // 20071 // Begin of segment recovery routines 20072 // 20073 20075 // // 20076 // markacutevertices() Mark acute vertices. // 20077 // // 20078 // A vertex v is called acute if there are two segments sharing at v forming // 20079 // an acute angle (i.e. smaller than 90 degree). // 20080 // // 20081 // This routine finds all acute vertices in the PLC and marks them as point- // 20082 // type ACUTEVERTEX. The other vertices of segments which are non-acute will // 20083 // be marked as NACUTEVERTEX. Vertices which are not endpoints of segments // 20084 // (such as DUPLICATEDVERTEX, UNUSEDVERTEX, etc) are not infected. // 20085 // // 20086 // NOTE: This routine should be called before Steiner points are introduced. // 20087 // That is, no point has type like FREESEGVERTEX, etc. // 20088 // // 20090 20091 void tetgenmesh::markacutevertices(REAL acuteangle) 20092 { 20093 shellface **segsperverlist; 20094 face segloop, nextseg; 20095 point pointloop, edest, eapex; 20096 REAL cosbound, anglearc; 20097 REAL v1[3], v2[3], L, D; 20098 bool isacute; 20099 int *idx2seglist; 20100 int acutecount; 20101 int idx, i, j, k; 20102 20103 if (b->verbose > 0) { 20104 printf(" Marking acute vertices.\n"); 20105 } 20106 20107 anglearc = acuteangle * PI / 180.0; 20108 cosbound = cos(anglearc); 20109 acutecount = 0; 20110 // Constructing a map from vertex to segments. 20111 makesegmentmap(idx2seglist, segsperverlist); 20112 20113 // Loop over the set of vertices. 20114 points->traversalinit(); 20115 pointloop = pointtraverse(); 20116 while (pointloop != (point) NULL) { 20117 idx = pointmark(pointloop) - in->firstnumber; 20118 // Only do test if p is an endpoint of some segments. 20119 if (idx2seglist[idx + 1] > idx2seglist[idx]) { 20120 // Init p to be non-acute. 20121 setpointtype(pointloop, NACUTEVERTEX); 20122 isacute = false; 20123 // Loop through all segments sharing at p. 20124 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) { 20125 segloop.sh = segsperverlist[i]; 20126 // segloop.shver = 0; 20127 if (sorg(segloop) != pointloop) sesymself(segloop); 20128 edest = sdest(segloop); 20129 for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) { 20130 nextseg.sh = segsperverlist[j]; 20131 // nextseg.shver = 0; 20132 if (sorg(nextseg) != pointloop) sesymself(nextseg); 20133 eapex = sdest(nextseg); 20134 // Check the angle formed by segs (p, edest) and (p, eapex). 20135 for (k = 0; k < 3; k++) { 20136 v1[k] = edest[k] - pointloop[k]; 20137 v2[k] = eapex[k] - pointloop[k]; 20138 } 20139 L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); 20140 for (k = 0; k < 3; k++) v1[k] /= L; 20141 L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]); 20142 for (k = 0; k < 3; k++) v2[k] /= L; 20143 D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; 20144 // Is D acute? 20145 isacute = (D >= cosbound); 20146 } 20147 } 20148 if (isacute) { 20149 // Mark p to be acute. 20150 setpointtype(pointloop, ACUTEVERTEX); 20151 acutecount++; 20152 } 20153 } 20154 pointloop = pointtraverse(); 20155 } 20156 20157 delete [] idx2seglist; 20158 delete [] segsperverlist; 20159 20160 if ((b->verbose > 0) && (acutecount > 0)) { 20161 printf(" %d acute vertices.\n", acutecount); 20162 } 20163 } 20164 20166 // // 20167 // finddirection() Find the first tetrahedron on the path from one point // 20168 // to another. // 20169 // // 20170 // Find the tetrahedron that intersects a line segment L (from the origin of // 20171 // 'searchtet' to the point 'tend'), and returns the result in 'searchtet'. // 20172 // The origin of 'searchtet' does not change, even though the tetrahedron // 20173 // returned may differ from the one passed in. This routine is used to find // 20174 // the direction to move in to get from one point to another. // 20175 // // 20176 // The return value notes the location of the line segment L with respect to // 20177 // 'searchtet': // 20178 // - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment // 20179 // from the origin to the destination of 'searchtet'. // 20180 // - Returns LEFTCOLLINEAR indicates L is collinear with the line segment // 20181 // from the origin to the apex of 'searchtet'. // 20182 // - Returns TOPCOLLINEAR indicates L is collinear with the line segment // 20183 // from the origin to the opposite of 'searchtet'. // 20184 // - Returns ACROSSEDGE indicates L intersects with the line segment from // 20185 // the destination to the apex of 'searchtet'. // 20186 // - Returns ACROSSFACE indicates L intersects with the face opposite to // 20187 // the origin of 'searchtet'. // 20188 // - Returns BELOWHULL indicates L crosses outside the mesh domain. This // 20189 // can only happen when the domain is non-convex. // 20190 // // 20191 // NOTE: This routine only works correctly when the mesh is exactly Delaunay.// 20192 // // 20193 // If 'maxtetnumber' > 0, stop the searching process if the number of passed // 20194 // tets is larger than it. Return BELOWHULL. // 20195 // // 20197 20198 enum tetgenmesh::finddirectionresult tetgenmesh:: 20199 finddirection(triface *searchtet, point tend, long maxtetnumber) 20200 { 20201 triface neightet; 20202 point tstart, tdest, tapex, toppo; 20203 REAL ori1, ori2, ori3; 20204 long tetnumber; 20205 20206 tstart = org(*searchtet); 20207 #ifdef SELF_CHECK 20208 assert(tstart != tend); 20209 #endif 20210 adjustedgering(*searchtet, CCW); 20211 if (tstart != org(*searchtet)) { 20212 enextself(*searchtet); // For keeping the same origin. 20213 } 20214 tdest = dest(*searchtet); 20215 if (tdest == tend) { 20216 return RIGHTCOLLINEAR; 20217 } 20218 tapex = apex(*searchtet); 20219 if (tapex == tend) { 20220 return LEFTCOLLINEAR; 20221 } 20222 20223 ori1 = orient3d(tstart, tdest, tapex, tend); 20224 if (ori1 > 0.0) { 20225 // 'tend' is below the face, get the neighbor of this side. 20226 sym(*searchtet, neightet); 20227 if (neightet.tet != dummytet) { 20228 findorg(&neightet, tstart); 20229 adjustedgering(neightet, CCW); 20230 if (org(neightet) != tstart) { 20231 enextself(neightet); // keep the same origin. 20232 } 20233 // Set the changed configuratiuon. 20234 *searchtet = neightet; 20235 ori1 = -1.0; 20236 tdest = dest(*searchtet); 20237 tapex = apex(*searchtet); 20238 } else { 20239 // A hull face. Only possible for a nonconvex mesh. 20240 #ifdef SELF_CHECK 20241 assert(nonconvex); 20242 #endif 20243 return BELOWHULL; 20244 } 20245 } 20246 20247 // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until 20248 // find a tetrahedron contains 'tend' or is crossed by the line segment 20249 // from 'tstart' to 'tend'. 20250 tetnumber = 0l; 20251 while ((maxtetnumber > 0) && (tetnumber <= maxtetnumber)) { 20252 tetnumber++; 20253 toppo = oppo(*searchtet); 20254 if (toppo == tend) { 20255 return TOPCOLLINEAR; 20256 } 20257 ori2 = orient3d(tstart, toppo, tdest, tend); 20258 if (ori2 > 0.0) { 20259 // 'tend' is below the face, get the neighbor at this side. 20260 fnext(*searchtet, neightet); 20261 symself(neightet); 20262 if (neightet.tet != dummytet) { 20263 findorg(&neightet, tstart); 20264 adjustedgering(neightet, CCW); 20265 if (org(neightet) != tstart) { 20266 enextself(neightet); // keep the same origin. 20267 } 20268 // Set the changed configuration. 20269 *searchtet = neightet; 20270 ori1 = -1.0; 20271 tdest = dest(*searchtet); 20272 tapex = apex(*searchtet); 20273 // Continue the search from the changed 'searchtet'. 20274 continue; 20275 } else { 20276 // A hull face. Only possible for a nonconvex mesh. 20277 #ifdef SELF_CHECK 20278 assert(nonconvex); 20279 #endif 20280 return BELOWHULL; 20281 } 20282 } 20283 ori3 = orient3d(tapex, toppo, tstart, tend); 20284 if (ori3 > 0.0) { 20285 // 'tend' is below the face, get the neighbor at this side. 20286 enext2fnext(*searchtet, neightet); 20287 symself(neightet); 20288 if (neightet.tet != dummytet) { 20289 findorg(&neightet, tstart); 20290 adjustedgering(neightet, CCW); 20291 if (org(neightet) != tstart) { 20292 enextself(neightet); // keep the same origin. 20293 } 20294 // Set the changed configuration. 20295 *searchtet = neightet; 20296 ori1 = -1.0; 20297 tdest = dest(*searchtet); 20298 tapex = apex(*searchtet); 20299 // Continue the search from the changed 'searchtet'. 20300 continue; 20301 } else { 20302 // A hull face. Only possible for a nonconvex mesh. 20303 #ifdef SELF_CHECK 20304 assert(nonconvex); 20305 #endif 20306 return BELOWHULL; 20307 } 20308 } 20309 // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0; 20310 if (ori1 < 0.0) { 20311 // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR. 20312 if (ori2 < 0.0) { 20313 if (ori3 < 0.0) { 20314 return ACROSSFACE; 20315 } else { // ori3 == 0.0; 20316 // Cross edge (apex, oppo) 20317 enext2fnextself(*searchtet); 20318 esymself(*searchtet); // org(*searchtet) == tstart; 20319 return ACROSSEDGE; 20320 } 20321 } else { // ori2 == 0.0; 20322 if (ori3 < 0.0) { 20323 // Cross edge (dest, oppo) 20324 fnextself(*searchtet); 20325 esymself(*searchtet); 20326 enextself(*searchtet); // org(*searchtet) == tstart; 20327 return ACROSSEDGE; 20328 } else { // ori3 == 0.0; 20329 // Collinear with edge (org, oppo) 20330 return TOPCOLLINEAR; 20331 } 20332 } 20333 } else { // ori1 == 0.0; 20334 // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE. 20335 if (ori2 < 0.0) { 20336 if (ori3 < 0.0) { 20337 // Cross edge (tdest, tapex) 20338 return ACROSSEDGE; 20339 } else { // ori3 == 0.0 20340 // Collinear with edge (torg, tapex) 20341 return LEFTCOLLINEAR; 20342 } 20343 } else { // ori2 == 0.0; 20344 #ifdef SELF_CHECK 20345 assert(ori3 != 0.0); 20346 #endif 20347 // Collinear with edge (torg, tdest) 20348 return RIGHTCOLLINEAR; 20349 } 20350 } 20351 } 20352 // Loop breakout. It may happen when the mesh is non-Delaunay. 20353 return BELOWHULL; 20354 } 20355 20357 // // 20358 // getsearchtet() Find a tetrahedron whose origin is either 'p1' or 'p2'. // 20359 // // 20360 // On return, the origin of 'searchtet' is either 'p1' or 'p2', and 'tend' // 20361 // returns the other point. 'searchtet' serves as the starting tetrahedron // 20362 // for searching of the line segment from 'p1' to 'p2' or vice versa. // 20363 // // 20365 20366 void tetgenmesh::getsearchtet(point p1, point p2, triface* searchtet, 20367 point* tend) 20368 { 20369 tetrahedron encodedtet1, encodedtet2; 20370 20371 // Is there a valid handle provided by the user? 20372 if ((searchtet->tet != (tetrahedron *) NULL) && !isdead(searchtet)) { 20373 // Find which endpoint the handle holds. 20374 if (findorg(searchtet, p1)) { 20375 *tend = p2; 20376 return; 20377 } else { 20378 if (findorg(searchtet, p2)) { 20379 *tend = p1; 20380 return; 20381 } 20382 } 20383 } 20384 // If not, search the tet handle stored in 'p1' or 'p2'. 20385 *tend = (point) NULL; 20386 encodedtet1 = point2tet(p1); 20387 encodedtet2 = point2tet(p2); 20388 if (encodedtet1 != (tetrahedron) NULL) { 20389 decode(encodedtet1, *searchtet); 20390 // Be careful, here 'searchtet' may be dead. 20391 if (findorg(searchtet, p1)) { 20392 *tend = p2; 20393 } 20394 } else if (encodedtet2 != (tetrahedron) NULL) { 20395 decode(encodedtet2, *searchtet); 20396 // Be careful, here 'searchtet' may be dead. 20397 if (findorg(searchtet, p2)) { 20398 *tend = p1; 20399 } 20400 } 20401 // If still not, perform a full point location. The starting tet is 20402 // chosen as follows: Use the handle stored in 'p1' or 'p2' if it is 20403 // alive; otherwise, start from a tet on the convex hull. 20404 if (*tend == (point) NULL) { 20405 if (encodedtet1 != (tetrahedron) NULL) { 20406 decode(encodedtet1, *searchtet); 20407 // Be careful, here 'searchtet' may be dead. 20408 } 20409 if (isdead(searchtet)) { 20410 if (encodedtet2 != (tetrahedron) NULL) { 20411 decode(encodedtet2, *searchtet); 20412 // Be careful, here 'searchtet' may be dead. 20413 } 20414 if (isdead(searchtet)) { 20415 searchtet->tet = dummytet; 20416 searchtet->loc = 0; 20417 symself(*searchtet); 20418 } 20419 #ifdef SELF_CHECK 20420 assert(!isdead(searchtet)); 20421 #endif 20422 } 20423 if (locate(p1, searchtet) != ONVERTEX) { 20424 printf("Internal error in getsearchtet(): Failed to locate point\n"); 20425 internalerror(); 20426 } 20427 // Remember this handle in 'p1' to enhance the search speed. 20428 setpoint2tet(p1, encode(*searchtet)); 20429 *tend = p2; 20430 } 20431 } 20432 20434 // // 20435 // isedgeencroached() Check whether or not a subsegment is encroached. // 20436 // // 20437 // A segment with endpoints 'p1' and 'p2' is encroached by the point 'testpt'// 20438 // if it lies in the diametral sphere of this segment. The degenerate case // 20439 // that 'testpt' lies on the sphere is treated as encroached if 'degflag' is // 20440 // set to be TRUE. // 20441 // // 20443 20444 bool tetgenmesh::isedgeencroached(point p1, point p2, point testpt, 20445 bool degflag) 20446 { 20447 REAL dotproduct; 20448 20449 // Check if the segment is facing an angle larger than 90 degree? 20450 dotproduct = (p1[0] - testpt[0]) * (p2[0] - testpt[0]) 20451 + (p1[1] - testpt[1]) * (p2[1] - testpt[1]) 20452 + (p1[2] - testpt[2]) * (p2[2] - testpt[2]); 20453 if (dotproduct < 0) { 20454 return true; 20455 } else if (dotproduct == 0 && degflag) { 20456 return true; 20457 } else { 20458 return false; 20459 } 20460 } 20461 20463 // // 20464 // scoutrefpoint() Search the reference point of a missing segment. // 20465 // // 20466 // A segment S is missing in current Delaunay tetrahedralization DT and will // 20467 // be split by inserting a point V in it. The two end points of S are the // 20468 // origin of 'searchtet' and 'tend'. And we know that S is crossing the face // 20469 // of 'searchtet' opposite to its origin (may be intersecting with the edge // 20470 // from the destination to the apex of the 'searchtet'). The search of P is // 20471 // completed by walking through all faces of DT across by S. // 20472 // // 20473 // Warning: This routine is correct when the tetrahedralization is Delaunay // 20474 // and convex. Otherwise, the search loop may not terminate. // 20475 // // 20477 20478 tetgenmesh::point tetgenmesh::scoutrefpoint(triface* searchtet, point tend) 20479 { 20480 triface checkface; 20481 point tstart, testpt, refpoint; 20482 REAL cent[3], radius, largest; 20483 REAL ahead; 20484 bool ncollinear; 20485 int sides; 20486 20487 if (b->verbose > 2) { 20488 printf(" Scout the reference point of segment (%d, %d).\n", 20489 pointmark(org(*searchtet)), pointmark(tend)); 20490 } 20491 20492 tstart = org(*searchtet); 20493 refpoint = (point) NULL; 20494 largest = 0; // avoid compile warning. 20495 20496 // Check the three vertices of the crossing face. 20497 testpt = apex(*searchtet); 20498 if (isedgeencroached(tstart, tend, testpt, true)) { 20499 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); 20500 #ifdef SELF_CHECK 20501 assert(ncollinear); 20502 #endif 20503 refpoint = testpt; 20504 largest = radius; 20505 } 20506 testpt = dest(*searchtet); 20507 if (isedgeencroached(tstart, tend, testpt, true)) { 20508 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); 20509 #ifdef SELF_CHECK 20510 assert(ncollinear); 20511 #endif 20512 if (refpoint == (point) NULL) { 20513 refpoint = testpt; 20514 largest = radius; 20515 } else { 20516 if (radius > largest) { 20517 refpoint = testpt; 20518 largest = radius; 20519 } 20520 } 20521 } 20522 testpt = oppo(*searchtet); 20523 if (isedgeencroached(tstart, tend, testpt, true)) { 20524 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); 20525 #ifdef SELF_CHECK 20526 assert(ncollinear); 20527 #endif 20528 if (refpoint == (point) NULL) { 20529 refpoint = testpt; 20530 largest = radius; 20531 } else { 20532 if (radius > largest) { 20533 refpoint = testpt; 20534 largest = radius; 20535 } 20536 } 20537 } 20538 // Check the opposite vertex of the neighboring tet in case the segment 20539 // crosses the edge (leftpoint, rightpoint) of the crossing face. 20540 sym(*searchtet, checkface); 20541 if (checkface.tet != dummytet) { 20542 testpt = oppo(checkface); 20543 if (isedgeencroached(tstart, tend, testpt, true)) { 20544 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); 20545 #ifdef SELF_CHECK 20546 assert(ncollinear); 20547 #endif 20548 if (refpoint == (point) NULL) { 20549 refpoint = testpt; 20550 largest = radius; 20551 } else { 20552 if (radius > largest) { 20553 refpoint = testpt; 20554 largest = radius; 20555 } 20556 } 20557 } 20558 } 20559 20560 // Walk through all crossing faces. 20561 enextfnext(*searchtet, checkface); 20562 sym(checkface, *searchtet); 20563 while (true) { 20564 // Check if we are reaching the boundary of the triangulation. 20565 #ifdef SELF_CHECK 20566 assert(searchtet->tet != dummytet); 20567 #endif 20568 // Search for an adjoining tetrahedron we can walk through. 20569 searchtet->ver = 0; 20570 // 'testpt' is the shared vertex for the following orientation tests. 20571 testpt = oppo(*searchtet); 20572 if (testpt == tend) { 20573 // The searching is finished. 20574 break; 20575 } else { 20576 // 'testpt' may encroach the segment. 20577 if ((testpt != tstart) && (testpt != refpoint)) { 20578 if (isedgeencroached(tstart, tend, testpt, true)) { 20579 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius); 20580 if (!ncollinear) { 20581 // 'testpt' is collinear with the segment. It may happen when a 20582 // set of collinear and continuous segments is defined by two 20583 // extreme endpoints. In this case, we should choose 'testpt' 20584 // as the splitting point immediately. No new point should be 20585 // created. 20586 refpoint = testpt; 20587 break; 20588 } 20589 if (refpoint == (point) NULL) { 20590 refpoint = testpt; 20591 largest = radius; 20592 } else { 20593 if (radius > largest) { 20594 refpoint = testpt; 20595 largest = radius; 20596 } 20597 } 20598 } 20599 } 20600 } 20601 // Check three side-faces of 'searchtet' to find the one through 20602 // which we can walk next. 20603 for (sides = 0; sides < 3; sides++) { 20604 fnext(*searchtet, checkface); 20605 ahead = orient3d(org(checkface), dest(checkface), testpt, tend); 20606 if (ahead < 0.0) { 20607 // We can walk through this face and continue the searching. 20608 sym(checkface, *searchtet); 20609 break; 20610 } 20611 enextself(*searchtet); 20612 } 20613 #ifdef SELF_CHECK 20614 assert (sides < 3); 20615 #endif 20616 } 20617 20618 #ifdef SELF_CHECK 20619 assert(refpoint != (point) NULL); 20620 #endif 20621 return refpoint; 20622 } 20623 20625 // // 20626 // getsegmentorigin() Return the origin of the (unsplit) segment. // 20627 // // 20628 // After a segment (or a subsegment) is split. Two resulting subsegments are // 20629 // connecting each other through the pointers saved in their data fields. // 20630 // With these pointers, the whole (unsplit) segment can be found. 'splitseg' // 20631 // may be a split subsegment. Returns the origin of the unsplit segment. // 20632 // // 20634 20635 tetgenmesh::point tetgenmesh::getsegmentorigin(face* splitseg) 20636 { 20637 face workseg; 20638 point farorg; 20639 20640 farorg = sorg(*splitseg); 20641 if ((pointtype(farorg) != ACUTEVERTEX) && 20642 (pointtype(farorg) != NACUTEVERTEX)) { 20643 workseg = *splitseg; 20644 do { 20645 senext2self(workseg); 20646 spivotself(workseg); 20647 if (workseg.sh != dummysh) { 20648 workseg.shver = 0; // It's a subsegment. 20649 if (sdest(workseg) != farorg) { 20650 sesymself(workseg); 20651 #ifdef SELF_CHECK 20652 assert(sdest(workseg) == farorg); 20653 #endif 20654 } 20655 farorg = sorg(workseg); 20656 if ((pointtype(farorg) == ACUTEVERTEX) || 20657 (pointtype(farorg) == NACUTEVERTEX)) break; 20658 } 20659 } while (workseg.sh != dummysh); 20660 } 20661 #ifdef SELF_CHECK 20662 assert((pointtype(farorg) == ACUTEVERTEX) || 20663 (pointtype(farorg) == NACUTEVERTEX)); 20664 #endif 20665 return farorg; 20666 } 20667 20669 // // 20670 // getsplitpoint() Get a point for splitting a segment. // 20671 // // 20672 // 'splitseg' is the segment will be split. 'refpoint' is a reference point // 20673 // for splitting this segment. Moreover, it should not collinear with the // 20674 // splitting segment. (The collinear case will be detected by iscollinear() // 20675 // before entering this routine.) The calculation of the splitting point is // 20676 // governed by three rules introduced in my paper. // 20677 // // 20678 // After the position is calculated, a new point is created at this location.// 20679 // The new point has one of the two pointtypes: FREESEGVERTEX indicating it // 20680 // is an inserting vertex on segment, and NACUTEVERTEX indicating it is an // 20681 // endpoint of a segment which original has type-3 now becomes type-2. // 20682 // // 20684 20685 tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint) 20686 { 20687 point splitpoint; 20688 point farorg, fardest; 20689 point ei, ej, ek, c; 20690 REAL v[3], r, split; 20691 REAL d1, d2, ps, rs; 20692 bool acuteorg, acutedest; 20693 int stype, rule; 20694 int i; 20695 20696 // First determine the type of the segment (type-1, type-2, or type-3). 20697 farorg = getsegmentorigin(splitseg); 20698 acuteorg = (pointtype(farorg) == ACUTEVERTEX); 20699 sesymself(*splitseg); 20700 fardest = getsegmentorigin(splitseg); 20701 acutedest = (pointtype(fardest) == ACUTEVERTEX); 20702 sesymself(*splitseg); 20703 20704 ek = (point) NULL; // avoid a compilation warning. 20705 20706 if (acuteorg) { 20707 if (acutedest) { 20708 stype = 3; 20709 } else { 20710 stype = 2; 20711 ek = farorg; 20712 } 20713 } else { 20714 if (acutedest) { 20715 stype = 2; 20716 // Adjust splitseg, so that its origin is acute. 20717 sesymself(*splitseg); 20718 ek = fardest; 20719 } else { 20720 stype = 1; 20721 } 20722 } 20723 ei = sorg(*splitseg); 20724 ej = sdest(*splitseg); 20725 20726 if (b->verbose > 1) { 20727 printf(" Splitting segment (%d, %d) type-%d with refpoint %d.\n", 20728 pointmark(ei), pointmark(ej), stype, pointmark(refpoint)); 20729 } 20730 20731 if (stype == 1 || stype == 3) { 20732 // Use rule-1. 20733 REAL eij, eip, ejp; 20734 eij = distance(ei, ej); 20735 eip = distance(ei, refpoint); 20736 ejp = distance(ej, refpoint); 20737 if ((eip < ejp) && (eip < 0.5 * eij)) { 20738 c = ei; 20739 r = eip; 20740 } else if ((eip > ejp) && (ejp < 0.5 * eij)) { 20741 c = ej; 20742 ej = ei; 20743 r = ejp; 20744 } else { 20745 c = ei; 20746 r = 0.5 * eij; 20747 } 20748 split = r / eij; 20749 for (i = 0; i < 3; i++) { 20750 v[i] = c[i] + split * (ej[i] - c[i]); 20751 } 20752 rule = 1; 20753 } else { 20754 // Use rule-2 or rule-3. 20755 REAL eki, ekj, ekp, evj, evp, eiv; 20756 c = ek; 20757 eki = distance(ek, ei); // eki may equal zero. 20758 ekj = distance(ek, ej); 20759 ekp = distance(ek, refpoint); 20760 // Calculate v (the going to split position between ei, ej). 20761 r = ekp; 20762 // Check the validity of the position. 20763 if (!(eki < r && r < ekj)) { 20764 printf("Error: Invalid PLC.\n"); 20765 printf(" Hint: Use -d switch to check it.\n"); 20766 terminatetetgen(1); 20767 } 20768 split = r / ekj; 20769 for (i = 0; i < 3; i++) { 20770 v[i] = c[i] + split * (ej[i] - c[i]); 20771 } 20772 rule = 2; 20773 evj = ekj - r; // distance(v, ej); 20774 evp = distance(v, refpoint); 20775 if (evj < evp) { 20776 // v is rejected, use rule-3. 20777 eiv = distance(ei, v); 20778 if (evp <= 0.5 * eiv) { 20779 r = eki + eiv - evp; 20780 } else { 20781 r = eki + 0.5 * eiv; 20782 } 20783 #ifdef SELF_CHECK 20784 assert(eki < r && r < ekj); 20785 #endif 20786 split = r / ekj; 20787 for (i = 0; i < 3; i++) { 20788 v[i] = c[i] + split * (ej[i] - c[i]); 20789 } 20790 if (b->verbose > 1) { 20791 printf(" Using rule-3.\n"); 20792 } 20793 rule = 3; 20794 } 20795 } 20796 20797 // Accumulate the corresponding counters. 20798 if (rule == 1) r1count++; 20799 else if (rule == 2) r2count++; 20800 else if (rule == 3) r3count++; 20801 20802 if (b->verbose > 1) { 20803 if (stype == 2) { 20804 printf(" Split = %.12g.\n", distance(ei, v) / distance(ei, ej)); 20805 } else { 20806 printf(" Split = %.12g.\n", distance(c, v) / distance(c, ej)); 20807 } 20808 } 20809 20810 // Create the newpoint. 20811 makepoint(&splitpoint); 20812 // Add a random perturbation on splitpoint. 20813 d1 = distance(c, v); 20814 d2 = distance(refpoint, v); 20815 if (stype == 1 || stype == 3) { 20816 ps = randgenerator(d1 * 1.0e-3); 20817 } else { 20818 // For type-2 segment, add a smaller perturbation. 20819 // ps = randgenerator(d1 * 1.0e-5); 20820 // REAL d2 = distance(refpoint, v); 20821 ps = randgenerator(d2 * 1.0e-5); 20822 } 20823 rs = ps / d1; 20824 // Perturb splitpoint away from c. 20825 for (i = 0; i < 3; i++) { 20826 splitpoint[i] = c[i] + (1.0 + rs) * (v[i] - c[i]); 20827 } 20828 // for (i = 0; i < in->numberofpointattributes; i++) { 20829 // splitpoint[i + 3] = c[i + 3] + (split + rs) * (ej[i + 3] - c[i + 3]); 20830 // } 20831 if (stype == 3) { 20832 // Change a type-3 segment into two type-2 segments. 20833 setpointtype(splitpoint, NACUTEVERTEX); 20834 } else { 20835 // Set it's type be FREESEGVERTEX. 20836 setpointtype(splitpoint, FREESEGVERTEX); 20837 } 20838 setpoint2sh(splitpoint, sencode(*splitseg)); 20839 20840 return splitpoint; 20841 } 20842 20844 // // 20845 // insertsegment() Insert segment into DT. Queue it if it does not exist. // 20846 // // 20848 20849 bool tetgenmesh::insertsegment(face *insseg, list *misseglist) 20850 { 20851 badface *misseg; 20852 triface searchtet, spintet; 20853 point tend, checkpoint; 20854 point p1, p2; 20855 enum finddirectionresult collinear; 20856 int hitbdry; 20857 20858 // Search segment ab in DT. 20859 p1 = (point) insseg->sh[3]; 20860 p2 = (point) insseg->sh[4]; 20861 getsearchtet(p1, p2, &searchtet, &tend); 20862 collinear = finddirection(&searchtet, tend, tetrahedrons->items); 20863 if (collinear == LEFTCOLLINEAR) { 20864 checkpoint = apex(searchtet); 20865 enext2self(searchtet); 20866 esymself(searchtet); 20867 } else if (collinear == RIGHTCOLLINEAR) { 20868 checkpoint = dest(searchtet); 20869 } else if (collinear == TOPCOLLINEAR) { 20870 checkpoint = oppo(searchtet); 20871 fnextself(searchtet); 20872 enext2self(searchtet); 20873 esymself(searchtet); 20874 } else { 20875 // assert(collinear == ACROSSFACE || collinear == ACROSSEDGE); 20876 checkpoint = (point) NULL; 20877 } 20878 if (checkpoint == tend) { 20879 // Segment exist. Bond it to all tets containing it. 20880 hitbdry = 0; 20881 adjustedgering(searchtet, CCW); 20882 fnextself(searchtet); 20883 spintet = searchtet; 20884 do { 20885 tssbond1(spintet, *insseg); 20886 if (!fnextself(spintet)) { 20887 hitbdry++; 20888 if (hitbdry < 2) { 20889 esym(searchtet, spintet); 20890 if (!fnextself(spintet)) { 20891 hitbdry++; 20892 } 20893 } 20894 } 20895 } while ((apex(spintet) != apex(searchtet)) && (hitbdry < 2)); 20896 return true; 20897 } else { 20898 // Segment is missing. 20899 if (misseglist != (list *) NULL) { 20900 if (b->verbose > 2) { 20901 printf(" Queuing missing segment (%d, %d).\n", pointmark(p1), 20902 pointmark(p2)); 20903 } 20904 misseg = (badface *) misseglist->append(NULL); 20905 misseg->ss = *insseg; 20906 misseg->forg = p1; 20907 misseg->fdest = p2; 20908 misseg->foppo = (point) NULL; // Not used. 20909 // setshell2badface(misseg->ss, misseg); 20910 } 20911 return false; 20912 } 20913 } 20914 20916 // // 20917 // tallmissegs() Find and queue all missing segments in DT. // 20918 // // 20920 20921 void tetgenmesh::tallmissegs(list *misseglist) 20922 { 20923 face segloop; 20924 20925 if (b->verbose) { 20926 printf(" Queuing missing segments.\n"); 20927 } 20928 20929 subsegs->traversalinit(); 20930 segloop.sh = shellfacetraverse(subsegs); 20931 while (segloop.sh != (shellface *) NULL) { 20932 insertsegment(&segloop, misseglist); 20933 segloop.sh = shellfacetraverse(subsegs); 20934 } 20935 } 20936 20938 // // 20939 // delaunizesegments() Split segments repeatedly until they appear in a // 20940 // Delaunay tetrahedralization. // 20941 // // 20942 // Given a PLC X, which has a set V of vertices and a set of segments. Start // 20943 // from a Delaunay tetrahedralization D of V, this routine recovers segments // 20944 // of X in D by incrementally inserting points on missing segments, updating // 20945 // D with the newly inserted points into D', which remains to be a Delaunay // 20946 // tetrahedralization and respects the segments of X. Hence, each segment of // 20947 // X appears as a union of edges in D'. // 20948 // // 20949 // This routine dynamically maintains two meshes, one is DT, another is the // 20950 // surface mesh F of X. DT and F have exactly the same vertices. They are // 20951 // updated simultaneously with the newly inserted points. // 20952 // // 20953 // Missing segments are found by looping the set S of segments, checking the // 20954 // existence of each segment in DT. Once a segment is found missing in DT, // 20955 // it is split into two subsegments by inserting a point into both DT and F, // 20956 // and S is updated accordingly. However, the inserted point may cause some // 20957 // other existing segments be non-Delaunay, hence are missing from the DT. // 20958 // In order to force all segments to appear in DT, we have to loop S again // 20959 // after some segments are split. (A little ugly method) Use a handle to // 20960 // remember the last segment be split in one loop, hence all segments after // 20961 // it are existing and need not be checked. // 20962 // // 20963 // In priciple, a segment on the convex hull should exist in DT. However, if // 20964 // there are four coplanar points on the convex hull, and the DT only can // 20965 // contain one diagonal edge which is unfortunately not the segment, then it // 20966 // is missing. During the recovery of the segment, it is possible that the // 20967 // calculated inserting point for recovering this convex hull segment is not // 20968 // exact enough and lies (slightly) outside the DT. In order to insert the // 20969 // point, we enlarge the convex hull of the DT, so it can contain the point // 20970 // and remains convex. 'inserthullsite()' is called for this case. // 20971 // // 20973 20974 void tetgenmesh::delaunizesegments() 20975 { 20976 list *misseglist; 20977 queue *flipqueue; 20978 badface *misloop; 20979 tetrahedron encodedtet; 20980 triface searchtet, splittet; 20981 face splitsh, symsplitsub; 20982 face segloop, symsplitseg; 20983 point refpoint, splitpoint, sympoint; 20984 point tend, checkpoint; 20985 point p1, p2, pa; 20986 enum finddirectionresult collinear; 20987 enum insertsiteresult success; 20988 enum locateresult symloc; 20989 bool coll; 20990 long vertcount; 20991 int i, j; 20992 20993 if (!b->quiet) { 20994 printf("Delaunizing segments.\n"); 20995 } 20996 20997 // Construct a map from points to tets for speeding point location. 20998 makepoint2tetmap(); 20999 // Initialize a flipqueue. 21000 flipqueue = new queue(sizeof(badface)); 21001 // Initialize the pool of missing segments. 21002 misseglist = new list(sizeof(badface), NULL, SUBPERBLOCK); 21003 // Looking for missing segments. 21004 tallmissegs(misseglist); 21005 // The DT contains segments now. 21006 checksubsegs = 1; 21007 // Remember the current number of points. 21008 vertcount = points->items; 21009 // Initialize the counters. 21010 r1count = r2count = r3count = 0l; 21011 21012 // Loop until 'misseglist' is empty. 21013 while (misseglist->items > 0) { 21014 // Randomly pick a missing segment to recover. 21015 i = randomnation(misseglist->items); 21016 misloop = (badface *)(* misseglist)[i]; 21017 segloop = misloop->ss; 21018 // Fill the "hole" in the list by filling the last one. 21019 *misloop = *(badface *)(* misseglist)[misseglist->items - 1]; 21020 misseglist->items--; 21021 // Now recover the segment. 21022 p1 = (point) segloop.sh[3]; 21023 p2 = (point) segloop.sh[4]; 21024 if (b->verbose > 1) { 21025 printf(" Recover segment (%d, %d).\n", pointmark(p1), pointmark(p2)); 21026 } 21027 getsearchtet(p1, p2, &searchtet, &tend); 21028 collinear = finddirection(&searchtet, tend, tetrahedrons->items); 21029 if (collinear == LEFTCOLLINEAR) { 21030 checkpoint = apex(searchtet); 21031 } else if (collinear == RIGHTCOLLINEAR) { 21032 checkpoint = dest(searchtet); 21033 } else if (collinear == TOPCOLLINEAR) { 21034 checkpoint = oppo(searchtet); 21035 } else { 21036 #ifdef SELF_CHECK 21037 assert(collinear == ACROSSFACE || collinear == ACROSSEDGE); 21038 #endif 21039 checkpoint = (point) NULL; 21040 } 21041 if (checkpoint != tend) { 21042 // ab is missing. 21043 splitpoint = (point) NULL; 21044 if (checkpoint != (point) NULL) { 21045 // An existing point c is found on the segment. It can happen when 21046 // ab is defined by a long segment with c inside it. Use c to 21047 // split ab. No new point is created. 21048 splitpoint = checkpoint; 21049 if (pointtype(checkpoint) == FREEVOLVERTEX) { 21050 // c is not a segment vertex yet. It becomes NACUTEVERTEX. 21051 setpointtype(splitpoint, NACUTEVERTEX); 21052 } else if (pointtype(checkpoint) == ACUTEVERTEX) { 21053 // c is an acute vertex. The definition of PLC is wrong. 21054 } else if (pointtype(checkpoint) == NACUTEVERTEX) { 21055 // c is an nonacute vertex. The definition of PLC is wrong. 21056 } else { 21057 // assert(0); 21058 } 21059 } else { 21060 // Find a reference point p of ab. 21061 refpoint = scoutrefpoint(&searchtet, tend); 21062 if (pointtype(refpoint) == FREEVOLVERTEX) { 21063 // p is an input point, check if it is nearly collinear with ab. 21064 coll = iscollinear(p1, p2, refpoint, b->epsilon); 21065 if (coll) { 21066 // a, b, and p are collinear. We insert p into ab. p becomes 21067 // a segment vertex with type NACUTEVERTEX. 21068 splitpoint = refpoint; 21069 setpointtype(splitpoint, NACUTEVERTEX); 21070 } 21071 } 21072 if (splitpoint == (point) NULL) { 21073 // Calculate a split point v using rule 1, or 2, or 3. 21074 splitpoint = getsplitpoint(&segloop, refpoint); 21075 21076 // Is there periodic boundary conditions? 21077 if (checkpbcs) { 21078 // Yes! Insert points on other segments of incident pbcgroups. 21079 i = shellmark(segloop) - 1; 21080 for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) { 21081 makepoint(&sympoint); 21082 symloc = getsegpbcsympoint(splitpoint, &segloop, sympoint, 21083 &symsplitseg, segpglist[j]); 21084 #ifdef SELF_CHECK 21085 assert(symloc != OUTSIDE); 21086 #endif 21087 if ((symloc == ONEDGE) && (symsplitseg.sh != segloop.sh)) { 21088 #ifdef SELF_CHECK 21089 assert(symsplitseg.sh != dummysh); 21090 #endif 21091 setpointtype(sympoint, FREESEGVERTEX); 21092 setpoint2sh(sympoint, sencode(symsplitseg)); 21093 // Insert sympoint into DT. 21094 pa = sorg(symsplitseg); 21095 splittet.tet = dummytet; 21096 // Find a good start point to search. 21097 encodedtet = point2tet(pa); 21098 if (encodedtet != (tetrahedron) NULL) { 21099 decode(encodedtet, splittet); 21100 if (isdead(&splittet)) { 21101 splittet.tet = dummytet; 21102 } 21103 } 21104 // Locate sympoint in DT. Do exact location. 21105 success = insertsite(sympoint, &splittet, false, flipqueue); 21106 #ifdef SELF_CHECK 21107 assert(success != DUPLICATEPOINT); 21108 #endif 21109 if (success == OUTSIDEPOINT) { 21110 inserthullsite(sympoint, &splittet, flipqueue); 21111 } 21112 if (steinerleft > 0) steinerleft--; 21113 // Let sympoint remember splittet. 21114 setpoint2tet(sympoint, encode(splittet)); 21115 // Do flip in DT. 21116 lawson(misseglist, flipqueue); 21117 // Insert sympoint into F. 21118 symsplitseg.shver = 0; 21119 spivot(symsplitseg, symsplitsub); 21120 // sympoint should on the edge of symsplitsub. 21121 splitsubedge(sympoint, &symsplitsub, flipqueue); 21122 // Do flip in facet. 21123 flipsub(flipqueue); 21124 // Insert the two subsegments. 21125 symsplitseg.shver = 0; 21126 insertsegment(&symsplitseg, misseglist); 21127 senextself(symsplitseg); 21128 spivotself(symsplitseg); 21129 symsplitseg.shver = 0; 21130 insertsegment(&symsplitseg, misseglist); 21131 } else { // if (symloc == ONVERTEX) { 21132 // The sympoint already exists. It is possible when two 21133 // pbc groups are exactly the same. Omit this point. 21134 pointdealloc(sympoint); 21135 } 21136 } 21137 } 21138 21139 // Insert 'splitpoint' into DT. 21140 if (isdead(&searchtet)) searchtet.tet = dummytet; 21141 success = insertsite(splitpoint, &searchtet, false, flipqueue); 21142 if (success == OUTSIDEPOINT) { 21143 // A convex hull edge is missing, and the inserting point lies 21144 // (slightly) outside the convex hull due to the significant 21145 // digits lost in the calculation. Enlarge the convex hull. 21146 inserthullsite(splitpoint, &searchtet, flipqueue); 21147 } 21148 if (steinerleft > 0) steinerleft--; 21149 // Remember a handle in 'splitpoint' to enhance the speed of 21150 // consequent point location. 21151 setpoint2tet(splitpoint, encode(searchtet)); 21152 // Maintain Delaunayness in DT. 21153 lawson(misseglist, flipqueue); 21154 } 21155 } 21156 // Insert 'splitpoint' into F. 21157 spivot(segloop, splitsh); 21158 splitsubedge(splitpoint, &splitsh, flipqueue); 21159 flipsub(flipqueue); 21160 // Insert the two subsegments. 21161 segloop.shver = 0; 21162 insertsegment(&segloop, misseglist); 21163 senextself(segloop); 21164 spivotself(segloop); 21165 segloop.shver = 0; 21166 insertsegment(&segloop, misseglist); 21167 } 21168 } 21169 21170 // Detach all segments from tets. 21171 tetrahedrons->traversalinit(); 21172 searchtet.tet = tetrahedrontraverse(); 21173 while (searchtet.tet != (tetrahedron *) NULL) { 21174 for (i = 0; i < 6; i++) { 21175 searchtet.tet[8 + i] = (tetrahedron) dummysh; 21176 } 21177 searchtet.tet = tetrahedrontraverse(); 21178 } 21179 // No segments now. 21180 checksubsegs = 0; 21181 21182 if (b->verbose > 0) { 21183 printf(" %ld protect points.\n", points->items - vertcount); 21184 printf(" R1: %ld, R2: %ld, R3: %ld.\n", r1count, r2count, r3count); 21185 } 21186 21187 delete flipqueue; 21188 delete misseglist; 21189 } 21190 21191 // 21192 // End of segments recovery routines 21193 // 21194 21195 // 21196 // Begin of facet recovery routines 21197 // 21198 21200 // // 21201 // insertsubface() Fix a subface in place. // 21202 // // 21203 // Search a subface s in current tetrahedralization T. If s is found a face // 21204 // face of T, it is inserted into T. Return FALSE if s is not found in T. // 21205 // // 21207 21208 bool tetgenmesh::insertsubface(face* insertsh, triface* searchtet) 21209 { 21210 triface spintet, symtet; 21211 face testsh, testseg; 21212 face spinsh, casin, casout; 21213 point tapex, checkpoint; 21214 enum finddirectionresult collinear; 21215 int hitbdry; 21216 21217 // Search an edge of s. 21218 getsearchtet(sorg(*insertsh), sdest(*insertsh), searchtet, &checkpoint); 21219 collinear = finddirection(searchtet, checkpoint, tetrahedrons->items); 21220 if (collinear == LEFTCOLLINEAR) { 21221 enext2self(*searchtet); 21222 esymself(*searchtet); 21223 } else if (collinear == TOPCOLLINEAR) { 21224 fnextself(*searchtet); 21225 enext2self(*searchtet); 21226 esymself(*searchtet); 21227 } 21228 if (dest(*searchtet) != checkpoint) { 21229 // The edge doesn't exist => s is missing. 21230 return false; 21231 } 21232 21233 // Search s by spinning faces around the edge. 21234 tapex = sapex(*insertsh); 21235 spintet = *searchtet; 21236 hitbdry = 0; 21237 do { 21238 if (apex(spintet) == tapex) { 21239 // Found s in T. Check if s has already been inserted. 21240 tspivot(spintet, testsh); 21241 if (testsh.sh == dummysh) { 21242 adjustedgering(spintet, CCW); 21243 findedge(insertsh, org(spintet), dest(spintet)); 21244 tsbond(spintet, *insertsh); 21245 sym(spintet, symtet); // 'symtet' maybe outside, use it anyway. 21246 sesymself(*insertsh); 21247 tsbond(symtet, *insertsh); 21248 } else { 21249 // Found a duplicated subface (due to the redundant input). 21250 if (!b->quiet) { 21251 printf("Warning: Two subfaces are found duplicated at "); 21252 printf("(%d, %d, %d)\n", pointmark(sorg(testsh)), 21253 pointmark(sdest(testsh)), pointmark(sapex(testsh))); 21254 printf(" Subface of facet #%d is deleted.\n", shellmark(*insertsh)); 21255 // printf(" Hint: -d switch can find all duplicated facets.\n"); 21256 } 21257 shellfacedealloc(subfaces, insertsh->sh); 21258 } 21259 return true; 21260 } 21261 if (!fnextself(spintet)) { 21262 hitbdry ++; 21263 if (hitbdry < 2) { 21264 esym(*searchtet, spintet); 21265 if (!fnextself(spintet)) { 21266 hitbdry ++; 21267 } 21268 } 21269 } 21270 } while (hitbdry < 2 && apex(spintet) != apex(*searchtet)); 21271 21272 // s is missing. 21273 return false; 21274 } 21275 21277 // // 21278 // tritritest() Test if two triangles are intersecting in their interior. // 21279 // // 21280 // One triangle t1 is the face of 'checktet', the other t2 is given by three // 21281 // corners 'p1', 'p2' and 'p3'. This routine calls tri_tri_inter() to detect // 21282 // whether t1 and t2 exactly intersect in their interior. Cases like share a // 21283 // vertex, share an edge, or coincidence are considered not intersect. // 21284 // // 21286 21287 bool tetgenmesh::tritritest(triface* checktet, point p1, point p2, point p3) 21288 { 21289 point forg, fdest, fapex; 21290 enum interresult intersect; 21291 21292 forg = org(*checktet); 21293 fdest = dest(*checktet); 21294 fapex = apex(*checktet); 21295 21296 #ifdef SELF_CHECK 21297 REAL ax, ay, az, bx, by, bz; 21298 REAL n[3]; 21299 // face (torg, tdest, tapex) should not be degenerate. However p1, p2, 21300 // and p3 may be collinear. Check it. 21301 ax = forg[0] - fdest[0]; 21302 ay = forg[1] - fdest[1]; 21303 az = forg[2] - fdest[2]; 21304 bx = forg[0] - fapex[0]; 21305 by = forg[1] - fapex[1]; 21306 bz = forg[2] - fapex[2]; 21307 n[0] = ay * bz - by * az; 21308 n[1] = az * bx - bz * ax; 21309 n[2] = ax * by - bx * ay; 21310 assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0); 21311 // The components of n should not smaller than the machine epsilon. 21312 21313 ax = p1[0] - p2[0]; 21314 ay = p1[1] - p2[1]; 21315 az = p1[2] - p2[2]; 21316 bx = p1[0] - p3[0]; 21317 by = p1[1] - p3[1]; 21318 bz = p1[2] - p3[2]; 21319 n[0] = ay * bz - by * az; 21320 n[1] = az * bx - bz * ax; 21321 n[2] = ax * by - bx * ay; 21322 assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0); 21323 // The components of n should not smaller than the machine epsilon. 21324 #endif 21325 21326 intersect = tri_tri_inter(forg, fdest, fapex, p1, p2, p3); 21327 return intersect == INTERSECT; 21328 } 21329 21331 // // 21332 // initializecavity() Initialize the cavity. // 21333 // // 21334 // A cavity C is bounded by a list of faces, called fronts. Each front f is // 21335 // hold by a tet t adjacent to C, t is not in C (uninfected). If f is a hull // 21336 // face, t does't exist, a fake tet t' is created to hold f. t' has the same // 21337 // vertices as f but no opposite. t' will be removed automatically after C // 21338 // is filled with new tets (by carvecavity()). // 21339 // // 21340 // The faces of C are given in two lists. 'floorlist' is a set of subfaces, // 21341 // each subface has been oriented to face to the inside of C. 'ceillist' is // 21342 // a set of tetrahedral faces. 'frontlist' returns the initialized fronts. // 21343 // // 21345 21346 void tetgenmesh::initializecavity(list* floorlist, list* ceillist, 21347 list* frontlist) 21348 { 21349 triface neightet, casingtet; 21350 triface faketet; 21351 face worksh; 21352 int i; 21353 21354 // Initialize subfaces of C. 21355 for (i = 0; i < floorlist->len(); i++) { 21356 // Get a subface s. 21357 worksh = * (face *)(* floorlist)[i]; 21358 #ifdef SELF_CHECK 21359 // Current side of s should be empty. 21360 stpivot(worksh, neightet); 21361 assert(neightet.tet == dummytet); 21362 #endif 21363 // Get the adjacent tet t. 21364 sesymself(worksh); 21365 stpivot(worksh, casingtet); 21366 // Does t exist? 21367 if (casingtet.tet == dummytet) { 21368 // Create a fake tet t' to hold f temporarily. 21369 maketetrahedron(&faketet); 21370 setorg(faketet, sorg(worksh)); 21371 setdest(faketet, sdest(worksh)); 21372 setapex(faketet, sapex(worksh)); 21373 setoppo(faketet, (point) NULL); // Indicates it is 'fake'. 21374 tsbond(faketet, worksh); 21375 frontlist->append(&faketet); 21376 } else { 21377 frontlist->append(&casingtet); 21378 } 21379 } 21380 // Initialize tet faces of C. 21381 for (i = 0; i < ceillist->len(); i++) { 21382 // Get a tet face c. 21383 neightet = * (triface *) (* ceillist)[i]; 21384 #ifdef SELF_CHECK 21385 // The tet of c must be inside C (going to be deleted). 21386 assert(infected(neightet)); 21387 #endif 21388 // Get the adjacent tet t. 21389 sym(neightet, casingtet); 21390 // Does t exist? 21391 if (casingtet.tet == dummytet) { 21392 // No. Create a fake tet t' to hold f temporarily. 21393 maketetrahedron(&faketet); 21394 // Be sure that the vertices of t' are CCW oriented. 21395 adjustedgering(neightet, CW); // CW edge ring. 21396 setorg(faketet, org(neightet)); 21397 setdest(faketet, dest(neightet)); 21398 setapex(faketet, apex(neightet)); 21399 setoppo(faketet, (point) NULL); // Indicates it is 'fake'. 21400 // Bond t' to a subface if it exists. 21401 tspivot(neightet, worksh); 21402 if (worksh.sh != dummysh) { 21403 sesymself(worksh); 21404 tsbond(faketet, worksh); 21405 } 21406 // Bond c <--> t'. So we're able to find t' and remove it. 21407 bond(faketet, neightet); 21408 // c may become uninfected due to the bond(). 21409 infect(neightet); 21410 frontlist->append(&faketet); 21411 } else { 21412 frontlist->append(&casingtet); 21413 } 21414 } 21415 } 21416 21418 // // 21419 // retrievenewtets() Retrieve the newly created tets. // 21420 // // 21421 // On input, 'newtetlist' contains at least one alive new tet. From this tet,// 21422 // other new tets can be found by a broadth-first searching. // 21423 // // 21425 21426 void tetgenmesh::retrievenewtets(list* newtetlist) 21427 { 21428 triface searchtet, casingtet; 21429 int i; 21430 21431 // There may be dead tets due to flip32(). Delete them first. 21432 for (i = 0; i < newtetlist->len(); i++) { 21433 searchtet = * (triface *)(* newtetlist)[i]; 21434 if (isdead(&searchtet)) { 21435 newtetlist->del(i, 0); i--; 21436 continue; 21437 } 21438 infect(searchtet); 21439 } 21440 // Find all new tets. 21441 for (i = 0; i < newtetlist->len(); i++) { 21442 searchtet = * (triface *)(* newtetlist)[i]; 21443 for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) { 21444 sym(searchtet, casingtet); 21445 if ((casingtet.tet != dummytet) && !infected(casingtet)) { 21446 infect(casingtet); 21447 newtetlist->append(&casingtet); 21448 } 21449 } 21450 } 21451 // Uninfect new tets. 21452 for (i = 0; i < newtetlist->len(); i++) { 21453 searchtet = * (triface *)(* newtetlist)[i]; 21454 uninfect(searchtet); 21455 } 21456 } 21457 21459 // // 21460 // delaunizecavvertices() Form a DT of the vertices of a cavity. // 21461 // // 21462 // 'floorptlist' and 'ceilptlist' are the vertices of the cavity. // 21463 // // 21464 // The tets of the DT are created directly in the pool 'tetrahedrons', i.e., // 21465 // no auxiliary data structure and memory are required. The trick is at the // 21466 // time they're created, there are no connections between them to the other // 21467 // tets in the pool. You can imagine they form an ioslated island. // 21468 // // 21470 21471 void tetgenmesh::delaunizecavvertices(triface* oldtet, list* floorptlist, 21472 list* ceilptlist, list* newtetlist, queue* flipque) 21473 { 21474 point *insertarray; 21475 triface bakhulltet, newtet; 21476 long bakhullsize; 21477 long arraysize; 21478 int bakchksub; 21479 int i, j; 21480 21481 // Prepare the array of points for inserting. 21482 arraysize = floorptlist->len(); 21483 if (ceilptlist != (list *) NULL) { 21484 arraysize += ceilptlist->len(); 21485 } 21486 insertarray = new point[arraysize]; 21487 for (i = 0; i < floorptlist->len(); i++) { 21488 insertarray[i] = * (point *)(* floorptlist)[i]; 21489 } 21490 if (ceilptlist != (list *) NULL) { 21491 for (j = 0; j < ceilptlist->len(); j++) { 21492 insertarray[i + j] = * (point *)(* ceilptlist)[j]; 21493 } 21494 } 21495 21496 // The incrflipdelaunay() is re-used. Backup global variables. 21497 decode(dummytet[0], bakhulltet); 21498 bakhullsize = hullsize; 21499 bakchksub = checksubfaces; 21500 checksubfaces = 0; 21501 b->verbose--; 21502 21503 // Form the DT by incremental flip Delaunay algorithm. Do not jump for 21504 // point location, do not merge points. 21505 incrflipdelaunay(oldtet, insertarray, arraysize, false, false, 0.0, flipque); 21506 21507 // Get a tet in D. 21508 decode(dummytet[0], newtet); 21509 newtetlist->append(&newtet); 21510 // Get all tets of D. 21511 retrievenewtets(newtetlist); 21512 21513 // Restore global variables. 21514 dummytet[0] = encode(bakhulltet); 21515 hullsize = bakhullsize; 21516 checksubfaces = bakchksub; 21517 b->verbose++; 21518 21519 delete [] insertarray; 21520 } 21521 21523 // // 21524 // insertauxsubface() Fix an auxilary subface in place. // 21525 // // 21526 // An auxilary subface s is fixed in D as it is a real subface, but s has no // 21527 // vertices and neighbors. It has two uses: (1) it protects an identfied // 21528 // front f in D; (2) it serves the link to bond a tet in C and f later. The // 21529 // first neighbor of s (s->sh[0]) stores a pointer to f. // 21530 // // 21531 // 'front' is a front f of C. idfront' t is a tet in D where f is identified // 21532 // be a face of it. s will be fixed between t and its neighbor. // 21533 // // 21535 21536 void tetgenmesh::insertauxsubface(triface* front, triface* idfront) 21537 { 21538 triface neightet; 21539 face auxsh; 21540 21541 // Create the aux subface s. 21542 makeshellface(subfaces, &auxsh); 21543 // Bond s <--> t. 21544 tsbond(*idfront, auxsh); 21545 // Does t's neighbor n exist? 21546 sym(*idfront, neightet); 21547 if (neightet.tet != dummytet) { 21548 // Bond s <--> n. 21549 sesymself(auxsh); 21550 tsbond(neightet, auxsh); 21551 } 21552 // Let s remember f. 21553 auxsh.sh[0] = (shellface) encode(*front); 21554 } 21555 21557 // // 21558 // scoutfront() Scout a face in D. // 21559 // // 21560 // Search a 'front' f in D. If f is found, return TRUE and the face of D is // 21561 // returned in 'idfront'. Otherwise, return FALSE. // 21562 // // 21564 21565 bool tetgenmesh::scoutfront(triface* front, triface* idfront, list* newtetlist) 21566 { 21567 triface spintet; 21568 point pa, pb, pc; 21569 enum locateresult loc; 21570 enum finddirectionresult col; 21571 int hitbdry; 21572 int i; 21573 21574 // Let the front we're searching is abc. 21575 pa = org(*front); 21576 pb = dest(*front); 21577 // Get a tet in D for searching. 21578 *idfront = recenttet; 21579 // Make sure the tet is valid (it may be killed by flips). 21580 if (isdead(idfront)) { 21581 // The tet is dead. Search a live tet in D. !!! 21582 for (i = 0; i < newtetlist->len(); i++) { 21583 recenttet = * (triface *)(* newtetlist)[i]; 21584 if (!isdead(&recenttet)) break; 21585 } 21586 assert(i < newtetlist->len()); 21587 } 21588 21589 // Search a tet having vertex a. 21590 loc = preciselocate(pa, idfront, (long) newtetlist->len()); 21591 assert(loc == ONVERTEX); 21592 recenttet = *idfront; 21593 // Search a tet having edge ab. 21594 col = finddirection(idfront, pb, (long) newtetlist->len()); 21595 if (col == RIGHTCOLLINEAR) { 21596 // b is just the destination. 21597 } else if (col == LEFTCOLLINEAR) { 21598 enext2self(*idfront); 21599 esymself(*idfront); 21600 } else if (col == TOPCOLLINEAR) { 21601 fnextself(*idfront); 21602 enext2self(*idfront); 21603 esymself(*idfront); 21604 } 21605 21606 if (dest(*idfront) == pb) { 21607 // Search a tet having face abc 21608 pc = apex(*front); 21609 spintet = *idfront; 21610 hitbdry = 0; 21611 do { 21612 if (apex(spintet) == pc) { 21613 // Found abc. Insert an auxilary subface s at idfront. 21614 // insertauxsubface(front, &spintet); 21615 *idfront = spintet; 21616 return true; 21617 } 21618 if (!fnextself(spintet)) { 21619 hitbdry ++; 21620 if (hitbdry < 2) { 21621 esym(*idfront, spintet); 21622 if (!fnextself(spintet)) { 21623 hitbdry ++; 21624 } 21625 } 21626 } 21627 if (apex(spintet) == apex(*idfront)) break; 21628 } while (hitbdry < 2); 21629 } 21630 21631 // f is missing in D. 21632 if (b->verbose > 2) { 21633 printf(" Front (%d, %d, %d) is missing.\n", pointmark(pa), 21634 pointmark(pb), pointmark(apex(*front))); 21635 } 21636 return false; 21637 } 21638 21640 // // 21641 // gluefronts() Glue two fronts together. // 21642 // // 21643 // This is a support routine for identifyfront(). Two fronts f and f1 are // 21644 // found indentical. This is caused by the non-coplanarity of vertices of a // 21645 // facet. Hence f and f1 are a subface and a tet. They are not fronts of the // 21646 // cavity anymore. This routine glues f and f1 together. // 21647 // // 21649 21650 void tetgenmesh::gluefronts(triface* front, triface* front1) 21651 { 21652 face consh; 21653 21654 // Glue f and f1 together. There're four cases: 21655 // (1) both f and f1 are not fake; 21656 // (2) f is not fake, f1 is fake; 21657 // (3) f is fake and f1 is not fake; 21658 // (4) both f and f1 are fake. 21659 // Case (4) should be not possible. 21660 21661 // Is there a concrete subface c at f. 21662 tspivot(*front, consh); 21663 if (consh.sh != dummysh) { 21664 sesymself(consh); 21665 tsbond(*front1, consh); // Bond: f1 <--> c. 21666 sesymself(consh); 21667 } 21668 // Does f hold by a fake tet. 21669 if (oppo(*front) == (point) NULL) { 21670 // f is fake. Case (3) or (4). 21671 assert(oppo(*front1) != (point) NULL); // Eliminate (4). 21672 // Case (3). 21673 if (consh.sh != dummysh) { 21674 stdissolve(consh); // Dissolve: c -x-> f. 21675 } 21676 // Dealloc f. 21677 tetrahedrondealloc(front->tet); 21678 // f1 becomes a hull. let 'dummytet' bond to it. 21679 dummytet[0] = encode(*front1); 21680 } else { 21681 // Case (1) or (2). 21682 bond(*front, *front1); // Bond f1 <--> f. 21683 } 21684 // Is f a fake tet? 21685 if (!isdead(front)) { 21686 // No. Check for case (2). 21687 tspivot(*front1, consh); 21688 // Is f1 fake? 21689 if (oppo(*front1) == (point) NULL) { 21690 // Case (2) or (4) 21691 assert(oppo(*front) != (point) NULL); // Eliminate (4). 21692 // Case (2). 21693 if (consh.sh != dummysh) { 21694 stdissolve(consh); // Dissolve: c -x-> f1. 21695 sesymself(consh); // Bond: f <--> c. 21696 tsbond(*front, consh); 21697 } 21698 // Dissolve: f -x->f1. 21699 dissolve(*front); 21700 // Dealloc f1. 21701 tetrahedrondealloc(front1->tet); 21702 // f becomes a hull. let 'dummytet' bond to it. 21703 dummytet[0] = encode(*front); 21704 } else { 21705 // Case (1). 21706 if (consh.sh != dummysh) { 21707 sesymself(consh); 21708 tsbond(*front, consh); // Bond: f <--> c. 21709 } 21710 } 21711 } 21712 } 21713 21715 // // 21716 // identifyfronts() Identify cavity faces in D. // 21717 // // 21718 // 'frontlist' are fronts of C need indentfying. This routine searches each // 21719 // front f in D. Once f is found, an auxilary subface s is inserted in D at // 21720 // the face. If f is not found in D, remove it from frontlist and save it in // 21721 // 'misfrontlist'. // 21722 // // 21724 21725 bool tetgenmesh::identifyfronts(list* frontlist, list* misfrontlist, 21726 list* newtetlist) 21727 { 21728 triface front, front1, tfront; 21729 triface idfront, neightet; 21730 face auxsh; 21731 int len, i, j; 21732 21733 misfrontlist->clear(); 21734 // Set a new tet in D for searching. 21735 recenttet = * (triface *)(* newtetlist)[0]; 21736 21737 // Identify all fronts in D. 21738 for (i = 0; i < frontlist->len(); i++) { 21739 // Get a front f. 21740 front = * (triface *)( *frontlist)[i]; 21741 if (scoutfront(&front, &idfront, newtetlist)) { 21742 // Found f. Insert an aux subface s. 21743 assert((idfront.tet != dummytet) && !isdead(&idfront)); 21744 // Does s already exist? 21745 tspivot(idfront, auxsh); 21746 if (auxsh.sh != dummysh) { 21747 // There're two identical fronts, f (front) and f1 (s.sh[0])! 21748 decode((tetrahedron) auxsh.sh[0], front1); 21749 assert((front1.tet != dummytet) && !infected(front1)); 21750 // Detach s in D. 21751 tsdissolve(idfront); 21752 sym(idfront, neightet); 21753 if (neightet.tet != dummytet) { 21754 tsdissolve(neightet); 21755 } 21756 // s has fulfilled its duty. Can be deleted. 21757 shellfacedealloc(subfaces, auxsh.sh); 21758 // Remove f from frontlist. 21759 frontlist->del(i, 1); i--; 21760 // Remove f1 from frontlist. 21761 len = frontlist->len(); 21762 for (j = 0; j < frontlist->len(); j++) { 21763 tfront = * (triface *)(* frontlist)[j]; 21764 if ((tfront.tet == front1.tet) && (tfront.loc == front1.loc)) { 21765 // Found f1 in list. Check f1 != f. 21766 assert((tfront.tet != front.tet) || (tfront.loc != front.loc)); 21767 frontlist->del(j, 1); i--; 21768 break; 21769 } 21770 } 21771 assert((frontlist->len() + 1) == len); 21772 // Glue f and f1 together. 21773 gluefronts(&front, &front1); 21774 } else { 21775 // Insert an aux subface to protect f in D. 21776 insertauxsubface(&front, &idfront); 21777 } 21778 } else { 21779 // f is missing. 21780 frontlist->del(i, 1); i--; 21781 // Are there two identical fronts, f (front) and f1 (front1)? 21782 for (j = 0; j < misfrontlist->len(); j++) { 21783 front1 = * (triface *)(* misfrontlist)[j]; 21784 if (isfacehaspoint(&front1, org(front)) && 21785 isfacehaspoint(&front1, dest(front)) && 21786 isfacehaspoint(&front1, apex(front))) break; 21787 } 21788 if (j < misfrontlist->len()) { 21789 // Found an identical front f1. Remove f1 from the list. 21790 misfrontlist->del(j, 1); 21791 // Glue f and f1 together. 21792 gluefronts(&front, &front1); 21793 } else { 21794 // Add f into misfrontlist. 21795 misfrontlist->append(&front); 21796 } 21797 } 21798 } 21799 return misfrontlist->len() == 0; 21800 } 21801 21803 // // 21804 // detachauxsubfaces() Detach auxilary subfaces in D. // 21805 // // 21806 // This is a reverse routine of identifyfronts(). Some fronts are missing in // 21807 // D. C can not be easily tetrahedralized. It needs remediation (expansion, // 21808 // or constrained flips, or adding a Steiner point). This routine detaches // 21809 // the auxilary subfaces have been inserted in D and delete them. // 21810 // // 21812 21813 void tetgenmesh::detachauxsubfaces(list* newtetlist) 21814 { 21815 triface newtet, neightet; 21816 face auxsh; 21817 int i; 21818 21819 for (i = 0; i < newtetlist->len(); i++) { 21820 // Get a new tet t. 21821 newtet = * (triface *)(* newtetlist)[i]; 21822 // t may e dead due to flips. 21823 if (isdead(&newtet)) continue; 21824 assert(!infected(newtet)); 21825 // Check the four faces of t. 21826 for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) { 21827 tspivot(newtet, auxsh); 21828 if (auxsh.sh != dummysh) { 21829 // An auxilary subface s. 21830 assert(sorg(auxsh) == (point) NULL); 21831 tsdissolve(newtet); // t -x-> s. 21832 sym(newtet, neightet); 21833 if (neightet.tet != dummytet) { 21834 assert(!isdead(&neightet)); 21835 tsdissolve(neightet); // n -x-> s. 21836 } 21837 // Delete s. 21838 shellfacedealloc(subfaces, auxsh.sh); 21839 } 21840 } 21841 } 21842 } 21843 21845 // // 21846 // expandcavity() Expand the cavity by adding new fronts. // 21847 // // 21848 // This is the support routine for delaunizecavity(). Some fronts of C are // 21849 // missing in D since they're not strongly Delaunay. Such fronts are removed // 21850 // and the faces of the tets abutting to them are added. C is then expanded. // 21851 // Some removed faces may be subfaces, they're queued to recover later. D is // 21852 // expanded simultaneously with the new vertices of the new fronts. // 21853 // // 21855 21856 void tetgenmesh::expandcavity(list* frontlist, list* misfrontlist, 21857 list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque) 21858 { 21859 triface misfront, newfront, casingtet, crosstet; 21860 triface searchtet, faketet, bakhulltet; 21861 face checksh; 21862 point pd; 21863 enum insertsiteresult success; 21864 long bakhullsize; 21865 int bakchksub; 21866 int i, j, k; 21867 21868 if (b->verbose > 1) { 21869 printf(" Expand cavity (%d missing fronts).\n", misfrontlist->len()); 21870 } 21871 // Increase the number of expanded times. 21872 expcavcount++; 21873 // The incrflipdelaunay() is re-used. Backup global variables. 21874 decode(dummytet[0], bakhulltet); 21875 bakhullsize = hullsize; 21876 bakchksub = checksubfaces; 21877 checksubfaces = 0; 21878 b->verbose--; 21879 21880 // Choose a tet in D for searching. 21881 recenttet = * (triface *)(* newtetlist)[0]; 21882 assert((recenttet.tet != dummytet) && !isdead(&recenttet)); 21883 21884 // Loop through 'misfrontlist'. 21885 for (i = 0; i < misfrontlist->len(); i++) { 21886 // Get a missing front f. 21887 misfront = * (triface *)(* misfrontlist)[i]; 21888 // C will be expanded at f. 21889 if (b->verbose > 1) { 21890 printf(" Get misfront (%d, %d, %d).\n", pointmark(org(misfront)), 21891 pointmark(dest(misfront)), pointmark(apex(misfront))); 21892 } 21893 // Is f has a subface s? 21894 tspivot(misfront, checksh); 21895 if (checksh.sh != dummysh) { 21896 // A subface s is found. Check whether f is expandable at s. 21897 sym(misfront, crosstet); 21898 if (!infected(crosstet)) { 21899 // f is not expandable. In principle is should not happen. However, 21900 // it can happen when PBC is in use. 21901 assert(checkpbcs); 21902 // Skip expanding f. It will be processed later. 21903 continue; 21904 } 21905 // Temporarily remove s. Queue and recover it later. 21906 if (b->verbose > 1) { 21907 printf(" Queuing subface (%d, %d, %d).\n", 21908 pointmark(sorg(checksh)), pointmark(sdest(checksh)), 21909 pointmark(sapex(checksh))); 21910 } 21911 // Detach s from tets at its both sides. 21912 tsdissolve(misfront); 21913 tsdissolve(crosstet); 21914 // Detach tets at from s. 21915 stdissolve(checksh); 21916 sesymself(checksh); 21917 stdissolve(checksh); 21918 // Mark and queue it. 21919 sinfect(checksh); 21920 missingshqueue->push(&checksh); 21921 } 21922 // f may already be processed (become a cross tet of C). 21923 if (infected(misfront)) continue; 21924 // Get the point p = oppo(t), t is the tet holds f. 21925 pd = oppo(misfront); 21926 #ifdef SELF_CHECK 21927 // t must not be fake. 21928 assert(pd != (point) NULL); 21929 #endif 21930 // Insert p in D. p may not be inserted if it is one of the two cases: 21931 // (1) p is already a vertex of D; 21932 // (2) p lies outside the CH of D; 21933 searchtet = recenttet; 21934 // Make sure the tet is valid (it may be killed by flips). 21935 if (isdead(&searchtet)) { 21936 // The tet is dead. Get a live tet in D. !!! 21937 for (j = 0; j < newtetlist->len(); j++) { 21938 recenttet = * (triface *)(* newtetlist)[j]; 21939 if (!isdead(&recenttet)) break; 21940 } 21941 assert(j < newtetlist->len()); 21942 searchtet = recenttet; 21943 } 21944 success = insertsite(pd, &searchtet, false, flipque); 21945 if (success == OUTSIDEPOINT) { 21946 // case (2). Insert p onto CH of D. 21947 inserthullsite(pd, &searchtet, flipque); 21948 } 21949 if (success != DUPLICATEPOINT) { 21950 // p is inserted. Recover Delaunness of D by flips. 21951 flip(flipque, NULL); 21952 } 21953 // Expand C by adding new fronts. The three faces of t which have p as a 21954 // vertex become new fronts. However, if a new front is coincident with 21955 // an old front of C, it is not added and the old front is removed. 21956 adjustedgering(misfront, CCW); 21957 for (j = 0; j < 3; j++) { 21958 // Notice: Below I mis-used the names. 'newfront' is not exactly a new 21959 // front, instead the 'casingtet' should be called new front. 21960 // Get a new front f_n. 21961 fnext(misfront, newfront); 21962 // Get the neighbor tet n at f_n. 21963 sym(newfront, casingtet); 21964 // Is n a cross tet? 21965 if (!infected(casingtet)) { 21966 // f_n becomes a new front of C. 21967 // Does n exist? 21968 if (casingtet.tet == dummytet) { 21969 // Create a fake tet n' to hold f_n temporarily. 21970 maketetrahedron(&faketet); 21971 // Be sure that the vertices of fake tet are CCW oriented. 21972 adjustedgering(newfront, CW); // CW edge ring. 21973 setorg(faketet, org(newfront)); 21974 setdest(faketet, dest(newfront)); 21975 setapex(faketet, apex(newfront)); 21976 setoppo(faketet, (point) NULL); // Indicates it is 'fake'. 21977 // Bond n' to a subface if it exists. 21978 tspivot(newfront, checksh); 21979 if (checksh.sh != dummysh) { 21980 sesymself(checksh); 21981 tsbond(faketet, checksh); 21982 } 21983 // Bond f_n <--> n'. So we're able to find n' and remove it. 21984 bond(faketet, newfront); 21985 frontlist->append(&faketet); 21986 } else { 21987 // Add n to frontlist. 21988 frontlist->append(&casingtet); 21989 } 21990 } else { 21991 // f_n is coincident with an existing front f' of C. f' is no longer 21992 // a front, remove it from frontlist. Use the inverse order to 21993 // search f' (most likely, a newly added front may be f'). 21994 for (k = frontlist->len() - 1; k >= 0; k--) { 21995 searchtet = * (triface *)(* frontlist)[k]; 21996 if ((newfront.tet == searchtet.tet) && 21997 (newfront.loc == searchtet.loc)) { 21998 frontlist->del(k, 0); 21999 break; 22000 } 22001 } 22002 // Is f_n a subface? 22003 tspivot(newfront, checksh); 22004 if (checksh.sh != dummysh) { 22005 // Temporarily remove checksh. Make it missing. recover it later. 22006 if (b->verbose > 2) { 22007 printf(" Queuing subface (%d, %d, %d).\n", 22008 pointmark(sorg(checksh)), pointmark(sdest(checksh)), 22009 pointmark(sapex(checksh))); 22010 } 22011 tsdissolve(newfront); 22012 tsdissolve(casingtet); 22013 // Detach tets at the both sides of checksh. 22014 stdissolve(checksh); 22015 sesymself(checksh); 22016 stdissolve(checksh); 22017 sinfect(checksh); 22018 missingshqueue->push(&checksh); 22019 } 22020 } 22021 enextself(misfront); 22022 } 22023 // C has been expanded at f. t becomes a cross tet. 22024 if (!infected(misfront)) { 22025 // t will be deleted, queue it. 22026 infect(misfront); 22027 crosstetlist->append(&misfront); 22028 } 22029 } 22030 22031 // Loop through misfrontlist, remove infected misfronts. 22032 for (i = 0; i < misfrontlist->len(); i++) { 22033 misfront = * (triface *)(* misfrontlist)[i]; 22034 if (infected(misfront)) { 22035 // Remove f, keep original list order. 22036 misfrontlist->del(i, 1); 22037 i--; 22038 } 22039 } 22040 22041 // Are we done? 22042 if (misfrontlist->len() > 0) { 22043 // No. There are unexpandable fronts. 22044 // expandcavity_sos(misfrontlist); 22045 assert(0); // Not done yet. 22046 } 22047 22048 // D has been updated (by added new tets or dead tets) (due to flips). 22049 retrievenewtets(newtetlist); 22050 22051 // Restore global variables. 22052 dummytet[0] = encode(bakhulltet); 22053 hullsize = bakhullsize; 22054 checksubfaces = bakchksub; 22055 b->verbose++; 22056 } 22057 22059 // // 22060 // carvecavity() Remove redundant (outside) tetrahedra from D. // 22061 // // 22062 // The fronts of C have been identified in D. Hence C can be tetrahedralized // 22063 // by removing the tets outside C. The CDT is then updated by filling C with // 22064 // the remaining tets (inside C) of D. // 22065 // // 22066 // Each front is protected by an auxilary subface s in D. s has a pointer to // 22067 // f (s.sh[0]). f can be used to classified the in- and out- tets of C (the // 22068 // CW orientation of f faces to the inside of C). The classified out-tets of // 22069 // C are marked (infected) for removing. // 22070 // // 22071 // Notice that the out-tets may not only the tets on the CH of C, but also // 22072 // tets completely inside D, eg., there is a "hole" in D. Such tets must be // 22073 // marked during classification. The hole tets are poped up and removed too. // 22074 // // 22076 22077 void tetgenmesh::carvecavity(list* newtetlist, list* outtetlist, 22078 queue* flipque) 22079 { 22080 triface newtet, neightet, front, outtet; 22081 face auxsh, consh; 22082 point pointptr; 22083 REAL ori; 22084 int i; 22085 22086 // Clear work list. 22087 outtetlist->clear(); 22088 22089 // Classify in- and out- tets in D. Mark and queue classified out-tets. 22090 for (i = 0; i < newtetlist->len(); i++) { 22091 // Get a new tet t. 22092 newtet = * (triface *)(* newtetlist)[i]; 22093 assert(!isdead(&newtet)); 22094 // Look for aux subfaces attached at t. 22095 for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) { 22096 tspivot(newtet, auxsh); 22097 if (auxsh.sh != dummysh) { 22098 // Has this side a neighbor n? 22099 sym(newtet, neightet); 22100 if (neightet.tet != dummytet) { 22101 // Classify t and n (one is "in" and another is "out"). 22102 // Get the front f. 22103 decode((tetrahedron) auxsh.sh[0], front); 22104 // Let f face to the inside of C. 22105 adjustedgering(front, CW); 22106 ori = orient3d(org(front), dest(front), apex(front), oppo(newtet)); 22107 assert(ori != 0.0); 22108 if (ori < 0.0) { 22109 // t is in-tet. n is out-tet. 22110 outtet = neightet; 22111 } else { 22112 // n is in-tet. t is out-tet. 22113 outtet = newtet; 22114 } 22115 // Add the out-tet into list. 22116 if (!infected(outtet)) { 22117 infect(outtet); 22118 outtetlist->append(&outtet); 22119 } 22120 } 22121 } 22122 } 22123 } 22124 22125 // Find and mark all out-tets. 22126 for (i = 0; i < outtetlist->len(); i++) { 22127 outtet = * (triface *)(* outtetlist)[i]; 22128 for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) { 22129 sym(outtet, neightet); 22130 // Does the neighbor exist and unmarked? 22131 if ((neightet.tet != dummytet) && !infected(neightet)) { 22132 // Is it protected by an aux subface? 22133 tspivot(outtet, auxsh); 22134 if (auxsh.sh == dummysh) { 22135 // It's an out-tet. 22136 infect(neightet); 22137 outtetlist->append(&neightet); 22138 } 22139 } 22140 } 22141 } 22142 22143 // Remove the out- (and hole) tets. 22144 for (i = 0; i < outtetlist->len(); i++) { 22145 // Get an out-tet t. 22146 outtet = * (triface *)(* outtetlist)[i]; 22147 // Detach t from the in-tets. 22148 for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) { 22149 // Is there an aux subface s? 22150 tspivot(outtet, auxsh); 22151 if (auxsh.sh != dummysh) { 22152 // Get the neighbor n. 22153 sym(outtet, neightet); 22154 assert(!infected(neightet)); // t must be in-tet. 22155 // Detach n -x-> t. 22156 dissolve(neightet); 22157 } 22158 } 22159 // Dealloc the tet. 22160 tetrahedrondealloc(outtet.tet); 22161 } 22162 22163 // Connect the in-tets of C to fronts. Remove aux subfaces and fake tets. 22164 for (i = 0; i < newtetlist->len(); i++) { 22165 // Get a new tet t. 22166 newtet = * (triface *)(* newtetlist)[i]; 22167 // t may be an out-tet and has got deleted. 22168 if (isdead(&newtet)) continue; 22169 // t is an in-tet. Look for aux subfaces attached at t. 22170 for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) { 22171 // Is there an aux subface s? 22172 tspivot(newtet, auxsh); 22173 if (auxsh.sh != dummysh) { 22174 // Get the front f. 22175 decode((tetrahedron) auxsh.sh[0], front); 22176 assert((front.tet != dummytet) && !infected(front)); 22177 // s has fulfilled its duty. Can be deleted. 22178 tsdissolve(newtet); // dissolve: t -x-> s. 22179 // Delete s. 22180 shellfacedealloc(subfaces, auxsh.sh); 22181 // Connect the newtet t and front f. 22182 // Is there a concrete subface c at f. 22183 tspivot(front, consh); 22184 if (consh.sh != dummysh) { 22185 sesymself(consh); 22186 // Bond: t <--> c. 22187 tsbond(newtet, consh); 22188 } 22189 // Does f hold by a fake tet. 22190 if (oppo(front) == (point) NULL) { 22191 // f is fake. 22192 if (consh.sh != dummysh) { 22193 sesymself(consh); 22194 // Dissolve: c -x-> f. 22195 stdissolve(consh); 22196 } 22197 // Dealloc f. 22198 tetrahedrondealloc(front.tet); 22199 // f becomes a hull. let 'dummytet' bond to it. 22200 dummytet[0] = encode(newtet); 22201 } else { 22202 // Bond t <--> f. 22203 bond(newtet, front); 22204 } 22205 // t may be non-locally Delaunay and flipable. 22206 if (flipque != (queue *) NULL) { 22207 enqueueflipface(newtet, flipque); 22208 } 22209 } 22210 } 22211 // Let the corners of t2 point to it for fast searching. 22212 pointptr = org(newtet); 22213 setpoint2tet(pointptr, encode(newtet)); 22214 pointptr = dest(newtet); 22215 setpoint2tet(pointptr, encode(newtet)); 22216 pointptr = apex(newtet); 22217 setpoint2tet(pointptr, encode(newtet)); 22218 pointptr = oppo(newtet); 22219 setpoint2tet(pointptr, encode(newtet)); 22220 } 22221 // The cavity has been re-tetrahedralized. 22222 } 22223 22225 // // 22226 // delaunizecavity() Tetrahedralize a cavity by Delaunay tetrahedra. // 22227 // // 22228 // The cavity C is bounded by a set of triangles in 'floorlist' (a list of // 22229 // coplanar subfaces) and 'ceillist' (a list of tetrahedral faces lie above // 22230 // the subfaces). 'floorptlist' and 'ceilptlist' are the vertices of C. // 22231 // // 22233 22234 void tetgenmesh::delaunizecavity(list* floorlist, list* ceillist, 22235 list* ceilptlist, list* floorptlist, list* frontlist, list* misfrontlist, 22236 list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque) 22237 { 22238 int vertnum; 22239 22240 vertnum = floorptlist->len(); 22241 vertnum += (ceilptlist != (list *) NULL ? ceilptlist->len() : 0); 22242 if (b->verbose > 1) { 22243 printf(" Delaunizing cavity (%d floors, %d ceilings, %d vertices).\n", 22244 floorlist->len(), ceillist->len(), vertnum); 22245 } 22246 // Save the size of the largest cavity. 22247 if ((floorlist->len() + ceillist->len()) > maxcavfaces) { 22248 maxcavfaces = floorlist->len() + ceillist->len(); 22249 } 22250 if (vertnum > maxcavverts) { 22251 maxcavverts = vertnum; 22252 } 22253 22254 // Clear these lists. 22255 frontlist->clear(); 22256 misfrontlist->clear(); 22257 newtetlist->clear(); 22258 22259 // Initialize the cavity C. 22260 initializecavity(floorlist, ceillist, frontlist); 22261 // Form the D of the vertices of C. 22262 delaunizecavvertices(NULL, floorptlist, ceilptlist, newtetlist, flipque); 22263 // Identify faces of C in D. 22264 while (!identifyfronts(frontlist, misfrontlist, newtetlist)) { 22265 // Remove protecting subfaces, keep new tets. 22266 detachauxsubfaces(newtetlist); 22267 // Expand C and updateing D. 22268 expandcavity(frontlist, misfrontlist, newtetlist, crosstetlist, 22269 missingshqueue, flipque); 22270 } 22271 // All fronts have identified in D. Get the shape of C by removing out 22272 // tets of C. 'misfrontlist' is reused for removing out tets. 22273 carvecavity(newtetlist, misfrontlist, NULL); 22274 } 22275 22277 // // 22278 // formmissingregion() Form the missing region. // 22279 // // 22280 // 'missingsh' is a missing subface. Start from it we can form the missing // 22281 // region R (a set of connected missing subfaces). Because all missing sub- // 22282 // faces have been marked (infected) before. R can be formed by checking the // 22283 // neighbors of 'missingsh', and the neighbors of the neighbors, and so on. // 22284 // Stop checking further at either a segment or an unmarked subface. // 22285 // // 22286 // 'missingshlist' returns R. The edge ring of subfaces of R are oriented in // 22287 // the same direction. 'equatptlist' returns the vertices of R, each vertex // 22288 // is marked with '1' (in 'worklist'). // 22289 // // 22291 22292 void tetgenmesh::formmissingregion(face* missingsh, list* missingshlist, 22293 list* equatptlist, int* worklist) 22294 { 22295 face neighsh, worksh, workseg; 22296 point workpt[3]; 22297 int idx, i, j; 22298 22299 // Add 'missingsh' into 'missingshlist'. 22300 missingshlist->append(missingsh); 22301 // Save and mark its three vertices. 22302 workpt[0] = sorg(*missingsh); 22303 workpt[1] = sdest(*missingsh); 22304 workpt[2] = sapex(*missingsh); 22305 for (i = 0; i < 3; i++) { 22306 idx = pointmark(workpt[i]) - in->firstnumber; 22307 worklist[idx] = 1; 22308 equatptlist->append(&workpt[i]); 22309 } 22310 // Temporarily uninfect it (avoid to save it again). 22311 suninfect(*missingsh); 22312 22313 // Find the other missing subfaces. 22314 for (i = 0; i < missingshlist->len(); i++) { 22315 // Get a missing subface. 22316 worksh = * (face *)(* missingshlist)[i]; 22317 // Check three neighbors of this face. 22318 for (j = 0; j < 3; j++) { 22319 sspivot(worksh, workseg); 22320 if (workseg.sh == dummysh) { 22321 spivot(worksh, neighsh); 22322 if (sinfected(neighsh)) { 22323 // Find a missing subface, adjust the face orientation. 22324 if (sorg(neighsh) != sdest(worksh)) { 22325 sesymself(neighsh); 22326 } 22327 if (b->verbose > 2) { 22328 printf(" Add missing subface (%d, %d, %d).\n", 22329 pointmark(sorg(neighsh)), pointmark(sdest(neighsh)), 22330 pointmark(sapex(neighsh))); 22331 } 22332 missingshlist->append(&neighsh); 22333 // Save and mark its apex. 22334 workpt[0] = sapex(neighsh); 22335 idx = pointmark(workpt[0]) - in->firstnumber; 22336 // Has workpt[0] been added? 22337 if (worklist[idx] == 0) { 22338 worklist[idx] = 1; 22339 equatptlist->append(&workpt[0]); 22340 } 22341 // Temporarily uninfect it (avoid to save it again). 22342 suninfect(neighsh); 22343 } 22344 } 22345 senextself(worksh); 22346 } 22347 } 22348 22349 // R has been formed. Infect missing subfaces again. 22350 for (i = 0; i < missingshlist->len(); i++) { 22351 worksh = * (face *)(* missingshlist)[i]; 22352 sinfect(worksh); 22353 } 22354 } 22355 22357 // // 22358 // rearrangesubfaces() Rearrange the set of subfaces of a missing region // 22359 // so that they conform to the faces of DT. // 22360 // // 22361 // The missing region formed by subfaces of 'missingshlist' contains a set // 22362 // of degenerate vertices, hence the set of subfaces don't match the set of // 22363 // faces in DT. Instead of forcing them to present in DT, we re-arrange the // 22364 // connection of them so that the new subfaces conform to the faces of DT. // 22365 // 'boundedgelist' is a set of boundary edges of the region, these edges(may // 22366 // be subsegments) must exist in DT. // 22367 // // 22368 // On completion, we have created and inserted a set of new subfaces which // 22369 // conform to faces of DT. The set of old subfaces in 'missingshlist' are // 22370 // deleted. The region vertices in 'equatptlist' are unmarked. // 22371 // // 22373 22374 void tetgenmesh::rearrangesubfaces(list* missingshlist, list* boundedgelist, 22375 list* equatptlist, int* worklist) 22376 { 22377 link *boundedgelink; 22378 link *newshlink; 22379 triface starttet, spintet, neightet, worktet; 22380 face shloop, newsh, neighsh, spinsh, worksh; 22381 face workseg, casingin, casingout; 22382 point torg, tdest, workpt; 22383 point spt1, spt2, spt3; 22384 enum finddirectionresult collinear; 22385 enum shestype shtype; 22386 REAL area; 22387 bool matchflag, finishflag; 22388 int shmark, pbcgp, idx, hitbdry; 22389 int i, j; 22390 22391 // Initialize the boundary edge link. 22392 boundedgelink = new link(sizeof(face), NULL, 256); 22393 // Initialize the new subface link. 22394 newshlink = new link(sizeof(face), NULL, 256); 22395 // Remember the type (skinny or not) of replaced subfaces. They should 22396 // all have the same type since there is no segment inside the region. 22397 worksh = * (face *)(* missingshlist)[0]; 22398 shtype = shelltype(worksh); 22399 // The following loop is only for checking purpose. 22400 for (i = 1; i < missingshlist->len(); i++) { 22401 worksh = * (face *)(* missingshlist)[i]; 22402 assert(shelltype(worksh) == shtype); 22403 } 22404 // To avoid compilation warnings. 22405 shmark = pbcgp = 0; 22406 area = 0.0; 22407 22408 // Create an initial boundary link. 22409 for (i = 0; i < boundedgelist->len(); i++) { 22410 shloop = * (face *)(* boundedgelist)[i]; 22411 if (i == 0) { 22412 // 'shmark' will be set to all new created subfaces. 22413 shmark = shellmark(shloop); 22414 if (b->quality && varconstraint) { 22415 // area will be copied to all new created subfaces. 22416 area = areabound(shloop); 22417 } 22418 if (checkpbcs) { 22419 // pbcgp will be copied to all new created subfaces. 22420 pbcgp = shellpbcgroup(shloop); 22421 } 22422 // Get the abovepoint of this facet. 22423 abovepoint = facetabovepointarray[shellmark(shloop)]; 22424 if (abovepoint == (point) NULL) { 22425 getfacetabovepoint(&shloop); 22426 } 22427 } 22428 sspivot(shloop, workseg); 22429 if (workseg.sh == dummysh) { 22430 // This edge is an interior edge. 22431 spivot(shloop, neighsh); 22432 boundedgelink->add(&neighsh); 22433 } else { 22434 // This side has a segment, the edge exists. 22435 boundedgelink->add(&shloop); 22436 } 22437 } 22438 22439 // Each edge ab of boundedgelink will be finished by finding a vertex c 22440 // which is a vertex of the missing region, such that: 22441 // (1) abc is inside the missing region, i.e., abc intersects at least 22442 // one of missing subfaces (saved in missingshlist); 22443 // (2) abc is not intersect with any previously created new subfaces 22444 // in the missing region (saved in newshlink). 22445 // After abc is created, it will be inserted into both the surface mesh 22446 // and the DT. The boundedgelink will be updated, ab is removed, bc and 22447 // ca will be added if they are open. 22448 22449 while (boundedgelink->len() > 0) { 22450 // Remove an edge (ab) from the link. 22451 shloop = * (face *) boundedgelink->del(1); 22452 // 'workseg' indicates it is a segment or not. 22453 sspivot(shloop, workseg); 22454 torg = sorg(shloop); // torg = a; 22455 tdest = sdest(shloop); // tdest = b; 22456 // Find a tetrahedron containing ab. 22457 getsearchtet(torg, tdest, &starttet, &workpt); 22458 collinear = finddirection(&starttet, workpt, tetrahedrons->items); 22459 if (collinear == LEFTCOLLINEAR) { 22460 enext2self(starttet); 22461 esymself(starttet); 22462 } else if (collinear == TOPCOLLINEAR) { 22463 fnextself(starttet); 22464 enext2self(starttet); 22465 esymself(starttet); 22466 } 22467 assert(dest(starttet) == workpt); 22468 // Checking faces around ab until a valid face is found. 22469 matchflag = false; 22470 spintet = starttet; 22471 hitbdry = 0; 22472 do { 22473 workpt = apex(spintet); 22474 idx = pointmark(workpt) - in->firstnumber; 22475 if (worklist[idx] == 1) { 22476 // (trog, tdest, workpt) is on the facet. Check if it satisfies (1). 22477 finishflag = false; 22478 for (i = 0; i < missingshlist->len(); i++) { 22479 worksh = * (face *)(* missingshlist)[i]; 22480 spt1 = sorg(worksh); 22481 spt2 = sdest(worksh); 22482 spt3 = sapex(worksh); 22483 // Does bc intersect the face? 22484 if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint) 22485 == INTERSECT) { 22486 finishflag = true; break; 22487 } 22488 // Does ca intersect the face? 22489 if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint) 22490 == INTERSECT) { 22491 finishflag = true; break; 22492 } 22493 // Does c inside the face? 22494 if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint) 22495 == INTERSECT) { 22496 finishflag = true; break; 22497 } 22498 } 22499 if (finishflag) { 22500 // Satisfying (1). Check if it satisfies (2). 22501 matchflag = true; 22502 for (i = 0; i < newshlink->len() && matchflag; i++) { 22503 worksh = * (face *) newshlink->getnitem(i + 1); 22504 spt1 = sorg(worksh); 22505 spt2 = sdest(worksh); 22506 spt3 = sapex(worksh); 22507 // Does bc intersect the face? 22508 if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint) 22509 == INTERSECT) { 22510 matchflag = false; break; 22511 } 22512 // Does ca intersect the face? 22513 if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint) 22514 == INTERSECT) { 22515 matchflag = false; break; 22516 } 22517 // Does c inside the face? 22518 if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint) 22519 == INTERSECT) { 22520 matchflag = false; break; 22521 } 22522 } 22523 } 22524 if (matchflag == true) { 22525 // Satisfying both (1) and (2). Find abc. 22526 break; 22527 } 22528 } 22529 if (!fnextself(spintet)) { 22530 hitbdry ++; 22531 if (hitbdry < 2) { 22532 esym(starttet, spintet); 22533 if (!fnextself(spintet)) { 22534 hitbdry ++; 22535 } 22536 } 22537 } 22538 } while (hitbdry < 2 && apex(spintet) != apex(starttet)); 22539 assert(matchflag == true); 22540 tspivot(spintet, neighsh); 22541 if (neighsh.sh != dummysh) { 22542 printf("Error: Invalid PLC.\n"); 22543 printf(" Facet #%d and facet #%d overlap each other.\n", 22544 shellmark(neighsh), shellmark(shloop)); 22545 printf(" It might be caused by a facet is defined more than once.\n"); 22546 printf(" Hint: Use -d switch to find all overlapping facets.\n"); 22547 exit(1); 22548 } 22549 // The side of 'spintet' is at which a new subface will be attached. 22550 adjustedgering(spintet, CCW); 22551 // Create the new subface. 22552 makeshellface(subfaces, &newsh); 22553 setsorg(newsh, org(spintet)); 22554 setsdest(newsh, dest(spintet)); 22555 setsapex(newsh, apex(spintet)); 22556 if (b->quality && varconstraint) { 22557 setareabound(newsh, area); 22558 } 22559 if (checkpbcs) { 22560 setshellpbcgroup(newsh, pbcgp); 22561 } 22562 setshellmark(newsh, shmark); 22563 setshelltype(newsh, shtype); // It may be a skinny subface. 22564 // Add newsh into newshlink for intersecting checking. 22565 newshlink->add(&newsh); 22566 // Insert it into the current mesh. 22567 tsbond(spintet, newsh); 22568 sym(spintet, neightet); 22569 if (neightet.tet != dummytet) { 22570 sesym(newsh, neighsh); 22571 tsbond(neightet, neighsh); 22572 } 22573 // Insert it into the surface mesh. 22574 sspivot(shloop, workseg); 22575 if (workseg.sh == dummysh) { 22576 sbond(shloop, newsh); 22577 } else { 22578 // There is a subsegment, 'shloop' is the subface which is going to 22579 // die. Insert the 'newsh' at the place of 'shloop' into its face 22580 // link, so as to dettach 'shloop'. The original connection is: 22581 // -> casingin -> shloop -> casingout ->, it will be changed with: 22582 // -> casingin -> newsh -> casingout ->. Pay attention to the 22583 // case when this subsegment is dangling in the mesh, i.e., 'shloop' 22584 // is bonded to itself. 22585 spivot(shloop, casingout); 22586 if (shloop.sh != casingout.sh) { 22587 // 'shloop' is not bonded to itself. 22588 spinsh = casingout; 22589 do { 22590 casingin = spinsh; 22591 spivotself(spinsh); 22592 } while (sapex(spinsh) != sapex(shloop)); 22593 assert(casingin.sh != shloop.sh); 22594 // Bond casingin -> newsh -> casingout. 22595 sbond1(casingin, newsh); 22596 sbond1(newsh, casingout); 22597 } else { 22598 // Bond newsh -> newsh. 22599 sbond(newsh, newsh); 22600 } 22601 // Bond the segment. 22602 ssbond(newsh, workseg); 22603 } 22604 // Check other two sides of this new subface. If a side is not bonded 22605 // to any edge in the link, it will be added to the link. 22606 for (i = 0; i < 2; i++) { 22607 if (i == 0) { 22608 senext(newsh, worksh); 22609 } else { 22610 senext2(newsh, worksh); 22611 } 22612 torg = sorg(worksh); 22613 tdest = sdest(worksh); 22614 finishflag = false; 22615 for (j = 0; j < boundedgelink->len() && !finishflag; j++) { 22616 neighsh = * (face *) boundedgelink->getnitem(j + 1); 22617 if ((sorg(neighsh) == torg && sdest(neighsh) == tdest) || 22618 (sorg(neighsh) == tdest && sdest(neighsh) == torg)) { 22619 // Find a boundary edge. Bond them and exit the loop. 22620 sspivot(neighsh, workseg); 22621 if (workseg.sh == dummysh) { 22622 sbond(neighsh, worksh); 22623 } else { 22624 // There is a subsegment, 'neighsh' is the subface which is 22625 // going to die. Do the same as above for 'worksh'. 22626 spivot(neighsh, casingout); 22627 if (neighsh.sh != casingout.sh) { 22628 // 'neighsh' is not bonded to itself. 22629 spinsh = casingout; 22630 do { 22631 casingin = spinsh; 22632 spivotself(spinsh); 22633 } while (sapex(spinsh) != sapex(neighsh)); 22634 assert(casingin.sh != neighsh.sh); 22635 // Bond casingin -> worksh -> casingout. 22636 sbond1(casingin, worksh); 22637 sbond1(worksh, casingout); 22638 } else { 22639 // Bond worksh -> worksh. 22640 sbond(worksh, worksh); 22641 } 22642 // Bond the segment. 22643 ssbond(worksh, workseg); 22644 } 22645 // Remove this boundary edge from the link. 22646 boundedgelink->del(j + 1); 22647 finishflag = true; 22648 } 22649 } 22650 if (!finishflag) { 22651 // It's a new boundary edge, add it to link. 22652 boundedgelink->add(&worksh); 22653 } 22654 } 22655 } 22656 22657 // Deallocate the set of old missing subfaces. 22658 for (i = 0; i < missingshlist->len(); i++) { 22659 worksh = * (face *)(* missingshlist)[i]; 22660 shellfacedealloc(subfaces, worksh.sh); 22661 } 22662 // Unmark region vertices in 'worklist'. 22663 for (i = 0; i < equatptlist->len(); i++) { 22664 workpt = * (point *)(* equatptlist)[i]; 22665 idx = pointmark(workpt) - in->firstnumber; 22666 worklist[idx] = 0; 22667 } 22668 22669 delete boundedgelink; 22670 delete newshlink; 22671 } 22672 22674 // // 22675 // scoutcrossingedge() Search an edge crossing the missing region. // 22676 // // 22677 // 'missingshlist' forms the missing region R. This routine searches for an // 22678 // edge crossing R. It first forms a 'boundedgelist' consisting of the // 22679 // boundary edges of R. Such edges are existing in CDT. A crossing edge is // 22680 // found by rotating faces around one of the boundary edges. It is possible // 22681 // there is no edge crosses R (e.g. R has a degenerate point set). // 22682 // // 22683 // If find a croosing edge, return TRUE, 'crossedgelist' contains this edge. // 22684 // Otherwise, return FALSE. // 22685 // // 22687 22688 bool tetgenmesh::scoutcrossingedge(list* missingshlist, list* boundedgelist, 22689 list* crossedgelist, int* worklist) 22690 { 22691 triface starttet, spintet, worktet; 22692 face startsh, neighsh, worksh, workseg; 22693 point torg, tdest, tapex; 22694 point workpt[3], pa, pb, pc; 22695 enum finddirectionresult collinear; 22696 REAL ori1, ori2; 22697 bool crossflag; 22698 int hitbdry; 22699 int i, j, k; 22700 22701 // Form the 'boundedgelist'. Loop through 'missingshlist', check each 22702 // edge of these subfaces. If an edge is a segment or the neighbor 22703 // subface is uninfected, add it to 'boundedgelist'. 22704 for (i = 0; i < missingshlist->len(); i++) { 22705 worksh = * (face *)(* missingshlist)[i]; 22706 for (j = 0; j < 3; j++) { 22707 sspivot(worksh, workseg); 22708 if (workseg.sh == dummysh) { 22709 spivot(worksh, neighsh); 22710 if (!sinfected(neighsh)) { 22711 boundedgelist->append(&worksh); 22712 } 22713 } else { 22714 boundedgelist->append(&worksh); 22715 } 22716 senextself(worksh); 22717 } 22718 } 22719 22720 crossflag = false; 22721 // Find a crossing edge. It is possible there is no such edge. We need to 22722 // loop through all edges of 'boundedgelist' for sure we don't miss any. 22723 for (i = 0; i < boundedgelist->len() && !crossflag; i++) { 22724 startsh = * (face *)(* boundedgelist)[i]; 22725 // 'startsh' (abc) holds an existing edge of the DT, find it. 22726 torg = sorg(startsh); 22727 tdest = sdest(startsh); 22728 tapex = sapex(startsh); 22729 getsearchtet(torg, tdest, &starttet, &workpt[0]); 22730 collinear = finddirection(&starttet, workpt[0], tetrahedrons->items); 22731 if (collinear == LEFTCOLLINEAR) { 22732 enext2self(starttet); 22733 esymself(starttet); 22734 } else if (collinear == TOPCOLLINEAR) { 22735 fnextself(starttet); 22736 enext2self(starttet); 22737 esymself(starttet); 22738 } 22739 #ifdef SELF_CHECK 22740 assert(dest(starttet) == workpt[0]); 22741 #endif 22742 // Now starttet holds edge ab. Find is edge de crossing R. 22743 spintet = starttet; 22744 hitbdry = 0; 22745 do { 22746 if (fnextself(spintet)) { 22747 // splittet = abde. Check if de crosses abc. 22748 workpt[1] = apex(spintet); // workpt[1] = d. 22749 workpt[2] = oppo(spintet); // workpt[2] = e. 22750 j = pointmark(workpt[1]) - in->firstnumber; 22751 k = pointmark(workpt[2]) - in->firstnumber; 22752 if (worklist[j] == 1) { 22753 ori1 = 0.0; // d is a vertex of the missing region. 22754 } else { 22755 // Get the orientation of d wrt. abc. 22756 ori1 = orient3d(torg, tdest, tapex, workpt[1]); 22757 } 22758 if (worklist[k] == 1) { 22759 ori2 = 0.0; // e is a vertex of the missing region. 22760 } else { 22761 // Get the orientation of e wrt. abc. 22762 ori2 = orient3d(torg, tdest, tapex, workpt[2]); 22763 } 22764 // Only do check if d and e locate on different sides of abc. 22765 if (ori1 * ori2 < 0.0) { 22766 // Check if de crosses any subface of R. 22767 for (j = 0; j < missingshlist->len(); j++) { 22768 worksh = * (face *)(* missingshlist)[j]; 22769 pa = sorg(worksh); 22770 pb = sdest(worksh); 22771 pc = sapex(worksh); 22772 crossflag = (tri_tri_inter(pa, pb, pc, workpt[0], workpt[1], 22773 workpt[2]) == INTERSECT); 22774 if (crossflag) { 22775 // Find a crossing edge. We're done. 22776 worktet = spintet; 22777 adjustedgering(worktet, CCW); 22778 enextfnextself(worktet); 22779 enextself(worktet); 22780 // Add this edge (worktet) into 'crossedgelist'. 22781 crossedgelist->append(&worktet); 22782 break; 22783 } 22784 } 22785 if (crossflag) break; 22786 } 22787 if (apex(spintet) == apex(starttet)) break; 22788 } else { 22789 hitbdry++; 22790 // It is only possible to hit boundary once. 22791 if (hitbdry < 2) { 22792 esym(starttet, spintet); 22793 } 22794 } 22795 } while (hitbdry < 2); 22796 } 22797 22798 return crossflag; 22799 } 22800 22802 // // 22803 // formcavity() Form the cavity for recovering the missing region. // 22804 // // 22805 // The cavity C is bounded by faces of current CDT. All tetrahedra inside C // 22806 // will be removed, intead a set of constrained Delaunay tetrahedra will be // 22807 // filled in and the missing region are recovered. // 22808 // // 22809 // 'missingshlist' contains a set of subfaces forming the missing region R. // 22810 // C is formed by first finding all the tetrahedra in CDT that intersect the // 22811 // relative interior of R; then deleting them from the CDT, this will form C // 22812 // inside the CDT. At the beginning, 'crossedgelist' contains an edge which // 22813 // is crossing R. All tets containing this edge must cross R. Start from it, // 22814 // other crossing edges can be found incrementally. The discovered crossing // 22815 // tets are saved in 'crosstetlist'. // 22816 // // 22817 // Notice that not all tets in 'crosstetlist' are crossing R. The discovered // 22818 // tets are connected each other. However, there may be other tets crossing // 22819 // R but disjoint with the found tets. Due to this fact we need to check the // 22820 // 'missingshlist' once more. Only recover those subfaces which are crossed // 22821 // by the set of discovered tets, i.e., R may be shrinked to conform the set // 22822 // of discovered tets. The extra subfaces of R will be recovered later. // 22823 // // 22824 // Notice that some previous recovered subfaces may completely included in C.// 22825 // This can happen when R is very big and these subfaces lie above R and so // 22826 // close to it. Such subfaces have to be queued (and sinfected()) to recover // 22827 // them later. Otherwise, we lost the connection to these subfaces forever. // 22828 // // 22830 22831 void tetgenmesh::formcavity(list* missingshlist, list* crossedgelist, 22832 list* equatptlist, list* crossshlist, list* crosstetlist, 22833 list* belowfacelist, list* abovefacelist, list* horizptlist, 22834 list* belowptlist, list* aboveptlist, queue* missingshqueue, int* worklist) 22835 { 22836 triface starttet, spintet, neightet, worktet; 22837 face startsh, neighsh, worksh, workseg; 22838 point torg, tdest, tapex, workpt[3]; 22839 REAL checksign, orgori, destori; 22840 bool crossflag, inlistflag; 22841 bool belowflag, aboveflag; 22842 int idx, share; 22843 int i, j, k; 22844 22845 // Get a face at horizon. 22846 startsh = * (face *)(* missingshlist)[0]; 22847 torg = sorg(startsh); 22848 tdest = sdest(startsh); 22849 tapex = sapex(startsh); 22850 22851 // Collect the set of crossing tetrahedra by rotating crossing edges. 22852 for (i = 0; i < crossedgelist->len(); i++) { 22853 // Get a tet abcd, ab is a crossing edge. 22854 starttet = * (triface *)(* crossedgelist)[i]; 22855 adjustedgering(starttet, CCW); 22856 if (b->verbose > 2) { 22857 printf(" Collect tets containing edge (%d, %d).\n", 22858 pointmark(org(starttet)), pointmark(dest(starttet))); 22859 } 22860 orgori = orient3d(torg, tdest, tapex, org(starttet)); 22861 destori = orient3d(torg, tdest, tapex, dest(starttet)); 22862 #ifdef SELF_CHECK 22863 assert(orgori * destori < 0.0); 22864 #endif 22865 spintet = starttet; 22866 do { 22867 // The face rotation should not meet boundary. 22868 fnextself(spintet); 22869 // Check the validity of the PLC. 22870 tspivot(spintet, worksh); 22871 if (worksh.sh != dummysh) { 22872 printf("Error: Invalid PLC.\n"); 22873 printf(" Two subfaces (%d, %d, %d) and (%d, %d, %d)\n", 22874 pointmark(torg), pointmark(tdest), pointmark(tapex), 22875 pointmark(sorg(worksh)), pointmark(sdest(worksh)), 22876 pointmark(sapex(worksh))); 22877 printf(" are found intersecting each other.\n"); 22878 printf(" Hint: Use -d switch to find all intersecting facets.\n"); 22879 terminatetetgen(1); 22880 } 22881 if (!infected(spintet)) { 22882 if (b->verbose > 2) { 22883 printf(" Add crossing tet (%d, %d, %d, %d).\n", 22884 pointmark(org(spintet)), pointmark(dest(spintet)), 22885 pointmark(apex(spintet)), pointmark(oppo(spintet))); 22886 } 22887 infect(spintet); 22888 crosstetlist->append(&spintet); 22889 } 22890 // Check whether other two edges of 'spintet' is a crossing edge. 22891 // It can be quickly checked from the apex of 'spintet', if it is 22892 // not on the facet, then there exists a crossing edge. 22893 workpt[0] = apex(spintet); 22894 idx = pointmark(workpt[0]) - in->firstnumber; 22895 if (worklist[idx] != 1) { 22896 // Either edge (dest, apex) or edge (apex, org) crosses. 22897 checksign = orient3d(torg, tdest, tapex, workpt[0]); 22898 #ifdef SELF_CHECK 22899 assert(checksign != 0.0); 22900 #endif 22901 if (checksign * orgori < 0.0) { 22902 enext2(spintet, worktet); // edge (apex, org). 22903 workpt[1] = org(spintet); 22904 } else { 22905 //#ifdef SELF_CHECK // commented out to get gcc 4.6 working 22906 assert(checksign * destori < 0.0); 22907 //#endif 22908 enext(spintet, worktet); // edge (dest, apex). 22909 workpt[1] = dest(spintet); 22910 } 22911 // 'worktet' represents the crossing edge. Add it into list only 22912 // it doesn't exist in 'crossedgelist'. 22913 inlistflag = false; 22914 for (j = 0; j < crossedgelist->len() && !inlistflag; j++) { 22915 neightet = * (triface *)(* crossedgelist)[j]; 22916 if (org(neightet) == workpt[0]) { 22917 if (dest(neightet) == workpt[1]) inlistflag = true; 22918 } else if (org(neightet) == workpt[1]) { 22919 if (dest(neightet) == workpt[0]) inlistflag = true; 22920 } 22921 } 22922 if (!inlistflag) { 22923 crossedgelist->append(&worktet); 22924 } 22925 } 22926 } while (apex(spintet) != apex(starttet)); 22927 } 22928 22929 // Identifying the boundary faces and vertices of C. Sort them into 22930 // 'abovefacelist', 'aboveptlist, 'belowfacelist', and 'belowptlist', 22931 // respectively. "above" and "below" are wrt.(torg, tdest, tapex). 22932 for (i = 0; i < crosstetlist->len(); i++) { 22933 // Get a tet abcd, ab is the crossing edge. 22934 starttet = * (triface *)(* crosstetlist)[i]; 22935 #ifdef SELF_CHECK 22936 assert(infected(starttet)); 22937 #endif 22938 adjustedgering(starttet, CCW); 22939 // abc and abd are sharing the crossing edge, the two neighbors must 22940 // be crossing tetrahedra too. They can't be boundaries of C. 22941 for (j = 0; j < 2; j++) { 22942 if (j == 0) { 22943 enextfnext(starttet, worktet); // Check bcd. 22944 } else { 22945 enext2fnext(starttet, worktet); // Check acd. 22946 } 22947 sym(worktet, neightet); 22948 // If the neighbor doesn't exist or exists but doesn't be infected, 22949 // it's a boundary face of C, save it. 22950 if ((neightet.tet == dummytet) || !infected(neightet)) { 22951 workpt[0] = org(worktet); 22952 workpt[1] = dest(worktet); 22953 workpt[2] = apex(worktet); 22954 belowflag = aboveflag = false; 22955 share = 0; 22956 for (k = 0; k < 3; k++) { 22957 idx = pointmark(workpt[k]) - in->firstnumber; 22958 if (worklist[idx] == 0) { 22959 // It's not a vertices of facet, find which side it lies. 22960 checksign = orient3d(torg, tdest, tapex, workpt[k]); 22961 #ifdef SELF_CHECK 22962 assert(checksign != 0.0); 22963 #endif 22964 if (checksign > 0.0) { 22965 // It lies "below" the facet wrt. 'startsh'. 22966 worklist[idx] = 2; 22967 belowptlist->append(&workpt[k]); 22968 } else if (checksign < 0.0) { 22969 // It lies "above" the facet wrt. 'startsh'. 22970 worklist[idx] = 3; 22971 aboveptlist->append(&workpt[k]); 22972 } 22973 } 22974 if (worklist[idx] == 2) { 22975 // This face lies "below" the facet wrt. 'startsh'. 22976 belowflag = true; 22977 } else if (worklist[idx] == 3) { 22978 // This face lies "above" the facet wrt. 'startsh'. 22979 aboveflag = true; 22980 } else { 22981 #ifdef SELF_CHECK 22982 // In degenerate case, this face may just be the equator. 22983 assert(worklist[idx] == 1); 22984 #endif 22985 share++; 22986 } 22987 } 22988 #ifdef SELF_CHECK 22989 // The degenerate case has been ruled out. 22990 assert(share < 3); 22991 // Only one flag is possible for a cavity face. 22992 assert(belowflag ^ aboveflag); 22993 #endif 22994 if (belowflag) { 22995 belowfacelist->append(&worktet); 22996 } else if (aboveflag) { 22997 abovefacelist->append(&worktet); 22998 } 22999 } 23000 } 23001 } 23002 23003 // Shrink R if not all its subfaces are crossing by the discovered tets. 23004 // 'crossshlist' and 'horizptlist' represent the set of subfaces and 23005 // vertices of the shrinked missing region, respectively. 23006 for (i = 0; i < missingshlist->len(); i++) { 23007 worksh = * (face *)(* missingshlist)[i]; 23008 #ifdef SELF_CHECK 23009 assert(sinfected(worksh)); 23010 #endif 23011 workpt[0] = sorg(worksh); 23012 workpt[1] = sdest(worksh); 23013 workpt[2] = sapex(worksh); 23014 crossflag = false; 23015 for (j = 0; j < crosstetlist->len() && !crossflag; j++) { 23016 // Get a tet abcd, ab is a crossing edge. 23017 starttet = * (triface *)(* crosstetlist)[j]; 23018 adjustedgering(starttet, CCW); 23019 // Only need to check two sides of worktet. 23020 for (k = 0; k < 2 && !crossflag; k++) { 23021 if (k == 0) { 23022 worktet = starttet; // Check abc. 23023 } else { 23024 fnext(starttet, worktet); // Check abd. 23025 } 23026 crossflag = tritritest(&worktet, workpt[0], workpt[1], workpt[2]); 23027 } 23028 } 23029 if (crossflag) { 23030 // 'worksh' is crossed by 'worktet', uninfect it. 23031 suninfect(worksh); 23032 crossshlist->append(&worksh); 23033 // Add its corners into 'horizptlist'. 23034 for (k = 0; k < 3; k++) { 23035 idx = pointmark(workpt[k]) - in->firstnumber; 23036 if (worklist[idx] != 4) { 23037 worklist[idx] = 4; 23038 horizptlist->append(&workpt[k]); 23039 } 23040 } 23041 } 23042 } 23043 23044 // Check 'crossingtetlist'. Queue subfaces inside them. 23045 for (i = 0; i < crosstetlist->len(); i++) { 23046 starttet = * (triface *)(* crosstetlist)[i]; 23047 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { 23048 sym(starttet, neightet); 23049 // If the neighbor exist and is infected, check it. 23050 if ((neightet.tet != dummytet) && infected(neightet)) { 23051 tspivot(starttet, worksh); 23052 if (worksh.sh != dummysh) { 23053 // Temporarily remove worksh. Make it missing. recover it later. 23054 if (b->verbose > 2) { 23055 printf(" Queuing subface (%d, %d, %d).\n", 23056 pointmark(sorg(worksh)), pointmark(sdest(worksh)), 23057 pointmark(sapex(worksh))); 23058 } 23059 tsdissolve(neightet); 23060 tsdissolve(starttet); 23061 // Detach tets at the both sides of this subface. 23062 stdissolve(worksh); 23063 sesymself(worksh); 23064 stdissolve(worksh); 23065 sinfect(worksh); 23066 missingshqueue->push(&worksh); 23067 } 23068 } 23069 } 23070 } 23071 23072 // Clear flags set in 'worklist'. 23073 for (i = 0; i < equatptlist->len(); i++) { 23074 workpt[0] = * (point *)(* equatptlist)[i]; 23075 idx = pointmark(workpt[0]) - in->firstnumber; 23076 #ifdef SELF_CHECK 23077 assert((worklist[idx] == 1) || (worklist[idx] == 4)); 23078 #endif 23079 worklist[idx] = 0; 23080 } 23081 for (i = 0; i < belowptlist->len(); i++) { 23082 workpt[0] = * (point *)(* belowptlist)[i]; 23083 idx = pointmark(workpt[0]) - in->firstnumber; 23084 #ifdef SELF_CHECK 23085 assert(worklist[idx] == 2); 23086 #endif 23087 worklist[idx] = 0; 23088 } 23089 for (i = 0; i < aboveptlist->len(); i++) { 23090 workpt[0] = * (point *)(* aboveptlist)[i]; 23091 idx = pointmark(workpt[0]) - in->firstnumber; 23092 #ifdef SELF_CHECK 23093 assert(worklist[idx] == 3); 23094 #endif 23095 worklist[idx] = 0; 23096 } 23097 } 23098 23100 // // 23101 // insertallsubfaces() Insert all subfaces, queue missing subfaces. // 23102 // // 23103 // Loop through all subfaces, insert each into the DT. If one already exists,// 23104 // bond it to the tetrahedra having it. Otherwise, it is missing, infect it // 23105 // and save it in 'missingshqueue'. // 23106 // // 23108 23109 void tetgenmesh::insertallsubfaces(queue* missingshqueue) 23110 { 23111 triface searchtet; 23112 face subloop; 23113 23114 searchtet.tet = (tetrahedron *) NULL; 23115 subfaces->traversalinit(); 23116 subloop.sh = shellfacetraverse(subfaces); 23117 while (subloop.sh != (shellface *) NULL) { 23118 if (!insertsubface(&subloop, &searchtet)) { 23119 if (b->verbose > 1) { 23120 printf(" Queuing subface (%d, %d, %d).\n", pointmark(sorg(subloop)), 23121 pointmark(sdest(subloop)), pointmark(sapex(subloop))); 23122 } 23123 sinfect(subloop); 23124 missingshqueue->push(&subloop); 23125 } 23126 subloop.sh = shellfacetraverse(subfaces); 23127 } 23128 } 23129 23131 // // 23132 // constrainedfacets() Recover subfaces in a Delaunay tetrahedralization. // 23133 // // 23134 // This routine creates a CDT by incrementally updating a DT D into a CDT T. // 23135 // The process of recovering facets can be imagined by "merging" the surface // 23136 // mesh F into D. At the beginning, F and D are completely seperated. Some // 23137 // faces of them are matching some are not because they are crossed by some // 23138 // tetrahedra of D. The non-matching subfaces will be forced to appear in T // 23139 // by locally retetrahedralizing the regions where F and D are intersecting. // 23140 // // 23141 // When a subface s of F is found missing in D, probably some other subfaces // 23142 // near to s are missing too. The set of adjoining coplanar missing faces // 23143 // forms a missing region R (R may not simply connected). // 23144 // // 23145 // There are two possibilities can result a mssing region R: (1) Some edges // 23146 // of D cross R; (2) No edge of D crosses R, but some faces of D spans R, ie,// 23147 // D is locally degenerate at R. In case (1), D is modified so that it resp- // 23148 // ects R (done by a cavity retetrahedralization algorithm). In case (2), F // 23149 // is modified so that the set of subfaces of R matches faces in D (done by // 23150 // a face rearrangment algorithm). // 23151 // // 23153 23154 void tetgenmesh::constrainedfacets() 23155 { 23156 queue *missingshqueue, *flipque; 23157 list *missingshlist, *equatptlist; 23158 list *boundedgelist, *crossedgelist, *crosstetlist; 23159 list *crossshlist, *belowfacelist, *abovefacelist; 23160 list *horizptlist, *belowptlist, *aboveptlist; 23161 list *frontlist, *misfrontlist, *newtetlist; 23162 triface searchtet, worktet; 23163 face subloop, worksh; 23164 int *worklist; 23165 int i; 23166 23167 if (!b->quiet) { 23168 printf("Constraining facets.\n"); 23169 } 23170 23171 // Initialize queues. 23172 missingshqueue = new queue(sizeof(face)); 23173 flipque = new queue(sizeof(badface)); 23174 // Initialize the working lists. 23175 missingshlist = new list(sizeof(face), NULL); 23176 boundedgelist = new list(sizeof(face), NULL); 23177 crossedgelist = new list(sizeof(triface), NULL); 23178 equatptlist = new list((char*) "point *"); 23179 crossshlist = new list(sizeof(face), NULL); 23180 crosstetlist = new list(sizeof(triface), NULL); 23181 belowfacelist = new list(sizeof(triface), NULL); 23182 abovefacelist = new list(sizeof(triface), NULL); 23183 horizptlist = new list((char*)"point *"); 23184 belowptlist = new list((char*)"point *"); 23185 aboveptlist = new list((char*)"point *"); 23186 frontlist = new list(sizeof(triface), NULL); 23187 misfrontlist = new list(sizeof(triface), NULL); 23188 newtetlist = new list(sizeof(triface), NULL); 23189 // Initialize the array for marking vertices. 23190 worklist = new int[points->items + 1]; 23191 for (i = 0; i < points->items + 1; i++) worklist[i] = 0; 23192 23193 // Compute a mapping from points to tetrahedra for fast searching. 23194 makepoint2tetmap(); 23195 23196 // Match subfaces in D, queue all missing subfaces. 23197 insertallsubfaces(missingshqueue); 23198 23199 // Recover all missing subfaces. 23200 while (!missingshqueue->empty()) { 23201 // Get a queued face s. 23202 subloop = * (face *) missingshqueue->pop(); 23203 // s may have been deleted in a face rearrangment operation. 23204 if (isdead(&subloop)) continue; 23205 // s may have been recovered in a previous missing region. 23206 if (!sinfected(subloop)) continue; 23207 // s may match a face in D now due to previous transformations. 23208 if (insertsubface(&subloop, &searchtet)) { 23209 suninfect(subloop); 23210 continue; 23211 } 23212 if (b->verbose > 1) { 23213 printf(" Recover subface (%d, %d, %d).\n", pointmark(sorg(subloop)), 23214 pointmark(sdest(subloop)), pointmark(sapex(subloop))); 23215 } 23216 // Form the missing region R containing s. 23217 formmissingregion(&subloop, missingshlist, equatptlist, worklist); 23218 // Is R crossing by any tetrahedron? 23219 if (scoutcrossingedge(missingshlist, boundedgelist, crossedgelist, 23220 worklist)) { 23221 // Form the cavity C containing R. 23222 formcavity(missingshlist, crossedgelist, equatptlist, crossshlist, 23223 crosstetlist, belowfacelist, abovefacelist, horizptlist, 23224 belowptlist, aboveptlist, missingshqueue, worklist); 23225 // Recover the above part of C. 23226 delaunizecavity(crossshlist, abovefacelist, aboveptlist, horizptlist, 23227 frontlist, misfrontlist, newtetlist, crosstetlist, 23228 missingshqueue, flipque); 23229 // Inverse the direction of subfaces in R. 23230 for (i = 0; i < crossshlist->len(); i++) { 23231 worksh = * (face *)(* crossshlist)[i]; 23232 sesymself(worksh); 23233 * (face *)(* crossshlist)[i] = worksh; 23234 } 23235 // Recover the below part of C. 23236 delaunizecavity(crossshlist, belowfacelist, belowptlist, horizptlist, 23237 frontlist, misfrontlist, newtetlist, crosstetlist, 23238 missingshqueue, flipque); 23239 // Delete tetrahedra in C. 23240 for (i = 0; i < crosstetlist->len(); i++) { 23241 worktet = * (triface *)(* crosstetlist)[i]; 23242 tetrahedrondealloc(worktet.tet); 23243 } 23244 // There may have some un-recovered subfaces of R. Put them back into 23245 // queue. Otherwise, they will be missing on the boundary. 23246 for (i = 0; i < missingshlist->len(); i++) { 23247 worksh = * (face *)(* missingshlist)[i]; 23248 if (sinfected(worksh)) { 23249 // An unrecovered subface, put it back into queue. 23250 missingshqueue->push(&worksh); 23251 } 23252 } 23253 crossshlist->clear(); 23254 belowfacelist->clear(); 23255 abovefacelist->clear(); 23256 horizptlist->clear(); 23257 belowptlist->clear(); 23258 aboveptlist->clear(); 23259 crosstetlist->clear(); 23260 } else { 23261 // No. Rearrange subfaces of F conforming to that of D in R. It can 23262 // happen when the facet has non-coplanar vertices. 23263 rearrangesubfaces(missingshlist, boundedgelist, equatptlist, worklist); 23264 } 23265 // Clear all working lists. 23266 missingshlist->clear(); 23267 boundedgelist->clear(); 23268 crossedgelist->clear(); 23269 equatptlist->clear(); 23270 } 23271 23272 // Subfaces have been merged into D. 23273 checksubfaces = 1; 23274 23275 if (b->verbose > 0) { 23276 printf(" The biggest cavity: %d faces, %d vertices\n", maxcavfaces, 23277 maxcavverts); 23278 printf(" Enlarged %d times\n", expcavcount); 23279 } 23280 23281 delete missingshqueue; 23282 delete flipque; 23283 delete missingshlist; 23284 delete boundedgelist; 23285 delete crossedgelist; 23286 delete equatptlist; 23287 delete crossshlist; 23288 delete crosstetlist; 23289 delete belowfacelist; 23290 delete abovefacelist; 23291 delete horizptlist; 23292 delete belowptlist; 23293 delete aboveptlist; 23294 delete frontlist; 23295 delete misfrontlist; 23296 delete newtetlist; 23297 delete [] worklist; 23298 } 23299 23300 // 23301 // End of facet recovery routines 23302 // 23303 23304 // 23305 // Begin of carving out holes and concavities routines 23306 // 23307 23309 // // 23310 // infecthull() Virally infect all of the tetrahedra of the convex hull // 23311 // that are not protected by subfaces. Where there are // 23312 // subfaces, set boundary markers as appropriate. // 23313 // // 23314 // Memorypool 'viri' is used to return all the infected tetrahedra. // 23315 // // 23317 23318 void tetgenmesh::infecthull(memorypool *viri) 23319 { 23320 triface tetloop, tsymtet; 23321 tetrahedron **deadtet; 23322 face hullface; 23323 // point horg, hdest, hapex; 23324 23325 if (b->verbose > 0) { 23326 printf(" Marking concavities for elimination.\n"); 23327 } 23328 tetrahedrons->traversalinit(); 23329 tetloop.tet = tetrahedrontraverse(); 23330 while (tetloop.tet != (tetrahedron *) NULL) { 23331 // Is this tetrahedron on the hull? 23332 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { 23333 sym(tetloop, tsymtet); 23334 if (tsymtet.tet == dummytet) { 23335 // Is the tetrahedron protected by a subface? 23336 tspivot(tetloop, hullface); 23337 if (hullface.sh == dummysh) { 23338 // The tetrahedron is not protected; infect it. 23339 if (!infected(tetloop)) { 23340 infect(tetloop); 23341 deadtet = (tetrahedron **) viri->alloc(); 23342 *deadtet = tetloop.tet; 23343 break; // Go and get next tet. 23344 } 23345 } else { 23346 // The tetrahedron is protected; set boundary markers if appropriate. 23347 if (shellmark(hullface) == 0) { 23348 setshellmark(hullface, 1); 23349 /* 23350 horg = sorg(hullface); 23351 hdest = sdest(hullface); 23352 hapex = sapex(hullface); 23353 if (pointmark(horg) == 0) { 23354 setpointmark(horg, 1); 23355 } 23356 if (pointmark(hdest) == 0) { 23357 setpointmark(hdest, 1); 23358 } 23359 if (pointmark(hapex) == 0) { 23360 setpointmark(hapex, 1); 23361 } 23362 */ 23363 } 23364 } 23365 } 23366 } 23367 tetloop.tet = tetrahedrontraverse(); 23368 } 23369 } 23370 23372 // // 23373 // plague() Spread the virus from all infected tets to any neighbors not // 23374 // protected by subfaces. // 23375 // // 23376 // This routine identifies all the tetrahedra that will die, and marks them // 23377 // as infected. They are marked to ensure that each tetrahedron is added to // 23378 // the virus pool only once, so the procedure will terminate. 'viri' returns // 23379 // all infected tetrahedra which are outside the domian. // 23380 // // 23382 23383 void tetgenmesh::plague(memorypool *viri) 23384 { 23385 tetrahedron **virusloop; 23386 tetrahedron **deadtet; 23387 triface testtet, neighbor; 23388 face neighsh, testseg; 23389 face spinsh, casingin, casingout; 23390 int firstdadsub; 23391 int i; 23392 23393 if (b->verbose > 0) { 23394 printf(" Marking neighbors of marked tetrahedra.\n"); 23395 } 23396 firstdadsub = 0; 23397 // Loop through all the infected tetrahedra, spreading the virus to 23398 // their neighbors, then to their neighbors' neighbors. 23399 viri->traversalinit(); 23400 virusloop = (tetrahedron **) viri->traverse(); 23401 while (virusloop != (tetrahedron **) NULL) { 23402 testtet.tet = *virusloop; 23403 // Temporarily uninfect this tetrahedron, not necessary. 23404 uninfect(testtet); 23405 // Check each of the tetrahedron's four neighbors. 23406 for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { 23407 // Find the neighbor. 23408 sym(testtet, neighbor); 23409 // Check for a shell between the tetrahedron and its neighbor. 23410 tspivot(testtet, neighsh); 23411 // Check if the neighbor is nonexistent or already infected. 23412 if ((neighbor.tet == dummytet) || infected(neighbor)) { 23413 if (neighsh.sh != dummysh) { 23414 // There is a subface separating the tetrahedron from its neighbor, 23415 // but both tetrahedra are dying, so the subface dies too. 23416 // Before deallocte this subface, dissolve the connections between 23417 // other subfaces, subsegments and tetrahedra. 23418 neighsh.shver = 0; 23419 if (!firstdadsub) { 23420 firstdadsub = 1; // Report the problem once. 23421 if (!b->quiet) { 23422 printf("Warning: Detecting an open face (%d, %d, %d).\n", 23423 pointmark(sorg(neighsh)), pointmark(sdest(neighsh)), 23424 pointmark(sapex(neighsh))); 23425 } 23426 } 23427 // For keep the same enext() direction. 23428 findedge(&testtet, sorg(neighsh), sdest(neighsh)); 23429 for (i = 0; i < 3; i++) { 23430 sspivot(neighsh, testseg); 23431 if (testseg.sh != dummysh) { 23432 // A subsegment is found at this side, dissolve this subface 23433 // from the face link of this subsegment. 23434 testseg.shver = 0; 23435 spinsh = neighsh; 23436 if (sorg(spinsh) != sorg(testseg)) { 23437 sesymself(spinsh); 23438 } 23439 spivot(spinsh, casingout); 23440 if (casingout.sh == spinsh.sh) { 23441 // This is a trivial face link, only 'neighsh' itself, 23442 // the subsegment at this side is also died. 23443 shellfacedealloc(subsegs, testseg.sh); 23444 } else { 23445 spinsh = casingout; 23446 do { 23447 casingin = spinsh; 23448 spivotself(spinsh); 23449 } while (spinsh.sh != neighsh.sh); 23450 // Set the link casingin->casingout. 23451 sbond1(casingin, casingout); 23452 // Bond the subsegment anyway. 23453 ssbond(casingin, testseg); 23454 } 23455 } 23456 senextself(neighsh); 23457 enextself(testtet); 23458 } 23459 if (neighbor.tet != dummytet) { 23460 // Make sure the subface doesn't get deallocated again later 23461 // when the infected neighbor is visited. 23462 tsdissolve(neighbor); 23463 } 23464 // This subface has been separated. 23465 if (in->mesh_dim > 2) { 23466 shellfacedealloc(subfaces, neighsh.sh); 23467 } else { 23468 // Dimension is 2. keep it for output. 23469 // Dissolve tets at both sides of this subface. 23470 stdissolve(neighsh); 23471 sesymself(neighsh); 23472 stdissolve(neighsh); 23473 } 23474 } 23475 } else { // The neighbor exists and is not infected. 23476 if (neighsh.sh == dummysh) { 23477 // There is no subface protecting the neighbor, infect it. 23478 infect(neighbor); 23479 // Ensure that the neighbor's neighbors will be infected. 23480 deadtet = (tetrahedron **) viri->alloc(); 23481 *deadtet = neighbor.tet; 23482 } else { // The neighbor is protected by a subface. 23483 // Remove this tetrahedron from the subface. 23484 stdissolve(neighsh); 23485 // The subface becomes a boundary. Set markers accordingly. 23486 if (shellmark(neighsh) == 0) { 23487 setshellmark(neighsh, 1); 23488 } 23489 // This side becomes hull. Update the handle in dummytet. 23490 dummytet[0] = encode(neighbor); 23491 } 23492 } 23493 } 23494 // Remark the tetrahedron as infected, so it doesn't get added to the 23495 // virus pool again. 23496 infect(testtet); 23497 virusloop = (tetrahedron **) viri->traverse(); 23498 } 23499 } 23500 23502 // // 23503 // regionplague() Spread regional attributes and/or volume constraints // 23504 // (from a .poly file) throughout the mesh. // 23505 // // 23506 // This procedure operates in two phases. The first phase spreads an attri- // 23507 // bute and/or a volume constraint through a (facet-bounded) region. The // 23508 // second phase uninfects all infected tetrahedra, returning them to normal. // 23509 // // 23511 23512 void tetgenmesh:: 23513 regionplague(memorypool *regionviri, REAL attribute, REAL volume) 23514 { 23515 tetrahedron **virusloop; 23516 tetrahedron **regiontet; 23517 triface testtet, neighbor; 23518 face neighsh; 23519 23520 if (b->verbose > 1) { 23521 printf(" Marking neighbors of marked tetrahedra.\n"); 23522 } 23523 // Loop through all the infected tetrahedra, spreading the attribute 23524 // and/or volume constraint to their neighbors, then to their neighbors' 23525 // neighbors. 23526 regionviri->traversalinit(); 23527 virusloop = (tetrahedron **) regionviri->traverse(); 23528 while (virusloop != (tetrahedron **) NULL) { 23529 testtet.tet = *virusloop; 23530 // Temporarily uninfect this tetrahedron, not necessary. 23531 uninfect(testtet); 23532 if (b->regionattrib) { 23533 // Set an attribute. 23534 setelemattribute(testtet.tet, in->numberoftetrahedronattributes, 23535 attribute); 23536 } 23537 if (b->varvolume) { 23538 // Set a volume constraint. 23539 setvolumebound(testtet.tet, volume); 23540 } 23541 // Check each of the tetrahedron's four neighbors. 23542 for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { 23543 // Find the neighbor. 23544 sym(testtet, neighbor); 23545 // Check for a subface between the tetrahedron and its neighbor. 23546 tspivot(testtet, neighsh); 23547 // Make sure the neighbor exists, is not already infected, and 23548 // isn't protected by a subface, or is protected by a nonsolid 23549 // subface. 23550 if ((neighbor.tet != dummytet) && !infected(neighbor) 23551 && (neighsh.sh == dummysh)) { 23552 // Infect the neighbor. 23553 infect(neighbor); 23554 // Ensure that the neighbor's neighbors will be infected. 23555 regiontet = (tetrahedron **) regionviri->alloc(); 23556 *regiontet = neighbor.tet; 23557 } 23558 } 23559 // Remark the tetrahedron as infected, so it doesn't get added to the 23560 // virus pool again. 23561 infect(testtet); 23562 virusloop = (tetrahedron **) regionviri->traverse(); 23563 } 23564 23565 // Uninfect all tetrahedra. 23566 if (b->verbose > 1) { 23567 printf(" Unmarking marked tetrahedra.\n"); 23568 } 23569 regionviri->traversalinit(); 23570 virusloop = (tetrahedron **) regionviri->traverse(); 23571 while (virusloop != (tetrahedron **) NULL) { 23572 testtet.tet = *virusloop; 23573 uninfect(testtet); 23574 virusloop = (tetrahedron **) regionviri->traverse(); 23575 } 23576 // Empty the virus pool. 23577 regionviri->restart(); 23578 } 23579 23581 // // 23582 // removeholetets() Remove tetrahedra which are outside the domain. // 23583 // // 23585 23586 void tetgenmesh::removeholetets(memorypool* viri) 23587 { 23588 tetrahedron **virusloop; 23589 triface testtet, neighbor; 23590 point checkpt; 23591 int *tetspernodelist; 23592 int i, j; 23593 23594 if (b->verbose > 0) { 23595 printf(" Deleting marked tetrahedra.\n"); 23596 } 23597 23598 // Create and initialize 'tetspernodelist'. 23599 tetspernodelist = new int[points->items + 1]; 23600 for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0; 23601 23602 // Loop the tetrahedra list, counter the number of tets sharing each node. 23603 tetrahedrons->traversalinit(); 23604 testtet.tet = tetrahedrontraverse(); 23605 while (testtet.tet != (tetrahedron *) NULL) { 23606 // Increment the number of sharing tets for each endpoint. 23607 for (i = 0; i < 4; i++) { 23608 j = pointmark((point) testtet.tet[4 + i]); 23609 tetspernodelist[j]++; 23610 } 23611 testtet.tet = tetrahedrontraverse(); 23612 } 23613 23614 viri->traversalinit(); 23615 virusloop = (tetrahedron **) viri->traverse(); 23616 while (virusloop != (tetrahedron **) NULL) { 23617 testtet.tet = *virusloop; 23618 // Record changes in the number of boundary faces, and disconnect 23619 // dead tetrahedra from their neighbors. 23620 for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { 23621 sym(testtet, neighbor); 23622 if (neighbor.tet == dummytet) { 23623 // There is no neighboring tetrahedron on this face, so this face 23624 // is a boundary face. This tetrahedron is being deleted, so this 23625 // boundary face is deleted. 23626 hullsize--; 23627 } else { 23628 // Disconnect the tetrahedron from its neighbor. 23629 dissolve(neighbor); 23630 // There is a neighboring tetrahedron on this face, so this face 23631 // becomes a boundary face when this tetrahedron is deleted. 23632 hullsize++; 23633 } 23634 } 23635 // Check the four corners of this tet if they're isolated. 23636 for (i = 0; i < 4; i++) { 23637 checkpt = (point) testtet.tet[4 + i]; 23638 j = pointmark(checkpt); 23639 tetspernodelist[j]--; 23640 if (tetspernodelist[j] == 0) { 23641 // If it is added volume vertex or '-j' is not used, delete it. 23642 if ((pointtype(checkpt) == FREEVOLVERTEX) || !b->nojettison) { 23643 setpointtype(checkpt, UNUSEDVERTEX); 23644 unuverts++; 23645 } 23646 } 23647 } 23648 // Return the dead tetrahedron to the pool of tetrahedra. 23649 tetrahedrondealloc(testtet.tet); 23650 virusloop = (tetrahedron **) viri->traverse(); 23651 } 23652 23653 delete [] tetspernodelist; 23654 } 23655 23657 // // 23658 // assignregionattribs() Assign each tetrahedron a region number. // 23659 // // 23660 // This routine is called when '-AA' switch is specified. Every tetrahedron // 23661 // of a (bounded) region will get a integer number to that region. Default, // 23662 // regions are numbered as 1, 2, 3, etc. However, if a number has already // 23663 // been used (set by user in the region section in .poly or .smesh), it is // 23664 // skipped and the next available number will be used. // 23665 // // 23667 23668 void tetgenmesh::assignregionattribs() 23669 { 23670 list *regionnumlist; 23671 list *regiontetlist; 23672 triface tetloop, regiontet, neightet; 23673 face checksh; 23674 bool flag; 23675 int regionnum, num; 23676 int attridx, count; 23677 int i; 23678 23679 if (b->verbose > 0) { 23680 printf(" Assign region numbers.\n"); 23681 } 23682 23683 regionnumlist = new list(sizeof(int), NULL, 256); 23684 regiontetlist = new list(sizeof(triface), NULL, 1024); 23685 attridx = in->numberoftetrahedronattributes; 23686 23687 // Loop through all tets. Infect tets which already have a region number, 23688 // and save the used numbers in 'regionnumlist'. 23689 tetrahedrons->traversalinit(); 23690 tetloop.tet = tetrahedrontraverse(); 23691 while (tetloop.tet != (tetrahedron *) NULL) { 23692 if (!infected(tetloop)) { 23693 regionnum = (int) elemattribute(tetloop.tet, attridx); 23694 if (regionnum != 0.0) { 23695 // Found a numbered region tet. 23696 infect(tetloop); 23697 regiontetlist->append(&tetloop); 23698 // Found and infect all tets in this region. 23699 for (i = 0; i < regiontetlist->len(); i++) { 23700 regiontet = * (triface *)(* regiontetlist)[i]; 23701 for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) { 23702 // Is there a boundary face? 23703 tspivot(regiontet, checksh); 23704 if (checksh.sh == dummysh) { 23705 sym(regiontet, neightet); 23706 if ((neightet.tet != dummytet) && !infected(neightet)) { 23707 #ifdef SELF_CHECK 23708 // neightet should have the same region number. Check it. 23709 num = (int) elemattribute(neightet.tet, attridx); 23710 assert(num == regionnum); 23711 #endif 23712 infect(neightet); 23713 regiontetlist->append(&neightet); 23714 } 23715 } 23716 } 23717 } 23718 // Add regionnum to list if it is not exist. 23719 flag = false; 23720 for (i = 0; i < regionnumlist->len() && !flag; i++) { 23721 num = * (int *)(* regionnumlist)[i]; 23722 flag = (num == regionnum); 23723 } 23724 if (!flag) regionnumlist->append(®ionnum); 23725 // Clear list for the next region. 23726 regiontetlist->clear(); 23727 } 23728 } 23729 tetloop.tet = tetrahedrontraverse(); 23730 } 23731 23732 if (b->verbose > 0) { 23733 printf(" %d user-specified regions.\n", regionnumlist->len()); 23734 } 23735 23736 // Now loop the tets again. Assign region numbers to uninfected tets. 23737 tetrahedrons->traversalinit(); 23738 tetloop.tet = tetrahedrontraverse(); 23739 regionnum = 1; // Start region number. 23740 count = 0; 23741 while (tetloop.tet != (tetrahedron *) NULL) { 23742 if (!infected(tetloop)) { 23743 // An unassigned region tet. 23744 count++; 23745 do { 23746 flag = false; 23747 // Check if the region number has been used. 23748 for (i = 0; i < regionnumlist->len() && !flag; i++) { 23749 num = * (int *)(* regionnumlist)[i]; 23750 flag = (num == regionnum); 23751 } 23752 if (flag) regionnum++; 23753 } while (flag); 23754 setelemattribute(tetloop.tet, attridx, (REAL) regionnum); 23755 infect(tetloop); 23756 regiontetlist->append(&tetloop); 23757 // Found and infect all tets in this region. 23758 for (i = 0; i < regiontetlist->len(); i++) { 23759 regiontet = * (triface *)(* regiontetlist)[i]; 23760 for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) { 23761 // Is there a boundary face? 23762 tspivot(regiontet, checksh); 23763 if (checksh.sh == dummysh) { 23764 sym(regiontet, neightet); 23765 if ((neightet.tet != dummytet) && !infected(neightet)) { 23766 #ifdef SELF_CHECK 23767 // neightet should have not been assigned yet. Check it. 23768 num = (int) elemattribute(neightet.tet, attridx); 23769 assert(num == 0); 23770 #endif 23771 setelemattribute(neightet.tet, attridx, (REAL) regionnum); 23772 infect(neightet); 23773 regiontetlist->append(&neightet); 23774 } 23775 } 23776 } 23777 } 23778 regiontetlist->clear(); 23779 regionnum++; // The next region number. 23780 } 23781 tetloop.tet = tetrahedrontraverse(); 23782 } 23783 23784 // Uninfect all tets. 23785 tetrahedrons->traversalinit(); 23786 tetloop.tet = tetrahedrontraverse(); 23787 while (tetloop.tet != (tetrahedron *) NULL) { 23788 #ifdef SELF_CHECK 23789 assert(infected(tetloop)); 23790 #endif 23791 uninfect(tetloop); 23792 tetloop.tet = tetrahedrontraverse(); 23793 } 23794 23795 if (b->verbose > 0) { 23796 printf(" %d regions are numbered.\n", count); 23797 } 23798 23799 delete regionnumlist; 23800 delete regiontetlist; 23801 } 23802 23804 // // 23805 // carveholes() Find the holes and infect them. Find the volume // 23806 // constraints and infect them. Infect the convex hull. // 23807 // Spread the infection and kill tetrahedra. Spread the // 23808 // volume constraints. // 23809 // // 23810 // This routine mainly calls other routines to carry out all these functions.// 23811 // // 23813 23814 void tetgenmesh::carveholes() 23815 { 23816 memorypool *holeviri, *regionviri; 23817 tetrahedron *tptr, **holetet, **regiontet; 23818 triface searchtet, *holetets, *regiontets; 23819 enum locateresult intersect; 23820 int i; 23821 23822 if (!b->quiet) { 23823 printf("Removing unwanted tetrahedra.\n"); 23824 if (b->verbose && (in->numberofholes > 0)) { 23825 printf(" Marking holes for elimination.\n"); 23826 } 23827 } 23828 23829 // Initialize a pool of viri to be used for holes, concavities. 23830 holeviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0); 23831 // Mark as infected any unprotected tetrahedra on the boundary. 23832 infecthull(holeviri); 23833 23834 if (in->numberofholes > 0) { 23835 // Allocate storage for the tetrahedra in which hole points fall. 23836 holetets = (triface *) new triface[in->numberofholes]; 23837 // Infect each tetrahedron in which a hole lies. 23838 for (i = 0; i < 3 * in->numberofholes; i += 3) { 23839 // Ignore holes that aren't within the bounds of the mesh. 23840 if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax) 23841 && (in->holelist[i + 1] >= ymin) 23842 && (in->holelist[i + 1] <= ymax) 23843 && (in->holelist[i + 2] >= zmin) 23844 && (in->holelist[i + 2] <= zmax)) { 23845 searchtet.tet = dummytet; 23846 // Find a tetrahedron that contains the hole. 23847 intersect = locate(&in->holelist[i], &searchtet); 23848 if ((intersect != OUTSIDE) && (!infected(searchtet))) { 23849 // Record the tetrahedron for processing carve hole. 23850 holetets[i / 3] = searchtet; 23851 } 23852 } 23853 } 23854 // Infect the hole tetrahedron. This is done by marking the tet as 23855 // infected and including the tetrahedron in the virus pool. 23856 for (i = 0; i < in->numberofholes; i++) { 23857 infect(holetets[i]); 23858 holetet = (tetrahedron **) holeviri->alloc(); 23859 *holetet = holetets[i].tet; 23860 } 23861 // Free up memory. 23862 delete [] holetets; 23863 } 23864 23865 // Mark as infected all tets of the holes and concavities. 23866 plague(holeviri); 23867 // The virus pool contains all outside tets now. 23868 23869 // Is -A switch in use. 23870 if (b->regionattrib) { 23871 // Assign every tetrahedron a regional attribute of zero. 23872 tetrahedrons->traversalinit(); 23873 tptr = tetrahedrontraverse(); 23874 while (tptr != (tetrahedron *) NULL) { 23875 setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0); 23876 tptr = tetrahedrontraverse(); 23877 } 23878 } 23879 23880 if (in->numberofregions > 0) { 23881 if (!b->quiet) { 23882 if (b->regionattrib) { 23883 if (b->varvolume) { 23884 printf("Spreading regional attributes and volume constraints.\n"); 23885 } else { 23886 printf("Spreading regional attributes.\n"); 23887 } 23888 } else { 23889 printf("Spreading regional volume constraints.\n"); 23890 } 23891 } 23892 // Allocate storage for the tetrahedra in which region points fall. 23893 regiontets = (triface *) new triface[in->numberofregions]; 23894 // Find the starting tetrahedron for each region. 23895 for (i = 0; i < in->numberofregions; i++) { 23896 regiontets[i].tet = dummytet; 23897 // Ignore region points that aren't within the bounds of the mesh. 23898 if ((in->regionlist[5 * i] >= xmin) 23899 && (in->regionlist[5 * i] <= xmax) 23900 && (in->regionlist[5 * i + 1] >= ymin) 23901 && (in->regionlist[5 * i + 1] <= ymax) 23902 && (in->regionlist[5 * i + 2] >= zmin) 23903 && (in->regionlist[5 * i + 2] <= zmax)) { 23904 searchtet.tet = dummytet; 23905 // Find a tetrahedron that contains the region point. 23906 intersect = locate(&in->regionlist[5 * i], &searchtet); 23907 if ((intersect != OUTSIDE) && (!infected(searchtet))) { 23908 // Record the tetrahedron for processing after the 23909 // holes have been carved. 23910 regiontets[i] = searchtet; 23911 } 23912 } 23913 } 23914 // Initialize a pool to be used for regional attrs, and/or regional 23915 // volume constraints. 23916 regionviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0); 23917 // Find and set all regions. 23918 for (i = 0; i < in->numberofregions; i++) { 23919 if (regiontets[i].tet != dummytet) { 23920 // Make sure the tetrahedron under consideration still exists. 23921 // It may have been eaten by the virus. 23922 if (!isdead(&(regiontets[i]))) { 23923 // Put one tetrahedron in the virus pool. 23924 infect(regiontets[i]); 23925 regiontet = (tetrahedron **) regionviri->alloc(); 23926 *regiontet = regiontets[i].tet; 23927 // Apply one region's attribute and/or volume constraint. 23928 regionplague(regionviri, in->regionlist[5 * i + 3], 23929 in->regionlist[5 * i + 4]); 23930 // The virus pool should be empty now. 23931 } 23932 } 23933 } 23934 // Free up memory. 23935 delete [] regiontets; 23936 delete regionviri; 23937 } 23938 23939 // Now acutually remove the outside and hole tets. 23940 removeholetets(holeviri); 23941 // The mesh is nonconvex now. 23942 nonconvex = 1; 23943 23944 if (b->regionattrib) { 23945 if (b->regionattrib > 1) { 23946 // -AA switch. Assign each tet a region number (> 0). 23947 assignregionattribs(); 23948 } 23949 // Note the fact that each tetrahedron has an additional attribute. 23950 in->numberoftetrahedronattributes++; 23951 } 23952 23953 // Free up memory. 23954 delete holeviri; 23955 } 23956 23957 // 23958 // End of carving out holes and concavities routines 23959 // 23960 23961 // 23962 // Begin of boundary Steiner points removing routines 23963 // 23964 23966 // // 23967 // replacepolygonsubs() Substitute the subfaces of a polygon. // 23968 // // 23969 // 'oldshlist' (T_old) contains the old subfaces of P. It will be replaced // 23970 // by 'newshlist' (T_new) of new subfaces. Each boundary edge of P is bonded // 23971 // to 'dummysh' in T_new. // 23972 // // 23973 // Notice that Not every boundary edge of T_new is able to bond to a subface,// 23974 // e.g., when it is a segment recovered by removing a Steiner point in it. // 23975 // // 23977 23978 void tetgenmesh::replacepolygonsubs(list* oldshlist, list* newshlist) 23979 { 23980 face newsh, oldsh, spinsh; 23981 face casingout, casingin; 23982 face checkseg; 23983 point pa, pb; 23984 int i, j, k, l; 23985 23986 for (i = 0; i < newshlist->len(); i++) { 23987 // Get a new subface s. 23988 newsh = * (face *)(* newshlist)[i]; 23989 // Check the three edges of s. 23990 for (k = 0; k < 3; k++) { 23991 spivot(newsh, casingout); 23992 // Is it a boundary edge? 23993 if (casingout.sh == dummysh) { 23994 // Find the old subface s_o having the same edge as s. 23995 pa = sorg(newsh); 23996 pb = sdest(newsh); 23997 for (j = 0; j < oldshlist->len(); j++) { 23998 oldsh = * (face *)(* oldshlist)[j]; 23999 for (l = 0; l < 3; l++) { 24000 if (((sorg(oldsh) == pa) && (sdest(oldsh) == pb)) || 24001 ((sorg(oldsh) == pb) && (sdest(oldsh) == pa))) break; 24002 senextself(oldsh); 24003 } 24004 if (l < 3) break; 24005 } 24006 // Is there a matched edge? 24007 if (j < oldshlist->len()) { 24008 // Get the neighbor subface s_out. 24009 spivot(oldsh, casingout); 24010 sspivot(oldsh, checkseg); 24011 if (checkseg.sh != dummysh) { 24012 // A segment. Insert s into the face ring, ie, s_in -> s -> s_out. 24013 if (oldsh.sh != casingout.sh) { 24014 // s is not bonded to itself. 24015 spinsh = casingout; 24016 do { 24017 casingin = spinsh; 24018 spivotself(spinsh); 24019 } while (sapex(spinsh) != sapex(oldsh)); 24020 assert(casingin.sh != oldsh.sh); 24021 // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out). 24022 sbond1(casingin, newsh); 24023 sbond1(newsh, casingout); 24024 } else { 24025 // Bond newsh -> newsh. 24026 sbond(newsh, newsh); 24027 } 24028 // Bond the segment. 24029 ssbond(newsh, checkseg); 24030 } else { 24031 // Bond s <-> s_out (and dissolve s_out -> s_old). 24032 sbond(newsh, casingout); 24033 } 24034 // Unbound oldsh to indicate it's neighbor has been replaced. 24035 // It will be used to indentfy the edge in the inverse. 24036 sdissolve(oldsh); 24037 ssdissolve(oldsh); 24038 } 24039 } 24040 // Go to the next edge of s. 24041 senextself(newsh); 24042 } 24043 } 24044 } 24045 24047 // // 24048 // orientnewsubs() Orient new subfaces facing to the inside of cavity. // 24049 // // 24050 // 'newshlist' contains new subfaces of the cavity C (created by re-triangu- // 24051 // lation the polygon P). They're not necessary facing to the inside of C. // 24052 // 'orientsh', faces to the inside of C, is used to adjust new subfaces. The // 24053 // normal of the new subfaces is returned in 'norm'. // 24054 // // 24056 24057 void tetgenmesh::orientnewsubs(list* newshlist, face* orientsh, REAL* norm) 24058 { 24059 face *newsh; 24060 point pa, pb, pc; 24061 REAL ref[3], ori, len; 24062 int i; 24063 24064 // Calculate the normal of 'orientsh'. 24065 pa = sorg(*orientsh); 24066 pb = sdest(*orientsh); 24067 pc = sapex(*orientsh); 24068 facenormal(pa, pb, pc, norm, &len); 24069 for (i = 0; i < 3; i++) ref[i] = pa[i] + norm[i]; 24070 for (i = 0; i < 3; i++) norm[i] /= len; 24071 24072 // Orient new subfaces. Let the normal above each one. 24073 for (i = 0; i < newshlist->len(); i++) { 24074 newsh = (face *)(* newshlist)[i]; 24075 pa = sorg(*newsh); 24076 pb = sdest(*newsh); 24077 pc = sapex(*newsh); 24078 ori = orient3d(pa, pb, pc, ref); 24079 assert(ori != 0.0); 24080 if (ori > 0.0) { 24081 sesymself(*newsh); 24082 } 24083 } 24084 } 24085 24087 // // 24088 // constrainedflip() Flip a non-constrained face. // 24089 // // 24090 // 'flipface' f (abc) is a face we want to flip. In addition, if 'front' is // 24091 // given (not a NULL), f is a crossface. f may not be flippable if it is one // 24092 // of the following cases: // 24093 // (1) f has an aux subface attached; // 24094 // (2) f is on the convex hull; // 24095 // (3) f is not locally Delaunay (f must be recovered by a previous flip, // 24096 // we should keep it, otherwise, we may fall into a flip loop); // 24097 // (4) f is T32 at ab, but abd or abe has an aux subface attached; // 24098 // (5) f is T22 or T44 at ab, but abd, or abe, or abf has an aux subface // 24099 // attached; // 24100 // (6) f is unflipable at ab, and abd, abe, ... are all unflippable due to // 24101 // the cases (1) - (5). // 24102 // If f is a crssface ('front' != NULL) and it is unflipable due to case (3),// 24103 // (4), (5) and (6). Try to flip the next crossing face of front first. // 24104 // // 24106 24107 bool tetgenmesh::constrainedflip(triface* flipface, triface* front, 24108 queue* flipque) 24109 { 24110 triface symface, spintet; 24111 face checksh; 24112 point pa, pb, pc, pd, pe; 24113 enum fliptype fc; 24114 REAL sign; 24115 bool doflip; 24116 int ia, ib, ic, id, ie; 24117 int i; 24118 24119 // (1) Is f protected by an (auxilary) subface? 24120 tspivot(*flipface, checksh); 24121 if (checksh.sh != dummysh) return false; 24122 // (2) Is f on the convex hull? 24123 sym(*flipface, symface); 24124 if (symface.tet == dummytet) return false; 24125 // (3) Is f not locally Delaunay? 24126 adjustedgering(*flipface, CCW); 24127 pa = dest(*flipface); 24128 pb = org(*flipface); 24129 pc = apex(*flipface); 24130 pd = oppo(*flipface); 24131 pe = oppo(symface); 24132 // if (symbolic) { 24133 ia = pointmark(pa); 24134 ib = pointmark(pb); 24135 ic = pointmark(pc); 24136 id = pointmark(pd); 24137 ie = pointmark(pe); 24138 sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie); 24139 assert(sign != 0.0); 24140 // } else { 24141 // sign = insphere(pa, pb, pc, pd, pe); 24142 // } 24143 if (sign <= 0.0) { 24144 // Get the fliptype of f. 24145 checksubfaces = 0; // switch off subface test. 24146 fc = categorizeface(*flipface); 24147 checksubfaces = 1; // switch on subface test. 24148 if (fc == T23) { 24149 doflip = true; 24150 // Avoid one tet created by the 2-3 flip is nearly degenerate. 24151 /* pc = oppo(*flipface); 24152 pd = oppo(symface); 24153 adjustedgering(*flipface, CCW); 24154 for (i = 0; i < 3; i++) { 24155 pa = org(*flipface); 24156 pb = dest(*flipface); 24157 ori = orient3d(pa, pb, pc, pd); 24158 if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) { 24159 doflip = false; break; 24160 } 24161 enextself(*flipface); 24162 } */ 24163 if (doflip) { 24164 flip23(flipface, flipque); 24165 return true; 24166 } 24167 } else if (fc == T32) { 24168 // (4) Is abd, or abe protected? 24169 doflip = true; 24170 spintet = *flipface; 24171 for (i = 0; i < 2; i++) { 24172 fnextself(spintet); 24173 tspivot(spintet, checksh); 24174 if (checksh.sh != dummysh) { 24175 doflip = false; break; // f is protected. Unflipable. 24176 } 24177 } 24178 if (doflip) { 24179 flip32(flipface, flipque); 24180 return true; 24181 } 24182 } else if (fc == T22 || fc == T44) { 24183 // (5) Is abd, abe, or abf protected? 24184 doflip = true; 24185 if (fc == T22) { 24186 for (i = 0; i < 2; i++) { 24187 spintet = *flipface; 24188 if (i == 1) { 24189 esymself(spintet); 24190 } 24191 fnextself(spintet); 24192 tspivot(spintet, checksh); 24193 if (checksh.sh != dummysh) { 24194 doflip = false; break; // f is protected. Unflipable. 24195 } 24196 } 24197 } else if (fc == T44) { 24198 spintet = *flipface; 24199 for (i = 0; i < 3; i++) { 24200 fnextself(spintet); 24201 tspivot(spintet, checksh); 24202 if (checksh.sh != dummysh) { 24203 doflip = false; break; // f is protected. Unflipable. 24204 } 24205 } 24206 } 24207 if (doflip) { 24208 flip22(flipface, flipque); 24209 return true; 24210 } 24211 } else if (fc == N32) { 24212 // Is f a crossface? 24213 if (front != (triface *) NULL) { 24214 // (6) Is any obstacle face (abd, or abe, ...) flipable? 24215 spintet = *flipface; 24216 while (fnextself(spintet)) { 24217 if (apex(spintet) == apex(*flipface)) break; 24218 // Check if spintet is flipable, no recursive. 24219 if (constrainedflip(&spintet, NULL, flipque)) { 24220 // One obstacle face has been flipped. 24221 return true; 24222 } 24223 // Unflipable. Go to the next obstacle face. 24224 findedge(&spintet, org(*flipface), dest(*flipface)); 24225 } 24226 } 24227 } 24228 } 24229 24230 // f is unflipable. Is f a crossface? 24231 if (front != (triface *) NULL) { 24232 // Look if there is another crossface. 24233 pa = org(*front); 24234 pb = dest(*front); 24235 pc = apex(*front); 24236 // sym(*flipface, symface); 24237 // Have we reach the end of abc (We've started from edge ab). 24238 if (oppo(symface) != pc) { 24239 adjustedgering(symface, CCW); 24240 for (i = 0; i < 3; i++) { 24241 fnext(symface, spintet); 24242 // Is c ahead of this face? 24243 sign = orient3d(org(spintet), dest(spintet), apex(spintet), pc); 24244 if (sign < 0.0) { 24245 if (tritritest(&spintet, pa, pb, pc)) { 24246 if (b->verbose > 2) { 24247 printf(" Next crossface (%d, %d, %d).\n", 24248 pointmark(org(spintet)), pointmark(dest(spintet)), 24249 pointmark(apex(spintet))); 24250 } 24251 return constrainedflip(&spintet, front, flipque); 24252 // return constrainedflip(&spintet, NULL, flipque); 24253 } 24254 } 24255 enextself(symface); 24256 } 24257 } 24258 } 24259 return false; 24260 } 24261 24263 // // 24264 // recoverfront() Recover a missing front by flips. // 24265 // // 24266 // 'front' f is missing in D - it was crossed by faces of D. The cross faces // 24267 // may be flippable, so f can be recovered by flipping them away. // 24268 // // 24270 24271 bool tetgenmesh::recoverfront(triface* front, list* newtetlist, queue* flipque) 24272 { 24273 triface idfront, starttet, spintet; 24274 point pa, pb, pc, pd, ref; 24275 enum locateresult loc; 24276 enum finddirectionresult col; 24277 REAL ori, ori1, ori2, sign; 24278 int hitbdry; 24279 int i, j; 24280 24281 // Find an existing edge of f in D to start with. 24282 for (i = 0; i < 3; i++) { 24283 pa = org(*front); 24284 pb = dest(*front); 24285 // Get a tet for searching. 24286 idfront = recenttet; 24287 // Make sure the tet is valid (flip32() may kill a tet). 24288 if (isdead(&idfront)) { 24289 // The tet is dead. Get a live tet in D. !!! 24290 for (j = 0; j < newtetlist->len(); j++) { 24291 recenttet = * (triface *)(* newtetlist)[j]; 24292 if (!isdead(&recenttet)) break; 24293 } 24294 assert(j < newtetlist->len()); 24295 } 24296 loc = preciselocate(pa, &idfront, (long) newtetlist->len()); 24297 if (loc != ONVERTEX) { 24298 // Do a brute-force search in D. 24299 for (j = 0; j < newtetlist->len(); j++) { 24300 idfront = * (triface *)(* newtetlist)[j]; 24301 if (isdead(&idfront)) continue; 24302 if (findorg(&idfront, pa)) break; 24303 } 24304 assert(j < newtetlist->len()); // a must belong to one tet. 24305 } 24306 recenttet = idfront; 24307 // Search for a tet having edge ab. 24308 col = finddirection(&idfront, pb, (long) newtetlist->len()); 24309 if (col == BELOWHULL) { 24310 // Do a brute-force search in D. 24311 for (j = 0; j < newtetlist->len(); j++) { 24312 idfront = * (triface *)(* newtetlist)[j]; 24313 if (isdead(&idfront)) continue; 24314 if (findorg(&idfront, pa)) { 24315 assert(org(idfront) == pa); 24316 if (dest(idfront) == pb) { 24317 col = RIGHTCOLLINEAR; break; 24318 } else if (apex(idfront) == pb) { 24319 col = LEFTCOLLINEAR; break; 24320 } else if (oppo(idfront) == pb) { 24321 col = TOPCOLLINEAR; break; 24322 } 24323 } 24324 } 24325 } 24326 if (col == RIGHTCOLLINEAR) { 24327 // b is just the destination. 24328 } else if (col == LEFTCOLLINEAR) { 24329 enext2self(idfront); 24330 esymself(idfront); 24331 } else if (col == TOPCOLLINEAR) { 24332 fnextself(idfront); 24333 enext2self(idfront); 24334 esymself(idfront); 24335 } 24336 if (dest(idfront) == pb) break; // Found. 24337 // Missing. Go to the next edge of f. 24338 enextself(*front); 24339 } 24340 if (i == 3) { 24341 // All three edges of f are missing - unrecoverable. 24342 return false; 24343 } 24344 24345 // Search for a tet having f (abc). 24346 pc = apex(*front); 24347 spintet = idfront; 24348 hitbdry = 0; 24349 do { 24350 if (apex(spintet) == pc) { 24351 // Found abc. Insert an auxilary subface s at idfront. 24352 insertauxsubface(front, &spintet); 24353 return true; 24354 } 24355 if (!fnextself(spintet)) { 24356 hitbdry ++; 24357 if (hitbdry < 2) { 24358 esym(idfront, spintet); 24359 if (!fnextself(spintet)) { 24360 hitbdry ++; 24361 } 24362 } 24363 } 24364 if (apex(spintet) == apex(idfront)) break; 24365 } while (hitbdry < 2); 24366 24367 // Search for a crossing face to flip. 24368 pd = apex(idfront); 24369 assert(pd != pc); 24370 // Decide the orientation of d with abc. 24371 ori = orient3d(pa, pb, pc, pd); 24372 if (ori < 0.0) { 24373 // d is above abc. Rotate downwards. 24374 esym(idfront, starttet); 24375 sign = -1.0; 24376 } else if (ori > 0.0) { 24377 // d is below abc. Rotate upwards. 24378 starttet = idfront; 24379 sign = 1.0; 24380 } else { 24381 assert(ori == 0.0); 24382 // d is coplanar with abc. Do abc and abd intersect? 24383 ref = oppo(idfront); 24384 ori1 = orient3d(pa, pb, ref, pc); 24385 ori2 = orient3d(pa, pb, ref, pd); 24386 assert(ori1 * ori2 != 0.0); 24387 if (ori1 * ori2 > 0) { 24388 // abc and abd intersect. There're two possible intersections: 24389 // ad and bc, or ac and bd. Find it out. 24390 ori1 = orient3d(pb, pc, ref, pd); 24391 ori2 = orient3d(pb, pc, ref, pa); 24392 assert(ori1 * ori2 != 0.0); 24393 if (ori1 * ori2 > 0) { 24394 // ac intersects bd. 24395 enextself(idfront); // go to edge bd. 24396 } else { 24397 // ad intersects bc. 24398 enext2self(idfront); // go to edge ad. 24399 } 24400 adjustedgering(idfront, CCW); 24401 fnextself(idfront); // face ade or bce need a 4-to-4 flip. 24402 if (b->verbose > 2) { 24403 printf(" Get crossface (%d, %d, %d).\n", pointmark(org(idfront)), 24404 pointmark(dest(idfront)), pointmark(apex(idfront))); 24405 } 24406 if (constrainedflip(&idfront, front, flipque)) { 24407 // A crossface has been flipped. Continue to recover f. 24408 return recoverfront(front, newtetlist, flipque); 24409 } 24410 // Unable to recover f. 24411 return false; // sign = 0.0; 24412 } else { 24413 // Not intersect. We can go either direction. 24414 starttet = idfront; 24415 if (fnextself(starttet)) { 24416 // Choose to rotate upwards. 24417 sign = 1.0; 24418 } else { 24419 // Hit convex hull. Choose to rotate downwrads. 24420 esym(idfront, starttet); 24421 sign = -1.0; 24422 } 24423 } 24424 } 24425 24426 assert(sign != 0.0); 24427 if (sign == -1) { 24428 // The edge ab has be changed. Reverse it. 24429 pa = org(starttet); 24430 pb = dest(starttet); 24431 // The sign has been reversed as well. 24432 sign = -sign; 24433 } 24434 // Rotate face abd around edge ab. Moreover, we've chosen the rotate 24435 // direction such that no convex hull face will be reach. 24436 spintet = starttet; 24437 while (fnextself(spintet)) { 24438 pd = apex(spintet); 24439 assert(pd != pc); 24440 // Check if the orientation of d (with abc) has changed. 24441 ori = orient3d(pa, pb, pc, pd); 24442 if (ori == 0.0) { 24443 // abc and abd must coplanar intersect (4-to-4 flip is needed). 24444 ref = oppo(spintet); 24445 ori1 = orient3d(pb, pc, ref, pd); 24446 ori2 = orient3d(pb, pc, ref, pa); 24447 assert(ori1 * ori2 != 0.0); 24448 if (ori1 * ori2 > 0) { 24449 // ac intersects bd. 24450 enextself(spintet); // go to edge bd. 24451 } else { 24452 // ad intersects bc. 24453 enext2self(spintet); // go to edge ad. 24454 } 24455 adjustedgering(spintet, CCW); 24456 fnextself(spintet); // face ade or bce need a 4-to-4 flip. 24457 if (b->verbose > 2) { 24458 printf(" Get crossface (%d, %d, %d).\n", pointmark(org(spintet)), 24459 pointmark(dest(spintet)), pointmark(apex(spintet))); 24460 } 24461 if (constrainedflip(&spintet, front, flipque)) { 24462 // A crossface has been flipped. Continue to recover f. 24463 return recoverfront(front, newtetlist, flipque); 24464 } 24465 // Unable to recover f. 24466 return false; // sign = 0.0; 24467 } else if (ori * sign < 0.0) { 24468 // Sign has changed. The face dea or deb must cross abc. 24469 adjustedgering(spintet, CCW); 24470 enextself(spintet); 24471 for (i = 0; i < 2; i++) { 24472 // Get the face dea or deb. 24473 fnext(spintet, starttet); 24474 if (tritritest(&starttet, pa, pb, pc)) { 24475 if (b->verbose > 2) { 24476 printf(" Get crossface (%d, %d, %d).\n", 24477 pointmark(org(starttet)), pointmark(dest(starttet)), 24478 pointmark(apex(starttet))); 24479 } 24480 if (constrainedflip(&starttet, front, flipque)) { 24481 // A crossface has been flipped. Continue to recover f. 24482 return recoverfront(front, newtetlist, flipque); 24483 } 24484 } 24485 enextself(spintet); 24486 } 24487 // Unable to recover f. 24488 return false; 24489 } 24490 } 24491 // Impossible to be here. 24492 assert(0); 24493 return false; 24494 } 24495 24497 // // 24498 // repairflips() Flip non-Delaunay and non-constrained faces. // 24499 // // 24501 24502 void tetgenmesh::repairflips(queue* flipque) 24503 { 24504 badface *qface; 24505 triface flipface, symface, spintet; 24506 face checksh; 24507 point pa, pb, pc, pd, pe; 24508 enum fliptype fc; 24509 REAL sign; 24510 long flipcount; 24511 bool doflip; 24512 int ia, ib, ic, id, ie; 24513 int i; 24514 24515 if (b->verbose > 1) { 24516 printf(" Repair flip %ld faces.\n", flipque->len()); 24517 } 24518 flipcount = flip23s + flip32s + flip22s + flip44s; 24519 // Loop until the queue is empty. 24520 while (!flipque->empty()) { 24521 qface = (badface *) flipque->pop(); 24522 flipface = qface->tt; 24523 // Check the validity of this face. 24524 if (isdead(&flipface) || flipface.tet == dummytet || 24525 (org(flipface) != qface->forg) || 24526 (dest(flipface) != qface->fdest) || 24527 (apex(flipface) != qface->fapex) || 24528 (oppo(flipface) == (point) NULL)) continue; 24529 // (1) Is f protected by an (auxilary) subface? 24530 tspivot(flipface, checksh); 24531 if (checksh.sh != dummysh) continue; 24532 // (2) Is f on the convex hull? 24533 sym(flipface, symface); 24534 if (symface.tet == dummytet) continue; 24535 // For positive orientation that insphere() test requires. 24536 adjustedgering(flipface, CW); 24537 pa = org(flipface); 24538 pb = dest(flipface); 24539 pc = apex(flipface); 24540 pd = oppo(flipface); 24541 pe = oppo(symface); 24542 // if (symbolic) { 24543 ia = pointmark(pa); 24544 ib = pointmark(pb); 24545 ic = pointmark(pc); 24546 id = pointmark(pd); 24547 ie = pointmark(pe); 24548 sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie); 24549 assert(sign != 0.0); 24550 // } else { 24551 // sign = insphere(pa, pb, pc, pd, pe); 24552 // } 24553 if (sign > 0.0) { 24554 // f is non-lcally Delaunay. Get the fliptype of f. 24555 checksubfaces = 0; // switch off subface test. 24556 fc = categorizeface(flipface); 24557 checksubfaces = 1; // switch on subface test. 24558 if (fc == T23) { 24559 doflip = true; 24560 // Avoid to create a nearly degenerate tet. 24561 /* pc = oppo(flipface); 24562 pd = oppo(symface); 24563 adjustedgering(flipface, CCW); 24564 for (i = 0; i < 3; i++) { 24565 pa = org(flipface); 24566 pb = dest(flipface); 24567 ori = orient3d(pa, pb, pc, pd); 24568 if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) { 24569 doflip = false; break; 24570 } 24571 enextself(flipface); 24572 } */ 24573 if (doflip) { 24574 flip23(&flipface, flipque); 24575 } 24576 } else if (fc == T32) { 24577 // (4) Is abd, or abe protected? 24578 doflip = true; 24579 spintet = flipface; 24580 for (i = 0; i < 2; i++) { 24581 fnextself(spintet); 24582 tspivot(spintet, checksh); 24583 if (checksh.sh != dummysh) { 24584 doflip = false; break; // f is protected. Unflipable. 24585 } 24586 } 24587 if (doflip) { 24588 flip32(&flipface, flipque); 24589 } 24590 } else if (fc == T22 || fc == T44) { 24591 // (5) Is abd, abe, or abf protected? 24592 doflip = true; 24593 if (fc == T22) { 24594 for (i = 0; i < 2; i++) { 24595 spintet = flipface; 24596 if (i == 1) { 24597 esymself(spintet); 24598 } 24599 fnextself(spintet); 24600 tspivot(spintet, checksh); 24601 if (checksh.sh != dummysh) { 24602 doflip = false; break; // f is protected. Unflipable. 24603 } 24604 } 24605 } else if (fc == T44) { 24606 spintet = flipface; 24607 for (i = 0; i < 3; i++) { 24608 fnextself(spintet); 24609 tspivot(spintet, checksh); 24610 if (checksh.sh != dummysh) { 24611 doflip = false; break; // f is protected. Unflipable. 24612 } 24613 } 24614 } 24615 if (doflip) { 24616 flip22(&flipface, flipque); 24617 } 24618 } 24619 } 24620 } 24621 flipcount = flip23s + flip32s + flip22s + flip44s - flipcount; 24622 if (b->verbose > 1) { 24623 printf(" %ld flips.\n", flipcount); 24624 } 24625 } 24626 24628 // // 24629 // constrainedcavity() Tetrahedralize a cavity by constrained tetrahedra. // 24630 // // 24631 // The cavity C is bounded by faces F in 'floorlist' and 'ceillist'. 'ptlist'// 24632 // V is the set of vertices of C. // 24633 // // 24635 24636 bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist, 24637 list* ceillist, list* ptlist, list* frontlist, list* misfrontlist, 24638 list* newtetlist, queue* flipque) 24639 { 24640 triface misfront, newtet; 24641 long facenum; 24642 int i; 24643 24644 if (b->verbose > 1) { 24645 printf(" Constrained cavity (%d floors, %d ceilings, %d vertices).\n", 24646 floorlist->len(), ceillist->len(), ptlist->len()); 24647 } 24648 24649 // symbolic = 1; 24650 24651 // Initialize the cavity C. 24652 initializecavity(floorlist, ceillist, frontlist); 24653 // Form the D of the vertices of C. 24654 delaunizecavvertices(oldtet, ptlist, NULL, newtetlist, flipque); 24655 24656 // Identify faces of C in D. 24657 if (!identifyfronts(frontlist, misfrontlist, newtetlist)) { 24658 // Some faces are missing. 24659 recenttet = * (triface *)(* newtetlist)[0]; 24660 assert((recenttet.tet != dummytet) && !isdead(&recenttet)); 24661 // Try to recover missing faces by flips. 24662 do { 24663 facenum = misfrontlist->len(); 24664 for (i = 0; i < misfrontlist->len(); i++) { 24665 // Get a missing front f. 24666 misfront = * (triface *)(* misfrontlist)[i]; 24667 // Let f face toward the inside of C. 24668 adjustedgering(misfront, CW); 24669 if (b->verbose > 1) { 24670 printf(" Recover face (%d, %d, %d).\n", pointmark(org(misfront)), 24671 pointmark(dest(misfront)), pointmark(apex(misfront))); 24672 } 24673 if (recoverfront(&misfront, newtetlist, flipque)) { 24674 // f has been recovered. 24675 frontlist->append(&misfront); 24676 misfrontlist->del(i, 0); i--; 24677 } 24678 // Flip non-locally non-constrained Delaunay faces. 24679 repairflips(flipque); 24680 } 24681 // Have all faces been recovered? 24682 if (misfrontlist->len() == 0) break; 24683 // No! There are still un-recovered faces. Continue the loop if any 24684 // face has been recovered. 24685 } while (misfrontlist->len() < facenum); 24686 // Retrieve new tets and purge dead tets in D. 24687 retrievenewtets(newtetlist); 24688 } 24689 24690 // symbolic = 0; 24691 24692 if (misfrontlist->len() == 0) { 24693 // All fronts have identified in D. Get the shape of C by removing out 24694 // tets of C. 'misfrontlist' is reused for removing out tets. 24695 // Don't do flip since the new tets may get deleted later. 24696 carvecavity(newtetlist, misfrontlist, NULL); 24697 // Recover locally Delaunay faces. 24698 // flip(flipque, NULL); 24699 return true; 24700 } else { 24701 // Fail to tetrahedralize C. 24702 // Remove aux subfaces. 24703 detachauxsubfaces(newtetlist); 24704 // Remove new tets. 24705 for (i = 0; i < newtetlist->len(); i++) { 24706 newtet = * (triface *)(* newtetlist)[i]; 24707 assert(!isdead(&newtet)); 24708 tetrahedrondealloc(newtet.tet); 24709 } 24710 newtetlist->clear(); 24711 // Restore faces of C in frontlist. 24712 for (i = 0; i < misfrontlist->len(); i++) { 24713 misfront = * (triface *)(* misfrontlist)[i]; 24714 frontlist->append(&misfront); 24715 } 24716 return false; 24717 } 24718 } 24719 24721 // // 24722 // expandsteinercavity() Expand the cavity of a Steiner point. // 24723 // // 24724 // Expand the cavity C if there fronts (except fronts having subfaces) which // 24725 // are either (nearly) coplanar or invisible by the Steiner point. // 24726 // // 24728 24729 void tetgenmesh::expandsteinercavity(point steinpt, REAL eps, list* frontlist, 24730 list* oldtetlist) 24731 { 24732 triface front, symfront, newfront, oldfront; 24733 face frontsh; 24734 point pa, pb, pc; 24735 REAL ori; 24736 bool expflag, newflag; 24737 int i, j; 24738 24739 do { 24740 expflag = false; 24741 for (i = 0; i < frontlist->len(); i++) { 24742 // Get a front f. 24743 front = * (triface *)(* frontlist)[i]; 24744 // f can be expanded if it is not a subface. 24745 tspivot(front, frontsh); 24746 if (frontsh.sh == dummysh) { 24747 // Let f face to the inside of C. 24748 adjustedgering(front, CW); 24749 pa = org(front); 24750 pb = dest(front); 24751 pc = apex(front); 24752 ori = orient3d(pa, pb, pc, steinpt); 24753 if (ori != 0.0) { 24754 if (iscoplanar(pa, pb, pc, steinpt, ori, eps)) { 24755 ori = 0.0; // f is nearly coplanar with p. 24756 } 24757 } 24758 if (ori >= 0.0) { 24759 // f is either invisible or coplanar with p. 24760 if (b->verbose > 2) { 24761 printf(" Remove front (%d, %d, %d).\n", pointmark(pa), 24762 pointmark(pb), pointmark(pc)); 24763 } 24764 frontlist->del(i, 1); 24765 expflag = true; 24766 break; 24767 } 24768 } 24769 } 24770 if (expflag) { 24771 assert(!infected(front) && (oppo(front) != NULL)); 24772 // Expand C at f by including new fronts. 24773 adjustedgering(front, CCW); 24774 for (i = 0; i < 3; i++) { 24775 newflag = true; 24776 // Get a new boundary n of the cavity. 24777 fnext(front, symfront); 24778 tspivot(symfront, frontsh); 24779 sym(symfront, newfront); 24780 if (frontsh.sh == dummysh) { 24781 assert(newfront.tet != dummytet); 24782 // Is n a front of the unexp. cavity? 24783 if (infected(newfront)) { 24784 for (j = 0; j < frontlist->len(); j++) { 24785 oldfront = * (triface *)(* frontlist)[j]; 24786 if ((oldfront.tet == symfront.tet) && 24787 (oldfront.loc == symfront.loc)) { 24788 // n is not a front anymore. 24789 if (b->verbose > 2) { 24790 printf(" Remove front (%d, %d, %d).\n", 24791 pointmark(org(oldfront)), pointmark(dest(oldfront)), 24792 pointmark(apex(oldfront))); 24793 } 24794 frontlist->del(j, 1); 24795 newflag = false; 24796 break; 24797 } 24798 } 24799 } 24800 } else { 24801 // n is a subface. 24802 if (newfront.tet == dummytet) { 24803 sesymself(frontsh); 24804 // Create a fake tet to hold n. 24805 maketetrahedron(&newfront); 24806 setorg(newfront, sorg(frontsh)); 24807 setdest(newfront, sdest(frontsh)); 24808 setapex(newfront, sapex(frontsh)); 24809 setoppo(newfront, (point) NULL); 24810 tsbond(newfront, frontsh); 24811 } else { 24812 // n should not be a front of cavity yet. 24813 assert(!infected(newfront)); 24814 } 24815 } 24816 if (newflag) { 24817 if (b->verbose > 2) { 24818 printf(" Add front (%d, %d, %d).\n", pointmark(org(newfront)), 24819 pointmark(dest(newfront)), pointmark(apex(newfront))); 24820 } 24821 frontlist->append(&newfront); 24822 } 24823 enextself(front); 24824 } 24825 // Add f into oldtetlist (to be deleted). 24826 infect(front); 24827 oldtetlist->append(&front); 24828 expcavcount++; 24829 } 24830 } while (expflag); 24831 } 24832 24834 // // 24835 // findrelocatepoint() Find new location for relocating a point. // 24836 // // 24837 // 'frontlist' contains the boundary faces of the cavity C. Some fronts are // 24838 // visible by 'stpt' p, some are coplanar with p. // 24839 // // 24841 24842 bool tetgenmesh::findrelocatepoint(point sp, point np, REAL* n, 24843 list* frontlist, list* oldtetlist) 24844 { 24845 triface front; 24846 point pa, pb, pc; 24847 REAL tp[3], tvol, mvol; 24848 REAL ori, eps; 24849 bool visible; 24850 int i, j, k; 24851 24852 if (b->verbose > 1) { 24853 printf(" Find new location for point %d.\n", pointmark(sp)); 24854 } 24855 24856 // Avoid compilation warnings. 24857 tvol = mvol = 0.0; 24858 visible = false; 24859 24860 eps = b->epsilon; 24861 // Initialize np far enough from p (outside C). 24862 for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i]; 24863 // Let tp = np; 24864 for (i = 0; i < 3; i++) tp[i] = np[i]; 24865 // Interation to adjust np until it is visible by all fronts. 24866 j = 0; 24867 do { 24868 for (i = 0; i < frontlist->len(); i++) { 24869 // Get a front face f. 24870 front = * (triface *)(* frontlist)[i]; 24871 // Let f face to the interior of C. 24872 adjustedgering(front, CW); 24873 pa = org(front); 24874 pb = dest(front); 24875 pc = apex(front); 24876 ori = orient3d(pa, pb, pc, np); 24877 visible = (ori < 0.0); 24878 if (!visible) { 24879 // A front is invisible by np. Move it towards p along the normal. 24880 for (i = 0; i < 3; i++) np[i] = sp[i] + 0.5 * (sp[i] - np[i]); 24881 // Failed if tp = np. 24882 if ((tp[0] == np[0]) && (tp[1] == np[1]) && (tp[2] == np[2])) { 24883 // Try to expand the cavity. 24884 expandsteinercavity(sp, eps, frontlist, oldtetlist); 24885 eps *= 10.0; 24886 if (eps > b->epsilon * 1000.0) { 24887 // printf("Internal error: Fail to relocate pt %d.\n",pointmark(sp)); 24888 // internalerror(); 24889 return false; 24890 } 24891 // Restart the point relocation. 24892 for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i]; 24893 } 24894 if (j % 2) { 24895 // Set tp = np (at every 2 steps) to catch the stop state. 24896 for (i = 0; i < 3; i++) tp[i] = np[i]; 24897 } 24898 break; 24899 } else { 24900 // Save the smallest volume. 24901 if (i == 0) { 24902 mvol = fabs(ori); 24903 } else { 24904 mvol = fabs(ori) < mvol ? fabs(ori) : mvol; 24905 } 24906 } 24907 } 24908 j++; 24909 } while (!visible); 24910 24911 if (b->verbose > 1) { 24912 printf(" %d iterations. minvol = %.12g.\n", j, mvol); 24913 } 24914 24915 // Continue to adjust np until the minimal volume of tets formed by 24916 // fronts and np doesn't increase (all fronts are visible by np). 24917 k = 0; 24918 do { 24919 j = 0; 24920 do { 24921 if (k == 0) { 24922 // Initial tp := np + 0.9 * (p - np). Move toward p. 24923 for (i = 0; i < 3; i++) tp[i] = sp[i] + 0.9 * (np[i] - sp[i]); 24924 } else { 24925 // Initial tp := np + 1.1 * (p - np). Move away from p. 24926 for (i = 0; i < 3; i++) tp[i] = sp[i] + 1.1 * (np[i] - sp[i]); 24927 } 24928 // Get the minial volume formed by tp with one of the fronts. 24929 for (i = 0; i < frontlist->len(); i++) { 24930 // Get a front face f. 24931 front = * (triface *)(* frontlist)[i]; 24932 // Let f face to the interior of C. 24933 adjustedgering(front, CW); 24934 pa = org(front); 24935 pb = dest(front); 24936 pc = apex(front); 24937 ori = orient3d(pa, pb, pc, tp); 24938 visible = (ori < 0.0); 24939 if (visible) { 24940 // Save the smallest volume. 24941 if (i == 0) { 24942 tvol = fabs(ori); 24943 } else { 24944 tvol = fabs(ori) < tvol ? fabs(ori) : tvol; 24945 } 24946 } else { 24947 // A front is invisible by tp. Stop. 24948 tvol = 0.0; 24949 break; 24950 } 24951 } 24952 if (tvol > mvol) { 24953 // Get a larger minimal volume. 24954 for (i = 0; i < 3; i++) np[i] = tp[i]; 24955 mvol = tvol; 24956 } else { 24957 // Minimal volume decreases. Stop. 24958 break; 24959 } 24960 // Continue to adjust np. 24961 j++; 24962 } while (true); 24963 // Has np been adjusted? 24964 if (j > 0) break; 24965 // Try to move np to anoter direction. 24966 k++; 24967 } while (k < 2); 24968 24969 if (b->verbose > 1) { 24970 printf(" %d adjust iterations. minvol = %.12g.\n", j, mvol); 24971 } 24972 return true; 24973 } 24974 24976 // // 24977 // relocatepoint() Relocate a point into the cavity. // 24978 // // 24979 // 'frontlist' contains the boundary faces of the cavity C. All fronts must // 24980 // be visible by 'steinpt'. Some fronts may hold by 'fake' tets (they are // 24981 // hull faces). Fake tets will be removed when they're finished. // 24982 // // 24984 24985 void tetgenmesh::relocatepoint(point steinpt, triface* oldtet, list* frontlist, 24986 list* newtetlist, queue* flipque) 24987 { 24988 triface front, newtet, newface, neightet; 24989 face checksh; 24990 point pa, pb; 24991 REAL attrib, volume; 24992 bool bdflag; 24993 int i, j, k, l; 24994 24995 if (b->verbose > 1) { 24996 printf(" Insert Steiner point (%.12g, %.12g, %.12g) %d.\n", 24997 steinpt[0], steinpt[1], steinpt[2], pointmark(steinpt)); 24998 } 24999 // Clear the list first. 25000 newtetlist->clear(); 25001 25002 // Create the tets formed by fronts and 'steinpt'. 25003 for (i = 0; i < frontlist->len(); i++) { 25004 // Get a front f. 25005 front = * (triface *)(* frontlist)[i]; 25006 // Let f face inside C. (f is a face of tet adjacent to C). 25007 adjustedgering(front, CW); 25008 if (b->verbose > 2) { 25009 printf(" Get front (%d, %d, %d).\n", pointmark(org(front)), 25010 pointmark(dest(front)), pointmark(apex(front))); 25011 } 25012 maketetrahedron(&newtet); 25013 newtetlist->append(&newtet); 25014 setorg(newtet, org(front)); 25015 setdest(newtet, dest(front)); 25016 setapex(newtet, apex(front)); 25017 setoppo(newtet, steinpt); 25018 if (oldtet != (triface *) NULL) { 25019 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 25020 attrib = elemattribute(oldtet->tet, j); 25021 setelemattribute(newtet.tet, j, attrib); 25022 } 25023 if (b->varvolume) { 25024 volume = volumebound(oldtet->tet); 25025 setvolumebound(newtet.tet, volume); 25026 } 25027 } 25028 // 'front' may be a 'fake' tet. 25029 tspivot(front, checksh); 25030 if (oppo(front) == (point) NULL) { 25031 if (checksh.sh != dummysh) { 25032 stdissolve(checksh); 25033 } 25034 // Dealloc the 'fake' tet. 25035 tetrahedrondealloc(front.tet); 25036 // This side (newtet) is a boundary face, let 'dummytet' bond to it. 25037 // Otherwise, 'dummytet' may point to a dead tetrahedron after the 25038 // old cavity tets are removed. 25039 dummytet[0] = encode(newtet); 25040 } else { 25041 // Bond two tetrahedra, also dissolve the old bond at 'front'. 25042 bond(newtet, front); 25043 } 25044 if (checksh.sh != dummysh) { 25045 sesymself(checksh); 25046 tsbond(newtet, checksh); 25047 } 25048 if (flipque != (queue *) NULL) { 25049 // f may be non-locally Delaunay and flipable. 25050 enqueueflipface(newtet, flipque); 25051 } 25052 // The three neighbors are open. Will be finished later. 25053 } 25054 25055 // Connect new tets in C. All connecting faces must contain 'steinpt'. 25056 for (i = 0; i < newtetlist->len(); i++) { 25057 newtet = * (triface *)(* newtetlist)[i]; 25058 newtet.ver = 0; 25059 for (j = 0; j < 3; j++) { 25060 fnext(newtet, newface); 25061 sym(newface, neightet); 25062 if (neightet.tet == dummytet) { 25063 // Find a neightet to connect it. 25064 bdflag = false; 25065 pa = org(newface); 25066 pb = dest(newface); 25067 assert(apex(newface) == steinpt); 25068 for (k = i + 1; k < newtetlist->len() && !bdflag; k++) { 25069 neightet = * (triface *)(* newtetlist)[k]; 25070 neightet.ver = 0; 25071 for (l = 0; l < 3; l++) { 25072 if ((org(neightet) == pa && dest(neightet) == pb) || 25073 (org(neightet) == pb && dest(neightet) == pa)) { 25074 // Find the neighbor. 25075 fnextself(neightet); 25076 assert(apex(neightet) == steinpt); 25077 // Now neightet is a face same as newface, bond them. 25078 bond(newface, neightet); 25079 bdflag = true; 25080 break; 25081 } 25082 enextself(neightet); 25083 } 25084 } 25085 assert(bdflag); 25086 } 25087 enextself(newtet); 25088 } 25089 // Let the corners of newtet point to it for fast searching. 25090 pa = org(newtet); 25091 setpoint2tet(pa, encode(newtet)); 25092 pa = dest(newtet); 25093 setpoint2tet(pa, encode(newtet)); 25094 pa = apex(newtet); 25095 setpoint2tet(pa, encode(newtet)); 25096 pa = oppo(newtet); 25097 setpoint2tet(pa, encode(newtet)); 25098 } 25099 25100 if (flipque != (queue *) NULL) { 25101 // Recover locally Delaunay faces. 25102 flip(flipque, NULL); 25103 } 25104 } 25105 25107 // // 25108 // findcollapseedge() Find collapseable edge to suppress an endpoint. // 25109 // // 25111 25112 bool tetgenmesh::findcollapseedge(point suppt, point *conpt, list* oldtetlist, 25113 list* ptlist) 25114 { 25115 triface front; 25116 point pt, pa, pb, pc; 25117 REAL *lenarray, ltmp, ori; 25118 bool visflag; 25119 int *idxarray, itmp; 25120 int n, i, j; 25121 25122 if (b->verbose > 2) { 25123 printf(" Search an edge (in %d edges) for collapse %d.\n", 25124 ptlist->len(), pointmark(suppt)); 25125 } 25126 25127 // Candidate edges are p to the points of B(p) (in 'ptlist'). 25128 n = ptlist->len(); 25129 lenarray = new REAL[n]; 25130 idxarray = new int[n]; 25131 // Sort the points of B(p) by distance to p. 25132 for (i = 0; i < n; i++) { 25133 pt = * (point *)(* ptlist)[i]; 25134 lenarray[i] = distance(suppt, pt); 25135 idxarray[i] = i; 25136 } 25137 // Bubble sort. 25138 for (i = 0; i < n - 1; i++) { 25139 for (j = 0; j < n - 1 - i; j++) { 25140 if (lenarray[j + 1] < lenarray[j]) { // compare the two neighbors 25141 ltmp = lenarray[j]; // swap a[j] and a[j + 1] 25142 lenarray[j] = lenarray[j + 1]; 25143 lenarray[j + 1] = ltmp; 25144 itmp = idxarray[j]; // swap a[j] and a[j + 1] 25145 idxarray[j] = idxarray[j + 1]; 25146 idxarray[j + 1] = itmp; 25147 } 25148 } 25149 } 25150 // For each point q of B(p), test if the edge (p, q) can be collapseed. 25151 for (i = 0; i < n; i++) { 25152 pt = * (point *)(* ptlist)[idxarray[i]]; 25153 // Is q visible by faces of B(p) not with q as a vertex. 25154 lenarray[i] = 0.0; // zero volume. 25155 visflag = true; 25156 for (j = 0; j < oldtetlist->len() && visflag; j++) { 25157 front = * (triface *)(* oldtetlist)[j]; 25158 // Let f face to inside of B(p). 25159 adjustedgering(front, CCW); 25160 pa = org(front); 25161 pb = dest(front); 25162 pc = apex(front); 25163 // Is f contains q? 25164 if ((pa != pt) && (pb != pt) && (pc != pt)) { 25165 ori = orient3d(pa, pb, pc, pt); 25166 if (ori != 0.0) { 25167 if (iscoplanar(pa, pb, pc, pt, ori, b->epsilon * 1e+2)) ori = 0.0; 25168 } 25169 visflag = ori < 0.0; 25170 if (visflag) { 25171 // Visible, set the smallest volume. 25172 if (j == 0) { 25173 lenarray[i] = fabs(ori); 25174 } else { 25175 lenarray[i] = fabs(ori) < lenarray[i] ? fabs(ori) : lenarray[i]; 25176 } 25177 } else { 25178 // Invisible. Do not collapse (p, q). 25179 lenarray[i] = 0.0; 25180 } 25181 } 25182 } 25183 if ((b->verbose > 2) && visflag) { 25184 printf(" Got candidate %d vol(%g).\n", pointmark(pt), lenarray[i]); 25185 } 25186 } 25187 25188 // Select the largest non-zero volume (result in ltmp). 25189 ltmp = lenarray[0]; 25190 itmp = idxarray[0]; 25191 for (i = 1; i < n; i++) { 25192 if (lenarray[i] != 0.0) { 25193 if (lenarray[i] > ltmp) { 25194 ltmp = lenarray[i]; 25195 itmp = idxarray[i]; // The index to find the point. 25196 } 25197 } 25198 } 25199 25200 delete [] lenarray; 25201 delete [] idxarray; 25202 25203 if (ltmp == 0.0) { 25204 // No edge can be collapseed. 25205 *conpt = (point) NULL; 25206 return false; 25207 } else { 25208 pt = * (point *)(* ptlist)[itmp]; 25209 *conpt = pt; 25210 return true; 25211 } 25212 } 25213 25215 // // 25216 // collapseedge() Remove a point by edge collapse. // 25217 // // 25219 25220 void tetgenmesh::collapseedge(point suppt, point conpt, list* oldtetlist, 25221 list* deadtetlist) 25222 { 25223 triface oldtet, deadtet; 25224 triface adjtet1, adjtet2; 25225 face adjsh; 25226 point pa, pb, pc; 25227 int i, j; 25228 25229 if (b->verbose > 2) { 25230 printf(" Collapse edge (%d,%d).\n", pointmark(suppt), pointmark(conpt)); 25231 } 25232 25233 // Loop in B(p), replace p with np, queue dead tets, uninfect old tets. 25234 for (i = 0; i < oldtetlist->len(); i++) { 25235 oldtet = * (triface *)(* oldtetlist)[i]; // assert(infected(oldtet)); 25236 uninfect(oldtet); 25237 pa = org(oldtet); 25238 pb = dest(oldtet); 25239 pc = apex(oldtet); 25240 assert(oppo(oldtet) == suppt); 25241 setoppo(oldtet, conpt); 25242 if ((pa == conpt) || (pb == conpt) || (pc == conpt)) { 25243 deadtetlist->append(&oldtet); // a collpased tet. 25244 } 25245 } 25246 // Loop in deadtetlist, glue adjacent tets of dead tets. 25247 for (i = 0; i < deadtetlist->len(); i++) { 25248 deadtet = * (triface *)(* deadtetlist)[i]; 25249 // Get the adjacent tet n1 (outside B(p)). 25250 sym(deadtet, adjtet1); 25251 tspivot(deadtet, adjsh); 25252 // Find the edge in deadtet opposite to conpt. 25253 adjustedgering(deadtet, CCW); 25254 for (j = 0; j < 3; j++) { 25255 if (apex(deadtet) == conpt) break; 25256 enextself(deadtet); 25257 } 25258 assert(j < 3); 25259 // Get another adjacent tet n2. 25260 fnext(deadtet, adjtet2); 25261 symself(adjtet2); 25262 assert(adjtet2.tet != dummytet); // n2 is inside B(p). 25263 if (adjtet1.tet != dummytet) { 25264 bond(adjtet1, adjtet2); // Bond n1 <--> n2. 25265 } else { 25266 dissolve(adjtet2); // Dissolve at n2. 25267 dummytet[0] = encode(adjtet2); // Let dummytet holds n2. 25268 } 25269 if (adjsh.sh != dummysh) { 25270 tsbond(adjtet2, adjsh); // Bond s <--> n2. 25271 } 25272 // Collapse deadtet. 25273 tetrahedrondealloc(deadtet.tet); 25274 } 25275 deadtetlist->clear(); 25276 } 25277 25279 // // 25280 // deallocfaketets() Deleted fake tets at fronts. // 25281 // // 25282 // This routine is only called when the findrelocatepoint() routine fails. // 25283 // In other cases, the fake tets are removed automatically in carvecavity() // 25284 // or relocatepoint(). // 25285 // // 25287 25288 void tetgenmesh::deallocfaketets(list* frontlist) 25289 { 25290 triface front, neightet; 25291 face checksh; 25292 bool infectflag; 25293 int i; 25294 25295 for (i = 0; i < frontlist->len(); i++) { 25296 // Get a front f. 25297 front = * (triface *)(* frontlist)[i]; 25298 // Let f face inside C. (f is a face of tet adjacent to C). 25299 adjustedgering(front, CW); 25300 sym(front, neightet); 25301 tspivot(front, checksh); 25302 if (oppo(front) == (point) NULL) { 25303 if (b->verbose > 2) { 25304 printf(" Get fake tet (%d, %d, %d).\n", pointmark(org(front)), 25305 pointmark(dest(front)), pointmark(apex(front))); 25306 } 25307 if (neightet.tet != dummytet) { 25308 // The neightet may be infected. After dissolve it, the infect flag 25309 // will be lost. Save the flag and restore it later. 25310 infectflag = infected(neightet); 25311 dissolve(neightet); 25312 if (infectflag) { 25313 infect(neightet); 25314 } 25315 } 25316 if (checksh.sh != dummysh) { 25317 infectflag = sinfected(checksh); 25318 stdissolve(checksh); 25319 if (infectflag) { 25320 sinfect(checksh); 25321 } 25322 } 25323 // Dealloc the 'fake' tet. 25324 tetrahedrondealloc(front.tet); 25325 // If 'neightet' is a hull face, let 'dummytet' bond to it. It is 25326 // a 'dummytet' when this front was created from a new subface. 25327 // In such case, it should not be bounded. 25328 if (neightet.tet != dummytet) { 25329 dummytet[0] = encode(neightet); 25330 } 25331 } 25332 } 25333 } 25334 25336 // // 25337 // restorepolyhedron() Restore the tetrahedralization in a polyhedron. // 25338 // // 25339 // This routine is only called when the operation of suppressing a point is // 25340 // aborted (eg., findrelocatepoint() routine fails). The polyhedron has been // 25341 // remeshed by new tets. This routine restore the old tets in it. // 25342 // // 25343 // 'oldtetlist' contains the list of old tets. Each old tet t_o assumes that // 25344 // it still connects to a tet t_b of the mesh, however, t_b does not connect // 25345 // to t_o, this routine resets the connection such that t_b <--> t_o. // 25346 // // 25348 25349 void tetgenmesh::restorepolyhedron(list* oldtetlist) 25350 { 25351 triface oldtet, neightet, neineitet; 25352 face checksh; 25353 int i; 25354 25355 for (i = 0; i < oldtetlist->len(); i++) { 25356 // Get an old tet t_o. 25357 oldtet = * (triface *)(* oldtetlist)[i]; 25358 // Check the four sides of t_o. 25359 for (oldtet.loc = 0; oldtet.loc < 4; oldtet.loc++) { 25360 sym(oldtet, neightet); 25361 tspivot(oldtet, checksh); 25362 if (neightet.tet != dummytet) { 25363 sym(neightet, neineitet); 25364 if (neineitet.tet != oldtet.tet) { 25365 // This face of t_o is a boundary of P. 25366 bond(neightet, oldtet); 25367 if (checksh.sh != dummysh) { 25368 tsbond(oldtet, checksh); 25369 } 25370 } 25371 } else { 25372 // t_o has a hull face. It should be the boundary of P. 25373 #ifdef SELF_CHECK 25374 assert(checksh.sh != dummysh); 25375 stpivot(checksh, neineitet); 25376 assert(neineitet.tet != oldtet.tet); 25377 #endif 25378 tsbond(oldtet, checksh); 25379 // Let dummytet[0] points to it. 25380 dummytet[0] = encode(oldtet); 25381 } 25382 } 25383 } 25384 } 25385 25387 // // 25388 // suppressfacetpoint() Suppress a point inside a facet. // 25389 // // 25390 // The point p inside a facet F will be suppressed from F by either being // 25391 // deleted from the mesh or being relocated into the volume. // 25392 // // 25393 // 'supsh' is a subface f of F, and p = sapex(f); the other parameters are // 25394 // working lists which are empty at the beginning and the end. // 25395 // // 25396 // 'optflag' is used for mesh optimization. If it is set, after removing p, // 25397 // test the object function on each new tet, queue bad tets. // 25398 // // 25400 25401 bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist, 25402 list* misfrontlist, list* ptlist, list* conlist, memorypool* viri, 25403 queue* flipque, bool noreloc, bool optflag) 25404 { 25405 list *oldtetlist[2], *newtetlist[2]; 25406 list *oldshlist, *newshlist; 25407 triface oldtet, newtet; 25408 face oldsh, newsh; 25409 point suppt, newpt[2]; 25410 point *cons; 25411 REAL norm[3]; 25412 bool success; 25413 int shmark; 25414 int i, j; 25415 25416 suppt = sapex(*supsh); 25417 if (b->verbose > 1) { 25418 printf(" Suppress point %d in facet.\n", pointmark(suppt)); 25419 } 25420 25421 // Initialize working lists, variables. 25422 for (i = 0; i < 2; i++) { 25423 oldtetlist[i] = (list *) NULL; 25424 newtetlist[i] = (list *) NULL; 25425 newpt[i] = (point) NULL; 25426 } 25427 oldshlist = new list(sizeof(face), NULL, 256); 25428 newshlist = new list(sizeof(face), NULL, 256); 25429 success = true; // Assume p can be suppressed. 25430 25431 // Find subs of C(p). 25432 oldshlist->append(supsh); 25433 formstarpolygon(suppt, oldshlist, ptlist); 25434 // Get the edges of C(p). They form a closed polygon. 25435 for (i = 0; i < oldshlist->len(); i++) { 25436 oldsh = * (face *)(* oldshlist)[i]; 25437 cons = (point *) conlist->append(NULL); 25438 cons[0] = sorg(oldsh); 25439 cons[1] = sdest(oldsh); 25440 } 25441 // Re-triangulate the old C(p). 25442 shmark = shellmark(*supsh); 25443 triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque); 25444 // Get new subs of C(p), remove protected segments. 25445 retrievenewsubs(newshlist, true); 25446 // Substitute the old C(p) with the new C(p) 25447 replacepolygonsubs(oldshlist, newshlist); 25448 // Clear work lists. 25449 ptlist->clear(); 25450 conlist->clear(); 25451 flipque->clear(); 25452 viri->restart(); 25453 25454 // B(p) (tets with p as a vertex) has been separated into two parts 25455 // (B_0(p) and B_1(p)) by F. Process them individually. 25456 for (i = 0; i < 2 && success; i++) { 25457 if (i == 1) sesymself(*supsh); 25458 // Get a tet containing p. 25459 stpivot(*supsh, oldtet); 25460 // Is this part empty? 25461 if (oldtet.tet == dummytet) continue; 25462 // Allocate spaces for storing (old and new) B_i(p). 25463 oldtetlist[i] = new list(sizeof(triface), NULL, 256); 25464 newtetlist[i] = new list(sizeof(triface), NULL, 256); 25465 // Form old B_i(p) in oldtetlist[i]. 25466 assert(!isdead(&oldtet)); 25467 oldtetlist[i]->append(&oldtet); 25468 formstarpolyhedron(suppt, oldtetlist[i], ptlist, false); 25469 // Infect the tets in old B_i(p) (they're going to be delete). 25470 for (j = 0; j < oldtetlist[i]->len(); j++) { 25471 oldtet = * (triface *)(* (oldtetlist[i]))[j]; 25472 infect(oldtet); 25473 } 25474 // Preparation for re-tetrahedralzing old B_i(p). 25475 orientnewsubs(newshlist, supsh, norm); 25476 // Tetrahedralize old B_i(p). 25477 success = constrainedcavity(&oldtet, newshlist, oldtetlist[i], ptlist, 25478 frontlist, misfrontlist, newtetlist[i], flipque); 25479 // If p is not suppressed, do relocation if 'noreloc' is not set. 25480 if (!success && !noreloc) { 25481 // Try to relocate p into the old B_i(p). 25482 makepoint(&(newpt[i])); 25483 success = findrelocatepoint(suppt, newpt[i], norm, frontlist, 25484 oldtetlist[i]); 25485 // Initialize newpt = suppt. 25486 // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j]; 25487 // success = smoothvolpoint(newpt[i], frontlist, true); 25488 if (success) { 25489 // p is relocated by newpt[i]. Now insert it. Don't do flip since 25490 // the new tets may get deleted again. 25491 relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL); 25492 setpointtype(newpt[i], FREEVOLVERTEX); 25493 relverts++; 25494 } else { 25495 // Fail to relocate p. Clean fake tets and quit this option. 25496 deallocfaketets(frontlist); 25497 pointdealloc(newpt[i]); 25498 newpt[i] = (point) NULL; 25499 assert(newtetlist[i]->len() == 0); 25500 } 25501 } 25502 if (!success && noreloc) { 25503 // Failed and no point relocation. Clean fake tets. 25504 deallocfaketets(frontlist); 25505 } 25506 // Clear work lists. 25507 ptlist->clear(); 25508 frontlist->clear(); 25509 misfrontlist->clear(); 25510 flipque->clear(); 25511 } 25512 25513 if (success) { 25514 // p has been removed! (Still in the pool). 25515 setpointtype(suppt, UNUSEDVERTEX); 25516 unuverts++; 25517 // Delete old C(p). 25518 for (i = 0; i < oldshlist->len(); i++) { 25519 oldsh = * (face *)(* oldshlist)[i]; 25520 if (i == 0) { 25521 // Update the 'hullsize' if C(p) is on the hull. 25522 stpivot(oldsh, oldtet); 25523 if (oldtet.tet != dummytet) { 25524 sesymself(oldsh); 25525 stpivot(oldsh, oldtet); 25526 } 25527 if (oldtet.tet == dummytet) { 25528 // A boundary face. Update the 'hullsize'. 25529 j = oldshlist->len() - newshlist->len(); 25530 assert(j > 0); 25531 hullsize -= j; 25532 } 25533 } 25534 shellfacedealloc(subfaces, oldsh.sh); 25535 } 25536 // Delete old B_i(p). 25537 for (i = 0; i < 2; i++) { 25538 if (oldtetlist[i] != (list *) NULL) { 25539 // Delete tets of the old B_i(p). 25540 for (j = 0; j < oldtetlist[i]->len(); j++) { 25541 oldtet = * (triface *)(* (oldtetlist[i]))[j]; 25542 assert(!isdead(&oldtet)); 25543 tetrahedrondealloc(oldtet.tet); 25544 } 25545 } 25546 } 25547 if (optflag) { 25548 // Check for new bad-quality tets. 25549 for (i = 0; i < 2; i++) { 25550 if (newtetlist[i] != (list *) NULL) { 25551 for (j = 0; j < newtetlist[i]->len(); j++) { 25552 newtet = * (triface *)(* (newtetlist[i]))[j]; 25553 if (!isdead(&newtet)) checktet4opt(&newtet, true); 25554 } 25555 } 25556 } 25557 } 25558 } else { 25559 // p is not suppressed. Recover the original state. 25560 unsupverts++; 25561 // Restore the old C(p). 25562 replacepolygonsubs(newshlist, oldshlist); 25563 // Delete subs of the new C(p) 25564 for (i = 0; i < newshlist->len(); i++) { 25565 newsh = * (face *)(* newshlist)[i]; 25566 shellfacedealloc(subfaces, newsh.sh); 25567 } 25568 // Restore old B_i(p). 25569 for (i = 0; i < 2; i++) { 25570 if (oldtetlist[i] != (list *) NULL) { 25571 // Uninfect tets of old B_i(p). 25572 for (j = 0; j < oldtetlist[i]->len(); j++) { 25573 oldtet = * (triface *)(* (oldtetlist[i]))[j]; 25574 assert(infected(oldtet)); 25575 uninfect(oldtet); 25576 } 25577 // Has it been re-meshed? 25578 if (newtetlist[i]->len() > 0) { 25579 // Restore the old B_i(p). 25580 restorepolyhedron(oldtetlist[i]); 25581 // Delete tets of the new B_i(p); 25582 for (j = 0; j < newtetlist[i]->len(); j++) { 25583 newtet = * (triface *)(* (newtetlist[i]))[j]; 25584 // Some new tets may already be deleted (by carvecavity()). 25585 if (!isdead(&newtet)) { 25586 tetrahedrondealloc(newtet.tet); 25587 } 25588 } 25589 } 25590 // Dealloc newpt[i] if it exists. 25591 if (newpt[i] != (point) NULL) { 25592 pointdealloc(newpt[i]); 25593 relverts--; 25594 } 25595 } 25596 } 25597 } 25598 25599 // Delete work lists. 25600 delete oldshlist; 25601 delete newshlist; 25602 for (i = 0; i < 2; i++) { 25603 if (oldtetlist[i] != (list *) NULL) { 25604 delete oldtetlist[i]; 25605 delete newtetlist[i]; 25606 } 25607 } 25608 25609 return success; 25610 } 25611 25613 // // 25614 // suppresssegpoint() Suppress a point on a segment. // 25615 // // 25616 // The point p on a segment S will be suppressed from S by either being // 25617 // deleted from the mesh or being relocated into the volume. // 25618 // // 25619 // 'supseg' is the segment S, and p = sdest(S); the other parameters are // 25620 // working lists which are empty at the beginning and the end. // 25621 // // 25623 25624 bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist, 25625 list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist, 25626 list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag) 25627 { 25628 list **oldtetlist, **newtetlist; 25629 list **oldshlist, **newshlist; 25630 list *pnewshlist, *dnewshlist; 25631 triface oldtet, newtet; 25632 face oldsh, newsh; 25633 face startsh, spinsh, segsh1, segsh2; 25634 face nsupseg, newseg, prevseg, nextseg; 25635 point suppt, *newpt; 25636 point pa, pb, *cons; 25637 REAL pnorm[2][3], norm[3]; 25638 bool success; 25639 int shmark; 25640 int n, i, j, k; 25641 25642 // Get the Steiner point p. 25643 assert(supseg->shver < 2); 25644 suppt = sdest(*supseg); 25645 // Find the segment ab split by p. 25646 senext(*supseg, nsupseg); 25647 spivotself(nsupseg); 25648 assert(nsupseg.sh != dummysh); 25649 nsupseg.shver = 0; 25650 if (sorg(nsupseg) != suppt) sesymself(nsupseg); 25651 assert(sorg(nsupseg) == suppt); 25652 pa = sorg(*supseg); 25653 pb = sdest(nsupseg); 25654 if (b->verbose > 1) { 25655 printf(" Remove point %d on segment (%d, %d).\n", 25656 pointmark(suppt), pointmark(pa), pointmark(pb)); 25657 } 25658 25659 // Let startsh s containing p. 25660 spivot(*supseg, startsh); 25661 spinsh = startsh; 25662 do { 25663 // Save it in list. 25664 spinshlist->append(&spinsh); 25665 // Go to the next facet. 25666 spivotself(spinsh); 25667 } while (spinsh.sh != startsh.sh); 25668 if (spinshlist->len() == 1) { 25669 // This case has not handled yet. 25670 // printf("Unhandled case: segment only belongs to one facet.\n"); 25671 spinshlist->clear(); 25672 unsupverts++; 25673 return false; 25674 } 25675 25676 // Suppose ab is shared by n facets (n > 1), then there are n B(p) (tets 25677 // with p as a vertex). Some B(p) may be empty, eg, outside. 25678 n = spinshlist->len(); 25679 oldtetlist = new list*[n]; 25680 newtetlist = new list*[n]; 25681 oldshlist = new list*[n]; 25682 newshlist = new list*[n]; 25683 newpt = new point[n]; 25684 for (i = 0; i < n; i++) { 25685 oldtetlist[i] = (list *) NULL; 25686 newtetlist[i] = (list *) NULL; 25687 oldshlist[i] = (list *) NULL; 25688 newshlist[i] = (list *) NULL; 25689 newpt[i] = (point) NULL; 25690 } 25691 25692 // Create a new segment ab (result in newseg). 25693 makeshellface(subsegs, &newseg); 25694 setsorg(newseg, pa); 25695 setsdest(newseg, pb); 25696 // ab gets the same mark and segment type as ap. 25697 setshellmark(newseg, shellmark(*supseg)); 25698 setshelltype(newseg, shelltype(*supseg)); 25699 if (b->quality && varconstraint) { 25700 // Copy the areabound into the new subsegment. 25701 setareabound(newseg, areabound(*supseg)); 25702 } 25703 // Save the old connection at a. 25704 senext2(*supseg, prevseg); 25705 spivotself(prevseg); 25706 if (prevseg.sh != dummysh) { 25707 prevseg.shver = 0; 25708 if (sdest(prevseg) != pa) sesymself(prevseg); 25709 assert(sdest(prevseg) == pa); 25710 senextself(prevseg); 25711 senext2self(newseg); 25712 sbond(newseg, prevseg); 25713 newseg.shver = 0; 25714 } 25715 // Save the old connection at b. 25716 senext(nsupseg, nextseg); 25717 spivotself(nextseg); 25718 if (nextseg.sh != dummysh) { 25719 nextseg.shver = 0; 25720 if (sorg(nextseg) != pb) sesymself(nextseg); 25721 assert(sorg(nextseg) == pb); 25722 senext2self(nextseg); 25723 senextself(newseg); 25724 sbond(newseg, nextseg); 25725 newseg.shver = 0; 25726 } 25727 25728 // Re-triangulate C(p) (subs with p as a vertex) to remove p. 25729 for (i = 0; i < spinshlist->len(); i++) { 25730 spinsh = * (face *)(* spinshlist)[i]; 25731 // Allocate spaces for C_i(p). 25732 oldshlist[i] = new list(sizeof(face), NULL, 256); 25733 newshlist[i] = new list(sizeof(face), NULL, 256); 25734 // Get the subs of C_i(p). 25735 oldshlist[i]->append(&spinsh); 25736 formstarpolygon(suppt, oldshlist[i], ptlist); 25737 // Find the edges of C_i(p). It DOES NOT form a closed polygon. 25738 for (j = 0; j < oldshlist[i]->len(); j++) { 25739 oldsh = * (face *)(* (oldshlist[i]))[j]; 25740 cons = (point *) conlist->append(NULL); 25741 cons[0] = sorg(oldsh); 25742 cons[1] = sdest(oldsh); 25743 } 25744 // The C_i(p) isn't closed without ab. Add it to it. 25745 cons = (point *) conlist->append(NULL); 25746 cons[0] = pa; 25747 cons[1] = pb; 25748 // Re-triangulate C_i(p). 25749 shmark = shellmark(spinsh); 25750 triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque); 25751 // Get new subs of C_i(p), remove protected segments. 25752 retrievenewsubs(newshlist[i], true); 25753 // Substitute old C_i(p) with the new C_i(p). !IT IS NOT COMPLETE! 25754 replacepolygonsubs(oldshlist[i], newshlist[i]); 25755 // Find the new subface s having edge ab. 25756 for (j = 0; j < newshlist[i]->len(); j++) { 25757 segsh1 = * (face *)(* (newshlist[i]))[j]; 25758 for (k = 0; k < 3; k++) { 25759 if (((sorg(segsh1) == pa) && (sdest(segsh1) == pb)) || 25760 ((sorg(segsh1) == pb) && (sdest(segsh1) == pa))) break; 25761 senextself(segsh1); 25762 } 25763 if (k < 3) break; // Found. 25764 } 25765 assert(j < newshlist[i]->len()); // ab must exist. 25766 // Bond s and ab together. The C_i(p) is completedly substituted. 25767 ssbond(segsh1, newseg); 25768 // Save s for forming the face ring of ab. 25769 newsegshlist->append(&segsh1); 25770 // Clear work lists. 25771 ptlist->clear(); 25772 conlist->clear(); 25773 flipque->clear(); 25774 viri->restart(); 25775 } 25776 // Form the face ring of ab. 25777 for (i = 0; i < newsegshlist->len(); i++) { 25778 segsh1 = * (face *)(* newsegshlist)[i]; 25779 if ((i + 1) == newsegshlist->len()) { 25780 segsh2 = * (face *)(* newsegshlist)[0]; 25781 } else { 25782 segsh2 = * (face *)(* newsegshlist)[i + 1]; 25783 } 25784 sbond1(segsh1, segsh2); 25785 } 25786 25787 // A work list for keeping subfaces from two facets. 25788 dnewshlist = new list(sizeof(face), NULL, 256); 25789 success = true; // Assume p is suppressable. 25790 25791 // Suppress p in all B(p). B_i(p) is looped wrt the right-hand rule of ab. 25792 for (i = 0; i < spinshlist->len() && success; i++) { 25793 // Get an old subface s (ap) of a facet. 25794 spinsh = * (face *)(* spinshlist)[i]; 25795 // Let the edge direction of s be a->b. Hence all subfaces follow 25796 // the right-hand rule of ab. 25797 if (sorg(spinsh) != pa) sesymself(spinsh); 25798 // Get a tet t of B_i(p). 25799 stpivot(spinsh, oldtet); 25800 // Is B_i(p) empty? 25801 if (oldtet.tet == dummytet) continue; 25802 // Allocate spaces for B_i(p). 25803 oldtetlist[i] = new list(sizeof(triface), NULL, 256); 25804 newtetlist[i] = new list(sizeof(triface), NULL, 256); 25805 // Find all tets of old B_i(p). 25806 oldtetlist[i]->append(&oldtet); 25807 formstarpolyhedron(suppt, oldtetlist[i], ptlist, false); 25808 // Infect tets of old B_i(p) (they're going to be deleted). 25809 for (j = 0; j < oldtetlist[i]->len(); j++) { 25810 oldtet = * (triface *)(* (oldtetlist[i]))[j]; 25811 infect(oldtet); 25812 } 25813 // Collect new subfaces (of two facets) bounded B_i(p). 25814 for (k = 0; k < 2; k++) { 25815 if ((i + k) < spinshlist->len()) { 25816 pnewshlist = newshlist[i + k]; 25817 segsh1 = * (face *)(* spinshlist)[i + k]; 25818 } else { 25819 pnewshlist = newshlist[0]; 25820 segsh1 = * (face *)(* spinshlist)[0]; 25821 } 25822 // Adjust the orientation of segsh1 to face to the inside of C. 25823 if (k == 0) { 25824 if (sorg(segsh1) != pa) sesymself(segsh1); 25825 assert(sorg(segsh1) == pa); 25826 } else { 25827 if (sdest(segsh1) != pa) sesymself(segsh1); 25828 assert(sdest(segsh1) == pa); 25829 } 25830 // Preparation for re-tetrahedralzing old B_i(p). 25831 orientnewsubs(pnewshlist, &segsh1, pnorm[k]); 25832 for (j = 0; j < pnewshlist->len(); j++) { 25833 dnewshlist->append((face *)(* pnewshlist)[j]); 25834 } 25835 } 25836 // Tetrahedralize B_i(p). 25837 success = constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist, 25838 frontlist, misfrontlist, newtetlist[i], flipque); 25839 if (!success && !noreloc) { 25840 // C must be finished by re-locating the steiner point. 25841 makepoint(&(newpt[i])); 25842 for (j = 0; j < 3; j++) norm[j] = 0.5 * (pnorm[0][j] + pnorm[1][j]); 25843 success = findrelocatepoint(suppt, newpt[i], norm, frontlist, 25844 oldtetlist[i]); 25845 // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j]; 25846 // success = smoothvolpoint(newpt[i], frontlist, true); 25847 if (success) { 25848 // p is relocated by newpt[i]. Now insert it. Don't do flip since 25849 // the new tets may get deleted again. 25850 relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL); 25851 setpointtype(newpt[i], FREEVOLVERTEX); 25852 relverts++; 25853 } else { 25854 // Fail to relocate p. Clean fake tets and quit this option. 25855 deallocfaketets(frontlist); 25856 pointdealloc(newpt[i]); 25857 newpt[i] = (point) NULL; 25858 assert(newtetlist[i]->len() == 0); 25859 } 25860 } 25861 if (!success && noreloc) { 25862 // Failed and no point relocation. Clean fake tets. 25863 deallocfaketets(frontlist); 25864 } 25865 // Clear work lists. 25866 dnewshlist->clear(); 25867 ptlist->clear(); 25868 frontlist->clear(); 25869 misfrontlist->clear(); 25870 flipque->clear(); 25871 } 25872 25873 if (success) { 25874 // p has been suppressed. (Still in the pool). 25875 setpointtype(suppt, UNUSEDVERTEX); 25876 unuverts++; 25877 // Update the segmnet pointers saved in a and b. 25878 setpoint2sh(pa, sencode(newseg)); 25879 setpoint2sh(pb, sencode(newseg)); 25880 // Delete old segments ap, pb. 25881 shellfacedealloc(subsegs, supseg->sh); 25882 shellfacedealloc(subsegs, nsupseg.sh); 25883 // Delete subs of old C_i(p). 25884 for (i = 0; i < spinshlist->len(); i++) { 25885 for (j = 0; j < oldshlist[i]->len(); j++) { 25886 oldsh = * (face *)(* (oldshlist[i]))[j]; 25887 if (j == 0) { 25888 // Update 'hullsize' if C_i(p) is on the hull. 25889 stpivot(oldsh, oldtet); 25890 if (oldtet.tet != dummytet) { 25891 sesymself(oldsh); 25892 stpivot(oldsh, oldtet); 25893 } 25894 if (oldtet.tet == dummytet) { 25895 // Update 'hullsize'. 25896 k = oldshlist[i]->len() - newshlist[i]->len(); 25897 assert(k > 0); 25898 hullsize -= k; 25899 } 25900 } 25901 shellfacedealloc(subfaces, oldsh.sh); 25902 } 25903 } 25904 // Delete tets old B_i(p). 25905 for (i = 0; i < spinshlist->len(); i++) { 25906 // Delete them if it is not empty. 25907 if (oldtetlist[i] != (list *) NULL) { 25908 for (j = 0; j < oldtetlist[i]->len(); j++) { 25909 oldtet = * (triface *)(* (oldtetlist[i]))[j]; 25910 assert(!isdead(&oldtet)); 25911 tetrahedrondealloc(oldtet.tet); 25912 } 25913 } 25914 } 25915 if (optflag) { 25916 for (i = 0; i < spinshlist->len(); i++) { 25917 // Check for new bad-quality tets. 25918 if (newtetlist[i] != (list *) NULL) { 25919 for (j = 0; j < newtetlist[i]->len(); j++) { 25920 newtet = * (triface *)(* (newtetlist[i]))[j]; 25921 if (!isdead(&newtet)) checktet4opt(&newtet, true); 25922 } 25923 } 25924 } 25925 } 25926 } else { 25927 // p is not suppressed. Recover the original state. 25928 unsupverts++; 25929 // Restore old connection at a. 25930 senext2(*supseg, prevseg); 25931 spivotself(prevseg); 25932 if (prevseg.sh != dummysh) { 25933 prevseg.shver = 0; 25934 if (sdest(prevseg) != pa) sesymself(prevseg); 25935 assert(sdest(prevseg) == pa); 25936 senextself(prevseg); 25937 senext2self(*supseg); 25938 sbond(*supseg, prevseg); 25939 senextself(*supseg); // Restore original state. 25940 assert(supseg->shver < 2); 25941 } 25942 // Restore old connection at b. 25943 senext(nsupseg, nextseg); 25944 spivotself(nextseg); 25945 if (nextseg.sh != dummysh) { 25946 nextseg.shver = 0; 25947 if (sorg(nextseg) != pb) sesymself(nextseg); 25948 assert(sorg(nextseg) == pb); 25949 senext2self(nextseg); 25950 senextself(nsupseg); 25951 sbond(nsupseg, nextseg); 25952 // nsupseg.shver = 0; 25953 senext2self(nsupseg); // Restore original state 25954 assert(nsupseg.shver < 2); 25955 } 25956 // Delete the new segment ab. 25957 shellfacedealloc(subsegs, newseg.sh); 25958 // Restore old C_i(p). 25959 for (i = 0; i < spinshlist->len(); i++) { 25960 replacepolygonsubs(newshlist[i], oldshlist[i]); 25961 // Delete subs of the new C_i(p) 25962 for (j = 0; j < newshlist[i]->len(); j++) { 25963 newsh = * (face *)(* (newshlist[i]))[j]; 25964 shellfacedealloc(subfaces, newsh.sh); 25965 } 25966 } 25967 // Restore old B_i(p). 25968 for (i = 0; i < spinshlist->len(); i++) { 25969 if (oldtetlist[i] != (list *) NULL) { 25970 // Uninfect tets of old B_i(p). 25971 for (j = 0; j < oldtetlist[i]->len(); j++) { 25972 oldtet = * (triface *)(* (oldtetlist[i]))[j]; 25973 assert(infected(oldtet)); 25974 uninfect(oldtet); 25975 } 25976 // Has it been re-meshed? 25977 if (newtetlist[i]->len() > 0) { 25978 // Restore the old B_i(p). 25979 restorepolyhedron(oldtetlist[i]); 25980 // Delete tets of the new B_i(p); 25981 for (j = 0; j < newtetlist[i]->len(); j++) { 25982 newtet = * (triface *)(* (newtetlist[i]))[j]; 25983 // Some new tets may already be deleted (by carvecavity()). 25984 if (!isdead(&newtet)) { 25985 tetrahedrondealloc(newtet.tet); 25986 } 25987 } 25988 } 25989 // Dealloc newpt[i] if it exists. 25990 if (newpt[i] != (point) NULL) { 25991 pointdealloc(newpt[i]); 25992 relverts--; 25993 } 25994 } 25995 } 25996 } 25997 25998 // Delete work lists. 25999 delete dnewshlist; 26000 for (i = 0; i < spinshlist->len(); i++) { 26001 delete oldshlist[i]; 26002 delete newshlist[i]; 26003 } 26004 delete [] oldshlist; 26005 delete [] newshlist; 26006 for (i = 0; i < spinshlist->len(); i++) { 26007 if (oldtetlist[i] != (list *) NULL) { 26008 delete oldtetlist[i]; 26009 delete newtetlist[i]; 26010 } 26011 } 26012 delete [] oldtetlist; 26013 delete [] newtetlist; 26014 // Clear work lists. 26015 newsegshlist->clear(); 26016 spinshlist->clear(); 26017 26018 return success; 26019 } 26020 26022 // // 26023 // suppressvolpoint() Suppress a point inside mesh. // 26024 // // 26025 // The point p = org(suptet) is inside the mesh and will be suppressed from // 26026 // the mesh. Note that p may not be suppressed. // 26027 // // 26028 // 'optflag' is used for mesh optimization. If it is set, after removing p, // 26029 // test the object function on each new tet, queue bad tets. // 26030 // // 26032 26033 bool tetgenmesh::suppressvolpoint(triface* suptet, list* frontlist, 26034 list* misfrontlist, list* ptlist, queue* flipque, bool optflag) 26035 { 26036 list *myfrontlist, *mymisfrontlist, *myptlist; 26037 list *oldtetlist, *newtetlist; 26038 list *newshlist; // a dummy list. 26039 queue *myflipque; 26040 triface oldtet, newtet; 26041 point suppt, conpt; 26042 bool success; 26043 int j; 26044 26045 // Allocate spaces for storing (old and new) B(p). 26046 oldtetlist = new list(sizeof(triface), NULL, 256); 26047 newtetlist = new list(sizeof(triface), NULL, 256); 26048 newshlist = new list(sizeof(face), NULL, 256); 26049 // Allocate work lists if user doesn't supply them. 26050 myfrontlist = mymisfrontlist = myptlist = (list *) NULL; 26051 myflipque = (queue *) NULL; 26052 if (frontlist == (list *) NULL) { 26053 myfrontlist = new list(sizeof(triface), NULL, 256); 26054 frontlist = myfrontlist; 26055 mymisfrontlist = new list(sizeof(triface), NULL, 256); 26056 misfrontlist = mymisfrontlist; 26057 myptlist = new list(sizeof(point *), NULL, 256); 26058 ptlist = myptlist; 26059 myflipque = new queue(sizeof(badface)); 26060 flipque = myflipque; 26061 } 26062 26063 suppt = org(*suptet); 26064 oldtet = *suptet; 26065 success = true; // Assume p can be suppressed. 26066 26067 if (b->verbose > 1) { 26068 printf(" Remove point %d in mesh.\n", pointmark(suppt)); 26069 } 26070 26071 // Form old B(p) in oldtetlist. 26072 oldtetlist->append(&oldtet); 26073 formstarpolyhedron(suppt, oldtetlist, ptlist, false); 26074 // Infect the tets in old B(p) (they're going to be delete). 26075 for (j = 0; j < oldtetlist->len(); j++) { 26076 oldtet = * (triface *)(* oldtetlist)[j]; 26077 infect(oldtet); 26078 } 26079 // Tetrahedralize old B(p). 26080 success = constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist, 26081 frontlist, misfrontlist, newtetlist, flipque); 26082 if (!success) { 26083 // Unable to suppress p. 26084 deallocfaketets(frontlist); 26085 // Try to collapse an edge at p. 26086 conpt = (point) NULL; 26087 assert(newtetlist->len() == 0); 26088 if (findcollapseedge(suppt, &conpt, oldtetlist, ptlist)) { 26089 // Collapse the edge suppt->conpt. Re-use newtetlist. 26090 collapseedge(suppt, conpt, oldtetlist, newtetlist); 26091 // The oldtetlist contains newtetlist. 26092 if (optflag) { 26093 assert(newtetlist->len() == 0); 26094 for (j = 0; j < oldtetlist->len(); j++) { 26095 newtet = * (triface *)(* oldtetlist)[j]; 26096 newtetlist->append(&newtet); 26097 } 26098 } 26099 oldtetlist->clear(); // Do not delete them. 26100 collapverts++; 26101 success = true; 26102 } 26103 } 26104 if (success) { 26105 // p has been removed! (Still in the pool). 26106 setpointtype(suppt, UNUSEDVERTEX); 26107 unuverts++; 26108 suprelverts++; 26109 // Delete old B(p). 26110 for (j = 0; j < oldtetlist->len(); j++) { 26111 oldtet = * (triface *)(* oldtetlist)[j]; 26112 assert(!isdead(&oldtet)); 26113 tetrahedrondealloc(oldtet.tet); 26114 } 26115 if (optflag) { 26116 // Check for new bad tets. 26117 for (j = 0; j < newtetlist->len(); j++) { 26118 newtet = * (triface *)(* newtetlist)[j]; 26119 if (!isdead(&newtet)) checktet4opt(&newtet, true); 26120 } 26121 } 26122 } else { 26123 // p is not suppressed. Recover the original state. 26124 // Uninfect tets of old B(p). 26125 for (j = 0; j < oldtetlist->len(); j++) { 26126 oldtet = * (triface *)(* oldtetlist)[j]; 26127 assert(infected(oldtet)); 26128 uninfect(oldtet); 26129 } 26130 } 26131 26132 // Clear work lists. 26133 ptlist->clear(); 26134 frontlist->clear(); 26135 misfrontlist->clear(); 26136 flipque->clear(); 26137 // Deallocate work lists. 26138 if (myfrontlist != (list *) NULL) { 26139 delete myfrontlist; 26140 delete mymisfrontlist; 26141 delete myptlist; 26142 delete myflipque; 26143 } 26144 delete oldtetlist; 26145 delete newtetlist; 26146 delete newshlist; 26147 26148 return success; 26149 } 26150 26152 // // 26153 // smoothpoint() Smooth a volume/segment point. // 26154 // // 26155 // 'smthpt' (p) is inside the polyhedron (C) bounded by faces in 'starlist'. // 26156 // This routine moves p inside C until an object function is maximized. // 26157 // // 26158 // Default, the CCW edge ring of the faces on C points to p. If 'invtori' is // 26159 // TRUE, the orientation is inversed. // 26160 // // 26161 // If 'key' != NULL, it contains an object value to be improved. Current it // 26162 // means the cosine of the largest dihedral angle. In such case, the point // 26163 // is smoothed only if the final configuration improves the object value, it // 26164 // is returned by the 'key'. // 26165 // // 26167 26168 bool tetgenmesh::smoothpoint(point smthpt, point e1, point e2, list *starlist, 26169 bool invtori, REAL *key) 26170 { 26171 triface starttet; 26172 point pa, pb, pc; 26173 REAL fcent[3], startpt[3], nextpt[3], bestpt[3]; 26174 REAL iniTmax, oldTmax, newTmax; 26175 REAL ori, aspT, aspTmax, imprate; 26176 REAL cosd, maxcosd; 26177 bool segflag, randflag; //, subflag; 26178 int numdirs; 26179 int iter, i, j; 26180 26181 // Is p a segment vertex? 26182 segflag = (e1 != (point) NULL); 26183 // Decide the number of moving directions. 26184 numdirs = segflag ? 2 : starlist->len(); 26185 randflag = numdirs > 10; 26186 if (randflag) { 26187 numdirs = 10; // Maximum 10 directions. 26188 } 26189 26190 aspTmax = 0.0; 26191 // Calculate the initial object value (the largest aspect ratio). 26192 for (i = 0; i < starlist->len(); i++) { 26193 starttet = * (triface *)(* starlist)[i]; 26194 adjustedgering(starttet, !invtori ? CCW : CW); 26195 pa = org(starttet); 26196 pb = dest(starttet); 26197 pc = apex(starttet); 26198 aspT = tetaspectratio(pa, pb, pc, smthpt); 26199 if (i == 0) { 26200 aspTmax = aspT; 26201 } else { 26202 aspTmax = aspT > aspTmax ? aspT : aspTmax; 26203 } 26204 } 26205 iniTmax = aspTmax; 26206 26207 if (b->verbose > 1) { 26208 printf(" Smooth %s point %d (%g, %g, %g).\n", segflag ? "seg" : "vol", 26209 pointmark(smthpt), smthpt[0], smthpt[1], smthpt[2]); 26210 printf(" Initial max L/h = %g.\n", iniTmax); 26211 } 26212 for (i = 0; i < 3; i++) { 26213 bestpt[i] = startpt[i] = smthpt[i]; 26214 } 26215 26216 // Do iteration until the new aspTmax does not decrease. 26217 newTmax = iniTmax; 26218 iter = 0; 26219 while (true) { 26220 // Find the best next location. 26221 oldTmax = newTmax; 26222 for (i = 0; i < numdirs; i++) { 26223 // Calculate the moved point (saved in 'nextpt'). 26224 if (!segflag) { 26225 if (randflag) { 26226 // Randomly pick a direction. 26227 j = (int) randomnation(starlist->len()); 26228 } else { 26229 j = i; 26230 } 26231 starttet = * (triface *)(* starlist)[j]; 26232 adjustedgering(starttet, !invtori ? CCW : CW); 26233 pa = org(starttet); 26234 pb = dest(starttet); 26235 pc = apex(starttet); 26236 for (j = 0; j < 3; j++) { 26237 fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0; 26238 } 26239 } else { 26240 for (j = 0; j < 3; j++) { 26241 fcent[j] = (i == 0 ? e1[j] : e2[j]); 26242 } 26243 } 26244 for (j = 0; j < 3; j++) { 26245 nextpt[j] = startpt[j] + 0.01 * (fcent[j] - startpt[j]); 26246 } 26247 // Get the largest object value for the new location. 26248 for (j = 0; j < starlist->len(); j++) { 26249 starttet = * (triface *)(* starlist)[j]; 26250 adjustedgering(starttet, !invtori ? CCW : CW); 26251 pa = org(starttet); 26252 pb = dest(starttet); 26253 pc = apex(starttet); 26254 ori = orient3d(pa, pb, pc, nextpt); 26255 if (ori < 0.0) { 26256 aspT = tetaspectratio(pa, pb, pc, nextpt); 26257 if (j == 0) { 26258 aspTmax = aspT; 26259 } else { 26260 aspTmax = aspT > aspTmax ? aspT : aspTmax; 26261 } 26262 } else { 26263 // An invalid new tet. Discard this point. 26264 aspTmax = newTmax; 26265 } // if (ori < 0.0) 26266 // Stop looping when the object value is bigger than before. 26267 if (aspTmax >= newTmax) break; 26268 } // for (j = 0; j < starlist->len(); j++) 26269 if (aspTmax < newTmax) { 26270 // Save the improved object value and the location. 26271 newTmax = aspTmax; 26272 for (j = 0; j < 3; j++) bestpt[j] = nextpt[j]; 26273 } 26274 } // for (i = 0; i < starlist->len(); i++) 26275 // Does the object value improved much? 26276 imprate = fabs(oldTmax - newTmax) / oldTmax; 26277 if (imprate < 1e-3) break; 26278 // Yes, move p to the new location and continue. 26279 for (j = 0; j < 3; j++) startpt[j] = bestpt[j]; 26280 iter++; 26281 } // while (true) 26282 26283 if (iter > 0) { 26284 // The point is moved. 26285 if (key) { 26286 // Check if the quality is improved by the smoothed point. 26287 maxcosd = 0.0; // = cos(90). 26288 for (j = 0; j < starlist->len(); j++) { 26289 starttet = * (triface *)(* starlist)[j]; 26290 adjustedgering(starttet, !invtori ? CCW : CW); 26291 pa = org(starttet); 26292 pb = dest(starttet); 26293 pc = apex(starttet); 26294 tetalldihedral(pa, pb, pc, startpt, NULL, &cosd, NULL); 26295 if (cosd < *key) { 26296 // This quality will not be improved. Stop. 26297 iter = 0; break; 26298 } else { 26299 // Remeber the worst quality value (of the new configuration). 26300 maxcosd = maxcosd < cosd ? maxcosd : cosd; 26301 } 26302 } 26303 if (iter > 0) *key = maxcosd; 26304 } 26305 } 26306 26307 if (iter > 0) { 26308 segflag ? smoothsegverts++ : smoothvolverts++; 26309 for (i = 0; i < 3; i++) smthpt[i] = startpt[i]; 26310 if (b->verbose > 1) { 26311 printf(" Move to new location (%g, %g, %g).\n", smthpt[0], smthpt[1], 26312 smthpt[2]); 26313 printf(" Final max L/h = %g. (%d iterations)\n", newTmax, iter); 26314 if (key) { 26315 printf(" Max. dihed = %g (degree).\n", acos(*key) / PI * 180.0); 26316 } 26317 } 26318 return true; 26319 } else { 26320 if (b->verbose > 1) { 26321 printf(" Not smoothed.\n"); 26322 } 26323 return false; 26324 } 26325 } 26326 26328 // // 26329 // removesteiners() Delete or relocate Steiner points on facets. // 26330 // // 26332 26333 void tetgenmesh::removesteiners(bool coarseflag) 26334 { 26335 list *frontlist, *misfrontlist; 26336 list *spinshlist, *newsegshlist; 26337 list *ptlist, *conlist; 26338 memorypool *viri; 26339 queue *flipque; 26340 triface checktet; 26341 face shloop; 26342 face segloop, nextseg; 26343 point pa, neipt; 26344 REAL len; 26345 bool remflag; 26346 int *worklist; 26347 int oldnum, rmstein; 26348 int i, j; 26349 26350 if (!b->quiet) { 26351 if (!coarseflag) { 26352 printf("Removing Steiner points.\n"); 26353 } else { 26354 printf("Coarsening mesh.\n"); 26355 } 26356 } 26357 26358 // Initialize work lists. 26359 frontlist = new list(sizeof(triface), NULL); 26360 misfrontlist = new list(sizeof(triface), NULL); 26361 spinshlist = new list(sizeof(face), NULL); 26362 newsegshlist = new list(sizeof(face), NULL); 26363 ptlist = new list(sizeof(point *), NULL); 26364 conlist = new list(sizeof(point *) * 2, NULL); 26365 flipque = new queue(sizeof(badface)); 26366 viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0); 26367 oldnum = unuverts; 26368 relverts = suprelverts = collapverts = unsupverts; 26369 smoothvolverts = 0; 26370 expcavcount = 0; 26371 26372 // Suppress Steiner points inside facets. 26373 do { 26374 rmstein = unuverts; 26375 subfaces->traversalinit(); 26376 shloop.sh = shellfacetraverse(subfaces); 26377 while (shloop.sh != (shellface *) NULL) { 26378 remflag = false; 26379 // Is s contains a Steiner point? 26380 shloop.shver = 0; 26381 for (i = 0; i < 3; i++) { 26382 pa = sapex(shloop); 26383 if (pointtype(pa) == FREESUBVERTEX) { 26384 if (!coarseflag) { 26385 // Remove it if it is not an input point. 26386 j = pointmark(pa) - in->firstnumber; 26387 if (j >= in->numberofpoints) { 26388 if (b->nobisect == 1) { 26389 // '-Y'. Remove p if s is a hull face. 26390 stpivot(shloop, checktet); 26391 if (checktet.tet != dummytet) { 26392 sesymself(shloop); 26393 stpivot(shloop, checktet); 26394 } 26395 remflag = (checktet.tet == dummytet); 26396 } else { 26397 // '-YY'. Remove p whatever s is a hull face or not. 26398 remflag = true; 26399 } 26400 } 26401 } else { 26402 // Check if this vertex can be coarsed. 26403 if (b->nobisect == 0) { 26404 // Is a background mesh available? 26405 if (b->metric) { 26406 // assert(pa[pointmtrindex] > 0.0); 26407 // Form the star of pa. 26408 spinshlist->append(&shloop); 26409 formstarpolygon(pa, spinshlist, ptlist); 26410 len = 0.0; 26411 for (j = 0; j < ptlist->len(); j++) { 26412 neipt = * (point *)(* ptlist)[j]; 26413 len += distance(pa, neipt); 26414 } 26415 len /= ptlist->len(); 26416 // Carse it if the average edge length is small. 26417 remflag = len < pa[pointmtrindex]; 26418 spinshlist->clear(); 26419 ptlist->clear(); 26420 } else { 26421 // Coarse it if (1) it is an input point and its pointmarker 26422 // is zero, or (2) it is a Steiner point. 26423 remflag = true; 26424 j = pointmark(pa) - in->firstnumber; 26425 if (j < in->numberofpoints) { 26426 remflag = (in->pointmarkerlist[j] == 0); 26427 } 26428 } // if (b->metric) 26429 } // if (b->nobisect == 0) 26430 } // if (!coarseflag) 26431 if (remflag) break; 26432 } // if (pointtype(pa) == FREESUBVERTEX) 26433 senextself(shloop); 26434 } // for (i = 0; i < 3; i++) 26435 if (remflag) { 26436 suppressfacetpoint(&shloop, frontlist, misfrontlist, ptlist, conlist, 26437 viri, flipque, coarseflag, false); 26438 } 26439 shloop.sh = shellfacetraverse(subfaces); 26440 } 26441 // Continue if any Steiner point has been removed. 26442 } while (unuverts > rmstein); 26443 26444 if (coarseflag) { 26445 shellface **segsperverlist; 26446 int *idx2seglist; 26447 face seg1, seg2; 26448 point e1, e2; 26449 // Connecting collinear segments. Hence the segment vertices may be 26450 // removed. In fact, this should be done by reconstructmesh(). 26451 makesegmentmap(idx2seglist, segsperverlist); 26452 subsegs->traversalinit(); 26453 segloop.sh = shellfacetraverse(subsegs); 26454 while (segloop.sh != (shellface *) NULL) { 26455 for (i = 0; i < 2; i++) { 26456 segloop.shver = i; 26457 senext(segloop, nextseg); 26458 spivotself(nextseg); 26459 if ((nextseg.sh == dummysh) || (nextseg.sh > segloop.sh)) { 26460 // No neighbor segment connection or haven't been processed yet. 26461 pa = sdest(segloop); 26462 j = pointmark(pa) - in->firstnumber; 26463 if (idx2seglist[j + 1] - idx2seglist[j] == 2) { 26464 // pa is shared by only two segments. Get the other one. 26465 nextseg.sh = segsperverlist[idx2seglist[j]]; 26466 if (nextseg.sh == segloop.sh) { 26467 nextseg.sh = segsperverlist[idx2seglist[j] + 1]; 26468 } 26469 nextseg.shver = 0; 26470 if (sorg(nextseg) != pa) sesymself(nextseg); 26471 // Check if the two segments are collinear. 26472 e1 = sorg(segloop); 26473 e2 = sdest(nextseg); 26474 if (iscollinear(e1, pa, e2, b->epsilon)) { 26475 // Connect the two segments together. 26476 if (b->verbose > 1) { 26477 printf(" Glue two insegs (%d, %d) at %d.\n", pointmark(e1), 26478 pointmark(e2), pointmark(pa)); 26479 } 26480 senext(segloop, seg1); 26481 senext2(nextseg, seg2); 26482 sbond(seg1, seg2); 26483 } 26484 } 26485 } // if (nextseg.sh == dummysh) 26486 } // for (i = 0; 26487 segloop.sh = shellfacetraverse(subsegs); 26488 } 26489 delete [] segsperverlist; 26490 delete [] idx2seglist; 26491 } 26492 26493 // Suppress Steiner points on segments. 26494 do { 26495 rmstein = unuverts; 26496 subsegs->traversalinit(); 26497 segloop.sh = shellfacetraverse(subsegs); 26498 while (segloop.sh != (shellface *) NULL) { 26499 remflag = false; 26500 // for (i = 0; i < 2; i++) { 26501 // Don't check the poinytype of pa, it may be a Steiner point but 26502 // has type NACUTEVERTEX due to splitting a type-3 segment. 26503 segloop.shver = 0; // segloop.shver = i; 26504 senext(segloop, nextseg); 26505 spivotself(nextseg); 26506 if (nextseg.sh != dummysh) { 26507 pa = sdest(segloop); // p is going to be checked for removal. 26508 nextseg.shver = 0; 26509 if (sorg(nextseg) != pa) sesymself(nextseg); 26510 assert(sorg(nextseg) == pa); 26511 if (!coarseflag) { 26512 // try to remove it if it is not an input point. 26513 j = pointmark(pa) - in->firstnumber; 26514 if (j >= in->numberofpoints) { 26515 if (b->nobisect == 1) { 26516 // '-Y'. Remove p if it is on the hull. 26517 sstpivot(&segloop, &checktet); 26518 assert(checktet.tet != dummytet); 26519 pa = apex(checktet); 26520 do { 26521 if (!fnextself(checktet)) { 26522 // Meet a boundary face - p is on the hull. 26523 remflag = true; break; 26524 } 26525 } while (pa != apex(checktet)); 26526 } else { 26527 // '-YY'. Remove p whatever it is on the hull or not. 26528 remflag = true; 26529 } 26530 } 26531 } else { 26532 // Check if this vertex can be coarsed. 26533 if (b->nobisect == 0) { 26534 if (b->metric) { 26535 // assert(pa[pointmtrindex] > 0.0); 26536 len = 0.0; 26537 neipt = sorg(segloop); 26538 for (j = 0; j < 2; j++) { 26539 len += distance(pa, neipt); 26540 /*// Is neipt inside the sparse ball of pa? 26541 if (len < pa[pointmtrindex]) { 26542 // Yes, the local of pa is too dense, corse it. 26543 remflag = true; break; 26544 } */ 26545 neipt = sdest(nextseg); 26546 } 26547 len /= 2.0; 26548 // Carse it if the average edge lengh is small. 26549 remflag = len < pa[pointmtrindex]; 26550 } else { 26551 // Coarse it if (1) it is an input point and its pointmarker 26552 // is zero, or (2) it is a Steiner point. 26553 remflag = true; 26554 j = pointmark(pa) - in->firstnumber; 26555 if (j < in->numberofpoints) { 26556 remflag = (in->pointmarkerlist[j] == 0); 26557 } 26558 } // if (b->metric) 26559 } // if (b->nobisect == 0) 26560 } // if (!coarseflag) 26561 } // if (nextseg.sh != dummysh) 26562 // if (remflag) break; 26563 // } // for (i = 0; i < 2; i++) 26564 if (remflag) { 26565 suppresssegpoint(&segloop, spinshlist, newsegshlist, frontlist, 26566 misfrontlist, ptlist, conlist, viri, flipque, coarseflag, false); 26567 } 26568 segloop.sh = shellfacetraverse(subsegs); 26569 } 26570 // Continue if any Steiner point has been removed. 26571 } while (unuverts > rmstein); 26572 26573 if ((relverts > 0) || coarseflag) { 26574 worklist = new int[points->items + 1]; 26575 // Suppress relocated points & coarse free mesh points. 26576 do { 26577 // Initialize the work list. Each entry of the list counts how many 26578 // times the point has been processed. 26579 for (i = 0; i < points->items + 1; i++) worklist[i] = 0; 26580 rmstein = unuverts; 26581 tetrahedrons->traversalinit(); 26582 checktet.tet = tetrahedrontraverse(); 26583 while (checktet.tet != (tetrahedron *) NULL) { 26584 remflag = false; 26585 for (i = 0; i < 4; i++) { 26586 pa = (point) checktet.tet[4 + i]; 26587 if (pointtype(pa) == FREEVOLVERTEX) { 26588 // NOTE. Chenge the number 3 will change the number n of removed 26589 // Steiner points. In my test, n is larger when it is 1. 3 26590 // reduces n in a reasonable way (see example, mech_part, 26591 // thepart), 5 results a larger n than 3 does. While the best 26592 // result is no limit of this number, but it makes the code 26593 // extremely slow. 26594 if (worklist[pointmark(pa)] < 3) { 26595 worklist[pointmark(pa)]++; 26596 if (!coarseflag) { 26597 // Remove p if it is a Steiner point. 26598 if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) { 26599 remflag = true; 26600 } 26601 } else { 26602 if (b->metric) { 26603 // assert(pa[pointmtrindex] > 0.0); 26604 // Form the star of pa. 26605 frontlist->append(&checktet); 26606 formstarpolyhedron(pa, frontlist, ptlist, true); 26607 len = 0.0; 26608 for (j = 0; j < ptlist->len(); j++) { 26609 neipt = * (point *)(* ptlist)[j]; 26610 len += distance(pa, neipt); 26611 } 26612 len /= ptlist->len(); 26613 // Carse it if the average edge length is small. 26614 remflag = len < pa[pointmtrindex]; 26615 frontlist->clear(); 26616 ptlist->clear(); 26617 } else { 26618 // Coarse it if (1) it is an input point and its pointmarker 26619 // is zero, or (2) it is a Steiner point. 26620 remflag = true; 26621 j = pointmark(pa) - in->firstnumber; 26622 if (j < in->numberofpoints) { 26623 remflag = (in->pointmarkerlist[j] == 0); 26624 } 26625 } // if (b->metric) 26626 } // if (!coarseflag) 26627 if (remflag) break; 26628 } // if (worklist[pointmark(pa)] == 0) 26629 } // if (pointtype(pa) == FREEVOLVERTEX) 26630 } // for (i = 0; i < 4; i++) 26631 if (remflag) { 26632 findorg(&checktet, pa); 26633 assert(org(checktet) == pa); 26634 suppressvolpoint(&checktet, frontlist, misfrontlist, ptlist, flipque, 26635 false); 26636 } 26637 checktet.tet = tetrahedrontraverse(); 26638 } 26639 // Continue if any relocated point has been suppressed. 26640 } while (unuverts > rmstein); 26641 26642 26643 // Smooth the unsuppressed points if it is not coarse mesh. 26644 if (!coarseflag && (relverts > suprelverts)) { 26645 if (b->verbose) { 26646 printf(" Smoothing relocated points.\n"); 26647 } 26648 for (i = 0; i < points->items + 1; i++) worklist[i] = 0; 26649 tetrahedrons->traversalinit(); 26650 checktet.tet = tetrahedrontraverse(); 26651 while (checktet.tet != (tetrahedron *) NULL) { 26652 for (i = 0; i < 4; i++) { 26653 pa = (point) checktet.tet[4 + i]; 26654 if (pointtype(pa) == FREEVOLVERTEX) { 26655 if (worklist[pointmark(pa)] == 0) { 26656 worklist[pointmark(pa)] = 1; 26657 if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) { 26658 // Smooth pa. 26659 findorg(&checktet, pa); 26660 frontlist->append(&checktet); 26661 formstarpolyhedron(pa, frontlist, NULL, false); 26662 smoothpoint(pa, NULL, NULL, frontlist, false, NULL); 26663 frontlist->clear(); 26664 } 26665 } // if (worklist[pointmark(pa)] == 0) 26666 } // if (pointtype(pa) == FREEVOLVERTEX) 26667 } // for (i = 0; i < 4; i++) 26668 checktet.tet = tetrahedrontraverse(); 26669 } 26670 } 26671 delete [] worklist; 26672 } 26673 26674 if (b->verbose > 0) { 26675 if (!coarseflag) { 26676 printf(" %d points removed from boundary", unuverts - oldnum); 26677 if (expcavcount > 0) { 26678 printf(" (%d cavity corrections)", expcavcount); 26679 } 26680 printf("\n"); 26681 if (relverts > 0) { 26682 printf(" %d points relocated (%d suppressed, %d collapsed).\n", 26683 relverts, suprelverts - collapverts, collapverts); 26684 if (smoothvolverts > 0) { 26685 printf(" %d points are smoothed.\n", smoothvolverts); 26686 } 26687 } 26688 if (unsupverts > 0) { 26689 printf(" !! %d points are unsuppressed.\n", unsupverts); 26690 } 26691 } else { 26692 printf(" %d points are removed.\n", unuverts - oldnum); 26693 } 26694 } 26695 26696 // Delete work lists. 26697 delete frontlist; 26698 delete misfrontlist; 26699 delete spinshlist; 26700 delete newsegshlist; 26701 delete ptlist; 26702 delete conlist; 26703 delete flipque; 26704 delete viri; 26705 } 26706 26707 // 26708 // End of boundary Steiner points removing routines 26709 // 26710 26712 // // 26713 // reconstructmesh() Reconstruct a tetrahedral mesh from a list of // 26714 // tetrahedra and possibly a list of boundary faces. // 26715 // // 26716 // The list of tetrahedra is stored in 'in->tetrahedronlist', the list of // 26717 // boundary faces is stored in 'in->trifacelist'. The tetrahedral mesh is // 26718 // reconstructed in memorypool 'tetrahedrons', its boundary faces (subfaces) // 26719 // are reconstructed in 'subfaces', its boundary edges (subsegments) are // 26720 // reconstructed in 'subsegs'. If the -a switch is used, this procedure will // 26721 // also read a list of REALs from 'in->tetrahedronvolumelist' and set a // 26722 // maximum volume constraint on each tetrahedron. // 26723 // // 26724 // If the user has provided the boundary faces in 'in->trifacelist', they // 26725 // will be inserted the mesh. Otherwise subfaces will be identified from the // 26726 // mesh. All hull faces (including faces of the internal holes) will be // 26727 // recognized as subfaces, internal faces between two tetrahedra which have // 26728 // different attributes will also be recognized as subfaces. // 26729 // // 26730 // Subsegments will be identified after subfaces are reconstructed. Edges at // 26731 // the intersections of non-coplanar subfaces are recognized as subsegments. // 26732 // Edges between two coplanar subfaces with different boundary markers are // 26733 // also recognized as subsegments. // 26734 // // 26735 // The facet index of each subface will be set automatically after we have // 26736 // recovered subfaces and subsegments. That is, the set of subfaces, which // 26737 // are coplanar and have the same boundary marker will be recognized as a // 26738 // facet and has a unique index, stored as the facet marker in each subface // 26739 // of the set, the real boundary marker of each subface will be found in // 26740 // 'in->facetmarkerlist' by the index. Facet index will be used in Delaunay // 26741 // refinement for detecting two incident facets. // 26742 // // 26743 // Points which are not corners of tetrahedra will be inserted into the mesh.// 26744 // Return the number of faces on the hull after the reconstruction. // 26745 // // 26747 26748 long tetgenmesh::reconstructmesh() 26749 { 26750 tetrahedron **tetsperverlist; 26751 shellface **facesperverlist; 26752 triface tetloop, neightet, neineightet, spintet; 26753 face subloop, neighsh, neineighsh, subseg; 26754 face sface1, sface2; 26755 point *idx2verlist; 26756 point torg, tdest, tapex, toppo; 26757 point norg, ndest, napex; 26758 list *neighshlist, *markerlist; 26759 REAL sign, attrib, volume; 26760 REAL da1, da2; 26761 bool bondflag, insertsegflag; 26762 int *idx2tetlist; 26763 int *idx2facelist; 26764 int *worklist; 26765 int facetidx, marker; 26766 int iorg, idest, iapex, ioppo; 26767 int inorg, indest, inapex; 26768 int index, i, j; 26769 26770 if (!b->quiet) { 26771 printf("Reconstructing mesh.\n"); 26772 } 26773 26774 // Create a map from index to points. 26775 makeindex2pointmap(idx2verlist); 26776 26777 // Create the tetrahedra. 26778 for (i = 0; i < in->numberoftetrahedra; i++) { 26779 // Create a new tetrahedron and set its four corners, make sure that 26780 // four corners form a positive orientation. 26781 maketetrahedron(&tetloop); 26782 index = i * in->numberofcorners; 26783 // Although there may be 10 nodes, we only read the first 4. 26784 iorg = in->tetrahedronlist[index] - in->firstnumber; 26785 idest = in->tetrahedronlist[index + 1] - in->firstnumber; 26786 iapex = in->tetrahedronlist[index + 2] - in->firstnumber; 26787 ioppo = in->tetrahedronlist[index + 3] - in->firstnumber; 26788 torg = idx2verlist[iorg]; 26789 tdest = idx2verlist[idest]; 26790 tapex = idx2verlist[iapex]; 26791 toppo = idx2verlist[ioppo]; 26792 sign = orient3d(torg, tdest, tapex, toppo); 26793 if (sign > 0.0) { 26794 norg = torg; torg = tdest; tdest = norg; 26795 } else if (sign == 0.0) { 26796 if (!b->quiet) { 26797 printf("Warning: Tet %d is degenerate.\n", i + in->firstnumber); 26798 } 26799 } 26800 setorg(tetloop, torg); 26801 setdest(tetloop, tdest); 26802 setapex(tetloop, tapex); 26803 setoppo(tetloop, toppo); 26804 // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that 26805 // they belong to the mesh. These types may be changed later. 26806 setpointtype(torg, FREEVOLVERTEX); 26807 setpointtype(tdest, FREEVOLVERTEX); 26808 setpointtype(tapex, FREEVOLVERTEX); 26809 setpointtype(toppo, FREEVOLVERTEX); 26810 // Set element attributes if they exist. 26811 for (j = 0; j < in->numberoftetrahedronattributes; j++) { 26812 index = i * in->numberoftetrahedronattributes; 26813 attrib = in->tetrahedronattributelist[index + j]; 26814 setelemattribute(tetloop.tet, j, attrib); 26815 } 26816 // If -a switch is used (with no number follows) Set a volume 26817 // constraint if it exists. 26818 if (b->varvolume) { 26819 if (in->tetrahedronvolumelist != (REAL *) NULL) { 26820 volume = in->tetrahedronvolumelist[i]; 26821 } else { 26822 volume = -1.0; 26823 } 26824 setvolumebound(tetloop.tet, volume); 26825 } 26826 } 26827 26828 // Set the connection between tetrahedra. 26829 hullsize = 0l; 26830 // Create a map from nodes to tetrahedra. 26831 maketetrahedronmap(idx2tetlist, tetsperverlist); 26832 // Initialize the worklist. 26833 worklist = new int[points->items]; 26834 for (i = 0; i < points->items; i++) worklist[i] = 0; 26835 26836 // Loop all tetrahedra, bond two tetrahedra if they share a common face. 26837 tetrahedrons->traversalinit(); 26838 tetloop.tet = tetrahedrontraverse(); 26839 while (tetloop.tet != (tetrahedron *) NULL) { 26840 // Loop the four sides of the tetrahedron. 26841 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { 26842 sym(tetloop, neightet); 26843 if (neightet.tet != dummytet) continue; // This side has finished. 26844 torg = org(tetloop); 26845 tdest = dest(tetloop); 26846 tapex = apex(tetloop); 26847 iorg = pointmark(torg) - in->firstnumber; 26848 idest = pointmark(tdest) - in->firstnumber; 26849 iapex = pointmark(tapex) - in->firstnumber; 26850 worklist[iorg] = 1; 26851 worklist[idest] = 1; 26852 worklist[iapex] = 1; 26853 bondflag = false; 26854 // Search its neighbor in the adjacent tets of torg. 26855 for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag; 26856 j++) { 26857 if (tetsperverlist[j] == tetloop.tet) continue; // Skip myself. 26858 neightet.tet = tetsperverlist[j]; 26859 for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { 26860 sym(neightet, neineightet); 26861 if (neineightet.tet == dummytet) { 26862 norg = org(neightet); 26863 ndest = dest(neightet); 26864 napex = apex(neightet); 26865 inorg = pointmark(norg) - in->firstnumber; 26866 indest = pointmark(ndest) - in->firstnumber; 26867 inapex = pointmark(napex) - in->firstnumber; 26868 if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) { 26869 // Find! Bond them together and break the loop. 26870 bond(tetloop, neightet); 26871 bondflag = true; 26872 break; 26873 } 26874 } 26875 } 26876 } 26877 if (!bondflag) { 26878 hullsize++; // It's a hull face. 26879 // Bond this side to outer space. 26880 dummytet[0] = encode(tetloop); 26881 if ((in->pointmarkerlist != (int *) NULL) && !b->coarse) { 26882 // Set its three corners's markers be boundary (hull) vertices. 26883 if (in->pointmarkerlist[iorg] == 0) { 26884 in->pointmarkerlist[iorg] = 1; 26885 } 26886 if (in->pointmarkerlist[idest] == 0) { 26887 in->pointmarkerlist[idest] = 1; 26888 } 26889 if (in->pointmarkerlist[iapex] == 0) { 26890 in->pointmarkerlist[iapex] = 1; 26891 } 26892 } 26893 } 26894 worklist[iorg] = 0; 26895 worklist[idest] = 0; 26896 worklist[iapex] = 0; 26897 } 26898 tetloop.tet = tetrahedrontraverse(); 26899 } 26900 26901 // Subfaces will be inserted into the mesh. It has two phases: 26902 // (1) Insert subfaces provided by user (in->trifacelist); 26903 // (2) Create subfaces for hull faces (if they're not subface yet) and 26904 // interior faces which separate two different materials. 26905 26906 // Phase (1). Is there a list of user-provided subfaces? 26907 if (in->trifacelist != (int *) NULL) { 26908 // Recover subfaces from 'in->trifacelist'. 26909 for (i = 0; i < in->numberoftrifaces; i++) { 26910 index = i * 3; 26911 iorg = in->trifacelist[index] - in->firstnumber; 26912 idest = in->trifacelist[index + 1] - in->firstnumber; 26913 iapex = in->trifacelist[index + 2] - in->firstnumber; 26914 // Look for the location of this subface. 26915 worklist[iorg] = 1; 26916 worklist[idest] = 1; 26917 worklist[iapex] = 1; 26918 bondflag = false; 26919 // Search its neighbor in the adjacent tets of torg. 26920 for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag; 26921 j++) { 26922 neightet.tet = tetsperverlist[j]; 26923 for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { 26924 norg = org(neightet); 26925 ndest = dest(neightet); 26926 napex = apex(neightet); 26927 inorg = pointmark(norg) - in->firstnumber; 26928 indest = pointmark(ndest) - in->firstnumber; 26929 inapex = pointmark(napex) - in->firstnumber; 26930 if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) { 26931 bondflag = true; // Find! 26932 break; 26933 } 26934 } 26935 } 26936 if (bondflag) { 26937 // Create a new subface and insert it into the mesh. 26938 makeshellface(subfaces, &subloop); 26939 torg = idx2verlist[iorg]; 26940 tdest = idx2verlist[idest]; 26941 tapex = idx2verlist[iapex]; 26942 setsorg(subloop, torg); 26943 setsdest(subloop, tdest); 26944 setsapex(subloop, tapex); 26945 // Set the vertices be FREESUBVERTEX to indicate they belong to a 26946 // facet of the domain. They may be changed later. 26947 setpointtype(torg, FREESUBVERTEX); 26948 setpointtype(tdest, FREESUBVERTEX); 26949 setpointtype(tapex, FREESUBVERTEX); 26950 if (in->trifacemarkerlist != (int *) NULL) { 26951 setshellmark(subloop, in->trifacemarkerlist[i]); 26952 } 26953 adjustedgering(neightet, CCW); 26954 findedge(&subloop, org(neightet), dest(neightet)); 26955 tsbond(neightet, subloop); 26956 sym(neightet, neineightet); 26957 if (neineightet.tet != dummytet) { 26958 sesymself(subloop); 26959 tsbond(neineightet, subloop); 26960 } 26961 } else { 26962 if (!b->quiet) { 26963 printf("Warning: Subface %d is discarded.\n", i + in->firstnumber); 26964 } 26965 } 26966 worklist[iorg] = 0; 26967 worklist[idest] = 0; 26968 worklist[iapex] = 0; 26969 } 26970 } 26971 26972 // Phase (2). Indentify subfaces from the mesh. 26973 tetrahedrons->traversalinit(); 26974 tetloop.tet = tetrahedrontraverse(); 26975 while (tetloop.tet != (tetrahedron *) NULL) { 26976 // Loop the four sides of the tetrahedron. 26977 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { 26978 tspivot(tetloop, subloop); 26979 if (subloop.sh != dummysh) continue; 26980 bondflag = false; 26981 sym(tetloop, neightet); 26982 if (neightet.tet == dummytet) { 26983 // It's a hull face. Insert a subface at here. 26984 bondflag = true; 26985 } else { 26986 // It's an interior face. Insert a subface if two tetrahedra have 26987 // different attributes (i.e., they belong to two regions). 26988 if (in->numberoftetrahedronattributes > 0) { 26989 if (elemattribute(neightet.tet, 26990 in->numberoftetrahedronattributes - 1) != 26991 elemattribute(tetloop.tet, 26992 in->numberoftetrahedronattributes - 1)) { 26993 bondflag = true; 26994 } 26995 } 26996 } 26997 if (bondflag) { 26998 adjustedgering(tetloop, CCW); 26999 makeshellface(subfaces, &subloop); 27000 torg = org(tetloop); 27001 tdest = dest(tetloop); 27002 tapex = apex(tetloop); 27003 setsorg(subloop, torg); 27004 setsdest(subloop, tdest); 27005 setsapex(subloop, tapex); 27006 // Set the vertices be FREESUBVERTEX to indicate they belong to a 27007 // facet of the domain. They may be changed later. 27008 setpointtype(torg, FREESUBVERTEX); 27009 setpointtype(tdest, FREESUBVERTEX); 27010 setpointtype(tapex, FREESUBVERTEX); 27011 tsbond(tetloop, subloop); 27012 if (neightet.tet != dummytet) { 27013 sesymself(subloop); 27014 tsbond(neightet, subloop); 27015 } 27016 } 27017 } 27018 tetloop.tet = tetrahedrontraverse(); 27019 } 27020 27021 // Set the connection between subfaces. A subsegment may have more than 27022 // two subfaces sharing it, 'neighshlist' stores all subfaces sharing 27023 // one edge. 27024 neighshlist = new list(sizeof(face), NULL); 27025 // Create a map from nodes to subfaces. 27026 makesubfacemap(idx2facelist, facesperverlist); 27027 27028 // Loop over the set of subfaces, setup the connection between subfaces. 27029 subfaces->traversalinit(); 27030 subloop.sh = shellfacetraverse(subfaces); 27031 while (subloop.sh != (shellface *) NULL) { 27032 for (i = 0; i < 3; i++) { 27033 spivot(subloop, neighsh); 27034 if (neighsh.sh == dummysh) { 27035 // This side is 'empty', operate on it. 27036 torg = sorg(subloop); 27037 tdest = sdest(subloop); 27038 tapex = sapex(subloop); 27039 neighshlist->append(&subloop); 27040 iorg = pointmark(torg) - in->firstnumber; 27041 // Search its neighbor in the adjacent list of torg. 27042 for (j = idx2facelist[iorg]; j < idx2facelist[iorg + 1]; j++) { 27043 neighsh.sh = facesperverlist[j]; 27044 if (neighsh.sh == subloop.sh) continue; 27045 neighsh.shver = 0; 27046 if (isfacehasedge(&neighsh, torg, tdest)) { 27047 findedge(&neighsh, torg, tdest); 27048 // Insert 'neighsh' into 'neighshlist'. 27049 if (neighshlist->len() < 2) { 27050 neighshlist->append(&neighsh); 27051 } else { 27052 for (index = 0; index < neighshlist->len() - 1; index++) { 27053 sface1 = * (face *)(* neighshlist)[index]; 27054 sface2 = * (face *)(* neighshlist)[index + 1]; 27055 da1 = facedihedral(torg, tdest, sapex(sface1), sapex(neighsh)); 27056 da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2)); 27057 if (da1 < da2) { 27058 break; // Insert it after index. 27059 } 27060 } 27061 neighshlist->insert(index + 1, &neighsh); 27062 } 27063 } 27064 } 27065 // Bond the subfaces in 'neighshlist'. 27066 if (neighshlist->len() > 1) { 27067 neighsh = * (face *)(* neighshlist)[0]; 27068 for (j = 1; j <= neighshlist->len(); j++) { 27069 if (j < neighshlist->len()) { 27070 neineighsh = * (face *)(* neighshlist)[j]; 27071 } else { 27072 neineighsh = * (face *)(* neighshlist)[0]; 27073 } 27074 sbond1(neighsh, neineighsh); 27075 neighsh = neineighsh; 27076 } 27077 } else { 27078 // No neighbor subface be found, bond 'subloop' to itself. 27079 sbond(subloop, subloop); 27080 } 27081 neighshlist->clear(); 27082 } 27083 senextself(subloop); 27084 } 27085 subloop.sh = shellfacetraverse(subfaces); 27086 } 27087 27088 // Segments will be introudced. Each segment has a unique marker (1-based). 27089 marker = 1; 27090 subfaces->traversalinit(); 27091 subloop.sh = shellfacetraverse(subfaces); 27092 while (subloop.sh != (shellface *) NULL) { 27093 for (i = 0; i < 3; i++) { 27094 sspivot(subloop, subseg); 27095 if (subseg.sh == dummysh) { 27096 // This side has no subsegment bonded, check it. 27097 torg = sorg(subloop); 27098 tdest = sdest(subloop); 27099 tapex = sapex(subloop); 27100 spivot(subloop, neighsh); 27101 spivot(neighsh, neineighsh); 27102 insertsegflag = false; 27103 if (subloop.sh == neighsh.sh || subloop.sh != neineighsh.sh) { 27104 // This side is either self-bonded or more than two subfaces, 27105 // insert a subsegment at this side. 27106 insertsegflag = true; 27107 } else { 27108 // Only two subfaces case. 27109 #ifdef SELF_CHECK 27110 assert(subloop.sh != neighsh.sh); 27111 #endif 27112 napex = sapex(neighsh); 27113 sign = orient3d(torg, tdest, tapex, napex); 27114 if (iscoplanar(torg, tdest, tapex, napex, sign, b->epsilon)) { 27115 // Although they are coplanar, we still need to check if they 27116 // have the same boundary marker. 27117 insertsegflag = (shellmark(subloop) != shellmark(neighsh)); 27118 } else { 27119 // Non-coplanar. 27120 insertsegflag = true; 27121 } 27122 } 27123 if (insertsegflag) { 27124 // Create a subsegment at this side. 27125 makeshellface(subsegs, &subseg); 27126 setsorg(subseg, torg); 27127 setsdest(subseg, tdest); 27128 // The two vertices have been marked as FREESUBVERTEX. Now mark 27129 // them as NACUTEVERTEX. 27130 setpointtype(torg, NACUTEVERTEX); 27131 setpointtype(tdest, NACUTEVERTEX); 27132 setshellmark(subseg, marker); 27133 marker++; 27134 // Bond all subfaces to this subsegment. 27135 neighsh = subloop; 27136 do { 27137 ssbond(neighsh, subseg); 27138 spivotself(neighsh); 27139 } while (neighsh.sh != subloop.sh); 27140 } 27141 } 27142 senextself(subloop); 27143 } 27144 subloop.sh = shellfacetraverse(subfaces); 27145 } 27146 // Remember the number of input segments. 27147 insegments = subsegs->items; 27148 // Find the acute vertices and set them be type ACUTEVERTEX. 27149 27150 // Indentify facets and set the facet marker (1-based) for subfaces. 27151 markerlist = new list((char*)"int"); 27152 27153 subfaces->traversalinit(); 27154 subloop.sh = shellfacetraverse(subfaces); 27155 while (subloop.sh != (shellface *) NULL) { 27156 // Only operate on uninfected subface, after operating, infect it. 27157 if (!sinfected(subloop)) { 27158 // A new facet is found. 27159 marker = shellmark(subloop); 27160 markerlist->append(&marker); 27161 facetidx = markerlist->len(); // 'facetidx' starts from 1. 27162 setshellmark(subloop, facetidx); 27163 sinfect(subloop); 27164 neighshlist->append(&subloop); 27165 // Find out all subfaces of this facet (bounded by subsegments). 27166 for (i = 0; i < neighshlist->len(); i++) { 27167 neighsh = * (face *) (* neighshlist)[i]; 27168 for (j = 0; j < 3; j++) { 27169 sspivot(neighsh, subseg); 27170 if (subseg.sh == dummysh) { 27171 spivot(neighsh, neineighsh); 27172 if (!sinfected(neineighsh)) { 27173 // 'neineighsh' is in the same facet as 'subloop'. 27174 #ifdef SELF_CHECK 27175 assert(shellmark(neineighsh) == marker); 27176 #endif 27177 setshellmark(neineighsh, facetidx); 27178 sinfect(neineighsh); 27179 neighshlist->append(&neineighsh); 27180 } 27181 } 27182 senextself(neighsh); 27183 } 27184 } 27185 neighshlist->clear(); 27186 } 27187 subloop.sh = shellfacetraverse(subfaces); 27188 } 27189 // Uninfect all subfaces. 27190 subfaces->traversalinit(); 27191 subloop.sh = shellfacetraverse(subfaces); 27192 while (subloop.sh != (shellface *) NULL) { 27193 #ifdef SELF_CHECK 27194 assert(sinfected(subloop)); 27195 #endif 27196 suninfect(subloop); 27197 subloop.sh = shellfacetraverse(subfaces); 27198 } 27199 // Save the facet markers in 'in->facetmarkerlist'. 27200 in->numberoffacets = markerlist->len(); 27201 in->facetmarkerlist = new int[in->numberoffacets]; 27202 for (i = 0; i < in->numberoffacets; i++) { 27203 marker = * (int *) (* markerlist)[i]; 27204 in->facetmarkerlist[i] = marker; 27205 } 27206 // Initialize the 'facetabovepointlist'. 27207 facetabovepointarray = new point[in->numberoffacets + 1]; 27208 for (i = 0; i < in->numberoffacets + 1; i++) { 27209 facetabovepointarray[i] = (point) NULL; 27210 } 27211 27212 // The mesh contains boundary now. 27213 checksubfaces = 1; 27214 // The mesh is nonconvex now. 27215 nonconvex = 1; 27216 27217 // Is there periodic boundary confitions? 27218 if (checkpbcs) { 27219 tetgenio::pbcgroup *pg; 27220 pbcdata *pd; 27221 // Initialize the global array 'subpbcgrouptable'. 27222 createsubpbcgrouptable(); 27223 // Loop for each pbcgroup i. 27224 for (i = 0; i < in->numberofpbcgroups; i++) { 27225 pg = &(in->pbcgrouplist[i]); 27226 pd = &(subpbcgrouptable[i]); 27227 // Find all subfaces of pd, set each subface's group id be i. 27228 for (j = 0; j < 2; j++) { 27229 subfaces->traversalinit(); 27230 subloop.sh = shellfacetraverse(subfaces); 27231 while (subloop.sh != (shellface *) NULL) { 27232 facetidx = shellmark(subloop); 27233 marker = in->facetmarkerlist[facetidx - 1]; 27234 if (marker == pd->fmark[j]) { 27235 setshellpbcgroup(subloop, i); 27236 pd->ss[j] = subloop; 27237 } 27238 subloop.sh = shellfacetraverse(subfaces); 27239 } 27240 } 27241 if (pg->pointpairlist != (int *) NULL) { 27242 // Set the connections between pbc point pairs. 27243 for (j = 0; j < pg->numberofpointpairs; j++) { 27244 iorg = pg->pointpairlist[j * 2] - in->firstnumber; 27245 idest = pg->pointpairlist[j * 2 + 1] - in->firstnumber; 27246 torg = idx2verlist[iorg]; 27247 tdest = idx2verlist[idest]; 27248 setpoint2pbcpt(torg, tdest); 27249 setpoint2pbcpt(tdest, torg); 27250 } 27251 } 27252 } 27253 // Create the global array 'segpbcgrouptable'. 27254 createsegpbcgrouptable(); 27255 } 27256 27257 delete markerlist; 27258 delete neighshlist; 27259 delete [] worklist; 27260 delete [] idx2tetlist; 27261 delete [] tetsperverlist; 27262 delete [] idx2facelist; 27263 delete [] facesperverlist; 27264 delete [] idx2verlist; 27265 27266 return hullsize; 27267 } 27268 27270 // // 27271 // insertconstrainedpoints() Insert a list of constrained points. // 27272 // // 27274 27275 void tetgenmesh::insertconstrainedpoints(tetgenio *addio) 27276 { 27277 queue *flipqueue; 27278 triface searchtet; 27279 face checksh, checkseg; 27280 point newpoint; 27281 enum locateresult loc; 27282 REAL *attr; 27283 bool insertflag; 27284 int covertices, outvertices; 27285 int index; 27286 int i, j; 27287 27288 if (!b->quiet) { 27289 printf("Insert additional points into mesh.\n"); 27290 } 27291 // Initialize 'flipqueue'. 27292 flipqueue = new queue(sizeof(badface)); 27293 recenttet.tet = dummytet; 27294 covertices = outvertices = 0; 27295 27296 index = 0; 27297 for (i = 0; i < addio->numberofpoints; i++) { 27298 // Create a newpoint. 27299 makepoint(&newpoint); 27300 newpoint[0] = addio->pointlist[index++]; 27301 newpoint[1] = addio->pointlist[index++]; 27302 newpoint[2] = addio->pointlist[index++]; 27303 // Read the add point attributes if current points have attributes. 27304 if ((addio->numberofpointattributes > 0) && 27305 (in->numberofpointattributes > 0)) { 27306 attr = addio->pointattributelist + addio->numberofpointattributes * i; 27307 for (j = 0; j < in->numberofpointattributes; j++) { 27308 if (j < addio->numberofpointattributes) { 27309 newpoint[3 + j] = attr[j]; 27310 } 27311 } 27312 } 27313 // Find the location of the inserted point. 27314 searchtet = recenttet; 27315 loc = locate(newpoint, &searchtet); 27316 if (loc != ONVERTEX) { 27317 loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon2); 27318 } 27319 if (loc == OUTSIDE) { 27320 loc = hullwalk(newpoint, &searchtet); 27321 if (loc == OUTSIDE) { 27322 // Perform a brute-force search. 27323 tetrahedrons->traversalinit(); 27324 searchtet.tet = tetrahedrontraverse(); 27325 while (searchtet.tet != (tetrahedron *) NULL) { 27326 loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon2); 27327 if (loc != OUTSIDE) break; 27328 searchtet.tet = tetrahedrontraverse(); 27329 } 27330 } 27331 } 27332 // Insert the point if it not lies outside or on a vertex. 27333 insertflag = true; 27334 switch (loc) { 27335 case INTETRAHEDRON: 27336 setpointtype(newpoint, FREEVOLVERTEX); 27337 splittetrahedron(newpoint, &searchtet, flipqueue); 27338 break; 27339 case ONFACE: 27340 tspivot(searchtet, checksh); 27341 if (checksh.sh != dummysh) { 27342 // It is a boundary face. Don't insert it if -Y option is used. 27343 if (b->nobisect) { 27344 insertflag = false; 27345 } else { 27346 setpointtype(newpoint, FREESUBVERTEX); 27347 } 27348 } else { 27349 setpointtype(newpoint, FREEVOLVERTEX); 27350 } 27351 if (insertflag) { 27352 splittetface(newpoint, &searchtet, flipqueue); 27353 } 27354 break; 27355 case ONEDGE: 27356 tsspivot(&searchtet, &checkseg); 27357 if (checkseg.sh != dummysh) { 27358 if (b->nobisect) { 27359 insertflag = false; 27360 } else { 27361 setpointtype(newpoint, FREESEGVERTEX); 27362 setpoint2sh(newpoint, sencode(checkseg)); 27363 } 27364 } else { 27365 tspivot(searchtet, checksh); 27366 if (checksh.sh != dummysh) { 27367 if (b->nobisect) { 27368 insertflag = false; 27369 } else { 27370 setpointtype(newpoint, FREESUBVERTEX); 27371 } 27372 } else { 27373 setpointtype(newpoint, FREEVOLVERTEX); 27374 } 27375 } 27376 if (insertflag) { 27377 splittetedge(newpoint, &searchtet, flipqueue); 27378 } 27379 break; 27380 case ONVERTEX: 27381 insertflag = false; 27382 covertices++; 27383 break; 27384 case OUTSIDE: 27385 insertflag = false; 27386 outvertices++; 27387 break; 27388 } 27389 // Remember the tetrahedron for next point searching. 27390 recenttet = searchtet; 27391 if (!insertflag) { 27392 pointdealloc(newpoint); 27393 } else { 27394 flip(flipqueue, NULL); 27395 } 27396 } 27397 27398 if (b->verbose) { 27399 if (covertices > 0) { 27400 printf(" %d constrained points already exist.\n", covertices); 27401 } 27402 if (outvertices > 0) { 27403 printf(" %d constrained points lie outside the mesh.\n", outvertices); 27404 } 27405 printf(" %d constrained points have been inserted.\n", 27406 addio->numberofpoints - covertices - outvertices); 27407 } 27408 27409 delete flipqueue; 27410 } 27411 27413 // // 27414 // p1interpolatebgm() Set pt size by p^1 interpolation in background mesh.// 27415 // // 27416 // On input, 'bgmtet' is a suggesting tet in background mesh for searching // 27417 // 'pt'. It returns the tet containing 'pt'. // 27418 // // 27420 27421 bool tetgenmesh::p1interpolatebgm(point pt, triface* bgmtet, long *scount) 27422 { 27423 point bgmpt[4]; 27424 enum locateresult loc; 27425 REAL vol, volpt[4], weights[4]; 27426 int i; 27427 27428 loc = bgm->preciselocate(pt, bgmtet, bgm->tetrahedrons->items); 27429 if (loc == OUTSIDE) { 27430 loc = bgm->hullwalk(pt, bgmtet); 27431 if (loc == OUTSIDE) { 27432 // Perform a brute-force search. 27433 if (b->verbose) { 27434 printf("Warning: Global point location.\n"); 27435 } 27436 if (scount) (*scount)++; 27437 bgm->tetrahedrons->traversalinit(); // in bgm 27438 bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm 27439 while (bgmtet->tet != (tetrahedron *) NULL) { 27440 loc = bgm->adjustlocate(pt, bgmtet, OUTSIDE, b->epsilon); 27441 if (loc != OUTSIDE) break; 27442 bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm 27443 } 27444 } 27445 } 27446 if (loc != OUTSIDE) { 27447 // Let p remember t. 27448 setpoint2bgmtet(pt, encode(*bgmtet)); // in m 27449 // get the corners of t. 27450 for (i = 0; i < 4; i++) bgmpt[i] = (point) bgmtet->tet[4 + i]; 27451 // Calculate the weighted coordinates of p in t. 27452 vol = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], bgmpt[3]); 27453 volpt[0] = orient3d(pt, bgmpt[1], bgmpt[2], bgmpt[3]); 27454 volpt[1] = orient3d(bgmpt[0], pt, bgmpt[2], bgmpt[3]); 27455 volpt[2] = orient3d(bgmpt[0], bgmpt[1], pt, bgmpt[3]); 27456 volpt[3] = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], pt); 27457 for (i = 0; i < 4; i++) weights[i] = fabs(volpt[i] / vol); 27458 // Interpolate the solution for p. 27459 for (i = 0; i < bgm->in->numberofpointmtrs; i++) { 27460 pt[pointmtrindex + i] = weights[0] * bgmpt[0][bgm->pointmtrindex + i] 27461 + weights[1] * bgmpt[1][bgm->pointmtrindex + i] 27462 + weights[2] * bgmpt[2][bgm->pointmtrindex + i] 27463 + weights[3] * bgmpt[3][bgm->pointmtrindex + i]; 27464 } 27465 } else { 27466 setpoint2bgmtet(pt, (tetrahedron) NULL); // in m 27467 } 27468 return loc != OUTSIDE; 27469 } 27470 27472 // // 27473 // interpolatesizemap() Interpolate the point sizes in the given size map.// 27474 // // 27475 // The size map is specified on each node of the background mesh. The points // 27476 // of current mesh get their sizes by interpolating. // 27477 // // 27478 // This function operation on two meshes simultaneously, the current mesh m, // 27479 // and the background mesh bgm. After this function, each point p in m will // 27480 // have a pointer to a tet of bgm. // 27481 // // 27483 27484 void tetgenmesh::interpolatesizemap() 27485 { 27486 list *adjtetlist; 27487 triface tetloop, neightet, bgmtet; 27488 point searchpt; 27489 long scount; 27490 int *worklist; 27491 int sepcount; 27492 int i; 27493 27494 if (b->verbose) { 27495 printf(" Interpolating size map.\n"); 27496 } 27497 27498 worklist = new int[points->items + 1]; 27499 for (i = 0; i < points->items + 1; i++) worklist[i] = 0; 27500 sepcount = 0; 27501 scount = 0l; 27502 27503 tetrahedrons->traversalinit(); 27504 tetloop.tet = tetrahedrontraverse(); 27505 while (tetloop.tet != (tetrahedron *) NULL) { 27506 if (!infected(tetloop)) { 27507 // Find a new subdomain. 27508 adjtetlist = new list(sizeof(triface), NULL, 1024); 27509 infect(tetloop); 27510 // Search the four corners in background mesh. 27511 for (i = 0; i < 4; i++) { 27512 searchpt = (point) tetloop.tet[4 + i]; 27513 // Mark the point for avoiding multiple searchings. 27514 // assert(worklist[pointmark(searchpt)] == 0); 27515 worklist[pointmark(searchpt)] = 1; 27516 // Does it contain a pointer to bgm tet? 27517 bgm->decode(point2bgmtet(searchpt), bgmtet); 27518 if (bgm->isdead(&bgmtet)) { 27519 bgmtet = bgm->recenttet; 27520 } 27521 if (p1interpolatebgm(searchpt, &bgmtet, &scount)) { 27522 bgm->recenttet = bgmtet; 27523 } 27524 } // for (i = 0; i < 4; i++) 27525 // Collect all tets in this region. 27526 adjtetlist->append(&tetloop); 27527 // Collect the tets in the subdomain. 27528 for (i = 0; i < adjtetlist->len(); i++) { 27529 tetloop = * (triface *)(* adjtetlist)[i]; 27530 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { 27531 sym(tetloop, neightet); 27532 if ((neightet.tet != dummytet) && !infected(neightet)) { 27533 // Only need to search for the opposite point. 27534 searchpt = oppo(neightet); 27535 if (worklist[pointmark(searchpt)] == 0) { 27536 worklist[pointmark(searchpt)] = 1; 27537 decode(point2bgmtet(searchpt), bgmtet); 27538 if (bgm->isdead(&bgmtet)) { 27539 bgmtet = bgm->recenttet; 27540 } 27541 if (p1interpolatebgm(searchpt, &bgmtet, &scount)) { 27542 bgm->recenttet = bgmtet; 27543 } 27544 } 27545 infect(neightet); 27546 adjtetlist->append(&neightet); 27547 } 27548 } 27549 } 27550 // Increase the number of separated domains. 27551 sepcount++; 27552 delete adjtetlist; 27553 } // if (!infect()) 27554 tetloop.tet = tetrahedrontraverse(); 27555 } 27556 27557 // Unmark all tets. 27558 tetrahedrons->traversalinit(); 27559 tetloop.tet = tetrahedrontraverse(); 27560 while (tetloop.tet != (tetrahedron *) NULL) { 27561 assert(infected(tetloop)); 27562 uninfect(tetloop); 27563 tetloop.tet = tetrahedrontraverse(); 27564 } 27565 delete [] worklist; 27566 27567 #ifdef SELF_CHECK 27568 if (b->verbose && scount > 0l) { 27569 printf(" %ld brute-force searches.\n", scount); 27570 } 27571 if (b->verbose && sepcount > 0) { 27572 printf(" %d separate domains.\n", sepcount); 27573 } 27574 #endif 27575 } 27576 27578 // // 27579 // duplicatebgmesh() Duplicate current mesh to background mesh. // 27580 // // 27581 // Current mesh 'this' is copied into 'this->bgm'.Both meshes share the same // 27582 // input tetgenio object, 'this->in', same tetgenbehavior object 'this->b'. // 27583 // // 27585 27586 void tetgenmesh::duplicatebgmesh() 27587 { 27588 triface tetloop, btetloop; 27589 triface symtet, bsymtet; 27590 face bhullsh, bneighsh; 27591 point *idx2bplist, *tetptbaklist; 27592 point ploop, bploop; 27593 int idx, i; 27594 27595 if (!b->quiet) { 27596 printf("Duplicating background mesh.\n"); 27597 } 27598 27599 // The background mesh itself has no background mesh. 27600 // assert(bgm->bgm == (tetgenmesh *) NULL); 27601 // The space for metric tensor should be allocated. 27602 // assert(bgm->sizeoftensor > 0); 27603 27604 // Copy point list. 27605 idx2bplist = new point[points->items + 1]; 27606 idx = in->firstnumber; 27607 points->traversalinit(); 27608 ploop = pointtraverse(); 27609 while (ploop != (point) NULL) { 27610 bgm->makepoint(&bploop); 27611 // Copy coordinates, attributes. 27612 for (i = 0; i < 3 + in->numberofpointattributes; i++) { 27613 bploop[i] = ploop[i]; 27614 } 27615 // Transfer the metric tensor. 27616 for (i = 0; i < bgm->sizeoftensor; i++) { 27617 bploop[bgm->pointmtrindex + i] = ploop[pointmtrindex + i]; 27618 // Metric tensor should have a positive value. 27619 if (bploop[bgm->pointmtrindex + i] <= 0.0) { 27620 printf("Error: Point %d has non-positive size %g (-m option).\n", 27621 bgm->pointmark(bploop), bploop[bgm->pointmtrindex + i]); 27622 terminatetetgen(1); 27623 } 27624 } 27625 // Remember the point for searching. 27626 idx2bplist[idx++] = bploop; 27627 ploop = pointtraverse(); 27628 } 27629 27630 // Copy tetrahedra list. 27631 tetptbaklist = new point[tetrahedrons->items + 1]; 27632 idx = in->firstnumber; 27633 tetrahedrons->traversalinit(); 27634 tetloop.tet = tetrahedrontraverse(); 27635 while (tetloop.tet != (tetrahedron *) NULL) { 27636 bgm->maketetrahedron(&btetloop); 27637 // Set the four corners. 27638 for (i = 0; i < 4; i++) { 27639 ploop = (point) tetloop.tet[4 + i]; 27640 bploop = idx2bplist[pointmark(ploop)]; 27641 btetloop.tet[4 + i] = (tetrahedron) bploop; 27642 } 27643 // Remember the tet for setting neighbor connections. 27644 tetptbaklist[idx++] = (point) tetloop.tet[4]; 27645 tetloop.tet[4] = (tetrahedron) btetloop.tet; 27646 tetloop.tet = tetrahedrontraverse(); 27647 } 27648 27649 // Set the connections between background tetrahedra. Create background 27650 // hull subfaces. Create the map of point-to-bgmtet. 27651 idx = in->firstnumber; 27652 tetrahedrons->traversalinit(); 27653 tetloop.tet = tetrahedrontraverse(); 27654 while (tetloop.tet != (tetrahedron *) NULL) { 27655 // Get the corresponding background tet. 27656 btetloop.tet = (tetrahedron *) tetloop.tet[4]; 27657 // Set the four neighbors. 27658 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { 27659 btetloop.loc = tetloop.loc; 27660 sym(tetloop, symtet); 27661 if ((symtet.tet != dummytet) && (symtet.tet > tetloop.tet)) { 27662 // Operate on the un-connected interior face. 27663 bsymtet.tet = (tetrahedron *) symtet.tet[4]; // The saved bgm tet. 27664 bsymtet.loc = symtet.loc; 27665 bgm->bond(btetloop, bsymtet); 27666 } else if (symtet.tet == dummytet) { 27667 // Create a subface in background mesh. 27668 bgm->makeshellface(bgm->subfaces, &bhullsh); 27669 bgm->adjustedgering(btetloop, CCW); // face to inside. 27670 bgm->setsorg(bhullsh, bgm->org(btetloop)); 27671 bgm->setsdest(bhullsh, bgm->dest(btetloop)); 27672 bgm->setsapex(bhullsh, bgm->apex(btetloop)); 27673 bgm->tsbond(btetloop, bhullsh); 27674 // Remember a hull face for point location. 27675 bgm->dummytet[0] = bgm->encode(btetloop); 27676 } 27677 } 27678 // Restore the backup tet point. 27679 tetloop.tet[4] = (tetrahedron) tetptbaklist[idx++]; 27680 // Make the point-to-bgmtet map for size interpolation. 27681 btetloop.loc = 0; 27682 for (i = 0; i < 4; i++) { 27683 ploop = (point) tetloop.tet[4 + i]; 27684 setpoint2bgmtet(ploop, bgm->encode(btetloop)); 27685 } 27686 // Go to the next tet, btet. 27687 tetloop.tet = tetrahedrontraverse(); 27688 } 27689 27690 // Connect bgm hull subfaces. Note: all hull subfaces form a 2-manifold. 27691 bgm->subfaces->traversalinit(); 27692 bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces); 27693 while (bhullsh.sh != (shellface *) NULL) { 27694 bhullsh.shver = 0; 27695 bgm->stpivot(bhullsh, btetloop); 27696 assert(btetloop.tet != bgm->dummytet); 27697 bgm->adjustedgering(btetloop, CCW); 27698 for (i = 0; i < 3; i++) { 27699 bgm->spivot(bhullsh, bneighsh); 27700 if (bneighsh.sh == bgm->dummysh) { 27701 // This side is open, operate on it. 27702 bsymtet = btetloop; 27703 while (bgm->fnextself(bsymtet)); 27704 bgm->tspivot(bsymtet, bneighsh); 27705 bgm->findedge(&bneighsh, bgm->sdest(bhullsh), bgm->sorg(bhullsh)); 27706 bgm->sbond(bhullsh, bneighsh); 27707 } 27708 bgm->enextself(btetloop); 27709 bgm->senextself(bhullsh); 27710 } 27711 bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces); 27712 } 27713 27714 delete [] tetptbaklist; 27715 delete [] idx2bplist; 27716 } 27717 27718 // 27719 // Begin of Delaunay refinement routines 27720 // 27721 27723 // // 27724 // marksharpsegments() Mark sharp segments. // 27725 // // 27726 // A segment s is called sharp if it is in one of the two cases: // 27727 // (1) There is a segment s' intersecting with s. The internal angle (*) // 27728 // between s and s' is acute. // 27729 // (2) There are two facets f1 and f2 intersecting at s. The internal // 27730 // dihedral angle (*) between f1 and f2 is acute. // 27731 // This routine finds the sharp segments and marked them as type SHARP. // 27732 // The minimum angle between segments (minfaceang) and the minimum dihedral // 27733 // angle between facets (minfacetdihed) are calulcated. // 27734 // // 27735 // (*) The internal angle (or dihedral) bewteen two features means the angle // 27736 // inside the mesh domain. // 27737 // // 27739 27740 void tetgenmesh::marksharpsegments(REAL sharpangle) 27741 { 27742 triface adjtet; 27743 face startsh, spinsh, neighsh; 27744 face segloop, prevseg, nextseg; 27745 point eorg, edest; 27746 REAL ang, smallang; 27747 bool issharp; 27748 int sharpsegcount; 27749 27750 if (b->verbose > 0) { 27751 printf(" Marking sharp segments.\n"); 27752 } 27753 27754 smallang = sharpangle * PI / 180.; 27755 sharpsegcount = 0; 27756 eorg = edest = (point) NULL; // To avoid compiler warnings. 27757 27758 // A segment s may have been split into many subsegments. Operate the one 27759 // which contains the origin of s. Then mark the rest of subsegments. 27760 subsegs->traversalinit(); 27761 segloop.sh = shellfacetraverse(subsegs); 27762 while (segloop.sh != (shellface *) NULL) { 27763 segloop.shver = 0; 27764 senext2(segloop, prevseg); 27765 spivotself(prevseg); 27766 if (prevseg.sh == dummysh) { 27767 // Operate on this seg s. 27768 assert(shelltype(segloop) != SHARP); // It should be unmarked. 27769 issharp = false; 27770 spivot(segloop, startsh); 27771 if (startsh.sh != dummysh) { 27772 // First check if two facets form an acute dihedral angle at s. 27773 eorg = sorg(segloop); 27774 edest = sdest(segloop); 27775 spinsh = startsh; 27776 do { 27777 if (sorg(spinsh) != eorg) { 27778 sesymself(spinsh); 27779 } 27780 // Only do test when the spinsh is faceing inward. 27781 stpivot(spinsh, adjtet); 27782 if (adjtet.tet != dummytet) { 27783 // Get the subface on the adjacent facet. 27784 spivot(spinsh, neighsh); 27785 // Do not calculate if it is self-bonded. 27786 if (neighsh.sh != spinsh.sh) { 27787 // Calculate the dihedral angle between the two subfaces. 27788 ang = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh)); 27789 // Only do check if a sharp angle has not been found. 27790 if (!issharp) issharp = (ang < smallang); 27791 // Remember the smallest facet dihedral angle. 27792 minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang; 27793 } 27794 } 27795 // Go to the next facet. 27796 spivotself(spinsh); 27797 } while (spinsh.sh != startsh.sh); 27798 // if (!issharp) { 27799 // Second check if s forms an acute angle with another seg. 27800 spinsh = startsh; 27801 do { 27802 if (sorg(spinsh) != eorg) { 27803 sesymself(spinsh); 27804 } 27805 // Calculate the angle between s and s' of this facet. 27806 neighsh = spinsh; 27807 // Rotate edges around 'eorg' until meeting another seg s'. Such 27808 // seg (s') must exist since the facet is segment-bounded. 27809 // The sum of the angles of faces at 'eorg' gives the internal 27810 // angle between the two segments. 27811 ang = 0.0; 27812 do { 27813 ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL); 27814 senext2self(neighsh); 27815 sspivot(neighsh, nextseg); 27816 if (nextseg.sh != dummysh) break; 27817 // Go to the next coplanar subface. 27818 spivotself(neighsh); 27819 assert(neighsh.sh != dummysh); 27820 if (sorg(neighsh) != eorg) { 27821 sesymself(neighsh); 27822 } 27823 } while (true); 27824 // Only do check if a sharp angle has not been found. 27825 if (!issharp) issharp = (ang < smallang); 27826 // Remember the smallest input face angle. 27827 minfaceang = minfaceang < ang ? minfaceang : ang; 27828 // Go to the next facet. 27829 spivotself(spinsh); 27830 } while (spinsh.sh != startsh.sh); 27831 // } 27832 } 27833 if (issharp) { 27834 setshelltype(segloop, SHARP); 27835 // Set the type for all subsegments at forwards. 27836 senext(segloop, nextseg); 27837 spivotself(nextseg); 27838 while (nextseg.sh != dummysh) { 27839 nextseg.shver = 0; 27840 setshelltype(nextseg, SHARP); 27841 senextself(nextseg); 27842 spivotself(nextseg); 27843 } 27844 sharpsegcount++; 27845 } 27846 } 27847 segloop.sh = shellfacetraverse(subsegs); 27848 } 27849 27850 // So far we have marked all segments which have an acute dihedral angle 27851 // or whose ORIGINs have an acute angle. In the un-marked subsegments, 27852 // there are possible ones whose DESTINATIONs have an acute angle. 27853 subsegs->traversalinit(); 27854 segloop.sh = shellfacetraverse(subsegs); 27855 while (segloop.sh != (shellface *) NULL) { 27856 // Only operate if s is non-sharp and contains the dest. 27857 segloop.shver = 0; 27858 senext(segloop, nextseg); 27859 spivotself(nextseg); 27860 // if ((nextseg.sh == dummysh) && (shelltype(segloop) != SHARP)) { 27861 if (nextseg.sh == dummysh) { 27862 // issharp = false; 27863 issharp = (shelltype(segloop) == SHARP); 27864 spivot(segloop, startsh); 27865 if (startsh.sh != dummysh) { 27866 // Check if s forms an acute angle with another seg. 27867 eorg = sdest(segloop); 27868 spinsh = startsh; 27869 do { 27870 if (sorg(spinsh) != eorg) { 27871 sesymself(spinsh); 27872 } 27873 // Calculate the angle between s and s' of this facet. 27874 neighsh = spinsh; 27875 ang = 0.0; 27876 do { 27877 ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL); 27878 senext2self(neighsh); 27879 sspivot(neighsh, nextseg); 27880 if (nextseg.sh != dummysh) break; 27881 // Go to the next coplanar subface. 27882 spivotself(neighsh); 27883 assert(neighsh.sh != dummysh); 27884 if (sorg(neighsh) != eorg) { 27885 sesymself(neighsh); 27886 } 27887 } while (true); 27888 // Only do check if a sharp angle has not been found. 27889 if (!issharp) issharp = (ang < smallang); 27890 // Remember the smallest input face angle. 27891 minfaceang = minfaceang < ang ? minfaceang : ang; 27892 // Go to the next facet. 27893 spivotself(spinsh); 27894 } while (spinsh.sh != startsh.sh); 27895 } 27896 if (issharp) { 27897 setshelltype(segloop, SHARP); 27898 // Set the type for all subsegments at backwards. 27899 senext2(segloop, prevseg); 27900 spivotself(prevseg); 27901 while (prevseg.sh != dummysh) { 27902 prevseg.shver = 0; 27903 setshelltype(prevseg, SHARP); 27904 senext2self(prevseg); 27905 spivotself(prevseg); 27906 } 27907 sharpsegcount++; 27908 } 27909 } 27910 segloop.sh = shellfacetraverse(subsegs); 27911 } 27912 27913 if ((b->verbose > 0) && (sharpsegcount > 0)) { 27914 printf(" %d sharp segments.\n", sharpsegcount); 27915 } 27916 } 27917 27919 // // 27920 // decidefeaturepointsizes() Decide the sizes for all feature points. // 27921 // // 27922 // A feature point is a point on a sharp segment. Every feature point p will // 27923 // be assigned a positive size which is the radius of the protecting ball. // 27924 // // 27925 // The size of a feature point may be specified by one of the following ways:// 27926 // (1) directly specifying on an input vertex (by using .mtr file); // 27927 // (2) imposing a fixed maximal volume constraint ('-a__' option); // 27928 // (3) imposing a maximal volume constraint in a region ('-a' option); // 27929 // (4) imposing a maximal area constraint on a facet (in .var file); // 27930 // (5) imposing a maximal length constraint on a segment (in .var file); // 27931 // (6) combining (1) - (5). // 27932 // (7) automatically deriving a size if none of (1) - (6) is available. // 27933 // In case (7),the size of p is set to be the smallest edge length among all // 27934 // edges connecting at p. The final size of p is the minimum of (1) - (7). // 27935 // // 27937 27938 void tetgenmesh::decidefeaturepointsizes() 27939 { 27940 list *tetlist, *verlist; 27941 shellface **segsperverlist; 27942 triface starttet; 27943 face shloop; 27944 face checkseg, prevseg, nextseg, testseg; 27945 point ploop, adjpt, e1, e2; 27946 REAL lfs_0, len, vol, maxlen, varlen; 27947 bool isfeature; 27948 int *idx2seglist; 27949 int featurecount; 27950 int idx, i, j; 27951 27952 maxlen = 0.0; 27953 27954 if (b->verbose > 0) { 27955 printf(" Deciding feature-point sizes.\n"); 27956 } 27957 27958 // Constructing a map from vertices to segments. 27959 makesegmentmap(idx2seglist, segsperverlist); 27960 // Initialize working lists. 27961 tetlist = new list(sizeof(triface), NULL, 256); 27962 verlist = new list(sizeof(point *), NULL, 256); 27963 27964 if (b->fixedvolume) { 27965 // A fixed volume constraint is imposed. This gives an upper bound of 27966 // the maximal radius of the protect ball of a vertex. 27967 maxlen = pow(6.0 * b->maxvolume, 1.0/3.0); 27968 } 27969 27970 if (!b->refine) { 27971 // Initially correct types for Steiner points. 27972 featurecount = 0; 27973 points->traversalinit(); 27974 ploop = pointtraverse(); 27975 while (ploop != (point) NULL) { 27976 if (pointtype(ploop) == NACUTEVERTEX) { 27977 if (point2sh(ploop) != (shellface) NULL) { 27978 setpointtype(ploop, FREESEGVERTEX); 27979 featurecount++; 27980 } 27981 } 27982 ploop = pointtraverse(); 27983 } 27984 #ifdef SELF_CHECK 27985 if ((b->verbose > 0) && (featurecount > 0)) { 27986 printf(" %d Steiner points correction.\n", featurecount); 27987 } 27988 #endif 27989 } 27990 27991 // First only assign a size of p if p is not a Steiner point. The size of 27992 // a Steiner point will be interpolated later from the endpoints of the 27993 // segment on which it lies. 27994 featurecount = 0; 27995 points->traversalinit(); 27996 ploop = pointtraverse(); 27997 while (ploop != (point) NULL) { 27998 if (pointtype(ploop) != FREESEGVERTEX) { 27999 // Is p a feature point? 28000 isfeature = false; 28001 idx = pointmark(ploop) - in->firstnumber; 28002 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) { 28003 checkseg.sh = segsperverlist[i]; 28004 isfeature = (shelltype(checkseg) == SHARP); 28005 } 28006 // Decide the size of p if it is on a sharp segment. 28007 if (isfeature) { 28008 // Find a tet containing p (checkseg is a sharp seg which contains p). 28009 sstpivot(&checkseg, &starttet); 28010 // Form star(p). 28011 tetlist->append(&starttet); 28012 formstarpolyhedron(ploop, tetlist, verlist, true); 28013 // Decide the size for p if no input size is given on input. 28014 if (ploop[pointmtrindex] == 0.0) { 28015 // Calculate lfs_0(p). 28016 lfs_0 = longest; 28017 for (i = 0; i < verlist->len(); i++) { 28018 adjpt = * (point *)(* verlist)[i]; 28019 if (pointtype(adjpt) == FREESEGVERTEX) { 28020 // A Steiner point q. Find the seg it lies on. 28021 sdecode(point2sh(adjpt), checkseg); 28022 assert(checkseg.sh != dummysh); 28023 checkseg.shver = 0; 28024 // Find the origin of this seg. 28025 prevseg = checkseg; 28026 do { 28027 senext2(prevseg, testseg); 28028 spivotself(testseg); 28029 if (testseg.sh == dummysh) break; 28030 prevseg = testseg; // Go to the previous subseg. 28031 prevseg.shver = 0; 28032 } while (true); 28033 // Find the dest of this seg. 28034 nextseg = checkseg; 28035 do { 28036 senext(nextseg, testseg); 28037 spivotself(testseg); 28038 if (testseg.sh == dummysh) break; 28039 nextseg = testseg; // Go to the next subseg. 28040 nextseg.shver = 0; 28041 } while (true); 28042 e1 = sorg(prevseg); 28043 e2 = sdest(nextseg); 28044 // Check if p is the origin or the dest of this seg. 28045 if (ploop == e1) { 28046 // Set q to be the dest of this seg. 28047 adjpt = e2; 28048 } else if (ploop == e2) { 28049 // Set q to be the org of this seg. 28050 adjpt = e1; 28051 } 28052 } 28053 len = distance(ploop, adjpt); 28054 if (lfs_0 > len) lfs_0 = len; 28055 } 28056 ploop[pointmtrindex] = lfs_0; 28057 } 28058 if (b->fixedvolume) { 28059 // A fixed volume constraint is imposed. Adjust H(p) <= maxlen. 28060 if (ploop[pointmtrindex] > maxlen) { 28061 ploop[pointmtrindex] = maxlen; 28062 } 28063 } 28064 if (b->varvolume) { 28065 // Variant volume constraints are imposed. Adjust H(p) <= varlen. 28066 for (i = 0; i < tetlist->len(); i++) { 28067 starttet = * (triface *)(* tetlist)[i]; 28068 vol = volumebound(starttet.tet); 28069 if (vol > 0.0) { 28070 varlen = pow(6 * vol, 1.0/3.0); 28071 if (ploop[pointmtrindex] > varlen) { 28072 ploop[pointmtrindex] = varlen; 28073 } 28074 } 28075 } 28076 } 28077 // Clear working lists. 28078 tetlist->clear(); 28079 verlist->clear(); 28080 featurecount++; 28081 } else { 28082 // NO feature point, set the size of p be zero. 28083 ploop[pointmtrindex] = 0.0; 28084 } 28085 } // if (pointtype(ploop) != FREESEGVERTEX) { 28086 ploop = pointtraverse(); 28087 } 28088 28089 if (b->verbose > 0) { 28090 printf(" %d feature points.\n", featurecount); 28091 } 28092 28093 if (!b->refine) { 28094 // Second only assign sizes for all Steiner points. A Steiner point p 28095 // inserted on a sharp segment s is assigned a size by interpolating 28096 // the sizes of the original endpoints of s. 28097 featurecount = 0; 28098 points->traversalinit(); 28099 ploop = pointtraverse(); 28100 while (ploop != (point) NULL) { 28101 if (pointtype(ploop) == FREESEGVERTEX) { 28102 if (ploop[pointmtrindex] == 0.0) { 28103 sdecode(point2sh(ploop), checkseg); 28104 assert(checkseg.sh != dummysh); 28105 if (shelltype(checkseg) == SHARP) { 28106 checkseg.shver = 0; 28107 // Find the origin of this seg. 28108 prevseg = checkseg; 28109 do { 28110 senext2(prevseg, testseg); 28111 spivotself(testseg); 28112 if (testseg.sh == dummysh) break; 28113 prevseg = testseg; // Go the previous subseg. 28114 prevseg.shver = 0; 28115 } while (true); 28116 // Find the dest of this seg. 28117 nextseg = checkseg; 28118 do { 28119 senext(nextseg, testseg); 28120 spivotself(testseg); 28121 if (testseg.sh == dummysh) break; 28122 nextseg = testseg; // Go the next subseg. 28123 nextseg.shver = 0; 28124 } while (true); 28125 e1 = sorg(prevseg); 28126 e2 = sdest(nextseg); 28127 len = distance(e1, e2); 28128 lfs_0 = distance(e1, ploop); 28129 // The following assert() happens when -Y option is used. 28130 if (b->nobisect == 0) { 28131 assert(lfs_0 < len); 28132 } 28133 ploop[pointmtrindex] = e1[pointmtrindex] 28134 + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]); 28135 featurecount++; 28136 } else { 28137 // NO feature point, set the size of p be zero. 28138 ploop[pointmtrindex] = 0.0; 28139 } // if (shelltype(checkseg) == SHARP) 28140 } // if (ploop[pointmtrindex] == 0.0) 28141 } // if (pointtype(ploop) != FREESEGVERTEX) 28142 ploop = pointtraverse(); 28143 } 28144 if ((b->verbose > 0) && (featurecount > 0)) { 28145 printf(" %d Steiner feature points.\n", featurecount); 28146 } 28147 } 28148 28149 if (varconstraint) { 28150 // A .var file exists. Adjust feature sizes. 28151 if (in->facetconstraintlist) { 28152 // Have facet area constrains. 28153 subfaces->traversalinit(); 28154 shloop.sh = shellfacetraverse(subfaces); 28155 while (shloop.sh != (shellface *) NULL) { 28156 varlen = areabound(shloop); 28157 if (varlen > 0.0) { 28158 // Check if the three corners are feature points. 28159 varlen = sqrt(varlen); 28160 for (j = 0; j < 3; j++) { 28161 ploop = (point) shloop.sh[3 + j]; 28162 isfeature = false; 28163 idx = pointmark(ploop) - in->firstnumber; 28164 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; 28165 i++) { 28166 checkseg.sh = segsperverlist[i]; 28167 isfeature = (shelltype(checkseg) == SHARP); 28168 } 28169 if (isfeature) { 28170 assert(ploop[pointmtrindex] > 0.0); 28171 if (ploop[pointmtrindex] > varlen) { 28172 ploop[pointmtrindex] = varlen; 28173 } 28174 } 28175 } // for (j = 0; j < 3; j++) 28176 } 28177 shloop.sh = shellfacetraverse(subfaces); 28178 } 28179 } 28180 if (in->segmentconstraintlist) { 28181 // Have facet area constrains. 28182 subsegs->traversalinit(); 28183 shloop.sh = shellfacetraverse(subsegs); 28184 while (shloop.sh != (shellface *) NULL) { 28185 varlen = areabound(shloop); 28186 if (varlen > 0.0) { 28187 // Check if the two endpoints are feature points. 28188 for (j = 0; j < 2; j++) { 28189 ploop = (point) shloop.sh[3 + j]; 28190 isfeature = false; 28191 idx = pointmark(ploop) - in->firstnumber; 28192 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; 28193 i++) { 28194 checkseg.sh = segsperverlist[i]; 28195 isfeature = (shelltype(checkseg) == SHARP); 28196 } 28197 if (isfeature) { 28198 assert(ploop[pointmtrindex] > 0.0); 28199 if (ploop[pointmtrindex] > varlen) { 28200 ploop[pointmtrindex] = varlen; 28201 } 28202 } 28203 } // for (j = 0; j < 2; j++) 28204 } 28205 shloop.sh = shellfacetraverse(subsegs); 28206 } 28207 } 28208 } // if (varconstraint) 28209 28210 delete [] segsperverlist; 28211 delete [] idx2seglist; 28212 delete tetlist; 28213 delete verlist; 28214 } 28215 28217 // // 28218 // enqueueencsub() Add an encroached subface into the queue. // 28219 // // 28221 28222 void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber, 28223 REAL* cent) 28224 { 28225 badface *encsub; 28226 int i; 28227 28228 encsub = (badface *) badsubfaces->alloc(); 28229 encsub->ss = *testsub; 28230 encsub->forg = sorg(*testsub); 28231 encsub->fdest = sdest(*testsub); 28232 encsub->fapex = sapex(*testsub); 28233 encsub->foppo = (point) encpt; 28234 for (i = 0; i < 3; i++) encsub->cent[i] = cent[i]; 28235 encsub->nextitem = (badface *) NULL; 28236 // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes: 28237 // (1) We can regonize it is encroached; (2) It is uniquely queued. 28238 setshell2badface(encsub->ss, encsub); 28239 // Add the subface to the end of a queue (quenumber = 2, high priority). 28240 *subquetail[quenumber] = encsub; 28241 // Maintain a pointer to the NULL pointer at the end of the queue. 28242 subquetail[quenumber] = &encsub->nextitem; 28243 if (b->verbose > 2) { 28244 printf(" Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg), 28245 pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber); 28246 } 28247 } 28248 28250 // // 28251 // dequeueencsub() Remove an enc-subface from the front of the queue. // 28252 // // 28254 28255 tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber) 28256 { 28257 badface *result; 28258 int quenumber; 28259 28260 // Look for a nonempty queue. 28261 for (quenumber = 2; quenumber >= 0; quenumber--) { 28262 result = subquefront[quenumber]; 28263 if (result != (badface *) NULL) { 28264 // Remove the badface from the queue. 28265 subquefront[quenumber] = result->nextitem; 28266 // Maintain a pointer to the NULL pointer at the end of the queue. 28267 if (subquefront[quenumber] == (badface *) NULL) { 28268 subquetail[quenumber] = &subquefront[quenumber]; 28269 } 28270 *pquenumber = quenumber; 28271 return result; 28272 } 28273 } 28274 return (badface *) NULL; 28275 } 28276 28278 // // 28279 // enqueuebadtet() Add a tetrahedron into the queue. // 28280 // // 28282 28283 void tetgenmesh::enqueuebadtet(triface* testtet, REAL ratio2, REAL* cent) 28284 { 28285 badface *newbadtet; 28286 int queuenumber; 28287 int i; 28288 28289 // Allocate space for the bad tetrahedron. 28290 newbadtet = (badface *) badtetrahedrons->alloc(); 28291 newbadtet->tt = *testtet; 28292 newbadtet->key = ratio2; 28293 if (cent != NULL) { 28294 for (i = 0; i < 3; i++) newbadtet->cent[i] = cent[i]; 28295 } else { 28296 for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0; 28297 } 28298 newbadtet->forg = org(*testtet); 28299 newbadtet->fdest = dest(*testtet); 28300 newbadtet->fapex = apex(*testtet); 28301 newbadtet->foppo = oppo(*testtet); 28302 newbadtet->nextitem = (badface *) NULL; 28303 // Determine the appropriate queue to put the bad tetrahedron into. 28304 if (ratio2 > b->goodratio) { 28305 // queuenumber = (int) ((ratio2 - b->goodratio) / 0.5); 28306 queuenumber = (int) (64.0 - 64.0 / ratio2); 28307 // 'queuenumber' may overflow (negative) caused by a very large ratio. 28308 if ((queuenumber > 63) || (queuenumber < 0)) { 28309 queuenumber = 63; 28310 } 28311 } else { 28312 // It's not a bad ratio; put the tet in the lowest-priority queue. 28313 queuenumber = 0; 28314 } 28315 28316 // Are we inserting into an empty queue? 28317 if (tetquefront[queuenumber] == (badface *) NULL) { 28318 // Yes. Will this become the highest-priority queue? 28319 if (queuenumber > firstnonemptyq) { 28320 // Yes, this is the highest-priority queue. 28321 nextnonemptyq[queuenumber] = firstnonemptyq; 28322 firstnonemptyq = queuenumber; 28323 } else { 28324 // No. Find the queue with next higher priority. 28325 i = queuenumber + 1; 28326 while (tetquefront[i] == (badface *) NULL) { 28327 i++; 28328 } 28329 // Mark the newly nonempty queue as following a higher-priority queue. 28330 nextnonemptyq[queuenumber] = nextnonemptyq[i]; 28331 nextnonemptyq[i] = queuenumber; 28332 } 28333 // Put the bad tetrahedron at the beginning of the (empty) queue. 28334 tetquefront[queuenumber] = newbadtet; 28335 } else { 28336 // Add the bad tetrahedron to the end of an already nonempty queue. 28337 tetquetail[queuenumber]->nextitem = newbadtet; 28338 } 28339 // Maintain a pointer to the last tetrahedron of the queue. 28340 tetquetail[queuenumber] = newbadtet; 28341 28342 if (b->verbose > 2) { 28343 printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n", 28344 pointmark(newbadtet->forg), pointmark(newbadtet->fdest), 28345 pointmark(newbadtet->fapex), pointmark(newbadtet->foppo), 28346 sqrt(ratio2), queuenumber); 28347 } 28348 } 28349 28351 // // 28352 // dequeuebadtet() Remove a tetrahedron from the front of the queue. // 28353 // // 28355 28356 tetgenmesh::badface* tetgenmesh::topbadtetra() 28357 { 28358 // Keep a record of which queue was accessed in case dequeuebadtetra() 28359 // is called later. 28360 recentq = firstnonemptyq; 28361 // If no queues are nonempty, return NULL. 28362 if (firstnonemptyq < 0) { 28363 return (badface *) NULL; 28364 } else { 28365 // Return the first tetrahedron of the highest-priority queue. 28366 return tetquefront[firstnonemptyq]; 28367 } 28368 } 28369 28370 void tetgenmesh::dequeuebadtet() 28371 { 28372 badface *deadbadtet; 28373 int i; 28374 28375 // If queues were empty last time topbadtetra() was called, do nothing. 28376 if (recentq >= 0) { 28377 // Find the tetrahedron last returned by topbadtetra(). 28378 deadbadtet = tetquefront[recentq]; 28379 // Remove the tetrahedron from the queue. 28380 tetquefront[recentq] = deadbadtet->nextitem; 28381 // If this queue is now empty, update the list of nonempty queues. 28382 if (deadbadtet == tetquetail[recentq]) { 28383 // Was this the highest-priority queue? 28384 if (firstnonemptyq == recentq) { 28385 // Yes; find the queue with next lower priority. 28386 firstnonemptyq = nextnonemptyq[firstnonemptyq]; 28387 } else { 28388 // No; find the queue with next higher priority. 28389 i = recentq + 1; 28390 while (tetquefront[i] == (badface *) NULL) { 28391 i++; 28392 } 28393 nextnonemptyq[i] = nextnonemptyq[recentq]; 28394 } 28395 } 28396 // Return the bad tetrahedron to the pool. 28397 badfacedealloc(badtetrahedrons, deadbadtet); 28398 } 28399 } 28400 28402 // // 28403 // checkseg4encroach() Check a subsegment to see if it is encroached. // 28404 // // 28405 // A segment s is encroached if there is a vertex lies inside or on its dia- // 28406 // metral circumsphere, i.e., s faces an angle theta >= 90 degrees. // 28407 // // 28408 // If 'testpt' (p) != NULL, only test if 'testseg' (s) is encroached by it, // 28409 // else, check all apexes of faces around s. Return TRUE if s is encroached. // 28410 // If and 'enqflag' is TRUE, add it into 'badsubsegs' if s is encroached. // 28411 // // 28412 // If 'prefpt' != NULL, it returns the reference point (defined in my paper) // 28413 // if it exists. This point is will be used to split s. // 28414 // // 28416 28417 bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt, 28418 bool enqflag) 28419 { 28420 badface *encsubseg; 28421 triface starttet, spintet; 28422 point eorg, edest, eapex, encpt; 28423 REAL cent[3], radius, dist, diff; 28424 REAL maxradius; 28425 bool enq; 28426 int hitbdry; 28427 28428 enq = false; 28429 eorg = sorg(*testseg); 28430 edest = sdest(*testseg); 28431 cent[0] = 0.5 * (eorg[0] + edest[0]); 28432 cent[1] = 0.5 * (eorg[1] + edest[1]); 28433 cent[2] = 0.5 * (eorg[2] + edest[2]); 28434 radius = distance(cent, eorg); 28435 28436 if (varconstraint && (areabound(*testseg) > 0.0)) { 28437 enq = (2.0 * radius) > areabound(*testseg); 28438 } 28439 28440 if (!enq) { 28441 maxradius = 0.0; 28442 if (testpt == (point) NULL) { 28443 // Check if it is encroached by traversing all faces containing it. 28444 sstpivot(testseg, &starttet); 28445 eapex = apex(starttet); 28446 spintet = starttet; 28447 hitbdry = 0; 28448 do { 28449 dist = distance(cent, apex(spintet)); 28450 diff = dist - radius; 28451 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. 28452 if (diff <= 0.0) { 28453 // s is encroached. 28454 enq = true; 28455 if (prefpt != (point *) NULL) { 28456 // Find the reference point. 28457 encpt = apex(spintet); 28458 circumsphere(eorg, edest, encpt, NULL, NULL, &dist); 28459 if (dist > maxradius) { 28460 // Rememebr this point. 28461 *prefpt = encpt; 28462 maxradius = dist; 28463 } 28464 } else { 28465 break; 28466 } 28467 } 28468 if (!fnextself(spintet)) { 28469 hitbdry++; 28470 if (hitbdry < 2) { 28471 esym(starttet, spintet); 28472 if (!fnextself(spintet)) { 28473 hitbdry++; 28474 } 28475 } 28476 } 28477 } while (apex(spintet) != eapex && (hitbdry < 2)); 28478 } else { 28479 // Only check if 'testseg' is encroached by 'testpt'. 28480 dist = distance(cent, testpt); 28481 diff = dist - radius; 28482 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. 28483 enq = (diff <= 0.0); 28484 } 28485 } 28486 28487 if (enq && enqflag) { 28488 if (b->verbose > 2) { 28489 printf(" Queuing encroaching subsegment (%d, %d).\n", 28490 pointmark(eorg), pointmark(edest)); 28491 } 28492 encsubseg = (badface *) badsubsegs->alloc(); 28493 encsubseg->ss = *testseg; 28494 encsubseg->forg = eorg; 28495 encsubseg->fdest = edest; 28496 encsubseg->foppo = (point) NULL; // Not used. 28497 // Set the pointer of 'encsubseg' into 'testseg'. It has two purposes: 28498 // (1) We can regonize it is encroached; (2) It is uniquely queued. 28499 setshell2badface(encsubseg->ss, encsubseg); 28500 } 28501 28502 return enq; 28503 } 28504 28506 // // 28507 // checksub4encroach() Check a subface to see if it is encroached. // 28508 // // 28509 // A subface f is encroached if there is a vertex inside or on its diametral // 28510 // circumsphere. // 28511 // // 28512 // If 'testpt (p) != NULL', test if 'testsub' (f) is encroached by it, else, // 28513 // test if f is encroached by one of the two opposites of the adjacent tets. // 28514 // Return TRUE if f is encroached and queue it if 'enqflag' is set. // 28515 // // 28517 28518 bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag) 28519 { 28520 triface abuttet; 28521 point pa, pb, pc, encpt; 28522 REAL A[4][4], rhs[4], D; 28523 REAL cent[3], area; 28524 REAL radius, dist, diff; 28525 bool enq; 28526 int indx[4]; 28527 int quenumber; 28528 28529 enq = false; 28530 radius = 0.0; 28531 encpt = (point) NULL; 28532 28533 pa = sorg(*testsub); 28534 pb = sdest(*testsub); 28535 pc = sapex(*testsub); 28536 28537 // Compute the coefficient matrix A (3x3). 28538 A[0][0] = pb[0] - pa[0]; 28539 A[0][1] = pb[1] - pa[1]; 28540 A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb) 28541 A[1][0] = pc[0] - pa[0]; 28542 A[1][1] = pc[1] - pa[1]; 28543 A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc) 28544 cross(A[0], A[1], A[2]); // vector V3 (V1 X V2) 28545 28546 if (varconstraint && (areabound(*testsub) > 0.0)) { 28547 // Check if the subface has too big area. 28548 area = 0.5 * sqrt(dot(A[2], A[2])); 28549 enq = area > areabound(*testsub); 28550 if (enq) { 28551 quenumber = 2; // A queue of subfaces having too big area. 28552 } 28553 } 28554 28555 // Compute the right hand side vector b (3x1). 28556 rhs[0] = 0.5 * dot(A[0], A[0]); 28557 rhs[1] = 0.5 * dot(A[1], A[1]); 28558 rhs[2] = 0.0; 28559 // Solve the 3 by 3 equations use LU decomposition with partial pivoting 28560 // and backward and forward substitute.. 28561 if (lu_decmp(A, 3, indx, &D, 0)) { 28562 lu_solve(A, 3, indx, rhs, 0); 28563 cent[0] = pa[0] + rhs[0]; 28564 cent[1] = pa[1] + rhs[1]; 28565 cent[2] = pa[2] + rhs[2]; 28566 radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); 28567 } 28568 28569 if (!enq) { 28570 // Check if the subface is encroached. 28571 if (testpt == (point) NULL) { 28572 stpivot(*testsub, abuttet); 28573 if (abuttet.tet != dummytet) { 28574 dist = distance(cent, oppo(abuttet)); 28575 diff = dist - radius; 28576 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. 28577 enq = (diff <= 0.0); 28578 if (enq) encpt = oppo(abuttet); 28579 } 28580 if (!enq) { 28581 sesymself(*testsub); 28582 stpivot(*testsub, abuttet); 28583 if (abuttet.tet != dummytet) { 28584 dist = distance(cent, oppo(abuttet)); 28585 diff = dist - radius; 28586 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. 28587 enq = (diff <= 0.0); 28588 if (enq) encpt = oppo(abuttet); 28589 } 28590 } 28591 } else { 28592 dist = distance(cent, testpt); 28593 diff = dist - radius; 28594 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. 28595 enq = (diff <= 0.0); 28596 } 28597 if (enq) { 28598 quenumber = 0; // A queue of encroached subfaces. 28599 } 28600 } 28601 28602 if (enq && enqflag) { 28603 enqueueencsub(testsub, encpt, quenumber, cent); 28604 } 28605 28606 return enq; 28607 } 28608 28610 // // 28611 // checktet4badqual() Test a tetrahedron for quality measures. // 28612 // // 28613 // Tests a tetrahedron to see if it satisfies the minimum ratio condition // 28614 // and the maximum volume condition. Tetrahedra that aren't upto spec are // 28615 // added to the bad tetrahedron queue. // 28616 // // 28618 28619 bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag) 28620 { 28621 point pa, pb, pc, pd, pe1, pe2; 28622 REAL vda[3], vdb[3], vdc[3]; 28623 REAL vab[3], vbc[3], vca[3]; 28624 REAL N[4][3], A[4][4], rhs[4], D; 28625 REAL elen[6], circumcent[3]; 28626 REAL bicent[3], offcent[3]; 28627 offcent[0] = 0.0; // Just to avoid uninitialised value warnings. 28628 offcent[1] = 0.0; // Just to avoid uninitialised value warnings. 28629 offcent[2] = 0.0; // Just to avoid uninitialised value warnings. 28630 REAL volume, L, cosd; 28631 REAL radius2, smlen2, ratio2; 28632 REAL dist, sdist, split; 28633 bool enq; 28634 int indx[4]; 28635 int sidx, i, j; 28636 28637 pa = (point) testtet->tet[4]; 28638 pb = (point) testtet->tet[5]; 28639 pc = (point) testtet->tet[6]; 28640 pd = (point) testtet->tet[7]; 28641 28642 // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c. 28643 // Set the matrix A = [vda, vdb, vdc]^T. 28644 for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i]; 28645 for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i]; 28646 for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i]; 28647 // Get the rest edge vectors 28648 for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i]; 28649 for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i]; 28650 for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i]; 28651 28652 // Lu-decompose the matrix A. 28653 lu_decmp(A, 3, indx, &D, 0); 28654 // Get the volume of abcd. 28655 volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; 28656 if (volume < 0.0) volume = -volume; 28657 // Check the radiu-edge ratio of the tet. 28658 rhs[0] = 0.5 * dot(vda, vda); 28659 rhs[1] = 0.5 * dot(vdb, vdb); 28660 rhs[2] = 0.5 * dot(vdc, vdc); 28661 lu_solve(A, 3, indx, rhs, 0); 28662 // Get the circumcenter. 28663 for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i]; 28664 // Get the square of the circumradius. 28665 radius2 = dot(rhs, rhs); 28666 // Find the square of the shortest edge length. 28667 elen[0] = dot(vda, vda); 28668 elen[1] = dot(vdb, vdb); 28669 elen[2] = dot(vdc, vdc); 28670 elen[3] = dot(vab, vab); 28671 elen[4] = dot(vbc, vbc); 28672 elen[5] = dot(vca, vca); 28673 smlen2 = elen[0]; sidx = 0; 28674 for (i = 1; i < 6; i++) { 28675 if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; } 28676 } 28677 // Calculate the square of radius-edge ratio. 28678 ratio2 = radius2 / smlen2; 28679 // Check whether the ratio is smaller than permitted. 28680 enq = ratio2 > b->goodratio; 28681 if (!enq) { 28682 // abcd has good ratio. 28683 // ratio2 = 0.0; 28684 // if (b->offcenter) { 28685 // Test if it is a sliver. 28686 // Compute the 4 face normals (N[0], ..., N[3]). 28687 for (j = 0; j < 3; j++) { 28688 for (i = 0; i < 3; i++) rhs[i] = 0.0; 28689 rhs[j] = 1.0; // Positive means the inside direction 28690 lu_solve(A, 3, indx, rhs, 0); 28691 for (i = 0; i < 3; i++) N[j][i] = rhs[i]; 28692 } 28693 // Get the fourth normal by summing up the first three. 28694 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; 28695 // Normalized the normals. 28696 for (i = 0; i < 4; i++) { 28697 L = sqrt(dot(N[i], N[i])); 28698 if (L > 0.0) { 28699 for (j = 0; j < 3; j++) N[i][j] /= L; 28700 } 28701 } 28702 // N[0] is the normal of face bcd. Test the dihedral angles at edge 28703 // cd, bd, and bc to see if they are too small or too big. 28704 for (i = 1; i < 4 && !enq; i++) { 28705 cosd = -dot(N[0], N[i]); // Edge cd, bd, bc. 28706 enq = cosd > cosmindihed; 28707 } 28708 if (!enq) { 28709 for (i = 2; i < 4 && !enq; i++) { 28710 cosd = -dot(N[1], N[i]); // Edge ad, ac 28711 enq = cosd > cosmindihed; 28712 } 28713 if (!enq) { 28714 cosd = -dot(N[2], N[3]); // Edge ab 28715 enq = cosd > cosmindihed; 28716 } 28717 } 28718 // } 28719 } else if (b->offcenter) { 28720 // abcd has bad-quality. Use off-center instead of circumcenter. 28721 switch (sidx) { 28722 case 0: // edge da. 28723 pe1 = pd; pe2 = pa; break; 28724 case 1: // edge db. 28725 pe1 = pd; pe2 = pb; break; 28726 case 2: // edge dc. 28727 pe1 = pd; pe2 = pc; break; 28728 case 3: // edge ab. 28729 pe1 = pa; pe2 = pb; break; 28730 case 4: // edge bc. 28731 pe1 = pb; pe2 = pc; break; 28732 case 5: // edge ca. 28733 pe1 = pc; pe2 = pa; break; 28734 default: 28735 pe1 = pe2 = (point) NULL; // Avoid a compile warning. 28736 } 28737 // The shortest edge is e1->e2. 28738 for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]); 28739 dist = distance(bicent, circumcent); 28740 // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle. 28741 // The following formulae is from 28742 sdist = b->alpha3 * (b->minratio+sqrt(b->goodratio-0.25))* sqrt(smlen2); 28743 split = sdist / dist; 28744 if (split > 1.0) split = 1.0; 28745 // Get the off-center. 28746 for (i = 0; i < 3; i++) { 28747 offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]); 28748 } 28749 } 28750 28751 if (!enq && (b->varvolume || b->fixedvolume)) { 28752 // Check if the tet has too big volume. 28753 enq = b->fixedvolume && (volume > b->maxvolume); 28754 if (!enq && b->varvolume) { 28755 enq = (volume > volumebound(testtet->tet)) && 28756 (volumebound(testtet->tet) > 0.0); 28757 } 28758 } 28759 28760 if (!enq) { 28761 // Check if the user-defined sizing function is satisfied. 28762 if (b->metric) { 28763 // assert(b->alpha1 > 0.0); 28764 sdist = sqrt(radius2) / b->alpha1; 28765 for (i = 0; i < 4; i++) { 28766 pa = (point) testtet->tet[4 + i]; 28767 // Get the indicated size of p. 28768 dist = pa[pointmtrindex]; // dist = b->alpha1 * pa[pointmtrindex]; 28769 enq = ((dist < sdist) && (dist > 0.0)); 28770 if (enq) break; // It is bad wrt. a node constraint. 28771 // *** Experiment ! Stop test if c is inside H(a). 28772 // if ((dist > 0.0) && (dist > sdist)) break; 28773 } 28774 // *** Experiment ! 28775 // enq = (i == 4); // Does c lies outside all sparse-ball? 28776 } // if (b->metric) 28777 } 28778 28779 if (enq && enqflag) { 28780 if (b->offcenter && (ratio2 > b->goodratio)) { 28781 for (i = 0; i < 3; i++) circumcent[i] = offcent[i]; 28782 } 28783 enqueuebadtet(testtet, ratio2, circumcent); 28784 } 28785 28786 return enq; 28787 } 28788 28790 // // 28791 // acceptsegpt() Check if a segment point can be inserted or not. // 28792 // // 28793 // Segment(ab) is indicated to be split by a point p (\in ab). This routine // 28794 // decides whether p can be inserted or not. // 28795 // // 28796 // p can not be inserted either the '-Y' option is used and ab is a hull // 28797 // segment or '-YY' option is used. // 28798 // // 28799 // p can be inserted if it is in one of the following cases: // 28800 // (1) if L = |a - b| is too long wrt the edge constraint; or // 28801 // (2) if |x - p| > \alpha_2 H(x) for x = a, b; or // 28802 // (3) if 'refpt' != NULL. // 28803 // // 28805 28806 bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg) 28807 { 28808 point p[2]; 28809 REAL L, lfs; 28810 int i, j; 28811 28812 if (b->nobisect == 1) { 28813 // '-Y'. It can not be split if it is on the hull. 28814 triface spintet; 28815 point pc; 28816 sstpivot(splitseg, &spintet); 28817 assert(spintet.tet != dummytet); 28818 pc = apex(spintet); 28819 do { 28820 if (!fnextself(spintet)) { 28821 // Meet a boundary face - s is on the hull. 28822 return false; 28823 } 28824 } while (pc != apex(spintet)); 28825 } else if (b->nobisect > 1) { 28826 // '-YY'. Do not split it. 28827 return false; 28828 } 28829 28830 p[0] = sorg(*splitseg); 28831 p[1] = sdest(*splitseg); 28832 if (varconstraint && (areabound(*splitseg) > 0)) { 28833 lfs = areabound(*splitseg); 28834 L = distance(p[0], p[1]); 28835 if (L > lfs) { 28836 return true; // case (1) 28837 } 28838 } 28839 28840 j = 0; // Use j to count the number of inside balls. 28841 for (i = 0; i < 2; i++) { 28842 // Check if p is inside the protect ball of q. 28843 if (p[i][pointmtrindex] > 0.0) { 28844 lfs = b->alpha2 * p[i][pointmtrindex]; 28845 L = distance(p[i], segpt); 28846 if (L < lfs) j++; // p is inside ball. 28847 } 28848 } 28849 if (j == 0) return true; // case (3). 28850 28851 // If 'refpt' != NULL, force p to be inserted. 28852 if (refpt != (point) NULL) { 28853 cdtenforcesegpts++; 28854 return true; 28855 } 28856 28857 // Do not split it. 28858 rejsegpts++; 28859 return false; 28860 } 28861 28863 // // 28864 // acceptfacpt() Check if a facet point can be inserted or not. // 28865 // // 28866 // 'subceillist' is CBC(p). 'verlist' (V) is empty on input, it returns the // 28867 // set of vertices of CBC(p). // 28868 // // 28869 // p can not be inserted either the '-Y' option is used and the facet is on // 28870 // the hull or '-YY' option is used. // 28871 // // 28872 // p can be inserted if |p - v| > \alpha_2 H(v), for all v \in V. // 28873 // // 28875 28876 bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist) 28877 { 28878 face *testsh; 28879 point p[2], ploop; 28880 REAL L, lfs; 28881 int idx, i, j; 28882 28883 if (b->nobisect == 1) { 28884 // '-Y'. p can not be inserted if CBC(p) is on the hull. 28885 triface testtet; 28886 testsh = (face *)(* subceillist)[0]; 28887 stpivot(*testsh, testtet); 28888 if (testtet.tet != dummytet) { 28889 sesymself(*testsh); 28890 stpivot(*testsh, testtet); 28891 } 28892 if (testtet.tet == dummytet) return false; 28893 } else if (b->nobisect > 1) { 28894 // '-YY'. Do not split s. 28895 return false; 28896 } 28897 28898 // Collect the vertices of CBC(p), save them in V. 28899 for (i = 0; i < subceillist->len(); i++) { 28900 testsh = (face *)(* subceillist)[i]; 28901 p[0] = sorg(*testsh); 28902 p[1] = sdest(*testsh); 28903 for (j = 0; j < 2; j++) { 28904 idx = pointmark(p[j]); 28905 if (idx >= 0) { 28906 setpointmark(p[j], -idx - 1); 28907 verlist->append(&(p[j])); 28908 } 28909 } 28910 } 28911 28912 j = 0; // Use j to count the number of inside balls. 28913 for (i = 0; i < verlist->len(); i++) { 28914 ploop = * (point *)(* verlist)[i]; 28915 // Uninfect q. 28916 idx = pointmark(ploop); 28917 setpointmark(ploop, -(idx + 1)); 28918 // Check if p is inside the protect ball of q. 28919 if (ploop[pointmtrindex] > 0.0) { 28920 lfs = b->alpha2 * ploop[pointmtrindex]; 28921 L = distance(ploop, facpt); 28922 if (L < lfs) j++; // p is inside ball. 28923 } 28924 } 28925 verlist->clear(); 28926 28927 if (j == 0) return true; // case (3). 28928 28929 rejsubpts++; 28930 return false; 28931 } 28932 28934 // // 28935 // acceptvolpt() Check if a volume point can be inserted or not. // 28936 // // 28937 // 'ceillist' is B(p). 'verlist' (V) is empty on input, it returns the set // 28938 // of vertices of B(p). // 28939 // // 28940 // p can be split if |p - v| > \alpha_2 H(v), for all v \in V. // 28941 // // 28943 28944 bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist) 28945 { 28946 triface* testtet; 28947 point p[3], ploop; 28948 REAL L, lfs; 28949 int idx, i, j; 28950 28951 // Collect the vertices of CBC(p), save them in V. 28952 for (i = 0; i < ceillist->len(); i++) { 28953 testtet = (triface *)(* ceillist)[i]; 28954 p[0] = org(*testtet); 28955 p[1] = dest(*testtet); 28956 p[2] = apex(*testtet); 28957 for (j = 0; j < 3; j++) { 28958 idx = pointmark(p[j]); 28959 if (idx >= 0) { 28960 setpointmark(p[j], -idx - 1); 28961 verlist->append(&(p[j])); 28962 } 28963 } 28964 } 28965 28966 j = 0; // Use j to counte the number of inside balls. 28967 for (i = 0; i < verlist->len(); i++) { 28968 ploop = * (point *)(* verlist)[i]; 28969 // Uninfect q. 28970 idx = pointmark(ploop); 28971 setpointmark(ploop, -(idx + 1)); 28972 // Check if p is inside the protect ball of q. 28973 if (ploop[pointmtrindex] > 0.0) { 28974 lfs = b->alpha2 * ploop[pointmtrindex]; 28975 L = distance(ploop, volpt); 28976 if (L < lfs) j++; // p is inside the protect ball. 28977 } 28978 } 28979 verlist->clear(); 28980 28981 if (j == 0) return true; // case (2). 28982 28983 rejtetpts++; 28984 return false; 28985 } 28986 28988 // // 28989 // getsplitpoint() Get the inserting point in a segment. // 28990 // // 28992 28993 void tetgenmesh::getsplitpoint(point e1, point e2, point refpt, point newpt) 28994 { 28995 point ei, ej; 28996 REAL split, L, d1, d2, ps, rs; 28997 bool acutea, acuteb; 28998 int i; 28999 29000 if (refpt != (point) NULL) { 29001 // Use the CDT rules to split the segment. 29002 acutea = (pointtype(e1) == ACUTEVERTEX); 29003 acuteb = (pointtype(e2) == ACUTEVERTEX); 29004 if (acutea ^ acuteb) { 29005 // Only one endpoint is acute. Use rule-2 or rule-3. 29006 ei = acutea ? e1 : e2; 29007 ej = acutea ? e2 : e1; 29008 L = distance(ei, ej); 29009 // Apply rule-2. 29010 d1 = distance(ei, refpt); 29011 split = d1 / L; 29012 for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]); 29013 // Check if rule-3 is needed. 29014 d2 = distance(refpt, newpt); 29015 if (d2 > (L - d1)) { 29016 // Apply rule-3. 29017 if ((d1 - d2) > (0.5 * d1)) { 29018 split = (d1 - d2) / L; 29019 } else { 29020 split = 0.5 * d1 / L; 29021 } 29022 for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]); 29023 if (b->verbose > 1) { 29024 printf(" Found by rule-3:"); 29025 } 29026 r3count++; 29027 } else { 29028 if (b->verbose > 1) { 29029 printf(" Found by rule-2:"); 29030 } 29031 r2count++; 29032 } 29033 if (b->verbose > 1) { 29034 printf(" center %d, split = %.12g.\n", pointmark(ei), split); 29035 } 29036 // Add a random perturbation on newpt. 29037 d1 = distance(ei, newpt); 29038 d2 = distance(newpt, refpt); 29039 ps = randgenerator(d2 * b->epsilon2 * 1e+2); 29040 rs = ps / d1; 29041 // Perturb newpt away from ei. 29042 for (i = 0; i < 3; i++) newpt[i] = ei[i] + (1.0+rs) * (newpt[i] - ei[i]); 29043 } else { 29044 // Both endpoints are acute or not. Split it at the middle. 29045 for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]); 29046 // Add a random perturbation on newpt. 29047 d1 = 0.5 * distance(e1, e2); 29048 ps = randgenerator(d1 * b->epsilon2 * 1e+2); 29049 rs = ps / d1; 29050 for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]); 29051 } 29052 } else { 29053 // Split the segment at its midpoint. 29054 for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]); 29055 // Add a random perturbation on newpt. 29056 d1 = 0.5 * distance(e1, e2); 29057 ps = randgenerator(d1 * b->epsilon2 * 1e+2); 29058 rs = ps / d1; 29059 for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]); 29060 } 29061 } 29062 29064 // // 29065 // shepardinterpolation() Interpolate the local size of a newpoint. // 29066 // // 29067 // The classical Shepard interoplation (inversed weighted distance) is used. // 29068 // (With the choice p = 2). // 29069 // // 29070 // 'verlist' contains a list vertices neighboring to 'newpt'. // 29071 // // 29073 29074 void tetgenmesh::shepardinterpolate(point newpt, list *verlist) 29075 { 29076 point neipt; 29077 REAL *weights, sumweight; 29078 REAL vec[3]; 29079 int i, j; 29080 29081 weights = new REAL[verlist->len()]; 29082 sumweight = 0.0; 29083 29084 // Calculate the weight of each point. 29085 for (i = 0; i < verlist->len(); i++) { 29086 neipt = * (point *)(* verlist)[i]; 29087 for (j = 0; j < 3; j++) vec[j] = neipt[j] - newpt[j]; 29088 weights[i] = 1.0 / dot(vec, vec); 29089 sumweight += weights[i]; 29090 } 29091 // Interpolate. 29092 newpt[pointmtrindex] = 0.0; 29093 for (i = 0; i < verlist->len(); i++) { 29094 neipt = * (point *)(* verlist)[i]; 29095 newpt[pointmtrindex] += (weights[i] * neipt[pointmtrindex]) / sumweight; 29096 } 29097 29098 delete [] weights; 29099 } 29100 29102 // // 29103 // setnewpointsize() Set the size for a new point. // 29104 // // 29105 // The size of the new point p is interpolated either from a background mesh // 29106 // (b->bgmesh) or from the two input endpoints. // 29107 // // 29109 29110 void tetgenmesh::setnewpointsize(point newpt, point e1, point e2) 29111 { 29112 if (b->metric) { 29113 // Interpolate the point size in a background mesh. 29114 triface bgmtet; 29115 // Get a tet in background mesh for locating p. 29116 decode(point2bgmtet(e1), bgmtet); 29117 p1interpolatebgm(newpt, &bgmtet, NULL); 29118 } else { 29119 if (e2 != (point) NULL) { 29120 // Interpolate the size between the two endpoints. 29121 REAL split, l, d; 29122 l = distance(e1, e2); 29123 d = distance(e1, newpt); 29124 split = d / l; 29125 #ifdef SELF_CHECK 29126 // Check if e1 and e2 are endpoints of a sharp segment. 29127 assert(e1[pointmtrindex] > 0.0); 29128 assert(e2[pointmtrindex] > 0.0); 29129 #endif 29130 newpt[pointmtrindex] = (1.0 - split) * e1[pointmtrindex] 29131 + split * e2[pointmtrindex]; 29132 } 29133 } 29134 } 29135 29137 // // 29138 // splitencseg() Split an enc-seg and recover the Delaunayness by flips. // 29139 // // 29141 29142 void tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist, 29143 list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet, 29144 bool optflag) 29145 { 29146 list *mytetlist; 29147 queue *myflipque; 29148 triface starttet; 29149 face startsh, spinsh, checksh; 29150 int i; 29151 29152 mytetlist = NULL; 29153 myflipque = NULL; 29154 29155 if (optflag) { 29156 mytetlist = new list(sizeof(triface), NULL, 1024); 29157 myflipque = new queue(sizeof(badface)); 29158 tetlist = mytetlist; 29159 flipque = myflipque; 29160 } 29161 29162 // Use the base orientation (important in this routine). 29163 splitseg->shver = 0; 29164 // Insert p, this should always success. 29165 sstpivot(splitseg, &starttet); 29166 splittetedge(newpt, &starttet, flipque); 29167 // Remove locally non-Delaunay faces by flipping. 29168 flip(flipque, NULL); // lawson(NULL, flipque); 29169 29170 if (!optflag) { 29171 // Check the two new subsegs to see if they're encroached (not by p). 29172 for (i = 0; i < 2; i++) { 29173 if (!shell2badface(*splitseg)) { 29174 checkseg4encroach(splitseg, NULL, NULL, true); 29175 } 29176 if (i == 1) break; // Two new segs have been checked. 29177 senextself(*splitseg); 29178 spivotself(*splitseg); 29179 #ifdef SELF_CHECK 29180 assert(splitseg->sh != (shellface *) NULL); 29181 #endif 29182 splitseg->shver = 0; 29183 } 29184 // Check the new subfaces to see if they're encroached (not by p). 29185 if (chkencsub) { 29186 spivot(*splitseg, startsh); 29187 spinsh = startsh; 29188 do { 29189 sublist->append(&spinsh); 29190 formstarpolygon(newpt, sublist, verlist); 29191 for (i = 0; i < sublist->len(); i++) { 29192 checksh = * (face *)(* sublist)[i]; 29193 if (!shell2badface(checksh)) { 29194 checksub4encroach(&checksh, NULL, true); 29195 } 29196 } 29197 sublist->clear(); 29198 if (verlist) verlist->clear(); 29199 spivotself(spinsh); 29200 } while (spinsh.sh != startsh.sh); 29201 } 29202 } // if (!optflag) 29203 29204 // Collect the new tets connecting at p. 29205 sstpivot(splitseg, &starttet); 29206 tetlist->append(&starttet); 29207 formstarpolyhedron(newpt, tetlist, verlist, true); 29208 29209 if (!optflag) { 29210 // Check if p encroaches adjacent segments. 29211 tallencsegs(newpt, 1, &tetlist); 29212 if (chkencsub) { 29213 // Check if p encroaches adjacent subfaces. 29214 tallencsubs(newpt, 1, &tetlist); 29215 } 29216 if (chkbadtet) { 29217 // Check if there are new bad quality tets at p. 29218 for (i = 0; i < tetlist->len(); i++) { 29219 starttet = * (triface *)(* tetlist)[i]; 29220 checktet4badqual(&starttet, true); 29221 } 29222 } 29223 tetlist->clear(); 29224 } else { 29225 // Check if new tets are non-optimal. 29226 for (i = 0; i < tetlist->len(); i++) { 29227 starttet = * (triface *)(* tetlist)[i]; 29228 checktet4opt(&starttet, true); 29229 } 29230 delete mytetlist; 29231 delete myflipque; 29232 } 29233 } 29234 29236 // // 29237 // tallencsegs() Check for encroached segments and save them in list. // 29238 // // 29239 // If 'testpt' (p) != NULL, only check if segments are encroached by p, else,// 29240 // check all the nearby mesh vertices. // 29241 // // 29242 // If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the // 29243 // segments which are on B_i(p)s, else, check the entire list of segments // 29244 // (in the pool 'this->subsegs'). // 29245 // // 29247 29248 bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists) 29249 { 29250 list *ceillist; 29251 triface ceiltet; 29252 face checkseg; 29253 long oldencnum; 29254 int i, j, k; 29255 29256 // Remember the current number of encroached segments. 29257 oldencnum = badsubsegs->items; 29258 29259 if (ceillists != (list **) NULL) { 29260 for (k = 0; k < n; k++) { 29261 ceillist = ceillists[k]; 29262 // Check the segments on B_i(p). 29263 for (i = 0; i < ceillist->len(); i++) { 29264 ceiltet = * (triface *)(* ceillist)[i]; 29265 ceiltet.ver = 0; 29266 for (j = 0; j < 3; j++) { 29267 tsspivot(&ceiltet, &checkseg); 29268 if (checkseg.sh != dummysh) { 29269 // Found a segment. Test it if it isn't in enc-list. 29270 if (!shell2badface(checkseg)) { 29271 checkseg4encroach(&checkseg, testpt, NULL, true); 29272 } 29273 } 29274 enextself(ceiltet); 29275 } 29276 } 29277 } 29278 } else { 29279 // Check the entire list of segments. 29280 subsegs->traversalinit(); 29281 checkseg.sh = shellfacetraverse(subsegs); 29282 while (checkseg.sh != (shellface *) NULL) { 29283 // Test it if it isn't in enc-list. 29284 if (!shell2badface(checkseg)) { 29285 checkseg4encroach(&checkseg, testpt, NULL, true); 29286 } 29287 checkseg.sh = shellfacetraverse(subsegs); 29288 } 29289 } 29290 29291 return (badsubsegs->items > oldencnum); 29292 } 29293 29295 // // 29296 // tallencsubs() Find all encroached subfaces and save them in list. // 29297 // // 29298 // If 'testpt' (p) != NULL, only check if subfaces are encroached by p, else,// 29299 // check the adjacent vertices of subfaces. // 29300 // // 29301 // If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the // 29302 // subfaces which are on B_i(p)s, else, check the entire list of subfaces // 29303 // (in the pool 'this->subfaces'). // 29304 // // 29306 29307 bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists) 29308 { 29309 list *ceillist; 29310 triface ceiltet; 29311 face checksh; 29312 long oldencnum; 29313 int i, k; 29314 29315 // Remember the current number of encroached segments. 29316 oldencnum = badsubfaces->items; 29317 29318 if (ceillists != (list **) NULL) { 29319 for (k = 0; k < n; k++) { 29320 ceillist = ceillists[k]; 29321 // Check the subfaces on B_i(p). 29322 for (i = 0; i < ceillist->len(); i++) { 29323 ceiltet = * (triface *)(* ceillist)[i]; 29324 tspivot(ceiltet, checksh); 29325 if (checksh.sh != dummysh) { 29326 // Found a subface. Test it if it isn't in enc-list. 29327 if (!shell2badface(checksh)) { 29328 checksub4encroach(&checksh, testpt, true); 29329 } 29330 } 29331 } 29332 } 29333 } else { 29334 // Check the entire list of subfaces. 29335 subfaces->traversalinit(); 29336 checksh.sh = shellfacetraverse(subfaces); 29337 while (checksh.sh != (shellface *) NULL) { 29338 // Test it if it isn't in enc-list. 29339 if (!shell2badface(checksh)) { 29340 checksub4encroach(&checksh, testpt, true); 29341 } 29342 checksh.sh = shellfacetraverse(subfaces); 29343 } 29344 } 29345 29346 return (badsubfaces->items > oldencnum); 29347 } 29348 29350 // // 29351 // tallbadtetrahedrons() Queue all the bad-quality tetrahedra in the mesh.// 29352 // // 29354 29355 void tetgenmesh::tallbadtetrahedrons() 29356 { 29357 triface tetloop; 29358 29359 tetrahedrons->traversalinit(); 29360 tetloop.tet = tetrahedrontraverse(); 29361 while (tetloop.tet != (tetrahedron *) NULL) { 29362 checktet4badqual(&tetloop, true); 29363 tetloop.tet = tetrahedrontraverse(); 29364 } 29365 } 29366 29368 // // 29369 // repairencsegs() Repair (split) all the encroached segments. // 29370 // // 29371 // Each encroached segment is repaired by splitting it - inserting a vertex // 29372 // at or near its midpoint. Newly inserted vertices may encroach upon other // 29373 // subsegments, these are also repaired. // 29374 // // 29375 // 'chkencsub' and 'chkbadtet' are two flags that specify whether one should // 29376 // take note of new encroaced subfaces and bad quality tets that result from // 29377 // inserting vertices to repair encroached subsegments. // 29378 // // 29380 29381 void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet) 29382 { 29383 list **tetlists, **ceillists; 29384 list **sublists, **subceillists; 29385 list *tetlist, *sublist; 29386 queue *flipque; 29387 badface *encloop; 29388 face splitseg, symsplitseg; 29389 point newpt, sympt, refpt; 29390 point e1, e2; 29391 enum locateresult symloc; 29392 int nmax, n, i, j; 29393 29394 ceillists = NULL; 29395 flipque = NULL; 29396 subceillists = NULL; 29397 sublist = NULL; 29398 sublists = NULL; 29399 tetlist = NULL; 29400 tetlists = NULL; 29401 29402 n = 0; 29403 nmax = 128; 29404 if (!b->fliprepair) { 29405 tetlists = new list*[nmax]; 29406 ceillists = new list*[nmax]; 29407 sublists = new list*[nmax]; 29408 subceillists = new list*[nmax]; 29409 } else { 29410 tetlist = new list(sizeof(triface), NULL, 1024); 29411 sublist = new list(sizeof(face), NULL, 256); 29412 flipque = new queue(sizeof(badface)); 29413 } 29414 29415 // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1 29416 // if an unlimited number of Steiner points is allowed. 29417 while ((badsubsegs->items > 0) && (steinerleft != 0)) { 29418 badsubsegs->traversalinit(); 29419 encloop = badfacetraverse(badsubsegs); 29420 while ((encloop != (badface *) NULL) && (steinerleft != 0)) { 29421 // Get an encroached subsegment s. 29422 splitseg = encloop->ss; 29423 // Clear the in-queue flag in s. 29424 setshell2badface(splitseg, NULL); 29425 if ((sorg(splitseg) == encloop->forg) && 29426 (sdest(splitseg) == encloop->fdest)) { 29427 if (b->verbose > 1) { 29428 printf(" Get an enc-seg (%d, %d)\n", pointmark(encloop->forg), 29429 pointmark(encloop->fdest)); 29430 } 29431 refpt = (point) NULL; 29432 if (b->conformdel) { 29433 // Look for a reference point. 29434 checkseg4encroach(&splitseg, NULL, &refpt, false); 29435 } 29436 // Create the new point p (at the middle of s). 29437 makepoint(&newpt); 29438 getsplitpoint(encloop->forg, encloop->fdest, refpt, newpt); 29439 setpointtype(newpt, FREESEGVERTEX); 29440 setpoint2sh(newpt, sencode(splitseg)); 29441 // Decide whether p can be inserted or not. 29442 if (acceptsegpt(newpt, refpt, &splitseg)) { 29443 // Is there periodic boundary condition? 29444 if (checkpbcs) { 29445 // Insert points on other segments of incident pbcgroups. 29446 i = shellmark(splitseg) - 1; 29447 for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) { 29448 makepoint(&sympt); 29449 symloc = getsegpbcsympoint(newpt, &splitseg, sympt, &symsplitseg, 29450 segpglist[j]); 29451 if (symloc == ONEDGE) { 29452 if (symsplitseg.sh != splitseg.sh) { 29453 // Insert sympt. 29454 setpointtype(sympt, FREESEGVERTEX); 29455 setpoint2sh(sympt, sencode(symsplitseg)); 29456 // Save the endpoints of the seg for size interpolation. 29457 e1 = sorg(symsplitseg); 29458 if (shelltype(symsplitseg) == SHARP) { 29459 e2 = sdest(symsplitseg); 29460 } else { 29461 e2 = (point) NULL; // No need to do size interpolation. 29462 } 29463 if (!b->fliprepair) { 29464 // Form BC(symp), B(symp), CBC(symp)s, C(symp)s. 29465 formbowatcavity(sympt, &symsplitseg, NULL, &n, &nmax, 29466 sublists, subceillists, tetlists, ceillists); 29467 // Validate BC(symp), B(symp), CBC(symp)s, C(symp)s. 29468 if (trimbowatcavity(sympt, &symsplitseg, n, sublists, 29469 subceillists, tetlists, ceillists, -1.0)) { 29470 bowatinsertsite(sympt, &symsplitseg, n, sublists, 29471 subceillists, tetlists, ceillists, NULL, flipque, 29472 true, chkencsub, chkbadtet); 29473 setnewpointsize(sympt, e1, e2); 29474 if (steinerleft > 0) steinerleft--; 29475 } else { 29476 // p did not insert for invalid BC(symp). 29477 pointdealloc(sympt); 29478 } 29479 // Free the memory allocated in formbowatcavity(). 29480 releasebowatcavity(&symsplitseg, n, sublists, subceillists, 29481 tetlists, ceillists); 29482 } else { 29483 splitencseg(sympt, &symsplitseg, tetlist, sublist, NULL, 29484 flipque, chkencsub, chkbadtet, false); 29485 setnewpointsize(sympt, e1, e2); 29486 if (steinerleft > 0) steinerleft--; 29487 } 29488 } else { 29489 // The sympt are on the same segment. It is possible when 29490 // splitseg is the symmetric rotating axes. 29491 pointdealloc(sympt); 29492 } 29493 } else if (symloc == ONVERTEX) { 29494 // The sympt already exists. It is possible when two pbc 29495 // groups are exactly the same. Omit this point. 29496 pointdealloc(sympt); 29497 } else { 29498 // Do not isnert symp for unknown cases: ONFACE, OUTSIDE. 29499 // assert(0); 29500 pointdealloc(sympt); 29501 } 29502 } // for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) 29503 } // if (checkpbcs) 29504 // Save the endpoints of the seg for size interpolation. 29505 e1 = sorg(splitseg); 29506 if (shelltype(splitseg) == SHARP) { 29507 e2 = sdest(splitseg); 29508 } else { 29509 e2 = (point) NULL; // No need to do size interoplation. 29510 } 29511 if (!b->fliprepair) { 29512 // Form BC(p), B(p), CBC(p)s, and C(p)s. 29513 formbowatcavity(newpt, &splitseg, NULL, &n, &nmax, sublists, 29514 subceillists, tetlists, ceillists); 29515 // Validate/update BC(p), B(p), CBC(p)s, and C(p)s. 29516 if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists, 29517 tetlists, ceillists, -1.0)) { 29518 bowatinsertsite(newpt, &splitseg, n, sublists, subceillists, 29519 tetlists, ceillists, NULL, flipque, true, 29520 chkencsub, chkbadtet); 29521 setnewpointsize(newpt, e1, e2); 29522 if (steinerleft > 0) steinerleft--; 29523 } else { 29524 // p did not insert for invalid B(p). 29525 pointdealloc(newpt); 29526 } 29527 // Free the memory allocated in formbowatcavity(). 29528 releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists, 29529 ceillists); 29530 } else { 29531 splitencseg(newpt, &splitseg, tetlist, sublist, NULL, flipque, 29532 chkencsub, chkbadtet, false); 29533 setnewpointsize(newpt, e1, e2); 29534 if (steinerleft > 0) steinerleft--; 29535 } 29536 } else { 29537 // p did not accept for insertion. 29538 pointdealloc(newpt); 29539 } // if (checkseg4splitting(newpt, &splitseg)) 29540 } // if ((encloop->forg == pa) && (encloop->fdest == pb)) 29541 badfacedealloc(badsubsegs, encloop); // Remove this entry from list. 29542 encloop = badfacetraverse(badsubsegs); // Get the next enc-segment. 29543 } // while ((encloop != (badface *) NULL) && (steinerleft != 0)) 29544 } // while ((badsubsegs->items > 0) && (steinerleft != 0)) 29545 29546 if (!b->fliprepair) { 29547 delete [] tetlists; 29548 delete [] ceillists; 29549 delete [] sublists; 29550 delete [] subceillists; 29551 } else { 29552 delete tetlist; 29553 delete sublist; 29554 delete flipque; 29555 } 29556 } 29557 29559 // // 29560 // repairencsubs() Repair (split) all the encroached subfaces. // 29561 // // 29562 // Each encroached subface is repaired by splitting it - inserting a vertex // 29563 // at or near its circumcenter. Newly inserted vertices may encroach upon // 29564 // other subfaces, these are also repaired. // 29565 // // 29566 // 'chkbadtet' is a flag that specifies whether one should take note of new // 29567 // bad quality tets that result from inserted vertices. // 29568 // // 29570 29571 void tetgenmesh::repairencsubs(bool chkbadtet) 29572 { 29573 list *tetlists[2], *ceillists[2]; 29574 list *sublist, *subceillist; 29575 list *verlist; 29576 badface *encloop; 29577 face splitsub, symsplitsub; 29578 point newpt, sympt, e1; 29579 enum locateresult loc, symloc; 29580 bool reject; 29581 long oldptnum; 29582 int quenumber, n, i; 29583 29584 quenumber = 0; 29585 n = 0; 29586 sublist = (list *) NULL; 29587 subceillist = (list *) NULL; 29588 verlist = new list(sizeof(point *), NULL, 256); 29589 29590 // Loop until the pool 'badsubfaces' is empty. Note that steinerleft == -1 29591 // if an unlimited number of Steiner points is allowed. 29592 while ((badsubfaces->items > 0) && (steinerleft != 0)) { 29593 // Get an encroached subface f. 29594 encloop = dequeueencsub(&quenumber); 29595 splitsub = encloop->ss; 29596 // Clear the in-queue flag of f. 29597 setshell2badface(splitsub, NULL); 29598 // f may not be the same one when it was determined to be encroached. 29599 if (!isdead(&splitsub) 29600 && (sorg(splitsub) == encloop->forg) 29601 && (sdest(splitsub) == encloop->fdest) 29602 && (sapex(splitsub) == encloop->fapex)) { 29603 if (b->verbose > 1) { 29604 printf(" Dequeuing ensub (%d, %d, %d) [%d].\n", 29605 pointmark(encloop->forg), pointmark(encloop->fdest), 29606 pointmark(encloop->fapex), quenumber); 29607 } 29608 // Create a new point p at the circumcenter of f. 29609 makepoint(&newpt); 29610 for (i = 0; i < 3; i++) newpt[i] = encloop->cent[i]; 29611 setpointtype(newpt, FREESUBVERTEX); 29612 setpoint2sh(newpt, sencode(splitsub)); 29613 // Set the abovepoint of f for point location. 29614 abovepoint = facetabovepointarray[shellmark(splitsub)]; 29615 if (abovepoint == (point) NULL) { 29616 getfacetabovepoint(&splitsub); 29617 } 29618 // Locate p, start from f, stop at segment (1), use a tolerance to 29619 // detect ONVERTEX or OUTSIDE case. Update f on return. 29620 loc = locatesub(newpt, &splitsub, 1, b->epsilon * 1e+2); 29621 if ((loc != ONVERTEX) && (loc != OUTSIDE)) { 29622 // Form BC(p), B(p), CBC(p) and C(p). 29623 formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist, 29624 &subceillist, tetlists, ceillists); 29625 // Check for encroached subsegments (on B(p)). 29626 reject = tallencsegs(newpt, 2, ceillists); 29627 // Execute point accept rule if p does not encroach upon any segment. 29628 if (!reject) { 29629 reject = !acceptfacpt(newpt, subceillist, verlist); 29630 } 29631 if (!reject) { 29632 // Validate/update cavity. 29633 reject = !trimbowatcavity(newpt, NULL, n, &sublist, &subceillist, 29634 tetlists, ceillists, -1.0); 29635 } 29636 if (!reject) { 29637 // CBC(p) should include s, so that s can be removed after CBC(p) 29638 // is remeshed. However, if there are locally non-Delaunay faces 29639 // and encroached subsegments, s may not be collected in CBC(p). 29640 // p should not be inserted in such case. 29641 reject = !sinfected(encloop->ss); 29642 } 29643 if (!reject) { 29644 if (checkpbcs) { 29645 if (shellpbcgroup(splitsub) >= 0) { 29646 // Check for splitting of the symmetric subface of f. 29647 makepoint(&sympt); 29648 symloc = getsubpbcsympoint(newpt,&splitsub,sympt,&symsplitsub); 29649 if (symloc != ONVERTEX) { 29650 // Release CBC(p) and BC(p) and free the memory.. 29651 releasebowatcavity(NULL, 2, &sublist, &subceillist, tetlists, 29652 ceillists); 29653 // Form CBC(symp), C(symp), BC(sympt) and B(sympt). 29654 formbowatcavity(sympt, NULL, &symsplitsub, &n, NULL, &sublist, 29655 &subceillist, tetlists, ceillists); 29656 reject = tallencsegs(sympt, 2, ceillists); 29657 if (!reject) { 29658 reject = !acceptfacpt(sympt, subceillist, verlist); 29659 } 29660 if (!reject) { 29661 reject = !trimbowatcavity(sympt,NULL,n,&sublist,&subceillist, 29662 tetlists, ceillists, -1.0); 29663 } 29664 if (!reject) { 29665 // Insert sympt. 29666 setpoint2pbcpt(newpt, sympt); 29667 setpoint2pbcpt(sympt, newpt); 29668 setpointtype(sympt, FREESUBVERTEX); 29669 setpoint2sh(sympt, sencode(symsplitsub)); 29670 // Save a point for size interpolation. 29671 e1 = sorg(symsplitsub); 29672 bowatinsertsite(sympt, NULL, n, &sublist, &subceillist, 29673 tetlists,ceillists,NULL,NULL,false,true,chkbadtet); 29674 setnewpointsize(sympt, e1, NULL); 29675 if (steinerleft > 0) steinerleft--; 29676 // Release CBC(symp) and BC(symp) and free the memory.. 29677 releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists, 29678 ceillists); 29679 } else { 29680 // symp is rejected for one of the following reasons: 29681 // (1) BC(symp) is not valid; or 29682 // (2) symp encroaches upon some subsegments (queued); or 29683 // (3) symp is rejected by point accepting rule. 29684 pointdealloc(sympt); 29685 // Cavity will be released by the following code. 29686 } 29687 } else { 29688 // Do not insert sympt for invalid PBC data. 29689 pointdealloc(sympt); 29690 // p is rejected due to symp. 29691 reject = true; 29692 } 29693 } 29694 } // if (checkpbcs) 29695 } 29696 if (!reject) { 29697 // Insert p. 29698 if (checkpbcs) { 29699 if (shellpbcgroup(splitsub) >= 0) { 29700 // Form CBC(p), C(p), BC(p) and B(p). 29701 formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist, 29702 &subceillist, tetlists, ceillists); 29703 trimbowatcavity(newpt, NULL, n, &sublist, &subceillist, tetlists, 29704 ceillists, -1.0); 29705 } 29706 } 29707 // Save a point for size interpolation. 29708 e1 = sorg(splitsub); 29709 bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists, 29710 ceillists, NULL, NULL, true, true, chkbadtet); 29711 setnewpointsize(newpt, e1, NULL); 29712 if (steinerleft > 0) steinerleft--; 29713 } else { 29714 // p is rejected for the one of the following reasons: 29715 // (1) BC(p) is not valid. 29716 // (2) s does not in CBC(p). 29717 // (3) p encroaches upon some segments (queued); or 29718 // (4) p is rejected by point accepting rule, or 29719 // (5) due to the rejection of symp (the PBC). 29720 pointdealloc(newpt); 29721 } // if (!reject) 29722 // Release the cavity and free the memory. 29723 releasebowatcavity(NULL,n,&sublist,&subceillist,tetlists,ceillists); 29724 if (reject) { 29725 // Are there queued encroached subsegments. 29726 if (badsubsegs->items > 0) { 29727 // Repair enc-subsegments. 29728 oldptnum = points->items; 29729 repairencsegs(true, chkbadtet); 29730 if (points->items > oldptnum) { 29731 // Some enc-subsegments got split. Try to repair f later. 29732 splitsub = encloop->ss; 29733 if (!isdead(&splitsub)) { 29734 if (!shell2badface(splitsub)) { 29735 checksub4encroach(&splitsub, NULL, true); 29736 } 29737 } 29738 } 29739 } 29740 } 29741 } else { 29742 // Don't insert p for one of the following reasons: 29743 // (1) Locate on an existing vertex; or 29744 // (2) locate outside the domain. 29745 // Case (1) should not be possible. If such vertex v exists, it is 29746 // the circumcenter of f, ie., f is non-Delaunay. Either f was got 29747 // split before by v, but survived after v was inserted, or the 29748 // same for a f' which is nearly co-circular with f. Whatsoever, 29749 // there are encroached segs by v, but the routine tallencsegs() 29750 // did not find them out. 29751 if (loc == ONVERTEX) { 29752 printf("Internal error in repairencsubs():\n"); 29753 printf(" During repairing encroached subface (%d, %d, %d)\n", 29754 pointmark(encloop->forg), pointmark(encloop->fdest), 29755 pointmark(encloop->fapex)); 29756 printf(" New point %d is coincident with an existing vertex %d\n", 29757 pointmark(newpt), pointmark(sorg(splitsub))); 29758 internalerror(); 29759 } 29760 // Case (2) can happen when thers is a segment s which is close to f 29761 // and is non-conforming Delaunay. The circumcenter of f encroaches 29762 // upon s, but the circumcenter of s is rejected for insertion. 29763 pointdealloc(newpt); 29764 } // if ((loc != ONVERTEX) && (loc != OUTSIDE)) 29765 } else { 29766 if (!isdead(&splitsub)) { 29767 // The subface has been changed, re-check it. 29768 checksub4encroach(&splitsub, NULL, true); 29769 } 29770 } // if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) && 29771 // Remove this entry from list. 29772 badfacedealloc(badsubfaces, encloop); 29773 } // while ((badsubfaces->items > 0) && (steinerleft != 0)) 29774 29775 delete verlist; 29776 } 29777 29779 // // 29780 // repairbadtets() Repair all bad-quality tetrahedra. // 29781 // // 29782 // All bad-quality tets are stored in pool 'badtetrahedrons'. Each bad tet // 29783 // is repaired by inserting a point at or near its circumcenter. However, if // 29784 // this point encroaches any subsegment or subface, it is not inserted. Ins- // 29785 // tead the encroached segment and subface are split. Newly inserted points // 29786 // may create other bad-quality tets, these are also repaired. // 29787 // // 29789 29790 void tetgenmesh::repairbadtets() 29791 { 29792 list *tetlist, *ceillist; 29793 list *verlist; 29794 badface *badtet; 29795 triface starttet; 29796 point newpt, e1; 29797 enum locateresult loc; 29798 bool reject; 29799 long oldptnum; 29800 int i; 29801 29802 tetlist = new list(sizeof(triface), NULL, 1024); 29803 ceillist = new list(sizeof(triface), NULL, 1024); 29804 verlist = new list(sizeof(point *), NULL, 256); 29805 29806 // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1 29807 // if an unlimited number of Steiner points is allowed. 29808 while ((badtetrahedrons->items > 0) && (steinerleft != 0)) { 29809 // Get a bad-quality tet t. 29810 badtet = topbadtetra(); 29811 // Make sure that the tet is still the same one when it was tested. 29812 // Subsequent transformations may have made it a different tet. 29813 if ((badtet != (badface *) NULL) && !isdead(&badtet->tt) 29814 && org(badtet->tt) == badtet->forg 29815 && dest(badtet->tt) == badtet->fdest 29816 && apex(badtet->tt) == badtet->fapex 29817 && oppo(badtet->tt) == badtet->foppo) { 29818 if (b->verbose > 1) { 29819 printf(" Dequeuing btet (%d, %d, %d, %d).\n", 29820 pointmark(badtet->forg), pointmark(badtet->fdest), 29821 pointmark(badtet->fapex), pointmark(badtet->foppo)); 29822 } 29823 // Create the new point p (at the circumcenter of t). 29824 makepoint(&newpt); 29825 for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i]; 29826 setpointtype(newpt, FREEVOLVERTEX); 29827 // Locate p. 29828 starttet = badtet->tt; 29829 loc = preciselocate(newpt, &starttet, tetrahedrons->items); 29830 if ((loc != ONVERTEX) && (loc != OUTSIDE)) { 29831 // For BC(p) and B(p). 29832 infect(starttet); 29833 tetlist->append(&starttet); 29834 formbowatcavityquad(newpt, tetlist, ceillist); 29835 // Check for encroached subsegments. 29836 reject = tallencsegs(newpt, 1, &ceillist); 29837 if (!reject) { 29838 // Check for encroached subfaces. 29839 reject = tallencsubs(newpt, 1, &ceillist); 29840 } 29841 // Execute point accepting rule if p does not encroach upon any 29842 // subsegment and subface. 29843 if (!reject) { 29844 reject = !acceptvolpt(newpt, ceillist, verlist); 29845 } 29846 if (!reject) { 29847 reject = !trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, 29848 &ceillist, -1.0); 29849 } 29850 if (!reject) { 29851 // BC(p) should include t, so that t can be removed after BC(p) is 29852 // remeshed. However, if there are locally non-Delaunay faces 29853 // and encroached subsegments/subfaces, t may not be collected 29854 // in BC(p). p should not be inserted in such case. 29855 reject = !infected(badtet->tt); 29856 if (reject) outbowatcircumcount++; 29857 } 29858 if (!reject) { 29859 // Save a point for size interpolation. 29860 e1 = org(starttet); 29861 // Insert p. 29862 bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, 29863 NULL, NULL, false, false, true); 29864 setnewpointsize(newpt, e1, NULL); 29865 if (steinerleft > 0) steinerleft--; 29866 } else { 29867 // p is rejected for one of the following reasons: 29868 // (1) BC(p) is not valid. 29869 // (2) t does not in BC(p). 29870 // (3) p encroaches upon some segments; 29871 // (4) p encroaches upon some subfaces; 29872 // (5) p is rejected by the point accepting rule. 29873 pointdealloc(newpt); 29874 // Uninfect tets of BC(p). 29875 for (i = 0; i < tetlist->len(); i++) { 29876 starttet = * (triface *)(* tetlist)[i]; 29877 uninfect(starttet); 29878 } 29879 } 29880 tetlist->clear(); 29881 ceillist->clear(); 29882 // Split encroached subsegments/subfaces if there are. 29883 if (reject) { 29884 oldptnum = points->items; 29885 if (badsubsegs->items > 0) { 29886 repairencsegs(true, true); 29887 } 29888 if (badsubfaces->items > 0) { 29889 repairencsubs(true); 29890 } 29891 if (points->items > oldptnum) { 29892 // Some encroaching subsegments/subfaces got split. Re-queue the 29893 // tet if it is still alive. 29894 starttet = badtet->tt; 29895 if (!isdead(&starttet)) { 29896 checktet4badqual(&starttet, true); 29897 } 29898 } 29899 } 29900 } else { 29901 // Do not insert p. The reason may be one of: 29902 // (1) p is coincident (ONVERTEX) with an existing vertex; or 29903 // (2) p is outside (OUTSIDE) the mesh. 29904 // Case (1) should not be possible. If such vertex v exists, it is 29905 // the circumcenter of t, ie., t is non-Delaunay. Either t was got 29906 // split before by v, but survived after v was inserted, or the 29907 // same for a t' which is nearly co-spherical with t. Whatsoever, 29908 // there are encroached segments or subfaces by v but the routines 29909 // tallencsegs() or tallencsubs() did not find them out. 29910 if (loc == ONVERTEX) { 29911 printf("Internal error in repairbadtets():\n"); 29912 printf(" During repairing bad tet (%d, %d, %d, %d)\n", 29913 pointmark(badtet->forg), pointmark(badtet->fdest), 29914 pointmark(badtet->fapex), pointmark(badtet->foppo)); 29915 printf(" New point %d is coincident with an existing vertex %d\n", 29916 pointmark(newpt), pointmark(org(starttet))); 29917 internalerror(); 29918 } 29919 // Case (2) can happen when there is a segment s (or subface f) which 29920 // is close to f and is non-conforming Delaunay. The circumcenter 29921 // of t encroaches upon s (or f), but the circumcenter of s (or f) 29922 // is rejected for insertion. 29923 pointdealloc(newpt); 29924 } // if ((loc != ONVERTEX) && (loc != OUTSIDE)) 29925 } // if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg && 29926 // Remove the tet from the queue. 29927 dequeuebadtet(); 29928 } // while ((badtetrahedrons->items > 0) && (steinerleft != 0)) 29929 29930 delete tetlist; 29931 delete ceillist; 29932 delete verlist; 29933 } 29934 29936 // // 29937 // enforcequality() Refine the mesh. // 29938 // // 29940 29941 void tetgenmesh::enforcequality() 29942 { 29943 long total, vertcount; 29944 int i; 29945 29946 if (!b->quiet) { 29947 printf("Adding Steiner points to enforce quality.\n"); 29948 } 29949 29950 total = vertcount = 0l; 29951 if (b->conformdel) { 29952 r2count = r3count = 0l; 29953 } 29954 29955 // If both '-D' and '-r' options are used. 29956 if (b->conformdel && b->refine) { 29957 markacutevertices(65.0); 29958 } 29959 // If '-m' is not used. 29960 if (!b->metric) { 29961 // Find and mark all sharp segments. 29962 marksharpsegments(65.0); 29963 // Decide the sizes for feature points. 29964 decidefeaturepointsizes(); 29965 } 29966 29967 // Initialize the pool of encroached subsegments. 29968 badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); 29969 // Looking for encroached subsegments. 29970 tallencsegs(NULL, 0, NULL); 29971 if (b->verbose && badsubsegs->items > 0) { 29972 printf(" Splitting encroached subsegments.\n"); 29973 } 29974 vertcount = points->items; 29975 // Fix encroached segments without noting any enc subfaces. 29976 repairencsegs(false, false); 29977 if (b->verbose > 0) { 29978 printf(" %ld split points.\n", points->items - vertcount); 29979 } 29980 total += points->items - vertcount; 29981 29982 // Initialize the pool of encroached subfaces. 29983 badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); 29984 // Initialize the priority queues of badfaces. 29985 for (i = 0; i < 3; i++) subquefront[i] = (badface *) NULL; 29986 for (i = 0; i < 3; i++) subquetail[i] = &subquefront[i]; 29987 // Looking for encroached subfaces. 29988 tallencsubs(NULL, 0, NULL); 29989 if (b->verbose && badsubfaces->items > 0) { 29990 printf(" Splitting encroached subfaces.\n"); 29991 } 29992 vertcount = points->items; 29993 // Fix encroached subfaces without noting bad tetrahedra. 29994 repairencsubs(false); 29995 if (b->verbose > 0) { 29996 printf(" %ld split points.\n", points->items - vertcount); 29997 } 29998 total += points->items - vertcount; 29999 // At this point, the mesh should be conforming Delaunay if no input 30000 // angle is smaller than 90 degree. 30001 30002 // Next, fix bad quality tetrahedra. 30003 if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) { 30004 // Initialize the pool of bad tets 30005 badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0); 30006 // Initialize the priority queues of bad tets. 30007 for (i = 0; i < 64; i++) tetquefront[i] = (badface *) NULL; 30008 firstnonemptyq = -1; 30009 recentq = -1; 30010 // Looking for bad quality tets. 30011 cosmaxdihed = cos(b->maxdihedral * PI / 180.0); 30012 cosmindihed = cos(b->mindihedral * PI / 180.0); 30013 tallbadtetrahedrons(); 30014 if (b->verbose && badtetrahedrons->items > 0) { 30015 printf(" Splitting bad tetrahedra.\n"); 30016 } 30017 vertcount = points->items; 30018 repairbadtets(); 30019 if (b->verbose > 0) { 30020 printf(" %ld refinement points.\n", points->items - vertcount); 30021 } 30022 total += points->items - vertcount; 30023 delete badtetrahedrons; 30024 } 30025 30026 if (b->verbose > 0) { 30027 printf(" Totally added %ld points.\n", total); 30028 } 30029 30030 delete badsubfaces; 30031 delete badsubsegs; 30032 } 30033 30034 // 30035 // End of Delaunay refinement routines 30036 // 30037 30038 // 30039 // Begin of mesh optimization routines 30040 // 30041 30042 void tetgenmesh::dumpbadtets() 30043 { 30044 FILE *fout; 30045 badface *remtet; 30046 30047 // Write out a file of remaining bad tets. 30048 printf(" Writing bad tets to file bad-dump.lua.\n"); 30049 fout = fopen("bad-dump.lua", "w"); 30050 fprintf(fout, "-- %ld remaining bad tets (> %g degree).\n", 30051 badtetrahedrons->items, b->maxdihedral); 30052 badtetrahedrons->traversalinit(); 30053 remtet = badfacetraverse(badtetrahedrons); 30054 while (remtet != (badface *) NULL) { 30055 if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg && 30056 dest(remtet->tt) == remtet->fdest && 30057 apex(remtet->tt) == remtet->fapex && 30058 oppo(remtet->tt) == remtet->foppo) { 30059 fprintf(fout, "p:draw_tet(%d, %d, %d, %d) -- %g\n", 30060 pointmark(remtet->forg), pointmark(remtet->fdest), 30061 pointmark(remtet->fapex), pointmark(remtet->foppo), 30062 acos(remtet->key) * 180.0 / PI); 30063 } 30064 remtet = badfacetraverse(badtetrahedrons); 30065 } 30066 fclose(fout); 30067 } 30068 30070 // // 30071 // checktet4ill() Check a tet to see if it is illegal. // 30072 // // 30073 // A tet is "illegal" if it spans on one input facet. Save the tet in queue // 30074 // if it is illegal and the flag 'enqflag' is set. // 30075 // // 30076 // Note: Such case can happen when the input facet has non-coplanar vertices // 30077 // and the Delaunay tetrahedralization of the vertices may creat such tets. // 30078 // // 30080 30081 bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag) 30082 { 30083 badface *newbadtet; 30084 triface checktet; 30085 face checksh1, checksh2; 30086 face checkseg; 30087 bool illflag; 30088 int i; 30089 30090 illflag = false; 30091 for (testtet->loc = 0; testtet->loc < 4; testtet->loc++) { 30092 tspivot(*testtet, checksh1); 30093 if (checksh1.sh != dummysh) { 30094 testtet->ver = 0; 30095 findedge(&checksh1, org(*testtet), dest(*testtet)); 30096 for (i = 0; i < 3; i++) { 30097 fnext(*testtet, checktet); 30098 tspivot(checktet, checksh2); 30099 if (checksh2.sh != dummysh) { 30100 // Two subfaces share this edge. 30101 sspivot(checksh1, checkseg); 30102 if (checkseg.sh == dummysh) { 30103 // The four corners of the tet are on one facet. Illegal! Try to 30104 // flip the opposite edge of the current one. 30105 enextfnextself(*testtet); 30106 enextself(*testtet); 30107 illflag = true; 30108 break; 30109 } 30110 } 30111 enextself(*testtet); 30112 senextself(checksh1); 30113 } 30114 } 30115 if (illflag) break; 30116 } 30117 30118 if (illflag && enqflag) { 30119 // Allocate space for the bad tetrahedron. 30120 newbadtet = (badface *) badtetrahedrons->alloc(); 30121 newbadtet->tt = *testtet; 30122 newbadtet->key = -1.0; // = 180 degree. 30123 for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0; 30124 newbadtet->forg = org(*testtet); 30125 newbadtet->fdest = dest(*testtet); 30126 newbadtet->fapex = apex(*testtet); 30127 newbadtet->foppo = oppo(*testtet); 30128 newbadtet->nextitem = (badface *) NULL; 30129 if (b->verbose > 2) { 30130 printf(" Queueing illtet: (%d, %d, %d, %d).\n", 30131 pointmark(newbadtet->forg), pointmark(newbadtet->fdest), 30132 pointmark(newbadtet->fapex), pointmark(newbadtet->foppo)); 30133 } 30134 } 30135 30136 return illflag; 30137 } 30138 30140 // // 30141 // checktet4opt() Check a tet to see if it needs to be optimized. // 30142 // // 30143 // A tet t needs to be optimized if it fails to certain quality measures. // 30144 // The only quality measure currently used is the maximal dihedral angle at // 30145 // edges. The desired maximal dihedral angle is b->maxdihed (set by the '-s' // 30146 // option. // 30147 // // 30148 // A tet may have one, two, or three big dihedral angles. Examples: Let the // 30149 // tet t = abcd, and its four corners are nearly co-planar. Then t has one // 30150 // big dihedral angle if d is very close to the edge ab; t has three big // 30151 // dihedral angles if d's projection on the face abc is also inside abc, i.e.// 30152 // the shape of t likes a hat; finally, t has two big dihedral angles if d's // 30153 // projection onto abc is outside abc. // 30154 // // 30156 30157 bool tetgenmesh::checktet4opt(triface* testtet, bool enqflag) 30158 { 30159 badface *newbadtet; 30160 point pa, pb, pc, pd; 30161 REAL N[4][3], len; 30162 REAL cosd; 30163 bool enq; 30164 int i, j; 30165 30166 cosd = 0.0; 30167 enq = false; 30168 pa = (point) testtet->tet[4]; 30169 pb = (point) testtet->tet[5]; 30170 pc = (point) testtet->tet[6]; 30171 pd = (point) testtet->tet[7]; 30172 // Compute the 4 face normals: N[0] cbd, N[1] acd, N[2] bad, N[3] abc. 30173 tetallnormal(pa, pb, pc, pd, N, NULL); 30174 // Normalize the normals. 30175 for (i = 0; i < 4; i++) { 30176 len = sqrt(dot(N[i], N[i])); 30177 if (len != 0.0) { 30178 for (j = 0; j < 3; j++) N[i][j] /= len; 30179 } 30180 } 30181 // Find all large dihedral angles. 30182 for (i = 0; i < 6; i++) { 30183 // Locate the edge i and calculate the dihedral angle at the edge. 30184 testtet->loc = 0; 30185 testtet->ver = 0; 30186 switch (i) { 30187 case 0: // edge ab 30188 cosd = -dot(N[2], N[3]); 30189 break; 30190 case 1: // edge cd 30191 enextfnextself(*testtet); 30192 enextself(*testtet); 30193 cosd = -dot(N[0], N[1]); 30194 break; 30195 case 2: // edge bd 30196 enextfnextself(*testtet); 30197 enext2self(*testtet); 30198 cosd = -dot(N[0], N[2]); 30199 break; 30200 case 3: // edge bc 30201 enextself(*testtet); 30202 cosd = -dot(N[0], N[3]); 30203 break; 30204 case 4: // edge ad 30205 enext2fnextself(*testtet); 30206 enextself(*testtet); 30207 cosd = -dot(N[1], N[2]); 30208 break; 30209 case 5: // edge ac 30210 enext2self(*testtet); 30211 cosd = -dot(N[1], N[3]); 30212 break; 30213 } 30214 if (cosd < cosmaxdihed) { 30215 // A bigger dihedral angle. 30216 if (enqflag) { 30217 // Allocate space for the bad tetrahedron. 30218 newbadtet = (badface *) badtetrahedrons->alloc(); 30219 newbadtet->tt = *testtet; 30220 newbadtet->key = cosd; 30221 for (j = 0; j < 3; j++) newbadtet->cent[j] = 0.0; 30222 newbadtet->forg = org(*testtet); 30223 newbadtet->fdest = dest(*testtet); 30224 newbadtet->fapex = apex(*testtet); 30225 newbadtet->foppo = oppo(*testtet); 30226 newbadtet->nextitem = (badface *) NULL; 30227 if (b->verbose > 2) { 30228 printf(" Queueing tet: (%d, %d, %d, %d), dihed %g (degree).\n", 30229 pointmark(newbadtet->forg), pointmark(newbadtet->fdest), 30230 pointmark(newbadtet->fapex), pointmark(newbadtet->foppo), 30231 acos(cosd) * 180.0 / PI); 30232 } 30233 } 30234 enq = true; 30235 } 30236 } 30237 30238 return enq; 30239 } 30240 30242 // // 30243 // removeedge() Remove an edge // 30244 // // 30245 // 'remedge' is a tet (abcd) having the edge ab wanted to be removed. Local // 30246 // reconnecting operations are used to remove edge ab. The following opera- // 30247 // tion will be tryed. // 30248 // // 30249 // If ab is on the hull, and abc and abd are both hull faces. Then ab can be // 30250 // removed by stripping abcd from the mesh. However, if ab is a segemnt, do // 30251 // the operation only if 'b->optlevel' > 1 and 'b->nobisect == 0'. // 30252 // // 30253 // If ab is an internal edge, there are n tets contains it. Then ab can be // 30254 // removed if there exists another m tets which can replace the n tets with- // 30255 // out changing the boundary of the n tets. // 30256 // // 30257 // If 'optflag' is set. The value 'remedge->key' means cos(theta), where // 30258 // 'theta' is the maximal dishedral angle at ab. In this case, even if the // 30259 // n-to-m flip exists, it will not be performed if the maximum dihedral of // 30260 // the new tets is larger than 'theta'. // 30261 // // 30263 30264 bool tetgenmesh::removeedge(badface* remedge, bool optflag) 30265 { 30266 triface abcd, badc; // Tet configuration at edge ab. 30267 triface baccasing, abdcasing; 30268 triface abtetlist[11]; // Old configuration at ab, save maximum 10 tets. 30269 triface bftetlist[11]; // Old configuration at bf, save maximum 10 tets. 30270 triface newtetlist[33]; // New configuration after removing ab. 30271 face checksh; 30272 enum fliptype fty; 30273 REAL key; 30274 bool remflag, subflag; 30275 int n, n1, m, i, j; 30276 30277 // First try to strip abcd from the mesh. This needs to check either ab 30278 // or cd is on the hull. Try to strip it whichever is true. 30279 abcd = remedge->tt; 30280 adjustedgering(abcd, CCW); 30281 i = 0; 30282 do { 30283 sym(abcd, baccasing); 30284 // Is the tet on the hull? 30285 if (baccasing.tet == dummytet) { 30286 fnext(abcd, badc); 30287 sym(badc, abdcasing); 30288 if (abdcasing.tet == dummytet) { 30289 // Strip the tet from the mesh -> ab is removed as well. 30290 if (removetetbypeeloff(&abcd)) { 30291 if (b->verbose > 1) { 30292 printf(" Stripped tet from the mesh.\n"); 30293 } 30294 optcount[0]++; 30295 return true; 30296 } 30297 } 30298 } 30299 // Check if the oppsite edge cd is on the hull. 30300 enext2fnextself(abcd); 30301 enext2self(abcd); 30302 esymself(abcd); // --> cdab 30303 i++; 30304 } while (i < 2); 30305 30306 // Get the tets configuration at ab. Collect maximum 10 tets. 30307 subflag = false; 30308 abcd = remedge->tt; 30309 adjustedgering(abcd, CW); 30310 n = 0; 30311 abtetlist[n] = abcd; 30312 do { 30313 // Is the list full? 30314 if (n == 10) break; 30315 // Stop if a subface appears. 30316 tspivot(abtetlist[n], checksh); 30317 if (checksh.sh != dummysh) { 30318 // ab is either a segment or a facet edge. The latter case is not 30319 // handled yet! An edge flip is needed. 30320 subflag = true; break; // return false; 30321 } 30322 // Get the next tet at ab. 30323 fnext(abtetlist[n], abtetlist[n + 1]); 30324 n++; 30325 } while (apex(abtetlist[n]) != apex(abcd)); 30326 30327 remflag = false; 30328 key = remedge->key; 30329 30330 if (subflag && optflag) { 30331 abcd = remedge->tt; 30332 adjustedgering(abcd, CCW); 30333 // Try to flip face cda or cdb to improve quality. 30334 for (j = 0; j < 2; j++) { 30335 if (j == 0) { 30336 enext2fnext(abcd, abtetlist[0]); // Goto cda. 30337 } else { 30338 enextfnext(abcd, abtetlist[0]); // Goto cdb. 30339 } 30340 fty = categorizeface(abtetlist[0]); 30341 if (fty == T23) { 30342 // A 2-to-3 flip is possible. 30343 sym(abtetlist[0], abtetlist[1]); 30344 assert(abtetlist[1].tet != dummytet); 30345 n = 2; 30346 m = 3; 30347 remflag = removefacebyflip23(&key, abtetlist, newtetlist, NULL); 30348 } else if (fty == T22) { 30349 // A 2-to-2 or 4-to-4 flip is possible. 30350 n = 2; 30351 newtetlist[0] = abtetlist[0]; 30352 adjustedgering(newtetlist[0], CW); 30353 fnext(newtetlist[0], newtetlist[1]); 30354 assert(newtetlist[1].tet != dummytet); 30355 // May it is 4-to-4 flip. 30356 if (fnext(newtetlist[1], newtetlist[2])) { 30357 fnext(newtetlist[2], newtetlist[3]); 30358 assert(newtetlist[3].tet != dummytet); 30359 n = 4; 30360 } 30361 m = n; 30362 remflag = removeedgebyflip22(&key, n, newtetlist, NULL); 30363 } 30364 // Has quality been improved? 30365 if (remflag) { 30366 if (b->verbose > 1) { 30367 printf(" Done flip %d-to-%d. Qual: %g -> %g.\n", n, m, 30368 acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0); 30369 } 30370 // Delete the old tets. Note, flip22() does not create new tets. 30371 if (m == 3) { 30372 for (i = 0; i < n; i++) { 30373 tetrahedrondealloc(abtetlist[i].tet); 30374 } 30375 } 30376 for (i = 0; i < m; i++) { 30377 checktet4opt(&(newtetlist[i]), true); 30378 } 30379 optcount[1]++; 30380 return true; 30381 } 30382 } // if (j = 0; j < 2; j++) 30383 // Faces are not flipable. Return. 30384 return false; 30385 } 30386 30387 // 2 <= n <= 10. 30388 if (n == 3) { 30389 // There are three tets at ab. Try to do a flip32 at ab. 30390 remflag = removeedgebyflip32(&key, abtetlist, newtetlist, NULL); 30391 } else if ((n == 4) || (n == 5) || (n == 6)) { 30392 // Four tets case. Try to do edge transformation. 30393 remflag = removeedgebytranNM(&key,n,abtetlist,newtetlist,NULL,NULL,NULL); 30394 } else { 30395 if (b->verbose > 1) { 30396 printf(" !! Unhandled case: n = %d.\n", n); 30397 } 30398 } 30399 if (remflag) { 30400 optcount[n]++; 30401 // Delete the old tets. 30402 for (i = 0; i < n; i++) { 30403 tetrahedrondealloc(abtetlist[i].tet); 30404 } 30405 m = (n - 2) * 2; // The numebr of new tets. 30406 if (b->verbose > 1) { 30407 printf(" Done flip %d-to-%d. ", n, m); 30408 if (optflag) { 30409 printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0, 30410 acos(key) / PI * 180.0); 30411 } 30412 printf("\n"); 30413 } 30414 } 30415 30416 if (!remflag && (key == remedge->key) && (n < 7)) { 30417 // Try to do a combination of flips. 30418 n1 = 0; 30419 remflag = removeedgebycombNM(&key, n, abtetlist, &n1, bftetlist, 30420 newtetlist, NULL); 30421 if (remflag) { 30422 optcount[9]++; 30423 // Delete the old tets. 30424 for (i = 0; i < n; i++) { 30425 tetrahedrondealloc(abtetlist[i].tet); 30426 } 30427 for (i = 0; i < n1; i++) { 30428 if (!isdead(&(bftetlist[i]))) { 30429 tetrahedrondealloc(bftetlist[i].tet); 30430 } 30431 } 30432 m = ((n1 - 2) * 2 - 1) + (n - 3) * 2; // The number of new tets. 30433 if (b->verbose > 1) { 30434 printf(" Done flip %d-to-%d (n-1=%d, n1=%d). ", n+n1-2, m, n-1,n1); 30435 if (optflag) { 30436 printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0, 30437 acos(key) / PI * 180.0); 30438 } 30439 printf("\n"); 30440 } 30441 } 30442 } 30443 30444 if (remflag) { 30445 // edge is removed. Test new tets for further optimization. 30446 for (i = 0; i < m; i++) { 30447 if (optflag) { 30448 checktet4opt(&(newtetlist[i]), true); 30449 } else { 30450 checktet4ill(&(newtetlist[i]), true); 30451 } 30452 } 30453 } 30454 30455 return remflag; 30456 } 30457 30459 // // 30460 // smoothsliver() Remove a sliver by smoothing a vertex of it. // 30461 // // 30462 // The 'slivtet' represents a sliver abcd, and ab is the current edge which // 30463 // has a large dihedral angle (close to 180 degree). // 30464 // // 30466 30467 bool tetgenmesh::smoothsliver(badface* remedge, list *starlist) 30468 { 30469 triface checktet; 30470 point smthpt; 30471 bool smthed; 30472 int idx, i, j; 30473 30474 // Find a Steiner volume point and smooth it. 30475 smthed = false; 30476 for (i = 0; i < 4 && !smthed; i++) { 30477 smthpt = (point) remedge->tt.tet[4 + i]; 30478 // Is it a volume point? 30479 if (pointtype(smthpt) == FREEVOLVERTEX) { 30480 // Is it a Steiner point? 30481 idx = pointmark(smthpt) - in->firstnumber; 30482 if (!(idx < in->numberofpoints)) { 30483 // Smooth a Steiner volume point. 30484 starlist->append(&(remedge->tt.tet)); 30485 formstarpolyhedron(smthpt, starlist, NULL, false); 30486 smthed = smoothpoint(smthpt,NULL,NULL,starlist,false,&remedge->key); 30487 // If it is smoothed. Queue new bad tets. 30488 if (smthed) { 30489 for (j = 0; j < starlist->len(); j++) { 30490 checktet = * (triface *)(* starlist)[j]; 30491 checktet4opt(&checktet, true); 30492 } 30493 } 30494 starlist->clear(); 30495 } 30496 } 30497 } 30498 30499 /* Omit to smooth segment points. This may cause infinite loop. 30500 if (smthed) { 30501 return true; 30502 } 30503 face abseg, nextseg, prevseg; 30504 point pt[2]; 30505 // Check if ab is a segment. 30506 tsspivot(slivtet, &abseg); 30507 if (abseg.sh == dummysh) { 30508 // ab is not a segment. Check if a or b is a Steiner segment point. 30509 for (i = 0; i < 2 && !smthed; i++) { 30510 smthpt = (i == 0 ? org(*slivtet) : dest(*slivtet)); 30511 if (pointtype(smthpt) == FREESEGVERTEX) { 30512 // Is it a Steiner point? 30513 idx = pointmark(smthpt) - in->firstnumber; 30514 if (!(idx < in->numberofpoints)) { 30515 // Smooth a Steiner segment point. Get the segment. 30516 sdecode(point2sh(smthpt), nextseg); 30517 locateseg(smthpt, &nextseg); 30518 assert(sorg(nextseg) == smthpt); 30519 pt[0] = sdest(nextseg); 30520 senext2(nextseg, prevseg); 30521 spivotself(prevseg); 30522 prevseg.shver = 0; 30523 if (sorg(prevseg) == smthpt) sesymself(prevseg); 30524 assert(sdest(prevseg) == smthpt); 30525 pt[1] = sorg(prevseg); 30526 starlist->append(slivtet); 30527 formstarpolyhedron(smthpt, starlist, NULL, true); 30528 smthed = smoothpoint(smthpt, pt[0], pt[1], starlist, false); 30529 // If it is smoothed. Check if the tet is still a sliver. 30530 if (smthed) checktet4opt(slivtet, true); 30531 starlist->clear(); 30532 } 30533 } 30534 } 30535 } 30536 */ 30537 30538 return smthed; 30539 } 30540 30542 // // 30543 // splitsliver() Remove a sliver by inserting a point. // 30544 // // 30545 // The 'remedge->tt' represents a sliver abcd, ab is the current edge which // 30546 // has a large dihedral angle (close to 180 degree). // 30547 // // 30549 30550 bool tetgenmesh::splitsliver(badface *remedge, list *tetlist, list *ceillist) 30551 { 30552 triface starttet; 30553 face checkseg; 30554 point newpt, pt[4]; 30555 bool remflag; 30556 int i; 30557 30558 starttet = remedge->tt; 30559 30560 // Check if cd is a segment. 30561 adjustedgering(starttet, CCW); 30562 enextfnextself(starttet); 30563 enextself(starttet); 30564 tsspivot(&starttet, &checkseg); 30565 if (b->nobisect == 0) { 30566 if (checkseg.sh != dummysh) { 30567 // cd is a segment. The seg will be split. BUT do not flip! Due to the 30568 // exact predicates, lot of slivers ay be rsulted and hard to remove. 30569 checkseg.shver = 0; 30570 pt[0] = sorg(checkseg); 30571 pt[1] = sdest(checkseg); 30572 makepoint(&newpt); 30573 getsplitpoint(pt[0], pt[1], NULL, newpt); 30574 setpointtype(newpt, FREESEGVERTEX); 30575 setpoint2sh(newpt, sencode(checkseg)); 30576 // Insert p, this should always success. 30577 sstpivot(&checkseg, &starttet); 30578 splittetedge(newpt, &starttet, NULL); 30579 // Collect the new tets connecting at p. 30580 sstpivot(&checkseg, &starttet); 30581 ceillist->append(&starttet); 30582 formstarpolyhedron(newpt, ceillist, NULL, true); 30583 setnewpointsize(newpt, pt[0], NULL); 30584 if (steinerleft > 0) steinerleft--; 30585 // Smooth p. 30586 smoothpoint(newpt, pt[0], pt[1], ceillist, false, NULL); 30587 // Queue new slivers. 30588 for (i = 0; i < ceillist->len(); i++) { 30589 starttet = * (triface *)(* ceillist)[i]; 30590 checktet4opt(&starttet, true); 30591 } 30592 ceillist->clear(); 30593 return true; 30594 } 30595 } 30596 30597 // Get the four corners. 30598 for (i = 0; i < 4; i++) { 30599 pt[i] = (point) starttet.tet[4 + i]; 30600 } 30601 // Create the new point p (at the circumcenter of t). 30602 makepoint(&newpt); 30603 for (i = 0; i < 3; i++) { 30604 newpt[i] = 0.25 * (pt[0][i] + pt[1][i] + pt[2][i] + pt[3][i]); 30605 } 30606 setpointtype(newpt, FREEVOLVERTEX); 30607 30608 // Form the Bowyer-Watson cavity of p. 30609 remflag = false; 30610 infect(starttet); 30611 tetlist->append(&starttet); 30612 formbowatcavityquad(newpt, tetlist, ceillist); 30613 if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, -1.0)) { 30614 // Smooth p. 30615 if (smoothpoint( newpt, NULL, NULL, ceillist, false, &remedge->key)) { 30616 // Insert p. 30617 bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, NULL, 30618 NULL, false, false, false); 30619 setnewpointsize(newpt, pt[0], NULL); 30620 if (steinerleft > 0) steinerleft--; 30621 // Queue new slivers. 30622 for (i = 0; i < ceillist->len(); i++) { 30623 starttet = * (triface *)(* ceillist)[i]; 30624 checktet4opt(&starttet, true); 30625 } 30626 remflag = true; 30627 } // if (smoothpoint) 30628 } // if (trimbowatcavity) 30629 30630 if (!remflag) { 30631 // p is rejected for BC(p) is not valid. 30632 pointdealloc(newpt); 30633 // Uninfect tets of BC(p). 30634 for (i = 0; i < tetlist->len(); i++) { 30635 starttet = * (triface *)(* tetlist)[i]; 30636 uninfect(starttet); 30637 } 30638 } 30639 tetlist->clear(); 30640 ceillist->clear(); 30641 30642 return remflag; 30643 } 30644 30646 // // 30647 // tallslivers() Queue all the slivers in the mesh. // 30648 // // 30650 30651 void tetgenmesh::tallslivers(bool optflag) 30652 { 30653 triface tetloop; 30654 30655 tetrahedrons->traversalinit(); 30656 tetloop.tet = tetrahedrontraverse(); 30657 while (tetloop.tet != (tetrahedron *) NULL) { 30658 if (optflag) { 30659 checktet4opt(&tetloop, true); 30660 } else { 30661 checktet4ill(&tetloop, true); 30662 } 30663 tetloop.tet = tetrahedrontraverse(); 30664 } 30665 } 30666 30668 // // 30669 // optimizemesh() Improve mesh quality by mesh optimizations. // 30670 // // 30671 // Available mesh optimizing operations are: (1) multiple edge flips (3-to-2,// 30672 // 4-to-4, 5-to-6, etc), (2) free vertex deletion, (3) new vertex insertion. // 30673 // (1) is mandatory, while (2) and (3) are optionally. // 30674 // // 30675 // The variable 'b->optlevel' (set after '-s') determines the use of these // 30676 // operations. If it is: 0, do no optimization; 1, only do (1) operation; 2, // 30677 // do (1) and (2) operations; 3, do all operations. Deault, b->optlvel = 2. // 30678 // // 30680 30681 void tetgenmesh::optimizemesh(bool optflag) 30682 { 30683 list *splittetlist, *tetlist, *ceillist; 30684 badface *remtet, *lastentry; 30685 //REAL maxdihed, objdihed, curdihed; // maxdihead commented out to get gcc 4.6 working 30686 REAL objdihed, curdihed; 30687 long oldnum; 30688 int iter, i; 30689 30690 objdihed = 0.0; 30691 30692 if (!b->quiet) { 30693 if (optflag) { 30694 printf("Optimizing mesh.\n"); 30695 } else { 30696 printf("Repairing mesh.\n"); 30697 } 30698 } 30699 30700 #ifdef SELF_CHECK 30701 if (optflag && (b->verbose)) { 30702 printf(" level = %d.\n", b->optlevel); 30703 } 30704 #endif 30705 30706 // Initialize the pool of bad tets. 30707 badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0); 30708 if (optflag) { 30709 cosmaxdihed = cos(b->maxdihedral * PI / 180.0); 30710 cosmindihed = cos(b->mindihedral * PI / 180.0); 30711 // The radian of the maximum dihedral angle. 30712 //maxdihed = b->maxdihedral / 180.0 * PI; // maxdihead commented out to get gcc 4.6 working 30713 // A sliver has an angle large than 'objdihed' will be split. 30714 objdihed = b->maxdihedral + 5.0; 30715 if (objdihed < 170.0) objdihed = 170.0; 30716 objdihed = objdihed / 180.0 * PI; 30717 } 30718 // Looking for non-optimal tets. 30719 tallslivers(optflag); 30720 30721 optcount[0] = 0l; // tet strip count. 30722 optcount[1] = 0l; // face (2-3) and edge (2-2) flip count. 30723 optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips. 30724 optcount[9] = 0l; // combined flip count. 30725 30726 // Perform edge flip to improve quality. 30727 lastentry = (badface *) NULL; 30728 // Loop until pool 'badtetrahedrons' is empty. 30729 while (badtetrahedrons->items > 0) { 30730 badtetrahedrons->traversalinit(); 30731 remtet = badfacetraverse(badtetrahedrons); 30732 while (remtet != (badface *) NULL) { 30733 // Make sure that the tet is still the same one when it was tested. 30734 // Subsequent transformations may have made it a different tet. 30735 if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg && 30736 dest(remtet->tt) == remtet->fdest && 30737 apex(remtet->tt) == remtet->fapex && 30738 oppo(remtet->tt) == remtet->foppo) { 30739 if (b->verbose > 1) { 30740 printf(" Repair tet (%d, %d, %d, %d) %g (degree).\n", 30741 pointmark(remtet->forg), pointmark(remtet->fdest), 30742 pointmark(remtet->fapex), pointmark(remtet->foppo), 30743 acos(remtet->key) / PI * 180.0); 30744 } 30745 if (!removeedge(remtet, optflag)) { 30746 // An unremoveable tet. Check if it forms a loop. 30747 if (lastentry != (badface *) NULL) { 30748 if (remtet == lastentry) break; 30749 } else { 30750 // Remember this tet as a breakpoint. 30751 lastentry = remtet; 30752 } 30753 } else { 30754 // Clear the breakpoint. 30755 lastentry = (badface *) NULL; 30756 // Remove the entry from the queue. 30757 badfacedealloc(badtetrahedrons, remtet); 30758 } 30759 } else { 30760 // Remove the entry from the queue. 30761 badfacedealloc(badtetrahedrons, remtet); 30762 } 30763 remtet = badfacetraverse(badtetrahedrons); 30764 } 30765 // Stop if the above loop was out by force. 30766 if (remtet != (badface *) NULL) break; 30767 } 30768 30769 if (b->verbose) { 30770 if (optcount[0] > 0l) { 30771 printf(" %ld tets are peeled off.\n", optcount[0]); 30772 } 30773 if (optcount[1] > 0l) { 30774 printf(" %ld faces are flipped.\n", optcount[1]); 30775 } 30776 if (optcount[3] + optcount[4] + optcount[5] + optcount[6] + 30777 optcount[9] > 0l) { 30778 printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] + 30779 optcount[5] + optcount[6] + optcount[9]); 30780 } 30781 // if (badtetrahedrons->items > 0l) { 30782 // printf(" %ld edges remain.\n", badtetrahedrons->items); 30783 // } 30784 } 30785 30786 if ((badtetrahedrons->items > 0l) && optflag && (b->optlevel > 2)) { 30787 splittetlist = new list(sizeof(badface), NULL, 256); 30788 tetlist = new list(sizeof(triface), NULL, 256); 30789 ceillist = new list(sizeof(triface), NULL, 256); 30790 oldnum = points->items; 30791 smoothsegverts = smoothvolverts = 0; 30792 optcount[1] = 0l; 30793 optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips. 30794 optcount[9] = 0l; // combined flip count. 30795 iter = 0; 30796 30797 do { 30798 // Form a list of slivers to be split and clean the pool. 30799 badtetrahedrons->traversalinit(); 30800 remtet = badfacetraverse(badtetrahedrons); 30801 while (remtet != (badface *) NULL) { 30802 splittetlist->append(remtet); 30803 // Remove the entry from the queue. 30804 badfacedealloc(badtetrahedrons, remtet); 30805 remtet = badfacetraverse(badtetrahedrons); 30806 } 30807 for (i = 0; i < splittetlist->len(); i++) { 30808 remtet = (badface *)(* splittetlist)[i]; 30809 // Make sure that the tet is still the same one when it was tested. 30810 // Subsequent transformations may have made it a different tet. 30811 if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg && 30812 dest(remtet->tt) == remtet->fdest && 30813 apex(remtet->tt) == remtet->fapex && 30814 oppo(remtet->tt) == remtet->foppo) { 30815 // The sliver may get smoothed due to a neighboring tet. 30816 curdihed = facedihedral(remtet->forg, remtet->fdest, remtet->fapex, 30817 remtet->foppo); 30818 // The dihedral angle of a tet must less than PI, correct it. 30819 if (curdihed > PI) curdihed = 2 * PI - curdihed; 30820 // Is it a large angle? 30821 if (curdihed > objdihed) { 30822 remtet->key = cos(curdihed); 30823 if (b->verbose > 1) { 30824 printf(" Get sliver (%d, %d, %d, %d) %g (degree).\n", 30825 pointmark(remtet->forg), pointmark(remtet->fdest), 30826 pointmark(remtet->fapex), pointmark(remtet->foppo), 30827 acos(remtet->key) / PI * 180.0); 30828 } 30829 if (!removeedge(remtet, optflag)) { 30830 if (!smoothsliver(remtet, tetlist)) { 30831 splitsliver(remtet, tetlist, ceillist); 30832 } 30833 } 30834 } 30835 } 30836 } 30837 iter++; 30838 } while ((badtetrahedrons->items > 0l) && (iter < b->optpasses)); 30839 30840 if (b->verbose) { 30841 printf(" %d passes.\n", iter); 30842 if ((points->items - oldnum) > 0l) { 30843 printf(" %ld points are inserted (%d on segment).\n", 30844 points->items - oldnum, smoothsegverts); 30845 } 30846 if (optcount[1] > 0l) { 30847 printf(" %ld faces are flipped.\n", optcount[1]); 30848 } 30849 if (optcount[3] + optcount[4] + optcount[5] + optcount[6] + 30850 optcount[9] > 0l) { 30851 printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] + 30852 optcount[5] + optcount[6] + optcount[9]); 30853 } 30854 // if (badtetrahedrons->items > 0l) { 30855 // printf(" %ld edges remain.\n", badtetrahedrons->items); 30856 // } 30857 } 30858 delete tetlist; 30859 delete ceillist; 30860 delete splittetlist; 30861 } 30862 30863 delete badtetrahedrons; 30864 badtetrahedrons = (memorypool *) NULL; 30865 } 30866 30867 // 30868 // End of mesh optimization routines 30869 // 30870 30871 // 30872 // Begin of I/O rouitnes 30873 // 30874 30876 // // 30877 // transfernodes() Transfer nodes from 'io->pointlist' to 'this->points'. // 30878 // // 30879 // Initializing 'this->points'. Transferring all points from 'in->pointlist'// 30880 // into it. All points are indexed (start from in->firstnumber). Each point // 30881 // is initialized be UNUSEDVERTEX. The bounding box (xmin, xmax, ymin, ymax,// 30882 // zmin, zmax) and the diameter (longest) of the point set are calculated. // 30883 // // 30885 30886 void tetgenmesh::transfernodes() 30887 { 30888 point pointloop; 30889 REAL x, y, z; 30890 int coordindex; 30891 int attribindex; 30892 int mtrindex; 30893 int i, j; 30894 30895 // Read the points. 30896 coordindex = 0; 30897 attribindex = 0; 30898 mtrindex = 0; 30899 for (i = 0; i < in->numberofpoints; i++) { 30900 makepoint(&pointloop); 30901 // Read the point coordinates. 30902 x = pointloop[0] = in->pointlist[coordindex++]; 30903 y = pointloop[1] = in->pointlist[coordindex++]; 30904 z = pointloop[2] = in->pointlist[coordindex++]; 30905 // Read the point attributes. 30906 for (j = 0; j < in->numberofpointattributes; j++) { 30907 pointloop[3 + j] = in->pointattributelist[attribindex++]; 30908 } 30909 // Read the point metric tensor. 30910 for (j = 0; j < in->numberofpointmtrs; j++) { 30911 pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++]; 30912 } 30913 // Determine the smallest and largests x, y and z coordinates. 30914 if (i == 0) { 30915 xmin = xmax = x; 30916 ymin = ymax = y; 30917 zmin = zmax = z; 30918 } else { 30919 xmin = (x < xmin) ? x : xmin; 30920 xmax = (x > xmax) ? x : xmax; 30921 ymin = (y < ymin) ? y : ymin; 30922 ymax = (y > ymax) ? y : ymax; 30923 zmin = (z < zmin) ? z : zmin; 30924 zmax = (z > zmax) ? z : zmax; 30925 } 30926 } 30927 // 'longest' is the largest possible edge length formed by input vertices. 30928 x = xmax - xmin; 30929 y = ymax - ymin; 30930 z = zmax - zmin; 30931 longest = sqrt(x * x + y * y + z * z); 30932 if (longest == 0.0) { 30933 printf("Error: The point set is trivial.\n"); 30934 terminatetetgen(1); 30935 } 30936 // Two identical points are distinguished by 'lengthlimit'. 30937 lengthlimit = longest * b->epsilon * 1e+2; 30938 } 30939 30941 // // 30942 // jettisonnodes() Jettison unused or duplicated vertices. // 30943 // // 30944 // Unused points are those input points which are outside the mesh domain or // 30945 // have no connection (isolated) to the mesh. Duplicated points exist for // 30946 // example if the input PLC is read from a .stl mesh file (marked during the // 30947 // Delaunay tetrahedralization step. This routine remove these points from // 30948 // points list. All existing points are reindexed. // 30949 // // 30951 30952 void tetgenmesh::jettisonnodes() 30953 { 30954 point pointloop; 30955 bool jetflag; 30956 int oldidx, newidx; 30957 int remcount; 30958 30959 if (!b->quiet) { 30960 printf("Jettisoning redundants points.\n"); 30961 } 30962 30963 points->traversalinit(); 30964 pointloop = pointtraverse(); 30965 oldidx = newidx = 0; // in->firstnumber; 30966 remcount = 0; 30967 while (pointloop != (point) NULL) { 30968 jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || 30969 (pointtype(pointloop) == UNUSEDVERTEX); 30970 if (jetflag) { 30971 // It is a duplicated point, delete it. 30972 pointdealloc(pointloop); 30973 remcount++; 30974 } else { 30975 // Re-index it. 30976 setpointmark(pointloop, newidx + in->firstnumber); 30977 if (in->pointmarkerlist != (int *) NULL) { 30978 if (oldidx < in->numberofpoints) { 30979 // Re-index the point marker as well. 30980 in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx]; 30981 } 30982 } 30983 newidx++; 30984 } 30985 oldidx++; 30986 if (oldidx == in->numberofpoints) { 30987 // Update the numbe of input points (Because some were removed). 30988 in->numberofpoints -= remcount; 30989 // Remember this number for output original input nodes. 30990 jettisoninverts = remcount; 30991 } 30992 pointloop = pointtraverse(); 30993 } 30994 if (b->verbose) { 30995 printf(" %d duplicated vertices have been removed.\n", dupverts); 30996 printf(" %d unused vertices have been removed.\n", unuverts); 30997 } 30998 dupverts = 0; 30999 unuverts = 0; 31000 31001 // The following line ensures that dead items in the pool of nodes cannot 31002 // be allocated for the new created nodes. This ensures that the input 31003 // nodes will occur earlier in the output files, and have lower indices. 31004 points->deaditemstack = (void *) NULL; 31005 } 31006 31008 // // 31009 // highorder() Create extra nodes for quadratic subparametric elements. // 31010 // // 31011 // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing // 31012 // high-order nodes of each tetrahedron. This routine is used only when -o2 // 31013 // switch is used. // 31014 // // 31016 31017 void tetgenmesh::highorder() 31018 { 31019 triface tetloop, worktet; 31020 triface spintet, adjtet; 31021 point torg, tdest, tapex; 31022 point *extralist, *adjextralist; 31023 point newpoint; 31024 int hitbdry, ptmark; 31025 int i, j; 31026 31027 if (!b->quiet) { 31028 printf("Adding vertices for second-order tetrahedra.\n"); 31029 } 31030 31031 // Initialize the 'highordertable'. 31032 highordertable = new point[tetrahedrons->items * 6]; 31033 if (highordertable == (point *) NULL) { 31034 printf("Error: Out of memory.\n"); 31035 terminatetetgen(1); 31036 } 31037 31038 // The following line ensures that dead items in the pool of nodes cannot 31039 // be allocated for the extra nodes associated with high order elements. 31040 // This ensures that the primary nodes (at the corners of elements) will 31041 // occur earlier in the output files, and have lower indices, than the 31042 // extra nodes. 31043 points->deaditemstack = (void *) NULL; 31044 31045 // Assign an entry for each tetrahedron to find its extra nodes. At the 31046 // mean while, initialize all extra nodes be NULL. 31047 i = 0; 31048 tetrahedrons->traversalinit(); 31049 tetloop.tet = tetrahedrontraverse(); 31050 while (tetloop.tet != (tetrahedron *) NULL) { 31051 tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i]; 31052 for (j = 0; j < 6; j++) { 31053 highordertable[i + j] = (point) NULL; 31054 } 31055 i += 6; 31056 tetloop.tet = tetrahedrontraverse(); 31057 } 31058 31059 // To create a unique node on each edge. Loop over all tetrahedra, and 31060 // look at the six edges of each tetrahedron. If the extra node in 31061 // the tetrahedron corresponding to this edge is NULL, create a node 31062 // for this edge, at the same time, set the new node into the extra 31063 // node lists of all other tetrahedra sharing this edge. 31064 tetrahedrons->traversalinit(); 31065 tetloop.tet = tetrahedrontraverse(); 31066 while (tetloop.tet != (tetrahedron *) NULL) { 31067 // Get the list of extra nodes. 31068 extralist = (point *) tetloop.tet[highorderindex]; 31069 worktet.tet = tetloop.tet; 31070 for (i = 0; i < 6; i++) { 31071 if (extralist[i] == (point) NULL) { 31072 // Operate on this edge. 31073 worktet.loc = edge2locver[i][0]; 31074 worktet.ver = edge2locver[i][1]; 31075 // Create a new node on this edge. 31076 torg = org(worktet); 31077 tdest = dest(worktet); 31078 // Create a new node in the middle of the edge. 31079 newpoint = (point) points->alloc(); 31080 // Interpolate its attributes. 31081 for (j = 0; j < 3 + in->numberofpointattributes; j++) { 31082 newpoint[j] = 0.5 * (torg[j] + tdest[j]); 31083 } 31084 ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); 31085 setpointmark(newpoint, ptmark); 31086 // Add this node to its extra node list. 31087 extralist[i] = newpoint; 31088 // Set 'newpoint' into extra node lists of other tetrahedra 31089 // sharing this edge. 31090 tapex = apex(worktet); 31091 spintet = worktet; 31092 hitbdry = 0; 31093 while (hitbdry < 2) { 31094 if (fnextself(spintet)) { 31095 // Get the extra node list of 'spintet'. 31096 adjextralist = (point *) spintet.tet[highorderindex]; 31097 // Find the index of its extra node list. 31098 j = locver2edge[spintet.loc][spintet.ver]; 31099 // Only set 'newpoint' into 'adjextralist' if it is a NULL. 31100 // Because two faces can belong to the same tetrahedron. 31101 if (adjextralist[j] == (point) NULL) { 31102 adjextralist[j] = newpoint; 31103 } 31104 if (apex(spintet) == tapex) { 31105 break; 31106 } 31107 } else { 31108 hitbdry++; 31109 if (hitbdry < 2) { 31110 esym(worktet, spintet); 31111 } 31112 } 31113 } 31114 } 31115 } 31116 tetloop.tet = tetrahedrontraverse(); 31117 } 31118 } 31119 31121 // // 31122 // outnodes() Output the points to a .node file or a tetgenio structure. // 31123 // // 31124 // Note: each point has already been numbered on input (the first index is // 31125 // 'in->firstnumber'). // 31126 // // 31128 31129 void tetgenmesh::outnodes(tetgenio* out) 31130 { 31131 FILE *outfile; 31132 char outnodefilename[FILENAMESIZE]; 31133 shellface subptr; 31134 triface adjtet; 31135 face subloop; 31136 point pointloop; 31137 point *extralist, ep[3]; 31138 int nextras, bmark, shmark, marker; 31139 int coordindex, attribindex; 31140 int pointnumber, firstindex; 31141 int index, i; 31142 31143 if (out == (tetgenio *) NULL) { 31144 strcpy(outnodefilename, b->outfilename); 31145 strcat(outnodefilename, ".node"); 31146 } 31147 31148 if (!b->quiet) { 31149 if (out == (tetgenio *) NULL) { 31150 printf("Writing %s.\n", outnodefilename); 31151 } else { 31152 printf("Writing nodes.\n"); 31153 } 31154 } 31155 31156 nextras = in->numberofpointattributes; 31157 bmark = !b->nobound && in->pointmarkerlist; 31158 31159 // Avoid compile warnings. 31160 outfile = (FILE *) NULL; 31161 marker = coordindex = 0; 31162 31163 if (out == (tetgenio *) NULL) { 31164 outfile = fopen(outnodefilename, "w"); 31165 if (outfile == (FILE *) NULL) { 31166 printf("File I/O Error: Cannot create file %s.\n", outnodefilename); 31167 terminatetetgen(1); 31168 } 31169 // Number of points, number of dimensions, number of point attributes, 31170 // and number of boundary markers (zero or one). 31171 fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark); 31172 } else { 31173 // Allocate space for 'pointlist'; 31174 out->pointlist = new REAL[points->items * 3]; 31175 if (out->pointlist == (REAL *) NULL) { 31176 printf("Error: Out of memory.\n"); 31177 terminatetetgen(1); 31178 } 31179 // Allocate space for 'pointattributelist' if necessary; 31180 if (nextras > 0) { 31181 out->pointattributelist = new REAL[points->items * nextras]; 31182 if (out->pointattributelist == (REAL *) NULL) { 31183 printf("Error: Out of memory.\n"); 31184 terminatetetgen(1); 31185 } 31186 } 31187 // Allocate space for 'pointmarkerlist' if necessary; 31188 if (bmark) { 31189 out->pointmarkerlist = new int[points->items]; 31190 if (out->pointmarkerlist == (int *) NULL) { 31191 printf("Error: Out of memory.\n"); 31192 terminatetetgen(1); 31193 } 31194 } 31195 out->numberofpoints = points->items; 31196 out->numberofpointattributes = nextras; 31197 coordindex = 0; 31198 attribindex = 0; 31199 } 31200 31201 if (bmark && (b->plc || b->refine)) { 31202 // Initialize the point2tet field of each point. 31203 points->traversalinit(); 31204 pointloop = pointtraverse(); 31205 while (pointloop != (point) NULL) { 31206 setpoint2tet(pointloop, (tetrahedron) NULL); 31207 pointloop = pointtraverse(); 31208 } 31209 // Make a map point-to-subface. Hence a boundary point will get the 31210 // facet marker from that facet where it lies on. 31211 subfaces->traversalinit(); 31212 subloop.sh = shellfacetraverse(subfaces); 31213 while (subloop.sh != (shellface *) NULL) { 31214 subloop.shver = 0; 31215 // Check all three points of the subface. 31216 for (i = 0; i < 3; i++) { 31217 pointloop = (point) subloop.sh[3 + i]; 31218 setpoint2tet(pointloop, (tetrahedron) sencode(subloop)); 31219 } 31220 if (b->order == 2) { 31221 // '-o2' switch. Set markers for quadratic nodes of this subface. 31222 stpivot(subloop, adjtet); 31223 if (adjtet.tet == dummytet) { 31224 sesymself(subloop); 31225 stpivot(subloop, adjtet); 31226 } 31227 assert(adjtet.tet != dummytet); 31228 extralist = (point *) adjtet.tet[highorderindex]; 31229 switch (adjtet.loc) { 31230 case 0: 31231 ep[0] = extralist[0]; 31232 ep[1] = extralist[1]; 31233 ep[2] = extralist[2]; 31234 break; 31235 case 1: 31236 ep[0] = extralist[0]; 31237 ep[1] = extralist[4]; 31238 ep[2] = extralist[3]; 31239 break; 31240 case 2: 31241 ep[0] = extralist[1]; 31242 ep[1] = extralist[5]; 31243 ep[2] = extralist[4]; 31244 break; 31245 case 3: 31246 ep[0] = extralist[2]; 31247 ep[1] = extralist[3]; 31248 ep[2] = extralist[5]; 31249 break; 31250 default: break; 31251 } 31252 for (i = 0; i < 3; i++) { 31253 setpoint2tet(ep[i], (tetrahedron) sencode(subloop)); 31254 } 31255 } 31256 subloop.sh = shellfacetraverse(subfaces); 31257 } 31258 } 31259 31260 // Determine the first index (0 or 1). 31261 firstindex = b->zeroindex ? 0 : in->firstnumber; 31262 31263 points->traversalinit(); 31264 pointloop = pointtraverse(); 31265 pointnumber = firstindex; // in->firstnumber; 31266 index = 0; 31267 while (pointloop != (point) NULL) { 31268 if (bmark) { 31269 // Default the vertex has a zero marker. 31270 marker = 0; 31271 // Is it an input vertex? 31272 if (index < in->numberofpoints) { 31273 // Input point's marker is directly copied to output. 31274 marker = in->pointmarkerlist[index]; 31275 } 31276 // Is it a boundary vertex has marker zero? 31277 if ((marker == 0) && (b->plc || b->refine)) { 31278 subptr = (shellface) point2tet(pointloop); 31279 if (subptr != (shellface) NULL) { 31280 // Default a boundary vertex has marker 1. 31281 marker = 1; 31282 if (in->facetmarkerlist != (int *) NULL) { 31283 // The vertex gets the marker from the facet it lies on. 31284 sdecode(subptr, subloop); 31285 shmark = shellmark(subloop); 31286 marker = in->facetmarkerlist[shmark - 1]; 31287 } 31288 } 31289 } 31290 } 31291 if (out == (tetgenio *) NULL) { 31292 // Point number, x, y and z coordinates. 31293 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, 31294 pointloop[0], pointloop[1], pointloop[2]); 31295 for (i = 0; i < nextras; i++) { 31296 // Write an attribute. 31297 fprintf(outfile, " %.17g", pointloop[3 + i]); 31298 } 31299 if (bmark) { 31300 // Write the boundary marker. 31301 fprintf(outfile, " %d", marker); 31302 } 31303 fprintf(outfile, "\n"); 31304 } else { 31305 // X, y, and z coordinates. 31306 out->pointlist[coordindex++] = pointloop[0]; 31307 out->pointlist[coordindex++] = pointloop[1]; 31308 out->pointlist[coordindex++] = pointloop[2]; 31309 // Point attributes. 31310 for (i = 0; i < nextras; i++) { 31311 // Output an attribute. 31312 out->pointattributelist[attribindex++] = pointloop[3 + i]; 31313 } 31314 if (bmark) { 31315 // Output the boundary marker. 31316 out->pointmarkerlist[index] = marker; 31317 } 31318 } 31319 pointloop = pointtraverse(); 31320 pointnumber++; 31321 index++; 31322 } 31323 31324 if (out == (tetgenio *) NULL) { 31325 fprintf(outfile, "# Generated by %s\n", b->commandline); 31326 fclose(outfile); 31327 } 31328 } 31329 31331 // // 31332 // outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. // 31333 // // 31335 31336 void tetgenmesh::outmetrics(tetgenio* out) 31337 { 31338 FILE *outfile; 31339 char outmtrfilename[FILENAMESIZE]; 31340 list *tetlist, *ptlist; 31341 triface tetloop; 31342 point ptloop, neipt; 31343 REAL lave, len; // lmin, lmax, 31344 int mtrindex; 31345 int i; 31346 31347 lave = 0.0; 31348 31349 if (out == (tetgenio *) NULL) { 31350 strcpy(outmtrfilename, b->outfilename); 31351 strcat(outmtrfilename, ".mtr"); 31352 } 31353 31354 if (!b->quiet) { 31355 if (out == (tetgenio *) NULL) { 31356 printf("Writing %s.\n", outmtrfilename); 31357 } else { 31358 printf("Writing metrics.\n"); 31359 } 31360 } 31361 31362 // Avoid compile warnings. 31363 outfile = (FILE *) NULL; 31364 mtrindex = 0; 31365 31366 if (out == (tetgenio *) NULL) { 31367 outfile = fopen(outmtrfilename, "w"); 31368 if (outfile == (FILE *) NULL) { 31369 printf("File I/O Error: Cannot create file %s.\n", outmtrfilename); 31370 terminatetetgen(1); 31371 } 31372 // Number of points, number of point metrices, 31373 // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3); 31374 fprintf(outfile, "%ld %d\n", points->items, 1); 31375 } else { 31376 // Allocate space for 'pointmtrlist' if necessary; 31377 // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)]; 31378 out->pointmtrlist = new REAL[points->items]; 31379 if (out->pointmtrlist == (REAL *) NULL) { 31380 printf("Error: Out of memory.\n"); 31381 terminatetetgen(1); 31382 } 31383 out->numberofpointmtrs = 1; // (sizeoftensor + 3); 31384 mtrindex = 0; 31385 } 31386 31387 // Initialize the point2tet field of each point. 31388 points->traversalinit(); 31389 ptloop = pointtraverse(); 31390 while (ptloop != (point) NULL) { 31391 setpoint2tet(ptloop, (tetrahedron) NULL); 31392 ptloop = pointtraverse(); 31393 } 31394 // Create the point-to-tet map. 31395 tetrahedrons->traversalinit(); 31396 tetloop.tet = tetrahedrontraverse(); 31397 while (tetloop.tet != (tetrahedron *) NULL) { 31398 for (i = 0; i < 4; i++) { 31399 ptloop = (point) tetloop.tet[4 + i]; 31400 setpoint2tet(ptloop, encode(tetloop)); 31401 } 31402 tetloop.tet = tetrahedrontraverse(); 31403 } 31404 31405 tetlist = new list(sizeof(triface), NULL, 256); 31406 ptlist = new list(sizeof(point *), NULL, 256); 31407 31408 points->traversalinit(); 31409 ptloop = pointtraverse(); 31410 while (ptloop != (point) NULL) { 31411 decode(point2tet(ptloop), tetloop); 31412 if (!isdead(&tetloop)) { 31413 // Form the star of p. 31414 tetlist->append(&tetloop); 31415 formstarpolyhedron(ptloop, tetlist, ptlist, true); 31416 // lmin = longest; 31417 // lmax = 0.0; 31418 lave = 0.0; 31419 for (i = 0; i < ptlist->len(); i++) { 31420 neipt = * (point *)(* ptlist)[i]; 31421 len = distance(ptloop, neipt); 31422 // lmin = lmin < len ? lmin : len; 31423 // lmax = lmax > len ? lmax : len; 31424 lave += len; 31425 } 31426 lave /= ptlist->len(); 31427 } 31428 if (out == (tetgenio *) NULL) { 31429 // for (i = 0; i < sizeoftensor; i++) { 31430 // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]); 31431 // } 31432 if (ptlist->len() > 0) { 31433 // fprintf(outfile, "%-16.8e %-16.8e %-16.8e", lmin, lmax, lave); 31434 fprintf(outfile, "%-16.8e ", lave); 31435 } else { 31436 fprintf(outfile, "0.0 "); // fprintf(outfile, "0.0 0.0 0.0"); 31437 } 31438 fprintf(outfile, "\n"); 31439 } else { 31440 // for (i = 0; i < sizeoftensor; i++) { 31441 // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i]; 31442 // } 31443 if (ptlist->len() > 0) { 31444 // out->pointmtrlist[mtrindex++] = lmin; 31445 // out->pointmtrlist[mtrindex++] = lmax; 31446 out->pointmtrlist[mtrindex++] = lave; 31447 } else { 31448 // out->pointmtrlist[mtrindex++] = 0.0; 31449 // out->pointmtrlist[mtrindex++] = 0.0; 31450 out->pointmtrlist[mtrindex++] = 0.0; 31451 } 31452 } 31453 tetlist->clear(); 31454 ptlist->clear(); 31455 ptloop = pointtraverse(); 31456 } 31457 31458 delete tetlist; 31459 delete ptlist; 31460 31461 if (out == (tetgenio *) NULL) { 31462 fprintf(outfile, "# Generated by %s\n", b->commandline); 31463 fclose(outfile); 31464 } 31465 } 31466 31468 // // 31469 // outelements() Output the tetrahedra to an .ele file or a tetgenio // 31470 // structure. // 31471 // // 31473 31474 void tetgenmesh::outelements(tetgenio* out) 31475 { 31476 FILE *outfile; 31477 char outelefilename[FILENAMESIZE]; 31478 tetrahedron* tptr; 31479 int *tlist; 31480 REAL *talist; 31481 int firstindex, shift; 31482 int pointindex; 31483 int attribindex; 31484 point p1, p2, p3, p4; 31485 point *extralist; 31486 int elementnumber; 31487 int eextras; 31488 int i; 31489 31490 if (out == (tetgenio *) NULL) { 31491 strcpy(outelefilename, b->outfilename); 31492 strcat(outelefilename, ".ele"); 31493 } 31494 31495 if (!b->quiet) { 31496 if (out == (tetgenio *) NULL) { 31497 printf("Writing %s.\n", outelefilename); 31498 } else { 31499 printf("Writing elements.\n"); 31500 } 31501 } 31502 31503 // Avoid compile warnings. 31504 outfile = (FILE *) NULL; 31505 tlist = (int *) NULL; 31506 talist = (double *) NULL; 31507 pointindex = attribindex = 0; 31508 31509 eextras = in->numberoftetrahedronattributes; 31510 if (out == (tetgenio *) NULL) { 31511 outfile = fopen(outelefilename, "w"); 31512 if (outfile == (FILE *) NULL) { 31513 printf("File I/O Error: Cannot create file %s.\n", outelefilename); 31514 terminatetetgen(1); 31515 } 31516 // Number of tetras, points per tetra, attributes per tetra. 31517 fprintf(outfile, "%ld %d %d\n", tetrahedrons->items, 31518 b->order == 1 ? 4 : 10, eextras); 31519 } else { 31520 // Allocate memory for output tetrahedra. 31521 out->tetrahedronlist = new int[tetrahedrons->items * 31522 (b->order == 1 ? 4 : 10)]; 31523 if (out->tetrahedronlist == (int *) NULL) { 31524 printf("Error: Out of memory.\n"); 31525 terminatetetgen(1); 31526 } 31527 // Allocate memory for output tetrahedron attributes if necessary. 31528 if (eextras > 0) { 31529 out->tetrahedronattributelist = new REAL[tetrahedrons->items * eextras]; 31530 if (out->tetrahedronattributelist == (REAL *) NULL) { 31531 printf("Error: Out of memory.\n"); 31532 terminatetetgen(1); 31533 } 31534 } 31535 out->numberoftetrahedra = tetrahedrons->items; 31536 out->numberofcorners = b->order == 1 ? 4 : 10; 31537 out->numberoftetrahedronattributes = eextras; 31538 tlist = out->tetrahedronlist; 31539 talist = out->tetrahedronattributelist; 31540 pointindex = 0; 31541 attribindex = 0; 31542 } 31543 31544 // Determine the first index (0 or 1). 31545 firstindex = b->zeroindex ? 0 : in->firstnumber; 31546 shift = 0; // Default no shiftment. 31547 if ((in->firstnumber == 1) && (firstindex == 0)) { 31548 shift = 1; // Shift the output indices by 1. 31549 } 31550 31551 tetrahedrons->traversalinit(); 31552 tptr = tetrahedrontraverse(); 31553 elementnumber = firstindex; // in->firstnumber; 31554 while (tptr != (tetrahedron *) NULL) { 31555 p1 = (point) tptr[4]; 31556 p2 = (point) tptr[5]; 31557 p3 = (point) tptr[6]; 31558 p4 = (point) tptr[7]; 31559 if (out == (tetgenio *) NULL) { 31560 // Tetrahedron number, indices for four points. 31561 fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, 31562 pointmark(p1) - shift, pointmark(p2) - shift, 31563 pointmark(p3) - shift, pointmark(p4) - shift); 31564 if (b->order == 2) { 31565 extralist = (point *) tptr[highorderindex]; 31566 // Tetrahedron number, indices for four points plus six extra points. 31567 fprintf(outfile, " %5d %5d %5d %5d %5d %5d", 31568 pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift, 31569 pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift, 31570 pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift); 31571 } 31572 for (i = 0; i < eextras; i++) { 31573 fprintf(outfile, " %.17g", elemattribute(tptr, i)); 31574 } 31575 fprintf(outfile, "\n"); 31576 } else { 31577 tlist[pointindex++] = pointmark(p1) - shift; 31578 tlist[pointindex++] = pointmark(p2) - shift; 31579 tlist[pointindex++] = pointmark(p3) - shift; 31580 tlist[pointindex++] = pointmark(p4) - shift; 31581 if (b->order == 2) { 31582 extralist = (point *) tptr[highorderindex]; 31583 tlist[pointindex++] = pointmark(extralist[0]) - shift; 31584 tlist[pointindex++] = pointmark(extralist[1]) - shift; 31585 tlist[pointindex++] = pointmark(extralist[2]) - shift; 31586 tlist[pointindex++] = pointmark(extralist[3]) - shift; 31587 tlist[pointindex++] = pointmark(extralist[4]) - shift; 31588 tlist[pointindex++] = pointmark(extralist[5]) - shift; 31589 } 31590 for (i = 0; i < eextras; i++) { 31591 talist[attribindex++] = elemattribute(tptr, i); 31592 } 31593 } 31594 if (b->neighout) { 31595 // Remember the index of this element. 31596 * (int *) (tptr + elemmarkerindex) = elementnumber; 31597 } 31598 tptr = tetrahedrontraverse(); 31599 elementnumber++; 31600 } 31601 if (b->neighout) { 31602 // Set the outside element marker. 31603 * (int *) (dummytet + elemmarkerindex) = -1; 31604 } 31605 31606 if (out == (tetgenio *) NULL) { 31607 fprintf(outfile, "# Generated by %s\n", b->commandline); 31608 fclose(outfile); 31609 } 31610 } 31611 31613 // // 31614 // outfaces() Output all faces to a .face file or a tetgenio structure. // 31615 // // 31616 // This routines outputs all triangular faces (including outer boundary // 31617 // faces and inner faces) of this mesh. // 31618 // // 31620 31621 void tetgenmesh::outfaces(tetgenio* out) 31622 { 31623 FILE *outfile; 31624 char facefilename[FILENAMESIZE]; 31625 int *elist; 31626 int *emlist; 31627 int neigh1, neigh2; 31628 int index; 31629 triface tface, tsymface; 31630 face checkmark; 31631 point torg, tdest, tapex; 31632 long faces; 31633 int bmark, faceid, marker; 31634 int firstindex, shift; 31635 int facenumber; 31636 31637 neigh1 = 0; 31638 neigh2 = 0; 31639 31640 if (out == (tetgenio *) NULL) { 31641 strcpy(facefilename, b->outfilename); 31642 strcat(facefilename, ".face"); 31643 } 31644 31645 if (!b->quiet) { 31646 if (out == (tetgenio *) NULL) { 31647 printf("Writing %s.\n", facefilename); 31648 } else { 31649 printf("Writing faces.\n"); 31650 } 31651 } 31652 31653 // Avoid compile warnings. 31654 outfile = (FILE *) NULL; 31655 elist = (int *) NULL; 31656 emlist = (int *) NULL; 31657 index = marker = 0; 31658 31659 faces = (4l * tetrahedrons->items + hullsize) / 2l; 31660 bmark = !b->nobound && in->facetmarkerlist; 31661 31662 if (out == (tetgenio *) NULL) { 31663 outfile = fopen(facefilename, "w"); 31664 if (outfile == (FILE *) NULL) { 31665 printf("File I/O Error: Cannot create file %s.\n", facefilename); 31666 terminatetetgen(1); 31667 } 31668 fprintf(outfile, "%ld %d\n", faces, bmark); 31669 } else { 31670 // Allocate memory for 'trifacelist'. 31671 out->trifacelist = new int[faces * 3]; 31672 if (out->trifacelist == (int *) NULL) { 31673 printf("Error: Out of memory.\n"); 31674 terminatetetgen(1); 31675 } 31676 // Allocate memory for 'trifacemarkerlist' if necessary. 31677 if (bmark) { 31678 out->trifacemarkerlist = new int[faces]; 31679 if (out->trifacemarkerlist == (int *) NULL) { 31680 printf("Error: Out of memory.\n"); 31681 terminatetetgen(1); 31682 } 31683 } 31684 if (b->neighout > 1) { 31685 // '-nn' switch. 31686 out->adjtetlist = new int[subfaces->items * 2]; 31687 if (out->adjtetlist == (int *) NULL) { 31688 printf("Error: Out of memory.\n"); 31689 terminatetetgen(1); 31690 } 31691 } 31692 out->numberoftrifaces = faces; 31693 elist = out->trifacelist; 31694 emlist = out->trifacemarkerlist; 31695 index = 0; 31696 } 31697 31698 // Determine the first index (0 or 1). 31699 firstindex = b->zeroindex ? 0 : in->firstnumber; 31700 shift = 0; // Default no shiftment. 31701 if ((in->firstnumber == 1) && (firstindex == 0)) { 31702 shift = 1; // Shift the output indices by 1. 31703 } 31704 31705 tetrahedrons->traversalinit(); 31706 tface.tet = tetrahedrontraverse(); 31707 facenumber = firstindex; // in->firstnumber; 31708 // To loop over the set of faces, loop over all tetrahedra, and look at 31709 // the four faces of each one. If there isn't another tetrahedron 31710 // adjacent to this face, operate on the face. If there is another 31711 // adjacent tetrahedron, operate on the face only if the current 31712 // tetrahedron has a smaller pointer than its neighbor. This way, each 31713 // face is considered only once. 31714 while (tface.tet != (tetrahedron *) NULL) { 31715 for (tface.loc = 0; tface.loc < 4; tface.loc ++) { 31716 sym(tface, tsymface); 31717 if ((tsymface.tet == dummytet) || (tface.tet < tsymface.tet)) { 31718 torg = org(tface); 31719 tdest = dest(tface); 31720 tapex = apex(tface); 31721 if (bmark) { 31722 // Get the boundary marker of this face. If it is an inner face, 31723 // it has no boundary marker, set it be zero. 31724 if (b->useshelles) { 31725 // Shell face is used. 31726 tspivot(tface, checkmark); 31727 if (checkmark.sh == dummysh) { 31728 marker = 0; // It is an inner face. 31729 } else { 31730 faceid = shellmark(checkmark) - 1; 31731 marker = in->facetmarkerlist[faceid]; 31732 } 31733 } else { 31734 // Shell face is not used, only distinguish outer and inner face. 31735 marker = tsymface.tet != dummytet ? 1 : 0; 31736 } 31737 } 31738 if (b->neighout > 1) { 31739 // '-nn' switch. Output adjacent tets indices. 31740 neigh1 = * (int *)(tface.tet + elemmarkerindex); 31741 if (tsymface.tet != dummytet) { 31742 neigh2 = * (int *)(tsymface.tet + elemmarkerindex); 31743 } else { 31744 neigh2 = -1; 31745 } 31746 } 31747 if (out == (tetgenio *) NULL) { 31748 // Face number, indices of three vertices. 31749 fprintf(outfile, "%5d %4d %4d %4d", facenumber, 31750 pointmark(torg) - shift, pointmark(tdest) - shift, 31751 pointmark(tapex) - shift); 31752 if (bmark) { 31753 // Output a boundary marker. 31754 fprintf(outfile, " %d", marker); 31755 } 31756 if (b->neighout > 1) { 31757 fprintf(outfile, " %5d %5d", neigh1, neigh2); 31758 } 31759 fprintf(outfile, "\n"); 31760 } else { 31761 // Output indices of three vertices. 31762 elist[index++] = pointmark(torg) - shift; 31763 elist[index++] = pointmark(tdest) - shift; 31764 elist[index++] = pointmark(tapex) - shift; 31765 if (bmark) { 31766 emlist[facenumber - in->firstnumber] = marker; 31767 } 31768 if (b->neighout > 1) { 31769 out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1; 31770 out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2; 31771 } 31772 } 31773 facenumber++; 31774 } 31775 } 31776 tface.tet = tetrahedrontraverse(); 31777 } 31778 31779 if (out == (tetgenio *) NULL) { 31780 fprintf(outfile, "# Generated by %s\n", b->commandline); 31781 fclose(outfile); 31782 } 31783 } 31784 31786 // // 31787 // outhullfaces() Output outer boundary faces to a .face file or a // 31788 // tetgenio structure. // 31789 // // 31790 // The normal of each face is arranged to point inside of the domain (use // 31791 // right-hand rule). This routines will outputs convex hull faces if the // 31792 // mesh is a Delaunay tetrahedralization. // 31793 // // 31795 31796 void tetgenmesh::outhullfaces(tetgenio* out) 31797 { 31798 FILE *outfile; 31799 char facefilename[FILENAMESIZE]; 31800 int *elist; 31801 int index; 31802 triface tface, tsymface; 31803 face checkmark; 31804 point torg, tdest, tapex; 31805 int firstindex, shift; 31806 int facenumber; 31807 31808 if (out == (tetgenio *) NULL) { 31809 strcpy(facefilename, b->outfilename); 31810 strcat(facefilename, ".face"); 31811 } 31812 31813 if (!b->quiet) { 31814 if (out == (tetgenio *) NULL) { 31815 printf("Writing %s.\n", facefilename); 31816 } else { 31817 printf("Writing faces.\n"); 31818 } 31819 } 31820 31821 // Avoid compile warnings. 31822 outfile = (FILE *) NULL; 31823 elist = (int *) NULL; 31824 index = 0; 31825 31826 if (out == (tetgenio *) NULL) { 31827 outfile = fopen(facefilename, "w"); 31828 if (outfile == (FILE *) NULL) { 31829 printf("File I/O Error: Cannot create file %s.\n", facefilename); 31830 terminatetetgen(1); 31831 } 31832 fprintf(outfile, "%ld 0\n", hullsize); 31833 } else { 31834 // Allocate memory for 'trifacelist'. 31835 out->trifacelist = new int[hullsize * 3]; 31836 if (out->trifacelist == (int *) NULL) { 31837 printf("Error: Out of memory.\n"); 31838 terminatetetgen(1); 31839 } 31840 out->numberoftrifaces = hullsize; 31841 elist = out->trifacelist; 31842 index = 0; 31843 } 31844 31845 // Determine the first index (0 or 1). 31846 firstindex = b->zeroindex ? 0 : in->firstnumber; 31847 shift = 0; // Default no shiftment. 31848 if ((in->firstnumber == 1) && (firstindex == 0)) { 31849 shift = 1; // Shift the output indices by 1. 31850 } 31851 31852 tetrahedrons->traversalinit(); 31853 tface.tet = tetrahedrontraverse(); 31854 facenumber = firstindex; // in->firstnumber; 31855 // To loop over the set of hull faces, loop over all tetrahedra, and look 31856 // at the four faces of each one. If there isn't another tetrahedron 31857 // adjacent to this face, operate on the face. 31858 while (tface.tet != (tetrahedron *) NULL) { 31859 for (tface.loc = 0; tface.loc < 4; tface.loc ++) { 31860 sym(tface, tsymface); 31861 if (tsymface.tet == dummytet) { 31862 torg = org(tface); 31863 tdest = dest(tface); 31864 tapex = apex(tface); 31865 if (out == (tetgenio *) NULL) { 31866 // Face number, indices of three vertices. 31867 fprintf(outfile, "%5d %4d %4d %4d", facenumber, 31868 pointmark(torg) - shift, pointmark(tdest) - shift, 31869 pointmark(tapex) - shift); 31870 fprintf(outfile, "\n"); 31871 } else { 31872 // Output indices of three vertices. 31873 elist[index++] = pointmark(torg) - shift; 31874 elist[index++] = pointmark(tdest) - shift; 31875 elist[index++] = pointmark(tapex) - shift; 31876 } 31877 facenumber++; 31878 } 31879 } 31880 tface.tet = tetrahedrontraverse(); 31881 } 31882 31883 if (out == (tetgenio *) NULL) { 31884 fprintf(outfile, "# Generated by %s\n", b->commandline); 31885 fclose(outfile); 31886 } 31887 } 31888 31890 // // 31891 // outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or // 31892 // a tetgenio structure. // 31893 // // 31894 // The boundary faces are exist in 'subfaces'. For listing triangle vertices // 31895 // in the same sense for all triangles in the mesh, the direction determined // 31896 // by right-hand rule is pointer to the inside of the volume. // 31897 // // 31899 31900 void tetgenmesh::outsubfaces(tetgenio* out) 31901 { 31902 FILE *outfile; 31903 char facefilename[FILENAMESIZE]; 31904 int *elist; 31905 int *emlist; 31906 int index, index1, index2; 31907 triface abuttingtet; 31908 face faceloop; 31909 point torg, tdest, tapex; 31910 int bmark, faceid, marker; 31911 int firstindex, shift; 31912 int neigh1, neigh2; 31913 int facenumber; 31914 31915 if (out == (tetgenio *) NULL) { 31916 strcpy(facefilename, b->outfilename); 31917 strcat(facefilename, ".face"); 31918 } 31919 31920 if (!b->quiet) { 31921 if (out == (tetgenio *) NULL) { 31922 printf("Writing %s.\n", facefilename); 31923 } else { 31924 printf("Writing faces.\n"); 31925 } 31926 } 31927 31928 // Avoid compile warnings. 31929 outfile = (FILE *) NULL; 31930 elist = (int *) NULL; 31931 emlist = (int *) NULL; 31932 index = index1 = index2 = 0; 31933 faceid = marker = 0; 31934 neigh1 = neigh2 = 0; 31935 31936 bmark = !b->nobound && in->facetmarkerlist; 31937 31938 if (out == (tetgenio *) NULL) { 31939 outfile = fopen(facefilename, "w"); 31940 if (outfile == (FILE *) NULL) { 31941 printf("File I/O Error: Cannot create file %s.\n", facefilename); 31942 terminatetetgen(1); 31943 } 31944 // Number of subfaces. 31945 fprintf(outfile, "%ld %d\n", subfaces->items, bmark); 31946 } else { 31947 // Allocate memory for 'trifacelist'. 31948 out->trifacelist = new int[subfaces->items * 3]; 31949 if (out->trifacelist == (int *) NULL) { 31950 printf("Error: Out of memory.\n"); 31951 terminatetetgen(1); 31952 } 31953 if (bmark) { 31954 // Allocate memory for 'trifacemarkerlist'. 31955 out->trifacemarkerlist = new int[subfaces->items]; 31956 if (out->trifacemarkerlist == (int *) NULL) { 31957 printf("Error: Out of memory.\n"); 31958 terminatetetgen(1); 31959 } 31960 } 31961 if (b->neighout > 1) { 31962 // '-nn' switch. 31963 out->adjtetlist = new int[subfaces->items * 2]; 31964 if (out->adjtetlist == (int *) NULL) { 31965 printf("Error: Out of memory.\n"); 31966 terminatetetgen(1); 31967 } 31968 } 31969 out->numberoftrifaces = subfaces->items; 31970 elist = out->trifacelist; 31971 emlist = out->trifacemarkerlist; 31972 } 31973 31974 // Determine the first index (0 or 1). 31975 firstindex = b->zeroindex ? 0 : in->firstnumber; 31976 shift = 0; // Default no shiftment. 31977 if ((in->firstnumber == 1) && (firstindex == 0)) { 31978 shift = 1; // Shift the output indices by 1. 31979 } 31980 31981 subfaces->traversalinit(); 31982 faceloop.sh = shellfacetraverse(subfaces); 31983 facenumber = firstindex; // in->firstnumber; 31984 while (faceloop.sh != (shellface *) NULL) { 31985 stpivot(faceloop, abuttingtet); 31986 if (abuttingtet.tet == dummytet) { 31987 sesymself(faceloop); 31988 stpivot(faceloop, abuttingtet); 31989 } 31990 if (abuttingtet.tet != dummytet) { 31991 // If there is a tetrahedron containing this subface, orient it so 31992 // that the normal of this face points to inside of the volume by 31993 // right-hand rule. 31994 adjustedgering(abuttingtet, CCW); 31995 torg = org(abuttingtet); 31996 tdest = dest(abuttingtet); 31997 tapex = apex(abuttingtet); 31998 } else { 31999 // This may happen when only a surface mesh be generated. 32000 torg = sorg(faceloop); 32001 tdest = sdest(faceloop); 32002 tapex = sapex(faceloop); 32003 } 32004 if (bmark) { 32005 faceid = shellmark(faceloop) - 1; 32006 marker = in->facetmarkerlist[faceid]; 32007 } 32008 if (b->neighout > 1) { 32009 // '-nn' switch. Output adjacent tets indices. 32010 neigh1 = -1; 32011 stpivot(faceloop, abuttingtet); 32012 if (abuttingtet.tet != dummytet) { 32013 neigh1 = * (int *)(abuttingtet.tet + elemmarkerindex); 32014 } 32015 neigh2 = -1; 32016 sesymself(faceloop); 32017 stpivot(faceloop, abuttingtet); 32018 if (abuttingtet.tet != dummytet) { 32019 neigh2 = * (int *)(abuttingtet.tet + elemmarkerindex); 32020 } 32021 } 32022 if (out == (tetgenio *) NULL) { 32023 fprintf(outfile, "%5d %4d %4d %4d", facenumber, 32024 pointmark(torg) - shift, pointmark(tdest) - shift, 32025 pointmark(tapex) - shift); 32026 if (bmark) { 32027 fprintf(outfile, " %d", marker); 32028 } 32029 if (b->neighout > 1) { 32030 fprintf(outfile, " %5d %5d", neigh1, neigh2); 32031 } 32032 fprintf(outfile, "\n"); 32033 } else { 32034 // Output three vertices of this face; 32035 elist[index++] = pointmark(torg) - shift; 32036 elist[index++] = pointmark(tdest) - shift; 32037 elist[index++] = pointmark(tapex) - shift; 32038 if (bmark) { 32039 emlist[index1++] = marker; 32040 } 32041 if (b->neighout > 1) { 32042 out->adjtetlist[index2++] = neigh1; 32043 out->adjtetlist[index2++] = neigh2; 32044 } 32045 } 32046 facenumber++; 32047 faceloop.sh = shellfacetraverse(subfaces); 32048 } 32049 32050 if (out == (tetgenio *) NULL) { 32051 fprintf(outfile, "# Generated by %s\n", b->commandline); 32052 fclose(outfile); 32053 } 32054 } 32055 32057 // // 32058 // outedges() Output all edges to a .edge file or a structure. // 32059 // // 32061 32062 void tetgenmesh::outedges(tetgenio* out) 32063 { 32064 FILE *outfile; 32065 char edgefilename[FILENAMESIZE]; 32066 int *elist, *emlist; 32067 int index, index1; 32068 triface tetloop, worktet, spintet; 32069 face checksh; 32070 point torg, tdest; 32071 long faces, edges; 32072 int firstindex, shift; 32073 int edgenumber, faceid, marker; 32074 int hitbdry, i; 32075 32076 if (out == (tetgenio *) NULL) { 32077 strcpy(edgefilename, b->outfilename); 32078 strcat(edgefilename, ".edge"); 32079 } 32080 32081 if (!b->quiet) { 32082 if (out == (tetgenio *) NULL) { 32083 printf("Writing %s.\n", edgefilename); 32084 } else { 32085 printf("Writing edges.\n"); 32086 } 32087 } 32088 32089 // Avoid compile warnings. 32090 outfile = (FILE *) NULL; 32091 elist = (int *) NULL; 32092 emlist = (int *) NULL; 32093 index = index1 = 0; 32094 faceid = marker = 0; 32095 32096 // Using the Euler formula (V-E+F-T=1) to get the total number of edges. 32097 faces = (4l * tetrahedrons->items + hullsize) / 2l; 32098 edges = points->items + faces - tetrahedrons->items - 1l; 32099 32100 if (out == (tetgenio *) NULL) { 32101 outfile = fopen(edgefilename, "w"); 32102 if (outfile == (FILE *) NULL) { 32103 printf("File I/O Error: Cannot create file %s.\n", edgefilename); 32104 terminatetetgen(1); 32105 } 32106 // Write the number of edges, boundary markers (0 or 1). 32107 fprintf(outfile, "%ld %d\n", edges, !b->nobound); 32108 } else { 32109 // Allocate memory for 'edgelist'. 32110 out->edgelist = new int[edges * 2]; 32111 if (out->edgelist == (int *) NULL) { 32112 printf("Error: Out of memory.\n"); 32113 terminatetetgen(1); 32114 } 32115 if (!b->nobound) { 32116 out->edgemarkerlist = new int[edges]; 32117 } 32118 out->numberofedges = edges; 32119 elist = out->edgelist; 32120 emlist = out->edgemarkerlist; 32121 } 32122 32123 // Determine the first index (0 or 1). 32124 firstindex = b->zeroindex ? 0 : in->firstnumber; 32125 shift = 0; // Default no shiftment. 32126 if ((in->firstnumber == 1) && (firstindex == 0)) { 32127 shift = 1; // Shift (reduce) the output indices by 1. 32128 } 32129 32130 tetrahedrons->traversalinit(); 32131 tetloop.tet = tetrahedrontraverse(); 32132 edgenumber = firstindex; // in->firstnumber; 32133 while (tetloop.tet != (tetrahedron *) NULL) { 32134 // Count the number of Voronoi faces. Look at the six edges of each 32135 // tetrahedron. Count the edge only if the tetrahedron's pointer is 32136 // smaller than those of all other tetrahedra that share the edge. 32137 worktet.tet = tetloop.tet; 32138 for (i = 0; i < 6; i++) { 32139 worktet.loc = edge2locver[i][0]; 32140 worktet.ver = edge2locver[i][1]; 32141 adjustedgering(worktet, CW); 32142 spintet = worktet; 32143 hitbdry = 0; 32144 while (hitbdry < 2) { 32145 if (fnextself(spintet)) { 32146 if (apex(spintet) == apex(worktet)) break; 32147 if (spintet.tet < worktet.tet) break; 32148 } else { 32149 hitbdry++; 32150 if (hitbdry < 2) { 32151 esym(worktet, spintet); 32152 fnextself(spintet); // In the same tet. 32153 } 32154 } 32155 } 32156 // Count this edge if no adjacent tets are smaller than this tet. 32157 if (spintet.tet >= worktet.tet) { 32158 torg = org(worktet); 32159 tdest = dest(worktet); 32160 if (out == (tetgenio *) NULL) { 32161 fprintf(outfile, "%5d %4d %4d", edgenumber, 32162 pointmark(torg) - shift, pointmark(tdest) - shift); 32163 } else { 32164 // Output three vertices of this face; 32165 elist[index++] = pointmark(torg) - shift; 32166 elist[index++] = pointmark(tdest) - shift; 32167 } 32168 if (!b->nobound) { 32169 if (hitbdry > 0) { 32170 // It is a boundary edge. Get the boundary marker of the facet 32171 // containing this edge. Note there may have more than one 32172 // facet, choose one arbitrarily. 32173 if ((b->plc || b->refine) && in->facetmarkerlist) { 32174 tspivot(spintet, checksh); 32175 faceid = shellmark(checksh) - 1; 32176 marker = in->facetmarkerlist[faceid]; 32177 } else { 32178 marker = 1; // Indicate it's a boundary edge. 32179 } 32180 } else { 32181 marker = 0; 32182 } 32183 if (out == (tetgenio *) NULL) { 32184 fprintf(outfile, " %d", marker); 32185 } else { 32186 emlist[index1++] = marker; 32187 } 32188 } 32189 if (out == (tetgenio *) NULL) { 32190 fprintf(outfile, "\n"); 32191 } 32192 edgenumber++; 32193 } 32194 } 32195 tetloop.tet = tetrahedrontraverse(); 32196 } 32197 32198 if (out == (tetgenio *) NULL) { 32199 fprintf(outfile, "# Generated by %s\n", b->commandline); 32200 fclose(outfile); 32201 } 32202 } 32203 32205 // // 32206 // outsubsegments() Output segments to a .edge file or a structure. // 32207 // // 32209 32210 void tetgenmesh::outsubsegments(tetgenio* out) 32211 { 32212 FILE *outfile; 32213 char edgefilename[FILENAMESIZE]; 32214 int *elist; 32215 int index; 32216 face edgeloop; 32217 point torg, tdest; 32218 int firstindex, shift; 32219 int edgenumber; 32220 32221 if (out == (tetgenio *) NULL) { 32222 strcpy(edgefilename, b->outfilename); 32223 strcat(edgefilename, ".edge"); 32224 } 32225 32226 if (!b->quiet) { 32227 if (out == (tetgenio *) NULL) { 32228 printf("Writing %s.\n", edgefilename); 32229 } else { 32230 printf("Writing edges.\n"); 32231 } 32232 } 32233 32234 // Avoid compile warnings. 32235 outfile = (FILE *) NULL; 32236 elist = (int *) NULL; 32237 index = 0; 32238 32239 if (out == (tetgenio *) NULL) { 32240 outfile = fopen(edgefilename, "w"); 32241 if (outfile == (FILE *) NULL) { 32242 printf("File I/O Error: Cannot create file %s.\n", edgefilename); 32243 terminatetetgen(1); 32244 } 32245 // Number of subsegments. 32246 fprintf(outfile, "%ld\n", subsegs->items); 32247 } else { 32248 // Allocate memory for 'edgelist'. 32249 out->edgelist = new int[subsegs->items * 2]; 32250 if (out->edgelist == (int *) NULL) { 32251 printf("Error: Out of memory.\n"); 32252 terminatetetgen(1); 32253 } 32254 out->numberofedges = subsegs->items; 32255 elist = out->edgelist; 32256 } 32257 32258 // Determine the first index (0 or 1). 32259 firstindex = b->zeroindex ? 0 : in->firstnumber; 32260 shift = 0; // Default no shiftment. 32261 if ((in->firstnumber == 1) && (firstindex == 0)) { 32262 shift = 1; // Shift the output indices by 1. 32263 } 32264 32265 subsegs->traversalinit(); 32266 edgeloop.sh = shellfacetraverse(subsegs); 32267 edgenumber = firstindex; // in->firstnumber; 32268 while (edgeloop.sh != (shellface *) NULL) { 32269 torg = sorg(edgeloop); 32270 tdest = sdest(edgeloop); 32271 if (out == (tetgenio *) NULL) { 32272 fprintf(outfile, "%5d %4d %4d\n", edgenumber, 32273 pointmark(torg) - shift, pointmark(tdest) - shift); 32274 } else { 32275 // Output three vertices of this face; 32276 elist[index++] = pointmark(torg) - shift; 32277 elist[index++] = pointmark(tdest) - shift; 32278 } 32279 edgenumber++; 32280 edgeloop.sh = shellfacetraverse(subsegs); 32281 } 32282 32283 if (out == (tetgenio *) NULL) { 32284 fprintf(outfile, "# Generated by %s\n", b->commandline); 32285 fclose(outfile); 32286 } 32287 } 32288 32290 // // 32291 // outneighbors() Output tet neighbors to a .neigh file or a structure. // 32292 // // 32294 32295 void tetgenmesh::outneighbors(tetgenio* out) 32296 { 32297 FILE *outfile; 32298 char neighborfilename[FILENAMESIZE]; 32299 int *nlist; 32300 int index; 32301 triface tetloop, tetsym; 32302 int neighbor1, neighbor2, neighbor3, neighbor4; 32303 int firstindex; 32304 int elementnumber; 32305 32306 if (out == (tetgenio *) NULL) { 32307 strcpy(neighborfilename, b->outfilename); 32308 strcat(neighborfilename, ".neigh"); 32309 } 32310 32311 if (!b->quiet) { 32312 if (out == (tetgenio *) NULL) { 32313 printf("Writing %s.\n", neighborfilename); 32314 } else { 32315 printf("Writing neighbors.\n"); 32316 } 32317 } 32318 32319 // Avoid compile warnings. 32320 outfile = (FILE *) NULL; 32321 nlist = (int *) NULL; 32322 index = 0; 32323 32324 if (out == (tetgenio *) NULL) { 32325 outfile = fopen(neighborfilename, "w"); 32326 if (outfile == (FILE *) NULL) { 32327 printf("File I/O Error: Cannot create file %s.\n", neighborfilename); 32328 terminatetetgen(1); 32329 } 32330 // Number of tetrahedra, four faces per tetrahedron. 32331 fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4); 32332 } else { 32333 // Allocate memory for 'neighborlist'. 32334 out->neighborlist = new int[tetrahedrons->items * 4]; 32335 if (out->neighborlist == (int *) NULL) { 32336 printf("Error: Out of memory.\n"); 32337 terminatetetgen(1); 32338 } 32339 nlist = out->neighborlist; 32340 } 32341 32342 // Determine the first index (0 or 1). 32343 firstindex = b->zeroindex ? 0 : in->firstnumber; 32344 32345 tetrahedrons->traversalinit(); 32346 tetloop.tet = tetrahedrontraverse(); 32347 elementnumber = firstindex; // in->firstnumber; 32348 while (tetloop.tet != (tetrahedron *) NULL) { 32349 tetloop.loc = 2; 32350 sym(tetloop, tetsym); 32351 neighbor1 = * (int *) (tetsym.tet + elemmarkerindex); 32352 tetloop.loc = 3; 32353 sym(tetloop, tetsym); 32354 neighbor2 = * (int *) (tetsym.tet + elemmarkerindex); 32355 tetloop.loc = 1; 32356 sym(tetloop, tetsym); 32357 neighbor3 = * (int *) (tetsym.tet + elemmarkerindex); 32358 tetloop.loc = 0; 32359 sym(tetloop, tetsym); 32360 neighbor4 = * (int *) (tetsym.tet + elemmarkerindex); 32361 if (out == (tetgenio *) NULL) { 32362 // Tetrahedra number, neighboring tetrahedron numbers. 32363 fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber, 32364 neighbor1, neighbor2, neighbor3, neighbor4); 32365 } else { 32366 nlist[index++] = neighbor1; 32367 nlist[index++] = neighbor2; 32368 nlist[index++] = neighbor3; 32369 nlist[index++] = neighbor4; 32370 } 32371 tetloop.tet = tetrahedrontraverse(); 32372 elementnumber++; 32373 } 32374 32375 if (out == (tetgenio *) NULL) { 32376 fprintf(outfile, "# Generated by %s\n", b->commandline); 32377 fclose(outfile); 32378 } 32379 } 32380 32382 // // 32383 // outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, // 32384 // and .v.cell. // 32385 // // 32386 // The Voronoi diagram is the geometric dual of the Delaunay triangulation. // 32387 // The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each // 32388 // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- // 32389 // unay face. At a face of convex hull, it becomes a ray (goto the infinity).// 32390 // A Voronoi face is the convex hull of all Voronoi vertices around a common // 32391 // Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a // 32392 // ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- // 32393 // onoi vertices around a common Delaunay vertex. It is a polytope for any // 32394 // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay // 32395 // vertex belonging to the convex hull. // 32396 // // 32398 32399 void tetgenmesh::outvoronoi(tetgenio* out) 32400 { 32401 FILE *outfile; 32402 char outfilename[FILENAMESIZE]; 32403 tetgenio::voroedge *vedge; 32404 tetgenio::vorofacet *vfacet; 32405 list *tetlist, *ptlist; 32406 triface tetloop, worktet, spintet; 32407 point pt[4], ptloop, neipt; 32408 REAL ccent[3], infvec[3], vec1[3], vec2[3], L; 32409 long faces, edges; 32410 int *tetfaceindexarray, *tetedgeindexarray; 32411 int arraysize, *vertarray; 32412 int vpointcount, vedgecount, vfacecount, tcount; 32413 int index, shift; 32414 int end1, end2; 32415 int hitbdry, i, j, k; 32416 32417 vedge = NULL; 32418 vertarray = NULL; 32419 vfacet = NULL; 32420 k = 0; 32421 32422 // Output Voronoi vertices to .v.node file. 32423 if (out == (tetgenio *) NULL) { 32424 strcpy(outfilename, b->outfilename); 32425 strcat(outfilename, ".v.node"); 32426 } 32427 32428 if (!b->quiet) { 32429 if (out == (tetgenio *) NULL) { 32430 printf("Writing %s.\n", outfilename); 32431 } else { 32432 printf("Writing Voronoi vertices.\n"); 32433 } 32434 } 32435 32436 // Determine the first index (0 or 1). 32437 shift = (b->zeroindex ? 0 : in->firstnumber); 32438 // The number of Delaunay faces (= the number of Voronoi edges). 32439 faces = (4l * tetrahedrons->items + hullsize) / 2l; 32440 // The number of Delaunay edges (= the number of Voronoi faces). 32441 edges = points->items + faces - tetrahedrons->items - 1; 32442 outfile = (FILE *) NULL; // Avoid compile warnings. 32443 32444 if (out == (tetgenio *) NULL) { 32445 outfile = fopen(outfilename, "w"); 32446 if (outfile == (FILE *) NULL) { 32447 printf("File I/O Error: Cannot create file %s.\n", outfilename); 32448 terminatetetgen(1); 32449 } 32450 // Number of voronoi points, 3 dim, no attributes, no marker. 32451 fprintf(outfile, "%ld 3 0 0\n", tetrahedrons->items); 32452 } else { 32453 // Allocate space for 'vpointlist'. 32454 out->numberofvpoints = (int) tetrahedrons->items; 32455 out->vpointlist = new REAL[out->numberofvpoints * 3]; 32456 if (out->vpointlist == (REAL *) NULL) { 32457 printf("Error: Out of memory.\n"); 32458 terminatetetgen(1); 32459 } 32460 } 32461 32462 // Loop the tetrahedronlist once, do the following: 32463 // (1) Output Voronoi vertices (the circumcenter of the tetrahedron). 32464 // (2) Make a map from points-to-tetrahedra (for Voronoi cells). 32465 tetrahedrons->traversalinit(); 32466 tetloop.tet = tetrahedrontraverse(); 32467 vpointcount = 0; 32468 index = 0; 32469 while (tetloop.tet != (tetrahedron *) NULL) { 32470 // Calculate the circumcenter. 32471 for (i = 0; i < 4; i++) { 32472 pt[i] = (point) tetloop.tet[4 + i]; 32473 setpoint2tet(pt[i], encode(tetloop)); 32474 } 32475 circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL); 32476 if (out == (tetgenio *) NULL) { 32477 fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift, 32478 ccent[0], ccent[1], ccent[2]); 32479 } else { 32480 out->vpointlist[index++] = ccent[0]; 32481 out->vpointlist[index++] = ccent[1]; 32482 out->vpointlist[index++] = ccent[2]; 32483 } 32484 // Remember the index of this element. 32485 * (int *) (tetloop.tet + elemmarkerindex) = vpointcount; 32486 vpointcount++; 32487 tetloop.tet = tetrahedrontraverse(); 32488 } 32489 // Set the outside element marker. 32490 * (int *) (dummytet + elemmarkerindex) = -1; 32491 32492 if (out == (tetgenio *) NULL) { 32493 fprintf(outfile, "# Generated by %s\n", b->commandline); 32494 fclose(outfile); 32495 } 32496 32497 // Output Voronoi edges to .v.edge file. 32498 if (out == (tetgenio *) NULL) { 32499 strcpy(outfilename, b->outfilename); 32500 strcat(outfilename, ".v.edge"); 32501 } 32502 32503 if (!b->quiet) { 32504 if (out == (tetgenio *) NULL) { 32505 printf("Writing %s.\n", outfilename); 32506 } else { 32507 printf("Writing Voronoi edges.\n"); 32508 } 32509 } 32510 32511 if (out == (tetgenio *) NULL) { 32512 outfile = fopen(outfilename, "w"); 32513 if (outfile == (FILE *) NULL) { 32514 printf("File I/O Error: Cannot create file %s.\n", outfilename); 32515 terminatetetgen(1); 32516 } 32517 // Number of Voronoi edges, no marker. 32518 fprintf(outfile, "%ld 0\n", faces); 32519 } else { 32520 // Allocate space for 'vpointlist'. 32521 out->numberofedges = (int) faces; 32522 out->vedgelist = new tetgenio::voroedge[out->numberofvedges]; 32523 } 32524 32525 // Loop the tetrahedronlist once, output the Voronoi edges. The index of 32526 // each Voronoi edge corresponding to the index of the Delaunay face. 32527 // The four faces' indices of each tetrahedron are saved in the list 32528 // 'tetfaceindexarray', in the entry of i, where i (0-based) is the 32529 // index of this tetrahedron (= vpointcount). 32530 tetfaceindexarray = new int[tetrahedrons->items * 4]; 32531 tetrahedrons->traversalinit(); 32532 tetloop.tet = tetrahedrontraverse(); 32533 vedgecount = 0; 32534 index = 0; 32535 while (tetloop.tet != (tetrahedron *) NULL) { 32536 // Count the number of Voronoi edges. Look at the four faces of each 32537 // tetrahedron. Count the face if the tetrahedron's pointer is 32538 // smaller than its neighbor's or the neighbor is outside. 32539 end1 = * (int *) (tetloop.tet + elemmarkerindex); 32540 for (i = 0; i < 4; i++) { 32541 decode(tetloop.tet[i], worktet); 32542 if ((worktet.tet == dummytet) || (tetloop.tet < worktet.tet)) { 32543 if (out == (tetgenio *) NULL) { 32544 fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift); 32545 } else { 32546 vedge = &(out->vedgelist[index++]); 32547 vedge->v1 = end1 + shift; 32548 } 32549 end2 = * (int *) (worktet.tet + elemmarkerindex); 32550 // Note that end2 may be -1 (worktet.tet is outside). 32551 if (end2 == -1) { 32552 // Calculate the out normal of this hull face. 32553 worktet.tet = tetloop.tet; 32554 worktet.loc = i; 32555 worktet.ver = 1; // The CW edge ring. 32556 pt[0] = org(worktet); 32557 pt[1] = dest(worktet); 32558 pt[2] = apex(worktet); 32559 for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j]; 32560 for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j]; 32561 cross(vec1, vec2, infvec); 32562 // Normalize it. 32563 L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1] 32564 + infvec[2] * infvec[2]); 32565 if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L; 32566 if (out == (tetgenio *) NULL) { 32567 fprintf(outfile, " -1"); 32568 fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]); 32569 } else { 32570 vedge->v2 = -1; 32571 vedge->vnormal[0] = infvec[0]; 32572 vedge->vnormal[1] = infvec[1]; 32573 vedge->vnormal[2] = infvec[2]; 32574 } 32575 } else { 32576 if (out == (tetgenio *) NULL) { 32577 fprintf(outfile, " %4d\n", end2 + shift); 32578 } else { 32579 vedge->v2 = end2 + shift; 32580 vedge->vnormal[0] = 0.0; 32581 vedge->vnormal[1] = 0.0; 32582 vedge->vnormal[2] = 0.0; 32583 } 32584 } 32585 // Save the face index in this tet and its neighbor if exists. 32586 tetfaceindexarray[end1 * 4 + i] = vedgecount; 32587 if (end2 != -1) { 32588 tetfaceindexarray[end2 * 4 + worktet.loc] = vedgecount; 32589 } 32590 vedgecount++; 32591 } 32592 } 32593 tetloop.tet = tetrahedrontraverse(); 32594 } 32595 32596 if (out == (tetgenio *) NULL) { 32597 fprintf(outfile, "# Generated by %s\n", b->commandline); 32598 fclose(outfile); 32599 } 32600 32601 // Output Voronoi faces to .v.face file. 32602 if (out == (tetgenio *) NULL) { 32603 strcpy(outfilename, b->outfilename); 32604 strcat(outfilename, ".v.face"); 32605 } 32606 32607 if (!b->quiet) { 32608 if (out == (tetgenio *) NULL) { 32609 printf("Writing %s.\n", outfilename); 32610 } else { 32611 printf("Writing Voronoi faces.\n"); 32612 } 32613 } 32614 32615 if (out == (tetgenio *) NULL) { 32616 outfile = fopen(outfilename, "w"); 32617 if (outfile == (FILE *) NULL) { 32618 printf("File I/O Error: Cannot create file %s.\n", outfilename); 32619 terminatetetgen(1); 32620 } 32621 // Number of Voronoi faces. 32622 fprintf(outfile, "%ld 0\n", edges); 32623 } else { 32624 out->numberofvfacets = edges; 32625 out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets]; 32626 if (out->vfacetlist == (tetgenio::vorofacet *) NULL) { 32627 printf("Error: Out of memory.\n"); 32628 terminatetetgen(1); 32629 } 32630 } 32631 32632 // Loop the tetrahedronlist once, Output Voronoi facets. The index of each 32633 // Voronoi facet corresponding to the index of the Delaunay edge. The 32634 // six edges' indices of each tetrahedron are saved in the list 'tetedge- 32635 // indexarray', in the entry of i, where i (0-based) is the index of 32636 // this tetrahedron (= vpointcount). 32637 tetedgeindexarray = new int[tetrahedrons->items * 6]; 32638 tetrahedrons->traversalinit(); 32639 tetloop.tet = tetrahedrontraverse(); 32640 vfacecount = 0; 32641 while (tetloop.tet != (tetrahedron *) NULL) { 32642 // Count the number of Voronoi faces. Look at the six edges of each 32643 // tetrahedron. Count the edge only if the tetrahedron's pointer is 32644 // smaller than those of all other tetrahedra that share the edge. 32645 worktet = tetloop; 32646 for (i = 0; i < 6; i++) { 32647 worktet.loc = edge2locver[i][0]; 32648 worktet.ver = edge2locver[i][1]; 32649 // Now count the number of tets surrounding this edge. 32650 tcount = 1; 32651 adjustedgering(worktet, CW); 32652 spintet = worktet; 32653 hitbdry = 0; 32654 while (hitbdry < 2) { 32655 if (fnextself(spintet)) { 32656 if (apex(spintet) == apex(worktet)) break; 32657 if (spintet.tet < worktet.tet) break; 32658 tcount++; 32659 } else { 32660 hitbdry++; 32661 if (hitbdry < 2) { 32662 esym(worktet, spintet); 32663 fnextself(spintet); // In the same tet. 32664 } 32665 } 32666 } 32667 // Count this edge if no adjacent tets are smaller than this tet. 32668 if (spintet.tet >= worktet.tet) { 32669 // Get the two endpoints of this edge. 32670 pt[0] = org(worktet); 32671 pt[1] = dest(worktet); 32672 end1 = pointmark(pt[0]) - in->firstnumber; 32673 end2 = pointmark(pt[1]) - in->firstnumber; 32674 if (out == (tetgenio *) NULL) { 32675 fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift, 32676 end1 + shift, end2 + shift, tcount + (hitbdry > 0)); 32677 } else { 32678 vfacet = &(out->vfacetlist[vfacecount]); 32679 vfacet->c1 = end1 + shift; 32680 vfacet->c2 = end2 + shift; 32681 vfacet->elist = new int[tcount + (hitbdry > 0) + 1]; 32682 vfacet->elist[0] = tcount + (hitbdry > 0); 32683 index = 1; 32684 } 32685 // If hitbdry > 0, then spintet is a hull face. 32686 if (hitbdry > 0) { 32687 // The edge list starts with a ray. 32688 vpointcount = * (int *) (spintet.tet + elemmarkerindex); 32689 vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc]; 32690 if (out == (tetgenio *) NULL) { 32691 fprintf(outfile, " %d", vedgecount + shift); 32692 } else { 32693 vfacet->elist[index++] = vedgecount + shift; 32694 } 32695 // Save this facet number in tet. 32696 tetedgeindexarray[vpointcount * 6 + 32697 locver2edge[spintet.loc][spintet.ver]] = vfacecount; 32698 esymself(spintet); 32699 fnextself(spintet); // In the same tet. 32700 } 32701 // Output internal Voronoi edges. 32702 for (j = 0; j < tcount; j++) { 32703 vpointcount = * (int *) (spintet.tet + elemmarkerindex); 32704 vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc]; 32705 if (out == (tetgenio *) NULL) { 32706 fprintf(outfile, " %d", vedgecount + shift); 32707 } else { 32708 vfacet->elist[index++] = vedgecount + shift; 32709 } 32710 // Save this facet number in tet. 32711 tetedgeindexarray[vpointcount * 6 + 32712 locver2edge[spintet.loc][spintet.ver]] = vfacecount; 32713 fnextself(spintet); 32714 } 32715 if (out == (tetgenio *) NULL) { 32716 fprintf(outfile, "\n"); 32717 } 32718 vfacecount++; 32719 } 32720 } // if (i = 0; i < 6; i++) 32721 tetloop.tet = tetrahedrontraverse(); 32722 } 32723 32724 if (out == (tetgenio *) NULL) { 32725 fprintf(outfile, "# Generated by %s\n", b->commandline); 32726 fclose(outfile); 32727 } 32728 32729 // Output Voronoi cells to .v.cell file. 32730 if (out == (tetgenio *) NULL) { 32731 strcpy(outfilename, b->outfilename); 32732 strcat(outfilename, ".v.cell"); 32733 } 32734 32735 if (!b->quiet) { 32736 if (out == (tetgenio *) NULL) { 32737 printf("Writing %s.\n", outfilename); 32738 } else { 32739 printf("Writing Voronoi cells.\n"); 32740 } 32741 } 32742 32743 if (out == (tetgenio *) NULL) { 32744 outfile = fopen(outfilename, "w"); 32745 if (outfile == (FILE *) NULL) { 32746 printf("File I/O Error: Cannot create file %s.\n", outfilename); 32747 terminatetetgen(1); 32748 } 32749 // Number of Voronoi cells. 32750 fprintf(outfile, "%ld\n", points->items); 32751 } else { 32752 out->numberofvcells = points->items; 32753 out->vcelllist = new int*[out->numberofvcells]; 32754 if (out->vcelllist == (int **) NULL) { 32755 printf("Error: Out of memory.\n"); 32756 terminatetetgen(1); 32757 } 32758 } 32759 32760 // Loop through point list, for each point, output a Voronoi cell. 32761 tetlist = new list(sizeof(triface), NULL, 256); 32762 ptlist = new list(sizeof(point *), NULL, 256); 32763 points->traversalinit(); 32764 ptloop = pointtraverse(); 32765 vpointcount = 0; 32766 while (ptloop != (point) NULL) { 32767 decode(point2tet(ptloop), tetloop); 32768 // assert(!isdead(&tetloop)); 32769 if (!isdead(&tetloop)) { 32770 // Form the star of p. 32771 tetlist->append(&tetloop); 32772 formstarpolyhedron(ptloop, tetlist, ptlist, true); 32773 tcount = ptlist->len(); 32774 if (out == (tetgenio *) NULL) { 32775 fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount); 32776 } else { 32777 arraysize = tcount; 32778 vertarray = out->vcelllist[vpointcount]; 32779 vertarray = new int[arraysize + 1]; 32780 vertarray[0] = arraysize; 32781 index = 1; 32782 } 32783 // List Voronoi facets bounding this cell. 32784 for (i = 0; i < ptlist->len(); i++) { 32785 neipt = * (point *)(* ptlist)[i]; 32786 // Find a tet in tetlist having edge (ptloop, neipt) -- Very Slow. 32787 for (j = 0; j < tetlist->len(); j++) { 32788 tetloop = * (triface *)(* tetlist)[j]; 32789 for (k = 0; k < 6; k++) { 32790 tetloop.loc = edge2locver[k][0]; 32791 tetloop.ver = edge2locver[k][1]; 32792 if (org(tetloop) == ptloop) { 32793 if (dest(tetloop) == neipt) break; 32794 } else if (org(tetloop) == neipt) { 32795 if (dest(tetloop) == ptloop) break; 32796 } 32797 } 32798 if (k < 6) break; // Found this edge. 32799 } 32800 assert(j < tetlist->len()); 32801 // k is the right edge number. 32802 end1 = * (int *) (tetloop.tet + elemmarkerindex); 32803 vfacecount = tetedgeindexarray[end1 * 6 + k]; 32804 if (out == (tetgenio *) NULL) { 32805 fprintf(outfile, " %d", vfacecount + shift); 32806 } else { 32807 vertarray[index++] = vfacecount + shift; 32808 } 32809 } // for (i = 0; i < ptlist->len(); i++) { 32810 if (out == (tetgenio *) NULL) { 32811 fprintf(outfile, "\n"); 32812 } 32813 vpointcount++; 32814 } 32815 tetlist->clear(); 32816 ptlist->clear(); 32817 ptloop = pointtraverse(); 32818 } 32819 delete tetlist; 32820 delete ptlist; 32821 delete [] tetfaceindexarray; 32822 delete [] tetedgeindexarray; 32823 32824 if (out == (tetgenio *) NULL) { 32825 fprintf(outfile, "# Generated by %s\n", b->commandline); 32826 fclose(outfile); 32827 } 32828 } 32829 32831 // // 32832 // outpbcnodes() Output pbc node pairs to a .pbc file or a structure. // 32833 // // 32835 32836 void tetgenmesh::outpbcnodes(tetgenio* out) 32837 { 32838 FILE *outfile; 32839 char pbcfilename[FILENAMESIZE]; 32840 list *ptpairlist; 32841 tetgenio::pbcgroup *pgi, *pgo; 32842 pbcdata *pd; 32843 face faceloop; 32844 face checkseg, symseg; 32845 point *ptpair, pa, pb; 32846 enum locateresult loc; 32847 REAL sympt[3], d1, d2; 32848 int *worklist; 32849 int firstindex, shift; 32850 int index, idx; 32851 int i, j, k, l; 32852 32853 if (out == (tetgenio *) NULL) { 32854 strcpy(pbcfilename, b->outfilename); 32855 strcat(pbcfilename, ".pbc"); 32856 } 32857 32858 if (!b->quiet) { 32859 if (out == (tetgenio *) NULL) { 32860 printf("Writing %s.\n", pbcfilename); 32861 } else { 32862 printf("Writing pbc nodes.\n"); 32863 } 32864 } 32865 32866 // Avoid compilation warnings. 32867 outfile = (FILE *) NULL; 32868 pgo = (tetgenio::pbcgroup *) NULL; 32869 index = 0; 32870 32871 if (out == (tetgenio *) NULL) { 32872 outfile = fopen(pbcfilename, "w"); 32873 if (outfile == (FILE *) NULL) { 32874 printf("File I/O Error: Cannot create file %s.\n", pbcfilename); 32875 terminatetetgen(1); 32876 } 32877 // Number of pbc groups. 32878 fprintf(outfile, "# number of PBCs.\n"); 32879 fprintf(outfile, "%d\n\n", in->numberofpbcgroups); 32880 } else { 32881 out->numberofpbcgroups = in->numberofpbcgroups; 32882 // Allocate memory for 'out->pbcgrouplist'. 32883 out->pbcgrouplist = new tetgenio::pbcgroup[in->numberofpbcgroups]; 32884 // (Next line was a bug, reported by Murry Nigel). 32885 if (out->pbcgrouplist == (tetgenio::pbcgroup *) NULL) { 32886 printf("Error: Out of memory.\n"); 32887 terminatetetgen(1); 32888 } 32889 } 32890 32891 ptpairlist = new list(2 * sizeof(point *), NULL, 256); 32892 worklist = new int[points->items + 1]; 32893 for (i = 0; i < points->items + 1; i++) worklist[i] = 0; 32894 32895 // Determine the first index (0 or 1). 32896 firstindex = b->zeroindex ? 0 : in->firstnumber; 32897 shift = 0; // Default no shiftment. 32898 if ((in->firstnumber == 1) && (firstindex == 0)) { 32899 shift = 1; // Shift the output indices by 1. 32900 } 32901 32902 for (i = 0; i < in->numberofpbcgroups; i++) { 32903 // Group i. 32904 pgi = &(in->pbcgrouplist[i]); 32905 if (out == (tetgenio *) NULL) { 32906 fprintf(outfile, "# PBC %d\n", in->firstnumber + i); 32907 // Output facet markers. 32908 fprintf(outfile, "%d %d\n", pgi->fmark1, pgi->fmark2); 32909 // Output transformation matrix. 32910 fprintf(outfile, "[\n"); 32911 for (j = 0; j < 4; j++) { 32912 fprintf(outfile, " %.12g %.12g %.12g %.12g\n", pgi->transmat[j][0], 32913 pgi->transmat[j][1], pgi->transmat[j][2], pgi->transmat[j][3]); 32914 } 32915 fprintf(outfile, "]\n"); 32916 } else { 32917 pgo = &(out->pbcgrouplist[i]); 32918 // Copy data from pgi to pgo. 32919 pgo->fmark1 = pgi->fmark1; 32920 pgo->fmark2 = pgi->fmark2; 32921 for (j = 0; j < 4; j++) { 32922 for (k = 0; k < 4; k++) pgo->transmat[j][k] = pgi->transmat[j][k]; 32923 } 32924 } 32925 32926 // Find the point pairs of group i. 32927 subfaces->traversalinit(); 32928 faceloop.sh = shellfacetraverse(subfaces); 32929 while (faceloop.sh != (shellface *) NULL) { 32930 if (shellpbcgroup(faceloop) == i) { 32931 // It is in group i. Operate on it if it has pgi->fmark1. 32932 idx = shellmark(faceloop) - 1; 32933 if (in->facetmarkerlist[idx] == pgi->fmark1) { 32934 // Loop three edges of the subface. 32935 for (j = 0; j < 3; j++) { 32936 sspivot(faceloop, checkseg); 32937 // Loop two vertices of the edge. 32938 for (k = 0; k < 2; k++) { 32939 if (k == 0) pa = sorg(faceloop); 32940 else pa = sdest(faceloop); 32941 if (worklist[pointmark(pa)] == 0) { 32942 pb = (point) NULL; 32943 if (checkseg.sh != dummysh) { 32944 // pa is on a segment. Find pb. 32945 // Find the incident pbcgroup of checkseg. 32946 idx = shellmark(checkseg) - 1; 32947 for (l = idx2segpglist[idx]; l < idx2segpglist[idx + 1]; 32948 l++) { 32949 pd = (pbcdata *)(* segpbcgrouptable)[segpglist[l]]; 32950 if (((pd->fmark[0] == pgi->fmark1) && 32951 (pd->fmark[1] == pgi->fmark2)) || 32952 ((pd->fmark[0] == pgi->fmark2) && 32953 (pd->fmark[1] == pgi->fmark1))) break; 32954 } 32955 #ifdef SELF_CHECK 32956 assert(l < idx2segpglist[idx + 1]); 32957 #endif 32958 loc = getsegpbcsympoint(pa, &checkseg, sympt, &symseg, 32959 segpglist[l]); 32960 if (loc != ONVERTEX) { 32961 // Not found a match point! It may be caused by the 32962 // pair of input vertices don't have enough digits. 32963 // Choose a near vertex. 32964 d1 = distance(sympt, sorg(symseg)); 32965 d2 = distance(sympt, sdest(symseg)); 32966 if (d1 > d2) sesymself(symseg); 32967 } 32968 pb = sorg(symseg); 32969 } else { 32970 // Operate on pa if it is inside the facet. 32971 if (pointtype(pa) == FREESUBVERTEX) { 32972 pb = point2pbcpt(pa); 32973 } 32974 } 32975 if (pb != (point) NULL) { 32976 // Add the pair (pa, pb) into list. 32977 ptpair = (point *) ptpairlist->append(NULL); 32978 ptpair[0] = pa; 32979 ptpair[1] = pb; 32980 // Mark pa (avoid to operate on it later). 32981 worklist[pointmark(pa)] = 1; 32982 } 32983 } 32984 } 32985 // Get the next edge. 32986 senextself(faceloop); 32987 } 32988 } 32989 } 32990 faceloop.sh = shellfacetraverse(subfaces); 32991 } 32992 32993 // Output the list of pbc points. 32994 if (out == (tetgenio *) NULL) { 32995 fprintf(outfile, "%d\n", ptpairlist->len()); 32996 } else { 32997 pgo->numberofpointpairs = ptpairlist->len(); 32998 pgo->pointpairlist = new int[pgo->numberofpointpairs * 2]; 32999 index = 0; 33000 } 33001 for (j = 0; j < ptpairlist->len(); j++) { 33002 ptpair = (point *)(* ptpairlist)[j]; 33003 pa = ptpair[0]; 33004 pb = ptpair[1]; 33005 if (out == (tetgenio *) NULL) { 33006 fprintf(outfile, " %4d %4d\n", pointmark(pa) - shift, 33007 pointmark(pb) - shift); 33008 } else { 33009 pgo->pointpairlist[index++] = pointmark(pa) - shift; 33010 pgo->pointpairlist[index++] = pointmark(pb) - shift; 33011 } 33012 // Unmark pa. 33013 worklist[pointmark(pa)] = 0; 33014 } 33015 if (out == (tetgenio *) NULL) { 33016 fprintf(outfile, "\n"); 33017 } 33018 ptpairlist->clear(); 33019 } 33020 33021 delete [] worklist; 33022 delete ptpairlist; 33023 33024 if (out == (tetgenio *) NULL) { 33025 fprintf(outfile, "# Generated by %s\n", b->commandline); 33026 fclose(outfile); 33027 } 33028 } 33029 33031 // // 33032 // outsmesh() Write surface mesh to a .smesh file, which can be read and // 33033 // tetrahedralized by TetGen. // 33034 // // 33035 // You can specify a filename (without suffix) in 'smfilename'. If you don't // 33036 // supply a filename (let smfilename be NULL), the default name stored in // 33037 // 'tetgenbehavior' will be used. // 33038 // // 33040 33041 void tetgenmesh::outsmesh(char* smfilename) 33042 { 33043 FILE *outfile; 33044 char nodfilename[FILENAMESIZE]; 33045 char smefilename[FILENAMESIZE]; 33046 face faceloop; 33047 point p1, p2, p3; 33048 int firstindex, shift; 33049 int bmark; 33050 int faceid, marker; 33051 int i; 33052 33053 if (smfilename != (char *) NULL && smfilename[0] != '\0') { 33054 strcpy(smefilename, smfilename); 33055 } else if (b->outfilename[0] != '\0') { 33056 strcpy(smefilename, b->outfilename); 33057 } else { 33058 strcpy(smefilename, "unnamed"); 33059 } 33060 strcpy(nodfilename, smefilename); 33061 strcat(smefilename, ".smesh"); 33062 strcat(nodfilename, ".node"); 33063 33064 if (!b->quiet) { 33065 printf("Writing %s.\n", smefilename); 33066 } 33067 outfile = fopen(smefilename, "w"); 33068 if (outfile == (FILE *) NULL) { 33069 printf("File I/O Error: Cannot create file %s.\n", smefilename); 33070 return; 33071 } 33072 33073 // Determine the first index (0 or 1). 33074 firstindex = b->zeroindex ? 0 : in->firstnumber; 33075 shift = 0; // Default no shiftment. 33076 if ((in->firstnumber == 1) && (firstindex == 0)) { 33077 shift = 1; // Shift the output indices by 1. 33078 } 33079 33080 fprintf(outfile, "# %s. TetGen's input file.\n", smefilename); 33081 fprintf(outfile, "\n# part 1: node list.\n"); 33082 fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename); 33083 33084 marker = 0; // avoid compile warning. 33085 bmark = !b->nobound && in->facetmarkerlist; 33086 33087 fprintf(outfile, "\n# part 2: facet list.\n"); 33088 // Number of facets, boundary marker. 33089 fprintf(outfile, "%ld %d\n", subfaces->items, bmark); 33090 33091 subfaces->traversalinit(); 33092 faceloop.sh = shellfacetraverse(subfaces); 33093 while (faceloop.sh != (shellface *) NULL) { 33094 p1 = sorg(faceloop); 33095 p2 = sdest(faceloop); 33096 p3 = sapex(faceloop); 33097 if (bmark) { 33098 faceid = shellmark(faceloop) - 1; 33099 if (faceid >= 0) { 33100 marker = in->facetmarkerlist[faceid]; 33101 } else { 33102 marker = 0; // This subface must be added manually later. 33103 } 33104 } 33105 fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift, 33106 pointmark(p2) - shift, pointmark(p3) - shift); 33107 if (bmark) { 33108 fprintf(outfile, " %d", marker); 33109 } 33110 fprintf(outfile, "\n"); 33111 faceloop.sh = shellfacetraverse(subfaces); 33112 } 33113 33114 // Copy input holelist. 33115 fprintf(outfile, "\n# part 3: hole list.\n"); 33116 fprintf(outfile, "%d\n", in->numberofholes); 33117 for (i = 0; i < in->numberofholes; i++) { 33118 fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber, 33119 in->holelist[i * 3], in->holelist[i * 3 + 1], 33120 in->holelist[i * 3 + 2]); 33121 } 33122 33123 // Copy input regionlist. 33124 fprintf(outfile, "\n# part 4: region list.\n"); 33125 fprintf(outfile, "%d\n", in->numberofregions); 33126 for (i = 0; i < in->numberofregions; i++) { 33127 fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber, 33128 in->regionlist[i * 5], in->regionlist[i * 5 + 1], 33129 in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3], 33130 in->regionlist[i * 5 + 4]); 33131 } 33132 33133 fprintf(outfile, "# Generated by %s\n", b->commandline); 33134 fclose(outfile); 33135 } 33136 33138 // // 33139 // outmesh2medit() Write mesh to a .mesh file, which can be read and // 33140 // rendered by Medit (a free mesh viewer from INRIA). // 33141 // // 33142 // You can specify a filename (without suffix) in 'mfilename'. If you don't // 33143 // supply a filename (let mfilename be NULL), the default name stored in // 33144 // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.// 33145 // // 33147 33148 void tetgenmesh::outmesh2medit(char* mfilename) 33149 { 33150 FILE *outfile; 33151 char mefilename[FILENAMESIZE]; 33152 tetrahedron* tetptr; 33153 triface tface, tsymface; 33154 face segloop, checkmark; 33155 point ptloop, p1, p2, p3, p4; 33156 long faces; 33157 int pointnumber; 33158 int i; 33159 33160 if (mfilename != (char *) NULL && mfilename[0] != '\0') { 33161 strcpy(mefilename, mfilename); 33162 } else if (b->outfilename[0] != '\0') { 33163 strcpy(mefilename, b->outfilename); 33164 } else { 33165 strcpy(mefilename, "unnamed"); 33166 } 33167 strcat(mefilename, ".mesh"); 33168 33169 if (!b->quiet) { 33170 printf("Writing %s.\n", mefilename); 33171 } 33172 outfile = fopen(mefilename, "w"); 33173 if (outfile == (FILE *) NULL) { 33174 printf("File I/O Error: Cannot create file %s.\n", mefilename); 33175 return; 33176 } 33177 33178 fprintf(outfile, "MeshVersionFormatted 1\n"); 33179 fprintf(outfile, "\n"); 33180 fprintf(outfile, "Dimension\n"); 33181 fprintf(outfile, "3\n"); 33182 fprintf(outfile, "\n"); 33183 33184 fprintf(outfile, "\n# Set of mesh vertices\n"); 33185 fprintf(outfile, "Vertices\n"); 33186 fprintf(outfile, "%ld\n", points->items); 33187 33188 points->traversalinit(); 33189 ptloop = pointtraverse(); 33190 pointnumber = 1; // Medit need start number form 1. 33191 while (ptloop != (point) NULL) { 33192 // Point coordinates. 33193 fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]); 33194 if (in->numberofpointattributes > 0) { 33195 // Write an attribute, ignore others if more than one. 33196 fprintf(outfile, " %.17g\n", ptloop[3]); 33197 } else { 33198 fprintf(outfile, " 0\n"); 33199 } 33200 setpointmark(ptloop, pointnumber); 33201 ptloop = pointtraverse(); 33202 pointnumber++; 33203 } 33204 33205 // Compute the number of edges. 33206 faces = (4l * tetrahedrons->items + hullsize) / 2l; 33207 33208 fprintf(outfile, "\n# Set of Triangles\n"); 33209 fprintf(outfile, "Triangles\n"); 33210 fprintf(outfile, "%ld\n", faces); 33211 33212 tetrahedrons->traversalinit(); 33213 tface.tet = tetrahedrontraverse(); 33214 // To loop over the set of faces, loop over all tetrahedra, and look at 33215 // the four faces of each tetrahedron. If there isn't another tetrahedron 33216 // adjacent to the face, operate on the face. If there is another adj- 33217 // acent tetrahedron, operate on the face only if the current tetrahedron 33218 // has a smaller pointer than its neighbor. This way, each face is 33219 // considered only once. 33220 while (tface.tet != (tetrahedron *) NULL) { 33221 for (tface.loc = 0; tface.loc < 4; tface.loc ++) { 33222 sym(tface, tsymface); 33223 if (tface.tet < tsymface.tet || tsymface.tet == dummytet) { 33224 p1 = org (tface); 33225 p2 = dest(tface); 33226 p3 = apex(tface); 33227 fprintf(outfile, "%5d %5d %5d", 33228 pointmark(p1), pointmark(p2), pointmark(p3)); 33229 fprintf(outfile, " 0\n"); 33230 } 33231 } 33232 tface.tet = tetrahedrontraverse(); 33233 } 33234 33235 fprintf(outfile, "\n# Set of Tetrahedra\n"); 33236 fprintf(outfile, "Tetrahedra\n"); 33237 fprintf(outfile, "%ld\n", tetrahedrons->items); 33238 33239 tetrahedrons->traversalinit(); 33240 tetptr = tetrahedrontraverse(); 33241 while (tetptr != (tetrahedron *) NULL) { 33242 p1 = (point) tetptr[4]; 33243 p2 = (point) tetptr[5]; 33244 p3 = (point) tetptr[6]; 33245 p4 = (point) tetptr[7]; 33246 fprintf(outfile, "%5d %5d %5d %5d", 33247 pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); 33248 if (in->numberoftetrahedronattributes > 0) { 33249 fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); 33250 } else { 33251 fprintf(outfile, " 0"); 33252 } 33253 fprintf(outfile, "\n"); 33254 tetptr = tetrahedrontraverse(); 33255 } 33256 33257 fprintf(outfile, "\nCorners\n"); 33258 fprintf(outfile, "%d\n", in->numberofpoints); 33259 33260 for (i = 0; i < in->numberofpoints; i++) { 33261 fprintf(outfile, "%4d\n", i + 1); 33262 } 33263 33264 if (b->useshelles) { 33265 fprintf(outfile, "\nEdges\n"); 33266 fprintf(outfile, "%ld\n", subsegs->items); 33267 33268 subsegs->traversalinit(); 33269 segloop.sh = shellfacetraverse(subsegs); 33270 while (segloop.sh != (shellface *) NULL) { 33271 p1 = sorg(segloop); 33272 p2 = sdest(segloop); 33273 fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2)); 33274 fprintf(outfile, " 0\n"); 33275 segloop.sh = shellfacetraverse(subsegs); 33276 } 33277 } 33278 33279 fprintf(outfile, "\nEnd\n"); 33280 fclose(outfile); 33281 } 33282 33284 // // 33285 // outmesh2gid() Write mesh to a .ele.msh file and a .face.msh file, // 33286 // which can be imported and rendered by Gid. // 33287 // // 33288 // You can specify a filename (without suffix) in 'gfilename'. If you don't // 33289 // supply a filename (let gfilename be NULL), the default name stored in // 33290 // 'tetgenbehavior' will be used. The suffixes (.ele.msh and .face.msh) will // 33291 // be automatically added. // 33292 // // 33294 33295 void tetgenmesh::outmesh2gid(char* gfilename) 33296 { 33297 FILE *outfile; 33298 char gidfilename[FILENAMESIZE]; 33299 tetrahedron* tetptr; 33300 triface tface, tsymface; 33301 face sface; 33302 point ptloop, p1, p2, p3, p4; 33303 int pointnumber; 33304 int elementnumber; 33305 33306 if (gfilename != (char *) NULL && gfilename[0] != '\0') { 33307 strcpy(gidfilename, gfilename); 33308 } else if (b->outfilename[0] != '\0') { 33309 strcpy(gidfilename, b->outfilename); 33310 } else { 33311 strcpy(gidfilename, "unnamed"); 33312 } 33313 strcat(gidfilename, ".ele.msh"); 33314 33315 if (!b->quiet) { 33316 printf("Writing %s.\n", gidfilename); 33317 } 33318 outfile = fopen(gidfilename, "w"); 33319 if (outfile == (FILE *) NULL) { 33320 printf("File I/O Error: Cannot create file %s.\n", gidfilename); 33321 return; 33322 } 33323 33324 fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n"); 33325 fprintf(outfile, "coordinates\n"); 33326 33327 points->traversalinit(); 33328 ptloop = pointtraverse(); 33329 pointnumber = 1; // Gid need start number form 1. 33330 while (ptloop != (point) NULL) { 33331 // Point coordinates. 33332 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, 33333 ptloop[0], ptloop[1], ptloop[2]); 33334 if (in->numberofpointattributes > 0) { 33335 // Write an attribute, ignore others if more than one. 33336 fprintf(outfile, " %.17g", ptloop[3]); 33337 } 33338 fprintf(outfile, "\n"); 33339 setpointmark(ptloop, pointnumber); 33340 ptloop = pointtraverse(); 33341 pointnumber++; 33342 } 33343 33344 fprintf(outfile, "end coordinates\n"); 33345 fprintf(outfile, "elements\n"); 33346 33347 tetrahedrons->traversalinit(); 33348 tetptr = tetrahedrontraverse(); 33349 elementnumber = 1; 33350 while (tetptr != (tetrahedron *) NULL) { 33351 p1 = (point) tetptr[4]; 33352 p2 = (point) tetptr[5]; 33353 p3 = (point) tetptr[6]; 33354 p4 = (point) tetptr[7]; 33355 fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, 33356 pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); 33357 if (in->numberoftetrahedronattributes > 0) { 33358 fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); 33359 } 33360 fprintf(outfile, "\n"); 33361 tetptr = tetrahedrontraverse(); 33362 elementnumber++; 33363 } 33364 33365 fprintf(outfile, "end elements\n"); 33366 fclose(outfile); 33367 33368 if (gfilename != (char *) NULL && gfilename[0] != '\0') { 33369 strcpy(gidfilename, gfilename); 33370 } else if (b->outfilename[0] != '\0') { 33371 strcpy(gidfilename, b->outfilename); 33372 } else { 33373 strcpy(gidfilename, "unnamed"); 33374 } 33375 strcat(gidfilename, ".face.msh"); 33376 33377 if (!b->quiet) { 33378 printf("Writing %s.\n", gidfilename); 33379 } 33380 outfile = fopen(gidfilename, "w"); 33381 if (outfile == (FILE *) NULL) { 33382 printf("File I/O Error: Cannot create file %s.\n", gidfilename); 33383 return; 33384 } 33385 33386 fprintf(outfile, "mesh dimension = 3 elemtype triangle nnode = 3\n"); 33387 fprintf(outfile, "coordinates\n"); 33388 33389 points->traversalinit(); 33390 ptloop = pointtraverse(); 33391 pointnumber = 1; // Gid need start number form 1. 33392 while (ptloop != (point) NULL) { 33393 // Point coordinates. 33394 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, 33395 ptloop[0], ptloop[1], ptloop[2]); 33396 if (in->numberofpointattributes > 0) { 33397 // Write an attribute, ignore others if more than one. 33398 fprintf(outfile, " %.17g", ptloop[3]); 33399 } 33400 fprintf(outfile, "\n"); 33401 setpointmark(ptloop, pointnumber); 33402 ptloop = pointtraverse(); 33403 pointnumber++; 33404 } 33405 33406 fprintf(outfile, "end coordinates\n"); 33407 fprintf(outfile, "elements\n"); 33408 33409 tetrahedrons->traversalinit(); 33410 tface.tet = tetrahedrontraverse(); 33411 elementnumber = 1; 33412 while (tface.tet != (tetrahedron *) NULL) { 33413 for (tface.loc = 0; tface.loc < 4; tface.loc ++) { 33414 sym(tface, tsymface); 33415 if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) { 33416 p1 = org(tface); 33417 p2 = dest(tface); 33418 p3 = apex(tface); 33419 if (tsymface.tet == dummytet) { 33420 // It's a hull face, output it. 33421 fprintf(outfile, "%5d %d %d %d\n", elementnumber, 33422 pointmark(p1), pointmark(p2), pointmark(p3)); 33423 elementnumber++; 33424 } else if (b->useshelles) { 33425 // Only output it if it's a subface. 33426 tspivot(tface, sface); 33427 if (sface.sh != dummysh) { 33428 fprintf(outfile, "%5d %d %d %d\n", elementnumber, 33429 pointmark(p1), pointmark(p2), pointmark(p3)); 33430 elementnumber++; 33431 } 33432 } 33433 } 33434 } 33435 tface.tet = tetrahedrontraverse(); 33436 } 33437 33438 fprintf(outfile, "end elements\n"); 33439 fclose(outfile); 33440 } 33441 33443 // // 33444 // outmesh2off() Write the mesh to an .off file. // 33445 // // 33446 // .off, the Object File Format, is one of the popular file formats from the // 33447 // Geometry Center's Geomview package (http://www.geomview.org). // 33448 // // 33450 33451 void tetgenmesh::outmesh2off(char* ofilename) 33452 { 33453 FILE *outfile; 33454 char offfilename[FILENAMESIZE]; 33455 triface tface, tsymface; 33456 point ptloop, p1, p2, p3; 33457 long faces; 33458 int shift; 33459 33460 if (ofilename != (char *) NULL && ofilename[0] != '\0') { 33461 strcpy(offfilename, ofilename); 33462 } else if (b->outfilename[0] != '\0') { 33463 strcpy(offfilename, b->outfilename); 33464 } else { 33465 strcpy(offfilename, "unnamed"); 33466 } 33467 strcat(offfilename, ".off"); 33468 33469 if (!b->quiet) { 33470 printf("Writing %s.\n", offfilename); 33471 } 33472 outfile = fopen(offfilename, "w"); 33473 if (outfile == (FILE *) NULL) { 33474 printf("File I/O Error: Cannot create file %s.\n", offfilename); 33475 return; 33476 } 33477 33478 // Calculate the number of triangular faces in the tetrahedral mesh. 33479 faces = (4l * tetrahedrons->items + hullsize) / 2l; 33480 33481 // Number of points, faces, and edges(not used, here show hullsize). 33482 fprintf(outfile, "OFF\n%ld %ld %ld\n", points->items, faces, hullsize); 33483 33484 // Write the points. 33485 points->traversalinit(); 33486 ptloop = pointtraverse(); 33487 while (ptloop != (point) NULL) { 33488 fprintf(outfile, " %.17g %.17g %.17g\n",ptloop[0], ptloop[1], ptloop[2]); 33489 ptloop = pointtraverse(); 33490 } 33491 33492 // OFF always use zero as the first index. 33493 shift = in->firstnumber == 1 ? 1 : 0; 33494 33495 tetrahedrons->traversalinit(); 33496 tface.tet = tetrahedrontraverse(); 33497 // To loop over the set of faces, loop over all tetrahedra, and look at 33498 // the four faces of each tetrahedron. If there isn't another tetrahedron 33499 // adjacent to the face, operate on the face. If there is another adj- 33500 // acent tetrahedron, operate on the face only if the current tetrahedron 33501 // has a smaller pointer than its neighbor. This way, each face is 33502 // considered only once. 33503 while (tface.tet != (tetrahedron *) NULL) { 33504 for (tface.loc = 0; tface.loc < 4; tface.loc ++) { 33505 sym(tface, tsymface); 33506 if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) { 33507 p1 = org(tface); 33508 p2 = dest(tface); 33509 p3 = apex(tface); 33510 // Face number, indices of three vertexs. 33511 fprintf(outfile, "3 %4d %4d %4d\n", pointmark(p1) - shift, 33512 pointmark(p2) - shift, pointmark(p3) - shift); 33513 } 33514 } 33515 tface.tet = tetrahedrontraverse(); 33516 } 33517 33518 fprintf(outfile, "# Generated by %s\n", b->commandline); 33519 fclose(outfile); 33520 } 33521 33522 // 33523 // End of I/O rouitnes 33524 // 33525 33526 // 33527 // Begin of user interaction routines 33528 // 33529 33531 // // 33532 // internalerror() Ask the user to send me the defective product. Exit. // 33533 // // 33535 33536 void tetgenmesh::internalerror() 33537 { 33538 printf(" Please report this bug to sihang@mail.berlios.de. Include the\n"); 33539 printf(" message above, your input data set, and the exact command\n"); 33540 printf(" line you used to run this program, thank you.\n"); 33541 terminatetetgen(2); 33542 } 33543 33545 // // 33546 // checkmesh() Test the mesh for topological consistency. // 33547 // // 33549 33550 void tetgenmesh::checkmesh() 33551 { 33552 triface tetraloop; 33553 triface oppotet, oppooppotet; 33554 point tetorg, tetdest, tetapex, tetoppo; 33555 REAL oritest; 33556 int horrors; 33557 33558 if (!b->quiet) { 33559 printf(" Checking consistency of mesh...\n"); 33560 } 33561 33562 horrors = 0; 33563 // Run through the list of tetrahedra, checking each one. 33564 tetrahedrons->traversalinit(); 33565 tetraloop.tet = tetrahedrontraverse(); 33566 while (tetraloop.tet != (tetrahedron *) NULL) { 33567 // Check all four faces of the tetrahedron. 33568 for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) { 33569 tetorg = org(tetraloop); 33570 tetdest = dest(tetraloop); 33571 tetapex = apex(tetraloop); 33572 tetoppo = oppo(tetraloop); 33573 if (tetraloop.loc == 0) { // Only test for inversion once. 33574 oritest = orient3d(tetorg, tetdest, tetapex, tetoppo); 33575 if (oritest >= 0.0) { 33576 printf(" !! !! %s ", oritest > 0.0 ? "Inverted" : "Degenerated"); 33577 printtet(&tetraloop); 33578 printf(" orient3d = %.17g.\n", oritest); 33579 horrors++; 33580 } 33581 } 33582 // Find the neighboring tetrahedron on this face. 33583 sym(tetraloop, oppotet); 33584 if (oppotet.tet != dummytet) { 33585 // Check that the tetrahedron's neighbor knows it's a neighbor. 33586 sym(oppotet, oppooppotet); 33587 if ((tetraloop.tet != oppooppotet.tet) 33588 || (tetraloop.loc != oppooppotet.loc)) { 33589 printf(" !! !! Asymmetric tetra-tetra bond:\n"); 33590 if (tetraloop.tet == oppooppotet.tet) { 33591 printf(" (Right tetrahedron, wrong orientation)\n"); 33592 } 33593 printf(" First "); 33594 printtet(&tetraloop); 33595 printf(" Second (nonreciprocating) "); 33596 printtet(&oppotet); 33597 horrors++; 33598 } 33599 } 33600 } 33601 tetraloop.tet = tetrahedrontraverse(); 33602 } 33603 if (horrors == 0) { 33604 if (!b->quiet) { 33605 printf(" In my studied opinion, the mesh appears to be consistent.\n"); 33606 } 33607 } else if (horrors == 1) { 33608 printf(" !! !! !! !! Precisely one festering wound discovered.\n"); 33609 } else { 33610 printf(" !! !! !! !! %d abominations witnessed.\n", horrors); 33611 } 33612 } 33613 33615 // // 33616 // checkshells() Test the boundary mesh for topological consistency. // 33617 // // 33619 33620 void tetgenmesh::checkshells() 33621 { 33622 triface oppotet, oppooppotet, testtet; 33623 face shloop, segloop, spin; 33624 face testsh, testseg, testshsh; 33625 point shorg, shdest, segorg, segdest; 33626 REAL checksign; 33627 bool same; 33628 int horrors; 33629 int i; 33630 33631 if (!b->quiet) { 33632 printf(" Checking consistency of the mesh boundary...\n"); 33633 } 33634 horrors = 0; 33635 33636 // Run through the list of subfaces, checking each one. 33637 subfaces->traversalinit(); 33638 shloop.sh = shellfacetraverse(subfaces); 33639 while (shloop.sh != (shellface *) NULL) { 33640 // Check two connected tetrahedra if they exist. 33641 shloop.shver = 0; 33642 stpivot(shloop, oppotet); 33643 if (oppotet.tet != dummytet) { 33644 tspivot(oppotet, testsh); 33645 if (testsh.sh != shloop.sh) { 33646 printf(" !! !! Wrong tetra-subface connection.\n"); 33647 printf(" Tetra: "); 33648 printtet(&oppotet); 33649 printf(" Subface: "); 33650 printsh(&shloop); 33651 horrors++; 33652 } 33653 if (oppo(oppotet) != (point) NULL) { 33654 adjustedgering(oppotet, CCW); 33655 checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop), 33656 oppo(oppotet)); 33657 if (checksign >= 0.0) { 33658 printf(" !! !! Wrong subface orientation.\n"); 33659 printf(" Subface: "); 33660 printsh(&shloop); 33661 horrors++; 33662 } 33663 } 33664 } 33665 sesymself(shloop); 33666 stpivot(shloop, oppooppotet); 33667 if (oppooppotet.tet != dummytet) { 33668 tspivot(oppooppotet, testsh); 33669 if (testsh.sh != shloop.sh) { 33670 printf(" !! !! Wrong tetra-subface connection.\n"); 33671 printf(" Tetra: "); 33672 printtet(&oppooppotet); 33673 printf(" Subface: "); 33674 printsh(&shloop); 33675 horrors++; 33676 } 33677 if (oppotet.tet != dummytet) { 33678 sym(oppotet, testtet); 33679 if (testtet.tet != oppooppotet.tet) { 33680 printf(" !! !! Wrong tetra-subface-tetra connection.\n"); 33681 printf(" Tetra 1: "); 33682 printtet(&oppotet); 33683 printf(" Subface: "); 33684 printsh(&shloop); 33685 printf(" Tetra 2: "); 33686 printtet(&oppooppotet); 33687 horrors++; 33688 } 33689 } 33690 if (oppo(oppooppotet) != (point) NULL) { 33691 adjustedgering(oppooppotet, CCW); 33692 checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop), 33693 oppo(oppooppotet)); 33694 if (checksign >= 0.0) { 33695 printf(" !! !! Wrong subface orientation.\n"); 33696 printf(" Subface: "); 33697 printsh(&shloop); 33698 horrors++; 33699 } 33700 } 33701 } 33702 // Check connection between subfaces. 33703 shloop.shver = 0; 33704 for (i = 0; i < 3; i++) { 33705 shorg = sorg(shloop); 33706 shdest = sdest(shloop); 33707 sspivot(shloop, testseg); 33708 if (testseg.sh != dummysh) { 33709 segorg = sorg(testseg); 33710 segdest = sdest(testseg); 33711 same = ((shorg == segorg) && (shdest == segdest)) 33712 || ((shorg == segdest) && (shdest == segorg)); 33713 if (!same) { 33714 printf(" !! !! Wrong subface-subsegment connection.\n"); 33715 printf(" Subface: "); 33716 printsh(&shloop); 33717 printf(" Subsegment: "); 33718 printsh(&testseg); 33719 horrors++; 33720 } 33721 } 33722 spivot(shloop, testsh); 33723 if (testsh.sh != dummysh) { 33724 segorg = sorg(testsh); 33725 segdest = sdest(testsh); 33726 same = ((shorg == segorg) && (shdest == segdest)) 33727 || ((shorg == segdest) && (shdest == segorg)); 33728 if (!same) { 33729 printf(" !! !! Wrong subface-subface connection.\n"); 33730 printf(" Subface 1: "); 33731 printsh(&shloop); 33732 printf(" Subface 2: "); 33733 printsh(&testsh); 33734 horrors++; 33735 } 33736 spivot(testsh, testshsh); 33737 shorg = sorg(testshsh); 33738 shdest = sdest(testshsh); 33739 same = ((shorg == segorg) && (shdest == segdest)) 33740 || ((shorg == segdest) && (shdest == segorg)); 33741 if (!same) { 33742 printf(" !! !! Wrong subface-subface connection.\n"); 33743 printf(" Subface 1: "); 33744 printsh(&testsh); 33745 printf(" Subface 2: "); 33746 printsh(&testshsh); 33747 horrors++; 33748 } 33749 if (testseg.sh == dummysh) { 33750 if (testshsh.sh != shloop.sh) { 33751 printf(" !! !! Wrong subface-subface connection.\n"); 33752 printf(" Subface 1: "); 33753 printsh(&shloop); 33754 printf(" Subface 2: "); 33755 printsh(&testsh); 33756 horrors++; 33757 } 33758 } 33759 } 33760 senextself(shloop); 33761 } 33762 shloop.sh = shellfacetraverse(subfaces); 33763 } 33764 33765 // Run through the list of subsegs, checking each one. 33766 subsegs->traversalinit(); 33767 segloop.sh = shellfacetraverse(subsegs); 33768 while (segloop.sh != (shellface *) NULL) { 33769 segorg = sorg(segloop); 33770 segdest = sdest(segloop); 33771 spivot(segloop, testsh); 33772 if (testsh.sh == dummysh) { 33773 printf(" !! !! Wrong subsegment-subface connection.\n"); 33774 printf(" Subsegment: "); 33775 printsh(&segloop); 33776 horrors++; 33777 segloop.sh = shellfacetraverse(subsegs); 33778 continue; 33779 } 33780 shorg = sorg(testsh); 33781 shdest = sdest(testsh); 33782 same = ((shorg == segorg) && (shdest == segdest)) 33783 || ((shorg == segdest) && (shdest == segorg)); 33784 if (!same) { 33785 printf(" !! !! Wrong subsegment-subface connection.\n"); 33786 printf(" Subsegment : "); 33787 printsh(&segloop); 33788 printf(" Subface : "); 33789 printsh(&testsh); 33790 horrors++; 33791 segloop.sh = shellfacetraverse(subsegs); 33792 continue; 33793 } 33794 // Check the connection of face loop around this subsegment. 33795 spin = testsh; 33796 i = 0; 33797 do { 33798 spivotself(spin); 33799 shorg = sorg(spin); 33800 shdest = sdest(spin); 33801 same = ((shorg == segorg) && (shdest == segdest)) 33802 || ((shorg == segdest) && (shdest == segorg)); 33803 if (!same) { 33804 printf(" !! !! Wrong subsegment-subface connection.\n"); 33805 printf(" Subsegment : "); 33806 printsh(&segloop); 33807 printf(" Subface : "); 33808 printsh(&testsh); 33809 horrors++; 33810 break; 33811 } 33812 i++; 33813 } while (spin.sh != testsh.sh && i < 1000); 33814 if (i >= 1000) { 33815 printf(" !! !! Wrong subsegment-subface connection.\n"); 33816 printf(" Subsegment : "); 33817 printsh(&segloop); 33818 horrors++; 33819 } 33820 segloop.sh = shellfacetraverse(subsegs); 33821 } 33822 if (horrors == 0) { 33823 if (!b->quiet) { 33824 printf(" Mesh boundaries connected correctly.\n"); 33825 } 33826 } else { 33827 printf(" !! !! !! !! %d boundary connection viewed with horror.\n", 33828 horrors); 33829 return; 33830 } 33831 } 33832 33834 // // 33835 // checkdelaunay() Ensure that the mesh is constrained Delaunay. // 33836 // // 33837 // If 'flipqueue' is not NULL, non-locally Delaunay faces are saved in it. // 33838 // // 33840 33841 void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue) 33842 { 33843 triface tetraloop; 33844 triface oppotet; 33845 face opposhelle; 33846 point tetorg, tetdest, tetapex, tetoppo; 33847 point oppooppo; 33848 enum fliptype fc; 33849 REAL sign; 33850 int shouldbedelaunay; 33851 int horrors; 33852 33853 if (!b->quiet) { 33854 printf(" Checking Delaunay property of the mesh...\n"); 33855 } 33856 horrors = 0; 33857 // Run through the list of triangles, checking each one. 33858 tetrahedrons->traversalinit(); 33859 tetraloop.tet = tetrahedrontraverse(); 33860 while (tetraloop.tet != (tetrahedron *) NULL) { 33861 // Check all four faces of the tetrahedron. 33862 for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) { 33863 tetorg = org(tetraloop); 33864 tetdest = dest(tetraloop); 33865 tetapex = apex(tetraloop); 33866 tetoppo = oppo(tetraloop); 33867 sym(tetraloop, oppotet); 33868 oppooppo = oppo(oppotet); 33869 // Only do testif there is an adjoining tetrahedron whose pointer is 33870 // larger (to ensure that each pair isn't tested twice). 33871 shouldbedelaunay = (oppotet.tet != dummytet) 33872 && (tetoppo != (point) NULL) 33873 && (oppooppo != (point) NULL) 33874 && (tetraloop.tet < oppotet.tet); 33875 if (checksubfaces && shouldbedelaunay) { 33876 // If a shell face separates the tetrahedra, then the face is 33877 // constrained, so no local Delaunay test should be done. 33878 tspivot(tetraloop, opposhelle); 33879 if (opposhelle.sh != dummysh){ 33880 shouldbedelaunay = 0; 33881 } 33882 } 33883 if (shouldbedelaunay) { 33884 sign = insphere(tetdest, tetorg, tetapex, tetoppo, oppooppo); 33885 if ((sign > 0.0) && (eps > 0.0)) { 33886 if (iscospheric(tetdest, tetorg, tetapex, tetoppo, oppooppo, sign, 33887 eps)) sign = 0.0; 33888 } 33889 if (sign > 0.0) { 33890 if (flipqueue) { 33891 enqueueflipface(tetraloop, flipqueue); 33892 } else { 33893 printf(" !! Non-locally Delaunay face (%d, %d, %d) ", 33894 pointmark(tetorg), pointmark(tetdest), pointmark(tetapex)); 33895 fc = categorizeface(tetraloop); 33896 switch (fc) { 33897 case T23: printf("\"T23\""); break; 33898 case T32: printf("\"T32\""); break; 33899 case T22: printf("\"T22\""); break; 33900 case T44: printf("\"T44\""); break; 33901 case N32: printf("\"N32\""); break; 33902 case N40: printf("\"N40\""); break; 33903 case FORBIDDENFACE:printf("\"FORBIDDENFACE\""); break; 33904 case FORBIDDENEDGE:printf("\"FORBIDDENEDGE\""); break; 33905 } 33906 printf("\n"); 33907 } 33908 horrors++; 33909 } 33910 } 33911 } 33912 tetraloop.tet = tetrahedrontraverse(); 33913 } 33914 if (flipqueue == (queue *) NULL) { 33915 if (horrors == 0) { 33916 if (!b->quiet) { 33917 printf(" The mesh is %s.\n", 33918 checksubfaces ? "constrained Delaunay" : "Delaunay"); 33919 } 33920 } else { 33921 printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); 33922 } 33923 } 33924 } 33925 33927 // // 33928 // checkconforming() Ensure that the mesh is conforming Delaunay. // 33929 // // 33931 33932 void tetgenmesh::checkconforming() 33933 { 33934 face segloop, shloop; 33935 int encsubsegs, encsubfaces; 33936 33937 if (!b->quiet) { 33938 printf(" Checking conforming Delaunay property of mesh...\n"); 33939 } 33940 encsubsegs = encsubfaces = 0; 33941 // Run through the list of subsegments, check each one. 33942 subsegs->traversalinit(); 33943 segloop.sh = shellfacetraverse(subsegs); 33944 while (segloop.sh != (shellface *) NULL) { 33945 if (checkseg4encroach(&segloop, NULL, NULL, false)) { 33946 printf(" !! !! Non-conforming subsegment: (%d, %d)\n", 33947 pointmark(sorg(segloop)), pointmark(sdest(segloop))); 33948 encsubsegs++; 33949 } 33950 segloop.sh = shellfacetraverse(subsegs); 33951 } 33952 // Run through the list of subfaces, check each one. 33953 subfaces->traversalinit(); 33954 shloop.sh = shellfacetraverse(subfaces); 33955 while (shloop.sh != (shellface *) NULL) { 33956 if (checksub4encroach(&shloop, NULL, false)) { 33957 printf(" !! !! Non-conforming subface: (%d, %d, %d)\n", 33958 pointmark(sorg(shloop)), pointmark(sdest(shloop)), 33959 pointmark(sapex(shloop))); 33960 encsubfaces++; 33961 } 33962 shloop.sh = shellfacetraverse(subfaces); 33963 } 33964 if (encsubsegs == 0 && encsubfaces == 0) { 33965 if (!b->quiet) { 33966 printf(" The mesh is conforming Delaunay.\n"); 33967 } 33968 } else { 33969 if (encsubsegs > 0) { 33970 printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs); 33971 } 33972 if (encsubfaces > 0) { 33973 printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces); 33974 } 33975 } 33976 } 33977 33979 // // 33980 // algorithmicstatistics() Print statistics about the mesh algorithms. // 33981 // // 33983 33984 #ifdef SELF_CHECK 33985 33986 void tetgenmesh::algorithmicstatistics() 33987 { 33988 /* 33989 printf("Algorithmic statistics:\n\n"); 33990 printf(" Point location millisecond: %g\n", (REAL) tloctime * 1e+3); 33991 printf(" Flip millisecond: %g\n", (REAL) tfliptime * 1e+3); 33992 if (b->plc || b->refine) { 33993 printf(" Number of facet above points calculations: %ld\n", abovecount); 33994 } 33995 if (b->plc) { 33996 printf(" Segment split rules: R1 %ld, R2 %ld, R3 %ld\n", r1count, r2count, 33997 r3count); 33998 } 33999 if (b->quality) { 34000 printf(" Bowyer-Watson insertions: seg %ld, sub %ld, vol %ld.\n", 34001 bowatsegcount, bowatsubcount, bowatvolcount); 34002 printf(" Bowyer-Watson corrections: seg %ld, sub %ld, vol %ld\n", 34003 updsegcount, updsubcount, updvolcount); 34004 printf(" Bowyer-Watson failures: seg %ld, sub %ld, vol %ld\n", 34005 failsegcount, failsubcount, failvolcount); 34006 printf(" Number of repair flips: %ld.\n", repairflipcount); 34007 printf(" Number of circumcenters outside Bowat-cav.: %ld.\n", 34008 outbowatcircumcount); 34009 if (b->conformdel) { 34010 printf(" Segment split rules: R2 %ld, R3 %ld\n", r2count, r3count); 34011 printf(" Number of CDT enforcement points: %ld.\n", cdtenforcesegpts); 34012 } 34013 printf(" Number of Rejections: seg %ld, sub %ld, tet %ld.\n", rejsegpts, 34014 rejsubpts, rejtetpts); 34015 if (b->optlevel) { 34016 printf( 34017 " Optimization flips: f32 %ld, f44 %ld, f56 %ld, f68 %ld, fnm %ld.\n", 34018 optcount[3], optcount[4], optcount[5], optcount[6], optcount[9]); 34019 printf(" Optimization segment deletions: %ld.\n", optcount[1]); 34020 } 34021 } 34022 printf("\n"); 34023 */ 34024 } 34025 34026 #endif // #ifdef SELF_CHECK 34027 34029 // // 34030 // qualitystatistics() Print statistics about the quality of the mesh. // 34031 // // 34033 34034 void tetgenmesh::qualitystatistics() 34035 { 34036 triface tetloop, neightet; 34037 point p[4]; 34038 char sbuf[128]; 34039 REAL radiusratiotable[12]; 34040 REAL aspectratiotable[12]; 34041 REAL A[4][4], rhs[4], D; 34042 REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights. 34043 REAL edgelength[6], alldihed[6], faceangle[3]; 34044 REAL shortest, longest; 34045 REAL smallestvolume, biggestvolume; 34046 REAL smallestdiangle, biggestdiangle; 34047 REAL smallestfaangle, biggestfaangle; 34048 REAL tetvol, minaltitude; 34049 REAL cirradius, minheightinv; // insradius; 34050 REAL shortlen, longlen; 34051 REAL tetaspect, tetradius; 34052 REAL smalldiangle, bigdiangle; 34053 REAL smallfaangle, bigfaangle; 34054 int radiustable[12]; 34055 int aspecttable[16]; 34056 int dihedangletable[18]; 34057 int faceangletable[18]; 34058 int indx[4]; 34059 int radiusindex; 34060 int aspectindex; 34061 int tendegree; 34062 int i, j; 34063 34064 smallfaangle = 0.0; 34065 bigfaangle = 0.0; 34066 34067 printf("Mesh quality statistics:\n\n"); 34068 34069 // Avoid compile warnings. 34070 shortlen = longlen = 0.0; 34071 smalldiangle = bigdiangle = 0.0; 34072 34073 radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0; 34074 radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2; 34075 radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6; 34076 radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0; 34077 radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0; 34078 radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0; 34079 34080 aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0; 34081 aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0; 34082 aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0; 34083 aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0; 34084 aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0; 34085 aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0; 34086 34087 for (i = 0; i < 12; i++) radiustable[i] = 0; 34088 for (i = 0; i < 12; i++) aspecttable[i] = 0; 34089 for (i = 0; i < 18; i++) dihedangletable[i] = 0; 34090 for (i = 0; i < 18; i++) faceangletable[i] = 0; 34091 34092 minaltitude = xmax - xmin + ymax - ymin + zmax - zmin; 34093 minaltitude = minaltitude * minaltitude; 34094 shortest = minaltitude; 34095 longest = 0.0; 34096 smallestvolume = minaltitude; 34097 biggestvolume = 0.0; 34098 smallestdiangle = smallestfaangle = 180.0; 34099 biggestdiangle = biggestfaangle = 0.0; 34100 34101 // Loop all elements, calculate quality parameters for each element. 34102 tetrahedrons->traversalinit(); 34103 tetloop.tet = tetrahedrontraverse(); 34104 while (tetloop.tet != (tetrahedron *) NULL) { 34105 34106 // Get four vertices: p0, p1, p2, p3. 34107 for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i]; 34108 // Set the edge vectors: V[0], ..., V[5] 34109 for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0. 34110 for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1. 34111 for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2. 34112 for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1. 34113 for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2. 34114 for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0. 34115 // Set the matrix A = [V[0], V[1], V[2]]^T. 34116 for (j = 0; j < 3; j++) { 34117 for (i = 0; i < 3; i++) A[j][i] = V[j][i]; 34118 } 34119 // Decompose A just once. 34120 lu_decmp(A, 3, indx, &D, 0); 34121 // Get the tet volume. 34122 tetvol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; 34123 // Get the three faces normals. 34124 for (j = 0; j < 3; j++) { 34125 for (i = 0; i < 3; i++) rhs[i] = 0.0; 34126 rhs[j] = 1.0; // Positive means the inside direction 34127 lu_solve(A, 3, indx, rhs, 0); 34128 for (i = 0; i < 3; i++) N[j][i] = rhs[i]; 34129 } 34130 // Get the fourth face normal by summing up the first three. 34131 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; 34132 // Get the radius of the circumsphere. 34133 for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]); 34134 lu_solve(A, 3, indx, rhs, 0); 34135 cirradius = sqrt(dot(rhs, rhs)); 34136 // Normalize the face normals. 34137 for (i = 0; i < 4; i++) { 34138 // H[i] is the inverse of height of its corresponding face. 34139 H[i] = sqrt(dot(N[i], N[i])); 34140 for (j = 0; j < 3; j++) N[i][j] /= H[i]; 34141 } 34142 // Get the radius of the inscribed sphere. 34143 // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]); 34144 // Get the biggest H[i] (corresponding to the smallest height). 34145 minheightinv = H[0]; 34146 for (i = 1; i < 3; i++) { 34147 if (H[i] > minheightinv) minheightinv = H[i]; 34148 } 34149 // Get the squares of the edge lengthes. 34150 for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]); 34151 // Get the dihedrals (in degree) at each edges. 34152 j = 0; 34153 for (i = 1; i < 4; i++) { 34154 alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc. 34155 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding. 34156 else if (alldihed[j] > 1.0) alldihed[j] = 1; 34157 alldihed[j] = acos(alldihed[j]) / PI * 180.0; 34158 j++; 34159 } 34160 for (i = 2; i < 4; i++) { 34161 alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac. 34162 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding. 34163 else if (alldihed[j] > 1.0) alldihed[j] = 1; 34164 alldihed[j] = acos(alldihed[j]) / PI * 180.0; 34165 j++; 34166 } 34167 alldihed[j] = -dot(N[2], N[3]); // Edge ab. 34168 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding. 34169 else if (alldihed[j] > 1.0) alldihed[j] = 1; 34170 alldihed[j] = acos(alldihed[j]) / PI * 180.0; 34171 34172 // Calculate the longest and shortest edge length. 34173 for (i = 0; i < 6; i++) { 34174 if (i == 0) { 34175 shortlen = longlen = edgelength[i]; 34176 } else { 34177 shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen; 34178 longlen = edgelength[i] > longlen ? edgelength[i] : longlen; 34179 } 34180 if (edgelength[i] > longest) { 34181 longest = edgelength[i]; 34182 } 34183 if (edgelength[i] < shortest) { 34184 shortest = edgelength[i]; 34185 } 34186 } 34187 34188 // Calculate the largest and smallest volume. 34189 if (tetvol < smallestvolume) { 34190 smallestvolume = tetvol; 34191 } 34192 if (tetvol > biggestvolume) { 34193 biggestvolume = tetvol; 34194 } 34195 34196 // Calculate the largest and smallest dihedral angles. 34197 for (i = 0; i < 6; i++) { 34198 if (i == 0) { 34199 smalldiangle = bigdiangle = alldihed[i]; 34200 } else { 34201 smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle; 34202 bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle; 34203 } 34204 if (alldihed[i] < smallestdiangle) { 34205 smallestdiangle = alldihed[i]; 34206 } 34207 if (alldihed[i] > biggestdiangle) { 34208 biggestdiangle = alldihed[i]; 34209 } 34210 } 34211 // Accumulate the corresponding number in the dihedral angle histogram. 34212 if (smalldiangle < 5.0) { 34213 tendegree = 0; 34214 } else if (smalldiangle >= 5.0 && smalldiangle < 10.0) { 34215 tendegree = 1; 34216 } else if (smalldiangle >= 80.0 && smalldiangle < 110.0) { 34217 tendegree = 9; // Angles between 80 to 110 degree are in one entry. 34218 } else { 34219 tendegree = (int) (smalldiangle / 10.); 34220 if (smalldiangle < 80.0) { 34221 tendegree++; // In the left column. 34222 } else { 34223 tendegree--; // In the right column. 34224 } 34225 } 34226 dihedangletable[tendegree]++; 34227 if (bigdiangle >= 80.0 && bigdiangle < 110.0) { 34228 tendegree = 9; // Angles between 80 to 110 degree are in one entry. 34229 } else if (bigdiangle >= 170.0 && bigdiangle < 175.0) { 34230 tendegree = 16; 34231 } else if (bigdiangle >= 175.0) { 34232 tendegree = 17; 34233 } else { 34234 tendegree = (int) (bigdiangle / 10.); 34235 if (bigdiangle < 80.0) { 34236 tendegree++; // In the left column. 34237 } else { 34238 tendegree--; // In the right column. 34239 } 34240 } 34241 dihedangletable[tendegree]++; 34242 34243 // Calulate the largest and smallest face angles. 34244 tetloop.ver = 0; 34245 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { 34246 sym(tetloop, neightet); 34247 // Only do the calulation once for a face. 34248 if ((neightet.tet == dummytet) || (tetloop.tet < neightet.tet)) { 34249 p[0] = org(tetloop); 34250 p[1] = dest(tetloop); 34251 p[2] = apex(tetloop); 34252 faceangle[0] = interiorangle(p[0], p[1], p[2], NULL); 34253 faceangle[1] = interiorangle(p[1], p[2], p[0], NULL); 34254 faceangle[2] = PI - (faceangle[0] + faceangle[1]); 34255 // Translate angles into degrees. 34256 for (i = 0; i < 3; i++) { 34257 faceangle[i] = (faceangle[i] * 180.0) / PI; 34258 } 34259 // Calculate the largest and smallest face angles. 34260 for (i = 0; i < 3; i++) { 34261 if (i == 0) { 34262 smallfaangle = bigfaangle = faceangle[i]; 34263 } else { 34264 smallfaangle = faceangle[i] < smallfaangle ? 34265 faceangle[i] : smallfaangle; 34266 bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle; 34267 } 34268 if (faceangle[i] < smallestfaangle) { 34269 smallestfaangle = faceangle[i]; 34270 } 34271 if (faceangle[i] > biggestfaangle) { 34272 biggestfaangle = faceangle[i]; 34273 } 34274 } 34275 tendegree = (int) (smallfaangle / 10.); 34276 faceangletable[tendegree]++; 34277 tendegree = (int) (bigfaangle / 10.); 34278 faceangletable[tendegree]++; 34279 } 34280 } 34281 34282 // Calculate aspect ratio and radius-edge ratio for this element. 34283 tetradius = cirradius / sqrt(shortlen); 34284 // tetaspect = sqrt(longlen) / (2.0 * insradius); 34285 tetaspect = sqrt(longlen) * minheightinv; 34286 aspectindex = 0; 34287 while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) { 34288 aspectindex++; 34289 } 34290 aspecttable[aspectindex]++; 34291 radiusindex = 0; 34292 while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) { 34293 radiusindex++; 34294 } 34295 radiustable[radiusindex]++; 34296 34297 tetloop.tet = tetrahedrontraverse(); 34298 } 34299 34300 shortest = sqrt(shortest); 34301 longest = sqrt(longest); 34302 minaltitude = sqrt(minaltitude); 34303 34304 printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n", 34305 smallestvolume, biggestvolume); 34306 printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", 34307 shortest, longest); 34308 sprintf(sbuf, "%.17g", biggestfaangle); 34309 if (strlen(sbuf) > 8) { 34310 sbuf[8] = '\0'; 34311 } 34312 printf(" Smallest facangle: %14.5g | Largest facangle: %s\n", 34313 smallestfaangle, sbuf); 34314 sprintf(sbuf, "%.17g", biggestdiangle); 34315 if (strlen(sbuf) > 8) { 34316 sbuf[8] = '\0'; 34317 } 34318 printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n", 34319 smallestdiangle, sbuf); 34320 34321 /* 34322 printf(" Radius-edge ratio histogram:\n"); 34323 printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", 34324 radiusratiotable[0], radiustable[0], radiusratiotable[5], 34325 radiusratiotable[6], radiustable[6]); 34326 for (i = 1; i < 5; i++) { 34327 printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", 34328 radiusratiotable[i - 1], radiusratiotable[i], radiustable[i], 34329 radiusratiotable[i + 5], radiusratiotable[i + 6], 34330 radiustable[i + 6]); 34331 } 34332 printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", 34333 radiusratiotable[4], radiusratiotable[5], radiustable[5], 34334 radiusratiotable[10], radiustable[11]); 34335 printf(" (A tetrahedron's radius-edge ratio is its radius of "); 34336 printf("circumsphere divided\n"); 34337 printf(" by its shortest edge length)\n\n"); 34338 */ 34339 34340 printf(" Aspect ratio histogram:\n"); 34341 printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", 34342 aspectratiotable[0], aspecttable[0], aspectratiotable[5], 34343 aspectratiotable[6], aspecttable[6]); 34344 for (i = 1; i < 5; i++) { 34345 printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", 34346 aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i], 34347 aspectratiotable[i + 5], aspectratiotable[i + 6], 34348 aspecttable[i + 6]); 34349 } 34350 printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", 34351 aspectratiotable[4], aspectratiotable[5], aspecttable[5], 34352 aspectratiotable[10], aspecttable[11]); 34353 printf(" (A tetrahedron's aspect ratio is its longest edge length"); 34354 printf(" divided by its\n"); 34355 printf(" smallest side height)\n\n"); 34356 34357 printf(" Face angle histogram:\n"); 34358 for (i = 0; i < 9; i++) { 34359 printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", 34360 i * 10, i * 10 + 10, faceangletable[i], 34361 i * 10 + 90, i * 10 + 100, faceangletable[i + 9]); 34362 } 34363 if (minfaceang != PI) { 34364 printf(" Minimum input face angle is %g (degree).\n", 34365 minfaceang / PI * 180.0); 34366 } 34367 printf("\n"); 34368 34369 printf(" Dihedral angle histogram:\n"); 34370 // Print the three two rows: 34371 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 34372 0, 5, dihedangletable[0], 80, 110, dihedangletable[9]); 34373 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 34374 5, 10, dihedangletable[1], 110, 120, dihedangletable[10]); 34375 // Print the third to seventh rows. 34376 for (i = 2; i < 7; i++) { 34377 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 34378 (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i], 34379 (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]); 34380 } 34381 // Print the last two rows. 34382 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 34383 60, 70, dihedangletable[7], 170, 175, dihedangletable[16]); 34384 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 34385 70, 80, dihedangletable[8], 175, 180, dihedangletable[17]); 34386 if (minfacetdihed != PI) { 34387 printf(" Minimum input facet dihedral angle is %g (degree).\n", 34388 minfacetdihed / PI * 180.0); 34389 } 34390 printf("\n"); 34391 } 34392 34394 // // 34395 // statistics() Print all sorts of cool facts. // 34396 // // 34398 34399 void tetgenmesh::statistics() 34400 { 34401 printf("\nStatistics:\n\n"); 34402 printf(" Input points: %d\n", in->numberofpoints + jettisoninverts); 34403 if (b->refine) { 34404 printf(" Input tetrahedra: %d\n", in->numberoftetrahedra); 34405 } 34406 if (b->plc) { 34407 printf(" Input facets: %d\n", in->numberoffacets); 34408 printf(" Input segments: %ld\n", insegments); 34409 printf(" Input holes: %d\n", in->numberofholes); 34410 printf(" Input regions: %d\n", in->numberofregions); 34411 } 34412 34413 printf("\n Mesh points: %ld\n", points->items); 34414 printf(" Mesh tetrahedra: %ld\n", tetrahedrons->items); 34415 if (b->plc || b->refine) { 34416 printf(" Mesh triangles: %ld\n", (4l*tetrahedrons->items+hullsize)/2l); 34417 } 34418 if (b->plc || b->refine) { 34419 printf(" Mesh subfaces: %ld\n", subfaces->items); 34420 printf(" Mesh subsegments: %ld\n\n", subsegs->items); 34421 } else { 34422 printf(" Convex hull triangles: %ld\n\n", hullsize); 34423 } 34424 if (b->verbose > 0) { 34425 qualitystatistics(); 34426 unsigned long totalmeshbytes; 34427 printf("Memory allocation statistics:\n\n"); 34428 printf(" Maximum number of vertices: %ld\n", points->maxitems); 34429 totalmeshbytes = points->maxitems * points->itembytes; 34430 printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems); 34431 totalmeshbytes += tetrahedrons->maxitems * tetrahedrons->itembytes; 34432 if (subfaces != (memorypool *) NULL) { 34433 printf(" Maximum number of subfaces: %ld\n", subfaces->maxitems); 34434 totalmeshbytes += subfaces->maxitems * subfaces->itembytes; 34435 } 34436 if (subsegs != (memorypool *) NULL) { 34437 printf(" Maximum number of segments: %ld\n", subsegs->maxitems); 34438 totalmeshbytes += subsegs->maxitems * subsegs->itembytes; 34439 } 34440 printf(" Approximate heap memory used by the mesh (K bytes): %g\n\n", 34441 (double) totalmeshbytes / 1024.0); 34442 #ifdef SELF_CHECK 34443 algorithmicstatistics(); 34444 #endif 34445 } 34446 } 34447 34448 // 34449 // End of user interaction routines 34450 // 34451 34452 // 34453 // Begin of constructor and destructor of tetgenmesh 34454 // 34455 34457 // // 34458 // ~tetgenmesh() Deallocte memory occupied by a tetgenmesh object. // 34459 // // 34461 34462 tetgenmesh::~tetgenmesh() 34463 { 34464 bgm = (tetgenmesh *) NULL; 34465 in = (tetgenio *) NULL; 34466 b = (tetgenbehavior *) NULL; 34467 34468 if (tetrahedrons != (memorypool *) NULL) { 34469 delete tetrahedrons; 34470 } 34471 if (subfaces != (memorypool *) NULL) { 34472 delete subfaces; 34473 } 34474 if (subsegs != (memorypool *) NULL) { 34475 delete subsegs; 34476 } 34477 if (points != (memorypool *) NULL) { 34478 delete points; 34479 } 34480 if (dummytetbase != (tetrahedron *) NULL) { 34481 delete [] dummytetbase; 34482 } 34483 if (dummyshbase != (shellface *) NULL) { 34484 delete [] dummyshbase; 34485 } 34486 if (facetabovepointarray != (point *) NULL) { 34487 delete [] facetabovepointarray; 34488 } 34489 if (highordertable != (point *) NULL) { 34490 delete [] highordertable; 34491 } 34492 if (subpbcgrouptable != (pbcdata *) NULL) { 34493 delete [] subpbcgrouptable; 34494 } 34495 if (segpbcgrouptable != (list *) NULL) { 34496 delete segpbcgrouptable; 34497 delete [] idx2segpglist; 34498 delete [] segpglist; 34499 } 34500 } 34501 34503 // // 34504 // tetgenmesh() Initialize a tetgenmesh object. // 34505 // // 34507 34508 tetgenmesh::tetgenmesh() 34509 { 34510 bgm = (tetgenmesh *) NULL; 34511 in = (tetgenio *) NULL; 34512 b = (tetgenbehavior *) NULL; 34513 34514 tetrahedrons = (memorypool *) NULL; 34515 subfaces = (memorypool *) NULL; 34516 subsegs = (memorypool *) NULL; 34517 points = (memorypool *) NULL; 34518 badsubsegs = (memorypool *) NULL; 34519 badsubfaces = (memorypool *) NULL; 34520 badtetrahedrons = (memorypool *) NULL; 34521 flipstackers = (memorypool *) NULL; 34522 34523 dummytet = (tetrahedron *) NULL; 34524 dummytetbase = (tetrahedron *) NULL; 34525 dummysh = (shellface *) NULL; 34526 dummyshbase = (shellface *) NULL; 34527 34528 facetabovepointarray = (point *) NULL; 34529 abovepoint = (point) NULL; 34530 highordertable = (point *) NULL; 34531 subpbcgrouptable = (pbcdata *) NULL; 34532 segpbcgrouptable = (list *) NULL; 34533 idx2segpglist = (int *) NULL; 34534 segpglist = (int *) NULL; 34535 34536 xmax = xmin = ymax = ymin = zmax = zmin = 0.0; 34537 longest = 0.0; 34538 hullsize = 0l; 34539 insegments = 0l; 34540 pointmtrindex = 0; 34541 pointmarkindex = 0; 34542 point2simindex = 0; 34543 point2pbcptindex = 0; 34544 highorderindex = 0; 34545 elemattribindex = 0; 34546 volumeboundindex = 0; 34547 shmarkindex = 0; 34548 areaboundindex = 0; 34549 checksubfaces = 0; 34550 checksubsegs = 0; 34551 checkpbcs = 0; 34552 varconstraint = 0; 34553 nonconvex = 0; 34554 dupverts = 0; 34555 unuverts = 0; 34556 relverts = 0; 34557 suprelverts = 0; 34558 collapverts = 0; 34559 unsupverts = 0; 34560 jettisoninverts = 0; 34561 symbolic = 1; 34562 samples = 0l; 34563 randomseed = 1l; 34564 macheps = 0.0; 34565 minfaceang = minfacetdihed = PI; 34566 maxcavfaces = maxcavverts = 0; 34567 expcavcount = 0; 34568 abovecount = 0l; 34569 bowatvolcount = bowatsubcount = bowatsegcount = 0l; 34570 updvolcount = updsubcount = updsegcount = 0l; 34571 repairflipcount = 0l; 34572 outbowatcircumcount = 0l; 34573 failvolcount = failsubcount = failsegcount = 0l; 34574 r1count = r2count = r3count = 0l; 34575 cdtenforcesegpts = 0l; 34576 rejsegpts = rejsubpts = rejtetpts = 0l; 34577 flip23s = flip32s = flip22s = flip44s = 0l; 34578 tloctime = tfliptime = 0.0; 34579 } 34580 34581 // 34582 // End of constructor and destructor of tetgenmesh 34583 // 34584 34585 // 34586 // End of class 'tetgenmesh' implementation. 34587 // 34588 34590 // // 34591 // tetrahedralize() The interface for users using TetGen library to // 34592 // generate tetrahedral meshes with all features. // 34593 // // 34594 // The sequence is roughly as follows. Many of these steps can be skipped, // 34595 // depending on the command line switches. // 34596 // // 34597 // - Initialize constants and parse the command line. // 34598 // - Read the vertices from a file and either // 34599 // - tetrahedralize them (no -r), or // 34600 // - read an old mesh from files and reconstruct it (-r). // 34601 // - Insert the PLC segments and facets (-p). // 34602 // - Read the holes (-p), regional attributes (-pA), and regional volume // 34603 // constraints (-pa). Carve the holes and concavities, and spread the // 34604 // regional attributes and volume constraints. // 34605 // - Enforce the constraints on minimum quality bound (-q) and maximum // 34606 // volume (-a). Also enforce the conforming Delaunay property (-q and -a). // 34607 // - Promote the mesh's linear tetrahedra to higher order elements (-o). // 34608 // - Write the output files and print the statistics. // 34609 // - Check the consistency and Delaunay property of the mesh (-C). // 34610 // // 34612 34613 void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, 34614 tetgenio *addin, tetgenio *bgmin) 34615 { 34616 tetgenmesh m; 34617 // Variables for timing the performance of TetGen (defined in time.h). 34618 clock_t tv[14]; 34619 34620 tv[0] = clock(); 34621 34622 m.b = b; 34623 m.in = in; 34624 m.macheps = exactinit(); 34625 m.steinerleft = b->steiner; 34626 if (b->metric) { 34627 m.bgm = new tetgenmesh(); 34628 m.bgm->b = b; 34629 m.bgm->in = bgmin; 34630 m.bgm->macheps = exactinit(); 34631 } 34632 m.initializepools(); 34633 m.transfernodes(); 34634 34635 tv[1] = clock(); 34636 34637 if (b->refine) { 34638 m.reconstructmesh(); 34639 } else { 34640 m.delaunizevertices(); 34641 } 34642 34643 tv[2] = clock(); 34644 34645 if (!b->quiet) { 34646 if (b->refine) { 34647 printf("Mesh reconstruction seconds:"); 34648 } else { 34649 printf("Delaunay seconds:"); 34650 } 34651 printf(" %g\n", (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC); 34652 } 34653 34654 if (b->metric) { 34655 if (bgmin != (tetgenio *) NULL) { 34656 m.bgm->initializepools(); 34657 m.bgm->transfernodes(); 34658 m.bgm->reconstructmesh(); 34659 } else { 34660 m.bgm->in = in; 34661 m.bgm->initializepools(); 34662 m.duplicatebgmesh(); 34663 } 34664 } 34665 34666 tv[3] = clock(); 34667 34668 if (!b->quiet) { 34669 if (b->metric) { 34670 printf("Background mesh reconstruct seconds: %g\n", 34671 (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC); 34672 } 34673 } 34674 34675 if (b->useshelles && !b->refine) { 34676 m.meshsurface(); 34677 if (b->diagnose != 1) { 34678 m.markacutevertices(89.0); 34679 m.incrperturbvertices(b->epsilon); 34680 m.delaunizesegments(); 34681 if (m.checkpbcs) { 34682 long oldnum; 34683 do { 34684 oldnum = m.points->items; 34685 m.incrperturbvertices(b->epsilon); 34686 if (m.points->items > oldnum) { 34687 oldnum = m.points->items; 34688 m.delaunizesegments(); 34689 } 34690 } while (oldnum < m.points->items); 34691 } 34692 m.constrainedfacets(); 34693 } else { 34694 m.detectinterfaces(); 34695 } 34696 } 34697 34698 tv[4] = clock(); 34699 34700 if (!b->quiet) { 34701 if (b->useshelles && !b->refine) { 34702 if (b->diagnose != 1) { 34703 printf("Segment and facet "); 34704 } else { 34705 printf("Intersection "); 34706 } 34707 printf("seconds: %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC); 34708 } 34709 } 34710 34711 if (b->plc && !(b->diagnose == 1)) { 34712 m.carveholes(); 34713 } 34714 34715 tv[5] = clock(); 34716 34717 if (!b->quiet) { 34718 if (b->plc && !(b->diagnose == 1)) { 34719 printf("Hole seconds: %g\n", (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC); 34720 } 34721 } 34722 34723 if ((b->plc || b->refine) && !(b->diagnose == 1)) { 34724 m.optimizemesh(false); 34725 } 34726 34727 tv[6] = clock(); 34728 34729 if (!b->quiet) { 34730 if ((b->plc || b->refine) && !(b->diagnose == 1)) { 34731 printf("Repair seconds: %g\n", (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC); 34732 } 34733 } 34734 34735 if ((b->plc && b->nobisect) && !(b->diagnose == 1)) { 34736 m.removesteiners(false); 34737 } 34738 34739 tv[7] = clock(); 34740 34741 if (!b->quiet) { 34742 if ((b->plc && b->nobisect) && !(b->diagnose == 1)) { 34743 printf("Steiner removal seconds: %g\n", 34744 (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC); 34745 } 34746 } 34747 34748 if (b->insertaddpoints && (addin != (tetgenio *) NULL)) { 34749 if (addin->numberofpoints > 0) { 34750 m.insertconstrainedpoints(addin); 34751 } 34752 } 34753 34754 tv[8] = clock(); 34755 34756 if (!b->quiet) { 34757 if ((b->plc || b->refine) && (b->insertaddpoints)) { 34758 printf("Constrained points seconds: %g\n", 34759 (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC); 34760 } 34761 } 34762 34763 if (b->metric) { 34764 m.interpolatesizemap(); 34765 } 34766 34767 tv[9] = clock(); 34768 34769 if (!b->quiet) { 34770 if (b->metric) { 34771 printf("Size interpolating seconds: %g\n", 34772 (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC); 34773 } 34774 } 34775 34776 if (b->coarse) { 34777 m.removesteiners(true); 34778 } 34779 34780 tv[10] = clock(); 34781 34782 if (!b->quiet) { 34783 if (b->coarse) { 34784 printf("Mesh coarsening seconds: %g\n", 34785 (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC); 34786 } 34787 } 34788 34789 if (b->quality) { 34790 m.enforcequality(); 34791 } 34792 34793 tv[11] = clock(); 34794 34795 if (!b->quiet) { 34796 if (b->quality) { 34797 printf("Quality seconds: %g\n", 34798 (tv[11] - tv[10]) / (REAL) CLOCKS_PER_SEC); 34799 } 34800 } 34801 34802 if (b->quality && (b->optlevel > 0)) { 34803 m.optimizemesh(true); 34804 } 34805 34806 tv[12] = clock(); 34807 34808 if (!b->quiet) { 34809 if (b->quality && (b->optlevel > 0)) { 34810 printf("Optimize seconds: %g\n", 34811 (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC); 34812 } 34813 } 34814 34815 if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0) 34816 || (b->refine && (in->numberofcorners == 10)))) { 34817 m.jettisonnodes(); 34818 } 34819 34820 if (b->order > 1) { 34821 m.highorder(); 34822 } 34823 34824 if (!b->quiet) { 34825 printf("\n"); 34826 } 34827 34828 if (out != (tetgenio *) NULL) { 34829 out->firstnumber = in->firstnumber; 34830 out->mesh_dim = in->mesh_dim; 34831 } 34832 34833 if (b->nonodewritten || b->noiterationnum) { 34834 if (!b->quiet) { 34835 printf("NOT writing a .node file.\n"); 34836 } 34837 } else { 34838 if (b->diagnose == 1) { 34839 if (m.subfaces->items > 0l) { 34840 m.outnodes(out); // Only output when self-intersecting faces exist. 34841 } 34842 } else { 34843 m.outnodes(out); 34844 if (b->quality || b->metric) { 34845 // m.outmetrics(out); 34846 } 34847 } 34848 } 34849 34850 if (b->noelewritten) { 34851 if (!b->quiet) { 34852 printf("NOT writing an .ele file.\n"); 34853 } 34854 } else { 34855 if (!(b->diagnose == 1)) { 34856 if (m.tetrahedrons->items > 0l) { 34857 m.outelements(out); 34858 } 34859 } 34860 } 34861 34862 if (b->nofacewritten) { 34863 if (!b->quiet) { 34864 printf("NOT writing an .face file.\n"); 34865 } 34866 } else { 34867 if (b->facesout) { 34868 if (m.tetrahedrons->items > 0l) { 34869 m.outfaces(out); // Output all faces. 34870 } 34871 } else { 34872 if (b->diagnose == 1) { 34873 if (m.subfaces->items > 0l) { 34874 m.outsubfaces(out); // Only output self-intersecting faces. 34875 } 34876 } else if (b->plc || b->refine) { 34877 if (m.subfaces->items > 0l) { 34878 m.outsubfaces(out); // Output boundary faces. 34879 } 34880 } else { 34881 if (m.tetrahedrons->items > 0l) { 34882 m.outhullfaces(out); // Output convex hull faces. 34883 } 34884 } 34885 } 34886 } 34887 34888 if (m.checkpbcs) { 34889 m.outpbcnodes(out); 34890 } 34891 34892 if (b->edgesout) { 34893 if (b->edgesout > 1) { 34894 m.outedges(out); // -ee, output all mesh edges. 34895 } else { 34896 m.outsubsegments(out); // -e, only output subsegments. 34897 } 34898 } 34899 34900 if (!out && b->plc && 34901 ((b->object == tetgenbehavior::OFF) || 34902 (b->object == tetgenbehavior::PLY) || 34903 (b->object == tetgenbehavior::STL))) { 34904 m.outsmesh(b->outfilename); 34905 } 34906 34907 if (!out && b->meditview) { 34908 m.outmesh2medit(b->outfilename); 34909 } 34910 34911 if (!out && b->gidview) { 34912 m.outmesh2gid(b->outfilename); 34913 } 34914 34915 if (!out && b->geomview) { 34916 m.outmesh2off(b->outfilename); 34917 } 34918 34919 if (b->neighout) { 34920 m.outneighbors(out); 34921 } 34922 34923 if (b->voroout) { 34924 m.outvoronoi(out); 34925 } 34926 34927 tv[13] = clock(); 34928 34929 if (!b->quiet) { 34930 printf("\nOutput seconds: %g\n", 34931 (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC); 34932 printf("Total running seconds: %g\n", 34933 (tv[13] - tv[0]) / (REAL) CLOCKS_PER_SEC); 34934 } 34935 34936 if (b->docheck) { 34937 m.checkmesh(); 34938 if (m.checksubfaces) { 34939 m.checkshells(); 34940 } 34941 if (b->docheck > 1) { 34942 m.checkdelaunay(0.0, NULL); 34943 if (b->docheck > 2) { 34944 if (b->quality || b->refine) { 34945 m.checkconforming(); 34946 } 34947 } 34948 } 34949 } 34950 34951 if (!b->quiet) { 34952 m.statistics(); 34953 } 34954 34955 if (b->metric) { 34956 delete m.bgm; 34957 } 34958 } 34959 34960 #ifndef TETLIBRARY 34961 34963 // // 34964 // main() The entrance for running TetGen from command line. // 34965 // // 34967 34968 int main(int argc, char *argv[]) 34969 34970 #else // with TETLIBRARY 34971 34973 // // 34974 // tetrahedralize() The entrance for calling TetGen from another program. // 34975 // // 34977 34978 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out, 34979 tetgenio *addin, tetgenio *bgmin) 34980 34981 #endif // not TETLIBRARY 34982 34983 { 34984 tetgenbehavior b; 34985 34986 #ifndef TETLIBRARY 34987 34988 tetgenio in, addin, bgmin; 34989 34990 if (!b.parse_commandline(argc, argv)) { 34991 terminatetetgen(1); 34992 } 34993 if (b.refine) { 34994 if (!in.load_tetmesh(b.infilename)) { 34995 terminatetetgen(1); 34996 } 34997 } else { 34998 if (!in.load_plc(b.infilename, (int) b.object)) { 34999 terminatetetgen(1); 35000 } 35001 } 35002 if (b.insertaddpoints) { 35003 if (!addin.load_node(b.addinfilename)) { 35004 addin.numberofpoints = 0l; 35005 } 35006 } 35007 if (b.metric) { 35008 if (!bgmin.load_tetmesh(b.bgmeshfilename)) { 35009 bgmin.numberoftetrahedra = 0l; 35010 } 35011 } 35012 35013 if (bgmin.numberoftetrahedra > 0l) { 35014 tetrahedralize(&b, &in, NULL, &addin, &bgmin); 35015 } else { 35016 tetrahedralize(&b, &in, NULL, &addin, NULL); 35017 } 35018 35019 return 0; 35020 35021 #else // with TETLIBRARY 35022 35023 if (!b.parse_commandline(switches)) { 35024 terminatetetgen(1); 35025 } 35026 tetrahedralize(&b, in, out, addin, bgmin); 35027 35028 #endif // not TETLIBRARY 35029 } 35030 35031 } //Added namespace to avoid clash with triangle 35032 35033 #ifndef TETLIBRARY 35034 // Shim for entry point to main inside the namespace. This is just in case we want to compile up a binary from this 35035 // source code. 35036 int main(int argc, char *argv[]) 35037 { 35038 tetgen::main(argc, argv); 35039 } 35040 #endif // not TETLIBRARY