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.