Chaste Commit::8b5d759ac2eb95e67ae57699734101efccb0a0a9
tetgen.cpp
Go to the documentation of this file.
1
7#ifndef UNUSED_OPT
8#ifdef NDEBUG
9#define UNUSED_OPT(var) var=var
10#else //NDEBUG
11#define UNUSED_OPT(var)
12#endif //NDEBUG
13#endif //UNUSED_OPT
14
15// This include is here so that the chaste_libs=0 build correctly links predicates.o.
16#include "predicates.hpp"
17
19// //
20// TetGen //
21// //
22// A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator //
23// //
24// Version 1.4 //
25// April 16, 2007 //
26// //
27// Copyright (C) 2002--2007 //
28// Hang Si //
29// Research Group Numerical Mathematics and Scientific Computing //
30// Weierstrass Institute for Applied Analysis and Stochastics //
31// Mohrenstr. 39, 10117 Berlin, Germany //
32// si@wias-berlin.de //
33// //
34// TetGen is freely available through the website: http://tetgen.berlios.de. //
35// It may be copied, modified, and redistributed for non-commercial use. //
36// Please consult the file LICENSE for the detailed copyright notices. //
37// //
39
41// //
42// tetgen.cxx //
43// //
44// The TetGen library and program. //
45// //
47
48#include "tetgen.h"
49namespace tetgen
50{ //Added namespace to avoid clash with triangle
51
53// //
54// terminatetetgen() Terminate TetGen with a given exit code. //
55// //
57
58void terminatetetgen(int x)
59{
60#ifdef TETLIBRARY
61 throw x;
62#else
63 exit(x);
64#endif // #ifdef TETLIBRARY
65}
66
67//
68// Begin of class 'tetgenio' implementation
69//
70
72// //
73// initialize() Initialize all variables of 'tetgenio'. //
74// //
75// It is called by the only class constructor 'tetgenio()' implicitly. Thus, //
76// all variables are guaranteed to be initialized. Each array is initialized //
77// to be a 'NULL' pointer, and its length is equal zero. Some variables have //
78// their default value, 'firstnumber' equals zero, 'mesh_dim' equals 3, and //
79// 'numberofcorners' equals 4. Another possible use of this routine is to //
80// call it before to re-use an object. //
81// //
83
84void tetgenio::initialize()
85{
86 firstnumber = 0; // Default item index is numbered from Zero.
87 mesh_dim = 3; // Default mesh dimension is 3.
88 useindex = true;
89
90 pointlist = (REAL *) NULL;
91 pointattributelist = (REAL *) NULL;
92 pointmtrlist = (REAL *) NULL;
93 pointmarkerlist = (int *) NULL;
94 numberofpoints = 0;
95 numberofpointattributes = 0;
96 numberofpointmtrs = 0;
97
98 tetrahedronlist = (int *) NULL;
99 tetrahedronattributelist = (REAL *) NULL;
100 tetrahedronvolumelist = (REAL *) NULL;
101 neighborlist = (int *) NULL;
102 numberoftetrahedra = 0;
103 numberofcorners = 4; // Default is 4 nodes per element.
104 numberoftetrahedronattributes = 0;
105
106 trifacelist = (int *) NULL;
107 adjtetlist = (int *) NULL;
108 trifacemarkerlist = (int *) NULL;
109 numberoftrifaces = 0;
110
111 facetlist = (facet *) NULL;
112 facetmarkerlist = (int *) NULL;
113 numberoffacets = 0;
114
115 edgelist = (int *) NULL;
116 edgemarkerlist = (int *) NULL;
117 numberofedges = 0;
118
119 holelist = (REAL *) NULL;
120 numberofholes = 0;
121
122 regionlist = (REAL *) NULL;
123 numberofregions = 0;
124
125 facetconstraintlist = (REAL *) NULL;
126 numberoffacetconstraints = 0;
127 segmentconstraintlist = (REAL *) NULL;
128 numberofsegmentconstraints = 0;
129
130 pbcgrouplist = (pbcgroup *) NULL;
131 numberofpbcgroups = 0;
132
133 vpointlist = (REAL *) NULL;
134 vedgelist = (voroedge *) NULL;
135 vfacetlist = (vorofacet *) NULL;
136 vcelllist = (int **) NULL;
137 numberofvpoints = 0;
138 numberofvedges = 0;
139 numberofvfacets = 0;
140 numberofvcells = 0;
141}
142
144// //
145// deinitialize() Free the memory allocated in 'tetgenio'. //
146// //
147// It is called by the class destructor '~tetgenio()' implicitly. Hence, the //
148// occupied memory by arrays of an object will be automatically released on //
149// the deletion of the object. However, this routine assumes that the memory //
150// is allocated by C++ memory allocation operator 'new', thus it is freed by //
151// the C++ array deletor 'delete []'. If one uses the C/C++ library function //
152// 'malloc()' to allocate memory for arrays, one has to free them with the //
153// 'free()' function, and call routine 'initialize()' once to disable this //
154// routine on deletion of the object. //
155// //
157
158void tetgenio::deinitialize()
159{
160 facet *f;
161 polygon *p;
162 pbcgroup *pg;
163 int i, j;
164
165 if (pointlist != (REAL *) NULL) {
166 delete [] pointlist;
167 }
168 if (pointattributelist != (REAL *) NULL) {
169 delete [] pointattributelist;
170 }
171 if (pointmtrlist != (REAL *) NULL) {
172 delete [] pointmtrlist;
173 }
174 if (pointmarkerlist != (int *) NULL) {
175 delete [] pointmarkerlist;
176 }
177
178 if (tetrahedronlist != (int *) NULL) {
179 delete [] tetrahedronlist;
180 }
181 if (tetrahedronattributelist != (REAL *) NULL) {
182 delete [] tetrahedronattributelist;
183 }
184 if (tetrahedronvolumelist != (REAL *) NULL) {
185 delete [] tetrahedronvolumelist;
186 }
187 if (neighborlist != (int *) NULL) {
188 delete [] neighborlist;
189 }
190
191 if (trifacelist != (int *) NULL) {
192 delete [] trifacelist;
193 }
194 if (adjtetlist != (int *) NULL) {
195 delete [] adjtetlist;
196 }
197 if (trifacemarkerlist != (int *) NULL) {
198 delete [] trifacemarkerlist;
199 }
200
201 if (edgelist != (int *) NULL) {
202 delete [] edgelist;
203 }
204 if (edgemarkerlist != (int *) NULL) {
205 delete [] edgemarkerlist;
206 }
207
208 if (facetlist != (facet *) NULL) {
209 for (i = 0; i < numberoffacets; i++) {
210 f = &facetlist[i];
211 for (j = 0; j < f->numberofpolygons; j++) {
212 p = &f->polygonlist[j];
213 delete [] p->vertexlist;
214 }
215 delete [] f->polygonlist;
216 if (f->holelist != (REAL *) NULL) {
217 delete [] f->holelist;
218 }
219 }
220 delete [] facetlist;
221 }
222 if (facetmarkerlist != (int *) NULL) {
223 delete [] facetmarkerlist;
224 }
225
226 if (holelist != (REAL *) NULL) {
227 delete [] holelist;
228 }
229 if (regionlist != (REAL *) NULL) {
230 delete [] regionlist;
231 }
232 if (facetconstraintlist != (REAL *) NULL) {
233 delete [] facetconstraintlist;
234 }
235 if (segmentconstraintlist != (REAL *) NULL) {
236 delete [] segmentconstraintlist;
237 }
238 if (pbcgrouplist != (pbcgroup *) NULL) {
239 for (i = 0; i < numberofpbcgroups; i++) {
240 pg = &(pbcgrouplist[i]);
241 if (pg->pointpairlist != (int *) NULL) {
242 delete [] pg->pointpairlist;
243 }
244 }
245 delete [] pbcgrouplist;
246 }
247 if (vpointlist != (REAL *) NULL) {
248 delete [] vpointlist;
249 }
250 if (vedgelist != (voroedge *) NULL) {
251 delete [] vedgelist;
252 }
253 if (vfacetlist != (vorofacet *) NULL) {
254 for (i = 0; i < numberofvfacets; i++) {
255 delete [] vfacetlist[i].elist;
256 }
257 delete [] vfacetlist;
258 }
259 if (vcelllist != (int **) NULL) {
260 for (i = 0; i < numberofvcells; i++) {
261 delete [] vcelllist[i];
262 }
263 delete [] vcelllist;
264 }
265}
266
268// //
269// load_node_call() Load a list of nodes. //
270// //
271// It is a support routine for routines: 'load_nodes()', 'load_poly()', and //
272// 'load_tetmesh()'. 'infile' is the file handle contains the node list. It //
273// may point to a .node, or .poly or .smesh file. 'markers' indicates each //
274// node contains an additional marker (integer) or not. 'infilename' is the //
275// name of the file being read, it is only appeared in error message. //
276// //
277// The 'firstnumber' (0 or 1) is automatically determined by the number of //
278// the first index of the first point. //
279// //
281
282bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename)
283{
284 char inputline[INPUTLINESIZE];
285 char *stringptr;
286 REAL x, y, z, attrib;
287 int firstnode, currentmarker;
288 int index, attribindex;
289 int i, j;
290
291 // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
292 pointlist = new REAL[numberofpoints * 3];
293 if (pointlist == (REAL *) NULL) {
294 printf("Error: Out of memory.\n");
295 terminatetetgen(1);
296 }
297 if (numberofpointattributes > 0) {
298 pointattributelist = new REAL[numberofpoints * numberofpointattributes];
299 if (pointattributelist == (REAL *) NULL) {
300 printf("Error: Out of memory.\n");
301 terminatetetgen(1);
302 }
303 }
304 if (markers) {
305 pointmarkerlist = new int[numberofpoints];
306 if (pointmarkerlist == (int *) NULL) {
307 printf("Error: Out of memory.\n");
308 terminatetetgen(1);
309 }
310 }
311
312 // Read the point section.
313 index = 0;
314 attribindex = 0;
315 for (i = 0; i < numberofpoints; i++) {
316 stringptr = readnumberline(inputline, infile, infilename);
317 if (useindex) {
318 if (i == 0) {
319 firstnode = (int) strtol (stringptr, &stringptr, 0);
320 if ((firstnode == 0) || (firstnode == 1)) {
321 firstnumber = firstnode;
322 }
323 }
324 stringptr = findnextnumber(stringptr);
325 } // if (useindex)
326 if (*stringptr == '\0') {
327 printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
328 break;
329 }
330 x = (REAL) strtod(stringptr, &stringptr);
331 stringptr = findnextnumber(stringptr);
332 if (*stringptr == '\0') {
333 printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
334 break;
335 }
336 y = (REAL) strtod(stringptr, &stringptr);
337 if (mesh_dim == 3) {
338 stringptr = findnextnumber(stringptr);
339 if (*stringptr == '\0') {
340 printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
341 break;
342 }
343 z = (REAL) strtod(stringptr, &stringptr);
344 } else {
345 z = 0.0; // mesh_dim == 2;
346 }
347 pointlist[index++] = x;
348 pointlist[index++] = y;
349 pointlist[index++] = z;
350 // Read the point attributes.
351 for (j = 0; j < numberofpointattributes; j++) {
352 stringptr = findnextnumber(stringptr);
353 if (*stringptr == '\0') {
354 attrib = 0.0;
355 } else {
356 attrib = (REAL) strtod(stringptr, &stringptr);
357 }
358 pointattributelist[attribindex++] = attrib;
359 }
360 if (markers) {
361 // Read a point marker.
362 stringptr = findnextnumber(stringptr);
363 if (*stringptr == '\0') {
364 currentmarker = 0;
365 } else {
366 currentmarker = (int) strtol (stringptr, &stringptr, 0);
367 }
368 pointmarkerlist[i] = currentmarker;
369 }
370 }
371 if (i < numberofpoints) {
372 // Failed to read points due to some error.
373 delete [] pointlist;
374 pointlist = (REAL *) NULL;
375 if (markers) {
376 delete [] pointmarkerlist;
377 pointmarkerlist = (int *) NULL;
378 }
379 if (numberofpointattributes > 0) {
380 delete [] pointattributelist;
381 pointattributelist = (REAL *) NULL;
382 }
383 numberofpoints = 0;
384 return false;
385 }
386 return true;
387}
388
390// //
391// load_node() Load a list of nodes from a .node file. //
392// //
393// 'filename' is the inputfile without suffix. The node list is in 'filename.//
394// node'. On completion, the node list is returned in 'pointlist'. //
395// //
397
398bool tetgenio::load_node(char* filename)
399{
400 FILE *infile;
401 char innodefilename[FILENAMESIZE];
402 char inputline[INPUTLINESIZE];
403 char *stringptr;
404 int markers;
405
406 markers = 0;
407 // Assembling the actual file names we want to open.
408 strcpy(innodefilename, filename);
409 strcat(innodefilename, ".node");
410
411 // Try to open a .node file.
412 infile = fopen(innodefilename, "r");
413 if (infile == (FILE *) NULL) {
414 printf("File I/O Error: Cannot access file %s.\n", innodefilename);
415 return false;
416 }
417 printf("Opening %s.\n", innodefilename);
418 // Read the first line of the file.
419 stringptr = readnumberline(inputline, infile, innodefilename);
420 // Is this list of points generated from rbox?
421 stringptr = strstr(inputline, "rbox");
422 if (stringptr == NULL) {
423 // Read number of points, number of dimensions, number of point
424 // attributes, and number of boundary markers.
425 stringptr = inputline;
426 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
427 stringptr = findnextnumber(stringptr);
428 if (*stringptr == '\0') {
429 mesh_dim = 3;
430 } else {
431 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
432 }
433 stringptr = findnextnumber(stringptr);
434 if (*stringptr == '\0') {
435 numberofpointattributes = 0;
436 } else {
437 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
438 }
439 stringptr = findnextnumber(stringptr);
440 if (*stringptr == '\0') {
441 markers = 0;
442 } else {
443 markers = (int) strtol (stringptr, &stringptr, 0);
444 }
445 } else {
446 // It is a rbox (qhull) input file.
447 stringptr = inputline;
448 // Get the dimension.
449 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
450 // Get the number of points.
451 stringptr = readnumberline(inputline, infile, innodefilename);
452 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
453 // There is no index column.
454 useindex = 0;
455 }
456
457 // if ((mesh_dim != 3) && (mesh_dim != 2)) {
458 // printf("Input error: TetGen only works for 2D & 3D point sets.\n");
459 // fclose(infile);
460 // return false;
461 // }
462 if (numberofpoints < (mesh_dim + 1)) {
463 printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
464 fclose(infile);
465 return false;
466 }
467
468 // Load the list of nodes.
469 if (!load_node_call(infile, markers, innodefilename)) {
470 fclose(infile);
471 return false;
472 }
473 fclose(infile);
474 return true;
475}
476
478// //
479// load_pbc() Load a list of pbc groups into 'pbcgrouplist'. //
480// //
481// 'filename' is the filename of the original inputfile without suffix. The //
482// pbc groups are found in file 'filename.pbc'. //
483// //
484// This routine will be called both in load_poly() and load_tetmesh(). //
485// //
487
488bool tetgenio::load_pbc(char* filename)
489{
490 FILE *infile;
491 char pbcfilename[FILENAMESIZE];
492 char inputline[INPUTLINESIZE];
493 char *stringptr;
494 pbcgroup *pg;
495 int index, p1, p2;
496 int i, j, k;
497
498 // Pbc groups are saved in file "filename.pbc".
499 strcpy(pbcfilename, filename);
500 strcat(pbcfilename, ".pbc");
501 infile = fopen(pbcfilename, "r");
502 if (infile != (FILE *) NULL) {
503 printf("Opening %s.\n", pbcfilename);
504 } else {
505 // No such file. Return.
506 return false;
507 }
508
509 // Read the number of pbc groups.
510 stringptr = readnumberline(inputline, infile, pbcfilename);
511 numberofpbcgroups = (int) strtol (stringptr, &stringptr, 0);
512 if (numberofpbcgroups == 0) {
513 // It looks this file contains no point.
514 fclose(infile);
515 return false;
516 }
517 // Initialize 'pbcgrouplist';
518 pbcgrouplist = new pbcgroup[numberofpbcgroups];
519
520 // Read the list of pbc groups.
521 for (i = 0; i < numberofpbcgroups; i++) {
522 pg = &(pbcgrouplist[i]);
523 // Initialize pbcgroup i;
524 pg->numberofpointpairs = 0;
525 pg->pointpairlist = (int *) NULL;
526 // Read 'fmark1', 'fmark2'.
527 stringptr = readnumberline(inputline, infile, pbcfilename);
528 if (*stringptr == '\0') break;
529 pg->fmark1 = (int) strtol(stringptr, &stringptr, 0);
530 stringptr = findnextnumber(stringptr);
531 if (*stringptr == '\0') break;
532 pg->fmark2 = (int) strtol(stringptr, &stringptr, 0);
533 // Read 'transmat'.
534 do {
535 stringptr = readline(inputline, infile, NULL);
536 } while ((*stringptr != '[') && (*stringptr != '\0'));
537 if (*stringptr == '\0') break;
538 for (j = 0; j < 4; j++) {
539 for (k = 0; k < 4; k++) {
540 // Read the entry of [j, k].
541 stringptr = findnextnumber(stringptr);
542 if (*stringptr == '\0') {
543 // Try to read another line.
544 stringptr = readnumberline(inputline, infile, pbcfilename);
545 if (*stringptr == '\0') break;
546 }
547 pg->transmat[j][k] = (REAL) strtod(stringptr, &stringptr);
548 }
549 if (k < 4) break; // Not complete!
550 }
551 if (j < 4) break; // Not complete!
552 // Read 'numberofpointpairs'.
553 stringptr = readnumberline(inputline, infile, pbcfilename);
554 if (*stringptr == '\0') break;
555 pg->numberofpointpairs = (int) strtol(stringptr, &stringptr, 0);
556 if (pg->numberofpointpairs > 0) {
557 pg->pointpairlist = new int[pg->numberofpointpairs * 2];
558 // Read the point pairs.
559 index = 0;
560 for (j = 0; j < pg->numberofpointpairs; j++) {
561 stringptr = readnumberline(inputline, infile, pbcfilename);
562 p1 = (int) strtol(stringptr, &stringptr, 0);
563 stringptr = findnextnumber(stringptr);
564 p2 = (int) strtol(stringptr, &stringptr, 0);
565 pg->pointpairlist[index++] = p1;
566 pg->pointpairlist[index++] = p2;
567 }
568 }
569 }
570 fclose(infile);
571
572 if (i < numberofpbcgroups) {
573 // Failed to read to additional points due to some error.
574 delete [] pbcgrouplist;
575 pbcgrouplist = (pbcgroup *) NULL;
576 numberofpbcgroups = 0;
577 return false;
578 }
579 return true;
580}
581
583// //
584// load_var() Load variant constraints applied on facets, segments, nodes.//
585// //
586// 'filename' is the filename of the original inputfile without suffix. The //
587// constraints are found in file 'filename.var'. //
588// //
590
591bool tetgenio::load_var(char* filename)
592{
593 FILE *infile;
594 char varfilename[FILENAMESIZE];
595 char inputline[INPUTLINESIZE];
596 char *stringptr;
597 int index;
598 int i;
599
600 // Variant constraints are saved in file "filename.var".
601 strcpy(varfilename, filename);
602 strcat(varfilename, ".var");
603 infile = fopen(varfilename, "r");
604 if (infile != (FILE *) NULL) {
605 printf("Opening %s.\n", varfilename);
606 } else {
607 // No such file. Return.
608 return false;
609 }
610
611 // Read the facet constraint section.
612 stringptr = readnumberline(inputline, infile, varfilename);
613 if (*stringptr != '\0') {
614 numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
615 } else {
616 numberoffacetconstraints = 0;
617 }
618 if (numberoffacetconstraints > 0) {
619 // Initialize 'facetconstraintlist'.
620 facetconstraintlist = new REAL[numberoffacetconstraints * 2];
621 index = 0;
622 for (i = 0; i < numberoffacetconstraints; i++) {
623 stringptr = readnumberline(inputline, infile, varfilename);
624 stringptr = findnextnumber(stringptr);
625 if (*stringptr == '\0') {
626 printf("Error: facet constraint %d has no facet marker.\n",
627 firstnumber + i);
628 break;
629 } else {
630 facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
631 }
632 stringptr = findnextnumber(stringptr);
633 if (*stringptr == '\0') {
634 printf("Error: facet constraint %d has no maximum area bound.\n",
635 firstnumber + i);
636 break;
637 } else {
638 facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
639 }
640 }
641 if (i < numberoffacetconstraints) {
642 // This must be caused by an error.
643 fclose(infile);
644 return false;
645 }
646 }
647
648 // Read the segment constraint section.
649 stringptr = readnumberline(inputline, infile, varfilename);
650 if (*stringptr != '\0') {
651 numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
652 } else {
653 numberofsegmentconstraints = 0;
654 }
655 if (numberofsegmentconstraints > 0) {
656 // Initialize 'segmentconstraintlist'.
657 segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
658 index = 0;
659 for (i = 0; i < numberofsegmentconstraints; i++) {
660 stringptr = readnumberline(inputline, infile, varfilename);
661 stringptr = findnextnumber(stringptr);
662 if (*stringptr == '\0') {
663 printf("Error: segment constraint %d has no frist endpoint.\n",
664 firstnumber + i);
665 break;
666 } else {
667 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
668 }
669 stringptr = findnextnumber(stringptr);
670 if (*stringptr == '\0') {
671 printf("Error: segment constraint %d has no second endpoint.\n",
672 firstnumber + i);
673 break;
674 } else {
675 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
676 }
677 stringptr = findnextnumber(stringptr);
678 if (*stringptr == '\0') {
679 printf("Error: segment constraint %d has no maximum length bound.\n",
680 firstnumber + i);
681 break;
682 } else {
683 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
684 }
685 }
686 if (i < numberofsegmentconstraints) {
687 // This must be caused by an error.
688 fclose(infile);
689 return false;
690 }
691 }
692
693 fclose(infile);
694 return true;
695}
696
698// //
699// load_mtr() Load a size specification map from file. //
700// //
701// 'filename' is the filename of the original inputfile without suffix. The //
702// size map is found in file 'filename.mtr'. //
703// //
705
706bool tetgenio::load_mtr(char* filename)
707{
708 FILE *infile;
709 char mtrfilename[FILENAMESIZE];
710 char inputline[INPUTLINESIZE];
711 char *stringptr;
712 REAL mtr;
713 int mtrindex;
714 int i, j;
715
716 strcpy(mtrfilename, filename);
717 strcat(mtrfilename, ".mtr");
718 infile = fopen(mtrfilename, "r");
719 if (infile != (FILE *) NULL) {
720 printf("Opening %s.\n", mtrfilename);
721 } else {
722 // No such file. Return.
723 return false;
724 }
725
726 // Read number of points, number of columns (1, 3, or 6).
727 stringptr = readnumberline(inputline, infile, mtrfilename);
728 stringptr = findnextnumber(stringptr); // Skip number of points.
729 if (*stringptr != '\0') {
730 numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
731 }
732 if (numberofpointmtrs == 0) {
733 // Column number doesn't match. Set a default number (1).
734 numberofpointmtrs = 1;
735 }
736
737 // Allocate space for pointmtrlist.
738 pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
739 if (pointmtrlist == (REAL *) NULL) {
740 printf("Error: Out of memory.\n");
741 terminatetetgen(1);
742 }
743 mtrindex = 0;
744 for (i = 0; i < numberofpoints; i++) {
745 // Read metrics.
746 stringptr = readnumberline(inputline, infile, mtrfilename);
747 for (j = 0; j < numberofpointmtrs; j++) {
748 if (*stringptr == '\0') {
749 printf("Error: Metric %d is missing value #%d in %s.\n",
750 i + firstnumber, j + 1, mtrfilename);
751 terminatetetgen(1);
752 }
753 mtr = (REAL) strtod(stringptr, &stringptr);
754 pointmtrlist[mtrindex++] = mtr;
755 stringptr = findnextnumber(stringptr);
756 }
757 }
758
759 fclose(infile);
760 return true;
761}
762
764// //
765// load_poly() Load a piecewise linear complex from a .poly or .smesh. //
766// //
767// 'filename' is the inputfile without suffix. The PLC is in 'filename.poly' //
768// or 'filename.smesh', and possibly plus 'filename.node' (when the first //
769// line of the file starts with a zero). //
770// //
772
773bool tetgenio::load_poly(char* filename)
774{
775 FILE *infile, *polyfile;
776 char innodefilename[FILENAMESIZE];
777 char inpolyfilename[FILENAMESIZE];
778 char insmeshfilename[FILENAMESIZE];
779 char inputline[INPUTLINESIZE];
780 char *stringptr, *infilename;
781 int smesh, markers, currentmarker;
782 int readnodefile, index;
783 int i, j, k;
784
785 // Assembling the actual file names we want to open.
786 strcpy(innodefilename, filename);
787 strcpy(inpolyfilename, filename);
788 strcpy(insmeshfilename, filename);
789 strcat(innodefilename, ".node");
790 strcat(inpolyfilename, ".poly");
791 strcat(insmeshfilename, ".smesh");
792
793 // First assume it is a .poly file.
794 smesh = 0;
795 // Try to open a .poly file.
796 polyfile = fopen(inpolyfilename, "r");
797 if (polyfile == (FILE *) NULL) {
798 // .poly doesn't exist! Try to open a .smesh file.
799 polyfile = fopen(insmeshfilename, "r");
800 if (polyfile == (FILE *) NULL) {
801 printf("File I/O Error: Cannot access file %s and %s.\n",
802 inpolyfilename, insmeshfilename);
803 return false;
804 } else {
805 printf("Opening %s.\n", insmeshfilename);
806 }
807 smesh = 1;
808 } else {
809 printf("Opening %s.\n", inpolyfilename);
810 }
811 // Initialize the default values.
812 mesh_dim = 3; // Three-dimemsional accoordinates.
813 numberofpointattributes = 0; // no point attribute.
814 markers = 0; // no boundary marker.
815 // Read number of points, number of dimensions, number of point
816 // attributes, and number of boundary markers.
817 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
818 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
819 stringptr = findnextnumber(stringptr);
820 if (*stringptr != '\0') {
821 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
822 }
823 stringptr = findnextnumber(stringptr);
824 if (*stringptr != '\0') {
825 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
826 }
827 stringptr = findnextnumber(stringptr);
828 if (*stringptr != '\0') {
829 markers = (int) strtol (stringptr, &stringptr, 0);
830 }
831 if (numberofpoints > 0) {
832 readnodefile = 0;
833 if (smesh) {
834 infilename = insmeshfilename;
835 } else {
836 infilename = inpolyfilename;
837 }
838 infile = polyfile;
839 } else {
840 // If the .poly or .smesh file claims there are zero points, that
841 // means the points should be read from a separate .node file.
842 readnodefile = 1;
843 infilename = innodefilename;
844 }
845
846 if (readnodefile) {
847 // Read the points from the .node file.
848 printf("Opening %s.\n", innodefilename);
849 infile = fopen(innodefilename, "r");
850 if (infile == (FILE *) NULL) {
851 printf("File I/O Error: Cannot access file %s.\n", innodefilename);
852 return false;
853 }
854 // Initialize the default values.
855 mesh_dim = 3; // Three-dimemsional accoordinates.
856 numberofpointattributes = 0; // no point attribute.
857 markers = 0; // no boundary marker.
858 // Read number of points, number of dimensions, number of point
859 // attributes, and number of boundary markers.
860 stringptr = readnumberline(inputline, infile, innodefilename);
861 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
862 stringptr = findnextnumber(stringptr);
863 if (*stringptr != '\0') {
864 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
865 }
866 stringptr = findnextnumber(stringptr);
867 if (*stringptr != '\0') {
868 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
869 }
870 stringptr = findnextnumber(stringptr);
871 if (*stringptr != '\0') {
872 markers = (int) strtol (stringptr, &stringptr, 0);
873 }
874 }
875
876 if ((mesh_dim != 3) && (mesh_dim != 2)) {
877 printf("Input error: TetGen only works for 2D & 3D point sets.\n");
878 fclose(infile);
879 return false;
880 }
881 if (numberofpoints < (mesh_dim + 1)) {
882 printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
883 fclose(infile);
884 return false;
885 }
886
887 // Load the list of nodes.
888 if (!load_node_call(infile, markers, infilename)) {
889 fclose(infile);
890 return false;
891 }
892
893 if (readnodefile) {
894 fclose(infile);
895 }
896
897 facet *f;
898 polygon *p;
899
900 if (mesh_dim == 3) {
901
902 // Read number of facets and number of boundary markers.
903 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
904 numberoffacets = (int) strtol (stringptr, &stringptr, 0);
905 if (numberoffacets <= 0) {
906 // No facet list, return.
907 fclose(polyfile);
908 return true;
909 }
910 stringptr = findnextnumber(stringptr);
911 if (*stringptr == '\0') {
912 markers = 0; // no boundary marker.
913 } else {
914 markers = (int) strtol (stringptr, &stringptr, 0);
915 }
916
917 // Initialize the 'facetlist', 'facetmarkerlist'.
918 facetlist = new facet[numberoffacets];
919 if (markers == 1) {
920 facetmarkerlist = new int[numberoffacets];
921 }
922
923 // Read data into 'facetlist', 'facetmarkerlist'.
924 if (smesh == 0) {
925 // Facets are in .poly file format.
926 for (i = 1; i <= numberoffacets; i++) {
927 f = &(facetlist[i - 1]);
928 init(f);
929 f->numberofholes = 0;
930 currentmarker = 0;
931 // Read number of polygons, number of holes, and a boundary marker.
932 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
933 f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
934 stringptr = findnextnumber(stringptr);
935 if (*stringptr != '\0') {
936 f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
937 if (markers == 1) {
938 stringptr = findnextnumber(stringptr);
939 if (*stringptr != '\0') {
940 currentmarker = (int) strtol(stringptr, &stringptr, 0);
941 }
942 }
943 }
944 // Initialize facetmarker if it needs.
945 if (markers == 1) {
946 facetmarkerlist[i - 1] = currentmarker;
947 }
948 // Each facet should has at least one polygon.
949 if (f->numberofpolygons <= 0) {
950 printf("Error: Wrong number of polygon in %d facet.\n", i);
951 break;
952 }
953 // Initialize the 'f->polygonlist'.
954 f->polygonlist = new polygon[f->numberofpolygons];
955 // Go through all polygons, read in their vertices.
956 for (j = 1; j <= f->numberofpolygons; j++) {
957 p = &(f->polygonlist[j - 1]);
958 init(p);
959 // Read number of vertices of this polygon.
960 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
961 p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
962 if (p->numberofvertices < 1) {
963 printf("Error: Wrong polygon %d in facet %d\n", j, i);
964 break;
965 }
966 // Initialize 'p->vertexlist'.
967 p->vertexlist = new int[p->numberofvertices];
968 // Read all vertices of this polygon.
969 for (k = 1; k <= p->numberofvertices; k++) {
970 stringptr = findnextnumber(stringptr);
971 if (*stringptr == '\0') {
972 // Try to load another non-empty line and continue to read the
973 // rest of vertices.
974 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
975 if (*stringptr == '\0') {
976 printf("Error: Missing %d endpoints of polygon %d in facet %d",
977 p->numberofvertices - k, j, i);
978 break;
979 }
980 }
981 p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
982 }
983 }
984 if (j <= f->numberofpolygons) {
985 // This must be caused by an error. However, there're j - 1
986 // polygons have been read. Reset the 'f->numberofpolygon'.
987 if (j == 1) {
988 // This is the first polygon.
989 delete [] f->polygonlist;
990 }
991 f->numberofpolygons = j - 1;
992 // No hole will be read even it exists.
993 f->numberofholes = 0;
994 break;
995 }
996 // If this facet has hole pints defined, read them.
997 if (f->numberofholes > 0) {
998 // Initialize 'f->holelist'.
999 f->holelist = new REAL[f->numberofholes * 3];
1000 // Read the holes' coordinates.
1001 index = 0;
1002 for (j = 1; j <= f->numberofholes; j++) {
1003 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1004 for (k = 1; k <= 3; k++) {
1005 stringptr = findnextnumber(stringptr);
1006 if (*stringptr == '\0') {
1007 printf("Error: Hole %d in facet %d has no coordinates", j, i);
1008 break;
1009 }
1010 f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1011 }
1012 if (k <= 3) {
1013 // This must be caused by an error.
1014 break;
1015 }
1016 }
1017 if (j <= f->numberofholes) {
1018 // This must be caused by an error.
1019 break;
1020 }
1021 }
1022 }
1023 if (i <= numberoffacets) {
1024 // This must be caused by an error.
1025 numberoffacets = i - 1;
1026 fclose(polyfile);
1027 return false;
1028 }
1029 } else { // poly == 0
1030 // Read the facets from a .smesh file.
1031 for (i = 1; i <= numberoffacets; i++) {
1032 f = &(facetlist[i - 1]);
1033 init(f);
1034 // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1035 // contains exactly one polygon, no hole.
1036 f->numberofpolygons = 1;
1037 f->polygonlist = new polygon[f->numberofpolygons];
1038 p = &(f->polygonlist[0]);
1039 init(p);
1040 // Read number of vertices of this polygon.
1041 stringptr = readnumberline(inputline, polyfile, insmeshfilename);
1042 p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1043 if (p->numberofvertices < 1) {
1044 printf("Error: Wrong number of vertex in facet %d\n", i);
1045 break;
1046 }
1047 // Initialize 'p->vertexlist'.
1048 p->vertexlist = new int[p->numberofvertices];
1049 for (k = 1; k <= p->numberofvertices; k++) {
1050 stringptr = findnextnumber(stringptr);
1051 if (*stringptr == '\0') {
1052 // Try to load another non-empty line and continue to read the
1053 // rest of vertices.
1054 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1055 if (*stringptr == '\0') {
1056 printf("Error: Missing %d endpoints in facet %d",
1057 p->numberofvertices - k, i);
1058 break;
1059 }
1060 }
1061 p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1062 }
1063 if (k <= p->numberofvertices) {
1064 // This must be caused by an error.
1065 break;
1066 }
1067 // Read facet's boundary marker at last.
1068 if (markers == 1) {
1069 stringptr = findnextnumber(stringptr);
1070 if (*stringptr == '\0') {
1071 currentmarker = 0;
1072 } else {
1073 currentmarker = (int) strtol(stringptr, &stringptr, 0);
1074 }
1075 facetmarkerlist[i - 1] = currentmarker;
1076 }
1077 }
1078 if (i <= numberoffacets) {
1079 // This must be caused by an error.
1080 numberoffacets = i - 1;
1081 fclose(polyfile);
1082 return false;
1083 }
1084 }
1085
1086 // Read the hole section.
1087 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1088 if (*stringptr != '\0') {
1089 numberofholes = (int) strtol (stringptr, &stringptr, 0);
1090 } else {
1091 numberofholes = 0;
1092 }
1093 if (numberofholes > 0) {
1094 // Initialize 'holelist'.
1095 holelist = new REAL[numberofholes * 3];
1096 for (i = 0; i < 3 * numberofholes; i += 3) {
1097 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1098 stringptr = findnextnumber(stringptr);
1099 if (*stringptr == '\0') {
1100 printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
1101 break;
1102 } else {
1103 holelist[i] = (REAL) strtod(stringptr, &stringptr);
1104 }
1105 stringptr = findnextnumber(stringptr);
1106 if (*stringptr == '\0') {
1107 printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
1108 break;
1109 } else {
1110 holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1111 }
1112 stringptr = findnextnumber(stringptr);
1113 if (*stringptr == '\0') {
1114 printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
1115 break;
1116 } else {
1117 holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1118 }
1119 }
1120 if (i < 3 * numberofholes) {
1121 // This must be caused by an error.
1122 fclose(polyfile);
1123 return false;
1124 }
1125 }
1126
1127 // Read the region section. The 'region' section is optional, if we
1128 // don't reach the end-of-file, try read it in.
1129 stringptr = readnumberline(inputline, polyfile, NULL);
1130 if (stringptr != (char *) NULL && *stringptr != '\0') {
1131 numberofregions = (int) strtol (stringptr, &stringptr, 0);
1132 } else {
1133 numberofregions = 0;
1134 }
1135 if (numberofregions > 0) {
1136 // Initialize 'regionlist'.
1137 regionlist = new REAL[numberofregions * 5];
1138 index = 0;
1139 for (i = 0; i < numberofregions; i++) {
1140 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1141 stringptr = findnextnumber(stringptr);
1142 if (*stringptr == '\0') {
1143 printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
1144 break;
1145 } else {
1146 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1147 }
1148 stringptr = findnextnumber(stringptr);
1149 if (*stringptr == '\0') {
1150 printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
1151 break;
1152 } else {
1153 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1154 }
1155 stringptr = findnextnumber(stringptr);
1156 if (*stringptr == '\0') {
1157 printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
1158 break;
1159 } else {
1160 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1161 }
1162 stringptr = findnextnumber(stringptr);
1163 if (*stringptr == '\0') {
1164 printf("Error: Region %d has no region attrib.\n", firstnumber + i);
1165 break;
1166 } else {
1167 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1168 }
1169 stringptr = findnextnumber(stringptr);
1170 if (*stringptr == '\0') {
1171 regionlist[index] = regionlist[index - 1];
1172 } else {
1173 regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1174 }
1175 index++;
1176 }
1177 if (i < numberofregions) {
1178 // This must be caused by an error.
1179 fclose(polyfile);
1180 return false;
1181 }
1182 }
1183
1184 } else {
1185
1186 // Read a PSLG from Triangle's poly file.
1187 assert(mesh_dim == 2);
1188 // A PSLG is a facet of a PLC.
1189 numberoffacets = 1;
1190 // Initialize the 'facetlist'.
1191 facetlist = new facet[numberoffacets];
1192 facetmarkerlist = (int *) NULL; // No facet markers.
1193 f = &(facetlist[0]);
1194 init(f);
1195 // Read number of segments.
1196 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1197 // Segments are degenerate polygons.
1198 f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
1199 if (f->numberofpolygons > 0) {
1200 f->polygonlist = new polygon[f->numberofpolygons];
1201 }
1202 // Go through all segments, read in their vertices.
1203 for (j = 0; j < f->numberofpolygons; j++) {
1204 p = &(f->polygonlist[j]);
1205 init(p);
1206 // Read in a segment.
1207 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1208 stringptr = findnextnumber(stringptr); // Skip its index.
1209 p->numberofvertices = 2; // A segment always has two vertices.
1210 p->vertexlist = new int[p->numberofvertices];
1211 p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
1212 stringptr = findnextnumber(stringptr);
1213 p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
1214 }
1215 // Read number of holes.
1216 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1217 f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
1218 if (f->numberofholes > 0) {
1219 // Initialize 'f->holelist'.
1220 f->holelist = new REAL[f->numberofholes * 3];
1221 // Read the holes' coordinates.
1222 for (j = 0; j < f->numberofholes; j++) {
1223 // Read a 2D hole point.
1224 stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1225 stringptr = findnextnumber(stringptr); // Skip its index.
1226 f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
1227 stringptr = findnextnumber(stringptr);
1228 f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
1229 f->holelist[j * 3 + 2] = 0.0; // The z-coord.
1230 }
1231 }
1232 // The regions are skipped.
1233
1234 }
1235
1236 // End of reading poly/smesh file.
1237 fclose(polyfile);
1238
1239 // Try to load a .var file if it exists.
1240 load_var(filename);
1241 // Try to load a .mtr file if it exists.
1242 load_mtr(filename);
1243 // Try to read a .pbc file if it exists.
1244 load_pbc(filename);
1245
1246 return true;
1247}
1248
1250// //
1251// load_off() Load a polyhedron described in a .off file. //
1252// //
1253// The .off format is one of file formats of the Geomview, an interactive //
1254// program for viewing and manipulating geometric objects. More information //
1255// is available form: http://www.geomview.org. //
1256// //
1257// 'filename' is a input filename with extension .off or without extension ( //
1258// the .off will be added in this case). On completion, the polyhedron is //
1259// returned in 'pointlist' and 'facetlist'. //
1260// //
1262
1263bool tetgenio::load_off(char* filename)
1264{
1265 FILE *fp;
1266 tetgenio::facet *f;
1267 tetgenio::polygon *p;
1268 char infilename[FILENAMESIZE];
1269 char buffer[INPUTLINESIZE];
1270 char *bufferp;
1271 double *coord;
1272 int nverts = 0, iverts = 0;
1273 int nfaces = 0, ifaces = 0;
1274 int nedges = 0;
1275 int line_count = 0, i;
1276
1277 strncpy(infilename, filename, 1024 - 1);
1278 infilename[FILENAMESIZE - 1] = '\0';
1279 if (infilename[0] == '\0') {
1280 printf("Error: No filename.\n");
1281 return false;
1282 }
1283 if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1284 strcat(infilename, ".off");
1285 }
1286
1287 if (!(fp = fopen(infilename, "r"))) {
1288 printf("File I/O Error: Unable to open file %s\n", infilename);
1289 return false;
1290 }
1291 printf("Opening %s.\n", infilename);
1292
1293 // OFF requires the index starts from '0'.
1294 firstnumber = 0;
1295
1296 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1297 // Check section
1298 if (nverts == 0) {
1299 // Read header
1300 bufferp = strstr(bufferp, "OFF");
1301 if (bufferp != NULL) {
1302 // Read mesh counts
1303 bufferp = findnextnumber(bufferp); // Skip field "OFF".
1304 if (*bufferp == '\0') {
1305 // Read a non-empty line.
1306 bufferp = readline(buffer, fp, &line_count);
1307 }
1308 if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1309 || (nverts == 0)) {
1310 printf("Syntax error reading header on line %d in file %s\n",
1311 line_count, infilename);
1312 fclose(fp);
1313 return false;
1314 }
1315 // Allocate memory for 'tetgenio'
1316 if (nverts > 0) {
1317 numberofpoints = nverts;
1318 pointlist = new REAL[nverts * 3];
1319 }
1320 if (nfaces > 0) {
1321 numberoffacets = nfaces;
1322 facetlist = new tetgenio::facet[nfaces];
1323 }
1324 }
1325 } else if (iverts < nverts) {
1326 // Read vertex coordinates
1327 coord = &pointlist[iverts * 3];
1328 for (i = 0; i < 3; i++) {
1329 if (*bufferp == '\0') {
1330 printf("Syntax error reading vertex coords on line %d in file %s\n",
1331 line_count, infilename);
1332 fclose(fp);
1333 return false;
1334 }
1335 coord[i] = (REAL) strtod(bufferp, &bufferp);
1336 bufferp = findnextnumber(bufferp);
1337 }
1338 iverts++;
1339 } else if (ifaces < nfaces) {
1340 // Get next face
1341 f = &facetlist[ifaces];
1342 init(f);
1343 // In .off format, each facet has one polygon, no hole.
1344 f->numberofpolygons = 1;
1345 f->polygonlist = new tetgenio::polygon[1];
1346 p = &f->polygonlist[0];
1347 init(p);
1348 // Read the number of vertices, it should be greater than 0.
1349 p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1350 if (p->numberofvertices == 0) {
1351 printf("Syntax error reading polygon on line %d in file %s\n",
1352 line_count, infilename);
1353 fclose(fp);
1354 return false;
1355 }
1356 // Allocate memory for face vertices
1357 p->vertexlist = new int[p->numberofvertices];
1358 for (i = 0; i < p->numberofvertices; i++) {
1359 bufferp = findnextnumber(bufferp);
1360 if (*bufferp == '\0') {
1361 printf("Syntax error reading polygon on line %d in file %s\n",
1362 line_count, infilename);
1363 fclose(fp);
1364 return false;
1365 }
1366 p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1367 }
1368 ifaces++;
1369 } else {
1370 // Should never get here
1371 printf("Found extra text starting at line %d in file %s\n", line_count,
1372 infilename);
1373 break;
1374 }
1375 }
1376
1377 // Close file
1378 fclose(fp);
1379
1380 // Check whether read all points
1381 if (iverts != nverts) {
1382 printf("Expected %d vertices, but read only %d vertices in file %s\n",
1383 nverts, iverts, infilename);
1384 return false;
1385 }
1386
1387 // Check whether read all faces
1388 if (ifaces != nfaces) {
1389 printf("Expected %d faces, but read only %d faces in file %s\n",
1390 nfaces, ifaces, infilename);
1391 return false;
1392 }
1393
1394 return true;
1395}
1396
1398// //
1399// load_ply() Load a polyhedron described in a .ply file. //
1400// //
1401// 'filename' is the file name with extension .ply or without extension (the //
1402// .ply will be added in this case). //
1403// //
1404// This is a simplified version of reading .ply files, which only reads the //
1405// set of vertices and the set of faces. Other informations (such as color, //
1406// material, texture, etc) in .ply file are ignored. Complete routines for //
1407// reading and writing ,ply files are available from: http://www.cc.gatech. //
1408// edu/projects/large_models/ply.html. Except the header section, ply file //
1409// format has exactly the same format for listing vertices and polygons as //
1410// off file format. //
1411// //
1412// On completion, 'pointlist' and 'facetlist' together return the polyhedron.//
1413// //
1415
1416bool tetgenio::load_ply(char* filename)
1417{
1418 FILE *fp;
1419 tetgenio::facet *f;
1420 tetgenio::polygon *p;
1421 char infilename[FILENAMESIZE];
1422 char buffer[INPUTLINESIZE];
1423 char *bufferp, *str;
1424 double *coord;
1425 int endheader = 0, format = 0;
1426 int nverts = 0, iverts = 0;
1427 int nfaces = 0, ifaces = 0;
1428 int line_count = 0, i;
1429
1430 strncpy(infilename, filename, FILENAMESIZE - 1);
1431 infilename[FILENAMESIZE - 1] = '\0';
1432 if (infilename[0] == '\0') {
1433 printf("Error: No filename.\n");
1434 return false;
1435 }
1436 if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1437 strcat(infilename, ".ply");
1438 }
1439
1440 if (!(fp = fopen(infilename, "r"))) {
1441 printf("Error: Unable to open file %s\n", infilename);
1442 return false;
1443 }
1444 printf("Opening %s.\n", infilename);
1445
1446 // PLY requires the index starts from '0'.
1447 firstnumber = 0;
1448
1449 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1450 if (!endheader) {
1451 // Find if it is the keyword "end_header".
1452 str = strstr(bufferp, "end_header");
1453 // strstr() is case sensitive.
1454 if (!str) str = strstr(bufferp, "End_header");
1455 if (!str) str = strstr(bufferp, "End_Header");
1456 if (str) {
1457 // This is the end of the header section.
1458 endheader = 1;
1459 continue;
1460 }
1461 // Parse the number of vertices and the number of faces.
1462 if (nverts == 0 || nfaces == 0) {
1463 // Find if it si the keyword "element".
1464 str = strstr(bufferp, "element");
1465 if (!str) str = strstr(bufferp, "Element");
1466 if (str) {
1467 bufferp = findnextfield(str);
1468 if (*bufferp == '\0') {
1469 printf("Syntax error reading element type on line%d in file %s\n",
1470 line_count, infilename);
1471 fclose(fp);
1472 return false;
1473 }
1474 if (nverts == 0) {
1475 // Find if it is the keyword "vertex".
1476 str = strstr(bufferp, "vertex");
1477 if (!str) str = strstr(bufferp, "Vertex");
1478 if (str) {
1479 bufferp = findnextnumber(str);
1480 if (*bufferp == '\0') {
1481 printf("Syntax error reading vertex number on line");
1482 printf(" %d in file %s\n", line_count, infilename);
1483 fclose(fp);
1484 return false;
1485 }
1486 nverts = (int) strtol(bufferp, &bufferp, 0);
1487 // Allocate memory for 'tetgenio'
1488 if (nverts > 0) {
1489 numberofpoints = nverts;
1490 pointlist = new REAL[nverts * 3];
1491 }
1492 }
1493 }
1494 if (nfaces == 0) {
1495 // Find if it is the keyword "face".
1496 str = strstr(bufferp, "face");
1497 if (!str) str = strstr(bufferp, "Face");
1498 if (str) {
1499 bufferp = findnextnumber(str);
1500 if (*bufferp == '\0') {
1501 printf("Syntax error reading face number on line");
1502 printf(" %d in file %s\n", line_count, infilename);
1503 fclose(fp);
1504 return false;
1505 }
1506 nfaces = (int) strtol(bufferp, &bufferp, 0);
1507 // Allocate memory for 'tetgenio'
1508 if (nfaces > 0) {
1509 numberoffacets = nfaces;
1510 facetlist = new tetgenio::facet[nfaces];
1511 }
1512 }
1513 }
1514 } // It is not the string "element".
1515 }
1516 if (format == 0) {
1517 // Find the keyword "format".
1518 str = strstr(bufferp, "format");
1519 if (!str) str = strstr(bufferp, "Format");
1520 if (str) {
1521 format = 1;
1522 bufferp = findnextfield(str);
1523 // Find if it is the string "ascii".
1524 str = strstr(bufferp, "ascii");
1525 if (!str) str = strstr(bufferp, "ASCII");
1526 if (!str) {
1527 printf("This routine only reads ascii format of ply files.\n");
1528 printf("Hint: You can convert the binary to ascii format by\n");
1529 printf(" using the provided ply tools:\n");
1530 printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
1531 fclose(fp);
1532 return false;
1533 }
1534 }
1535 }
1536 } else if (iverts < nverts) {
1537 // Read vertex coordinates
1538 coord = &pointlist[iverts * 3];
1539 for (i = 0; i < 3; i++) {
1540 if (*bufferp == '\0') {
1541 printf("Syntax error reading vertex coords on line %d in file %s\n",
1542 line_count, infilename);
1543 fclose(fp);
1544 return false;
1545 }
1546 coord[i] = (REAL) strtod(bufferp, &bufferp);
1547 bufferp = findnextnumber(bufferp);
1548 }
1549 iverts++;
1550 } else if (ifaces < nfaces) {
1551 // Get next face
1552 f = &facetlist[ifaces];
1553 init(f);
1554 // In .off format, each facet has one polygon, no hole.
1555 f->numberofpolygons = 1;
1556 f->polygonlist = new tetgenio::polygon[1];
1557 p = &f->polygonlist[0];
1558 init(p);
1559 // Read the number of vertices, it should be greater than 0.
1560 p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1561 if (p->numberofvertices == 0) {
1562 printf("Syntax error reading polygon on line %d in file %s\n",
1563 line_count, infilename);
1564 fclose(fp);
1565 return false;
1566 }
1567 // Allocate memory for face vertices
1568 p->vertexlist = new int[p->numberofvertices];
1569 for (i = 0; i < p->numberofvertices; i++) {
1570 bufferp = findnextnumber(bufferp);
1571 if (*bufferp == '\0') {
1572 printf("Syntax error reading polygon on line %d in file %s\n",
1573 line_count, infilename);
1574 fclose(fp);
1575 return false;
1576 }
1577 p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1578 }
1579 ifaces++;
1580 } else {
1581 // Should never get here
1582 printf("Found extra text starting at line %d in file %s\n", line_count,
1583 infilename);
1584 break;
1585 }
1586 }
1587
1588 // Close file
1589 fclose(fp);
1590
1591 // Check whether read all points
1592 if (iverts != nverts) {
1593 printf("Expected %d vertices, but read only %d vertices in file %s\n",
1594 nverts, iverts, infilename);
1595 return false;
1596 }
1597
1598 // Check whether read all faces
1599 if (ifaces != nfaces) {
1600 printf("Expected %d faces, but read only %d faces in file %s\n",
1601 nfaces, ifaces, infilename);
1602 return false;
1603 }
1604
1605 return true;
1606}
1607
1609// //
1610// load_stl() Load a surface mesh described in a .stl file. //
1611// //
1612// 'filename' is the file name with extension .stl or without extension (the //
1613// .stl will be added in this case). //
1614// //
1615// The .stl or stereolithography format is an ASCII or binary file used in //
1616// manufacturing. It is a list of the triangular surfaces that describe a //
1617// computer generated solid model. This is the standard input for most rapid //
1618// prototyping machines. //
1619// //
1620// On completion, 'pointlist' and 'facetlist' together return the polyhedron.//
1621// Note: After load_stl(), there exist many duplicated points in 'pointlist'.//
1622// They will be unified during the Delaunay tetrahedralization process. //
1623// //
1625
1626bool tetgenio::load_stl(char* filename)
1627{
1628 FILE *fp;
1629 tetgenmesh::list *plist;
1630 tetgenio::facet *f;
1631 tetgenio::polygon *p;
1632 char infilename[FILENAMESIZE];
1633 char buffer[INPUTLINESIZE];
1634 char *bufferp, *str;
1635 double *coord;
1636 int solid = 0;
1637 int nverts = 0, iverts = 0;
1638 int nfaces = 0;
1639 int line_count = 0, i;
1640
1641 strncpy(infilename, filename, FILENAMESIZE - 1);
1642 infilename[FILENAMESIZE - 1] = '\0';
1643 if (infilename[0] == '\0') {
1644 printf("Error: No filename.\n");
1645 return false;
1646 }
1647 if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1648 strcat(infilename, ".stl");
1649 }
1650
1651 if (!(fp = fopen(infilename, "r"))) {
1652 printf("Error: Unable to open file %s\n", infilename);
1653 return false;
1654 }
1655 printf("Opening %s.\n", infilename);
1656
1657 // STL file has no number of points available. Use a list to read points.
1658 plist = new tetgenmesh::list(sizeof(double) * 3, NULL, 1024);
1659
1660 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1661 // The ASCII .stl file must start with the lower case keyword solid and
1662 // end with endsolid.
1663 if (solid == 0) {
1664 // Read header
1665 bufferp = strstr(bufferp, "solid");
1666 if (bufferp != NULL) {
1667 solid = 1;
1668 }
1669 } else {
1670 // We're inside the block of the solid.
1671 str = bufferp;
1672 // Is this the end of the solid.
1673 bufferp = strstr(bufferp, "endsolid");
1674 if (bufferp != NULL) {
1675 solid = 0;
1676 } else {
1677 // Read the XYZ coordinates if it is a vertex.
1678 bufferp = str;
1679 bufferp = strstr(bufferp, "vertex");
1680 if (bufferp != NULL) {
1681 coord = (double *) plist->append(NULL);
1682 for (i = 0; i < 3; i++) {
1683 bufferp = findnextnumber(bufferp);
1684 if (*bufferp == '\0') {
1685 printf("Syntax error reading vertex coords on line %d\n",
1686 line_count);
1687 delete plist;
1688 fclose(fp);
1689 return false;
1690 }
1691 coord[i] = (REAL) strtod(bufferp, &bufferp);
1692 }
1693 }
1694 }
1695 }
1696 }
1697 fclose(fp);
1698
1699 nverts = plist->len();
1700 // nverts should be an integer times 3 (every 3 vertices denote a face).
1701 if (nverts == 0 || (nverts % 3 != 0)) {
1702 printf("Error: Wrong number of vertices in file %s.\n", infilename);
1703 delete plist;
1704 return false;
1705 }
1706 numberofpoints = nverts;
1707 pointlist = new REAL[nverts * 3];
1708 for (i = 0; i < nverts; i++) {
1709 coord = (double *) (* plist)[i];
1710 iverts = i * 3;
1711 pointlist[iverts] = (REAL) coord[0];
1712 pointlist[iverts + 1] = (REAL) coord[1];
1713 pointlist[iverts + 2] = (REAL) coord[2];
1714 }
1715
1716 nfaces = (int) (nverts / 3);
1717 numberoffacets = nfaces;
1718 facetlist = new tetgenio::facet[nfaces];
1719
1720 // Default use '1' as the array starting index.
1721 firstnumber = 1;
1722 iverts = firstnumber;
1723 for (i = 0; i < nfaces; i++) {
1724 f = &facetlist[i];
1725 init(f);
1726 // In .stl format, each facet has one polygon, no hole.
1727 f->numberofpolygons = 1;
1728 f->polygonlist = new tetgenio::polygon[1];
1729 p = &f->polygonlist[0];
1730 init(p);
1731 // Each polygon has three vertices.
1732 p->numberofvertices = 3;
1733 p->vertexlist = new int[p->numberofvertices];
1734 p->vertexlist[0] = iverts;
1735 p->vertexlist[1] = iverts + 1;
1736 p->vertexlist[2] = iverts + 2;
1737 iverts += 3;
1738 }
1739
1740 delete plist;
1741 return true;
1742}
1743
1745// //
1746// load_medit() Load a surface mesh described in .mesh file. //
1747// //
1748// 'filename' is the file name with extension .mesh or without entension ( //
1749// the .mesh will be added in this case). .mesh is the file format of Medit, //
1750// a user-friendly interactive mesh viewing program. //
1751// //
1752// This routine ONLY reads the sections containing vertices, triangles, and //
1753// quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.//
1754// //
1756
1757bool tetgenio::load_medit(char* filename)
1758{
1759 FILE *fp;
1760 tetgenio::facet *tmpflist, *f;
1761 tetgenio::polygon *p;
1762 char infilename[FILENAMESIZE];
1763 char buffer[INPUTLINESIZE];
1764 char *bufferp, *str;
1765 double *coord;
1766 int *tmpfmlist;
1767 int dimension = 0;
1768 int nverts = 0;
1769 int nfaces = 0;
1770 int line_count = 0;
1771 int corners = 0; // 3 (triangle) or 4 (quad).
1772 int i, j;
1773
1774 strncpy(infilename, filename, FILENAMESIZE - 1);
1775 infilename[FILENAMESIZE - 1] = '\0';
1776 if (infilename[0] == '\0') {
1777 printf("Error: No filename.\n");
1778 return false;
1779 }
1780 if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1781 strcat(infilename, ".mesh");
1782 }
1783
1784 if (!(fp = fopen(infilename, "r"))) {
1785 printf("Error: Unable to open file %s\n", infilename);
1786 return false;
1787 }
1788 printf("Opening %s.\n", infilename);
1789
1790 // Default uses the index starts from '1'.
1791 firstnumber = 1;
1792
1793 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1794 if (*bufferp == '#') continue; // A comment line is skipped.
1795 if (dimension == 0) {
1796 // Find if it is the keyword "Dimension".
1797 str = strstr(bufferp, "Dimension");
1798 if (!str) str = strstr(bufferp, "dimension");
1799 if (!str) str = strstr(bufferp, "DIMENSION");
1800 if (str) {
1801 // Read the dimensions
1802 bufferp = findnextnumber(str); // Skip field "Dimension".
1803 if (*bufferp == '\0') {
1804 // Read a non-empty line.
1805 bufferp = readline(buffer, fp, &line_count);
1806 }
1807 dimension = (int) strtol(bufferp, &bufferp, 0);
1808 if (dimension != 2 && dimension != 3) {
1809 printf("Unknown dimension in file on line %d in file %s\n",
1810 line_count, infilename);
1811 fclose(fp);
1812 return false;
1813 }
1814 mesh_dim = dimension;
1815 }
1816 }
1817 if (nverts == 0) {
1818 // Find if it is the keyword "Vertices".
1819 str = strstr(bufferp, "Vertices");
1820 if (!str) str = strstr(bufferp, "vertices");
1821 if (!str) str = strstr(bufferp, "VERTICES");
1822 if (str) {
1823 // Read the number of vertices.
1824 bufferp = findnextnumber(str); // Skip field "Vertices".
1825 if (*bufferp == '\0') {
1826 // Read a non-empty line.
1827 bufferp = readline(buffer, fp, &line_count);
1828 }
1829 nverts = (int) strtol(bufferp, &bufferp, 0);
1830 // Allocate memory for 'tetgenio'
1831 if (nverts > 0) {
1832 numberofpoints = nverts;
1833 pointlist = new REAL[nverts * 3];
1834 }
1835 // Read the follwoing node list.
1836 for (i = 0; i < nverts; i++) {
1837 bufferp = readline(buffer, fp, &line_count);
1838 if (bufferp == NULL) {
1839 printf("Unexpected end of file on line %d in file %s\n",
1840 line_count, infilename);
1841 fclose(fp);
1842 return false;
1843 }
1844 // Read vertex coordinates
1845 coord = &pointlist[i * 3];
1846 for (j = 0; j < 3; j++) {
1847 if (*bufferp == '\0') {
1848 printf("Syntax error reading vertex coords on line");
1849 printf(" %d in file %s\n", line_count, infilename);
1850 fclose(fp);
1851 return false;
1852 }
1853 if ((j < 2) || (dimension == 3)) {
1854 coord[j] = (REAL) strtod(bufferp, &bufferp);
1855 } else {
1856 assert((j == 2) && (dimension == 2));
1857 coord[j] = 0.0;
1858 }
1859 bufferp = findnextnumber(bufferp);
1860 }
1861 }
1862 continue;
1863 }
1864 }
1865 if (nfaces == 0) {
1866 // Find if it is the keyword "Triangles" or "Quadrilaterals".
1867 corners = 0;
1868 str = strstr(bufferp, "Triangles");
1869 if (!str) str = strstr(bufferp, "triangles");
1870 if (!str) str = strstr(bufferp, "TRIANGLES");
1871 if (str) {
1872 corners = 3;
1873 } else {
1874 str = strstr(bufferp, "Quadrilaterals");
1875 if (!str) str = strstr(bufferp, "quadrilaterals");
1876 if (!str) str = strstr(bufferp, "QUADRILATERALS");
1877 if (str) {
1878 corners = 4;
1879 }
1880 }
1881 if (corners == 3 || corners == 4) {
1882 // Read the number of triangles (or quadrilaterals).
1883 bufferp = findnextnumber(str); // Skip field "Triangles".
1884 if (*bufferp == '\0') {
1885 // Read a non-empty line.
1886 bufferp = readline(buffer, fp, &line_count);
1887 }
1888 nfaces = strtol(bufferp, &bufferp, 0);
1889 // Allocate memory for 'tetgenio'
1890 if (nfaces > 0) {
1891 if (numberoffacets > 0) {
1892 // facetlist has already been allocated. Enlarge arrays.
1893 tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1894 tmpfmlist = new int[numberoffacets + nfaces];
1895 // Copy the data of old arrays into new arrays.
1896 for (i = 0; i < numberoffacets; i++) {
1897 f = &(tmpflist[i]);
1898 tetgenio::init(f);
1899 *f = facetlist[i];
1900 tmpfmlist[i] = facetmarkerlist[i];
1901 }
1902 // Release old arrays.
1903 delete [] facetlist;
1904 delete [] facetmarkerlist;
1905 // Remember the new arrays.
1906 facetlist = tmpflist;
1907 facetmarkerlist = tmpfmlist;
1908 } else {
1909 // This is the first time to allocate facetlist.
1910 facetlist = new tetgenio::facet[nfaces];
1911 facetmarkerlist = new int[nfaces];
1912 }
1913 }
1914 // Read the following list of faces.
1915 for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
1916 bufferp = readline(buffer, fp, &line_count);
1917 if (bufferp == NULL) {
1918 printf("Unexpected end of file on line %d in file %s\n",
1919 line_count, infilename);
1920 fclose(fp);
1921 return false;
1922 }
1923 f = &facetlist[i];
1924 tetgenio::init(f);
1925 // In .mesh format, each facet has one polygon, no hole.
1926 f->numberofpolygons = 1;
1927 f->polygonlist = new tetgenio::polygon[1];
1928 p = &f->polygonlist[0];
1929 tetgenio::init(p);
1930 p->numberofvertices = corners;
1931 // Allocate memory for face vertices
1932 p->vertexlist = new int[p->numberofvertices];
1933 // Read the vertices of the face.
1934 for (j = 0; j < corners; j++) {
1935 if (*bufferp == '\0') {
1936 printf("Syntax error reading face on line %d in file %s\n",
1937 line_count, infilename);
1938 fclose(fp);
1939 return false;
1940 }
1941 p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
1942 if (firstnumber == 1) {
1943 // Check if a '0' index appears.
1944 if (p->vertexlist[j] == 0) {
1945 // The first index is set to be 0.
1946 firstnumber = 0;
1947 }
1948 }
1949 bufferp = findnextnumber(bufferp);
1950 }
1951 // Read the marker of the face if it exists.
1952 facetmarkerlist[i] = 0;
1953 if (*bufferp != '\0') {
1954 facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
1955 }
1956 }
1957 // Have read in a list of triangles/quads.
1958 numberoffacets += nfaces;
1959 nfaces = 0;
1960 }
1961 }
1962 // if (nverts > 0 && nfaces > 0) break; // Ignore other data.
1963 }
1964
1965 // Close file
1966 fclose(fp);
1967
1968 return true;
1969}
1970
1972// //
1973// load_plc() Load a piecewise linear complex from file. //
1974// //
1975// This is main entrance for loading plcs from different file formats into //
1976// tetgenio. 'filename' is the input file name without extention. 'object' //
1977// indicates which file format is used to describ the plc. //
1978// //
1980
1981bool tetgenio::load_plc(char* filename, int object)
1982{
1983 enum tetgenbehavior::objecttype type;
1984
1985 type = (enum tetgenbehavior::objecttype) object;
1986 switch (type) {
1987 case tetgenbehavior::NODES:
1988 return load_node(filename);
1989 case tetgenbehavior::POLY:
1990 return load_poly(filename);
1991 case tetgenbehavior::OFF:
1992 return load_off(filename);
1993 case tetgenbehavior::PLY:
1994 return load_ply(filename);
1995 case tetgenbehavior::STL:
1996 return load_stl(filename);
1997 case tetgenbehavior::MEDIT:
1998 return load_medit(filename);
1999 default:
2000 return load_poly(filename);
2001 }
2002}
2003
2005// //
2006// load_tetmesh() Load a tetrahedral mesh from files. //
2007// //
2008// 'filename' is the inputfile without suffix. The nodes of the tetrahedral //
2009// mesh is in "filename.node", the elements is in "filename.ele", if the //
2010// "filename.face" and "filename.vol" exists, they will also be read. //
2011// //
2013
2014bool tetgenio::load_tetmesh(char* filename)
2015{
2016 FILE *infile;
2017 char innodefilename[FILENAMESIZE];
2018 char inelefilename[FILENAMESIZE];
2019 char infacefilename[FILENAMESIZE];
2020 char inedgefilename[FILENAMESIZE];
2021 char involfilename[FILENAMESIZE];
2022 char inputline[INPUTLINESIZE];
2023 char *stringptr, *infilename;
2024 REAL attrib, volume;
2025 int volelements;
2026 int markers, corner;
2027 int index, attribindex;
2028 int i, j;
2029
2030 markers = 0;
2031
2032 // Assembling the actual file names we want to open.
2033 strcpy(innodefilename, filename);
2034 strcpy(inelefilename, filename);
2035 strcpy(infacefilename, filename);
2036 strcpy(inedgefilename, filename);
2037 strcpy(involfilename, filename);
2038 strcat(innodefilename, ".node");
2039 strcat(inelefilename, ".ele");
2040 strcat(infacefilename, ".face");
2041 strcat(inedgefilename, ".edge");
2042 strcat(involfilename, ".vol");
2043
2044 // Read the points from a .node file.
2045 infilename = innodefilename;
2046 printf("Opening %s.\n", infilename);
2047 infile = fopen(infilename, "r");
2048 if (infile == (FILE *) NULL) {
2049 printf("File I/O Error: Cannot access file %s.\n", infilename);
2050 return false;
2051 }
2052 // Read the first line of the file.
2053 stringptr = readnumberline(inputline, infile, infilename);
2054 // Is this list of points generated from rbox?
2055 stringptr = strstr(inputline, "rbox");
2056 if (stringptr == NULL) {
2057 // Read number of points, number of dimensions, number of point
2058 // attributes, and number of boundary markers.
2059 stringptr = inputline;
2060 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
2061 stringptr = findnextnumber(stringptr);
2062 if (*stringptr == '\0') {
2063 mesh_dim = 3;
2064 } else {
2065 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2066 }
2067 stringptr = findnextnumber(stringptr);
2068 if (*stringptr == '\0') {
2069 numberofpointattributes = 0;
2070 } else {
2071 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
2072 }
2073 stringptr = findnextnumber(stringptr);
2074 if (*stringptr == '\0') {
2075 markers = 0; // Default value.
2076 } else {
2077 markers = (int) strtol (stringptr, &stringptr, 0);
2078 }
2079 } else {
2080 // It is a rbox (qhull) input file.
2081 stringptr = inputline;
2082 // Get the dimension.
2083 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2084 // Get the number of points.
2085 stringptr = readnumberline(inputline, infile, infilename);
2086 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
2087 // There is no index column.
2088 useindex = 0;
2089 }
2090
2091 // Load the list of nodes.
2092 if (!load_node_call(infile, markers, infilename)) {
2093 fclose(infile);
2094 return false;
2095 }
2096 fclose(infile);
2097
2098 // Read the elements from an .ele file.
2099 if (mesh_dim == 3) {
2100 infilename = inelefilename;
2101 infile = fopen(infilename, "r");
2102 if (infile != (FILE *) NULL) {
2103 printf("Opening %s.\n", infilename);
2104 // Read number of elements, number of corners (4 or 10), number of
2105 // element attributes.
2106 stringptr = readnumberline(inputline, infile, infilename);
2107 numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
2108 stringptr = findnextnumber(stringptr);
2109 if (*stringptr == '\0') {
2110 numberofcorners = 4; // Default read 4 nodes per element.
2111 } else {
2112 numberofcorners = (int) strtol(stringptr, &stringptr, 0);
2113 }
2114 stringptr = findnextnumber(stringptr);
2115 if (*stringptr == '\0') {
2116 numberoftetrahedronattributes = 0; // Default no attribute.
2117 } else {
2118 numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
2119 }
2120 if (numberofcorners != 4 && numberofcorners != 10) {
2121 printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
2122 numberofcorners);
2123 fclose(infile);
2124 return false;
2125 }
2126 // Allocate memory for tetrahedra.
2127 if (numberoftetrahedra > 0) {
2128 tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
2129 if (tetrahedronlist == (int *) NULL) {
2130 printf("Error: Out of memory.\n");
2131 terminatetetgen(1);
2132 }
2133 // Allocate memory for output tetrahedron attributes if necessary.
2134 if (numberoftetrahedronattributes > 0) {
2135 tetrahedronattributelist = new REAL[numberoftetrahedra *
2136 numberoftetrahedronattributes];
2137 if (tetrahedronattributelist == (REAL *) NULL) {
2138 printf("Error: Out of memory.\n");
2139 terminatetetgen(1);
2140 }
2141 }
2142 }
2143 // Read the list of tetrahedra.
2144 index = 0;
2145 attribindex = 0;
2146 for (i = 0; i < numberoftetrahedra; i++) {
2147 // Read tetrahedron index and the tetrahedron's corners.
2148 stringptr = readnumberline(inputline, infile, infilename);
2149 for (j = 0; j < numberofcorners; j++) {
2150 stringptr = findnextnumber(stringptr);
2151 if (*stringptr == '\0') {
2152 printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
2153 i + firstnumber, j + 1, infilename);
2154 terminatetetgen(1);
2155 }
2156 corner = (int) strtol(stringptr, &stringptr, 0);
2157 if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
2158 printf("Error: Tetrahedron %d has an invalid vertex index.\n",
2159 i + firstnumber);
2160 terminatetetgen(1);
2161 }
2162 tetrahedronlist[index++] = corner;
2163 }
2164 // Read the tetrahedron's attributes.
2165 for (j = 0; j < numberoftetrahedronattributes; j++) {
2166 stringptr = findnextnumber(stringptr);
2167 if (*stringptr == '\0') {
2168 attrib = 0.0;
2169 } else {
2170 attrib = (REAL) strtod(stringptr, &stringptr);
2171 }
2172 tetrahedronattributelist[attribindex++] = attrib;
2173 }
2174 }
2175 fclose(infile);
2176 }
2177 } // if (meshdim == 3)
2178
2179 // Read the hullfaces or subfaces from a .face file if it exists.
2180 if (mesh_dim == 3) {
2181 infilename = infacefilename;
2182 } else {
2183 infilename = inelefilename;
2184 }
2185 infile = fopen(infilename, "r");
2186 if (infile != (FILE *) NULL) {
2187 printf("Opening %s.\n", infilename);
2188 // Read number of faces, boundary markers.
2189 stringptr = readnumberline(inputline, infile, infilename);
2190 numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
2191 stringptr = findnextnumber(stringptr);
2192 if (mesh_dim == 2) {
2193 // Skip a number.
2194 stringptr = findnextnumber(stringptr);
2195 }
2196 if (*stringptr == '\0') {
2197 markers = 0; // Default there is no marker per face.
2198 } else {
2199 markers = (int) strtol (stringptr, &stringptr, 0);
2200 }
2201 if (numberoftrifaces > 0) {
2202 trifacelist = new int[numberoftrifaces * 3];
2203 if (trifacelist == (int *) NULL) {
2204 printf("Error: Out of memory.\n");
2205 terminatetetgen(1);
2206 }
2207 if (markers) {
2208 trifacemarkerlist = new int[numberoftrifaces * 3];
2209 if (trifacemarkerlist == (int *) NULL) {
2210 printf("Error: Out of memory.\n");
2211 terminatetetgen(1);
2212 }
2213 }
2214 }
2215 // Read the list of faces.
2216 index = 0;
2217 for (i = 0; i < numberoftrifaces; i++) {
2218 // Read face index and the face's three corners.
2219 stringptr = readnumberline(inputline, infile, infilename);
2220 for (j = 0; j < 3; j++) {
2221 stringptr = findnextnumber(stringptr);
2222 if (*stringptr == '\0') {
2223 printf("Error: Face %d is missing vertex %d in %s.\n",
2224 i + firstnumber, j + 1, infilename);
2225 terminatetetgen(1);
2226 }
2227 corner = (int) strtol(stringptr, &stringptr, 0);
2228 if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
2229 printf("Error: Face %d has an invalid vertex index.\n",
2230 i + firstnumber);
2231 terminatetetgen(1);
2232 }
2233 trifacelist[index++] = corner;
2234 }
2235 // Read the boundary marker if it exists.
2236 if (markers) {
2237 stringptr = findnextnumber(stringptr);
2238 if (*stringptr == '\0') {
2239 attrib = 0.0;
2240 } else {
2241 attrib = (REAL) strtod(stringptr, &stringptr);
2242 }
2243 trifacemarkerlist[i] = (int) attrib;
2244 }
2245 }
2246 fclose(infile);
2247 }
2248
2249 // Read the boundary edges from a .edge file if it exists.
2250 infilename = inedgefilename;
2251 infile = fopen(infilename, "r");
2252 if (infile != (FILE *) NULL) {
2253 printf("Opening %s.\n", infilename);
2254 // Read number of boundary edges.
2255 stringptr = readnumberline(inputline, infile, infilename);
2256 numberofedges = (int) strtol (stringptr, &stringptr, 0);
2257 if (numberofedges > 0) {
2258 edgelist = new int[numberofedges * 2];
2259 if (edgelist == (int *) NULL) {
2260 printf("Error: Out of memory.\n");
2261 terminatetetgen(1);
2262 }
2263 }
2264 // Read the list of faces.
2265 index = 0;
2266 for (i = 0; i < numberofedges; i++) {
2267 // Read face index and the edge's two endpoints.
2268 stringptr = readnumberline(inputline, infile, infilename);
2269 for (j = 0; j < 2; j++) {
2270 stringptr = findnextnumber(stringptr);
2271 if (*stringptr == '\0') {
2272 printf("Error: Edge %d is missing vertex %d in %s.\n",
2273 i + firstnumber, j + 1, infilename);
2274 terminatetetgen(1);
2275 }
2276 corner = (int) strtol(stringptr, &stringptr, 0);
2277 if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
2278 printf("Error: Edge %d has an invalid vertex index.\n",
2279 i + firstnumber);
2280 terminatetetgen(1);
2281 }
2282 edgelist[index++] = corner;
2283 }
2284 }
2285 fclose(infile);
2286 }
2287
2288 // Read the volume constraints from a .vol file if it exists.
2289 infilename = involfilename;
2290 infile = fopen(infilename, "r");
2291 if (infile != (FILE *) NULL) {
2292 printf("Opening %s.\n", infilename);
2293 // Read number of tetrahedra.
2294 stringptr = readnumberline(inputline, infile, infilename);
2295 volelements = (int) strtol (stringptr, &stringptr, 0);
2296 if (volelements != numberoftetrahedra) {
2297 printf("Warning: %s and %s disagree on number of tetrahedra.\n",
2298 inelefilename, involfilename);
2299 volelements = 0;
2300 }
2301 if (volelements > 0) {
2302 tetrahedronvolumelist = new REAL[volelements];
2303 if (tetrahedronvolumelist == (REAL *) NULL) {
2304 printf("Error: Out of memory.\n");
2305 terminatetetgen(1);
2306 }
2307 }
2308 // Read the list of volume constraints.
2309 for (i = 0; i < volelements; i++) {
2310 stringptr = readnumberline(inputline, infile, infilename);
2311 stringptr = findnextnumber(stringptr);
2312 if (*stringptr == '\0') {
2313 volume = -1.0; // No constraint on this tetrahedron.
2314 } else {
2315 volume = (REAL) strtod(stringptr, &stringptr);
2316 }
2317 tetrahedronvolumelist[i] = volume;
2318 }
2319 fclose(infile);
2320 }
2321
2322 // Try to load a .mtr file if it exists.
2323 load_mtr(filename);
2324 // Try to read a .pbc file if it exists.
2325 load_pbc(filename);
2326
2327 return true;
2328}
2329
2331// //
2332// load_voronoi() Load a Voronoi diagram from files. //
2333// //
2334// 'filename' is the inputfile without suffix. The Voronoi diagram is read //
2335// from files: filename.v.node, filename.v.edge, and filename.v.face. //
2336// //
2338
2339bool tetgenio::load_voronoi(char* filename)
2340{
2341 FILE *infile;
2342 char innodefilename[FILENAMESIZE];
2343 char inedgefilename[FILENAMESIZE];
2344 char inputline[INPUTLINESIZE];
2345 char *stringptr, *infilename;
2346 voroedge *vedge;
2347 REAL x, y, z;
2348 int firstnode, corner;
2349 int index;
2350 int i, j;
2351
2352 // Assembling the actual file names we want to open.
2353 strcpy(innodefilename, filename);
2354 strcpy(inedgefilename, filename);
2355 strcat(innodefilename, ".v.node");
2356 strcat(inedgefilename, ".v.edge");
2357
2358 // Read the points from a .v.node file.
2359 infilename = innodefilename;
2360 printf("Opening %s.\n", infilename);
2361 infile = fopen(infilename, "r");
2362 if (infile == (FILE *) NULL) {
2363 printf("File I/O Error: Cannot access file %s.\n", infilename);
2364 return false;
2365 }
2366 // Read the first line of the file.
2367 stringptr = readnumberline(inputline, infile, infilename);
2368 // Is this list of points generated from rbox?
2369 stringptr = strstr(inputline, "rbox");
2370 if (stringptr == NULL) {
2371 // Read number of points, number of dimensions, number of point
2372 // attributes, and number of boundary markers.
2373 stringptr = inputline;
2374 numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
2375 stringptr = findnextnumber(stringptr);
2376 if (*stringptr == '\0') {
2377 mesh_dim = 3; // Default.
2378 } else {
2379 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2380 }
2381 useindex = 1; // There is an index column.
2382 } else {
2383 // It is a rbox (qhull) input file.
2384 stringptr = inputline;
2385 // Get the dimension.
2386 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2387 // Get the number of points.
2388 stringptr = readnumberline(inputline, infile, infilename);
2389 numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
2390 useindex = 0; // No index column.
2391 }
2392 // Initialize 'vpointlist'.
2393 vpointlist = new REAL[numberofvpoints * 3];
2394 if (vpointlist == (REAL *) NULL) {
2395 printf("Error: Out of memory.\n");
2396 terminatetetgen(1);
2397 }
2398 // Read the point section.
2399 index = 0;
2400 for (i = 0; i < numberofvpoints; i++) {
2401 stringptr = readnumberline(inputline, infile, infilename);
2402 if (useindex) {
2403 if (i == 0) {
2404 firstnode = (int) strtol (stringptr, &stringptr, 0);
2405 if ((firstnode == 0) || (firstnode == 1)) {
2406 firstnumber = firstnode;
2407 }
2408 }
2409 stringptr = findnextnumber(stringptr);
2410 } // if (useindex)
2411 if (*stringptr == '\0') {
2412 printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
2413 terminatetetgen(1);
2414 }
2415 x = (REAL) strtod(stringptr, &stringptr);
2416 stringptr = findnextnumber(stringptr);
2417 if (*stringptr == '\0') {
2418 printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
2419 terminatetetgen(1);
2420 }
2421 y = (REAL) strtod(stringptr, &stringptr);
2422 if (mesh_dim == 3) {
2423 stringptr = findnextnumber(stringptr);
2424 if (*stringptr == '\0') {
2425 printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
2426 terminatetetgen(1);
2427 }
2428 z = (REAL) strtod(stringptr, &stringptr);
2429 } else {
2430 z = 0.0; // mesh_dim == 2;
2431 }
2432 vpointlist[index++] = x;
2433 vpointlist[index++] = y;
2434 vpointlist[index++] = z;
2435 }
2436 fclose(infile);
2437
2438 // Read the Voronoi edges from a .v.edge file if it exists.
2439 infilename = inedgefilename;
2440 infile = fopen(infilename, "r");
2441 if (infile != (FILE *) NULL) {
2442 printf("Opening %s.\n", infilename);
2443 // Read number of boundary edges.
2444 stringptr = readnumberline(inputline, infile, infilename);
2445 numberofvedges = (int) strtol (stringptr, &stringptr, 0);
2446 if (numberofvedges > 0) {
2447 vedgelist = new voroedge[numberofvedges];
2448 }
2449 // Read the list of faces.
2450 index = 0;
2451 for (i = 0; i < numberofvedges; i++) {
2452 // Read edge index and the edge's two endpoints.
2453 stringptr = readnumberline(inputline, infile, infilename);
2454 vedge = &(vedgelist[i]);
2455 for (j = 0; j < 2; j++) {
2456 stringptr = findnextnumber(stringptr);
2457 if (*stringptr == '\0') {
2458 printf("Error: Edge %d is missing vertex %d in %s.\n",
2459 i + firstnumber, j + 1, infilename);
2460 terminatetetgen(1);
2461 }
2462 corner = (int) strtol(stringptr, &stringptr, 0);
2463 j == 0 ? vedge->v1 = corner : vedge->v2 = corner;
2464 }
2465 if (vedge->v2 < 0) {
2466 for (j = 0; j < mesh_dim; j++) {
2467 stringptr = findnextnumber(stringptr);
2468 if (*stringptr == '\0') {
2469 printf("Error: Edge %d is missing normal in %s.\n",
2470 i + firstnumber, infilename);
2471 terminatetetgen(1);
2472 }
2473 vedge->vnormal[j] = (REAL) strtod(stringptr, &stringptr);
2474 }
2475 if (mesh_dim == 2) {
2476 vedge->vnormal[2] = 0.0;
2477 }
2478 } else {
2479 vedge->vnormal[0] = 0.0;
2480 vedge->vnormal[1] = 0.0;
2481 vedge->vnormal[2] = 0.0;
2482 }
2483 }
2484 fclose(infile);
2485 }
2486
2487 return true;
2488}
2489
2491// //
2492// save_nodes() Save points to a .node file. //
2493// //
2494// 'filename' is a string containing the file name without suffix. //
2495// //
2497
2498void tetgenio::save_nodes(char* filename)
2499{
2500 FILE *fout;
2501 char outnodefilename[FILENAMESIZE];
2502 char outmtrfilename[FILENAMESIZE];
2503 int i, j;
2504
2505 sprintf(outnodefilename, "%s.node", filename);
2506 printf("Saving nodes to %s\n", outnodefilename);
2507 fout = fopen(outnodefilename, "w");
2508 fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
2509 numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
2510 for (i = 0; i < numberofpoints; i++) {
2511 if (mesh_dim == 2) {
2512 fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 2],
2513 pointlist[i * 2 + 1]);
2514 } else {
2515 fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
2516 pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2517 }
2518 for (j = 0; j < numberofpointattributes; j++) {
2519 fprintf(fout, " %.16g",
2520 pointattributelist[i * numberofpointattributes + j]);
2521 }
2522 if (pointmarkerlist != NULL) {
2523 fprintf(fout, " %d", pointmarkerlist[i]);
2524 }
2525 fprintf(fout, "\n");
2526 }
2527 fclose(fout);
2528
2529 // If the point metrics exist, output them to a .mtr file.
2530 if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
2531 sprintf(outmtrfilename, "%s.mtr", filename);
2532 printf("Saving metrics to %s\n", outmtrfilename);
2533 fout = fopen(outmtrfilename, "w");
2534 fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
2535 for (i = 0; i < numberofpoints; i++) {
2536 for (j = 0; j < numberofpointmtrs; j++) {
2537 fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2538 }
2539 fprintf(fout, "\n");
2540 }
2541 fclose(fout);
2542 }
2543}
2544
2546// //
2547// save_elements() Save elements to a .ele file. //
2548// //
2549// 'filename' is a string containing the file name without suffix. //
2550// //
2552
2553void tetgenio::save_elements(char* filename)
2554{
2555 FILE *fout;
2556 char outelefilename[FILENAMESIZE];
2557 int i, j;
2558
2559 sprintf(outelefilename, "%s.ele", filename);
2560 printf("Saving elements to %s\n", outelefilename);
2561 fout = fopen(outelefilename, "w");
2562 fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
2563 numberoftetrahedronattributes);
2564 for (i = 0; i < numberoftetrahedra; i++) {
2565 fprintf(fout, "%d", i + firstnumber);
2566 for (j = 0; j < numberofcorners; j++) {
2567 fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
2568 }
2569 for (j = 0; j < numberoftetrahedronattributes; j++) {
2570 fprintf(fout, " %g",
2571 tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2572 }
2573 fprintf(fout, "\n");
2574 }
2575
2576 fclose(fout);
2577}
2578
2580// //
2581// save_faces() Save faces to a .face file. //
2582// //
2583// 'filename' is a string containing the file name without suffix. //
2584// //
2586
2587void tetgenio::save_faces(char* filename)
2588{
2589 FILE *fout;
2590 char outfacefilename[FILENAMESIZE];
2591 int i;
2592
2593 sprintf(outfacefilename, "%s.face", filename);
2594 printf("Saving faces to %s\n", outfacefilename);
2595 fout = fopen(outfacefilename, "w");
2596 fprintf(fout, "%d %d\n", numberoftrifaces,
2597 trifacemarkerlist != NULL ? 1 : 0);
2598 for (i = 0; i < numberoftrifaces; i++) {
2599 fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
2600 trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2601 if (trifacemarkerlist != NULL) {
2602 fprintf(fout, " %d", trifacemarkerlist[i]);
2603 }
2604 fprintf(fout, "\n");
2605 }
2606
2607 fclose(fout);
2608}
2609
2611// //
2612// save_edges() Save egdes to a .edge file. //
2613// //
2614// 'filename' is a string containing the file name without suffix. //
2615// //
2617
2618void tetgenio::save_edges(char* filename)
2619{
2620 FILE *fout;
2621 char outedgefilename[FILENAMESIZE];
2622 int i;
2623
2624 sprintf(outedgefilename, "%s.edge", filename);
2625 printf("Saving edges to %s\n", outedgefilename);
2626 fout = fopen(outedgefilename, "w");
2627 fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2628 for (i = 0; i < numberofedges; i++) {
2629 fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2630 edgelist[i * 2 + 1]);
2631 if (edgemarkerlist != NULL) {
2632 fprintf(fout, " %d", edgemarkerlist[i]);
2633 }
2634 fprintf(fout, "\n");
2635 }
2636
2637 fclose(fout);
2638}
2639
2641// //
2642// save_neighbors() Save egdes to a .neigh file. //
2643// //
2644// 'filename' is a string containing the file name without suffix. //
2645// //
2647
2648void tetgenio::save_neighbors(char* filename)
2649{
2650 FILE *fout;
2651 char outneighborfilename[FILENAMESIZE];
2652 int i;
2653
2654 sprintf(outneighborfilename, "%s.neigh", filename);
2655 printf("Saving neighbors to %s\n", outneighborfilename);
2656 fout = fopen(outneighborfilename, "w");
2657 fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
2658 for (i = 0; i < numberoftetrahedra; i++) {
2659 if (mesh_dim == 2) {
2660 fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
2661 neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2662 } else {
2663 fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
2664 neighborlist[i * 4], neighborlist[i * 4 + 1],
2665 neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2666 }
2667 fprintf(fout, "\n");
2668 }
2669
2670 fclose(fout);
2671}
2672
2674// //
2675// save_poly() Save segments or facets to a .poly file. //
2676// //
2677// 'filename' is a string containing the file name without suffix. It only //
2678// save the facets, holes and regions. The nodes are saved in a .node file //
2679// by routine save_nodes(). //
2680// //
2682
2683void tetgenio::save_poly(char* filename)
2684{
2685 FILE *fout;
2686 facet *f;
2687 polygon *p;
2688 char outpolyfilename[FILENAMESIZE];
2689 int i, j, k;
2690
2691 sprintf(outpolyfilename, "%s.poly", filename);
2692 printf("Saving poly to %s\n", outpolyfilename);
2693 fout = fopen(outpolyfilename, "w");
2694
2695 // The zero indicates that the vertices are in a separate .node file.
2696 // Followed by number of dimensions, number of vertex attributes,
2697 // and number of boundary markers (zero or one).
2698 fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2699 pointmarkerlist != NULL ? 1 : 0);
2700
2701 // Save segments or facets.
2702 if (mesh_dim == 2) {
2703 // Number of segments, number of boundary markers (zero or one).
2704 fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2705 for (i = 0; i < numberofedges; i++) {
2706 fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2707 edgelist[i * 2 + 1]);
2708 if (edgemarkerlist != NULL) {
2709 fprintf(fout, " %d", edgemarkerlist[i]);
2710 }
2711 fprintf(fout, "\n");
2712 }
2713 } else {
2714 // Number of facets, number of boundary markers (zero or one).
2715 fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
2716 for (i = 0; i < numberoffacets; i++) {
2717 f = &(facetlist[i]);
2718 fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
2719 facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
2720 // Output polygons of this facet.
2721 for (j = 0; j < f->numberofpolygons; j++) {
2722 p = &(f->polygonlist[j]);
2723 fprintf(fout, "%d ", p->numberofvertices);
2724 for (k = 0; k < p->numberofvertices; k++) {
2725 if (((k + 1) % 10) == 0) {
2726 fprintf(fout, "\n ");
2727 }
2728 fprintf(fout, " %d", p->vertexlist[k]);
2729 }
2730 fprintf(fout, "\n");
2731 }
2732 // Output holes of this facet.
2733 for (j = 0; j < f->numberofholes; j++) {
2734 fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
2735 f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2736 }
2737 }
2738 }
2739
2740 // Save holes.
2741 fprintf(fout, "%d\n", numberofholes);
2742 for (i = 0; i < numberofholes; i++) {
2743 // Output x, y coordinates.
2744 fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
2745 holelist[i * mesh_dim + 1]);
2746 if (mesh_dim == 3) {
2747 // Output z coordinate.
2748 fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
2749 }
2750 fprintf(fout, "\n");
2751 }
2752
2753 // Save regions.
2754 fprintf(fout, "%d\n", numberofregions);
2755 for (i = 0; i < numberofregions; i++) {
2756 if (mesh_dim == 2) {
2757 // Output the index, x, y coordinates, attribute (region number)
2758 // and maximum area constraint (maybe -1).
2759 fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
2760 regionlist[i * 4], regionlist[i * 4 + 1],
2761 regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2762 } else {
2763 // Output the index, x, y, z coordinates, attribute (region number)
2764 // and maximum volume constraint (maybe -1).
2765 fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
2766 regionlist[i * 5], regionlist[i * 5 + 1],
2767 regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2768 regionlist[i * 5 + 4]);
2769 }
2770 }
2771
2772 fclose(fout);
2773}
2774
2776// //
2777// readline() Read a nonempty line from a file. //
2778// //
2779// A line is considered "nonempty" if it contains something more than white //
2780// spaces. If a line is considered empty, it will be dropped and the next //
2781// line will be read, this process ends until reaching the end-of-file or a //
2782// non-empty line. Return NULL if it is the end-of-file, otherwise, return //
2783// a pointer to the first non-whitespace character of the line. //
2784// //
2786
2787char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2788{
2789 char *result;
2790
2791 // Search for a non-empty line.
2792 do {
2793 result = fgets(string, INPUTLINESIZE - 1, infile);
2794 if (linenumber) (*linenumber)++;
2795 if (result == (char *) NULL) {
2796 return (char *) NULL;
2797 }
2798 // Skip white spaces.
2799 while ((*result == ' ') || (*result == '\t')) result++;
2800 // If it's end of line, read another line and try again.
2801 } while (*result == '\0');
2802 return result;
2803}
2804
2806// //
2807// findnextfield() Find the next field of a string. //
2808// //
2809// Jumps past the current field by searching for whitespace or a comma, then //
2810// jumps past the whitespace or the comma to find the next field. //
2811// //
2813
2814char* tetgenio::findnextfield(char *string)
2815{
2816 char *result;
2817
2818 result = string;
2819 // Skip the current field. Stop upon reaching whitespace or a comma.
2820 while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
2821 (*result != ',') && (*result != ';')) {
2822 result++;
2823 }
2824 // Now skip the whitespace or the comma, stop at anything else that looks
2825 // like a character, or the end of a line.
2826 while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2827 (*result == ';')) {
2828 result++;
2829 }
2830 return result;
2831}
2832
2834// //
2835// readnumberline() Read a nonempty number line from a file. //
2836// //
2837// A line is considered "nonempty" if it contains something that looks like //
2838// a number. Comments (prefaced by `#') are ignored. //
2839// //
2841
2842char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2843{
2844 char *result;
2845
2846 // Search for something that looks like a number.
2847 do {
2848 result = fgets(string, INPUTLINESIZE, infile);
2849 if (result == (char *) NULL) {
2850 if (infilename != (char *) NULL) {
2851 printf(" Error: Unexpected end of file in %s.\n", infilename);
2852 terminatetetgen(1);
2853 }
2854 return result;
2855 }
2856 // Skip anything that doesn't look like a number, a comment,
2857 // or the end of a line.
2858 while ((*result != '\0') && (*result != '#')
2859 && (*result != '.') && (*result != '+') && (*result != '-')
2860 && ((*result < '0') || (*result > '9'))) {
2861 result++;
2862 }
2863 // If it's a comment or end of line, read another line and try again.
2864 } while ((*result == '#') || (*result == '\0'));
2865 return result;
2866}
2867
2869// //
2870// findnextnumber() Find the next field of a number string. //
2871// //
2872// Jumps past the current field by searching for whitespace or a comma, then //
2873// jumps past the whitespace or the comma to find the next field that looks //
2874// like a number. //
2875// //
2877
2878char* tetgenio::findnextnumber(char *string)
2879{
2880 char *result;
2881
2882 result = string;
2883 // Skip the current field. Stop upon reaching whitespace or a comma.
2884 while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2885 (*result != '\t') && (*result != ',')) {
2886 result++;
2887 }
2888 // Now skip the whitespace and anything else that doesn't look like a
2889 // number, a comment, or the end of a line.
2890 while ((*result != '\0') && (*result != '#')
2891 && (*result != '.') && (*result != '+') && (*result != '-')
2892 && ((*result < '0') || (*result > '9'))) {
2893 result++;
2894 }
2895 // Check for a comment (prefixed with `#').
2896 if (*result == '#') {
2897 *result = '\0';
2898 }
2899 return result;
2900}
2901
2902//
2903// End of class 'tetgenio' implementation
2904//
2905
2906static REAL PI = 3.14159265358979323846264338327950288419716939937510582;
2907
2908//
2909// Begin of class 'tetgenbehavior' implementation
2910//
2911
2913// //
2914// tetgenbehavior() Initialize veriables of 'tetgenbehavior'. //
2915// //
2917
2918tetgenbehavior::tetgenbehavior()
2919{
2920 // Initialize command line switches.
2921 plc = 0;
2922 quality = 0;
2923 refine = 0;
2924 coarse = 0;
2925 metric = 0;
2926 minratio = 2.0;
2927 goodratio = 0.0;
2928 minangle = 20.0;
2929 goodangle = 0.0;
2930 maxdihedral = 165.0;
2931 mindihedral = 5.0;
2932 varvolume = 0;
2933 fixedvolume = 0;
2934 maxvolume = -1.0;
2935 regionattrib = 0;
2936 insertaddpoints = 0;
2937 diagnose = 0;
2938 offcenter = 0;
2939 conformdel = 0;
2940 alpha1 = sqrt(2.0);
2941 alpha2 = 1.0;
2942 alpha3 = 0.6;
2943 zeroindex = 0;
2944 facesout = 0;
2945 edgesout = 0;
2946 neighout = 0;
2947 voroout = 0;
2948 meditview = 0;
2949 gidview = 0;
2950 geomview = 0;
2951 optlevel = 3;
2952 optpasses = 3;
2953 order = 1;
2954 nojettison = 0;
2955 nobound = 0;
2956 nonodewritten = 0;
2957 noelewritten = 0;
2958 nofacewritten = 0;
2959 noiterationnum = 0;
2960 nobisect = 0;
2961 noflip = 0;
2962 steiner = -1;
2963 fliprepair = 1;
2964 nomerge = 0;
2965 docheck = 0;
2966 quiet = 0;
2967 verbose = 0;
2968 useshelles = 0;
2969 epsilon = 1.0e-8;
2970 epsilon2 = 1.0e-5;
2971 object = NONE;
2972 // Initialize strings
2973 commandline[0] = '\0';
2974 infilename[0] = '\0';
2975 outfilename[0] = '\0';
2976 addinfilename[0] = '\0';
2977 bgmeshfilename[0] = '\0';
2978}
2979
2981// //
2982// versioninfo() Print the version information of TetGen. //
2983// //
2985
2986void tetgenbehavior::versioninfo()
2987{
2988 printf("Version 1.4.2 (April 16, 2007).\n");
2989 printf("\n");
2990 printf("Copyright (C) 2002 - 2007\n");
2991 printf("Hang Si\n");
2992 printf("Mohrenstr. 39, 10117 Berlin, Germany\n");
2993 printf("si@wias-berlin.de\n");
2994}
2995
2997// //
2998// syntax() Print list of command line switches and exit the program. //
2999// //
3001
3002void tetgenbehavior::syntax()
3003{
3004 printf(" tetgen [-prq_Ra_AiMYS_T_dzo_fenvgGOJBNEFICQVh] input_file\n");
3005 printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
3006 printf(" -r Reconstructs a previously generated mesh.\n");
3007 printf(" -q Quality mesh generation (adding new mesh points to ");
3008 printf("improve mesh quality).\n");
3009 printf(" -R Mesh coarsening (deleting redundant mesh points).\n");
3010 printf(" -a Applies a maximum tetrahedron volume constraint.\n");
3011 printf(" -A Assigns attributes to identify tetrahedra in different ");
3012 printf("regions.\n");
3013 printf(" -i Inserts a list of additional points into mesh.\n");
3014 printf(" -M Does not merge coplanar facets.\n");
3015 printf(" -Y Suppresses boundary facets/segments splitting.\n");
3016 printf(" -S Specifies maximum number of added points.\n");
3017 printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
3018 printf(" -d Detects self-intersections of facets of the PLC.\n");
3019 printf(" -z Numbers all output items starting from zero.\n");
3020 printf(" -o2 Generates second-order subparametric elements.\n");
3021 printf(" -f Outputs all faces to .face file.");
3022 printf("file.\n");
3023 printf(" -e Outputs all edges to .edge file.\n");
3024 printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
3025 printf(" -v Outputs Voronoi diagram to files.\n");
3026 printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
3027 printf(" -G Outputs mesh to .msh file for viewing by Gid.\n");
3028 printf(" -O Outputs mesh to .off file for viewing by Geomview.\n");
3029 printf(" -J No jettison of unused vertices from output .node file.\n");
3030 printf(" -B Suppresses output of boundary information.\n");
3031 printf(" -N Suppresses output of .node file.\n");
3032 printf(" -E Suppresses output of .ele file.\n");
3033 printf(" -F Suppresses output of .face file.\n");
3034 printf(" -I Suppresses mesh iteration numbers.\n");
3035 printf(" -C Checks the consistency of the final mesh.\n");
3036 printf(" -Q Quiet: No terminal output except errors.\n");
3037 printf(" -V Verbose: Detailed information, more terminal output.\n");
3038 printf(" -h Help: A brief instruction for using TetGen.\n");
3039}
3040
3042// //
3043// usage() Print a brief instruction for using TetGen. //
3044// //
3046
3047void tetgenbehavior::usage()
3048{
3049 printf("TetGen\n");
3050 printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
3051 printf("Triangulator\n");
3052 versioninfo();
3053 printf("\n");
3054 printf("What Can TetGen Do?\n");
3055 printf("\n");
3056 printf(" TetGen generates exact Delaunay tetrahedralizations, exact\n");
3057 printf(" constrained Delaunay tetrahedralizations, and quality ");
3058 printf("tetrahedral\n meshes. The latter are nicely graded and whose ");
3059 printf("tetrahedra have\n radius-edge ratio bounded, thus are suitable ");
3060 printf("for finite element and\n finite volume analysis.\n");
3061 printf("\n");
3062 printf("Command Line Syntax:\n");
3063 printf("\n");
3064 printf(" Below is the command line syntax of TetGen with a list of ");
3065 printf("short\n");
3066 printf(" descriptions. Underscores indicate that numbers may optionally\n");
3067 printf(" follow certain switches. Do not leave any space between a ");
3068 printf("switch\n");
3069 printf(" and its numeric parameter. \'input_file\' contains input data\n");
3070 printf(" depending on the switches you supplied which may be a ");
3071 printf(" piecewise\n");
3072 printf(" linear complex or a list of nodes. File formats and detailed\n");
3073 printf(" description of command line switches are found in user's ");
3074 printf("manual.\n");
3075 printf("\n");
3076 syntax();
3077 printf("\n");
3078 printf("Examples of How to Use TetGen:\n");
3079 printf("\n");
3080 printf(" \'tetgen object\' reads vertices from object.node, and writes ");
3081 printf("their\n Delaunay tetrahedralization to object.1.node and ");
3082 printf("object.1.ele.\n");
3083 printf("\n");
3084 printf(" \'tetgen -p object\' reads a PLC from object.poly or object.");
3085 printf("smesh (and\n possibly object.node) and writes its constrained ");
3086 printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele and ");
3087 printf("object.1.face.\n");
3088 printf("\n");
3089 printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
3090 printf(" object.smesh (and possibly object.node), generates a mesh ");
3091 printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and ");
3092 printf("have volume\n of 0.1 or less, and writes the mesh to ");
3093 printf("object.1.node, object.1.ele\n and object.1.face.\n");
3094 printf("\n");
3095 printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
3096}
3097
3099// //
3100// parse_commandline() Read the command line, identify switches, and set //
3101// up options and file names. //
3102// //
3103// 'argc' and 'argv' are the same parameters passed to the function main() //
3104// of a C/C++ program. They together represent the command line user invoked //
3105// from an environment in which TetGen is running. //
3106// //
3107// When TetGen is invoked from an environment. 'argc' is nonzero, switches //
3108// and input filename should be supplied as zero-terminated strings in //
3109// argv[0] through argv[argc - 1] and argv[0] shall be the name used to //
3110// invoke TetGen, i.e. "tetgen". Switches are previously started with a //
3111// dash '-' to identify them from the input filename. //
3112// //
3113// When TetGen is called from within another program. 'argc' is set to zero. //
3114// switches are given in one zero-terminated string (no previous dash is //
3115// required.), and 'argv' is a pointer points to this string. No input //
3116// filename is required (usually the input data has been directly created by //
3117// user in the 'tetgenio' structure). A default filename 'tetgen-tmpfile' //
3118// will be created for debugging output purpose. //
3119// //
3121
3122bool tetgenbehavior::parse_commandline(int argc, char **argv)
3123{
3124 int startindex;
3125 int increment;
3126 int meshnumber;
3127 int scount;
3128 int i, j, k;
3129 char workstring[1024];
3130
3131 // First determine the input style of the switches.
3132 if (argc == 0) {
3133 startindex = 0; // Switches are given without a dash.
3134 argc = 1; // For running the following for-loop once.
3135 commandline[0] = '\0';
3136 } else {
3137 startindex = 1;
3138 strcpy(commandline, argv[0]);
3139 strcat(commandline, " ");
3140 }
3141
3142 // Rcount used to count the number of '-R' be used.
3143 scount = 0;
3144
3145 for (i = startindex; i < argc; i++) {
3146 // Remember the command line switches.
3147 strcat(commandline, argv[i]);
3148 strcat(commandline, " ");
3149 if (startindex == 1) {
3150 // Is this string a filename?
3151 if (argv[i][0] != '-') {
3152 strncpy(infilename, argv[i], 1024 - 1);
3153 infilename[1024 - 1] = '\0';
3154 // Go to the next string directly.
3155 continue;
3156 }
3157 }
3158 // Parse the individual switch from the string.
3159 for (j = startindex; argv[i][j] != '\0'; j++) {
3160 if (argv[i][j] == 'p') {
3161 plc = 1;
3162 } else if (argv[i][j] == 'r') {
3163 refine = 1;
3164 } else if (argv[i][j] == 'R') {
3165 coarse = 1;
3166 } else if (argv[i][j] == 'q') {
3167 quality++;
3168 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3169 (argv[i][j + 1] == '.')) {
3170 k = 0;
3171 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3172 (argv[i][j + 1] == '.')) {
3173 j++;
3174 workstring[k] = argv[i][j];
3175 k++;
3176 }
3177 workstring[k] = '\0';
3178 if (quality == 1) {
3179 minratio = (REAL) strtod(workstring, (char **) NULL);
3180 } else if (quality == 2) {
3181 mindihedral = (REAL) strtod(workstring, (char **) NULL);
3182 } else if (quality == 3) {
3183 maxdihedral = (REAL) strtod(workstring, (char **) NULL);
3184 } else if (quality == 4) {
3185 alpha2 = (REAL) strtod(workstring, (char **) NULL);
3186 } else if (quality == 5) {
3187 alpha1 = (REAL) strtod(workstring, (char **) NULL);
3188 }
3189 }
3190 } else if (argv[i][j] == 'm') {
3191 metric++;
3192 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3193 (argv[i][j + 1] == '.')) {
3194 k = 0;
3195 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3196 (argv[i][j + 1] == '.')) {
3197 j++;
3198 workstring[k] = argv[i][j];
3199 k++;
3200 }
3201 workstring[k] = '\0';
3202 if (metric == 1) {
3203 alpha1 = (REAL) strtod(workstring, (char **) NULL);
3204 } else if (metric == 2) {
3205 alpha2 = (REAL) strtod(workstring, (char **) NULL);
3206 }
3207 }
3208 } else if (argv[i][j] == 'a') {
3209 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3210 (argv[i][j + 1] == '.')) {
3211 fixedvolume = 1;
3212 k = 0;
3213 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3214 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3215 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3216 j++;
3217 workstring[k] = argv[i][j];
3218 k++;
3219 }
3220 workstring[k] = '\0';
3221 maxvolume = (REAL) strtod(workstring, (char **) NULL);
3222 } else {
3223 varvolume = 1;
3224 }
3225 } else if (argv[i][j] == 'A') {
3226 regionattrib++;
3227 } else if (argv[i][j] == 'i') {
3228 insertaddpoints = 1;
3229 } else if (argv[i][j] == 'd') {
3230 diagnose = 1;
3231 } else if (argv[i][j] == 'z') {
3232 zeroindex = 1;
3233 } else if (argv[i][j] == 'f') {
3234 facesout = 1;
3235 } else if (argv[i][j] == 'e') {
3236 edgesout++;
3237 } else if (argv[i][j] == 'n') {
3238 neighout++;
3239 } else if (argv[i][j] == 'v') {
3240 voroout = 1;
3241 } else if (argv[i][j] == 'g') {
3242 meditview = 1;
3243 } else if (argv[i][j] == 'G') {
3244 gidview = 1;
3245 } else if (argv[i][j] == 'O') {
3246 geomview = 1;
3247 } else if (argv[i][j] == 'M') {
3248 nomerge = 1;
3249 } else if (argv[i][j] == 'Y') {
3250 nobisect++;
3251 } else if (argv[i][j] == 'J') {
3252 nojettison = 1;
3253 } else if (argv[i][j] == 'B') {
3254 nobound = 1;
3255 } else if (argv[i][j] == 'N') {
3256 nonodewritten = 1;
3257 } else if (argv[i][j] == 'E') {
3258 noelewritten = 1;
3259 } else if (argv[i][j] == 'F') {
3260 nofacewritten = 1;
3261 } else if (argv[i][j] == 'I') {
3262 noiterationnum = 1;
3263 } else if (argv[i][j] == 'o') {
3264 if (argv[i][j + 1] == '2') {
3265 j++;
3266 order = 2;
3267 }
3268 } else if (argv[i][j] == 'S') {
3269 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3270 (argv[i][j + 1] == '.')) {
3271 k = 0;
3272 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3273 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3274 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3275 j++;
3276 workstring[k] = argv[i][j];
3277 k++;
3278 }
3279 workstring[k] = '\0';
3280 steiner = (int) strtol(workstring, (char **) NULL, 0);
3281 }
3282 } else if (argv[i][j] == 's') {
3283 scount++;
3284 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3285 (argv[i][j + 1] == '.')) {
3286 k = 0;
3287 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3288 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3289 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3290 j++;
3291 workstring[k] = argv[i][j];
3292 k++;
3293 }
3294 workstring[k] = '\0';
3295 if (scount == 1) {
3296 optlevel = (int) strtol(workstring, (char **) NULL, 0);
3297 } else if (scount == 2) {
3298 optpasses = (int) strtol(workstring, (char **) NULL, 0);
3299 }
3300 }
3301 } else if (argv[i][j] == 'D') {
3302 conformdel++;
3303 } else if (argv[i][j] == 'T') {
3304 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3305 (argv[i][j + 1] == '.')) {
3306 k = 0;
3307 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3308 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3309 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3310 j++;
3311 workstring[k] = argv[i][j];
3312 k++;
3313 }
3314 workstring[k] = '\0';
3315 epsilon = (REAL) strtod(workstring, (char **) NULL);
3316 }
3317 } else if (argv[i][j] == 'C') {
3318 docheck++;
3319 } else if (argv[i][j] == 'X') {
3320 fliprepair = 0;
3321 } else if (argv[i][j] == 'Q') {
3322 quiet = 1;
3323 } else if (argv[i][j] == 'V') {
3324 verbose++;
3325 // } else if (argv[i][j] == 'v') {
3326 // versioninfo();
3327 // terminatetetgen(0);
3328 } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
3329 (argv[i][j] == '?')) {
3330 usage();
3331 terminatetetgen(0);
3332 } else {
3333 printf("Warning: Unknown switch -%c.\n", argv[i][j]);
3334 }
3335 }
3336 }
3337
3338 if (startindex == 0) {
3339 // Set a temporary filename for debugging output.
3340 strcpy(infilename, "tetgen-tmpfile");
3341 } else {
3342 if (infilename[0] == '\0') {
3343 // No input file name. Print the syntax and exit.
3344 syntax();
3345 terminatetetgen(0);
3346 }
3347 // Recognize the object from file extension if it is available.
3348 if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3349 infilename[strlen(infilename) - 5] = '\0';
3350 object = NODES;
3351 } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3352 infilename[strlen(infilename) - 5] = '\0';
3353 object = POLY;
3354 plc = 1;
3355 } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3356 infilename[strlen(infilename) - 6] = '\0';
3357 object = POLY;
3358 plc = 1;
3359 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3360 infilename[strlen(infilename) - 4] = '\0';
3361 object = OFF;
3362 plc = 1;
3363 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3364 infilename[strlen(infilename) - 4] = '\0';
3365 object = PLY;
3366 plc = 1;
3367 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3368 infilename[strlen(infilename) - 4] = '\0';
3369 object = STL;
3370 plc = 1;
3371 } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3372 infilename[strlen(infilename) - 5] = '\0';
3373 object = MEDIT;
3374 plc = 1;
3375 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3376 infilename[strlen(infilename) - 4] = '\0';
3377 object = MESH;
3378 refine = 1;
3379 }
3380 }
3381 plc = plc || diagnose;
3382 useshelles = plc || refine || coarse || quality;
3383 goodratio = minratio;
3384 goodratio *= goodratio;
3385
3386 // Detect improper combinations of switches.
3387 if (plc && refine) {
3388 printf("Error: Switch -r cannot use together with -p.\n");
3389 return false;
3390 }
3391 if (refine && (plc || noiterationnum)) {
3392 printf("Error: Switches %s cannot use together with -r.\n",
3393 "-p, -d, and -I");
3394 return false;
3395 }
3396 if (diagnose && (quality || insertaddpoints || (order == 2) || neighout
3397 || docheck)) {
3398 printf("Error: Switches %s cannot use together with -d.\n",
3399 "-q, -i, -o2, -n, and -C");
3400 return false;
3401 }
3402
3403 // Be careful not to allocate space for element area constraints that
3404 // will never be assigned any value (other than the default -1.0).
3405 if (!refine && !plc) {
3406 varvolume = 0;
3407 }
3408 // Be careful not to add an extra attribute to each element unless the
3409 // input supports it (PLC in, but not refining a preexisting mesh).
3410 if (refine || !plc) {
3411 regionattrib = 0;
3412 }
3413 // If '-a' or '-aa' is in use, enable '-q' option too.
3414 if (fixedvolume || varvolume) {
3415 if (quality == 0) {
3416 quality = 1;
3417 }
3418 }
3419 // Calculate the goodangle for testing bad subfaces.
3420 goodangle = cos(minangle * PI / 180.0);
3421 goodangle *= goodangle;
3422
3423 increment = 0;
3424 strcpy(workstring, infilename);
3425 j = 1;
3426 while (workstring[j] != '\0') {
3427 if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
3428 increment = j + 1;
3429 }
3430 j++;
3431 }
3432 meshnumber = 0;
3433 if (increment > 0) {
3434 j = increment;
3435 do {
3436 if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
3437 meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
3438 } else {
3439 increment = 0;
3440 }
3441 j++;
3442 } while (workstring[j] != '\0');
3443 }
3444 if (noiterationnum) {
3445 strcpy(outfilename, infilename);
3446 } else if (increment == 0) {
3447 strcpy(outfilename, infilename);
3448 strcat(outfilename, ".1");
3449 } else {
3450 workstring[increment] = '%';
3451 workstring[increment + 1] = 'd';
3452 workstring[increment + 2] = '\0';
3453 sprintf(outfilename, workstring, meshnumber + 1);
3454 }
3455 // Additional input file name has the end ".a".
3456 strcpy(addinfilename, infilename);
3457 strcat(addinfilename, ".a");
3458 // Background filename has the form "*.b.ele", "*.b.node", ...
3459 strcpy(bgmeshfilename, infilename);
3460 strcat(bgmeshfilename, ".b");
3461
3462 return true;
3463}
3464
3465//
3466// End of class 'tetgenbehavior' implementation
3467//
3468
3469//
3470// Begin of class 'tetgenmesh' implementation
3471//
3472
3473//
3474// Begin of class 'list', 'memorypool' and 'link' implementation
3475//
3476
3477// Following are predefined compare functions for primitive data types.
3478// These functions take two pointers of the corresponding date type,
3479// perform the comparation. Return -1, 0 or 1 indicating the default
3480// linear order of two operators.
3481
3482// Compare two 'integers'.
3483int tetgenmesh::compare_2_ints(const void* x, const void* y) {
3484 if (* (int *) x < * (int *) y) {
3485 return -1;
3486 } else if (* (int *) x > * (int *) y) {
3487 return 1;
3488 } else {
3489 return 0;
3490 }
3491}
3492
3493// Compare two 'longs'. Note: in 64-bit machine the 'long' type is 64-bit
3494// (8-byte) where the 'int' only 32-bit (4-byte).
3495int tetgenmesh::compare_2_longs(const void* x, const void* y) {
3496 if (* (long *) x < * (long *) y) {
3497 return -1;
3498 } else if (* (long *) x > * (long *) y) {
3499 return 1;
3500 } else {
3501 return 0;
3502 }
3503}
3504
3505// Compare two 'unsigned longs'.
3506int tetgenmesh::compare_2_unsignedlongs(const void* x, const void* y) {
3507 if (* (unsigned long *) x < * (unsigned long *) y) {
3508 return -1;
3509 } else if (* (unsigned long *) x > * (unsigned long *) y) {
3510 return 1;
3511 } else {
3512 return 0;
3513 }
3514}
3515
3517// //
3518// set_compfunc() Determine the size of primitive data types and set the //
3519// corresponding predefined linear order functions. //
3520// //
3521// 'str' is a zero-end string indicating a primitive data type, like 'int', //
3522// 'long' or 'unsigned long'. Every string ending with a '*' is though as a //
3523// type of pointer and the type 'unsign long' is used for it. //
3524// //
3525// When the type of 'str' is determined, the size of this type (in byte) is //
3526// returned in 'itbytes', and the pointer of corresponding predefined linear //
3527// order functions is returned in 'pcomp'. //
3528// //
3530
3531void tetgenmesh::set_compfunc(char* str, int* itbytes, compfunc* pcomp)
3532{
3533 // First figure out whether it is a pointer or not.
3534 if (str[strlen(str) - 1] == '*') {
3535 *itbytes = sizeof(unsigned long);
3536 *pcomp = &compare_2_unsignedlongs;
3537 return;
3538 }
3539 // Then determine other types.
3540 if (strcmp(str, "int") == 0) {
3541 *itbytes = sizeof(int);
3542 *pcomp = &compare_2_ints;
3543 } else if (strcmp(str, "long") == 0) {
3544 *itbytes = sizeof(long);
3545 *pcomp = &compare_2_longs;
3546 } else if (strcmp(str, "unsigned long") == 0) {
3547 *itbytes = sizeof(unsigned long);
3548 *pcomp = &compare_2_unsignedlongs;
3549 } else {
3550 // It is an unknown type.
3551 printf("Error in set_compfunc(): unknown type %s.\n", str);
3552 terminatetetgen(1);
3553 }
3554}
3555
3557// //
3558// listinit() Initialize a list for storing a data type. //
3559// //
3560// Determine the size of each item, set the maximum size allocated at onece, //
3561// set the expand size in case the list is full, and set the linear order //
3562// function if it is provided (default is NULL). //
3563// //
3565
3566void tetgenmesh::list::
3567listinit(int itbytes, compfunc pcomp, int mitems,int exsize)
3568{
3569#ifdef SELF_CHECK
3570 assert(itbytes > 0 && mitems > 0 && exsize > 0);
3571#endif
3572 itembytes = itbytes;
3573 comp = pcomp;
3574 maxitems = mitems;
3575 expandsize = exsize;
3576 base = (char *) malloc(maxitems * itembytes);
3577 if (base == (char *) NULL) {
3578 printf("Error: Out of memory.\n");
3579 terminatetetgen(1);
3580 }
3581 items = 0;
3582}
3583
3585// //
3586// append() Add a new item at the end of the list. //
3587// //
3588// A new space at the end of this list will be allocated for storing the new //
3589// item. If the memory is not sufficient, reallocation will be performed. If //
3590// 'appitem' is not NULL, the contents of this pointer will be copied to the //
3591// new allocated space. Returns the pointer to the new allocated space. //
3592// //
3594
3595void* tetgenmesh::list::append(void *appitem)
3596{
3597 // Do we have enough space?
3598 if (items == maxitems) {
3599 char* newbase = (char *) realloc(base, (maxitems + expandsize) *
3600 itembytes);
3601 if (newbase == (char *) NULL) {
3602 printf("Error: Out of memory.\n");
3603 terminatetetgen(1);
3604 }
3605 base = newbase;
3606 maxitems += expandsize;
3607 }
3608 if (appitem != (void *) NULL) {
3609 memcpy(base + items * itembytes, appitem, itembytes);
3610 }
3611 items++;
3612 return (void *) (base + (items - 1) * itembytes);
3613}
3614
3616// //
3617// insert() Insert an item before 'pos' (range from 0 to items - 1). //
3618// //
3619// A new space will be inserted at the position 'pos', that is, items lie //
3620// after pos (including the item at pos) will be moved one space downwords. //
3621// If 'insitem' is not NULL, its contents will be copied into the new //
3622// inserted space. Return a pointer to the new inserted space. //
3623// //
3625
3626void* tetgenmesh::list::insert(int pos, void* insitem)
3627{
3628 if (pos >= items) {
3629 return append(insitem);
3630 }
3631 // Do we have enough space.
3632 if (items == maxitems) {
3633 char* newbase = (char *) realloc(base, (maxitems + expandsize) *
3634 itembytes);
3635 if (newbase == (char *) NULL) {
3636 printf("Error: Out of memory.\n");
3637 terminatetetgen(1);
3638 }
3639 base = newbase;
3640 maxitems += expandsize;
3641 }
3642 // Do block move.
3643 memmove(base + (pos + 1) * itembytes, // dest
3644 base + pos * itembytes, // src
3645 (items - pos) * itembytes); // size in bytes
3646 // Insert the item.
3647 if (insitem != (void *) NULL) {
3648 memcpy(base + pos * itembytes, insitem, itembytes);
3649 }
3650 items++;
3651 return (void *) (base + pos * itembytes);
3652}
3653
3655// //
3656// del() Delete an item at 'pos' (range from 0 to items - 1). //
3657// //
3658// The space at 'pos' will be overlapped by other item. If 'order' is 1, the //
3659// remaining items of the list have the same order as usual, i.e., items lie //
3660// after pos will be moved one space upwords. If 'order' is 0, the last item //
3661// of the list will be moved up to pos. //
3662// //
3664
3665void tetgenmesh::list::del(int pos, int order)
3666{
3667 // If 'pos' is the last item of the list, nothing need to do.
3668 if (pos >= 0 && pos < items - 1) {
3669 if (order == 1) {
3670 // Do block move.
3671 memmove(base + pos * itembytes, // dest
3672 base + (pos + 1) * itembytes, // src
3673 (items - pos - 1) * itembytes);
3674 } else {
3675 // Use the last item to overlap the del item.
3676 memcpy(base + pos * itembytes, // item at pos
3677 base + (items - 1) * itembytes, // item at last
3678 itembytes);
3679 }
3680 }
3681 if (items > 0) {
3682 items--;
3683 }
3684}
3685
3687// //
3688// hasitem() Search in this list to find if 'checkitem' exists. //
3689// //
3690// This routine assumes that a linear order function has been set. It loops //
3691// through the entire list, compares each item to 'checkitem'. If it exists, //
3692// return its position (between 0 to items - 1), otherwise, return -1. //
3693// //
3695
3696int tetgenmesh::list::hasitem(void* checkitem)
3697{
3698 int i;
3699
3700 for (i = 0; i < items; i++) {
3701 if (comp != (compfunc) NULL) {
3702 if ((* comp)((void *)(base + i * itembytes), checkitem) == 0) {
3703 return i;
3704 }
3705 }
3706 }
3707 return -1;
3708}
3709
3711// //
3712// sort() Sort the items with respect to a linear order function. //
3713// //
3714// Uses QuickSort routines (qsort) of the standard C/C++ library (stdlib.h). //
3715// //
3717
3718void tetgenmesh::list::sort()
3719{
3720 qsort((void *) base, (size_t) items, (size_t) itembytes, comp);
3721}
3722
3724// //
3725// memorypool() The constructors of memorypool. //
3726// //
3728
3729tetgenmesh::memorypool::memorypool()
3730{
3731 firstblock = nowblock = (void **) NULL;
3732 nextitem = (void *) NULL;
3733 deaditemstack = (void *) NULL;
3734 pathblock = (void **) NULL;
3735 pathitem = (void *) NULL;
3736 itemwordtype = POINTER;
3737 alignbytes = 0;
3738 itembytes = itemwords = 0;
3739 itemsperblock = 0;
3740 items = maxitems = 0l;
3741 unallocateditems = 0;
3742 pathitemsleft = 0;
3743}
3744
3745tetgenmesh::memorypool::
3746memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment)
3747{
3748 poolinit(bytecount, itemcount, wtype, alignment);
3749}
3750
3752// //
3753// ~memorypool() Free to the operating system all memory taken by a pool. //
3754// //
3756
3757tetgenmesh::memorypool::~memorypool()
3758{
3759 while (firstblock != (void **) NULL) {
3760 nowblock = (void **) *(firstblock);
3761 free(firstblock);
3762 firstblock = nowblock;
3763 }
3764}
3765
3767// //
3768// poolinit() Initialize a pool of memory for allocation of items. //
3769// //
3770// A `pool' is created whose records have size at least `bytecount'. Items //
3771// will be allocated in `itemcount'-item blocks. Each item is assumed to be //
3772// a collection of words, and either pointers or floating-point values are //
3773// assumed to be the "primary" word type. (The "primary" word type is used //
3774// to determine alignment of items.) If `alignment' isn't zero, all items //
3775// will be `alignment'-byte aligned in memory. `alignment' must be either a //
3776// multiple or a factor of the primary word size; powers of two are safe. //
3777// `alignment' is normally used to create a few unused bits at the bottom of //
3778// each item's pointer, in which information may be stored. //
3779// //
3781
3782void tetgenmesh::memorypool::
3783poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
3784{
3785 int wordsize;
3786
3787 // Initialize values in the pool.
3788 itemwordtype = wtype;
3789 wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL);
3790 // Find the proper alignment, which must be at least as large as:
3791 // - The parameter `alignment'.
3792 // - The primary word type, to avoid unaligned accesses.
3793 // - sizeof(void *), so the stack of dead items can be maintained
3794 // without unaligned accesses.
3795 if (alignment > wordsize) {
3796 alignbytes = alignment;
3797 } else {
3798 alignbytes = wordsize;
3799 }
3800 if ((int) sizeof(void *) > alignbytes) {
3801 alignbytes = (int) sizeof(void *);
3802 }
3803 itemwords = ((bytecount + alignbytes - 1) / alignbytes)
3804 * (alignbytes / wordsize);
3805 itembytes = itemwords * wordsize;
3806 itemsperblock = itemcount;
3807
3808 // Allocate a block of items. Space for `itemsperblock' items and one
3809 // pointer (to point to the next block) are allocated, as well as space
3810 // to ensure alignment of the items.
3811 firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
3812 + alignbytes);
3813 if (firstblock == (void **) NULL) {
3814 printf("Error: Out of memory.\n");
3815 terminatetetgen(1);
3816 }
3817 // Set the next block pointer to NULL.
3818 *(firstblock) = (void *) NULL;
3819 restart();
3820}
3821
3823// //
3824// restart() Deallocate all items in this pool. //
3825// //
3826// The pool is returned to its starting state, except that no memory is //
3827// freed to the operating system. Rather, the previously allocated blocks //
3828// are ready to be reused. //
3829// //
3831
3832void tetgenmesh::memorypool::restart()
3833{
3834 unsigned long alignptr;
3835
3836 items = 0;
3837 maxitems = 0;
3838
3839 // Set the currently active block.
3840 nowblock = firstblock;
3841 // Find the first item in the pool. Increment by the size of (void *).
3842 alignptr = (unsigned long) (nowblock + 1);
3843 // Align the item on an `alignbytes'-byte boundary.
3844 nextitem = (void *)
3845 (alignptr + (unsigned long) alignbytes -
3846 (alignptr % (unsigned long) alignbytes));
3847 // There are lots of unallocated items left in this block.
3848 unallocateditems = itemsperblock;
3849 // The stack of deallocated items is empty.
3850 deaditemstack = (void *) NULL;
3851}
3852
3854// //
3855// alloc() Allocate space for an item. //
3856// //
3858
3859void* tetgenmesh::memorypool::alloc()
3860{
3861 void *newitem;
3862 void **newblock;
3863 unsigned long alignptr;
3864
3865 // First check the linked list of dead items. If the list is not
3866 // empty, allocate an item from the list rather than a fresh one.
3867 if (deaditemstack != (void *) NULL) {
3868 newitem = deaditemstack; // Take first item in list.
3869 deaditemstack = * (void **) deaditemstack;
3870 } else {
3871 // Check if there are any free items left in the current block.
3872 if (unallocateditems == 0) {
3873 // Check if another block must be allocated.
3874 if (*nowblock == (void *) NULL) {
3875 // Allocate a new block of items, pointed to by the previous block.
3876 newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
3877 + alignbytes);
3878 if (newblock == (void **) NULL) {
3879 printf("Error: Out of memory.\n");
3880 terminatetetgen(1);
3881 }
3882 *nowblock = (void *) newblock;
3883 // The next block pointer is NULL.
3884 *newblock = (void *) NULL;
3885 }
3886 // Move to the new block.
3887 nowblock = (void **) *nowblock;
3888 // Find the first item in the block.
3889 // Increment by the size of (void *).
3890 alignptr = (unsigned long) (nowblock + 1);
3891 // Align the item on an `alignbytes'-byte boundary.
3892 nextitem = (void *)
3893 (alignptr + (unsigned long) alignbytes -
3894 (alignptr % (unsigned long) alignbytes));
3895 // There are lots of unallocated items left in this block.
3896 unallocateditems = itemsperblock;
3897 }
3898 // Allocate a new item.
3899 newitem = nextitem;
3900 // Advance `nextitem' pointer to next free item in block.
3901 if (itemwordtype == POINTER) {
3902 nextitem = (void *) ((void **) nextitem + itemwords);
3903 } else {
3904 nextitem = (void *) ((REAL *) nextitem + itemwords);
3905 }
3906 unallocateditems--;
3907 maxitems++;
3908 }
3909 items++;
3910 return newitem;
3911}
3912
3914// //
3915// dealloc() Deallocate space for an item. //
3916// //
3917// The deallocated space is stored in a queue for later reuse. //
3918// //
3920
3921void tetgenmesh::memorypool::dealloc(void *dyingitem)
3922{
3923 // Push freshly killed item onto stack.
3924 *((void **) dyingitem) = deaditemstack;
3925 deaditemstack = dyingitem;
3926 items--;
3927}
3928
3930// //
3931// traversalinit() Prepare to traverse the entire list of items. //
3932// //
3933// This routine is used in conjunction with traverse(). //
3934// //
3936
3937void tetgenmesh::memorypool::traversalinit()
3938{
3939 unsigned long alignptr;
3940
3941 // Begin the traversal in the first block.
3942 pathblock = firstblock;
3943 // Find the first item in the block. Increment by the size of (void *).
3944 alignptr = (unsigned long) (pathblock + 1);
3945 // Align with item on an `alignbytes'-byte boundary.
3946 pathitem = (void *)
3947 (alignptr + (unsigned long) alignbytes -
3948 (alignptr % (unsigned long) alignbytes));
3949 // Set the number of items left in the current block.
3950 pathitemsleft = itemsperblock;
3951}
3952
3954// //
3955// traverse() Find the next item in the list. //
3956// //
3957// This routine is used in conjunction with traversalinit(). Be forewarned //
3958// that this routine successively returns all items in the list, including //
3959// deallocated ones on the deaditemqueue. It's up to you to figure out which //
3960// ones are actually dead. It can usually be done more space-efficiently by //
3961// a routine that knows something about the structure of the item. //
3962// //
3964
3965void* tetgenmesh::memorypool::traverse()
3966{
3967 void *newitem;
3968 unsigned long alignptr;
3969
3970 // Stop upon exhausting the list of items.
3971 if (pathitem == nextitem) {
3972 return (void *) NULL;
3973 }
3974 // Check whether any untraversed items remain in the current block.
3975 if (pathitemsleft == 0) {
3976 // Find the next block.
3977 pathblock = (void **) *pathblock;
3978 // Find the first item in the block. Increment by the size of (void *).
3979 alignptr = (unsigned long) (pathblock + 1);
3980 // Align with item on an `alignbytes'-byte boundary.
3981 pathitem = (void *)
3982 (alignptr + (unsigned long) alignbytes -
3983 (alignptr % (unsigned long) alignbytes));
3984 // Set the number of items left in the current block.
3985 pathitemsleft = itemsperblock;
3986 }
3987 newitem = pathitem;
3988 // Find the next item in the block.
3989 if (itemwordtype == POINTER) {
3990 pathitem = (void *) ((void **) pathitem + itemwords);
3991 } else {
3992 pathitem = (void *) ((REAL *) pathitem + itemwords);
3993 }
3994 pathitemsleft--;
3995 return newitem;
3996}
3997
3999// //
4000// linkinit() Initialize a link for storing items. //
4001// //
4002// The input parameters are the size of each item, a pointer of a linear //
4003// order function and the number of items allocating in one memory bulk. //
4004// //
4006
4007void tetgenmesh::link::linkinit(int bytecount, compfunc pcomp, int itemcount)
4008{
4009#ifdef SELF_CHECK
4010 assert(bytecount > 0 && itemcount > 0);
4011#endif
4012 // Remember the real size of each item.
4013 linkitembytes = bytecount;
4014 // Set the linear order function for this link.
4015 comp = pcomp;
4016
4017 // Call the constructor of 'memorypool' to initialize its variables.
4018 // like: itembytes, itemwords, items, ... Each node has size
4019 // bytecount + 2 * sizeof(void **), and total 'itemcount + 2' (because
4020 // link has additional two nodes 'head' and 'tail').
4021 poolinit(bytecount + 2 * sizeof(void **), itemcount + 2, POINTER, 0);
4022
4023 // Initial state of this link.
4024 head = (void **) alloc();
4025 tail = (void **) alloc();
4026 *head = (void *) tail;
4027 *(head + 1) = NULL;
4028 *tail = NULL;
4029 *(tail + 1) = (void *) head;
4030 nextlinkitem = *head;
4031 curpos = 1;
4032 linkitems = 0;
4033}
4034
4036// //
4037// clear() Deallocate all nodes in this link. //
4038// //
4039// The link is returned to its starting state, except that no memory is //
4040// freed to the operating system. Rather, the previously allocated blocks //
4041// are ready to be reused. //
4042// //
4044
4045void tetgenmesh::link::clear()
4046{
4047 // Reset the pool.
4048 restart();
4049
4050 // Initial state of this link.
4051 head = (void **) alloc();
4052 tail = (void **) alloc();
4053 *head = (void *) tail;
4054 *(head + 1) = NULL;
4055 *tail = NULL;
4056 *(tail + 1) = (void *) head;
4057 nextlinkitem = *head;
4058 curpos = 1;
4059 linkitems = 0;
4060}
4061
4063// //
4064// move() Causes 'nextlinkitem' to traverse the specified number of nodes,//
4065// updates 'curpos' to be the node to which 'nextlinkitem' points. //
4066// //
4067// 'numberofnodes' is a number indicating how many nodes need be traversed //
4068// (not counter the current node) need be traversed. It may be positive(move //
4069// forward) or negative (move backward). Return TRUE if it is successful. //
4070// //
4072
4073bool tetgenmesh::link::move(int numberofnodes)
4074{
4075 void **nownode;
4076 int i;
4077
4078 nownode = (void **) nextlinkitem;
4079 if (numberofnodes > 0) {
4080 // Move forward.
4081 i = 0;
4082 while ((i < numberofnodes) && *nownode) {
4083 nownode = (void **) *nownode;
4084 i++;
4085 }
4086 if (*nownode == NULL) return false;
4087 nextlinkitem = (void *) nownode;
4088 curpos += numberofnodes;
4089 } else if (numberofnodes < 0) {
4090 // Move backward.
4091 i = 0;
4092 numberofnodes = -numberofnodes;
4093 while ((i < numberofnodes) && *(nownode + 1)) {
4094 nownode = (void **) *(nownode + 1);
4095 i++;
4096 }
4097 if (*(nownode + 1) == NULL) return false;
4098 nextlinkitem = (void *) nownode;
4099 curpos -= numberofnodes;
4100 }
4101 return true;
4102}
4103
4105// //
4106// locate() Locates the node at the specified position. //
4107// //
4108// The number 'pos' (between 1 and 'linkitems') indicates the location. This //
4109// routine first decides the shortest path traversing from 'curpos' to 'pos',//
4110// i.e., from head, tail or 'curpos'. Routine 'move()' is called to really //
4111// traverse the link. If success, 'nextlinkitem' points to the node, 'curpos'//
4112// and 'pos' are equal. Otherwise, return FALSE. //
4113// //
4115
4116bool tetgenmesh::link::locate(int pos)
4117{
4118 int headdist, taildist, curdist;
4119 int abscurdist, mindist;
4120
4121 if (pos < 1 || pos > linkitems) return false;
4122
4123 headdist = pos - 1;
4124 taildist = linkitems - pos;
4125 curdist = pos - curpos;
4126 abscurdist = curdist >= 0 ? curdist : -curdist;
4127
4128 if (headdist > taildist) {
4129 if (taildist > abscurdist) {
4130 mindist = curdist;
4131 } else {
4132 // taildist <= abs(curdist)
4133 mindist = -taildist;
4134 goend();
4135 }
4136 } else {
4137 // headdist <= taildist
4138 if (headdist > abscurdist) {
4139 mindist = curdist;
4140 } else {
4141 // headdist <= abs(curdist)
4142 mindist = headdist;
4143 rewind();
4144 }
4145 }
4146
4147 return move(mindist);
4148}
4149
4151// //
4152// add() Add a node at the end of this link. //
4153// //
4154// A new node is appended to the end of the link. If 'newitem' is not NULL, //
4155// its conents will be copied to the data slot of the new node. Returns the //
4156// pointer to the newest added node. //
4157// //
4159
4160void* tetgenmesh::link::add(void* newitem)
4161{
4162 void **newnode = tail;
4163 if (newitem != (void *) NULL) {
4164 memcpy((void *)(newnode + 2), newitem, linkitembytes);
4165 }
4166 tail = (void **) alloc();
4167 *tail = NULL;
4168 *newnode = (void*) tail;
4169 *(tail + 1) = (void*) newnode;
4170 linkitems++;
4171 return (void *)(newnode + 2);
4172}
4173
4175// //
4176// insert() Inserts a node before the specified position. //
4177// //
4178// 'pos' (between 1 and 'linkitems') indicates the inserting position. This //
4179// routine inserts a new node before the node of 'pos'. If 'newitem' is not //
4180// NULL, its conents will be copied into the data slot of the new node. If //
4181// 'pos' is larger than 'linkitems', it is equal as 'add()'. A pointer to //
4182// the newest inserted item is returned. //
4183// //
4185
4186void* tetgenmesh::link::insert(int pos, void* insitem)
4187{
4188 if (!locate(pos)) {
4189 return add(insitem);
4190 }
4191
4192 void **nownode = (void **) nextlinkitem;
4193
4194 // Insert a node before 'nownode'.
4195 void **newnode = (void **) alloc();
4196 if (insitem != (void *) NULL) {
4197 memcpy((void *)(newnode + 2), insitem, linkitembytes);
4198 }
4199
4200 *(void **)(*(nownode + 1)) = (void *) newnode;
4201 *newnode = (void *) nownode;
4202 *(newnode + 1) = *(nownode + 1);
4203 *(nownode + 1) = (void *) newnode;
4204
4205 linkitems++;
4206
4207 nextlinkitem = (void *) newnode;
4208 return (void *)(newnode + 2);
4209}
4210
4212// //
4213// del() Delete a node. //
4214// //
4215// Returns a pointer of the deleted data. If you try to delete a non-existed //
4216// node (e.g. link is empty or a wrong index is given) return NULL. //
4217// //
4219
4220void* tetgenmesh::link::deletenode(void** deadnode)
4221{
4222 void **nextnode = (void **) *deadnode;
4223 void **prevnode = (void **) *(deadnode + 1);
4224 *prevnode = (void *) nextnode;
4225 *(nextnode + 1) = (void *) prevnode;
4226
4227 dealloc((void *) deadnode);
4228 linkitems--;
4229
4230 nextlinkitem = (void *) nextnode;
4231 return (void *)(deadnode + 2);
4232}
4233
4235// //
4236// del() Delete a node at the specified position. //
4237// //
4238// 'pos' between 1 and 'linkitems'. Returns a pointer of the deleted data. //
4239// If you try to delete a non-existed node (e.g. link is empty or a wrong //
4240// index is given) return NULL. //
4241// //
4243
4244void* tetgenmesh::link::del(int pos)
4245{
4246 if (!locate(pos) || (linkitems == 0)) {
4247 return (void *) NULL;
4248 }
4249 return deletenode((void **) nextlinkitem);
4250}
4251
4253// //
4254// getitem() The link traversal routine. //
4255// //
4256// Returns the node to which 'nextlinkitem' points. Returns a 'NULL' if the //
4257// end of the link is reaching. Both 'nextlinkitem' and 'curpos' will be //
4258// updated after this operation. //
4259// //
4261
4262void* tetgenmesh::link::getitem()
4263{
4264 if (nextlinkitem == (void *) tail) return NULL;
4265 void **nownode = (void **) nextlinkitem;
4266 nextlinkitem = *nownode;
4267 curpos += 1;
4268 return (void *)(nownode + 2);
4269}
4270
4272// //
4273// getnitem() Returns the node at a specified position. //
4274// //
4275// 'pos' between 1 and 'linkitems'. After this operation, 'nextlinkitem' and //
4276// 'curpos' will be updated to indicate this node. //
4277// //
4279
4280void* tetgenmesh::link::getnitem(int pos)
4281{
4282 if (!locate(pos)) return NULL;
4283 return (void *)((void **) nextlinkitem + 2);
4284}
4285
4287// //
4288// hasitem() Search in this link to find if 'checkitem' exists. //
4289// //
4290// If 'checkitem' exists, return its position (between 1 to 'linkitems'), //
4291// otherwise, return -1. This routine requires the linear order function has //
4292// been set. //
4293// //
4295
4296int tetgenmesh::link::hasitem(void* checkitem)
4297{
4298 void *pathitem;
4299 int count;
4300
4301 rewind();
4302 pathitem = getitem();
4303 count = 0;
4304 while (pathitem) {
4305 count ++;
4306 if (comp) {
4307 if ((* comp)(pathitem, checkitem) == 0) {
4308 return count;
4309 }
4310 }
4311 pathitem = getitem();
4312 }
4313 return -1;
4314}
4315
4316//
4317// End of class 'list', 'memorypool' and 'link' implementation
4318//
4319
4320//
4321// Begin of mesh manipulation primitives
4322//
4323
4324//
4325// Begin of tables initialization.
4326//
4327
4328// For enumerating three edges of a triangle.
4329
4330int tetgenmesh::plus1mod3[3] = {1, 2, 0};
4331int tetgenmesh::minus1mod3[3] = {2, 0, 1};
4332
4333// Table 've' takes an edge version as input, returns the next edge version
4334// in the same edge ring.
4335
4336int tetgenmesh::ve[6] = { 2, 5, 4, 1, 0, 3 };
4337
4338// Tables 'vo', 'vd' and 'va' take an edge version, return the positions of
4339// the origin, destination and apex in the triangle.
4340
4341int tetgenmesh::vo[6] = { 0, 1, 1, 2, 2, 0 };
4342int tetgenmesh::vd[6] = { 1, 0, 2, 1, 0, 2 };
4343int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 };
4344
4345// The following tables are for tetrahedron primitives (operate on trifaces).
4346
4347// For 'org()', 'dest()' and 'apex()'. Use 'loc' as the first index and
4348// 'ver' as the second index.
4349
4350int tetgenmesh::locver2org[4][6] = {
4351 {0, 1, 1, 2, 2, 0},
4352 {0, 3, 3, 1, 1, 0},
4353 {1, 3, 3, 2, 2, 1},
4354 {2, 3, 3, 0, 0, 2}
4355};
4356int tetgenmesh::locver2dest[4][6] = {
4357 {1, 0, 2, 1, 0, 2},
4358 {3, 0, 1, 3, 0, 1},
4359 {3, 1, 2, 3, 1, 2},
4360 {3, 2, 0, 3, 2, 0}
4361};
4362int tetgenmesh::locver2apex[4][6] = {
4363 {2, 2, 0, 0, 1, 1},
4364 {1, 1, 0, 0, 3, 3},
4365 {2, 2, 1, 1, 3, 3},
4366 {0, 0, 2, 2, 3, 3}
4367};
4368
4369// For oppo() primitives, use 'loc' as the index.
4370
4371int tetgenmesh::loc2oppo[4] = { 3, 2, 0, 1 };
4372
4373// For fnext() primitive. Use 'loc' as the first index and 'ver' as the
4374// second index. Returns a new 'loc' and new 'ver' in an array. (It is
4375// only valid for edge version equals one of {0, 2, 4}.)
4376
4377int tetgenmesh::locver2nextf[4][6][2] = {
4378 { {1, 5}, {-1, -1}, {2, 5}, {-1, -1}, {3, 5}, {-1, -1} },
4379 { {3, 3}, {-1, -1}, {2, 1}, {-1, -1}, {0, 1}, {-1, -1} },
4380 { {1, 3}, {-1, -1}, {3, 1}, {-1, -1}, {0, 3}, {-1, -1} },
4381 { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} }
4382};
4383
4384// The edge number (from 0 to 5) of a tet is defined as follows:
4385// 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0)
4386// 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2).
4387
4388int tetgenmesh::locver2edge[4][6] = {
4389 {0, 0, 1, 1, 2, 2},
4390 {3, 3, 4, 4, 0, 0},
4391 {4, 4, 5, 5, 1, 1},
4392 {5, 5, 3, 3, 2, 2}
4393};
4394
4395int tetgenmesh::edge2locver[6][2] = {
4396 {0, 0}, // 0 v0 -> v1
4397 {0, 2}, // 1 v1 -> v2
4398 {0, 4}, // 2 v2 -> v1
4399 {1, 0}, // 3 v0 -> v3
4400 {1, 2}, // 4 v1 -> v3
4401 {2, 2} // 5 v2 -> v3
4402};
4403
4404//
4405// End of tables initialization.
4406//
4407
4408// Some macros for convenience
4409
4410#define Div2 >> 1
4411#define Mod2 & 01
4412
4413// NOTE: These bit operators should only be used in macros below.
4414
4415// Get orient(Range from 0 to 2) from face version(Range from 0 to 5).
4416
4417#define Orient(V) ((V) Div2)
4418
4419// Determine edge ring(0 or 1) from face version(Range from 0 to 5).
4420
4421#define EdgeRing(V) ((V) Mod2)
4422
4423//
4424// Begin of primitives for tetrahedra
4425//
4426
4427// Each tetrahedron contains four pointers to its neighboring tetrahedra,
4428// with face indices. To save memory, both information are kept in a
4429// single pointer. To make this possible, all tetrahedra are aligned to
4430// eight-byte boundaries, so that the last three bits of each pointer are
4431// zeros. A face index (in the range 0 to 3) is compressed into the last
4432// two bits of each pointer by the function 'encode()'. The function
4433// 'decode()' decodes a pointer, extracting a face index and a pointer to
4434// the beginning of a tetrahedron.
4435
4436inline void tetgenmesh::decode(tetrahedron ptr, triface& t) {
4437 t.loc = (int) ((unsigned long) (ptr) & (unsigned long) 3l);
4438 t.tet = (tetrahedron *) ((unsigned long) (ptr) & ~(unsigned long) 7l);
4439}
4440
4441inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) {
4442 return (tetrahedron) ((unsigned long) t.tet | (unsigned long) t.loc);
4443}
4444
4445// sym() finds the abutting tetrahedron on the same face.
4446
4447inline void tetgenmesh::sym(triface& t1, triface& t2) {
4448 tetrahedron ptr = t1.tet[t1.loc];
4449 decode(ptr, t2);
4450}
4451
4452inline void tetgenmesh::symself(triface& t) {
4453 tetrahedron ptr = t.tet[t.loc];
4454 decode(ptr, t);
4455}
4456
4457// Bond two tetrahedra together at their faces.
4458
4459inline void tetgenmesh::bond(triface& t1, triface& t2) {
4460 t1.tet[t1.loc] = encode(t2);
4461 t2.tet[t2.loc] = encode(t1);
4462}
4463
4464// Dissolve a bond (from one side). Note that the other tetrahedron will
4465// still think it is connected to this tetrahedron. Usually, however,
4466// the other tetrahedron is being deleted entirely, or bonded to another
4467// tetrahedron, so it doesn't matter.
4468
4469inline void tetgenmesh::dissolve(triface& t) {
4470 t.tet[t.loc] = (tetrahedron) dummytet;
4471}
4472
4473// These primitives determine or set the origin, destination, apex or
4474// opposition of a tetrahedron with respect to 'loc' and 'ver'.
4475
4476inline tetgenmesh::point tetgenmesh::org(triface& t) {
4477 return (point) t.tet[locver2org[t.loc][t.ver] + 4];
4478}
4479
4480inline tetgenmesh::point tetgenmesh::dest(triface& t) {
4481 return (point) t.tet[locver2dest[t.loc][t.ver] + 4];
4482}
4483
4484inline tetgenmesh::point tetgenmesh::apex(triface& t) {
4485 return (point) t.tet[locver2apex[t.loc][t.ver] + 4];
4486}
4487
4488inline tetgenmesh::point tetgenmesh::oppo(triface& t) {
4489 return (point) t.tet[loc2oppo[t.loc] + 4];
4490}
4491
4492inline void tetgenmesh::setorg(triface& t, point pointptr) {
4493 t.tet[locver2org[t.loc][t.ver] + 4] = (tetrahedron) pointptr;
4494}
4495
4496inline void tetgenmesh::setdest(triface& t, point pointptr) {
4497 t.tet[locver2dest[t.loc][t.ver] + 4] = (tetrahedron) pointptr;
4498}
4499
4500inline void tetgenmesh::setapex(triface& t, point pointptr) {
4501 t.tet[locver2apex[t.loc][t.ver] + 4] = (tetrahedron) pointptr;
4502}
4503
4504inline void tetgenmesh::setoppo(triface& t, point pointptr) {
4505 t.tet[loc2oppo[t.loc] + 4] = (tetrahedron) pointptr;
4506}
4507
4508// These primitives were drived from Mucke's triangle-edge data structure
4509// to change face-edge relation in a tetrahedron (esym, enext and enext2)
4510// or between two tetrahedra (fnext).
4511
4512// If e0 = e(i, j), e1 = e(j, i), that is e0 and e1 are the two directions
4513// of the same undirected edge of a face. e0.sym() = e1 and vice versa.
4514
4515inline void tetgenmesh::esym(triface& t1, triface& t2) {
4516 t2.tet = t1.tet;
4517 t2.loc = t1.loc;
4518 t2.ver = t1.ver + (EdgeRing(t1.ver) ? -1 : 1);
4519}
4520
4521inline void tetgenmesh::esymself(triface& t) {
4522 t.ver += (EdgeRing(t.ver) ? -1 : 1);
4523}
4524
4525// If e0 and e1 are both in the same edge ring of a face, e1 = e0.enext().
4526
4527inline void tetgenmesh::enext(triface& t1, triface& t2) {
4528 t2.tet = t1.tet;
4529 t2.loc = t1.loc;
4530 t2.ver = ve[t1.ver];
4531}
4532
4533inline void tetgenmesh::enextself(triface& t) {
4534 t.ver = ve[t.ver];
4535}
4536
4537// enext2() is equal to e2 = e0.enext().enext()
4538
4539inline void tetgenmesh::enext2(triface& t1, triface& t2) {
4540 t2.tet = t1.tet;
4541 t2.loc = t1.loc;
4542 t2.ver = ve[ve[t1.ver]];
4543}
4544
4545inline void tetgenmesh::enext2self(triface& t) {
4546 t.ver = ve[ve[t.ver]];
4547}
4548
4549// If f0 and f1 are both in the same face ring of a face, f1 = f0.fnext().
4550// If f1 exists, return true. Otherwise, return false, i.e., f0 is a
4551// boundary or hull face.
4552
4553inline bool tetgenmesh::fnext(triface& t1, triface& t2)
4554{
4555 // Get the next face.
4556 t2.loc = locver2nextf[t1.loc][t1.ver][0];
4557 // Is the next face in the same tet?
4558 if (t2.loc != -1) {
4559 // It's in the same tet. Get the edge version.
4560 t2.ver = locver2nextf[t1.loc][t1.ver][1];
4561 t2.tet = t1.tet;
4562 } else {
4563 // The next face is in the neigbhour of 't1'.
4564 sym(t1, t2);
4565 if (t2.tet != dummytet) {
4566 // Find the corresponding edge in t2.
4567 point torg;
4568 int tloc, tver, i;
4569 t2.ver = 0;
4570 torg = org(t1);
4571 for (i = 0; (i < 3) && (org(t2) != torg); i++) {
4572 enextself(t2);
4573 }
4574 // Go to the next face in t2.
4575 tloc = t2.loc;
4576 tver = t2.ver;
4577 t2.loc = locver2nextf[tloc][tver][0];
4578 t2.ver = locver2nextf[tloc][tver][1];
4579 }
4580 }
4581 return t2.tet != dummytet;
4582}
4583
4584inline bool tetgenmesh::fnextself(triface& t1)
4585{
4586 triface t2;
4587
4588 // Get the next face.
4589 t2.loc = locver2nextf[t1.loc][t1.ver][0];
4590 // Is the next face in the same tet?
4591 if (t2.loc != -1) {
4592 // It's in the same tet. Get the edge version.
4593 t2.ver = locver2nextf[t1.loc][t1.ver][1];
4594 t1.loc = t2.loc;
4595 t1.ver = t2.ver;
4596 } else {
4597 // The next face is in the neigbhour of 't1'.
4598 sym(t1, t2);
4599 if (t2.tet != dummytet) {
4600 // Find the corresponding edge in t2.
4601 point torg;
4602 int i;
4603 t2.ver = 0;
4604 torg = org(t1);
4605 for (i = 0; (i < 3) && (org(t2) != torg); i++) {
4606 enextself(t2);
4607 }
4608 t1.loc = locver2nextf[t2.loc][t2.ver][0];
4609 t1.ver = locver2nextf[t2.loc][t2.ver][1];
4610 t1.tet = t2.tet;
4611 }
4612 }
4613 return t2.tet != dummytet;
4614}
4615
4616// enextfnext() and enext2fnext() are combination primitives of enext(),
4617// enext2() and fnext().
4618
4619inline void tetgenmesh::enextfnext(triface& t1, triface& t2) {
4620 enext(t1, t2);
4621 fnextself(t2);
4622}
4623
4624inline void tetgenmesh::enextfnextself(triface& t) {
4625 enextself(t);
4626 fnextself(t);
4627}
4628
4629inline void tetgenmesh::enext2fnext(triface& t1, triface& t2) {
4630 enext2(t1, t2);
4631 fnextself(t2);
4632}
4633
4634inline void tetgenmesh::enext2fnextself(triface& t) {
4635 enext2self(t);
4636 fnextself(t);
4637}
4638
4639// Primitives to infect or cure a tetrahedron with the virus. The last
4640// third bit of the pointer is marked for infection. These rely on the
4641// assumption that all tetrahedron are aligned to eight-byte boundaries.
4642
4643inline void tetgenmesh::infect(triface& t) {
4644 t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] | (unsigned long) 4l);
4645}
4646
4647inline void tetgenmesh::uninfect(triface& t) {
4648 t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] & ~ (unsigned long) 4l);
4649}
4650
4651// Test a tetrahedron for viral infection.
4652
4653inline bool tetgenmesh::infected(triface& t) {
4654 return (((unsigned long) t.tet[0] & (unsigned long) 4l) != 0);
4655}
4656
4657// Check or set a tetrahedron's attributes.
4658
4659inline REAL tetgenmesh::elemattribute(tetrahedron* ptr, int attnum) {
4660 return ((REAL *) (ptr))[elemattribindex + attnum];
4661}
4662
4663inline void tetgenmesh::
4664setelemattribute(tetrahedron* ptr, int attnum, REAL value){
4665 ((REAL *) (ptr))[elemattribindex + attnum] = value;
4666}
4667
4668// Check or set a tetrahedron's maximum volume bound.
4669
4670inline REAL tetgenmesh::volumebound(tetrahedron* ptr) {
4671 return ((REAL *) (ptr))[volumeboundindex];
4672}
4673
4674inline void tetgenmesh::setvolumebound(tetrahedron* ptr, REAL value) {
4675 ((REAL *) (ptr))[volumeboundindex] = value;
4676}
4677
4678//
4679// End of primitives for tetrahedra
4680//
4681
4682//
4683// Begin of primitives for subfaces/subsegments
4684//
4685
4686// Each subface contains three pointers to its neighboring subfaces, with
4687// edge versions. To save memory, both information are kept in a single
4688// pointer. To make this possible, all subfaces are aligned to eight-byte
4689// boundaries, so that the last three bits of each pointer are zeros. An
4690// edge version (in the range 0 to 5) is compressed into the last three
4691// bits of each pointer by 'sencode()'. 'sdecode()' decodes a pointer,
4692// extracting an edge version and a pointer to the beginning of a subface.
4693
4694inline void tetgenmesh::sdecode(shellface sptr, face& s) {
4695 s.shver = (int) ((unsigned long) (sptr) & (unsigned long) 7l);
4696 s.sh = (shellface *) ((unsigned long) (sptr) & ~ (unsigned long) 7l);
4697}
4698
4699inline tetgenmesh::shellface tetgenmesh::sencode(face& s) {
4700 return (shellface) ((unsigned long) s.sh | (unsigned long) s.shver);
4701}
4702
4703// spivot() finds the other subface (from this subface) that shares the
4704// same edge.
4705
4706inline void tetgenmesh::spivot(face& s1, face& s2) {
4707 shellface sptr = s1.sh[Orient(s1.shver)];
4708 sdecode(sptr, s2);
4709}
4710
4711inline void tetgenmesh::spivotself(face& s) {
4712 shellface sptr = s.sh[Orient(s.shver)];
4713 sdecode(sptr, s);
4714}
4715
4716// sbond() bonds two subfaces together, i.e., after bonding, both faces
4717// are pointing to each other.
4718
4719inline void tetgenmesh::sbond(face& s1, face& s2) {
4720 s1.sh[Orient(s1.shver)] = sencode(s2);
4721 s2.sh[Orient(s2.shver)] = sencode(s1);
4722}
4723
4724// sbond1() only bonds s2 to s1, i.e., after bonding, s1 is pointing to s2,
4725// but s2 is not pointing to s1.
4726
4727inline void tetgenmesh::sbond1(face& s1, face& s2) {
4728 s1.sh[Orient(s1.shver)] = sencode(s2);
4729}
4730
4731// Dissolve a subface bond (from one side). Note that the other subface
4732// will still think it's connected to this subface.
4733
4734inline void tetgenmesh::sdissolve(face& s) {
4735 s.sh[Orient(s.shver)] = (shellface) dummysh;
4736}
4737
4738// These primitives determine or set the origin, destination, or apex
4739// of a subface with respect to the edge version.
4740
4741inline tetgenmesh::point tetgenmesh::sorg(face& s) {
4742 return (point) s.sh[3 + vo[s.shver]];
4743}
4744
4745inline tetgenmesh::point tetgenmesh::sdest(face& s) {
4746 return (point) s.sh[3 + vd[s.shver]];
4747}
4748
4749inline tetgenmesh::point tetgenmesh::sapex(face& s) {
4750 return (point) s.sh[3 + va[s.shver]];
4751}
4752
4753inline void tetgenmesh::setsorg(face& s, point pointptr) {
4754 s.sh[3 + vo[s.shver]] = (shellface) pointptr;
4755}
4756
4757inline void tetgenmesh::setsdest(face& s, point pointptr) {
4758 s.sh[3 + vd[s.shver]] = (shellface) pointptr;
4759}
4760
4761inline void tetgenmesh::setsapex(face& s, point pointptr) {
4762 s.sh[3 + va[s.shver]] = (shellface) pointptr;
4763}
4764
4765// These primitives were drived from Mucke[2]'s triangle-edge data structure
4766// to change face-edge relation in a subface (sesym, senext and senext2).
4767
4768inline void tetgenmesh::sesym(face& s1, face& s2) {
4769 s2.sh = s1.sh;
4770 s2.shver = s1.shver + (EdgeRing(s1.shver) ? -1 : 1);
4771}
4772
4773inline void tetgenmesh::sesymself(face& s) {
4774 s.shver += (EdgeRing(s.shver) ? -1 : 1);
4775}
4776
4777inline void tetgenmesh::senext(face& s1, face& s2) {
4778 s2.sh = s1.sh;
4779 s2.shver = ve[s1.shver];
4780}
4781
4782inline void tetgenmesh::senextself(face& s) {
4783 s.shver = ve[s.shver];
4784}
4785
4786inline void tetgenmesh::senext2(face& s1, face& s2) {
4787 s2.sh = s1.sh;
4788 s2.shver = ve[ve[s1.shver]];
4789}
4790
4791inline void tetgenmesh::senext2self(face& s) {
4792 s.shver = ve[ve[s.shver]];
4793}
4794
4795// If f0 and f1 are both in the same face ring, then f1 = f0.fnext(),
4796
4797inline void tetgenmesh::sfnext(face& s1, face& s2) {
4798 getnextsface(&s1, &s2);
4799}
4800
4801inline void tetgenmesh::sfnextself(face& s) {
4802 getnextsface(&s, NULL);
4803}
4804
4805// These primitives read or set a pointer of the badface structure. The
4806// pointer is stored sh[11].
4807
4808inline tetgenmesh::badface* tetgenmesh::shell2badface(face& s) {
4809 return (badface*) s.sh[11];
4810}
4811
4812inline void tetgenmesh::setshell2badface(face& s, badface* value) {
4813 s.sh[11] = (shellface) value;
4814}
4815
4816// Check or set a subface's maximum area bound.
4817
4818inline REAL tetgenmesh::areabound(face& s) {
4819 return ((REAL *) (s.sh))[areaboundindex];
4820}
4821
4822inline void tetgenmesh::setareabound(face& s, REAL value) {
4823 ((REAL *) (s.sh))[areaboundindex] = value;
4824}
4825
4826// These two primitives read or set a shell marker. Shell markers are used
4827// to hold user boundary information.
4828
4829inline int tetgenmesh::shellmark(face& s) {
4830 return ((int *) (s.sh))[shmarkindex];
4831}
4832
4833inline void tetgenmesh::setshellmark(face& s, int value) {
4834 ((int *) (s.sh))[shmarkindex] = value;
4835}
4836
4837// These two primitives set or read the type of the subface or subsegment.
4838
4839inline enum tetgenmesh::shestype tetgenmesh::shelltype(face& s) {
4840 return (enum shestype) ((int *) (s.sh))[shmarkindex + 1];
4841}
4842
4843inline void tetgenmesh::setshelltype(face& s, enum shestype value) {
4844 ((int *) (s.sh))[shmarkindex + 1] = (int) value;
4845}
4846
4847// These two primitives set or read the pbc group of the subface.
4848
4849inline int tetgenmesh::shellpbcgroup(face& s) {
4850 return ((int *) (s.sh))[shmarkindex + 2];
4851}
4852
4853inline void tetgenmesh::setshellpbcgroup(face& s, int value) {
4854 ((int *) (s.sh))[shmarkindex + 2] = value;
4855}
4856
4857// Primitives to infect or cure a subface with the virus. These rely on the
4858// assumption that all tetrahedra are aligned to eight-byte boundaries.
4859
4860inline void tetgenmesh::sinfect(face& s) {
4861 s.sh[6] = (shellface) ((unsigned long) s.sh[6] | (unsigned long) 4l);
4862}
4863
4864inline void tetgenmesh::suninfect(face& s) {
4865 s.sh[6] = (shellface)((unsigned long) s.sh[6] & ~(unsigned long) 4l);
4866}
4867
4868// Test a subface for viral infection.
4869
4870inline bool tetgenmesh::sinfected(face& s) {
4871 return (((unsigned long) s.sh[6] & (unsigned long) 4l) != 0);
4872}
4873
4874//
4875// End of primitives for subfaces/subsegments
4876//
4877
4878//
4879// Begin of primitives for interacting between tetrahedra and subfaces
4880//
4881
4882// tspivot() finds a subface abutting on this tetrahdera.
4883
4884inline void tetgenmesh::tspivot(triface& t, face& s) {
4885 shellface sptr = (shellface) t.tet[8 + t.loc];
4886 sdecode(sptr, s);
4887}
4888
4889// stpivot() finds a tetrahedron abutting a subface.
4890
4891inline void tetgenmesh::stpivot(face& s, triface& t) {
4892 tetrahedron ptr = (tetrahedron) s.sh[6 + EdgeRing(s.shver)];
4893 decode(ptr, t);
4894}
4895
4896// tsbond() bond a tetrahedron to a subface.
4897
4898inline void tetgenmesh::tsbond(triface& t, face& s) {
4899 t.tet[8 + t.loc] = (tetrahedron) sencode(s);
4900 s.sh[6 + EdgeRing(s.shver)] = (shellface) encode(t);
4901}
4902
4903// tsdissolve() dissolve a bond (from the tetrahedron side).
4904
4905inline void tetgenmesh::tsdissolve(triface& t) {
4906 t.tet[8 + t.loc] = (tetrahedron) dummysh;
4907}
4908
4909// stdissolve() dissolve a bond (from the subface side).
4910
4911inline void tetgenmesh::stdissolve(face& s) {
4912 s.sh[6 + EdgeRing(s.shver)] = (shellface) dummytet;
4913}
4914
4915//
4916// End of primitives for interacting between tetrahedra and subfaces
4917//
4918
4919//
4920// Begin of primitives for interacting between subfaces and subsegs
4921//
4922
4923// sspivot() finds a subsegment abutting a subface.
4924
4925inline void tetgenmesh::sspivot(face& s, face& edge) {
4926 shellface sptr = (shellface) s.sh[8 + Orient(s.shver)];
4927 sdecode(sptr, edge);
4928}
4929
4930// ssbond() bond a subface to a subsegment.
4931
4932inline void tetgenmesh::ssbond(face& s, face& edge) {
4933 s.sh[8 + Orient(s.shver)] = sencode(edge);
4934 edge.sh[0] = sencode(s);
4935}
4936
4937// ssdisolve() dissolve a bond (from the subface side)
4938
4939inline void tetgenmesh::ssdissolve(face& s) {
4940 s.sh[8 + Orient(s.shver)] = (shellface) dummysh;
4941}
4942
4943//
4944// End of primitives for interacting between subfaces and subsegs
4945//
4946
4947//
4948// Begin of primitives for interacting between tet and subsegs.
4949//
4950
4951inline void tetgenmesh::tsspivot1(triface& t, face& seg)
4952{
4953 shellface sptr = (shellface) t.tet[8 + locver2edge[t.loc][t.ver]];
4954 sdecode(sptr, seg);
4955}
4956
4957// Only bond/dissolve at tet's side, but not vice versa.
4958
4959inline void tetgenmesh::tssbond1(triface& t, face& seg)
4960{
4961 t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) sencode(seg);
4962}
4963
4964inline void tetgenmesh::tssdissolve1(triface& t)
4965{
4966 t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) dummysh;
4967}
4968
4969//
4970// End of primitives for interacting between tet and subsegs.
4971//
4972
4973//
4974// Begin of primitives for points
4975//
4976
4977inline int tetgenmesh::pointmark(point pt) {
4978 return ((int *) (pt))[pointmarkindex];
4979}
4980
4981inline void tetgenmesh::setpointmark(point pt, int value) {
4982 ((int *) (pt))[pointmarkindex] = value;
4983}
4984
4985// These two primitives set and read the type of the point.
4986
4987inline enum tetgenmesh::verttype tetgenmesh::pointtype(point pt) {
4988 return (enum verttype) ((int *) (pt))[pointmarkindex + 1];
4989}
4990
4991inline void tetgenmesh::setpointtype(point pt, enum verttype value) {
4992 ((int *) (pt))[pointmarkindex + 1] = (int) value;
4993}
4994
4995// These following primitives set and read a pointer to a tetrahedron
4996// a subface/subsegment, a point, or a tet of background mesh.
4997
4998inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) {
4999 return ((tetrahedron *) (pt))[point2simindex];
5000}
5001
5002inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) {
5003 ((tetrahedron *) (pt))[point2simindex] = value;
5004}
5005
5006inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) {
5007 return (shellface) ((tetrahedron *) (pt))[point2simindex + 1];
5008}
5009
5010inline void tetgenmesh::setpoint2sh(point pt, shellface value) {
5011 ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value;
5012}
5013
5014inline tetgenmesh::point tetgenmesh::point2ppt(point pt) {
5015 return (point) ((tetrahedron *) (pt))[point2simindex + 2];
5016}
5017
5018inline void tetgenmesh::setpoint2ppt(point pt, point value) {
5019 ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value;
5020}
5021
5022inline tetgenmesh::tetrahedron tetgenmesh::point2bgmtet(point pt) {
5023 return ((tetrahedron *) (pt))[point2simindex + 3];
5024}
5025
5026inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) {
5027 ((tetrahedron *) (pt))[point2simindex + 3] = value;
5028}
5029
5030// These primitives set and read a pointer to its pbc point.
5031
5032inline tetgenmesh::point tetgenmesh::point2pbcpt(point pt) {
5033 return (point) ((tetrahedron *) (pt))[point2pbcptindex];
5034}
5035
5036inline void tetgenmesh::setpoint2pbcpt(point pt, point value) {
5037 ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value;
5038}
5039
5040//
5041// End of primitives for points
5042//
5043
5044//
5045// Begin of advanced primitives
5046//
5047
5048// adjustedgering() adjusts the edge version so that it belongs to the
5049// indicated edge ring. The 'direction' only can be 0(CCW) or 1(CW).
5050// If the edge is not in the wanted edge ring, reverse it.
5051
5052inline void tetgenmesh::adjustedgering(triface& t, int direction) {
5053 if (EdgeRing(t.ver) != direction) {
5054 esymself(t);
5055 }
5056}
5057
5058inline void tetgenmesh::adjustedgering(face& s, int direction) {
5059 if (EdgeRing(s.shver) != direction) {
5060 sesymself(s);
5061 }
5062}
5063
5064// isdead() returns TRUE if the tetrahedron or subface has been dealloced.
5065
5066inline bool tetgenmesh::isdead(triface* t) {
5067 if (t->tet == (tetrahedron *) NULL) return true;
5068 else return t->tet[4] == (tetrahedron) NULL;
5069}
5070
5071inline bool tetgenmesh::isdead(face* s) {
5072 if (s->sh == (shellface *) NULL) return true;
5073 else return s->sh[3] == (shellface) NULL;
5074}
5075
5076// isfacehaspoint() returns TRUE if the 'testpoint' is one of the vertices
5077// of the tetface 't' subface 's'.
5078
5079inline bool tetgenmesh::isfacehaspoint(triface* t, point testpoint) {
5080 return ((org(*t) == testpoint) || (dest(*t) == testpoint) ||
5081 (apex(*t) == testpoint));
5082}
5083
5084inline bool tetgenmesh::isfacehaspoint(face* s, point testpoint) {
5085 return (s->sh[3] == (shellface) testpoint) ||
5086 (s->sh[4] == (shellface) testpoint) ||
5087 (s->sh[5] == (shellface) testpoint);
5088}
5089
5090// isfacehasedge() returns TRUE if the edge (given by its two endpoints) is
5091// one of the three edges of the subface 's'.
5092
5093inline bool tetgenmesh::isfacehasedge(face* s, point tend1, point tend2) {
5094 return (isfacehaspoint(s, tend1) && isfacehaspoint(s, tend2));
5095}
5096
5097// issymexist() returns TRUE if the adjoining tetrahedron is not 'duumytet'.
5098
5099inline bool tetgenmesh::issymexist(triface* t) {
5100 tetrahedron *ptr = (tetrahedron *)
5101 ((unsigned long)(t->tet[t->loc]) & ~(unsigned long)7l);
5102 return ptr != dummytet;
5103}
5104
5106// //
5107// getnextsface() Finds the next subface in the face ring. //
5108// //
5109// For saving space in the data structure of subface, there only exists one //
5110// face ring around a segment (see programming manual). This routine imple- //
5111// ments the double face ring as desired in Muecke's data structure. //
5112// //
5114
5115void tetgenmesh::getnextsface(face* s1, face* s2)
5116{
5117 face neighsh, spinsh;
5118 face testseg;
5119
5120 sspivot(*s1, testseg);
5121 if (testseg.sh != dummysh) {
5122 testseg.shver = 0;
5123 if (sorg(testseg) == sorg(*s1)) {
5124 spivot(*s1, neighsh);
5125 } else {
5126 spinsh = *s1;
5127 do {
5128 neighsh = spinsh;
5129 spivotself(spinsh);
5130 } while (spinsh.sh != s1->sh);
5131 }
5132 } else {
5133 spivot(*s1, neighsh);
5134 }
5135 if (sorg(neighsh) != sorg(*s1)) {
5136 sesymself(neighsh);
5137 }
5138 if (s2 != (face *) NULL) {
5139 *s2 = neighsh;
5140 } else {
5141 *s1 = neighsh;
5142 }
5143}
5144
5146// //
5147// tsspivot() Finds a subsegment abutting on a tetrahderon's edge. //
5148// //
5149// The edge is represented in the primary edge of 'checkedge'. If there is a //
5150// subsegment bonded at this edge, it is returned in handle 'checkseg', the //
5151// edge direction of 'checkseg' is conformed to 'checkedge'. If there isn't, //
5152// set 'checkseg.sh = dummysh' to indicate it is not a subsegment. //
5153// //
5154// To find whether an edge of a tetrahedron is a subsegment or not. First we //
5155// need find a subface around this edge to see if it contains a subsegment. //
5156// The reason is there is no direct connection between a tetrahedron and its //
5157// adjoining subsegments. //
5158// //
5160
5161void tetgenmesh::tsspivot(triface* checkedge, face* checkseg)
5162{
5163 triface spintet;
5164 face parentsh;
5165 point tapex;
5166 int hitbdry;
5167
5168 spintet = *checkedge;
5169 tapex = apex(*checkedge);
5170 hitbdry = 0;
5171 do {
5172 tspivot(spintet, parentsh);
5173 // Does spintet have a (non-fake) subface attached?
5174 if ((parentsh.sh != dummysh) && (sapex(parentsh) != NULL)) {
5175 // Find a subface! Find the edge in it.
5176 findedge(&parentsh, org(*checkedge), dest(*checkedge));
5177 sspivot(parentsh, *checkseg);
5178 if (checkseg->sh != dummysh) {
5179 // Find a subsegment! Correct its edge direction before return.
5180 if (sorg(*checkseg) != org(*checkedge)) {
5181 sesymself(*checkseg);
5182 }
5183 }
5184 return;
5185 }
5186 if (!fnextself(spintet)) {
5187 hitbdry++;
5188 if (hitbdry < 2) {
5189 esym(*checkedge, spintet);
5190 if (!fnextself(spintet)) {
5191 hitbdry++;
5192 }
5193 }
5194 }
5195 } while ((apex(spintet) != tapex) && (hitbdry < 2));
5196 // Not find.
5197 checkseg->sh = dummysh;
5198}
5199
5201// //
5202// sstpivot() Finds a tetrahedron abutting a subsegment. //
5203// //
5204// This is the inverse operation of 'tsspivot()'. One subsegment shared by //
5205// arbitrary number of tetrahedron, the returned tetrahedron is not unique. //
5206// The edge direction of the returned tetrahedron is conformed to the given //
5207// subsegment. //
5208// //
5210
5211void tetgenmesh::sstpivot(face* checkseg, triface* retedge)
5212{
5213 face parentsh;
5214
5215 // Get the subface which holds the subsegment.
5216 sdecode(checkseg->sh[0], parentsh);
5217#ifdef SELF_CHECK
5218 assert(parentsh.sh != dummysh);
5219#endif
5220 // Get a tetraheron to which the subface attches.
5221 stpivot(parentsh, *retedge);
5222 if (retedge->tet == dummytet) {
5223 sesymself(parentsh);
5224 stpivot(parentsh, *retedge);
5225#ifdef SELF_CHECK
5226 assert(retedge->tet != dummytet);
5227#endif
5228 }
5229 // Correct the edge direction before return.
5230 findedge(retedge, sorg(*checkseg), sdest(*checkseg));
5231}
5232
5234// //
5235// findorg() Finds a point in the given handle (tetrahedron or subface). //
5236// //
5237// If 'dorg' is a one of vertices of the given handle, set the origin of //
5238// this handle be that point and return TRUE. Otherwise, return FALSE and //
5239// 'tface' remains unchanged. //
5240// //
5242
5243bool tetgenmesh::findorg(triface* tface, point dorg)
5244{
5245 if (org(*tface) == dorg) {
5246 return true;
5247 } else {
5248 if (dest(*tface) == dorg) {
5249 enextself(*tface);
5250 return true;
5251 } else {
5252 if (apex(*tface) == dorg) {
5253 enext2self(*tface);
5254 return true;
5255 } else {
5256 if (oppo(*tface) == dorg) {
5257 // Keep 'tface' referring to the same tet after fnext().
5258 adjustedgering(*tface, CCW);
5259 fnextself(*tface);
5260 enext2self(*tface);
5261 return true;
5262 }
5263 }
5264 }
5265 }
5266 return false;
5267}
5268
5269bool tetgenmesh::findorg(face* sface, point dorg)
5270{
5271 if (sorg(*sface) == dorg) {
5272 return true;
5273 } else {
5274 if (sdest(*sface) == dorg) {
5275 senextself(*sface);
5276 return true;
5277 } else {
5278 if (sapex(*sface) == dorg) {
5279 senext2self(*sface);
5280 return true;
5281 }
5282 }
5283 }
5284 return false;
5285}
5286
5288// //
5289// findedge() Find an edge in the given handle (tetrahedron or subface). //
5290// //
5291// The edge is given in two points 'eorg' and 'edest'. It is assumed that //
5292// the edge must exist in the given handle (tetrahedron or subface). This //
5293// routine sets the right edge version for the input handle. //
5294// //
5296
5297void tetgenmesh::findedge(triface* tface, point eorg, point edest)
5298{
5299 int i;
5300
5301 for (i = 0; i < 3; i++) {
5302 if (org(*tface) == eorg) {
5303 if (dest(*tface) == edest) {
5304 // Edge is found, return.
5305 return;
5306 }
5307 } else {
5308 if (org(*tface) == edest) {
5309 if (dest(*tface) == eorg) {
5310 // Edge is found, inverse the direction and return.
5311 esymself(*tface);
5312 return;
5313 }
5314 }
5315 }
5316 enextself(*tface);
5317 }
5318 // It should never be here.
5319 printf("Internalerror in findedge(): Unable to find an edge in tet.\n");
5320 internalerror();
5321}
5322
5323void tetgenmesh::findedge(face* sface, point eorg, point edest)
5324{
5325 int i;
5326
5327 for (i = 0; i < 3; i++) {
5328 if (sorg(*sface) == eorg) {
5329 if (sdest(*sface) == edest) {
5330 // Edge is found, return.
5331 return;
5332 }
5333 } else {
5334 if (sorg(*sface) == edest) {
5335 if (sdest(*sface) == eorg) {
5336 // Edge is found, inverse the direction and return.
5337 sesymself(*sface);
5338 return;
5339 }
5340 }
5341 }
5342 senextself(*sface);
5343 }
5344 printf("Internalerror in findedge(): Unable to find an edge in subface.\n");
5345 internalerror();
5346}
5347
5349// //
5350// findface() Find the face has the given origin, destination and apex. //
5351// //
5352// On input, 'fface' is a handle which may contain the three corners or may //
5353// not or may be dead. On return, it represents exactly the face with the //
5354// given origin, destination and apex. //
5355// //
5357
5358void tetgenmesh::findface(triface *fface, point forg, point fdest, point fapex)
5359{
5360 triface spintet;
5361 enum finddirectionresult collinear;
5362 int hitbdry;
5363
5364 if (!isdead(fface)) {
5365 // First check the easiest case, that 'fface' is just the right one.
5366 if (org(*fface) == forg && dest(*fface) == fdest &&
5367 apex(*fface) == fapex) return;
5368 } else {
5369 // The input handle is dead, use the 'recenttet' if it is alive.
5370 if (!isdead(&recenttet)) *fface = recenttet;
5371 }
5372
5373 if (!isdead(fface)) {
5374 if (!findorg(fface, forg)) {
5375 // 'forg' is not a corner of 'fface', locate it.
5376 preciselocate(forg, fface, tetrahedrons->items);
5377 }
5378 // It is possible that forg is not found in a non-convex mesh.
5379 if (org(*fface) == forg) {
5380 collinear = finddirection(fface, fdest, tetrahedrons->items);
5381 if (collinear == RIGHTCOLLINEAR) {
5382 // fdest is just the destination.
5383 } else if (collinear == LEFTCOLLINEAR) {
5384 enext2self(*fface);
5385 esymself(*fface);
5386 } else if (collinear == TOPCOLLINEAR) {
5387 fnextself(*fface);
5388 enext2self(*fface);
5389 esymself(*fface);
5390 }
5391 }
5392 // It is possible taht fdest is not found in a non-convex mesh.
5393 if ((org(*fface) == forg) && (dest(*fface) == fdest)) {
5394 // Find the apex of 'fapex'.
5395 spintet = *fface;
5396 hitbdry = 0;
5397 do {
5398 if (apex(spintet) == fapex) {
5399 // We have done. Be careful the edge direction of 'spintet',
5400 // it may reversed because of hitting boundary once.
5401 if (org(spintet) != org(*fface)) {
5402 esymself(spintet);
5403 }
5404 *fface = spintet;
5405 return;
5406 }
5407 if (!fnextself(spintet)) {
5408 hitbdry ++;
5409 if (hitbdry < 2) {
5410 esym(*fface, spintet);
5411 if (!fnextself(spintet)) {
5412 hitbdry ++;
5413 }
5414 }
5415 }
5416 } while (hitbdry < 2 && apex(spintet) != apex(*fface));
5417 // It is possible that fapex is not found in a non-convex mesh.
5418 }
5419 }
5420
5421 if (isdead(fface) || (org(*fface) != forg) || (dest(*fface) != fdest) ||
5422 (apex(*fface) != fapex)) {
5423 // Too bad, the input handle is useless. We have to find a handle
5424 // for 'fface' contains the 'forg' and 'fdest'. Here a brute force
5425 // search is performed.
5426 if (b->verbose > 1) {
5427 printf("Warning in findface(): Perform a brute-force searching.\n");
5428 }
5429 enum verttype forgty, fdestty, fapexty;
5430 int share, i;
5431 forgty = pointtype(forg);
5432 fdestty = pointtype(fdest);
5433 fapexty = pointtype(fapex);
5434 setpointtype(forg, DEADVERTEX);
5435 setpointtype(fdest, DEADVERTEX);
5436 setpointtype(fapex, DEADVERTEX);
5437 tetrahedrons->traversalinit();
5438 fface->tet = tetrahedrontraverse();
5439 while (fface->tet != (tetrahedron *) NULL) {
5440 share = 0;
5441 for (i = 0; i < 4; i++) {
5442 if (pointtype((point) fface->tet[4 + i]) == DEADVERTEX) share ++;
5443 }
5444 if (share == 3) {
5445 // Found! Set the correct face and desired corners.
5446 if (pointtype((point) fface->tet[4]) != DEADVERTEX) {
5447 fface->loc = 2;
5448 } else if (pointtype((point) fface->tet[5]) != DEADVERTEX) {
5449 fface->loc = 3;
5450 } else if (pointtype((point) fface->tet[6]) != DEADVERTEX) {
5451 fface->loc = 1;
5452 } else { // pointtype((point) fface->tet[7]) != DEADVERTEX
5453 fface->loc = 0;
5454 }
5455 findedge(fface, forg, fdest);
5456 break;
5457 }
5458 fface->tet = tetrahedrontraverse();
5459 }
5460 setpointtype(forg, forgty);
5461 setpointtype(fdest, fdestty);
5462 setpointtype(fapex, fapexty);
5463 if (fface->tet == (tetrahedron *) NULL) {
5464 // It is impossible to reach here.
5465 printf("Internal error: Fail to find the indicated face.\n");
5466 internalerror();
5467 }
5468 }
5469}
5470
5472// //
5473// getonextseg() Get the next SEGMENT counterclockwise with the same org. //
5474// //
5475// 's' is a subface. This routine reteuns the segment which is counterclock- //
5476// wise with the origin of s. //
5477// //
5479
5480void tetgenmesh::getonextseg(face* s, face* lseg)
5481{
5482 face checksh, checkseg;
5483 point forg;
5484
5485 forg = sorg(*s);
5486 checksh = *s;
5487 do {
5488 // Go to the edge at forg's left side.
5489 senext2self(checksh);
5490 // Check if there is a segment attaching this edge.
5491 sspivot(checksh, checkseg);
5492 if (checkseg.sh != dummysh) break;
5493 // No segment! Go to the neighbor of this subface.
5494 spivotself(checksh);
5495#ifdef SELF_CHECK
5496 // It should always meet a segment before come back.
5497 assert(checksh.sh != s->sh);
5498#endif
5499 if (sorg(checksh) != forg) {
5500 sesymself(checksh);
5501#ifdef SELF_CHECK
5502 assert(sorg(checksh) == forg);
5503#endif
5504 }
5505 } while (true);
5506 if (sorg(checkseg) != forg) sesymself(checkseg);
5507 *lseg = checkseg;
5508}
5509
5511// //
5512// getseghasorg() Get the segment containing the given point. //
5513// //
5514// 'dorg' is an endpoint of a segment S. 'sseg' is a subsegment of S. This //
5515// routine search a subsegment (along sseg) of S containing dorg. On return, //
5516// 'sseg' contains 'dorg' as its origin. //
5517// //
5519
5520void tetgenmesh::getseghasorg(face* sseg, point dorg)
5521{
5522 face nextseg;
5523 point checkpt;
5524
5525 nextseg = *sseg;
5526 checkpt = sorg(nextseg);
5527 while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) {
5528 // Search dorg along the original direction of sseg.
5529 senext2self(nextseg);
5530 spivotself(nextseg);
5531 nextseg.shver = 0;
5532 if (sdest(nextseg) != checkpt) sesymself(nextseg);
5533 checkpt = sorg(nextseg);
5534 }
5535 if (checkpt == dorg) {
5536 *sseg = nextseg;
5537 return;
5538 }
5539 nextseg = *sseg;
5540 checkpt = sdest(nextseg);
5541 while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) {
5542 // Search dorg along the destinational direction of sseg.
5543 senextself(nextseg);
5544 spivotself(nextseg);
5545 nextseg.shver = 0;
5546 if (sorg(nextseg) != checkpt) sesymself(nextseg);
5547 checkpt = sdest(nextseg);
5548 }
5549 if (checkpt == dorg) {
5550 sesym(nextseg, *sseg);
5551 return;
5552 }
5553 // Should never be here.
5554 printf("Internalerror in getseghasorg(): Unable to find the subseg.\n");
5555 internalerror();
5556}
5557
5559// //
5560// getsubsegfarorg() Get the origin of the parent segment of a subseg. //
5561// //
5563
5564tetgenmesh::point tetgenmesh::getsubsegfarorg(face* sseg)
5565{
5566 face prevseg;
5567 point checkpt;
5568
5569 checkpt = sorg(*sseg);
5570 senext2(*sseg, prevseg);
5571 spivotself(prevseg);
5572 // Search dorg along the original direction of sseg.
5573 while (prevseg.sh != dummysh) {
5574 prevseg.shver = 0;
5575 if (sdest(prevseg) != checkpt) sesymself(prevseg);
5576 checkpt = sorg(prevseg);
5577 senext2self(prevseg);
5578 spivotself(prevseg);
5579 }
5580 return checkpt;
5581}
5582
5584// //
5585// getsubsegfardest() Get the dest. of the parent segment of a subseg. //
5586// //
5588
5589tetgenmesh::point tetgenmesh::getsubsegfardest(face* sseg)
5590{
5591 face nextseg;
5592 point checkpt;
5593
5594 checkpt = sdest(*sseg);
5595 senext(*sseg, nextseg);
5596 spivotself(nextseg);
5597 // Search dorg along the destinational direction of sseg.
5598 while (nextseg.sh != dummysh) {
5599 nextseg.shver = 0;
5600 if (sorg(nextseg) != checkpt) sesymself(nextseg);
5601 checkpt = sdest(nextseg);
5602 senextself(nextseg);
5603 spivotself(nextseg);
5604 }
5605 return checkpt;
5606}
5607
5609// //
5610// printtet() Print out the details of a tetrahedron on screen. //
5611// //
5612// It's also used when the highest level of verbosity (`-VVV') is specified. //
5613// //
5615
5616void tetgenmesh::printtet(triface* tface)
5617{
5618 triface tmpface, prtface;
5619 point tmppt;
5620 face tmpsh;
5621 int facecount;
5622
5623 printf("Tetra x%lx with loc(%i) and ver(%i):",
5624 (unsigned long)(tface->tet), tface->loc, tface->ver);
5625 if (infected(*tface)) {
5626 printf(" (infected)");
5627 }
5628 printf("\n");
5629
5630 tmpface = *tface;
5631 facecount = 0;
5632 while(facecount < 4) {
5633 tmpface.loc = facecount;
5634 sym(tmpface, prtface);
5635 if(prtface.tet == dummytet) {
5636 printf(" [%i] Outer space.\n", facecount);
5637 } else {
5638 printf(" [%i] x%lx loc(%i).", facecount,
5639 (unsigned long)(prtface.tet), prtface.loc);
5640 if (infected(prtface)) {
5641 printf(" (infected)");
5642 }
5643 printf("\n");
5644 }
5645 facecount ++;
5646 }
5647
5648 tmppt = org(*tface);
5649 if(tmppt == (point) NULL) {
5650 printf(" Org [%i] NULL\n", locver2org[tface->loc][tface->ver]);
5651 } else {
5652 printf(" Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5653 locver2org[tface->loc][tface->ver], (unsigned long)(tmppt),
5654 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5655 }
5656 tmppt = dest(*tface);
5657 if(tmppt == (point) NULL) {
5658 printf(" Dest[%i] NULL\n", locver2dest[tface->loc][tface->ver]);
5659 } else {
5660 printf(" Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5661 locver2dest[tface->loc][tface->ver], (unsigned long)(tmppt),
5662 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5663 }
5664 tmppt = apex(*tface);
5665 if(tmppt == (point) NULL) {
5666 printf(" Apex[%i] NULL\n", locver2apex[tface->loc][tface->ver]);
5667 } else {
5668 printf(" Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5669 locver2apex[tface->loc][tface->ver], (unsigned long)(tmppt),
5670 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5671 }
5672 tmppt = oppo(*tface);
5673 if(tmppt == (point) NULL) {
5674 printf(" Oppo[%i] NULL\n", loc2oppo[tface->loc]);
5675 } else {
5676 printf(" Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5677 loc2oppo[tface->loc], (unsigned long)(tmppt),
5678 tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5679 }
5680
5681 if (b->useshelles) {
5682 tmpface = *tface;
5683 facecount = 0;
5684 while(facecount < 6) {
5685 tmpface.loc = facecount;
5686 tspivot(tmpface, tmpsh);
5687 if(tmpsh.sh != dummysh) {
5688 printf(" [%i] x%lx ID(%i) ", facecount,
5689 (unsigned long)(tmpsh.sh), shellmark(tmpsh));
5690 if (sorg(tmpsh) == (point) NULL) {
5691 printf("(fake)");
5692 }
5693 printf("\n");
5694 }
5695 facecount ++;
5696 }
5697 }
5698}
5699
5701// //
5702// printsh() Print out the details of a subface or subsegment on screen. //
5703// //
5704// It's also used when the highest level of verbosity (`-VVV') is specified. //
5705// //
5707
5708void tetgenmesh::printsh(face* sface)
5709{
5710 face prtsh;
5711 triface prttet;
5712 point printpoint;
5713
5714 if (sapex(*sface) != NULL) {
5715 printf("subface x%lx, ver %d, mark %d:",
5716 (unsigned long)(sface->sh), sface->shver, shellmark(*sface));
5717 } else {
5718 printf("Subsegment x%lx, ver %d, mark %d:",
5719 (unsigned long)(sface->sh), sface->shver, shellmark(*sface));
5720 }
5721 if (sinfected(*sface)) {
5722 printf(" (infected)");
5723 }
5724 if (shell2badface(*sface)) {
5725 printf(" (queued)");
5726 }
5727 if (sapex(*sface) != NULL) {
5728 if (shelltype(*sface) == SHARP) {
5729 printf(" (sharp)");
5730 }
5731 } else {
5732 if (shelltype(*sface) == SHARP) {
5733 printf(" (sharp)");
5734 }
5735 }
5736 if (checkpbcs) {
5737 if (shellpbcgroup(*sface) >= 0) {
5738 printf(" (pbc %d)", shellpbcgroup(*sface));
5739 }
5740 }
5741 printf("\n");
5742
5743 sdecode(sface->sh[0], prtsh);
5744 if (prtsh.sh == dummysh) {
5745 printf(" [0] = No shell\n");
5746 } else {
5747 printf(" [0] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
5748 }
5749 sdecode(sface->sh[1], prtsh);
5750 if (prtsh.sh == dummysh) {
5751 printf(" [1] = No shell\n");
5752 } else {
5753 printf(" [1] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
5754 }
5755 sdecode(sface->sh[2], prtsh);
5756 if (prtsh.sh == dummysh) {
5757 printf(" [2] = No shell\n");
5758 } else {
5759 printf(" [2] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
5760 }
5761
5762 printpoint = sorg(*sface);
5763 if (printpoint == (point) NULL)
5764 printf(" Org [%d] = NULL\n", vo[sface->shver]);
5765 else
5766 printf(" Org [%d] = x%lx (%.12g,%.12g,%.12g) %d\n",
5767 vo[sface->shver], (unsigned long)(printpoint), printpoint[0],
5768 printpoint[1], printpoint[2], pointmark(printpoint));
5769 printpoint = sdest(*sface);
5770 if (printpoint == (point) NULL)
5771 printf(" Dest[%d] = NULL\n", vd[sface->shver]);
5772 else
5773 printf(" Dest[%d] = x%lx (%.12g,%.12g,%.12g) %d\n",
5774 vd[sface->shver], (unsigned long)(printpoint), printpoint[0],
5775 printpoint[1], printpoint[2], pointmark(printpoint));
5776
5777 if (sapex(*sface) != NULL) {
5778 printpoint = sapex(*sface);
5779 if (printpoint == (point) NULL)
5780 printf(" Apex[%d] = NULL\n", va[sface->shver]);
5781 else
5782 printf(" Apex[%d] = x%lx (%.12g,%.12g,%.12g) %d\n",
5783 va[sface->shver], (unsigned long)(printpoint), printpoint[0],
5784 printpoint[1], printpoint[2], pointmark(printpoint));
5785
5786 decode(sface->sh[6], prttet);
5787 if (prttet.tet == dummytet) {
5788 printf(" [6] = Outer space\n");
5789 } else {
5790 printf(" [6] = x%lx %d\n",
5791 (unsigned long)(prttet.tet), prttet.loc);
5792 }
5793 decode(sface->sh[7], prttet);
5794 if (prttet.tet == dummytet) {
5795 printf(" [7] = Outer space\n");
5796 } else {
5797 printf(" [7] = x%lx %d\n",
5798 (unsigned long)(prttet.tet), prttet.loc);
5799 }
5800
5801 sdecode(sface->sh[8], prtsh);
5802 if (prtsh.sh == dummysh) {
5803 printf(" [8] = No subsegment\n");
5804 } else {
5805 printf(" [8] = x%lx %d\n",
5806 (unsigned long)(prtsh.sh), prtsh.shver);
5807 }
5808 sdecode(sface->sh[9], prtsh);
5809 if (prtsh.sh == dummysh) {
5810 printf(" [9] = No subsegment\n");
5811 } else {
5812 printf(" [9] = x%lx %d\n",
5813 (unsigned long)(prtsh.sh), prtsh.shver);
5814 }
5815 sdecode(sface->sh[10], prtsh);
5816 if (prtsh.sh == dummysh) {
5817 printf(" [10]= No subsegment\n");
5818 } else {
5819 printf(" [10]= x%lx %d\n",
5820 (unsigned long)(prtsh.sh), prtsh.shver);
5821 }
5822 }
5823}
5824
5825//
5826// End of advanced primitives
5827//
5828
5829//
5830// End of mesh manipulation primitives
5831//
5832
5833//
5834// Begin of mesh items searching routines
5835//
5836
5838// //
5839// makepoint2tetmap() Construct a mapping from points to tetrahedra. //
5840// //
5841// Traverses all the tetrahedra, provides each corner of each tetrahedron //
5842// with a pointer to that tetrahedera. Some pointers will be overwritten by //
5843// other pointers because each point may be a corner of several tetrahedra, //
5844// but in the end every point will point to a tetrahedron that contains it. //
5845// //
5847
5848void tetgenmesh::makepoint2tetmap()
5849{
5850 triface tetloop;
5851 point pointptr;
5852
5853 if (b->verbose > 0) {
5854 printf(" Constructing mapping from points to tetrahedra.\n");
5855 }
5856
5857 // Initialize the point2tet field of each point.
5858 points->traversalinit();
5859 pointptr = pointtraverse();
5860 while (pointptr != (point) NULL) {
5861 setpoint2tet(pointptr, (tetrahedron) NULL);
5862 pointptr = pointtraverse();
5863 }
5864
5865 tetrahedrons->traversalinit();
5866 tetloop.tet = tetrahedrontraverse();
5867 while (tetloop.tet != (tetrahedron *) NULL) {
5868 // Check all four points of the tetrahedron.
5869 tetloop.loc = 0;
5870 pointptr = org(tetloop);
5871 setpoint2tet(pointptr, encode(tetloop));
5872 pointptr = dest(tetloop);
5873 setpoint2tet(pointptr, encode(tetloop));
5874 pointptr = apex(tetloop);
5875 setpoint2tet(pointptr, encode(tetloop));
5876 pointptr = oppo(tetloop);
5877 setpoint2tet(pointptr, encode(tetloop));
5878 // Get the next tetrahedron in the list.
5879 tetloop.tet = tetrahedrontraverse();
5880 }
5881}
5882
5884// //
5885// makeindex2pointmap() Create a map from index to vertices. //
5886// //
5887// 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
5888// to each vertex is set into the array. The pointer to the first vertex is //
5889// saved in 'idx2verlist[0]'. Don't forget to minus 'in->firstnumber' when //
5890// to get the vertex form its index. //
5891// //
5893
5894void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
5895{
5896 point pointloop;
5897 int idx;
5898
5899 if (b->verbose > 0) {
5900 printf(" Constructing mapping from indices to points.\n");
5901 }
5902
5903 idx2verlist = new point[points->items];
5904
5905 points->traversalinit();
5906 pointloop = pointtraverse();
5907 idx = 0;
5908 while (pointloop != (point) NULL) {
5909 idx2verlist[idx] = pointloop;
5910 idx++;
5911 pointloop = pointtraverse();
5912 }
5913}
5914
5916// //
5917// makesegmentmap() Create a map from vertices (their indices) to //
5918// segments incident at the same vertices. //
5919// //
5920// Two arrays 'idx2seglist' and 'segsperverlist' together return the map. //
5921// They form a sparse matrix structure with size (n + 1) x (n + 1), n is the //
5922// number of segments. idx2seglist contains row information and //
5923// segsperverlist contains all (non-zero) elements. The i-th entry of //
5924// idx2seglist is the starting position of i-th row's (non-zero) elements in //
5925// segsperverlist. The number of elements of i-th row is calculated by the //
5926// (i+1)-th entry minus i-th entry of idx2seglist. //
5927// //
5928// NOTE: These two arrays will be created inside this routine, don't forget //
5929// to free them after using. //
5930// //
5932
5933void tetgenmesh::makesegmentmap(int*& idx2seglist, shellface**& segsperverlist)
5934{
5935 shellface *shloop;
5936 int i, j, k;
5937
5938 if (b->verbose > 0) {
5939 printf(" Constructing mapping from points to segments.\n");
5940 }
5941
5942 // Create and initialize 'idx2seglist'.
5943 idx2seglist = new int[points->items + 1];
5944 for (i = 0; i < points->items + 1; i++) idx2seglist[i] = 0;
5945
5946 // Loop the set of segments once, counter the number of segments sharing
5947 // each vertex.
5948 subsegs->traversalinit();
5949 shloop = shellfacetraverse(subsegs);
5950 while (shloop != (shellface *) NULL) {
5951 // Increment the number of sharing segments for each endpoint.
5952 for (i = 0; i < 2; i++) {
5953 j = pointmark((point) shloop[3 + i]) - in->firstnumber;
5954 idx2seglist[j]++;
5955 }
5956 shloop = shellfacetraverse(subsegs);
5957 }
5958
5959 // Calculate the total length of array 'facesperverlist'.
5960 j = idx2seglist[0];
5961 idx2seglist[0] = 0; // Array starts from 0 element.
5962 for (i = 0; i < points->items; i++) {
5963 k = idx2seglist[i + 1];
5964 idx2seglist[i + 1] = idx2seglist[i] + j;
5965 j = k;
5966 }
5967 // The total length is in the last unit of idx2seglist.
5968 segsperverlist = new shellface*[idx2seglist[i]];
5969 // Loop the set of segments again, set the info. of segments per vertex.
5970 subsegs->traversalinit();
5971 shloop = shellfacetraverse(subsegs);
5972 while (shloop != (shellface *) NULL) {
5973 for (i = 0; i < 2; i++) {
5974 j = pointmark((point) shloop[3 + i]) - in->firstnumber;
5975 segsperverlist[idx2seglist[j]] = shloop;
5976 idx2seglist[j]++;
5977 }
5978 shloop = shellfacetraverse(subsegs);
5979 }
5980 // Contents in 'idx2seglist' are shifted, now shift them back.
5981 for (i = points->items - 1; i >= 0; i--) {
5982 idx2seglist[i + 1] = idx2seglist[i];
5983 }
5984 idx2seglist[0] = 0;
5985}
5986
5988// //
5989// makesubfacemap() Create a map from vertices (their indices) to //
5990// subfaces incident at the same vertices. //
5991// //
5992// Two arrays 'idx2facelist' and 'facesperverlist' together return the map. //
5993// They form a sparse matrix structure with size (n + 1) x (n + 1), n is the //
5994// number of subfaces. idx2facelist contains row information and //
5995// facesperverlist contains all (non-zero) elements. The i-th entry of //
5996// idx2facelist is the starting position of i-th row's(non-zero) elements in //
5997// facesperverlist. The number of elements of i-th row is calculated by the //
5998// (i+1)-th entry minus i-th entry of idx2facelist. //
5999// //
6000// NOTE: These two arrays will be created inside this routine, don't forget //
6001// to free them after using. //
6002// //
6004
6005void tetgenmesh::
6006makesubfacemap(int*& idx2facelist, shellface**& facesperverlist)
6007{
6008 shellface *shloop;
6009 int i, j, k;
6010
6011 if (b->verbose > 0) {
6012 printf(" Constructing mapping from points to subfaces.\n");
6013 }
6014
6015 // Create and initialize 'idx2facelist'.
6016 idx2facelist = new int[points->items + 1];
6017 for (i = 0; i < points->items + 1; i++) idx2facelist[i] = 0;
6018
6019 // Loop the set of subfaces once, counter the number of subfaces sharing
6020 // each vertex.
6021 subfaces->traversalinit();
6022 shloop = shellfacetraverse(subfaces);
6023 while (shloop != (shellface *) NULL) {
6024 // Increment the number of sharing segments for each endpoint.
6025 for (i = 0; i < 3; i++) {
6026 j = pointmark((point) shloop[3 + i]) - in->firstnumber;
6027 idx2facelist[j]++;
6028 }
6029 shloop = shellfacetraverse(subfaces);
6030 }
6031
6032 // Calculate the total length of array 'facesperverlist'.
6033 j = idx2facelist[0];
6034 idx2facelist[0] = 0; // Array starts from 0 element.
6035 for (i = 0; i < points->items; i++) {
6036 k = idx2facelist[i + 1];
6037 idx2facelist[i + 1] = idx2facelist[i] + j;
6038 j = k;
6039 }
6040 // The total length is in the last unit of idx2facelist.
6041 facesperverlist = new shellface*[idx2facelist[i]];
6042 // Loop the set of segments again, set the info. of segments per vertex.
6043 subfaces->traversalinit();
6044 shloop = shellfacetraverse(subfaces);
6045 while (shloop != (shellface *) NULL) {
6046 for (i = 0; i < 3; i++) {
6047 j = pointmark((point) shloop[3 + i]) - in->firstnumber;
6048 facesperverlist[idx2facelist[j]] = shloop;
6049 idx2facelist[j]++;
6050 }
6051 shloop = shellfacetraverse(subfaces);
6052 }
6053 // Contents in 'idx2facelist' are shifted, now shift them back.
6054 for (i = points->items - 1; i >= 0; i--) {
6055 idx2facelist[i + 1] = idx2facelist[i];
6056 }
6057 idx2facelist[0] = 0;
6058}
6059
6061// //
6062// maketetrahedronmap() Create a map from vertices (their indices) to //
6063// tetrahedra incident at the same vertices. //
6064// //
6065// Two arrays 'idx2tetlist' and 'tetsperverlist' together return the map. //
6066// They form a sparse matrix structure with size (n + 1) x (n + 1), n is the //
6067// number of tetrahedra. idx2tetlist contains row information and //
6068// tetsperverlist contains all (non-zero) elements. The i-th entry of //
6069// idx2tetlist is the starting position of i-th row's (non-zero) elements in //
6070// tetsperverlist. The number of elements of i-th row is calculated by the //
6071// (i+1)-th entry minus i-th entry of idx2tetlist. //
6072// //
6073// NOTE: These two arrays will be created inside this routine, don't forget //
6074// to free them after using. //
6075// //
6077
6078void tetgenmesh::
6079maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist)
6080{
6081 tetrahedron *tetloop;
6082 int i, j, k;
6083
6084 if (b->verbose > 0) {
6085 printf(" Constructing mapping from points to tetrahedra.\n");
6086 }
6087
6088 // Create and initialize 'idx2tetlist'.
6089 idx2tetlist = new int[points->items + 1];
6090 for (i = 0; i < points->items + 1; i++) idx2tetlist[i] = 0;
6091
6092 // Loop the set of tetrahedra once, counter the number of tetrahedra
6093 // sharing each vertex.
6094 tetrahedrons->traversalinit();
6095 tetloop = tetrahedrontraverse();
6096 while (tetloop != (tetrahedron *) NULL) {
6097 // Increment the number of sharing tetrahedra for each endpoint.
6098 for (i = 0; i < 4; i++) {
6099 j = pointmark((point) tetloop[4 + i]) - in->firstnumber;
6100 idx2tetlist[j]++;
6101 }
6102 tetloop = tetrahedrontraverse();
6103 }
6104
6105 // Calculate the total length of array 'tetsperverlist'.
6106 j = idx2tetlist[0];
6107 idx2tetlist[0] = 0; // Array starts from 0 element.
6108 for (i = 0; i < points->items; i++) {
6109 k = idx2tetlist[i + 1];
6110 idx2tetlist[i + 1] = idx2tetlist[i] + j;
6111 j = k;
6112 }
6113 // The total length is in the last unit of idx2tetlist.
6114 tetsperverlist = new tetrahedron*[idx2tetlist[i]];
6115 // Loop the set of tetrahedra again, set the info. of tet. per vertex.
6116 tetrahedrons->traversalinit();
6117 tetloop = tetrahedrontraverse();
6118 while (tetloop != (tetrahedron *) NULL) {
6119 for (i = 0; i < 4; i++) {
6120 j = pointmark((point) tetloop[4 + i]) - in->firstnumber;
6121 tetsperverlist[idx2tetlist[j]] = tetloop;
6122 idx2tetlist[j]++;
6123 }
6124 tetloop = tetrahedrontraverse();
6125 }
6126 // Contents in 'idx2tetlist' are shifted, now shift them back.
6127 for (i = points->items - 1; i >= 0; i--) {
6128 idx2tetlist[i + 1] = idx2tetlist[i];
6129 }
6130 idx2tetlist[0] = 0;
6131}
6132
6133//
6134// End of mesh items searching routines
6135//
6136
6137//
6138// Begin of linear algebra functions
6139//
6140
6141// dot() returns the dot product: v1 dot v2.
6142
6143inline REAL tetgenmesh::dot(REAL* v1, REAL* v2)
6144{
6145 return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
6146}
6147
6148// cross() computes the cross product: n = v1 cross v2.
6149
6150inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n)
6151{
6152 n[0] = v1[1] * v2[2] - v2[1] * v1[2];
6153 n[1] = -(v1[0] * v2[2] - v2[0] * v1[2]);
6154 n[2] = v1[0] * v2[1] - v2[0] * v1[1];
6155}
6156
6157// initm44() initializes a 4x4 matrix.
6158static void initm44(REAL a00, REAL a01, REAL a02, REAL a03,
6159 REAL a10, REAL a11, REAL a12, REAL a13,
6160 REAL a20, REAL a21, REAL a22, REAL a23,
6161 REAL a30, REAL a31, REAL a32, REAL a33,
6162 REAL M[4][4])
6163{
6164 M[0][0] = a00; M[0][1] = a01; M[0][2] = a02; M[0][3] = a03;
6165 M[1][0] = a10; M[1][1] = a11; M[1][2] = a12; M[1][3] = a13;
6166 M[2][0] = a20; M[2][1] = a21; M[2][2] = a22; M[2][3] = a23;
6167 M[3][0] = a30; M[3][1] = a31; M[3][2] = a32; M[3][3] = a33;
6168}
6169
6170// m4xm4() multiplies 2 4x4 matrics: m1 = m1 * m2.
6171static void m4xm4(REAL m1[4][4], REAL m2[4][4])
6172{
6173 REAL tmp[4];
6174 int i, j;
6175
6176 for (i = 0; i < 4; i++) { // i-th row
6177 for (j = 0; j < 4; j++) { // j-th col
6178 tmp[j] = m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j]
6179 + m1[i][2] * m2[2][j] + m1[i][3] * m2[3][j];
6180 }
6181 for (j = 0; j < 4; j++)
6182 m1[i][j] = tmp[j];
6183 }
6184}
6185
6186// m4xv4() multiplies a 4x4 matrix and 4x1 vector: v2 = m * v1
6187static void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4])
6188{
6189 v2[0] = m[0][0]*v1[0] + m[0][1]*v1[1] + m[0][2]*v1[2] + m[0][3]*v1[3];
6190 v2[1] = m[1][0]*v1[0] + m[1][1]*v1[1] + m[1][2]*v1[2] + m[1][3]*v1[3];
6191 v2[2] = m[2][0]*v1[0] + m[2][1]*v1[1] + m[2][2]*v1[2] + m[2][3]*v1[3];
6192 v2[3] = m[3][0]*v1[0] + m[3][1]*v1[1] + m[3][2]*v1[2] + m[3][3]*v1[3];
6193}
6194
6196// //
6197// lu_decmp() Compute the LU decomposition of a matrix. //
6198// //
6199// Compute the LU decomposition of a (non-singular) square matrix A using //
6200// partial pivoting and implicit row exchanges. The result is: //
6201// A = P * L * U, //
6202// where P is a permutation matrix, L is unit lower triangular, and U is //
6203// upper triangular. The factored form of A is used in combination with //
6204// 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
6205// //
6206// The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
6207// On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
6208// tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
6209// permutation effected by the partial pivoting, effectively, 'ps' array //
6210// tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
6211// depending on whether the number of row interchanges was even or odd, //
6212// respectively. //
6213// //
6214// Return true if the LU decomposition is successfully computed, otherwise, //
6215// return false in case that A is a singular matrix. //
6216// //
6218
6219bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6220{
6221 REAL scales[4];
6222 REAL pivot, biggest, mult, tempf;
6223 int pivotindex = 0;
6224 int i, j, k;
6225
6226 *d = 1.0; // No row interchanges yet.
6227
6228 for (i = N; i < n + N; i++) { // For each row.
6229 // Find the largest element in each row for row equilibration
6230 biggest = 0.0;
6231 for (j = N; j < n + N; j++)
6232 if (biggest < (tempf = fabs(lu[i][j])))
6233 biggest = tempf;
6234 if (biggest != 0.0)
6235 scales[i] = 1.0 / biggest;
6236 else {
6237 scales[i] = 0.0;
6238 return false; // Zero row: singular matrix.
6239 }
6240 ps[i] = i; // Initialize pivot sequence.
6241 }
6242
6243 for (k = N; k < n + N - 1; k++) { // For each column.
6244 // Find the largest element in each column to pivot around.
6245 biggest = 0.0;
6246 for (i = k; i < n + N; i++) {
6247 if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6248 biggest = tempf;
6249 pivotindex = i;
6250 }
6251 }
6252 if (biggest == 0.0) {
6253 return false; // Zero column: singular matrix.
6254 }
6255 if (pivotindex != k) { // Update pivot sequence.
6256 j = ps[k];
6257 ps[k] = ps[pivotindex];
6258 ps[pivotindex] = j;
6259 *d = -(*d); // ...and change the parity of d.
6260 }
6261
6262 // Pivot, eliminating an extra variable each time
6263 pivot = lu[ps[k]][k];
6264 for (i = k + 1; i < n + N; i++) {
6265 lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6266 if (mult != 0.0) {
6267 for (j = k + 1; j < n + N; j++)
6268 lu[ps[i]][j] -= mult * lu[ps[k]][j];
6269 }
6270 }
6271 }
6272
6273 // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6274 return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6275}
6276
6278// //
6279// lu_solve() Solves the linear equation: Ax = b, after the matrix A //
6280// has been decomposed into the lower and upper triangular //
6281// matrices L and U, where A = LU. //
6282// //
6283// 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
6284// its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
6285// is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
6286// is input as the right-hand side vector, and returns with the solution //
6287// vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
6288// left in place for successive calls with different right-hand sides 'b'. //
6289// //
6291
6292void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6293{
6294 int i, j;
6295 REAL X[4], dot;
6296
6297 for (i = N; i < n + N; i++) X[i] = 0.0;
6298
6299 // Vector reduction using U triangular matrix.
6300 for (i = N; i < n + N; i++) {
6301 dot = 0.0;
6302 for (j = N; j < i + N; j++)
6303 dot += lu[ps[i]][j] * X[j];
6304 X[i] = b[ps[i]] - dot;
6305 }
6306
6307 // Back substitution, in L triangular matrix.
6308 for (i = n + N - 1; i >= N; i--) {
6309 dot = 0.0;
6310 for (j = i + 1; j < n + N; j++)
6311 dot += lu[ps[i]][j] * X[j];
6312 X[i] = (X[i] - dot) / lu[ps[i]][i];
6313 }
6314
6315 for (i = N; i < n + N; i++) b[i] = X[i];
6316}
6317
6318//
6319// End of linear algebra functions
6320//
6321
6322//
6323// Begin of geometric tests
6324//
6325
6326// All the following routines require the input objects are not degenerate.
6327// i.e., a triangle must has three non-collinear corners; an edge must
6328// has two identical endpoints. Degenerate cases should have to detect
6329// first and then handled as special cases.
6330
6332// //
6333// edge_vert_col_inter() Test whether an edge (ab) and a collinear vertex //
6334// (p) are intersecting or not. //
6335// //
6336// Possible cases are p is coincident to a (p = a), or to b (p = b), or p is //
6337// inside ab (a < p < b), or outside ab (p < a or p > b). These cases can be //
6338// quickly determined by comparing the corresponding coords of a, b, and p //
6339// (which are not all equal). //
6340// //
6341// The return value indicates one of the three cases: DISJOINT, SHAREVERTEX //
6342// (p = a or p = b), and INTERSECT (a < p < b). //
6343// //
6345
6346enum tetgenmesh::interresult tetgenmesh::edge_vert_col_inter(REAL* A, REAL* B,
6347 REAL* P)
6348{
6349 int i = 0;
6350 do {
6351 if (A[i] < B[i]) {
6352 if (P[i] < A[i]) {
6353 return DISJOINT;
6354 } else if (P[i] > A[i]) {
6355 if (P[i] < B[i]) {
6356 return INTERSECT;
6357 } else if (P[i] > B[i]) {
6358 return DISJOINT;
6359 } else {
6360 // assert(P[i] == B[i]);
6361 return SHAREVERTEX;
6362 }
6363 } else {
6364 // assert(P[i] == A[i]);
6365 return SHAREVERTEX;
6366 }
6367 } else if (A[i] > B[i]) {
6368 if (P[i] < B[i]) {
6369 return DISJOINT;
6370 } else if (P[i] > B[i]) {
6371 if (P[i] < A[i]) {
6372 return INTERSECT;
6373 } else if (P[i] > A[i]) {
6374 return DISJOINT;
6375 } else {
6376 // assert(P[i] == A[i]);
6377 return SHAREVERTEX;
6378 }
6379 } else {
6380 // assert(P[i] == B[i]);
6381 return SHAREVERTEX;
6382 }
6383 }
6384 // i-th coordinates are equal, try i+1-th;
6385 i++;
6386 } while (i < 3);
6387 // Should never be here.
6388 return DISJOINT;
6389}
6390
6392// //
6393// edge_edge_cop_inter() Test whether two coplanar edges (ab, and pq) are //
6394// intersecting or not. //
6395// //
6396// Possible cases are ab and pq are disjointed, or proper intersecting (int- //
6397// ersect at a point other than their endpoints), or both collinear and int- //
6398// ersecting, or sharing at a common endpoint, or are coincident. //
6399// //
6400// A reference point R is required, which is exactly not coplanar with these //
6401// two edges. Since the caller knows these two edges are coplanar, it must //
6402// be able to provide (or calculate) such a point. //
6403// //
6404// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6405// SHAREEDGE, and INTERSECT. //
6406// //
6408
6409enum tetgenmesh::interresult tetgenmesh:: edge_edge_cop_inter(REAL* A, REAL* B,
6410 REAL* P, REAL* Q, REAL* R)
6411{
6412 REAL s1, s2, s3, s4;
6413
6414#ifdef SELF_CHECK
6415 assert(R != NULL);
6416#endif
6417 s1 = orient3d(A, B, R, P);
6418 s2 = orient3d(A, B, R, Q);
6419 if (s1 * s2 > 0.0) {
6420 // Both p and q are at the same side of ab.
6421 return DISJOINT;
6422 }
6423 s3 = orient3d(P, Q, R, A);
6424 s4 = orient3d(P, Q, R, B);
6425 if (s3 * s4 > 0.0) {
6426 // Both a and b are at the same side of pq.
6427 return DISJOINT;
6428 }
6429
6430 // Possible degenerate cases are:
6431 // (1) Only one of p and q is collinear with ab;
6432 // (2) Both p and q are collinear with ab;
6433 // (3) Only one of a and b is collinear with pq.
6434 enum interresult abp, abq;
6435 enum interresult pqa, pqb;
6436
6437 if (s1 == 0.0) {
6438 // p is collinear with ab.
6439 abp = edge_vert_col_inter(A, B, P);
6440 if (abp == INTERSECT) {
6441 // p is inside ab.
6442 return INTERSECT;
6443 }
6444 if (s2 == 0.0) {
6445 // q is collinear with ab. Case (2).
6446 abq = edge_vert_col_inter(A, B, Q);
6447 if (abq == INTERSECT) {
6448 // q is inside ab.
6449 return INTERSECT;
6450 }
6451 if (abp == SHAREVERTEX && abq == SHAREVERTEX) {
6452 // ab and pq are identical.
6453 return SHAREEDGE;
6454 }
6455 pqa = edge_vert_col_inter(P, Q, A);
6456 if (pqa == INTERSECT) {
6457 // a is inside pq.
6458 return INTERSECT;
6459 }
6460 pqb = edge_vert_col_inter(P, Q, B);
6461 if (pqb == INTERSECT) {
6462 // b is inside pq.
6463 return INTERSECT;
6464 }
6465 if (abp == SHAREVERTEX || abq == SHAREVERTEX) {
6466 // either p or q is coincident with a or b.
6467#ifdef SELF_CHECK
6468 // ONLY one case is possible, otherwise, shoule be SHAREEDGE.
6469 assert(abp ^ abq);
6470#endif
6471 return SHAREVERTEX;
6472 }
6473 // The last case. They are disjointed.
6474#ifdef SELF_CHECK
6475 assert((abp == DISJOINT) && (abp == abq && abq == pqa && pqa == pqb));
6476#endif
6477 return DISJOINT;
6478 } else {
6479 // p is collinear with ab. Case (1).
6480#ifdef SELF_CHECK
6481 assert(abp == SHAREVERTEX || abp == DISJOINT);
6482#endif
6483 return abp;
6484 }
6485 }
6486 // p is NOT collinear with ab.
6487 if (s2 == 0.0) {
6488 // q is collinear with ab. Case (1).
6489 abq = edge_vert_col_inter(A, B, Q);
6490#ifdef SELF_CHECK
6491 assert(abq == SHAREVERTEX || abq == DISJOINT || abq == INTERSECT);
6492#endif
6493 return abq;
6494 }
6495
6496 // We have found p and q are not collinear with ab. However, it is still
6497 // possible that a or b is collinear with pq (ONLY one of a and b).
6498 if (s3 == 0.0) {
6499 // a is collinear with pq. Case (3).
6500#ifdef SELF_CHECK
6501 assert(s4 != 0.0);
6502#endif
6503 pqa = edge_vert_col_inter(P, Q, A);
6504#ifdef SELF_CHECK
6505 // This case should have been detected in above.
6506 assert(pqa != SHAREVERTEX);
6507 assert(pqa == INTERSECT || pqa == DISJOINT);
6508#endif
6509 return pqa;
6510 }
6511 if (s4 == 0.0) {
6512 // b is collinear with pq. Case (3).
6513#ifdef SELF_CHECK
6514 assert(s3 != 0.0);
6515#endif
6516 pqb = edge_vert_col_inter(P, Q, B);
6517#ifdef SELF_CHECK
6518 // This case should have been detected in above.
6519 assert(pqb != SHAREVERTEX);
6520 assert(pqb == INTERSECT || pqb == DISJOINT);
6521#endif
6522 return pqb;
6523 }
6524
6525 // ab and pq are intersecting properly.
6526 return INTERSECT;
6527}
6528
6530// //
6531// Notations //
6532// //
6533// Let ABC be the plane passes through a, b, and c; ABC+ be the halfspace //
6534// including the set of all points x, such that orient3d(a, b, c, x) > 0; //
6535// ABC- be the other halfspace, such that for each point x in ABC-, //
6536// orient3d(a, b, c, x) < 0. For the set of x which are on ABC, orient3d(a, //
6537// b, c, x) = 0. //
6538// //
6540
6542// //
6543// tri_vert_copl_inter() Test whether a triangle (abc) and a coplanar //
6544// point (p) are intersecting or not. //
6545// //
6546// Possible cases are p is inside abc, or on an edge of, or coincident with //
6547// a vertex of, or outside abc. //
6548// //
6549// A reference point R is required. R is exactly not coplanar with abc and p.//
6550// Since the caller knows they are coplanar, it must be able to provide (or //
6551// calculate) such a point. //
6552// //
6553// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6554// and INTERSECT. //
6555// //
6557
6558enum tetgenmesh::interresult tetgenmesh::tri_vert_cop_inter(REAL* A, REAL* B,
6559 REAL* C, REAL* P, REAL* R)
6560{
6561 REAL s1, s2, s3;
6562 int sign;
6563
6564#ifdef SELF_CHECK
6565 assert(R != (REAL *) NULL);
6566#endif
6567 // Adjust the orientation of a, b, c and r, so that we can assume that
6568 // r is strictly in ABC- (i.e., r is above ABC wrt. right-hand rule).
6569 s1 = orient3d(A, B, C, R);
6570#ifdef SELF_CHECK
6571 assert(s1 != 0.0);
6572#endif
6573 sign = s1 < 0.0 ? 1 : -1;
6574
6575 // Test starts from here.
6576 s1 = orient3d(A, B, R, P) * sign;
6577 if (s1 < 0.0) {
6578 // p is in ABR-.
6579 return DISJOINT;
6580 }
6581 s2 = orient3d(B, C, R, P) * sign;
6582 if (s2 < 0.0) {
6583 // p is in BCR-.
6584 return DISJOINT;
6585 }
6586 s3 = orient3d(C, A, R, P) * sign;
6587 if (s3 < 0.0) {
6588 // p is in CAR-.
6589 return DISJOINT;
6590 }
6591 if (s1 == 0.0) {
6592 // p is on ABR.
6593 if (s2 == 0.0) {
6594 // p is on BCR.
6595#ifdef SELF_CHECK
6596 assert(s3 > 0.0);
6597#endif
6598 // p is coincident with b.
6599 return SHAREVERTEX;
6600 }
6601 if (s3 == 0.0) {
6602 // p is on CAR.
6603 // p is coincident with a.
6604 return SHAREVERTEX;
6605 }
6606 // p is on edge ab.
6607 return INTERSECT;
6608 }
6609 // p is in ABR+.
6610 if (s2 == 0.0) {
6611 // p is on BCR.
6612 if (s3 == 0.0) {
6613 // p is on CAR.
6614 // p is coincident with c.
6615 return SHAREVERTEX;
6616 }
6617 // p is on edge bc.
6618 return INTERSECT;
6619 }
6620 if (s3 == 0.0) {
6621 // p is on CAR.
6622 // p is on edge ca.
6623 return INTERSECT;
6624 }
6625
6626 // p is strictly inside abc.
6627 return INTERSECT;
6628}
6629
6631// //
6632// tri_edge_cop_inter() Test whether a triangle (abc) and a coplanar edge //
6633// (pq) are intersecting or not. //
6634// //
6635// A reference point R is required. R is exactly not coplanar with abc and //
6636// pq. Since the caller knows they are coplanar, it must be able to provide //
6637// (or calculate) such a point. //
6638// //
6639// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6640// SHAREEDGE, and INTERSECT. //
6641// //
6643
6644enum tetgenmesh::interresult tetgenmesh::tri_edge_cop_inter(REAL* A, REAL* B,
6645 REAL* C, REAL* P, REAL* Q, REAL* R)
6646{
6647 enum interresult abpq, bcpq, capq;
6648 enum interresult abcp, abcq;
6649
6650 // Test if pq is intersecting one of edges of abc.
6651 abpq = edge_edge_cop_inter(A, B, P, Q, R);
6652 if (abpq == INTERSECT || abpq == SHAREEDGE) {
6653 return abpq;
6654 }
6655 bcpq = edge_edge_cop_inter(B, C, P, Q, R);
6656 if (bcpq == INTERSECT || bcpq == SHAREEDGE) {
6657 return bcpq;
6658 }
6659 capq = edge_edge_cop_inter(C, A, P, Q, R);
6660 if (capq == INTERSECT || capq == SHAREEDGE) {
6661 return capq;
6662 }
6663
6664 // Test if p and q is inside abc.
6665 abcp = tri_vert_cop_inter(A, B, C, P, R);
6666 if (abcp == INTERSECT) {
6667 return INTERSECT;
6668 }
6669 abcq = tri_vert_cop_inter(A, B, C, Q, R);
6670 if (abcq == INTERSECT) {
6671 return INTERSECT;
6672 }
6673
6674 // Combine the test results of edge intersectings and triangle insides
6675 // to detect whether abc and pq are sharing vertex or disjointed.
6676 if (abpq == SHAREVERTEX) {
6677 // p or q is coincident with a or b.
6678#ifdef SELF_CHECK
6679 assert(abcp ^ abcq);
6680#endif
6681 return SHAREVERTEX;
6682 }
6683 if (bcpq == SHAREVERTEX) {
6684 // p or q is coincident with b or c.
6685#ifdef SELF_CHECK
6686 assert(abcp ^ abcq);
6687#endif
6688 return SHAREVERTEX;
6689 }
6690 if (capq == SHAREVERTEX) {
6691 // p or q is coincident with c or a.
6692#ifdef SELF_CHECK
6693 assert(abcp ^ abcq);
6694#endif
6695 return SHAREVERTEX;
6696 }
6697
6698 // They are disjointed.
6699 return DISJOINT;
6700}
6701
6703// //
6704// tri_edge_inter_tail() Test whether a triangle (abc) and an edge (pq) //
6705// are intersecting or not. //
6706// //
6707// s1 and s2 are results of pre-performed orientation tests. s1 = orient3d( //
6708// a, b, c, p); s2 = orient3d(a, b, c, q). To separate this routine from //
6709// tri_edge_inter() can save two orientation tests in tri_tri_inter(). //
6710// //
6711// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6712// SHAREEDGE, and INTERSECT. //
6713// //
6715
6716enum tetgenmesh::interresult tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B,
6717 REAL* C, REAL* P, REAL* Q, REAL s1, REAL s2)
6718{
6719 REAL s3, s4, s5;
6720 int sign;
6721
6722 if (s1 * s2 > 0.0) {
6723 // p, q are at the same halfspace of ABC, no intersection.
6724 return DISJOINT;
6725 }
6726
6727 if (s1 * s2 < 0.0) {
6728 // p, q are both not on ABC (and not sharing vertices, edges of abc).
6729 // Adjust the orientation of a, b, c and p, so that we can assume that
6730 // p is strictly in ABC-, and q is strictly in ABC+.
6731 sign = s1 < 0.0 ? 1 : -1;
6732 s3 = orient3d(A, B, P, Q) * sign;
6733 if (s3 < 0.0) {
6734 // q is at ABP-.
6735 return DISJOINT;
6736 }
6737 s4 = orient3d(B, C, P, Q) * sign;
6738 if (s4 < 0.0) {
6739 // q is at BCP-.
6740 return DISJOINT;
6741 }
6742 s5 = orient3d(C, A, P, Q) * sign;
6743 if (s5 < 0.0) {
6744 // q is at CAP-.
6745 return DISJOINT;
6746 }
6747 if (s3 == 0.0) {
6748 // q is on ABP.
6749 if (s4 == 0.0) {
6750 // q is on BCP (and q must in CAP+).
6751#ifdef SELF_CHECK
6752 assert(s5 > 0.0);
6753#endif
6754 // pq intersects abc at vertex b.
6755 return SHAREVERTEX;
6756 }
6757 if (s5 == 0.0) {
6758 // q is on CAP (and q must in BCP+).
6759 // pq intersects abc at vertex a.
6760 return SHAREVERTEX;
6761 }
6762 // q in both BCP+ and CAP+.
6763 // pq crosses ab properly.
6764 return INTERSECT;
6765 }
6766 // q is in ABP+;
6767 if (s4 == 0.0) {
6768 // q is on BCP.
6769 if (s5 == 0.0) {
6770 // q is on CAP.
6771 // pq intersects abc at vertex c.
6772 return SHAREVERTEX;
6773 }
6774 // pq crosses bc properly.
6775 return INTERSECT;
6776 }
6777 // q is in BCP+;
6778 if (s5 == 0.0) {
6779 // q is on CAP.
6780 // pq crosses ca properly.
6781 return INTERSECT;
6782 }
6783 // q is in CAP+;
6784 // pq crosses abc properly.
6785 return INTERSECT;
6786 }
6787
6788 if (s1 != 0.0 || s2 != 0.0) {
6789 // Either p or q is coplanar with abc. ONLY one of them is possible.
6790 if (s1 == 0.0) {
6791 // p is coplanar with abc, q can be used as reference point.
6792#ifdef SELF_CHECK
6793 assert(s2 != 0.0);
6794#endif
6795 return tri_vert_cop_inter(A, B, C, P, Q);
6796 } else {
6797 // q is coplanar with abc, p can be used as reference point.
6798#ifdef SELF_CHECK
6799 assert(s2 == 0.0);
6800#endif
6801 return tri_vert_cop_inter(A, B, C, Q, P);
6802 }
6803 }
6804
6805 // pq is coplanar with abc. Calculate a point which is exactly not
6806 // coplanar with a, b, and c.
6807 REAL R[3], N[3];
6808 REAL ax, ay, az, bx, by, bz;
6809
6810 ax = A[0] - B[0];
6811 ay = A[1] - B[1];
6812 az = A[2] - B[2];
6813 bx = A[0] - C[0];
6814 by = A[1] - C[1];
6815 bz = A[2] - C[2];
6816 N[0] = ay * bz - by * az;
6817 N[1] = az * bx - bz * ax;
6818 N[2] = ax * by - bx * ay;
6819 // The normal should not be a zero vector (otherwise, abc are collinear).
6820#ifdef SELF_CHECK
6821 assert((fabs(N[0]) + fabs(N[1]) + fabs(N[2])) > 0.0);
6822#endif
6823 // The reference point R is lifted from A to the normal direction with
6824 // a distance d = average edge length of the triangle abc.
6825 R[0] = N[0] + A[0];
6826 R[1] = N[1] + A[1];
6827 R[2] = N[2] + A[2];
6828 // Becareful the case: if the non-zero component(s) in N is smaller than
6829 // the machine epsilon (i.e., 2^(-16) for double), R will exactly equal
6830 // to A due to the round-off error. Do check if it is.
6831 if (R[0] == A[0] && R[1] == A[1] && R[2] == A[2]) {
6832 int i, j;
6833 for (i = 0; i < 3; i++) {
6834#ifdef SELF_CHECK
6835 assert (R[i] == A[i]);
6836#endif
6837 j = 2;
6838 do {
6839 if (N[i] > 0.0) {
6840 N[i] += (j * macheps);
6841 } else {
6842 N[i] -= (j * macheps);
6843 }
6844 R[i] = N[i] + A[i];
6845 j *= 2;
6846 } while (R[i] == A[i]);
6847 }
6848 }
6849
6850 return tri_edge_cop_inter(A, B, C, P, Q, R);
6851}
6852
6854// //
6855// tri_edge_inter() Test whether a triangle (abc) and an edge (pq) are //
6856// intersecting or not. //
6857// //
6858// The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6859// SHAREEDGE, and INTERSECT. //
6860// //
6862
6863enum tetgenmesh::interresult tetgenmesh::tri_edge_inter(REAL* A, REAL* B,
6864 REAL* C, REAL* P, REAL* Q)
6865{
6866 REAL s1, s2;
6867
6868 // Test the locations of p and q with respect to ABC.
6869 s1 = orient3d(A, B, C, P);
6870 s2 = orient3d(A, B, C, Q);
6871
6872 return tri_edge_inter_tail(A, B, C, P, Q, s1, s2);
6873}
6874
6876// //
6877// tri_tri_inter() Test whether two triangle (abc) and (opq) are //
6878// intersecting or not. //
6879// //
6880// The return value indicates one of the five cases: DISJOINT, SHAREVERTEX, //
6881// SHAREEDGE, SHAREFACE, and INTERSECT. //
6882// //
6884
6885enum tetgenmesh::interresult tetgenmesh::tri_tri_inter(REAL* A, REAL* B,
6886 REAL* C, REAL* O, REAL* P, REAL* Q)
6887{
6888 REAL s_o, s_p, s_q;
6889 REAL s_a, s_b, s_c;
6890
6891 s_o = orient3d(A, B, C, O);
6892 s_p = orient3d(A, B, C, P);
6893 s_q = orient3d(A, B, C, Q);
6894 if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
6895 // o, p, q are all in the same halfspace of ABC.
6896 return DISJOINT;
6897 }
6898
6899 s_a = orient3d(O, P, Q, A);
6900 s_b = orient3d(O, P, Q, B);
6901 s_c = orient3d(O, P, Q, C);
6902 if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
6903 // a, b, c are all in the same halfspace of OPQ.
6904 return DISJOINT;
6905 }
6906
6907 enum interresult abcop, abcpq, abcqo;
6908 int shareedge = 0;
6909
6910 abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
6911 if (abcop == INTERSECT) {
6912 return INTERSECT;
6913 } else if (abcop == SHAREEDGE) {
6914 shareedge++;
6915 }
6916 abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
6917 if (abcpq == INTERSECT) {
6918 return INTERSECT;
6919 } else if (abcpq == SHAREEDGE) {
6920 shareedge++;
6921 }
6922 abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
6923 if (abcqo == INTERSECT) {
6924 return INTERSECT;
6925 } else if (abcqo == SHAREEDGE) {
6926 shareedge++;
6927 }
6928 if (shareedge == 3) {
6929 // opq are coincident with abc.
6930 return SHAREFACE;
6931 }
6932#ifdef SELF_CHECK
6933 // It is only possible either no share edge or one.
6934 assert(shareedge == 0 || shareedge == 1);
6935#endif
6936
6937 // Continue to detect whether opq and abc are intersecting or not.
6938 enum interresult opqab, opqbc, opqca;
6939
6940 opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
6941 if (opqab == INTERSECT) {
6942 return INTERSECT;
6943 }
6944 opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
6945 if (opqbc == INTERSECT) {
6946 return INTERSECT;
6947 }
6948 opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
6949 if (opqca == INTERSECT) {
6950 return INTERSECT;
6951 }
6952
6953 // At this point, two triangles are not intersecting and not coincident.
6954 // They may be share an edge, or share a vertex, or disjoint.
6955 if (abcop == SHAREEDGE) {
6956#ifdef SELF_CHECK
6957 assert(abcpq == SHAREVERTEX && abcqo == SHAREVERTEX);
6958#endif
6959 // op is coincident with an edge of abc.
6960 return SHAREEDGE;
6961 }
6962 if (abcpq == SHAREEDGE) {
6963#ifdef SELF_CHECK
6964 assert(abcop == SHAREVERTEX && abcqo == SHAREVERTEX);
6965#endif
6966 // pq is coincident with an edge of abc.
6967 return SHAREEDGE;
6968 }
6969 if (abcqo == SHAREEDGE) {
6970#ifdef SELF_CHECK
6971 assert(abcop == SHAREVERTEX && abcpq == SHAREVERTEX);
6972#endif
6973 // qo is coincident with an edge of abc.
6974 return SHAREEDGE;
6975 }
6976
6977 // They may share a vertex or disjoint.
6978 if (abcop == SHAREVERTEX) {
6979 // o or p is coincident with a vertex of abc.
6980 if (abcpq == SHAREVERTEX) {
6981 // p is the coincident vertex.
6982#ifdef SELF_CHECK
6983 assert(abcqo != SHAREVERTEX);
6984#endif
6985 } else {
6986 // o is the coincident vertex.
6987#ifdef SELF_CHECK
6988 assert(abcqo == SHAREVERTEX);
6989#endif
6990 }
6991 return SHAREVERTEX;
6992 }
6993 if (abcpq == SHAREVERTEX) {
6994 // q is the coincident vertex.
6995#ifdef SELF_CHECK
6996 assert(abcqo == SHAREVERTEX);
6997#endif
6998 return SHAREVERTEX;
6999 }
7000
7001 // They are disjoint.
7002 return DISJOINT;
7003}
7004
7006// //
7007// insphere_sos() Insphere test with symbolic perturbation. //
7008// //
7009// The input points a, b, c, and d should be non-coplanar. They must be ord- //
7010// ered so that they have a positive orientation (as defined by orient3d()), //
7011// or the sign of the result will be reversed. //
7012// //
7013// Return a positive value if the point e lies inside the circumsphere of a, //
7014// b, c, and d; a negative value if it lies outside. //
7015// //
7017
7018REAL tetgenmesh::insphere_sos(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
7019 int ia, int ib, int ic, int id, int ie)
7020{
7021 REAL det;
7022
7023 det = insphere(pa, pb, pc, pd, pe);
7024 if (det != 0.0) {
7025 return det;
7026 }
7027
7028 // det = 0.0, use symbolic perturbation.
7029 REAL *p[5], *tmpp;
7030 REAL sign, det_c, det_d;
7031 int idx[5], perm, tmp;
7032 int n, i, j;
7033
7034 p[0] = pa; idx[0] = ia;
7035 p[1] = pb; idx[1] = ib;
7036 p[2] = pc; idx[2] = ic;
7037 p[3] = pd; idx[3] = id;
7038 p[4] = pe; idx[4] = ie;
7039
7040 // Bubble sort the points by the increasing order of the indices.
7041 n = 5;
7042 perm = 0; // The number of total swaps.
7043 for (i = 0; i < n - 1; i++) {
7044 for (j = 0; j < n - 1 - i; j++) {
7045 if (idx[j + 1] < idx[j]) { // compare the two neighbors.
7046 tmp = idx[j]; // swap idx[j] and idx[j + 1]
7047 idx[j] = idx[j + 1];
7048 idx[j + 1] = tmp;
7049 tmpp = p[j]; // swap p[j] and p[j + 1]
7050 p[j] = p[j + 1];
7051 p[j + 1] = tmpp;
7052 perm++;
7053 }
7054 }
7055 }
7056
7057 sign = (perm % 2 == 0) ? 1.0 : -1.0;
7058 det_c = orient3d(p[1], p[2], p[3], p[4]); // orient3d(b, c, d, e)
7059 if (det_c != 0.0) {
7060 return sign * det_c;
7061 }
7062 det_d = orient3d(p[0], p[2], p[3], p[4]); // orient3d(a, c, d, e)
7063 return -sign * det_d;
7064}
7065
7067// //
7068// iscollinear() Check if three points are approximately collinear. //
7069// //
7070// 'eps' is a relative error tolerance. The collinearity is determined by //
7071// the value q = cos(theta), where theta is the angle between two vectors //
7072// A->B and A->C. They're collinear if 1.0 - q <= epspp. //
7073// //
7075
7076bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL eps)
7077{
7078 REAL abx, aby, abz;
7079 REAL acx, acy, acz;
7080 REAL Lv, Lw, dd;
7081 REAL d, q;
7082
7083 // Limit of two closed points.
7084 q = longest * eps;
7085 q *= q;
7086
7087 abx = A[0] - B[0];
7088 aby = A[1] - B[1];
7089 abz = A[2] - B[2];
7090 acx = A[0] - C[0];
7091 acy = A[1] - C[1];
7092 acz = A[2] - C[2];
7093 Lv = abx * abx + aby * aby + abz * abz;
7094 // Is AB (nearly) indentical?
7095 if (Lv < q) return true;
7096 Lw = acx * acx + acy * acy + acz * acz;
7097 // Is AC (nearly) indentical?
7098 if (Lw < q) return true;
7099 dd = abx * acx + aby * acy + abz * acz;
7100
7101 d = (dd * dd) / (Lv * Lw);
7102 if (d > 1.0) d = 1.0; // Rounding.
7103 q = 1.0 - sqrt(d); // Notice 0 < q < 1.0.
7104
7105 return q <= eps;
7106}
7107
7109// //
7110// iscoplanar() Check if four points are approximately coplanar. //
7111// //
7112// 'vol6' is six times of the signed volume of the tetrahedron formed by the //
7113// four points. 'eps' is the relative error tolerance. The coplanarity is //
7114// determined by the value: q = fabs(vol6) / L^3, where L is the average //
7115// edge length of the tet. They're coplanar if q <= eps. //
7116// //
7118
7119bool tetgenmesh::
7120iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL eps)
7121{
7122 REAL L, q;
7123 REAL x, y, z;
7124
7125 if (vol6 == 0.0) return true;
7126
7127 x = k[0] - l[0];
7128 y = k[1] - l[1];
7129 z = k[2] - l[2];
7130 L = sqrt(x * x + y * y + z * z);
7131 x = l[0] - m[0];
7132 y = l[1] - m[1];
7133 z = l[2] - m[2];
7134 L += sqrt(x * x + y * y + z * z);
7135 x = m[0] - k[0];
7136 y = m[1] - k[1];
7137 z = m[2] - k[2];
7138 L += sqrt(x * x + y * y + z * z);
7139 x = k[0] - n[0];
7140 y = k[1] - n[1];
7141 z = k[2] - n[2];
7142 L += sqrt(x * x + y * y + z * z);
7143 x = l[0] - n[0];
7144 y = l[1] - n[1];
7145 z = l[2] - n[2];
7146 L += sqrt(x * x + y * y + z * z);
7147 x = m[0] - n[0];
7148 y = m[1] - n[1];
7149 z = m[2] - n[2];
7150 L += sqrt(x * x + y * y + z * z);
7151#ifdef SELF_CHECK
7152 assert(L > 0.0);
7153#endif
7154 L /= 6.0;
7155 q = fabs(vol6) / (L * L * L);
7156
7157 return q <= eps;
7158}
7159
7161// //
7162// iscospheric() Check if five points are approximately coplanar. //
7163// //
7164// 'vol24' is the 24 times of the signed volume of the 4-dimensional simplex //
7165// formed by the five points. 'eps' is the relative tolerance. The cosphere //
7166// case is determined by the value: q = fabs(vol24) / L^4, where L is the //
7167// average edge length of the simplex. They're cosphere if q <= eps. //
7168// //
7170
7171bool tetgenmesh::
7172iscospheric(REAL* k, REAL* l, REAL* m, REAL* n, REAL* o, REAL vol24, REAL eps)
7173{
7174 REAL L, q;
7175
7176 // A 4D simplex has 10 edges.
7177 L = distance(k, l);
7178 L += distance(l, m);
7179 L += distance(m, k);
7180 L += distance(k, n);
7181 L += distance(l, n);
7182 L += distance(m, n);
7183 L += distance(k, o);
7184 L += distance(l, o);
7185 L += distance(m, o);
7186 L += distance(n, o);
7187#ifdef SELF_CHECK
7188 assert(L > 0.0);
7189#endif
7190 L /= 10.0;
7191 q = fabs(vol24) / (L * L * L * L);
7192
7193 return q < eps;
7194}
7195
7196//
7197// End of geometric tests
7198//
7199
7200//
7201// Begin of Geometric quantities calculators
7202//
7203
7204// distance() computs the Euclidean distance between two points.
7205inline REAL tetgenmesh::distance(REAL* p1, REAL* p2)
7206{
7207 return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) +
7208 (p2[1] - p1[1]) * (p2[1] - p1[1]) +
7209 (p2[2] - p1[2]) * (p2[2] - p1[2]));
7210}
7211
7213// //
7214// shortdistance() Returns the shortest distance from point p to a line //
7215// defined by two points e1 and e2. //
7216// //
7217// First compute the projection length l_p of the vector v1 = p - e1 along //
7218// the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
7219// shortest distance. //
7220// //
7221// This routine allows that p is collinear with the line. In this case, the //
7222// return value is zero. The two points e1 and e2 should not be identical. //
7223// //
7225
7226REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
7227{
7228 REAL v1[3], v2[3];
7229 REAL len, l_p;
7230
7231 v1[0] = e2[0] - e1[0];
7232 v1[1] = e2[1] - e1[1];
7233 v1[2] = e2[2] - e1[2];
7234 v2[0] = p[0] - e1[0];
7235 v2[1] = p[1] - e1[1];
7236 v2[2] = p[2] - e1[2];
7237
7238 len = sqrt(dot(v1, v1));
7239#ifdef SELF_CHECK
7240 assert(len != 0.0);
7241#endif
7242 v1[0] /= len;
7243 v1[1] /= len;
7244 v1[2] /= len;
7245 l_p = dot(v1, v2);
7246
7247 return sqrt(dot(v2, v2) - l_p * l_p);
7248}
7249
7251// //
7252// shortdistance() Returns the shortest distance from point p to a face. //
7253// //
7255
7256REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3)
7257{
7258 REAL prj[3];
7259
7260 projpt2face(p, e1, e2, e3, prj);
7261 return distance(p, prj);
7262}
7263
7265// //
7266// interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
7267// o->p1 and o->p2. //
7268// //
7269// 'n' is the normal of the plane containing face (o, p1, p2). The interior //
7270// angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
7271// the position of p1 and p2 will get the complement angle of the other one. //
7272// i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
7273// 'n' be NULL if you only want the interior angle between 0 - PI. //
7274// //
7276
7277REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
7278{
7279 REAL v1[3], v2[3], np[3];
7280 REAL theta, costheta, lenlen;
7281 REAL ori, len1, len2;
7282
7283 // Get the interior angle (0 - PI) between o->p1, and o->p2.
7284 v1[0] = p1[0] - o[0];
7285 v1[1] = p1[1] - o[1];
7286 v1[2] = p1[2] - o[2];
7287 v2[0] = p2[0] - o[0];
7288 v2[1] = p2[1] - o[1];
7289 v2[2] = p2[2] - o[2];
7290 len1 = sqrt(dot(v1, v1));
7291 len2 = sqrt(dot(v2, v2));
7292 lenlen = len1 * len2;
7293#ifdef SELF_CHECK
7294 assert(lenlen != 0.0);
7295#endif
7296 costheta = dot(v1, v2) / lenlen;
7297 if (costheta > 1.0) {
7298 costheta = 1.0; // Roundoff.
7299 } else if (costheta < -1.0) {
7300 costheta = -1.0; // Roundoff.
7301 }
7302 theta = acos(costheta);
7303 if (n != NULL) {
7304 // Get a point above the face (o, p1, p2);
7305 np[0] = o[0] + n[0];
7306 np[1] = o[1] + n[1];
7307 np[2] = o[2] + n[2];
7308 // Adjust theta (0 - 2 * PI).
7309 ori = orient3d(p1, o, np, p2);
7310 if (ori > 0.0) {
7311 theta = 2 * PI - theta;
7312 }
7313 }
7314
7315 return theta;
7316}
7317
7319// //
7320// projpt2edge() Return the projection point from a point to an edge. //
7321// //
7323
7324void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
7325{
7326 REAL v1[3], v2[3];
7327 REAL len, l_p;
7328
7329 v1[0] = e2[0] - e1[0];
7330 v1[1] = e2[1] - e1[1];
7331 v1[2] = e2[2] - e1[2];
7332 v2[0] = p[0] - e1[0];
7333 v2[1] = p[1] - e1[1];
7334 v2[2] = p[2] - e1[2];
7335
7336 len = sqrt(dot(v1, v1));
7337#ifdef SELF_CHECK
7338 assert(len != 0.0);
7339#endif
7340 v1[0] /= len;
7341 v1[1] /= len;
7342 v1[2] /= len;
7343 l_p = dot(v1, v2);
7344
7345 prj[0] = e1[0] + l_p * v1[0];
7346 prj[1] = e1[1] + l_p * v1[1];
7347 prj[2] = e1[2] + l_p * v1[2];
7348}
7349
7351// //
7352// projpt2face() Return the projection point from a point to a face. //
7353// //
7355
7356void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
7357{
7358 REAL fnormal[3], v1[3];
7359 REAL len, dist;
7360
7361 // Get the unit face normal.
7362 facenormal(f1, f2, f3, fnormal, &len);
7363#ifdef SELF_CHECK
7364 assert(len > 0.0);
7365#endif
7366 fnormal[0] /= len;
7367 fnormal[1] /= len;
7368 fnormal[2] /= len;
7369 // Get the vector v1 = |p - f1|.
7370 v1[0] = p[0] - f1[0];
7371 v1[1] = p[1] - f1[1];
7372 v1[2] = p[2] - f1[2];
7373 // Get the project distance.
7374 dist = dot(fnormal, v1);
7375
7376 // Get the project point.
7377 prj[0] = p[0] - dist * fnormal[0];
7378 prj[1] = p[1] - dist * fnormal[1];
7379 prj[2] = p[2] - dist * fnormal[2];
7380}
7381
7383// //
7384// facenormal() Calculate the normal of a face given by three points. //
7385// //
7386// In general, the face normal can be calculate by the cross product of any //
7387// pair of the three edge vectors. However, if the three points are nearly //
7388// collinear, the rounding error may harm the result. To choose a good pair //
7389// of vectors is helpful to reduce the error. //
7390// //
7392
7393void tetgenmesh::facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen)
7394{
7395 REAL v1[3], v2[3];
7396
7397 v1[0] = pb[0] - pa[0];
7398 v1[1] = pb[1] - pa[1];
7399 v1[2] = pb[2] - pa[2];
7400 v2[0] = pc[0] - pa[0];
7401 v2[1] = pc[1] - pa[1];
7402 v2[2] = pc[2] - pa[2];
7403
7404 cross(v1, v2, n);
7405 if (nlen != (REAL *) NULL) {
7406 *nlen = sqrt(dot(n, n));
7407 }
7408}
7409
7411// //
7412// edgeorthonormal() Return the unit normal of an edge in a given plane. //
7413// //
7414// The edge is from e1 to e2, the plane is defined by given an additional //
7415// point op, which is non-collinear with the edge. In addition, the side of //
7416// the edge in which op lies defines the positive position of the normal. //
7417// //
7418// Let v1 be the unit vector from e1 to e2, v2 be the unit edge vector from //
7419// e1 to op, fn be the unit face normal calculated by fn = v1 x v2. Then the //
7420// unit edge normal of e1e2 pointing to op is n = fn x v1. Note, we should //
7421// not change the position of fn and v1, otherwise, we get the edge normal //
7422// pointing to the other side of op. //
7423// //
7425
7426void tetgenmesh::edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n)
7427{
7428 REAL v1[3], v2[3], fn[3];
7429 REAL len;
7430
7431 // Get the edge vector v1.
7432 v1[0] = e2[0] - e1[0];
7433 v1[1] = e2[1] - e1[1];
7434 v1[2] = e2[2] - e1[2];
7435 // Get the edge vector v2.
7436 v2[0] = op[0] - e1[0];
7437 v2[1] = op[1] - e1[1];
7438 v2[2] = op[2] - e1[2];
7439 // Get the face normal fn = v1 x v2.
7440 cross(v1, v2, fn);
7441 // Get the edge normal n pointing to op. n = fn x v1.
7442 cross(fn, v1, n);
7443 // Normalize the vector.
7444 len = sqrt(dot(n, n));
7445 n[0] /= len;
7446 n[1] /= len;
7447 n[2] /= len;
7448}
7449
7451// //
7452// facedihedral() Return the dihedral angle (in radian) between two //
7453// adjoining faces. //
7454// //
7455// 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are //
7456// apexes of these two faces. Return the angle (between 0 to 2*pi) between //
7457// the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). //
7458// //
7460
7461REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
7462{
7463 REAL n1[3], n2[3];
7464 REAL n1len, n2len;
7465 REAL costheta, ori;
7466 REAL theta;
7467
7468 facenormal(pa, pb, pc1, n1, &n1len);
7469 facenormal(pa, pb, pc2, n2, &n2len);
7470 costheta = dot(n1, n2) / (n1len * n2len);
7471 // Be careful rounding error!
7472 if (costheta > 1.0) {
7473 costheta = 1.0;
7474 } else if (costheta < -1.0) {
7475 costheta = -1.0;
7476 }
7477 theta = acos(costheta);
7478 ori = orient3d(pa, pb, pc1, pc2);
7479 if (ori > 0.0) {
7480 theta = 2 * PI - theta;
7481 }
7482
7483 return theta;
7484}
7485
7487// //
7488// tetalldihedral() Get all (six) dihedral angles of a tet. //
7489// //
7490// The tet is given by its four corners a, b, c, and d. If 'cosdd' is not //
7491// NULL, it returns the cosines of the 6 dihedral angles, the corresponding //
7492// edges are: ab, bc, ca, ad, bd, and cd. If 'cosmaxd' (or 'cosmind') is not //
7493// NULL, it returns the cosine of the maximal (or minimal) dihedral angle. //
7494// //
7496
7497void tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
7498 REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
7499{
7500 REAL N[4][3], cosd, len;
7501 int f1, f2, i, j;
7502
7503 f1=0;
7504 f2=0;
7505
7506 // Get four normals of faces of the tet.
7507 tetallnormal(pa, pb, pc, pd, N, NULL);
7508 // Normalize the normals.
7509 for (i = 0; i < 4; i++) {
7510 len = sqrt(dot(N[i], N[i]));
7511 if (len != 0.0) {
7512 for (j = 0; j < 3; j++) N[i][j] /= len;
7513 }
7514 }
7515
7516 for (i = 0; i < 6; i++) {
7517 switch (i) {
7518 case 0: f1 = 2; f2 = 3; break; // edge ab.
7519 case 1: f1 = 0; f2 = 3; break; // edge bc.
7520 case 2: f1 = 1; f2 = 3; break; // edge ca.
7521 case 3: f1 = 1; f2 = 2; break; // edge ad.
7522 case 4: f1 = 2; f2 = 0; break; // edge bd.
7523 case 5: f1 = 0; f2 = 1; break; // edge cd.
7524 }
7525 cosd = -dot(N[f1], N[f2]);
7526 if (cosdd) cosdd[i] = cosd;
7527 if (i == 0) {
7528 if (cosmaxd) *cosmaxd = cosd;
7529 if (cosmind) *cosmind = cosd;
7530 } else {
7531 if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
7532 if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
7533 }
7534 }
7535}
7536
7538// //
7539// tetallnormal() Get the in-noramls of the four faces of a given tet. //
7540// //
7541// Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
7542// N[1] acd, N[2] bad, N[3] abc. These normals are unnormalized. //
7543// //
7545
7546void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
7547 REAL N[4][3], REAL* volume)
7548{
7549 REAL A[4][4], rhs[4], D;
7550 int indx[4];
7551 int i, j;
7552
7553 // get the entries of A[3][3].
7554 for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
7555 for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
7556 for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
7557 // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
7558 lu_decmp(A, 3, indx, &D, 0); // Decompose the matrix just once.
7559 if (volume != NULL) {
7560 // Get the volume of the tet.
7561 *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
7562 }
7563 for (j = 0; j < 3; j++) {
7564 for (i = 0; i < 3; i++) rhs[i] = 0.0;
7565 rhs[j] = 1.0; // Positive means the inside direction
7566 lu_solve(A, 3, indx, rhs, 0);
7567 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
7568 }
7569 // Get the fourth normal by summing up the first three.
7570 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
7571}
7572
7574// //
7575// tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
7576// //
7577// The aspect ratio of a tet is R/h, where R is the circumradius and h is //
7578// the shortest height of the tet. //
7579// //
7581
7582REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
7583{
7584 REAL vda[3], vdb[3], vdc[3];
7585 REAL N[4][3], A[4][4], rhs[4], D;
7586 REAL H[4], volume, radius2, minheightinv;
7587 int indx[4];
7588 int i, j;
7589
7590 // Set the matrix A = [vda, vdb, vdc]^T.
7591 for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
7592 for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
7593 for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
7594 // Lu-decompose the matrix A.
7595 lu_decmp(A, 3, indx, &D, 0);
7596 // Get the volume of abcd.
7597 volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
7598 // Check if it is zero.
7599 if (volume == 0.0) return 1.0e+200; // A degenerate tet.
7600 // if (volume < 0.0) volume = -volume;
7601 // Check the radiu-edge ratio of the tet.
7602 rhs[0] = 0.5 * dot(vda, vda);
7603 rhs[1] = 0.5 * dot(vdb, vdb);
7604 rhs[2] = 0.5 * dot(vdc, vdc);
7605 lu_solve(A, 3, indx, rhs, 0);
7606 // Get the circumcenter.
7607 // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
7608 // Get the square of the circumradius.
7609 radius2 = dot(rhs, rhs);
7610
7611 // Compute the 4 face normals (N[0], ..., N[3]).
7612 for (j = 0; j < 3; j++) {
7613 for (i = 0; i < 3; i++) rhs[i] = 0.0;
7614 rhs[j] = 1.0; // Positive means the inside direction
7615 lu_solve(A, 3, indx, rhs, 0);
7616 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
7617 }
7618 // Get the fourth normal by summing up the first three.
7619 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
7620 // Normalized the normals.
7621 for (i = 0; i < 4; i++) {
7622 // H[i] is the inverse of the height of its corresponding face.
7623 H[i] = sqrt(dot(N[i], N[i]));
7624 // if (H[i] > 0.0) {
7625 // for (j = 0; j < 3; j++) N[i][j] /= H[i];
7626 // }
7627 }
7628 // Get the radius of the inscribed sphere.
7629 // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
7630 // Get the biggest H[i] (corresponding to the smallest height).
7631 minheightinv = H[0];
7632 for (i = 1; i < 3; i++) {
7633 if (H[i] > minheightinv) minheightinv = H[i];
7634 }
7635
7636 return sqrt(radius2) * minheightinv;
7637}
7638
7640// //
7641// circumsphere() Calculate the smallest circumsphere (center and radius) //
7642// of the given three or four points. //
7643// //
7644// The circumsphere of four points (a tetrahedron) is unique if they are not //
7645// degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
7646// the diametral sphere of the triangle if they are not degenerate. //
7647// //
7648// Return TRUE if the input points are not degenerate and the circumcenter //
7649// and circumradius are returned in 'cent' and 'radius' respectively if they //
7650// are not NULLs. Otherwise, return FALSE indicated the points are degenrate.//
7651// //
7653
7654bool tetgenmesh::
7655circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius)
7656{
7657 REAL A[4][4], rhs[4], D;
7658 int indx[4];
7659
7660 // Compute the coefficient matrix A (3x3).
7661 A[0][0] = pb[0] - pa[0];
7662 A[0][1] = pb[1] - pa[1];
7663 A[0][2] = pb[2] - pa[2];
7664 A[1][0] = pc[0] - pa[0];
7665 A[1][1] = pc[1] - pa[1];
7666 A[1][2] = pc[2] - pa[2];
7667 if (pd != NULL) {
7668 A[2][0] = pd[0] - pa[0];
7669 A[2][1] = pd[1] - pa[1];
7670 A[2][2] = pd[2] - pa[2];
7671 } else {
7672 cross(A[0], A[1], A[2]);
7673 }
7674
7675 // Compute the right hand side vector b (3x1).
7676 rhs[0] = 0.5 * dot(A[0], A[0]);
7677 rhs[1] = 0.5 * dot(A[1], A[1]);
7678 if (pd != NULL) {
7679 rhs[2] = 0.5 * dot(A[2], A[2]);
7680 } else {
7681 rhs[2] = 0.0;
7682 }
7683
7684 // Solve the 3 by 3 equations use LU decomposition with partial pivoting
7685 // and backward and forward substitute..
7686 if (!lu_decmp(A, 3, indx, &D, 0)) {
7687 if (radius != (REAL *) NULL) *radius = 0.0;
7688 return false;
7689 }
7690 lu_solve(A, 3, indx, rhs, 0);
7691 if (cent != (REAL *) NULL) {
7692 cent[0] = pa[0] + rhs[0];
7693 cent[1] = pa[1] + rhs[1];
7694 cent[2] = pa[2] + rhs[2];
7695 }
7696 if (radius != (REAL *) NULL) {
7697 *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
7698 }
7699 return true;
7700}
7701
7703// //
7704// inscribedsphere() Compute the radius and center of the biggest //
7705// inscribed sphere of a given tetrahedron. //
7706// //
7707// The tetrahedron is given by its four points, it must not be degenerate. //
7708// The center and radius are returned in 'cent' and 'radius' respectively if //
7709// they are not NULLs. //
7710// //
7711// Geometrical fact. For any simplex in d dimension, //
7712// r/h1 + r/h2 + ... r/hn = 1 (n <= d + 1); //
7713// where r is the radius of inscribed ball, and h is the height of each side //
7714// of the simplex. The value of 'r/h' is just the barycenter coordinates of //
7715// each vertex of the simplex. Therefore, we can compute the radius and //
7716// center of the smallest inscribed ball as following equations: //
7717// r = 1.0 / (1/h1 + 1/h2 + ... + 1/hn); (1) //
7718// C = r/h1 * P1 + r/h2 * P2 + ... + r/hn * Pn; (2) //
7719// where C is the vector of center, P1, P2, .. Pn are vectors of vertices. //
7720// Here (2) contains n linear equations with n variables. (h, P) must be a //
7721// pair, h is the height from P to its opposite face. //
7722// //
7724
7725void tetgenmesh::inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
7726 REAL* cent, REAL* radius)
7727{
7728 REAL N[4][3], H[4]; // Normals (colume vectors) and heights of each face.
7729 REAL rd;
7730 int i;
7731
7732 // Get the all normals of the tet.
7733 tetallnormal(pa, pb, pc, pd, N, NULL);
7734 for (i = 0; i < 4; i++) {
7735 // H[i] is the inverse of height of its corresponding face.
7736 H[i] = sqrt(dot(N[i], N[i]));
7737 }
7738 // Compute the radius use eq. (1).
7739 rd = 1.0 / (H[0] + H[1] + H[2] + H[3]);
7740 if (radius != (REAL*) NULL) *radius = rd;
7741 if (cent != (REAL*) NULL) {
7742 // Compute the center use eq. (2).
7743 cent[0] = rd * (H[0] * pa[0] + H[1] * pb[0] + H[2] * pc[0] + H[3] * pd[0]);
7744 cent[1] = rd * (H[0] * pa[1] + H[1] * pb[1] + H[2] * pc[1] + H[3] * pd[1]);
7745 cent[2] = rd * (H[0] * pa[2] + H[1] * pb[2] + H[2] * pc[2] + H[3] * pd[2]);
7746 }
7747}
7748
7750// //
7751// rotatepoint() Create a point by rotating an existing point. //
7752// //
7753// Create a 3D point by rotating point 'p' with an angle 'rotangle' (in arc //
7754// degree) around a rotating axis given by a vector from point 'p1' to 'p2'. //
7755// The rotation is according with right-hand rule, i.e., use your right-hand //
7756// to grab the axis with your thumber pointing to its positive direction, //
7757// your fingers indicate the rotating direction. //
7758// //
7759// The rotating steps are the following: //
7760// 1. Translate vector 'p1->p2' to origin, M1; //
7761// 2. Rotate vector around the Y-axis until it lies in the YZ plane, M2; //
7762// 3. Rotate vector around the X-axis until it lies on the Z axis, M3; //
7763// 4. Perform the rotation of 'p' around the z-axis, M4; //
7764// 5. Undo Step 3, M5; //
7765// 6. Undo Step 2, M6; //
7766// 7. Undo Step 1, M7; //
7767// Use matrix multiplication to combine the above sequences, we get: //
7768// p0' = T * p0, where T = M7 * M6 * M5 * M4 * M3 * M2 * M1 //
7769// //
7771
7772void tetgenmesh::rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2)
7773{
7774 REAL T[4][4], pp0[4], p0t[4], p2t[4];
7775 REAL roty, rotx, alphaR, projlen;
7776 REAL dx, dy, dz;
7777
7778 initm44(1, 0, 0, -p1[0],
7779 0, 1, 0, -p1[1],
7780 0, 0, 1, -p1[2],
7781 0, 0, 0, 1, T);
7782 pp0[0] = p[0]; pp0[1] = p[1]; pp0[2] = p[2]; pp0[3] = 1.0;
7783 m4xv4(p0t, T, pp0); // Step 1
7784 pp0[0] = p2[0]; pp0[1] = p2[1]; pp0[2] = p2[2]; pp0[3] = 1.0;
7785 m4xv4(p2t, T, pp0); // Step 1
7786
7787 // Get the rotation angle around y-axis;
7788 dx = p2t[0];
7789 dz = p2t[2];
7790 projlen = sqrt(dx * dx + dz * dz);
7791 if (projlen <= (b->epsilon * 1e-2) * longest) {
7792 roty = 0;
7793 } else {
7794 roty = acos(dz / projlen);
7795 if (dx < 0) {
7796 roty = -roty;
7797 }
7798 }
7799
7800 initm44(cos(-roty), 0, sin(-roty), 0,
7801 0, 1, 0, 0,
7802 -sin(-roty), 0, cos(-roty), 0,
7803 0, 0, 0, 1, T);
7804 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7805 m4xv4(p0t, T, pp0); // Step 2
7806 pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0;
7807 m4xv4(p2t, T, pp0); // Step 2
7808
7809 // Get the rotation angle around x-axis
7810 dy = p2t[1];
7811 dz = p2t[2];
7812 projlen = sqrt(dy * dy + dz * dz);
7813 if (projlen <= (b->epsilon * 1e-2) * longest) {
7814 rotx = 0;
7815 } else {
7816 rotx = acos(dz / projlen);
7817 if (dy < 0) {
7818 rotx = -rotx;
7819 }
7820 }
7821
7822 initm44(1, 0, 0, 0,
7823 0, cos(rotx), -sin(rotx), 0,
7824 0, sin(rotx), cos(rotx), 0,
7825 0, 0, 0, 1, T);
7826 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7827 m4xv4(p0t, T, pp0); // Step 3
7828 // pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0;
7829 // m4xv4(p2t, T, pp0); // Step 3
7830
7831 alphaR = rotangle;
7832 initm44(cos(alphaR), -sin(alphaR), 0, 0,
7833 sin(alphaR), cos(alphaR), 0, 0,
7834 0, 0, 1, 0,
7835 0, 0, 0, 1, T);
7836 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7837 m4xv4(p0t, T, pp0); // Step 4
7838
7839 initm44(1, 0, 0, 0,
7840 0, cos(-rotx), -sin(-rotx), 0,
7841 0, sin(-rotx), cos(-rotx), 0,
7842 0, 0, 0, 1, T);
7843 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7844 m4xv4(p0t, T, pp0); // Step 5
7845
7846 initm44(cos(roty), 0, sin(roty), 0,
7847 0, 1, 0, 0,
7848 -sin(roty), 0, cos(roty), 0,
7849 0, 0, 0, 1, T);
7850 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7851 m4xv4(p0t, T, pp0); // Step 6
7852
7853 initm44(1, 0, 0, p1[0],
7854 0, 1, 0, p1[1],
7855 0, 0, 1, p1[2],
7856 0, 0, 0, 1, T);
7857 pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7858 m4xv4(p0t, T, pp0); // Step 7
7859
7860 p[0] = p0t[0];
7861 p[1] = p0t[1];
7862 p[2] = p0t[2];
7863}
7864
7866// //
7867// spherelineint() 3D line sphere (or circle) intersection. //
7868// //
7869// The line is given by two points p1, and p2, the sphere is centered at c //
7870// with radius r. This function returns a pointer array p which first index //
7871// indicates the number of intersection point, followed by coordinate pairs. //
7872// //
7873// The following code are adapted from: http://astronomy.swin.edu.au/pbourke //
7874// /geometry/sphereline. Paul Bourke pbourke@swin.edu.au //
7875// //
7877
7878void tetgenmesh::spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7])
7879{
7880 REAL x1, y1, z1; // P1 coordinates (point of line)
7881 REAL x2, y2, z2; // P2 coordinates (point of line)
7882 REAL x3, y3, z3, r; // P3 coordinates and radius (sphere)
7883 REAL a, b, c, mu, i ;
7884
7885 x1 = p1[0]; y1 = p1[1]; z1 = p1[2];
7886 x2 = p2[0]; y2 = p2[1]; z2 = p2[2];
7887 x3 = C[0]; y3 = C[1]; z3 = C[2];
7888 r = R;
7889
7890 a = (x2 - x1) * (x2 - x1)
7891 + (y2 - y1) * (y2 - y1)
7892 + (z2 - z1) * (z2 - z1);
7893 b = 2 * ( (x2 - x1) * (x1 - x3)
7894 + (y2 - y1) * (y1 - y3)
7895 + (z2 - z1) * (z1 - z3) ) ;
7896 c = (x3 * x3) + (y3 * y3) + (z3 * z3)
7897 + (x1 * x1) + (y1 * y1) + (z1 * z1)
7898 - 2 * (x3 * x1 + y3 * y1 + z3 * z1) - (r * r) ;
7899 i = b * b - 4 * a * c ;
7900
7901 if (i < 0.0) {
7902 // no intersection
7903 p[0] = 0.0;
7904 } else if (i == 0.0) {
7905 // one intersection
7906 p[0] = 1.0;
7907 mu = -b / (2 * a) ;
7908 p[1] = x1 + mu * (x2 - x1);
7909 p[2] = y1 + mu * (y2 - y1);
7910 p[3] = z1 + mu * (z2 - z1);
7911 } else {
7912 // two intersections
7913 p[0] = 2.0;
7914 // first intersection
7915 mu = (-b + sqrt((b * b) - 4 * a * c)) / (2 * a);
7916 p[1] = x1 + mu * (x2 - x1);
7917 p[2] = y1 + mu * (y2 - y1);
7918 p[3] = z1 + mu * (z2 - z1);
7919 // second intersection
7920 mu = (-b - sqrt((b * b) - 4 * a * c)) / (2 * a);
7921 p[4] = x1 + mu * (x2 - x1);
7922 p[5] = y1 + mu * (y2 - y1);
7923 p[6] = z1 + mu * (z2 - z1);
7924 }
7925}
7926
7928// //
7929// linelineint() Calculate the shortest line between two lines in 3D. //
7930// //
7931// Two 3D lines generally don't intersect at a point, they may be parallel ( //
7932// no intersections), or coincident (infinite intersections) but most often //
7933// only their projections onto a plane intersect. If they don't exactly int- //
7934// ersect at a point they can be connected by a line segment, the shortest //
7935// segment is unique and is often considered to be their intersection in 3D. //
7936// //
7937// The following code are adapted from: http://astronomy.swin.edu.au/pbourke //
7938// /geometry/lineline3d. Paul Bourke pbourke@swin.edu.au //
7939// //
7940// Calculate the line segment PaPb that is the shortest route between two //
7941// lines P1P2 and P3P4. This function returns a pointer array p which first //
7942// index indicates there exists solution or not, 0 means no solution, 1 meas //
7943// has solution followed by two coordinate pairs. //
7944// //
7946
7947void tetgenmesh::linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7])
7948{
7949 REAL p13[3], p43[3], p21[3];
7950 REAL d1343, d4321, d1321, d4343, d2121;
7951 REAL numer, denom;
7952 REAL mua, mub;
7953
7954 p13[0] = p1[0] - p3[0];
7955 p13[1] = p1[1] - p3[1];
7956 p13[2] = p1[2] - p3[2];
7957 p43[0] = p4[0] - p3[0];
7958 p43[1] = p4[1] - p3[1];
7959 p43[2] = p4[2] - p3[2];
7960 if (p43[0] == 0.0 && p43[1] == 0.0 && p43[2] == 0.0) {
7961 p[0] = 0.0;
7962 return;
7963 }
7964
7965 p21[0] = p2[0] - p1[0];
7966 p21[1] = p2[1] - p1[1];
7967 p21[2] = p2[2] - p1[2];
7968 if (p21[0] == 0.0 && p21[1] == 0.0 && p21[2] == 0.0) {
7969 p[0] = 0.0;
7970 return;
7971 }
7972
7973 d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2];
7974 d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2];
7975 d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2];
7976 d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2];
7977 d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2];
7978
7979 denom = d2121 * d4343 - d4321 * d4321;
7980 if (denom == 0.0) {
7981 p[0] = 0.0;
7982 return;
7983 }
7984 numer = d1343 * d4321 - d1321 * d4343;
7985 mua = numer / denom;
7986 mub = (d1343 + d4321 * mua) / d4343;
7987
7988 p[0] = 1.0;
7989 p[1] = p1[0] + mua * p21[0];
7990 p[2] = p1[1] + mua * p21[1];
7991 p[3] = p1[2] + mua * p21[2];
7992 p[4] = p3[0] + mub * p43[0];
7993 p[5] = p3[1] + mub * p43[1];
7994 p[6] = p3[2] + mub * p43[2];
7995}
7996
7998// //
7999// planelineint() Calculate the intersection of a line and a plane. //
8000// //
8001// The equation of a plane (points P are on the plane with normal N and P3 //
8002// on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
8003// line (points P on the line passing through P1 and P2) can be written as: //
8004// P = P1 + u (P2 - P1). The intersection of these two occurs when: //
8005// N dot (P1 + u (P2 - P1)) = N dot P3. //
8006// Solving for u gives: //
8007// N dot (P3 - P1) //
8008// u = ------------------. //
8009// N dot (P2 - P1) //
8010// If the denominator is 0 then N (the normal to the plane) is perpendicular //
8011// to the line. Thus the line is either parallel to the plane and there are //
8012// no solutions or the line is on the plane in which case there are an infi- //
8013// nite number of solutions. //
8014// //
8015// The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
8016// line. If u is non-zero, The intersection point (if exists) returns in ip. //
8017// //
8019
8020void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
8021 REAL* ip, REAL* u)
8022{
8023 REAL n[3], det, det1;
8024
8025 // Calculate N.
8026 facenormal(pa, pb, pc, n, NULL);
8027 // Calculate N dot (e2 - e1).
8028 det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
8029 + n[2] * (e2[2] - e1[2]);
8030 if (det != 0.0) {
8031 // Calculate N dot (pa - e1)
8032 det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
8033 + n[2] * (pa[2] - e1[2]);
8034 *u = det1 / det;
8035 ip[0] = e1[0] + *u * (e2[0] - e1[0]);
8036 ip[1] = e1[1] + *u * (e2[1] - e1[1]);
8037 ip[2] = e1[2] + *u * (e2[2] - e1[2]);
8038 } else {
8039 *u = 0.0;
8040 }
8041}
8042
8043//
8044// End of Geometric quantities calculators
8045//
8046
8047//
8048// Begin of memory management routines
8049//
8050
8052// //
8053// dummyinit() Initialize the tetrahedron that fills "outer space" and //
8054// the omnipresent subface. //
8055// //
8056// The tetrahedron that fills "outer space" called 'dummytet', is pointed to //
8057// by every tetrahedron and subface on a boundary (be it outer or inner) of //
8058// the tetrahedralization. Also, 'dummytet' points to one of the tetrahedron //
8059// on the convex hull(until the holes and concavities are carved), making it //
8060// possible to find a starting tetrahedron for point location. //
8061// //
8062// The omnipresent subface,'dummysh', is pointed to by every tetrahedron or //
8063// subface that doesn't have a full complement of real subface to point to. //
8064// //
8066
8067void tetgenmesh::dummyinit(int tetwords, int shwords)
8068{
8069 unsigned long alignptr;
8070
8071 // Set up 'dummytet', the 'tetrahedron' that occupies "outer space".
8072 dummytetbase = (tetrahedron *) new char[tetwords * sizeof(tetrahedron)
8073 + tetrahedrons->alignbytes];
8074 // Align 'dummytet' on a 'tetrahedrons->alignbytes'-byte boundary.
8075 alignptr = (unsigned long) dummytetbase;
8076 dummytet = (tetrahedron *)
8077 (alignptr + (unsigned long) tetrahedrons->alignbytes
8078 - (alignptr % (unsigned long) tetrahedrons->alignbytes));
8079 // Initialize the four adjoining tetrahedra to be "outer space". These
8080 // will eventually be changed by various bonding operations, but their
8081 // values don't really matter, as long as they can legally be
8082 // dereferenced.
8083 dummytet[0] = (tetrahedron) dummytet;
8084 dummytet[1] = (tetrahedron) dummytet;
8085 dummytet[2] = (tetrahedron) dummytet;
8086 dummytet[3] = (tetrahedron) dummytet;
8087 // Four null vertex points.
8088 dummytet[4] = (tetrahedron) NULL;
8089 dummytet[5] = (tetrahedron) NULL;
8090 dummytet[6] = (tetrahedron) NULL;
8091 dummytet[7] = (tetrahedron) NULL;
8092
8093 if (b->useshelles) {
8094 // Set up 'dummysh', the omnipresent "subface" pointed to by any
8095 // tetrahedron side or subface end that isn't attached to a real
8096 // subface.
8097 dummyshbase = (shellface *) new char[shwords * sizeof(shellface)
8098 + subfaces->alignbytes];
8099 // Align 'dummysh' on a 'subfaces->alignbytes'-byte boundary.
8100 alignptr = (unsigned long) dummyshbase;
8101 dummysh = (shellface *)
8102 (alignptr + (unsigned long) subfaces->alignbytes
8103 - (alignptr % (unsigned long) subfaces->alignbytes));
8104 // Initialize the three adjoining subfaces to be the omnipresent
8105 // subface. These will eventually be changed by various bonding
8106 // operations, but their values don't really matter, as long as they
8107 // can legally be dereferenced.
8108 dummysh[0] = (shellface) dummysh;
8109 dummysh[1] = (shellface) dummysh;
8110 dummysh[2] = (shellface) dummysh;
8111 // Three null vertex points.
8112 dummysh[3] = (shellface) NULL;
8113 dummysh[4] = (shellface) NULL;
8114 dummysh[5] = (shellface) NULL;
8115 // Initialize the two adjoining tetrahedra to be "outer space".
8116 dummysh[6] = (shellface) dummytet;
8117 dummysh[7] = (shellface) dummytet;
8118 // Initialize the three adjoining subsegments to be "out boundary".
8119 dummysh[8] = (shellface) dummysh;
8120 dummysh[9] = (shellface) dummysh;
8121 dummysh[10] = (shellface) dummysh;
8122 // Initialize the pointer to badface structure.
8123 dummysh[11] = (shellface) NULL;
8124 // Initialize the four adjoining subfaces of 'dummytet' to be the
8125 // omnipresent subface.
8126 dummytet[8 ] = (tetrahedron) dummysh;
8127 dummytet[9 ] = (tetrahedron) dummysh;
8128 dummytet[10] = (tetrahedron) dummysh;
8129 dummytet[11] = (tetrahedron) dummysh;
8130 }
8131}
8132
8134// //
8135// initializepools() Calculate the sizes of the point, tetrahedron, and //
8136// subface. Initialize their memory pools. //
8137// //
8138// This routine also computes the indices 'pointmarkindex', 'point2simindex',//
8139// and 'point2pbcptindex' used to find values within each point; computes //
8140// indices 'highorderindex', 'elemattribindex', and 'volumeboundindex' used //
8141// to find values within each tetrahedron. //
8142// //
8143// There are two types of boundary elements, which are subfaces and subsegs, //
8144// they are stored in seperate pools. However, the data structures of them //
8145// are the same. A subsegment can be regarded as a degenerate subface, i.e.,//
8146// one of its three corners is not used. We set the apex of it be 'NULL' to //
8147// distinguish it's a subsegment. //
8148// //
8150
8151void tetgenmesh::initializepools()
8152{
8153 enum wordtype wtype;
8154 int pointsize, elesize, shsize;
8155
8156 // Default checkpbc = 0;
8157 if ((b->plc || b->refine) && (in->pbcgrouplist != NULL)) {
8158 checkpbcs = 1;
8159 }
8160 // Default varconstraint = 0;
8161 if (in->segmentconstraintlist || in->facetconstraintlist) {
8162 varconstraint = 1;
8163 }
8164
8165 // The index within each point at which its metric tensor is found. It is
8166 // saved directly after the list of point attributes.
8167 pointmtrindex = 3 + in->numberofpointattributes;
8168 // Decide the size (1, 3, or 6) of the metric tensor.
8169 if (b->metric) {
8170 // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
8171 if (bgm != (tetgenmesh *) NULL) {
8172 // A background mesh is allocated. It may not exist though.
8173 sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
8174 bgm->in->numberofpointmtrs : in->numberofpointmtrs;
8175 } else {
8176 // No given background mesh - Itself is a background mesh.
8177 sizeoftensor = in->numberofpointmtrs;
8178 }
8179 // Make sure sizeoftensor is at least 1.
8180 sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
8181 } else {
8182 // For '-q' option. Make sure to have space for saving a scalar value.
8183 sizeoftensor = b->quality ? 1 : 0;
8184 }
8185 // The index within each point at which an element pointer is found, where
8186 // the index is measured in pointers. Ensure the index is aligned to a
8187 // sizeof(tetrahedron)-byte address.
8188 point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
8189 + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
8190 if (b->plc || b->refine) {
8191 // Increase the point size by three pointers, which are:
8192 // - a pointer to a tet, read by point2tet();
8193 // - a pointer to a subface/subsegment , read by point2sh();
8194 // - a pointer to a parent point, read by point2ppt()).
8195 if (b->metric) {
8196 // Increase one pointer to a tet of the background mesh.
8197 pointsize = (point2simindex + 4) * sizeof(tetrahedron);
8198 } else {
8199 pointsize = (point2simindex + 3) * sizeof(tetrahedron);
8200 }
8201 // The index within each point at which a pbc point is found.
8202 point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1)
8203 / sizeof(tetrahedron);
8204 if (checkpbcs) {
8205 // Increase the size by one pointer to a corresponding pbc point,
8206 // read by point2pbcpt().
8207 pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron);
8208 }
8209 } else {
8210 pointsize = point2simindex * sizeof(tetrahedron);
8211 }
8212 // The index within each point at which the boundary marker is found,
8213 // Ensure the point marker is aligned to a sizeof(int)-byte address.
8214 pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
8215 // Now point size is the ints (inidcated by pointmarkindex) plus:
8216 // - an integer for boundary marker;
8217 // - an integer for vertex type;
8218 pointsize = (pointmarkindex + 2) * sizeof(int);
8219 // Decide the wordtype used in vertex pool.
8220 wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER;
8221 // Initialize the pool of vertices.
8222 points = new memorypool(pointsize, VERPERBLOCK, wtype, 0);
8223
8224 // The number of bytes occupied by a tetrahedron. There are four pointers
8225 // to other tetrahedra, four pointers to corners, and possibly four
8226 // pointers to subfaces.
8227 elesize = (8 + b->useshelles * 6) * sizeof(tetrahedron);
8228 // If Voronoi diagram is wanted, make sure we have additional space.
8229 if (b->voroout && (b->useshelles == 0)) {
8230 elesize = (8 + 4) * sizeof(tetrahedron);
8231 }
8232 // The index within each element at which its attributes are found, where
8233 // the index is measured in REALs.
8234 elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
8235 // The index within each element at which the maximum voulme bound is
8236 // found, where the index is measured in REALs. Note that if the
8237 // `b->regionattrib' flag is set, an additional attribute will be added.
8238 volumeboundindex = elemattribindex + in->numberoftetrahedronattributes
8239 + (b->regionattrib > 0);
8240 // If element attributes or an constraint are needed, increase the number
8241 // of bytes occupied by an element.
8242 if (b->varvolume) {
8243 elesize = (volumeboundindex + 1) * sizeof(REAL);
8244 } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) {
8245 elesize = volumeboundindex * sizeof(REAL);
8246 }
8247 // If element neighbor graph is requested (-n switch), an additional
8248 // integer is allocated for each element.
8249 elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
8250 if (b->neighout || b->voroout) {
8251 elesize = (elemmarkerindex + 1) * sizeof(int);
8252 }
8253 // If -o2 switch is used, an additional pointer pointed to the list of
8254 // higher order nodes is allocated for each element.
8255 highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
8256 if (b->order == 2) {
8257 elesize = (highorderindex + 1) * sizeof(tetrahedron);
8258 }
8259 // Having determined the memory size of an element, initialize the pool.
8260 tetrahedrons = new memorypool(elesize, ELEPERBLOCK, POINTER, 8);
8261
8262 if (b->useshelles) {
8263 // The number of bytes occupied by a subface. The list of pointers
8264 // stored in a subface are: three to other subfaces, three to corners,
8265 // three to subsegments, two to tetrahedra, and one to a badface.
8266 shsize = 12 * sizeof(shellface);
8267 // The index within each subface at which the maximum area bound is
8268 // found, where the index is measured in REALs.
8269 areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
8270 // If -q switch is in use, increase the number of bytes occupied by
8271 // a subface for saving maximum area bound.
8272 if (b->quality && varconstraint) {
8273 shsize = (areaboundindex + 1) * sizeof(REAL);
8274 } else {
8275 shsize = areaboundindex * sizeof(REAL);
8276 }
8277 // The index within subface at which the facet marker is found. Ensure
8278 // the marker is aligned to a sizeof(int)-byte address.
8279 shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
8280 // Increase the number of bytes by two or three integers, one for facet
8281 // marker, one for shellface type, and optionally one for pbc group.
8282 shsize = (shmarkindex + 2 + checkpbcs) * sizeof(int);
8283 // Initialize the pool of subfaces. Each subface record is eight-byte
8284 // aligned so it has room to store an edge version (from 0 to 5) in
8285 // the least three bits.
8286 subfaces = new memorypool(shsize, SUBPERBLOCK, POINTER, 8);
8287 // Initialize the pool of subsegments. The subsegment's record is same
8288 // with subface.
8289 subsegs = new memorypool(shsize, SUBPERBLOCK, POINTER, 8);
8290 // Initialize the "outer space" tetrahedron and omnipresent subface.
8291 dummyinit(tetrahedrons->itemwords, subfaces->itemwords);
8292 } else {
8293 // Initialize the "outer space" tetrahedron.
8294 dummyinit(tetrahedrons->itemwords, 0);
8295 }
8296}
8297
8299// //
8300// tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
8301// //
8303
8304void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
8305{
8306 // Set tetrahedron's vertices to NULL. This makes it possible to detect
8307 // dead tetrahedra when traversing the list of all tetrahedra.
8308 dyingtetrahedron[4] = (tetrahedron) NULL;
8309 dyingtetrahedron[5] = (tetrahedron) NULL;
8310 dyingtetrahedron[6] = (tetrahedron) NULL;
8311 dyingtetrahedron[7] = (tetrahedron) NULL;
8312 tetrahedrons->dealloc((void *) dyingtetrahedron);
8313}
8314
8316// //
8317// tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
8318// //
8320
8321tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
8322{
8323 tetrahedron *newtetrahedron;
8324
8325 do {
8326 newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
8327 if (newtetrahedron == (tetrahedron *) NULL) {
8328 return (tetrahedron *) NULL;
8329 }
8330 } while (newtetrahedron[7] == (tetrahedron) NULL); // Skip dead ones.
8331 return newtetrahedron;
8332}
8333
8335// //
8336// shellfacedealloc() Deallocate space for a shellface, marking it dead. //
8337// Used both for dealloc a subface and subsegment. //
8338// //
8340
8341void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
8342{
8343 // Set shellface's vertices to NULL. This makes it possible to detect dead
8344 // shellfaces when traversing the list of all shellfaces.
8345 dyingsh[3] = (shellface) NULL;
8346 dyingsh[4] = (shellface) NULL;
8347 dyingsh[5] = (shellface) NULL;
8348 pool->dealloc((void *) dyingsh);
8349}
8350
8352// //
8353// shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
8354// for both subfaces and subsegments pool traverse. //
8355// //
8357
8358tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
8359{
8360 shellface *newshellface;
8361
8362 do {
8363 newshellface = (shellface *) pool->traverse();
8364 if (newshellface == (shellface *) NULL) {
8365 return (shellface *) NULL;
8366 }
8367 } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
8368 return newshellface;
8369}
8370
8372// //
8373// badfacedealloc() Deallocate space for a badface, marking it dead. //
8374// //
8376
8377void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying)
8378{
8379 // Set badface's forg to NULL. This makes it possible to detect dead
8380 // ones when traversing the list of all items.
8381 dying->forg = (point) NULL;
8382 pool->dealloc((void *) dying);
8383}
8384
8386// //
8387// badfacetraverse() Traverse the pools, skipping dead ones. //
8388// //
8390
8391tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool)
8392{
8393 badface *newsh;
8394
8395 do {
8396 newsh = (badface *) pool->traverse();
8397 if (newsh == (badface *) NULL) {
8398 return (badface *) NULL;
8399 }
8400 } while (newsh->forg == (point) NULL); // Skip dead ones.
8401 return newsh;
8402}
8403
8405// //
8406// pointdealloc() Deallocate space for a point, marking it dead. //
8407// //
8409
8410void tetgenmesh::pointdealloc(point dyingpoint)
8411{
8412 // Mark the point as dead. This makes it possible to detect dead points
8413 // when traversing the list of all points.
8414 setpointtype(dyingpoint, DEADVERTEX);
8415 points->dealloc((void *) dyingpoint);
8416}
8417
8419// //
8420// pointtraverse() Traverse the points, skipping dead ones. //
8421// //
8423
8424tetgenmesh::point tetgenmesh::pointtraverse()
8425{
8426 point newpoint;
8427
8428 do {
8429 newpoint = (point) points->traverse();
8430 if (newpoint == (point) NULL) {
8431 return (point) NULL;
8432 }
8433 } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
8434 return newpoint;
8435}
8436
8438// //
8439// maketetrahedron() Create a new tetrahedron. //
8440// //
8442
8443void tetgenmesh::maketetrahedron(triface *newtet)
8444{
8445 newtet->tet = (tetrahedron *) tetrahedrons->alloc();
8446 // Initialize the four adjoining tetrahedra to be "outer space".
8447 newtet->tet[0] = (tetrahedron) dummytet;
8448 newtet->tet[1] = (tetrahedron) dummytet;
8449 newtet->tet[2] = (tetrahedron) dummytet;
8450 newtet->tet[3] = (tetrahedron) dummytet;
8451 // Four NULL vertices.
8452 newtet->tet[4] = (tetrahedron) NULL;
8453 newtet->tet[5] = (tetrahedron) NULL;
8454 newtet->tet[6] = (tetrahedron) NULL;
8455 newtet->tet[7] = (tetrahedron) NULL;
8456 // Initialize the four adjoining subfaces to be the omnipresent subface.
8457 if (b->useshelles) {
8458 newtet->tet[8 ] = (tetrahedron) dummysh;
8459 newtet->tet[9 ] = (tetrahedron) dummysh;
8460 newtet->tet[10] = (tetrahedron) dummysh;
8461 newtet->tet[11] = (tetrahedron) dummysh;
8462 newtet->tet[12] = (tetrahedron) dummysh;
8463 newtet->tet[13] = (tetrahedron) dummysh;
8464 }
8465 for (int i = 0; i < in->numberoftetrahedronattributes; i++) {
8466 setelemattribute(newtet->tet, i, 0.0);
8467 }
8468 if (b->varvolume) {
8469 setvolumebound(newtet->tet, -1.0);
8470 }
8471 // Initialize the location and version to be Zero.
8472 newtet->loc = 0;
8473 newtet->ver = 0;
8474}
8475
8477// //
8478// makeshellface() Create a new shellface with version zero. Used for //
8479// both subfaces and seusegments. //
8480// //
8482
8483void tetgenmesh::makeshellface(memorypool *pool, face *newface)
8484{
8485 newface->sh = (shellface *) pool->alloc();
8486 //Initialize the three adjoining subfaces to be the omnipresent subface.
8487 newface->sh[0] = (shellface) dummysh;
8488 newface->sh[1] = (shellface) dummysh;
8489 newface->sh[2] = (shellface) dummysh;
8490 // Three NULL vertices.
8491 newface->sh[3] = (shellface) NULL;
8492 newface->sh[4] = (shellface) NULL;
8493 newface->sh[5] = (shellface) NULL;
8494 // Initialize the two adjoining tetrahedra to be "outer space".
8495 newface->sh[6] = (shellface) dummytet;
8496 newface->sh[7] = (shellface) dummytet;
8497 // Initialize the three adjoining subsegments to be the omnipresent
8498 // subsegments.
8499 newface->sh [8] = (shellface) dummysh;
8500 newface->sh [9] = (shellface) dummysh;
8501 newface->sh[10] = (shellface) dummysh;
8502 // Initialize the pointer to badface structure.
8503 newface->sh[11] = (shellface) NULL;
8504 if (b->quality && varconstraint) {
8505 // Initialize the maximum area bound.
8506 setareabound(*newface, 0.0);
8507 }
8508 // Set the boundary marker to zero.
8509 setshellmark(*newface, 0);
8510 // Set the type.
8511 setshelltype(*newface, NSHARP);
8512 if (checkpbcs) {
8513 // Set the pbcgroup be ivalid.
8514 setshellpbcgroup(*newface, -1);
8515 }
8516 // Initialize the version to be Zero.
8517 newface->shver = 0;
8518}
8519
8521// //
8522// makepoint() Create a new point. //
8523// //
8525
8526void tetgenmesh::makepoint(point* pnewpoint)
8527{
8528 int ptmark, i;
8529
8530 *pnewpoint = (point) points->alloc();
8531 // Initialize three coordinates.
8532 (*pnewpoint)[0] = 0.0;
8533 (*pnewpoint)[1] = 0.0;
8534 (*pnewpoint)[2] = 0.0;
8535 // Initialize the list of user-defined attributes.
8536 for (i = 0; i < in->numberofpointattributes; i++) {
8537 (*pnewpoint)[3 + i] = 0.0;
8538 }
8539 // Initialize the metric tensor.
8540 for (i = 0; i < sizeoftensor; i++) {
8541 (*pnewpoint)[pointmtrindex + i] = 0.0;
8542 }
8543 if (b->plc || b->refine) {
8544 // Initialize the point-to-simplex filed.
8545 setpoint2tet(*pnewpoint, NULL);
8546 setpoint2sh(*pnewpoint, NULL);
8547 setpoint2ppt(*pnewpoint, NULL);
8548 if (b->metric) {
8549 setpoint2bgmtet(*pnewpoint, NULL);
8550 }
8551 if (checkpbcs) {
8552 // Initialize the other pointer to its pbc point.
8553 setpoint2pbcpt(*pnewpoint, NULL);
8554 }
8555 }
8556 // Initialize the point marker (starting from in->firstnumber).
8557 ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
8558 setpointmark(*pnewpoint, ptmark);
8559 // Initialize the point type.
8560 setpointtype(*pnewpoint, UNUSEDVERTEX);
8561}
8562
8563//
8564// End of memory management routines
8565//
8566
8567//
8568// Begin of point location routines
8569//
8570
8572// //
8573// randomnation() Generate a random number between 0 and 'choices' - 1. //
8574// //
8576
8577unsigned long tetgenmesh::randomnation(unsigned int choices)
8578{
8579 unsigned long newrandom;
8580
8581 if (choices >= 714025l) {
8582 newrandom = (randomseed * 1366l + 150889l) % 714025l;
8583 randomseed = (newrandom * 1366l + 150889l) % 714025l;
8584 newrandom = newrandom * (choices / 714025l) + randomseed;
8585 if (newrandom >= choices) {
8586 return newrandom - choices;
8587 } else {
8588 return newrandom;
8589 }
8590 } else {
8591 randomseed = (randomseed * 1366l + 150889l) % 714025l;
8592 return randomseed % choices;
8593 }
8594 // Old function.
8595 // randomseed = (randomseed * 1366l + 150889l) % 714025l;
8596 // return randomseed / (714025l / choices + 1);
8597}
8598
8600// //
8601// distance2() Returns the square "distance" of a tetrahedron to point p. //
8602// //
8604
8605REAL tetgenmesh::distance2(tetrahedron* tetptr, point p)
8606{
8607 point p1, p2, p3, p4;
8608 REAL dx, dy, dz;
8609
8610 p1 = (point) tetptr[4];
8611 p2 = (point) tetptr[5];
8612 p3 = (point) tetptr[6];
8613 p4 = (point) tetptr[7];
8614
8615 dx = p[0] - 0.25 * (p1[0] + p2[0] + p3[0] + p4[0]);
8616 dy = p[1] - 0.25 * (p1[1] + p2[1] + p3[1] + p4[1]);
8617 dz = p[2] - 0.25 * (p1[2] + p2[2] + p3[2] + p4[2]);
8618
8619 return dx * dx + dy * dy + dz * dz;
8620}
8621
8623// //
8624// preciselocate() Find a simplex containing a given point. //
8625// //
8626// This routine implements the simple Walk-through point location algorithm. //
8627// Begins its search from 'searchtet', assume there is a line segment L from //
8628// a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
8629// towards 'searchpt' by traversing all faces intersected by L. //
8630// //
8631// On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
8632// returned value indicates one of the following cases: //
8633// - Returns ONVERTEX if the point lies on an existing vertex. 'searchtet' //
8634// is a handle whose origin is the existing vertex. //
8635// - Returns ONEDGE if the point lies on a mesh edge. 'searchtet' is a //
8636// handle whose primary edge is the edge on which the point lies. //
8637// - Returns ONFACE if the point lies strictly within a face. 'searchtet' //
8638// is a handle whose primary face is the face on which the point lies. //
8639// - Returns INTETRAHEDRON if the point lies strictly in a tetrahededron. //
8640// 'searchtet' is a handle on the tetrahedron that contains the point. //
8641// - Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a //
8642// handle whose location is the face the point is to 'above' of. //
8643// //
8644// WARNING: This routine is designed for convex triangulations, and will not //
8645// generally work after the holes and concavities have been carved. //
8646// //
8647// If 'maxtetnumber' > 0, stop the searching process if the number of passed //
8648// tets is larger than it and return OUTSIDE. //
8649// //
8651
8652enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt,
8653 triface* searchtet, long maxtetnumber)
8654{
8655 triface backtracetet;
8656 triface walkthroface;
8657 point forg, fdest, fapex, toppo;
8658 REAL ori1, ori2, ori3, ori4;
8659 long tetnumber;
8660 int side;
8661
8662 if (isdead(searchtet)) searchtet->tet = dummytet;
8663 if (searchtet->tet == dummytet) {
8664 searchtet->loc = 0;
8665 symself(*searchtet);
8666 }
8667 // 'searchtet' should be a valid tetrahedron now.
8668#ifdef SELF_CHECK
8669 // assert(!isdead(searchtet) && (searchtet->tet != dummytet));
8670#endif
8671 if (isdead(searchtet)) {
8672 printf("Warning: Point location failed.\n");
8673 return OUTSIDE;
8674 }
8675
8676 searchtet->ver = 0; // Keep in CCW edge ring.
8677 // Find a face of 'searchtet' such that the 'searchpt' lies strictly
8678 // above it. Such face should always exist.
8679 for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) {
8680 forg = org(*searchtet);
8681 fdest = dest(*searchtet);
8682 fapex = apex(*searchtet);
8683 ori1 = orient3d(forg, fdest, fapex, searchpt);
8684 if (ori1 < 0.0) break;
8685 }
8686#ifdef SELF_CHECK
8687 assert(searchtet->loc < 4);
8688#endif
8689
8690 // Define 'tetnumber' for exit the loop when it's running endless.
8691 tetnumber = 0l;
8692 while ((maxtetnumber > 0l) && (tetnumber <= maxtetnumber)) {
8693 // Check if we are reaching the boundary of the triangulation.
8694 if (searchtet->tet == dummytet) {
8695 *searchtet = backtracetet;
8696 return OUTSIDE;
8697 }
8698 // Initialize the face for returning the walk-through face.
8699 walkthroface.tet = (tetrahedron *) NULL;
8700 // Adjust the edge ring, so that 'ori1 < 0.0' holds.
8701 searchtet->ver = 0;
8702 // 'toppo' remains unchange for the following orientation tests.
8703 toppo = oppo(*searchtet);
8704 // Check the three sides of 'searchtet' to find the face through which
8705 // we can walk next.
8706 for (side = 0; side < 3; side++) {
8707 forg = org(*searchtet);
8708 fdest = dest(*searchtet);
8709 ori2 = orient3d(forg, fdest, toppo, searchpt);
8710 if (ori2 == 0.0) {
8711 // They are coplanar, check if 'searchpt' lies inside, or on an edge,
8712 // or coindice with a vertex of face (forg, fdest, toppo).
8713 fapex = apex(*searchtet);
8714 ori3 = orient3d(fdest, fapex, toppo, searchpt);
8715 if (ori3 < 0.0) {
8716 // Outside the face (fdest, fapex, toppo), walk through it.
8717 enextself(*searchtet);
8718 fnext(*searchtet, walkthroface);
8719 break;
8720 }
8721 ori4 = orient3d(fapex, forg, toppo, searchpt);
8722 if (ori4 < 0.0) {
8723 // Outside the face (fapex, forg, toppo), walk through it.
8724 enext2self(*searchtet);
8725 fnext(*searchtet, walkthroface);
8726 break;
8727 }
8728 // Remember, ori1 < 0.0, which means 'searchpt' will not on edge
8729 // (forg, fdest) or on vertex forg or fdest.
8730#ifdef SELF_CHECK
8731 assert(ori1 < 0.0);
8732#endif
8733 // The rest possible cases are:
8734 // (1) 'searchpt' lies on edge (fdest, toppo);
8735 // (2) 'searchpt' lies on edge (toppo, forg);
8736 // (3) 'searchpt' coincident with toppo;
8737 // (4) 'searchpt' lies inside face (forg, fdest, toppo).
8738 fnextself(*searchtet);
8739 if (ori3 == 0.0) {
8740 if (ori4 == 0.0) {
8741 // Case (4).
8742 enext2self(*searchtet);
8743 return ONVERTEX;
8744 } else {
8745 // Case (1).
8746 enextself(*searchtet);
8747 return ONEDGE;
8748 }
8749 }
8750 if (ori4 == 0.0) {
8751 // Case (2).
8752 enext2self(*searchtet);
8753 return ONEDGE;
8754 }
8755 // Case (4).
8756 return ONFACE;
8757 } else if (ori2 < 0.0) {
8758 // Outside the face (forg, fdest, toppo), walk through it.
8759 fnext(*searchtet, walkthroface);
8760 break;
8761 }
8762 // Go to check next side.
8763 enextself(*searchtet);
8764 }
8765 if (side >= 3) {
8766 // Found! Inside tetrahedron.
8767 return INTETRAHEDRON;
8768 }
8769 // We walk through the face 'walkthroface' and continue the searching.
8770#ifdef SELF_CHECK
8771 assert(walkthroface.tet != (tetrahedron *) NULL);
8772#endif
8773 // Store the face handle in 'backtracetet' before we take the real walk.
8774 // So we are able to restore the handle to 'searchtet' if we are
8775 // reaching the outer boundary.
8776 backtracetet = walkthroface;
8777 sym(walkthroface, *searchtet);
8778 tetnumber++;
8779 }
8780
8781 // Should never be here.
8782 // printf("Internal error in preciselocate(): Point location failed.\n");
8783 // internalerror();
8784 return OUTSIDE;
8785}
8786
8788// //
8789// locate() Find a simplex containing a given point. //
8790// //
8791// This routine implements Muecke's Jump-and-walk point location algorithm. //
8792// It improves the simple walk-through by "jumping" to a good starting point //
8793// via random sampling. Searching begins from one of handles: the input //
8794// 'searchtet', a recently encountered tetrahedron 'recenttet', or from one //
8795// chosen from a random sample. The choice is made by determining which one //
8796// 's barycenter is closest to the point we are searcing for. Having chosen //
8797// the starting tetrahedron, the simple Walk-through algorithm is used to do //
8798// the real walking. //
8799// //
8800// The return value indicates the location of the 'searchpt' (INTETRAHEDRON, //
8801// or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding //
8802// to that value. See the introduction part of preciselocate() for detail. //
8803// //
8804// WARNING: This routine is designed for convex triangulations, and will not //
8805// generally work after the holes and concavities have been carved. //
8806// //
8808
8809enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt,
8810 triface *searchtet)
8811{
8812 tetrahedron *firsttet, *tetptr;
8813 void **sampleblock;
8814 long sampleblocks, samplesperblock, samplenum;
8815 long tetblocks, i, j;
8816 unsigned long alignptr;
8817 REAL searchdist, dist;
8818
8819 // 'searchtet' should be a valid tetrahedron.
8820 if (isdead(searchtet)) {
8821 searchtet->tet = dummytet;
8822 }
8823 if (searchtet->tet == dummytet) {
8824 // This is an 'Outer Space' handle, get a hull tetrahedron.
8825 searchtet->loc = 0;
8826 symself(*searchtet);
8827 }
8828#ifdef SELF_CHECK
8829 // assert(!isdead(searchtet));
8830#endif
8831 if (isdead(searchtet)) {
8832 printf("Warning: Point location failed.\n");
8833 return OUTSIDE;
8834 }
8835
8836 // Get the distance from the suggested starting tet to the point we seek.
8837 searchdist = distance2(searchtet->tet, searchpt);
8838
8839 // If a recently encountered tetrahedron has been recorded and has not
8840 // been deallocated, test it as a good starting point.
8841 if (!isdead(&recenttet) && (recenttet.tet != searchtet->tet)) {
8842 dist = distance2(recenttet.tet, searchpt);
8843 if (dist < searchdist) {
8844 *searchtet = recenttet;
8845 searchdist = dist;
8846 }
8847 }
8848
8849 // Select "good" candidate using k random samples, taking the closest one.
8850 // The number of random samples taken is proportional to the fourth root
8851 // of the number of tetrahedra in the mesh. The next bit of code assumes
8852 // that the number of tetrahedra increases monotonically.
8853 while (SAMPLEFACTOR * samples * samples * samples * samples <
8854 tetrahedrons->items) {
8855 samples++;
8856 }
8857 // Find how much blocks in current tet pool.
8858 tetblocks = (tetrahedrons->maxitems + ELEPERBLOCK - 1) / ELEPERBLOCK;
8859 // Find the average samles per block. Each block at least have 1 sample.
8860 samplesperblock = 1 + (samples / tetblocks);
8861 sampleblocks = samples / samplesperblock;
8862 sampleblock = tetrahedrons->firstblock;
8863 for (i = 0; i < sampleblocks; i++) {
8864 alignptr = (unsigned long) (sampleblock + 1);
8865 firsttet = (tetrahedron *)
8866 (alignptr + (unsigned long) tetrahedrons->alignbytes
8867 - (alignptr % (unsigned long) tetrahedrons->alignbytes));
8868 for (j = 0; j < samplesperblock; j++) {
8869 if (i == tetblocks - 1) {
8870 // This is the last block.
8871 samplenum = randomnation((int)
8872 (tetrahedrons->maxitems - (i * ELEPERBLOCK)));
8873 } else {
8874 samplenum = randomnation(ELEPERBLOCK);
8875 }
8876 tetptr = (tetrahedron *)
8877 (firsttet + (samplenum * tetrahedrons->itemwords));
8878 if (tetptr[4] != (tetrahedron) NULL) {
8879 dist = distance2(tetptr, searchpt);
8880 if (dist < searchdist) {
8881 searchtet->tet = tetptr;
8882 searchdist = dist;
8883 }
8884 }
8885 }
8886 sampleblock = (void **) *sampleblock;
8887 }
8888
8889 // Call simple walk-through to locate the point.
8890 return preciselocate(searchpt, searchtet, tetrahedrons->items);
8891}
8892
8894// //
8895// adjustlocate() Adjust the precise location of a vertex. //
8896// //
8897// 'precise' is the value returned from preciselocate(). It indicates the //
8898// exact location of the point 'searchpt' with respect to the tetrahedron //
8899// 'searchtet'. 'epspp' is a given relative tolerance. //
8900// //
8901// This routine re-evaluates the orientations of searchpt with respect to //
8902// the four sides of searchtet. Detects the coplanarities by additinal tests //
8903// which are based on the given tolerance. If 'precise' is ONFACE or ONEDGE, //
8904// we can save one or two orientation tests. //
8905// //
8906// The return value indicates the location of the 'searchpt' (INTETRAHEDRON, //
8907// or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding //
8908// to that value. See the introduction part of preciselocate() for detail. //
8909// //
8910// WARNING: This routine detect degenerate case using relative tolerance. //
8911// It is better used after locate() or preciselocate(). For general inputs, //
8912// it may not able to tell the correct location. //
8913// //
8915
8916enum tetgenmesh::locateresult tetgenmesh::adjustlocate(point searchpt,
8917 triface* searchtet, enum locateresult precise, REAL epspp)
8918{
8919 point torg, tdest, tapex, toppo;
8920 REAL s1, s2, s3, s4;
8921
8922 // For the given 'searchtet', the orientations tests are:
8923 // s1: (tdest, torg, tapex, searchpt);
8924 // s2: (torg, tdest, toppo, searchpt);
8925 // s3: (tdest, tapex, toppo, searchpt);
8926 // s4: (tapex, torg, toppo, searchpt);
8927 adjustedgering(*searchtet, CCW);
8928 torg = org(*searchtet);
8929 tdest = dest(*searchtet);
8930 tapex = apex(*searchtet);
8931 toppo = oppo(*searchtet);
8932
8933 switch (precise) {
8934 case ONVERTEX:
8935 // This case we don't need do any further test.
8936 return ONVERTEX;
8937 case ONEDGE:
8938 // (torg, tdest);
8939 s1 = 0.0;
8940 s2 = 0.0;
8941 break;
8942 case ONFACE:
8943 // (tdest, torg, tapex);
8944 s1 = 0.0;
8945 s2 = orient3d(torg, tdest, toppo, searchpt);
8946 break;
8947 default: // INTETRAHEDRON or OUTSIDE
8948 s1 = orient3d(tdest, torg, tapex, searchpt);
8949 s2 = orient3d(torg, tdest, toppo, searchpt);
8950 }
8951
8952 if (s1 != 0.0) {
8953 if (iscoplanar(tdest, torg, tapex, searchpt, s1, epspp)) {
8954 s1 = 0.0;
8955 }
8956 }
8957 if (s1 < 0.0) {
8958 return OUTSIDE;
8959 }
8960
8961 if (s2 != 0.0) {
8962 if (iscoplanar(torg, tdest, toppo, searchpt, s2, epspp)) {
8963 s2 = 0.0;
8964 }
8965 }
8966 if (s2 < 0.0) {
8967 fnextself(*searchtet);
8968 return OUTSIDE;
8969 }
8970
8971 s3 = orient3d(tdest, tapex, toppo, searchpt);
8972 if (s3 != 0.0) {
8973 if (iscoplanar(tdest, tapex, toppo, searchpt, s3, epspp)) {
8974 s3 = 0.0;
8975 }
8976 }
8977 if (s3 < 0.0) {
8978 enextfnextself(*searchtet);
8979 return OUTSIDE;
8980 }
8981
8982 s4 = orient3d(tapex, torg, toppo, searchpt);
8983 if (s4 != 0.0) {
8984 if (iscoplanar(tapex, torg, toppo, searchpt, s4, epspp)) {
8985 s4 = 0.0;
8986 }
8987 }
8988 if (s4 < 0.0) {
8989 enext2fnextself(*searchtet);
8990 return OUTSIDE;
8991 }
8992
8993 // Determine degenerate cases.
8994 if (s1 == 0.0) {
8995 if (s2 == 0.0) {
8996 if (s3 == 0.0) {
8997 // On tdest.
8998 enextself(*searchtet);
8999 return ONVERTEX;
9000 }
9001 if (s4 == 0.0) {
9002 // On torg.
9003 return ONVERTEX;
9004 }
9005 // On edge (torg, tdest).
9006 return ONEDGE;
9007 }
9008 if (s3 == 0.0) {
9009 if (s4 == 0.0) {
9010 // On tapex.
9011 enext2self(*searchtet);
9012 return ONVERTEX;
9013 }
9014 // On edge (tdest, tapex).
9015 enextself(*searchtet);
9016 return ONEDGE;
9017 }
9018 if (s4 == 0.0) {
9019 // On edge (tapex, torg).
9020 enext2self(*searchtet);
9021 return ONEDGE;
9022 }
9023 // On face (torg, tdest, tapex).
9024 return ONFACE;
9025 }
9026 if (s2 == 0.0) {
9027 fnextself(*searchtet);
9028 if (s3 == 0.0) {
9029 if (s4 == 0.0) {
9030 // On toppo.
9031 enext2self(*searchtet);
9032 return ONVERTEX;
9033 }
9034 // On edge (tdest, toppo).
9035 enextself(*searchtet);
9036 return ONEDGE;
9037 }
9038 if (s4 == 0.0) {
9039 // On edge (toppo, torg).
9040 enext2self(*searchtet);
9041 return ONEDGE;
9042 }
9043 // On face (torg, tdest, toppo).
9044 return ONFACE;
9045 }
9046 if (s3 == 0.0) {
9047 enextfnextself(*searchtet);
9048 if (s4 == 0.0) {
9049 // On edge (tapex, toppo).
9050 enextself(*searchtet);
9051 return ONEDGE;
9052 }
9053 // On face (tdest, tapex, toppo).
9054 return ONFACE;
9055 }
9056 if (s4 == 0.0) {
9057 enext2fnextself(*searchtet);
9058 // On face (tapex, torg, toppo).
9059 return ONFACE;
9060 }
9061
9062 // Inside tetrahedron.
9063 return INTETRAHEDRON;
9064}
9065
9067// //
9068// hullwalk() Find a tetrahedron on the hull to continue search. //
9069// //
9071
9072enum tetgenmesh::locateresult tetgenmesh::hullwalk(point searchpt,
9073 triface *hulltet)
9074{
9075 list* travtetlist;
9076 triface travtet, neightet;
9077 point pa, pb, pc;
9078 enum locateresult loc;
9079 REAL ori;
9080 int i;
9081
9082 travtetlist = new list(sizeof(triface), NULL, 256);
9083 travtet = *hulltet;
9084 infect(travtet);
9085 travtetlist->append(&travtet);
9086
9087 loc = OUTSIDE;
9088 for (i = 0; i < travtetlist->len(); i++) {
9089 travtet = * (triface *)(* travtetlist)[i];
9090 // Choose the CCW-edgering in face.
9091 travtet.ver = 0;
9092 // Look for a side where pt lies below it.
9093 for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) {
9094 pa = org(travtet);
9095 pb = dest(travtet);
9096 pc = apex(travtet);
9097 ori = orient3d(pa, pb, pc, searchpt);
9098 if (ori > 0.0) break;
9099 }
9100 // Is pt above all (or coplanar with some of) the four sides?
9101 if (travtet.loc == 4) {
9102 hulltet->tet = travtet.tet;
9103 loc = adjustlocate(searchpt, hulltet, INTETRAHEDRON, b->epsilon);
9104 assert(loc != OUTSIDE);
9105 } else { // ori > 0.0
9106 // pt is below (behind) this side. We want to walk through it.
9107 sym(travtet, neightet);
9108 if (neightet.tet == dummytet) {
9109 // This is a hull side. Is p approximately on this side.
9110 loc = adjustlocate(searchpt, &travtet, OUTSIDE, b->epsilon);
9111 }
9112 if (loc == OUTSIDE) {
9113 // Let's collect all the neighbors for next searching.
9114 for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) {
9115 sym(travtet, neightet);
9116 if ((neightet.tet != dummytet) && !infected(neightet)) {
9117 // Neighbor exists and not visited.
9118 infect(neightet);
9119 travtetlist->append(&neightet);
9120 }
9121 } // for (travtet.loc = 0;
9122 } // if (loc == OUTSIDE)
9123 } // if (travtet.loc == 4)
9124 if (loc != OUTSIDE) break;
9125 } // for (i = 0; i < travtetlist->len(); i++)
9126
9127 // Uninfect traversed tets.
9128 for (i = 0; i < travtetlist->len(); i++) {
9129 travtet = * (triface *)(* travtetlist)[i];
9130 uninfect(travtet);
9131 }
9132
9133 delete travtetlist;
9134 return loc;
9135}
9136
9138// //
9139// locatesub() Find a point in the surface mesh of a facet. //
9140// //
9141// Searching begins from the input 'searchsh', it should be a handle on the //
9142// convex hull of the facet triangulation. //
9143// //
9144// If 'stopatseg' is nonzero, the search will stop if it tries to walk //
9145// through a subsegment, and will return OUTSIDE. //
9146// //
9147// On completion, 'searchsh' is a subface that contains 'searchpt'. //
9148// - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' //
9149// is a handle whose origin is the existing vertex. //
9150// - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a //
9151// handle whose primary edge is the edge on which the point lies. //
9152// - Returns ONFACE if the point lies strictly within a subface. //
9153// 'searchsh' is a handle on which the point lies. //
9154// - Returns OUTSIDE if the point lies outside the triangulation. //
9155// //
9156// WARNING: This routine is designed for convex triangulations, and will not //
9157// not generally work after the holes and concavities have been carved. //
9158// //
9160
9161enum tetgenmesh::locateresult tetgenmesh::locatesub(point searchpt,
9162 face* searchsh, int stopatseg, REAL epspp)
9163{
9164 face backtracksh, spinsh, checkedge;
9165 point forg, fdest, fapex;
9166 REAL orgori, destori;
9167 REAL ori, sign;
9168 int moveleft, i;
9169
9170 if (searchsh->sh == dummysh) {
9171 searchsh->shver = 0;
9172 spivotself(*searchsh);
9173#ifdef SELF_CHECK
9174 assert(searchsh->sh != dummysh);
9175#endif
9176 }
9177 // Find the sign to simulate that abovepoint is 'above' the facet.
9178 adjustedgering(*searchsh, CCW);
9179 forg = sorg(*searchsh);
9180 fdest = sdest(*searchsh);
9181 fapex = sapex(*searchsh);
9182 ori = orient3d(forg, fdest, fapex, abovepoint);
9183 sign = ori > 0.0 ? -1 : 1;
9184
9185 // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has
9186 // CCW orientation with respect to searchsh in plane). Such edge
9187 // should always exist. Save it as (forg, fdest).
9188 for (i = 0; i < 3; i++) {
9189 forg = sorg(*searchsh);
9190 fdest = sdest(*searchsh);
9191 ori = orient3d(forg, fdest, abovepoint, searchpt) * sign;
9192 if (ori > 0.0) break;
9193 senextself(*searchsh);
9194 }
9195#ifdef SELF_CHECK
9196 assert(i < 3);
9197#endif
9198
9199 while (1) {
9200 fapex = sapex(*searchsh);
9201 // Check whether the apex is the point we seek.
9202 if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] &&
9203 fapex[2] == searchpt[2]) {
9204 senext2self(*searchsh);
9205 return ONVERTEX;
9206 }
9207 // Does the point lie on the other side of the line defined by the
9208 // triangle edge opposite the triangle's destination?
9209 destori = orient3d(forg, fapex, abovepoint, searchpt) * sign;
9210 if (epspp > 0.0) {
9211 if (iscoplanar(forg, fapex, abovepoint, searchpt, destori, epspp)) {
9212 destori = 0.0;
9213 }
9214 }
9215 // Does the point lie on the other side of the line defined by the
9216 // triangle edge opposite the triangle's origin?
9217 orgori = orient3d(fapex, fdest, abovepoint, searchpt) * sign;
9218 if (epspp > 0.0) {
9219 if (iscoplanar(fapex, fdest, abovepoint, searchpt, orgori, epspp)) {
9220 orgori = 0.0;
9221 }
9222 }
9223 if (destori > 0.0) {
9224 moveleft = 1;
9225 } else {
9226 if (orgori > 0.0) {
9227 moveleft = 0;
9228 } else {
9229 // The point must be on the boundary of or inside this triangle.
9230 if (destori == 0.0) {
9231 senext2self(*searchsh);
9232 return ONEDGE;
9233 }
9234 if (orgori == 0.0) {
9235 senextself(*searchsh);
9236 return ONEDGE;
9237 }
9238 return ONFACE;
9239 }
9240 }
9241 // Move to another triangle. Leave a trace `backtracksh' in case
9242 // walking off a boundary of the triangulation.
9243 if (moveleft) {
9244 senext2(*searchsh, backtracksh);
9245 fdest = fapex;
9246 } else {
9247 senext(*searchsh, backtracksh);
9248 forg = fapex;
9249 }
9250 // Check if we meet a segment.
9251 sspivot(backtracksh, checkedge);
9252 if (checkedge.sh != dummysh) {
9253 if (stopatseg) {
9254 // The flag indicates we should not cross a segment. Stop.
9255 *searchsh = backtracksh;
9256 return OUTSIDE;
9257 }
9258 // Try to walk through a segment. We need to find a coplanar subface
9259 // sharing this segment to get into.
9260 spinsh = backtracksh;
9261 do {
9262 spivotself(spinsh);
9263 if (spinsh.sh == backtracksh.sh) {
9264 // Turn back, no coplanar subface is found.
9265 break;
9266 }
9267 // Are they belong to the same facet.
9268 if (shellmark(spinsh) == shellmark(backtracksh)) {
9269 // Find a coplanar subface. Walk into it.
9270 *searchsh = spinsh;
9271 break;
9272 }
9273 // Are they (nearly) coplanar?
9274 ori = orient3d(forg, fdest, sapex(backtracksh), sapex(spinsh));
9275 if (iscoplanar(forg, fdest, sapex(backtracksh), sapex(spinsh), ori,
9276 b->epsilon)) {
9277 // Find a coplanar subface. Walk into it.
9278 *searchsh = spinsh;
9279 break;
9280 }
9281 } while (spinsh.sh != backtracksh.sh);
9282 } else {
9283 spivot(backtracksh, *searchsh);
9284 }
9285 // Check for walking right out of the triangulation.
9286 if ((searchsh->sh == dummysh) || (searchsh->sh == backtracksh.sh)) {
9287 // Go back to the last triangle.
9288 *searchsh = backtracksh;
9289 return OUTSIDE;
9290 }
9291 // To keep the same orientation wrt abovepoint.
9292 if (sorg(*searchsh) != forg) sesymself(*searchsh);
9293#ifdef SELF_CHECK
9294 assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest));
9295#endif
9296 }
9297}
9298
9300// //
9301// adjustlocatesub() Adjust the precise location of a vertex. //
9302// //
9303// 'precise' is the precise location (returned from locatesub()) of 'searcht'//
9304// with respect to 'searchsh'. 'epspp' is the given relative tolerance. //
9305// //
9306// This routine re-evaluates the orientations of 'searchpt' with respect to //
9307// the three edges of 'searchsh'. Detects the collinearities by additinal //
9308// tests based on the given tolerance. If 'precise' is ONEDGE, one can save //
9309// one orientation test for the current edge of 'searchsh'. //
9310// //
9311// On completion, 'searchsh' is a subface contains 'searchpt'. The returned //
9312// value indicates one of the following cases: //
9313// - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' //
9314// is a handle whose origin is the existing vertex. //
9315// - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a //
9316// handle whose primary edge is the edge on which the point lies. //
9317// - Returns ONFACE if the point lies strictly within a subface. //
9318// 'searchsh' is a handle on which the point lies. //
9319// - Returns OUTSIDE if the point lies outside 'searchsh'. //
9320// //
9322
9323enum tetgenmesh::locateresult tetgenmesh::
9324adjustlocatesub(point searchpt, face* searchsh, enum locateresult precise,
9325 REAL epspp)
9326{
9327 point pa, pb, pc;
9328 bool s1, s2, s3;
9329
9330 pa = sorg(*searchsh);
9331 pb = sdest(*searchsh);
9332 pc = sapex(*searchsh);
9333
9334 if (precise == ONEDGE) {
9335 s1 = true;
9336 } else {
9337 s1 = iscollinear(pa, pb, searchpt, epspp);
9338 }
9339 s2 = iscollinear(pb, pc, searchpt, epspp);
9340 s3 = iscollinear(pc, pa, searchpt, epspp);
9341 if (s1) {
9342 if (s2) {
9343 // on vertex pb.
9344#ifdef SELF_CHECK
9345 assert(!s3);
9346#endif
9347 senextself(*searchsh);
9348 return ONVERTEX;
9349 } else if (s3) {
9350 // on vertex pa.
9351 return ONVERTEX;
9352 } else {
9353 // on edge pa->pb.
9354 return ONEDGE;
9355 }
9356 } else if (s2) {
9357 if (s3) {
9358 // on vertex pc.
9359 senext2self(*searchsh);
9360 return ONVERTEX;
9361 } else {
9362 // on edge pb->pc.
9363 senextself(*searchsh);
9364 return ONEDGE;
9365 }
9366 } else if (s3) {
9367 // on edge pc->pa.
9368 senext2self(*searchsh);
9369 return ONEDGE;
9370 } else {
9371 return precise;
9372 }
9373}
9374
9376// //
9377// locateseg() Find a point in subsegments. //
9378// //
9379// Searching begins from the input 'searchseg', it should be a subsegment of //
9380// the whole segment. //
9381// //
9382// On completion, 'searchseg' is a subsegment that contains 'searchpt'. //
9383// - Returns ONVERTEX if the point lies on an existing vertex. 'searchseg' //
9384// is a handle whose origin is the existing vertex. //
9385// - Returns ONEDGE if the point lies inside 'searchseg'. //
9386// - Returns OUTSIDE if the point lies outside the segment. //
9387// //
9389
9390enum tetgenmesh::locateresult tetgenmesh::
9391locateseg(point searchpt, face* searchseg)
9392{
9393 face backtraceseg;
9394 point pa, pb;
9395 REAL dx, dy, dz;
9396 int moveleft;
9397 int i;
9398
9399 moveleft = 0;
9400 while (1) {
9401 searchseg->shver = 0;
9402 pa = sorg(*searchseg);
9403 pb = sdest(*searchseg);
9404 // Find the biggest difference in x, y, and z coordinates of a and b.
9405 dx = fabs(pb[0] - pa[0]);
9406 dy = fabs(pb[1] - pa[1]);
9407 dz = fabs(pb[2] - pa[2]);
9408 if (dx > dy) {
9409 if (dx > dz) {
9410 i = 0;
9411 } else {
9412 i = 2;
9413 }
9414 } else {
9415 if (dy > dz) {
9416 i = 1;
9417 } else {
9418 i = 2;
9419 }
9420 }
9421 if (pa[i] < pb[i]) {
9422 if (searchpt[i] < pa[i]) {
9423 moveleft = 1;
9424 } else if (searchpt[i] > pa[i]) {
9425 if (searchpt[i] < pb[i]) {
9426 return ONEDGE;
9427 } else if (searchpt[i] > pb[i]) {
9428 moveleft = 0;
9429 } else {
9430#ifdef SELF_CHECK
9431 assert(searchpt[i] == pb[i]);
9432#endif
9433 sesymself(*searchseg);
9434 return ONVERTEX;
9435 }
9436 } else {
9437#ifdef SELF_CHECK
9438 assert(searchpt[i] == pa[i]);
9439#endif
9440 return ONVERTEX;
9441 }
9442 } else if (pa[i] > pb[i]) {
9443 if (searchpt[i] < pb[i]) {
9444 moveleft = 0;
9445 } else if (searchpt[i] > pb[i]) {
9446 if (searchpt[i] < pa[i]) {
9447 return ONEDGE;
9448 } else if (searchpt[i] > pa[i]) {
9449 moveleft = 1;
9450 } else {
9451#ifdef SELF_CHECK
9452 assert(searchpt[i] == pa[i]);
9453#endif
9454 return ONVERTEX;
9455 }
9456 } else {
9457#ifdef SELF_CHECK
9458 assert(searchpt[i] == pb[i]);
9459#endif
9460 sesymself(*searchseg);
9461 return ONVERTEX;
9462 }
9463 }
9464 backtraceseg = *searchseg;
9465 if (moveleft) {
9466 senext2self(*searchseg);
9467 } else {
9468 senextself(*searchseg);
9469 }
9470 spivotself(*searchseg);
9471 if (searchseg->sh == dummysh) {
9472 *searchseg = backtraceseg;
9473 break;
9474 }
9475 }
9476
9477 return OUTSIDE;
9478}
9479
9481// //
9482// adjustlocateseg() Adjust the precise location of a vertex on segment. //
9483// //
9484// 'searchpt' is either inside or ouside the segment 'searchseg'. It will be //
9485// adjusted to on vertex if it is very close to an endpoint of 'searchseg'. //
9486// 'epspp' is the given relative tolerance. //
9487// //
9489
9490enum tetgenmesh::locateresult tetgenmesh::
9491adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise,
9492 REAL epspp)
9493{
9494 point pa, pb;
9495 REAL L, d, r;
9496
9497 pa = sorg(*searchseg);
9498 pb = sdest(*searchseg);
9499 L = distance(pa, pb);
9500
9501 // Is searchpt approximate to pa?
9502 d = distance(pa, searchpt);
9503 r = d / L;
9504 if (r <= epspp) {
9505 return ONVERTEX;
9506 }
9507 // Is searchpt approximate to pb?
9508 d = distance(pb, searchpt);
9509 r = d / L;
9510 if (r <= epspp) {
9511 sesymself(*searchseg);
9512 return ONVERTEX;
9513 }
9514
9515 return precise;
9516}
9517
9518//
9519// End of point location routines
9520//
9521
9522//
9523// Begin of mesh transformation routines
9524//
9525
9527// //
9528// Flip operations //
9529// //
9530// If abc is a hull face, it is unflipable, and is locally Delaunay. In the //
9531// following, we assume abc is an interior face, and the other tetrahedron //
9532// adjoining at abc is bace. //
9533// //
9534// If the convex hull CH of the set {a, b, c, d, e} only has four vertices, //
9535// i.e., one vertex lies inside CH, then abc is unflipable, and is locally //
9536// Delaunay. If CH is the vertex set itself, we have the following cases to //
9537// determine whether abc is flipable or not. //
9538// //
9539// If no four points of {a, b, c, d, e} are coplanar, a 2-to-3 flip can be //
9540// applied to abc if the edge de crosses the triangle abc; a 3-to-2 flip can //
9541// be applied to abc if ab crosses cde, and abde exists, otherwise, face abc //
9542// is unflipable, i.e., the tetrahedron abde is not present. //
9543// //
9544// If four points of {a, b, c, d, e} are coplanar (two faces are coplanar). //
9545// Assume faces abd and abe are coplanar (it is impossible be abc). If a, b, //
9546// d, e form a non-convex quadrilateral, then abc is unflipable, furthermore,//
9547// it is locally Delaunay. Assume they are convex quadrilateral, if abd and //
9548// abe are hull faces, a 2-to-2 flip can be applied to abc; if abd and abe //
9549// are interior faces, assume two tetrahedra adjoining abd and abe at the //
9550// opposite sides are abdg and abef, respectively. If g = f, a 4-to-4 flip //
9551// can be applied to abc, otherwise, abc is unflipable. //
9552// //
9553// There are other cases which can cause abc unflipable. If abc is a subface,//
9554// a 2-to-3 flip is forbidden; if ab is a subsegment, flips 3-to-2, 2-to-2, //
9555// and 4-to-4 are forbidden. //
9556// //
9558
9560// //
9561// categorizeface() Determine the flip type of a given face. //
9562// //
9563// On input, 'horiz' represents the face abc we want to flip (imagine it is //
9564// parallel to the horizon). Let the tet above it be abcd. //
9565// //
9566// This routine determines the suitable type of flip operation for 'horiz'. //
9567// - Returns T23 if a 2-to-3 flip is applicable. 'horiz' is same as input. //
9568// - Returns T32 if a 3-to-2 flip is applicable. 'horiz' returns the edge //
9569// of abc which is the flipable. //
9570// - Returns T22 if a 2-to-2 or 4-to-4 flip is applicable. 'horiz' returns //
9571// the edge of abc which is flipable. //
9572// - Returns N32 indicates it is unflipable due to the absence of a tet. //
9573// 'horize' returns the unflipable edge. //
9574// - Returns N40 indicates it is unflipable and is locally Delaunay. //
9575// - Returns FORBIDDENFACE indicates abc is a subface. //
9576// - Returns FORBIDDENEDGE indicates the flipable edge of abc is a segment.//
9577// 'horize' returns the flipable edge. //
9578// //
9579// Given a face abc, with two adjoining tetrahedra abcd and bace. If abc is //
9580// flipable, i.e., T23, T32, T22 or T44, its flip type can be determined by //
9581// doing five orientation tests: two tests for determining that d, e lie on //
9582// the different sides of abc, three tests for determining if the edge de //
9583// intersects the face abc. However, if we use the neighbor information of //
9584// the mesh data structure, we can reduce the five orientation tests to at //
9585// most three tests, that is, the two tests for determining whether d and e //
9586// lie on the different sides of abc can be saved. //
9587// //
9589
9590enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
9591{
9592 triface symhoriz, casing;
9593 face checksh, checkseg;
9594 face cassh1, cassh2;
9595 point pa, pb, pc, pd, pe, pf, pg;
9596 point abdoppo, bcdoppo, cadoppo;
9597 REAL ori1, ori2, ori3;
9598 int adjtet;
9599
9600 sym(horiz, symhoriz);
9601 if (symhoriz.tet == dummytet) {
9602 // A hull face is unflipable and locally Delaunay.
9603 return N40;
9604 }
9605
9606 adjustedgering(horiz, CCW);
9607 findedge(&symhoriz, dest(horiz), org(horiz));
9608 pa = org(horiz);
9609 pb = dest(horiz);
9610 pc = apex(horiz);
9611 pd = oppo(horiz);
9612 pe = oppo(symhoriz);
9613
9614 // Find the number of adjacent tetrahedra of abc, which have d, e, and one
9615 // of corners of abc as their corners. This number can be 0, 1 and 2.
9616 abdoppo = bcdoppo = cadoppo = (point) NULL;
9617 adjtet = 0;
9618 fnext(horiz, casing); // at edge 'ab'.
9619 symself(casing);
9620 if (casing.tet != dummytet) {
9621 abdoppo = oppo(casing);
9622 if (abdoppo == pe) adjtet++;
9623 }
9624 enextfnext(horiz, casing); // at edge 'bc'.
9625 symself(casing);
9626 if (casing.tet != dummytet) {
9627 bcdoppo = oppo(casing);
9628 if (bcdoppo == pe) adjtet++;
9629 }
9630 enext2fnext(horiz, casing); // at edge 'ca'.
9631 symself(casing);
9632 if (casing.tet != dummytet) {
9633 cadoppo = oppo(casing);
9634 if (cadoppo == pe) adjtet++;
9635 }
9636
9637 if (adjtet == 0) {
9638 // No adjacent tetrahedron. Types T23, T22 and T44 are possible.
9639 ori1 = orient3d(pa, pb, pd, pe);
9640 if (checksubfaces && ori1 != 0.0) {
9641 // Check if abd and abe are both boundary faces?
9642 fnext(horiz, casing);
9643 tspivot(casing, cassh1);
9644 fnext(symhoriz, casing);
9645 tspivot(casing, cassh2);
9646 if ((cassh1.sh != dummysh) && (cassh2.sh != dummysh)) {
9647 // abd and abe are both boundary faces. Check if ab is a segment.
9648 findedge(&cassh1, pa, pb);
9649 sspivot(cassh1, checkseg);
9650 if (checkseg.sh == dummysh) {
9651 // ab is not a segment - abd and abe belong to the same facet.
9652 // The four points are forced to be coplanar.
9653 ori1 = 0.0;
9654 } else {
9655 // ab is a segment - abd and abe belong to two different facets.
9656 // In principle, a, b, c and d can form a tetrahedron (since
9657 // ori1 != 0.0). However, we should avoid to create a very
9658 // flat one which may form a sequence of extremely badly-shaped
9659 // or even wrong orientational tets. Test with a larger epsilon.
9660 if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
9661 }
9662 } else {
9663 // abd and abe are not both boundary faces. Check if abd and bae
9664 // are approximately coplanar with respect to the epsilon.
9665 if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon)) ori1 = 0.0;
9666 }
9667 }
9668 if (ori1 < 0.0) {
9669 // e lies above abd, unflipable, tet abde is not present.
9670#ifdef SELF_CHECK
9671 if (!nonconvex) {
9672 // abd and abe should not be hull faces, check it.
9673 fnext(horiz, casing);
9674 symself(casing);
9675 assert(casing.tet != dummytet);
9676 fnext(symhoriz, casing);
9677 symself(casing);
9678 assert(casing.tet != dummytet);
9679 }
9680#endif
9681 if (checksubfaces) {
9682 // The nonconvexbility may be casued by existing an subsegment.
9683 tsspivot(&horiz, &checkseg);
9684 if (checkseg.sh != dummysh) {
9685 return FORBIDDENEDGE;
9686 }
9687 }
9688 return N32;
9689 }
9690 ori2 = orient3d(pb, pc, pd, pe);
9691 if (checksubfaces && ori2 != 0.0) {
9692 // Check if bcd and cbe are both boundary faces.
9693 enextfnext(horiz, casing);
9694 tspivot(casing, cassh1);
9695 enext2fnext(symhoriz, casing);
9696 tspivot(casing, cassh2);
9697 if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9698 // bcd and cbe are both boundary faces. Check if bc is a segment.
9699 findedge(&cassh1, pb, pc);
9700 sspivot(cassh1, checkseg);
9701 if (checkseg.sh == dummysh) {
9702 // bc is not a segment - bcd and cbe belong to the same facet.
9703 // The four points are forced to be coplanar.
9704 ori2 = 0.0;
9705 } else {
9706 if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
9707 }
9708 } else {
9709 // bcd and cbe are not both boundary faces. Check if bcd and cbe
9710 // are approximately coplanar with respect to the epsilon.
9711 if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon)) ori2 = 0.0;
9712 }
9713 }
9714 if (ori2 < 0.0) {
9715 // e lies above bcd, unflipable, tet bcde is not present.
9716#ifdef SELF_CHECK
9717 if (!nonconvex) {
9718 // bcd and cbe should not be hull faces, check it.
9719 enextfnext(horiz, casing);
9720 symself(casing);
9721 assert(casing.tet != dummytet);
9722 enext2fnext(symhoriz, casing);
9723 symself(casing);
9724 assert(casing.tet != dummytet);
9725 }
9726#endif
9727 enextself(horiz);
9728 if (checksubfaces) {
9729 // The nonconvexbility may be casued by existing an subsegment.
9730 tsspivot(&horiz, &checkseg);
9731 if (checkseg.sh != dummysh) {
9732 return FORBIDDENEDGE;
9733 }
9734 }
9735 return N32;
9736 }
9737 ori3 = orient3d(pc, pa, pd, pe);
9738 if (checksubfaces && ori3 != 0.0) {
9739 // Check if cad and ace are both boundary faces.
9740 enext2fnext(horiz, casing);
9741 tspivot(casing, cassh1);
9742 enextfnext(symhoriz, casing);
9743 tspivot(casing, cassh2);
9744 if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9745 // cad and ace are both boundary faces. Check if ca is a segment.
9746 findedge(&cassh1, pc, pa);
9747 sspivot(cassh1, checkseg);
9748 if (checkseg.sh == dummysh) {
9749 // ca is not a segment - cad and ace belong to the same facet.
9750 // The four points are forced to be coplanar.
9751 ori3 = 0.0;
9752 } else {
9753 // ca is a segment - cad and ace belong to two different facets.
9754 // In principle, c, a, d and e can form a tetrahedron (since
9755 // ori3 != 0.0). Use a larger eps to test if they're coplanar.
9756 if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon * 1e+2)) ori3 = 0.0;
9757 }
9758 } else {
9759 // cad and ace are not both boundary faces. Check if cad and ace
9760 // are approximately coplanar with respect to the epsilon.
9761 if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon)) ori3 = 0.0;
9762 }
9763 }
9764 if (ori3 < 0.0) {
9765 // e lies above cad, unflipable, tet cade is not present.
9766#ifdef SELF_CHECK
9767 if (!nonconvex) {
9768 // cad and ace should not be hull faces, check it.
9769 enext2fnext(horiz, casing);
9770 symself(casing);
9771 assert(casing.tet != dummytet);
9772 enextfnext(symhoriz, casing);
9773 symself(casing);
9774 assert(casing.tet != dummytet);
9775 }
9776#endif
9777 enext2self(horiz);
9778 if (checksubfaces) {
9779 // The nonconvexbility may be casued by existing an subsegment.
9780 tsspivot(&horiz, &checkseg);
9781 if (checkseg.sh != dummysh) {
9782 return FORBIDDENEDGE;
9783 }
9784 }
9785 return N32;
9786 }
9787 if (ori1 == 0.0) {
9788 // e is coplanar with abd.
9789 if (ori2 * ori3 == 0.0) {
9790 // only one zero is possible.
9791 // assert(!(ori2 == 0.0 && ori3 == 0.0));
9792 // Three points (d, e, and a or b) are collinear, abc is unflipable
9793 // and locally Delaunay.
9794 return N40;
9795 }
9796 } else if (ori2 == 0.0) {
9797 // e is coplanar with bcd.
9798 if (ori1 * ori3 == 0.0) {
9799 // only one zero is possible.
9800 // assert(!(ori1 == 0.0 && ori3 == 0.0));
9801 // Three points (d, e, and b or c) are collinear, abc is unflipable
9802 // and locally Delaunay.
9803 return N40;
9804 }
9805 // Adjust 'horiz' and 'symhoriz' be the edge bc.
9806 enextself(horiz);
9807 enext2self(symhoriz);
9808 } else if (ori3 == 0.0) {
9809 // e is coplanar with cad.
9810 if (ori1 * ori2 == 0.0) {
9811 // only one zero is possible.
9812 // assert(!(ori1 == 0.0 && ori2 == 0.0));
9813 // Three points (d, e, and c or a) are collinear, abc is unflipable
9814 // and locally Delaunay.
9815 return N40;
9816 }
9817 // Adjust 'horiz' and 'symhoriz' be the edge ca.
9818 enext2self(horiz);
9819 enextself(symhoriz);
9820 } else {
9821 // e lies below all three faces, flipable.
9822 if (checksubfaces) {
9823 tspivot(horiz, checksh);
9824 if (checksh.sh != dummysh) {
9825 // To flip a subface is forbidden.
9826 return FORBIDDENFACE;
9827 }
9828 }
9829 return T23;
9830 }
9831 // Four points are coplanar, T22 or T44 is possible.
9832 if (checksubfaces) {
9833 tsspivot(&horiz, &checkseg);
9834 if (checkseg.sh != dummysh) {
9835 // To flip a subsegment is forbidden.
9836 return FORBIDDENEDGE;
9837 }
9838 tspivot(horiz, checksh);
9839 if (checksh.sh != dummysh) {
9840 // To flip a subface is forbidden.
9841 return FORBIDDENFACE;
9842 }
9843 }
9844 // Assume the four coplanar points are a, b, d, e, abd and abe are two
9845 // coplanar faces. If both abd and abe are hull faces, flipable(T22).
9846 // If they are interior faces, get the opposite tetrahedra abdf and
9847 // abeg, if f = g, flipable (T44). Otherwise, unflipable.
9848 pf = pg = (point) NULL;
9849 fnext(horiz, casing);
9850 symself(casing);
9851 if (casing.tet != dummytet) {
9852 pf = oppo(casing);
9853 }
9854 fnext(symhoriz, casing);
9855 symself(casing);
9856 if (casing.tet != dummytet) {
9857 pg = oppo(casing);
9858 }
9859 if (pf == pg) {
9860 // Either T22 (pf == pg == NULL) or T44 (pf and pg) is possible.
9861 if (checksubfaces) {
9862 // Retreat the corner points a, b, and c.
9863 pa = org(horiz);
9864 pb = dest(horiz);
9865 pc = apex(horiz);
9866 // Be careful not to create an inverted tetrahedron. Check the case.
9867 ori1 = orient3d(pc, pd, pe, pa);
9868 if (ori1 <= 0) return N40;
9869 ori1 = orient3d(pd, pc, pe, pb);
9870 if (ori1 <= 0) return N40;
9871 if (pf != (point) NULL) {
9872 ori1 = orient3d(pd, pf, pe, pa);
9873 if (ori1 <= 0) return N40;
9874 ori1 = orient3d(pf, pd, pe, pb);
9875 if (ori1 <= 0) return N40;
9876 }
9877 }
9878 if (pf == (point) NULL) {
9879 // abd and abe are hull faces, flipable.
9880 return T22;
9881 } else {
9882 // abd and abe are interior faces, flipable.
9883#ifdef SELF_CHECK
9884 assert(pf != (point) NULL);
9885#endif
9886 return T44;
9887 }
9888 } else {
9889 // ab has more than four faces around it, unflipable.
9890 return N32;
9891 }
9892 } else if (adjtet == 1) {
9893 // One of its three edges is locally non-convex. Type T32 is possible.
9894 // Adjust current configuration so that edge ab is non-convex.
9895 if (bcdoppo == pe) {
9896 // Edge bc is non-convex. Adjust 'horiz' and 'symhoriz' be edge bc.
9897 enextself(horiz);
9898 enext2self(symhoriz);
9899 pa = org(horiz);
9900 pb = dest(horiz);
9901 pc = apex(horiz);
9902 } else if (cadoppo == pe) {
9903 // Edge ca is non-convex. Adjust 'horiz' and 'symhoriz' be edge ca.
9904 enext2self(horiz);
9905 enextself(symhoriz);
9906 pa = org(horiz);
9907 pb = dest(horiz);
9908 pc = apex(horiz);
9909 } else {
9910 // Edge ab is non-convex.
9911#ifdef SELF_CHECK
9912 assert(abdoppo == pe);
9913#endif
9914 } // Now ab is the non-convex edge.
9915 // In order to be flipable, ab should cross face cde. Check it.
9916 ori1 = orient3d(pc, pd, pe, pa);
9917 if (checksubfaces && ori1 != 0.0) {
9918 // Check if cad and ace are both boundary faces.
9919 enext2fnext(horiz, casing);
9920 tspivot(casing, cassh1);
9921 enextfnext(symhoriz, casing);
9922 tspivot(casing, cassh2);
9923 if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9924 // cad and ace are both boundary faces. Check if ca is a segment.
9925 findedge(&cassh1, pc, pa);
9926 sspivot(cassh1, checkseg);
9927 if (checkseg.sh == dummysh) {
9928 // ca is not a segment. cad and ace belong to the same facet.
9929 // The four points are forced to be coplanar.
9930 ori1 = 0.0;
9931 } else {
9932 // ca is a segment. cad and ace belong to different facets.
9933 // In principle, c, d, e, and a can form a tetrahedron (since
9934 // ori1 != 0.0). However, we should avoid to create a very
9935 // flat tet. Use a larger epsilon to test if they're coplanar.
9936 if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
9937 }
9938 } else {
9939 // Check if c, d, e, and a are approximately coplanar.
9940 if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon)) ori1 = 0.0;
9941 }
9942 }
9943 if (ori1 <= 0.0) {
9944 // a lies above or is coplanar cde, abc is locally Delaunay.
9945 return N40;
9946 }
9947 ori2 = orient3d(pd, pc, pe, pb);
9948 if (checksubfaces && ori2 != 0.0) {
9949 // Check if bcd and cbe are both boundary faces.
9950 enextfnext(horiz, casing);
9951 tspivot(casing, cassh1);
9952 enext2fnext(symhoriz, casing);
9953 tspivot(casing, cassh2);
9954 if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9955 // bcd and cbe are both boundary faces. Check if bc is a segment.
9956 findedge(&cassh1, pb, pc);
9957 sspivot(cassh1, checkseg);
9958 if (checkseg.sh == dummysh) {
9959 // bc is not a segment. bcd and cbe belong to the same facet.
9960 // The four points are forced to be coplanar.
9961 ori2 = 0.0;
9962 } else {
9963 // bc is a segment. bcd and cbe belong to different facets.
9964 // In principle, d, c, e, and b can form a tetrahedron (since
9965 // ori2 != 0.0). However, we should avoid to create a very
9966 // flat tet. Use a larger epsilon to test if they're coplanar.
9967 if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
9968 }
9969 } else {
9970 // Check if d, c, e, and b are approximately coplanar.
9971 if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon)) ori2 = 0.0;
9972 }
9973 }
9974 if (ori2 <= 0.0) {
9975 // b lies above dce, unflipable, and abc is locally Delaunay.
9976 return N40;
9977 }
9978 // Edge ab crosses face cde properly.
9979 if (checksubfaces) {
9980 // If abc is subface, then ab must be a subsegment (because abde is
9981 // a tetrahedron and ab crosses cde properly).
9982 tsspivot(&horiz, &checkseg);
9983 if (checkseg.sh != dummysh) {
9984 // To flip a subsegment is forbidden.
9985 return FORBIDDENEDGE;
9986 }
9987 // Both abd and bae should not be subfaces (because they're not
9988 // coplanar and ab is not a subsegment). However, they may be
9989 // subfaces and belong to a facet (created during facet recovery),
9990 // that is, abde is an invalid tetrahedron. Find this case out.
9991 fnext(horiz, casing);
9992 tspivot(casing, cassh1);
9993 fnext(symhoriz, casing);
9994 tspivot(casing, cassh2);
9995 if (cassh1.sh != dummysh || cassh2.sh != dummysh) {
9996 if (!b->quiet) {
9997 // Unfortunately, they're subfaces. Corrections need be done here.
9998 printf("Warning: A tetrahedron spans two subfaces of a facet.\n");
9999 }
10000 // Temporarily, let it be there.
10001 return N32;
10002 }
10003 }
10004 return T32;
10005 } else {
10006 // The convex hull of {a, b, c, d, e} has only four vertices, abc is
10007 // unflipable, furthermore, it is locally Delaunay.
10008 return N40;
10009 }
10010}
10011
10013// //
10014// enqueueflipface(), enqueueflipedge() Queue a face (or an edge). //
10015// //
10016// The face (or edge) may be non-locally Delaunay. It is queued for process- //
10017// ing in flip() (or flipsub()). The vertices of the face (edge) are stored //
10018// seperatly to ensure the face (or edge) is still the same one when we save //
10019// it since other flips will cause this face (or edge) be changed or dead. //
10020// //
10022
10023void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue)
10024{
10025 badface *queface;
10026 triface symface;
10027
10028 sym(checkface, symface);
10029 if (symface.tet != dummytet) {
10030 queface = (badface *) flipqueue->push((void *) NULL);
10031 queface->tt = checkface;
10032 queface->foppo = oppo(symface);
10033 }
10034}
10035
10036void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue)
10037{
10038 badface *queface;
10039
10040 queface = (badface *) flipqueue->push((void *) NULL);
10041 queface->ss = checkedge;
10042 queface->forg = sorg(checkedge);
10043 queface->fdest = sdest(checkedge);
10044}
10045
10047// //
10048// flip23() Perform a 2-to-3 flip. //
10049// //
10050// On input, 'flipface' represents the face will be flipped. Let it is abc, //
10051// the two tetrahedra sharing abc are abcd, bace. abc is not a subface. //
10052// //
10053// A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra //
10054// edab, edbc, and edca. As a result, face abc has been removed and three //
10055// new faces eda, edb and edc have been created. //
10056// //
10057// On completion, 'flipface' returns edab. If 'flipqueue' is not NULL, all //
10058// possibly non-Delaunay faces are added into it. //
10059// //
10061
10062void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
10063{
10064 triface abcd, bace; // Old configuration.
10065 triface oldabd, oldbcd, oldcad;
10066 triface abdcasing, bcdcasing, cadcasing;
10067 triface oldbae, oldcbe, oldace;
10068 triface baecasing, cbecasing, acecasing;
10069 triface worktet;
10070 face abdsh, bcdsh, cadsh; // The six subfaces on the CH.
10071 face baesh, cbesh, acesh;
10072 face abseg, bcseg, caseg; // The nine segs on the CH.
10073 face adseg, bdseg, cdseg;
10074 face aeseg, beseg, ceseg;
10075 triface edab, edbc, edca; // New configuration.
10076 point pa, pb, pc, pd, pe;
10077 REAL attrib, volume;
10078 int i;
10079
10080 abcd = *flipface;
10081 adjustedgering(abcd, CCW); // abcd represents edge ab.
10082 pa = org(abcd);
10083 pb = dest(abcd);
10084 pc = apex(abcd);
10085 pd = oppo(abcd);
10086 // sym(abcd, bace);
10087 // findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba.
10088 sym(abcd, bace);
10089 bace.ver = 0; // CCW.
10090 for (i = 0; (i < 3) && (org(bace) != pb); i++) {
10091 enextself(bace);
10092 }
10093 pe = oppo(bace);
10094
10095 if (b->verbose > 2) {
10096 printf(" Do T23 on face (%d, %d, %d) %d, %d.\n", pointmark(pa),
10097 pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
10098 }
10099 flip23s++;
10100
10101 // Storing the old configuration outside the convex hull.
10102 fnext(abcd, oldabd);
10103 enextfnext(abcd, oldbcd);
10104 enext2fnext(abcd, oldcad);
10105 fnext(bace, oldbae);
10106 enext2fnext(bace, oldcbe);
10107 enextfnext(bace, oldace);
10108 sym(oldabd, abdcasing);
10109 sym(oldbcd, bcdcasing);
10110 sym(oldcad, cadcasing);
10111 sym(oldbae, baecasing);
10112 sym(oldcbe, cbecasing);
10113 sym(oldace, acecasing);
10114 if (checksubfaces) {
10115 tspivot(oldabd, abdsh);
10116 tspivot(oldbcd, bcdsh);
10117 tspivot(oldcad, cadsh);
10118 tspivot(oldbae, baesh);
10119 tspivot(oldcbe, cbesh);
10120 tspivot(oldace, acesh);
10121 } else if (checksubsegs) {
10122 tsspivot1(abcd, abseg);
10123 enext(abcd, worktet);
10124 tsspivot1(worktet, bcseg);
10125 enext2(abcd, worktet);
10126 tsspivot1(worktet, caseg);
10127 enext2(oldabd, worktet);
10128 tsspivot1(worktet, adseg);
10129 enext2(oldbcd, worktet);
10130 tsspivot1(worktet, bdseg);
10131 enext2(oldcad, worktet);
10132 tsspivot1(worktet, cdseg);
10133 enext(oldbae, worktet);
10134 tsspivot1(worktet, aeseg);
10135 enext(oldcbe, worktet);
10136 tsspivot1(worktet, beseg);
10137 enext(oldace, worktet);
10138 tsspivot1(worktet, ceseg);
10139 }
10140
10141 // Creating the new configuration inside the convex hull.
10142 edab.tet = abcd.tet; // Update abcd to be edab.
10143 setorg (edab, pe);
10144 setdest(edab, pd);
10145 setapex(edab, pa);
10146 setoppo(edab, pb);
10147 edbc.tet = bace.tet; // Update bace to be edbc.
10148 setorg (edbc, pe);
10149 setdest(edbc, pd);
10150 setapex(edbc, pb);
10151 setoppo(edbc, pc);
10152 maketetrahedron(&edca); // Create edca.
10153 setorg (edca, pe);
10154 setdest(edca, pd);
10155 setapex(edca, pc);
10156 setoppo(edca, pa);
10157 // Set the element attributes of the new tetrahedron 'edca'.
10158 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
10159 attrib = elemattribute(abcd.tet, i);
10160 setelemattribute(edca.tet, i, attrib);
10161 }
10162 // Set the volume constraint of the new tetrahedron 'edca' if the -ra
10163 // switches are not used together. In -ra case, the various volume
10164 // constraints can be spreaded very far.
10165 if (b->varvolume && !b->refine) {
10166 volume = volumebound(abcd.tet);
10167 setvolumebound(edca.tet, volume);
10168 }
10169
10170 // Clear old bonds in edab(was abcd) and edbc(was bace).
10171 for (i = 0; i < 4; i ++) {
10172 edab.tet[i] = (tetrahedron) dummytet;
10173 }
10174 for (i = 0; i < 4; i ++) {
10175 edbc.tet[i] = (tetrahedron) dummytet;
10176 }
10177 // Bond the faces inside the convex hull.
10178 edab.loc = 0;
10179 edca.loc = 1;
10180 bond(edab, edca);
10181 edab.loc = 1;
10182 edbc.loc = 0;
10183 bond(edab, edbc);
10184 edbc.loc = 1;
10185 edca.loc = 0;
10186 bond(edbc, edca);
10187 // Bond the faces on the convex hull.
10188 edab.loc = 2;
10189 bond(edab, abdcasing);
10190 edab.loc = 3;
10191 bond(edab, baecasing);
10192 edbc.loc = 2;
10193 bond(edbc, bcdcasing);
10194 edbc.loc = 3;
10195 bond(edbc, cbecasing);
10196 edca.loc = 2;
10197 bond(edca, cadcasing);
10198 edca.loc = 3;
10199 bond(edca, acecasing);
10200 // There may exist subfaces that need to be bonded to new configuarton.
10201 if (checksubfaces) {
10202 // Clear old flags in edab(was abcd) and edbc(was bace).
10203 for (i = 0; i < 4; i ++) {
10204 edab.loc = i;
10205 tsdissolve(edab);
10206 edbc.loc = i;
10207 tsdissolve(edbc);
10208 }
10209 if (abdsh.sh != dummysh) {
10210 edab.loc = 2;
10211 tsbond(edab, abdsh);
10212 }
10213 if (baesh.sh != dummysh) {
10214 edab.loc = 3;
10215 tsbond(edab, baesh);
10216 }
10217 if (bcdsh.sh != dummysh) {
10218 edbc.loc = 2;
10219 tsbond(edbc, bcdsh);
10220 }
10221 if (cbesh.sh != dummysh) {
10222 edbc.loc = 3;
10223 tsbond(edbc, cbesh);
10224 }
10225 if (cadsh.sh != dummysh) {
10226 edca.loc = 2;
10227 tsbond(edca, cadsh);
10228 }
10229 if (acesh.sh != dummysh) {
10230 edca.loc = 3;
10231 tsbond(edca, acesh);
10232 }
10233 } else if (checksubsegs) {
10234 for (i = 0; i < 6; i++) {
10235 edab.tet[8 + i] = (tetrahedron) dummysh;
10236 }
10237 for (i = 0; i < 6; i++) {
10238 edbc.tet[8 + i] = (tetrahedron) dummysh;
10239 }
10240 edab.loc = edab.ver = 0;
10241 edbc.loc = edab.ver = 0;
10242 edca.loc = edab.ver = 0;
10243 // Operate in tet edab (5 edges).
10244 enext(edab, worktet);
10245 tssbond1(worktet, adseg);
10246 enext2(edab, worktet);
10247 tssbond1(worktet, aeseg);
10248 fnext(edab, worktet);
10249 enextself(worktet);
10250 tssbond1(worktet, bdseg);
10251 enextself(worktet);
10252 tssbond1(worktet, beseg);
10253 enextfnext(edab, worktet);
10254 enextself(worktet);
10255 tssbond1(worktet, abseg);
10256 // Operate in tet edbc (5 edges)
10257 enext(edbc, worktet);
10258 tssbond1(worktet, bdseg);
10259 enext2(edbc, worktet);
10260 tssbond1(worktet, beseg);
10261 fnext(edbc, worktet);
10262 enextself(worktet);
10263 tssbond1(worktet, cdseg);
10264 enextself(worktet);
10265 tssbond1(worktet, ceseg);
10266 enextfnext(edbc, worktet);
10267 enextself(worktet);
10268 tssbond1(worktet, bcseg);
10269 // Operate in tet edca (5 edges)
10270 enext(edca, worktet);
10271 tssbond1(worktet, cdseg);
10272 enext2(edca, worktet);
10273 tssbond1(worktet, ceseg);
10274 fnext(edca, worktet);
10275 enextself(worktet);
10276 tssbond1(worktet, adseg);
10277 enextself(worktet);
10278 tssbond1(worktet, aeseg);
10279 enextfnext(edca, worktet);
10280 enextself(worktet);
10281 tssbond1(worktet, caseg);
10282 }
10283
10284 edab.loc = 0;
10285 edbc.loc = 0;
10286 edca.loc = 0;
10287 if (b->verbose > 3) {
10288 printf(" Updating edab ");
10289 printtet(&edab);
10290 printf(" Updating edbc ");
10291 printtet(&edbc);
10292 printf(" Creating edca ");
10293 printtet(&edca);
10294 }
10295
10296 if (flipqueue != (queue *) NULL) {
10297 enextfnext(edab, abdcasing);
10298 enqueueflipface(abdcasing, flipqueue);
10299 enext2fnext(edab, baecasing);
10300 enqueueflipface(baecasing, flipqueue);
10301 enextfnext(edbc, bcdcasing);
10302 enqueueflipface(bcdcasing, flipqueue);
10303 enext2fnext(edbc, cbecasing);
10304 enqueueflipface(cbecasing, flipqueue);
10305 enextfnext(edca, cadcasing);
10306 enqueueflipface(cadcasing, flipqueue);
10307 enext2fnext(edca, acecasing);
10308 enqueueflipface(acecasing, flipqueue);
10309 }
10310
10311 // Save a live handle in 'recenttet'.
10312 recenttet = edbc;
10313 // Set the return handle be edab.
10314 *flipface = edab;
10315}
10316
10318// //
10319// flip32() Perform a 3-to-2 flip. //
10320// //
10321// On input, 'flipface' represents the face will be flipped. Let it is eda, //
10322// where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,//
10323// edbc, and edca. ed is not a subsegment. //
10324// //
10325// A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into //
10326// another two tetrahedra abcd and bace. As a result, the edge ed has been //
10327// removed and the face abc has been created. //
10328// //
10329// On completion, 'flipface' returns abcd. If 'flipqueue' is not NULL, all //
10330// possibly non-Delaunay faces are added into it. //
10331// //
10333
10334void tetgenmesh::flip32(triface* flipface, queue* flipqueue)
10335{
10336 triface edab, edbc, edca; // Old configuration.
10337 triface oldabd, oldbcd, oldcad;
10338 triface abdcasing, bcdcasing, cadcasing;
10339 triface oldbae, oldcbe, oldace;
10340 triface baecasing, cbecasing, acecasing;
10341 triface worktet;
10342 face abdsh, bcdsh, cadsh;
10343 face baesh, cbesh, acesh;
10344 face abseg, bcseg, caseg; // The nine segs on the CH.
10345 face adseg, bdseg, cdseg;
10346 face aeseg, beseg, ceseg;
10347 triface abcd, bace; // New configuration.
10348 point pa, pb, pc, pd, pe;
10349 int i;
10350
10351 edab = *flipface;
10352 adjustedgering(edab, CCW);
10353 pa = apex(edab);
10354 pb = oppo(edab);
10355 pd = dest(edab);
10356 pe = org(edab);
10357 fnext(edab, edbc);
10358 symself(edbc);
10359 edbc.ver = 0;
10360 for (i = 0; (i < 3) && (org(edbc) != pe); i++) {
10361 enextself(edbc);
10362 }
10363 pc = oppo(edbc);
10364 fnext(edbc, edca);
10365 symself(edca);
10366 edca.ver = 0;
10367 for (i = 0; (i < 3) && (org(edca) != pe); i++) {
10368 enextself(edca);
10369 }
10370
10371 if (b->verbose > 2) {
10372 printf(" Do T32 on edge (%d, %d) %d, %d, %d.\n", pointmark(pe),
10373 pointmark(pd), pointmark(pa), pointmark(pb), pointmark(pc));
10374 }
10375 flip32s++;
10376
10377 // Storing the old configuration outside the convex hull.
10378 enextfnext(edab, oldabd);
10379 enext2fnext(edab, oldbae);
10380 enextfnext(edbc, oldbcd);
10381 enext2fnext(edbc, oldcbe);
10382 enextfnext(edca, oldcad);
10383 enext2fnext(edca, oldace);
10384 sym(oldabd, abdcasing);
10385 sym(oldbcd, bcdcasing);
10386 sym(oldcad, cadcasing);
10387 sym(oldbae, baecasing);
10388 sym(oldcbe, cbecasing);
10389 sym(oldace, acecasing);
10390 if (checksubfaces) {
10391 tspivot(oldabd, abdsh);
10392 tspivot(oldbcd, bcdsh);
10393 tspivot(oldcad, cadsh);
10394 tspivot(oldbae, baesh);
10395 tspivot(oldcbe, cbesh);
10396 tspivot(oldace, acesh);
10397 } else if (checksubsegs) {
10398 enext(edab, worktet);
10399 tsspivot1(worktet, adseg);
10400 enext2(edab, worktet);
10401 tsspivot1(worktet, aeseg);
10402 enext(edbc, worktet);
10403 tsspivot1(worktet, bdseg);
10404 enext2(edbc, worktet);
10405 tsspivot1(worktet, beseg);
10406 enext(edca, worktet);
10407 tsspivot1(worktet, cdseg);
10408 enext2(edca, worktet);
10409 tsspivot1(worktet, ceseg);
10410 enextfnext(edab, worktet);
10411 enextself(worktet);
10412 tsspivot1(worktet, abseg);
10413 enextfnext(edbc, worktet);
10414 enextself(worktet);
10415 tsspivot1(worktet, bcseg);
10416 enextfnext(edca, worktet);
10417 enextself(worktet);
10418 tsspivot1(worktet, caseg);
10419 }
10420
10421 // Creating the new configuration inside the convex hull.
10422 abcd.tet = edab.tet; // Update edab to be abcd.
10423 setorg (abcd, pa);
10424 setdest(abcd, pb);
10425 setapex(abcd, pc);
10426 setoppo(abcd, pd);
10427 bace.tet = edbc.tet; // Update edbc to be bace.
10428 setorg (bace, pb);
10429 setdest(bace, pa);
10430 setapex(bace, pc);
10431 setoppo(bace, pe);
10432 // Dealloc a redundant tetrahedron (edca).
10433 tetrahedrondealloc(edca.tet);
10434
10435 // Clear the old bonds in abcd (was edab) and bace (was edbc).
10436 for (i = 0; i < 4; i ++) {
10437 abcd.tet[i] = (tetrahedron) dummytet;
10438 }
10439 for (i = 0; i < 4; i ++) {
10440 bace.tet[i] = (tetrahedron) dummytet;
10441 }
10442 // Bond the inside face of the convex hull.
10443 abcd.loc = 0;
10444 bace.loc = 0;
10445 bond(abcd, bace);
10446 // Bond the outside faces of the convex hull.
10447 abcd.loc = 1;
10448 bond(abcd, abdcasing);
10449 abcd.loc = 2;
10450 bond(abcd, bcdcasing);
10451 abcd.loc = 3;
10452 bond(abcd, cadcasing);
10453 bace.loc = 1;
10454 bond(bace, baecasing);
10455 bace.loc = 3;
10456 bond(bace, cbecasing);
10457 bace.loc = 2;
10458 bond(bace, acecasing);
10459 if (checksubfaces) {
10460 // Clear old bonds in abcd(was edab) and bace(was edbc).
10461 for (i = 0; i < 4; i ++) {
10462 abcd.tet[8 + i] = (tetrahedron) dummysh;
10463 }
10464 for (i = 0; i < 4; i ++) {
10465 bace.tet[8 + i] = (tetrahedron) dummysh;
10466 }
10467 if (abdsh.sh != dummysh) {
10468 abcd.loc = 1;
10469 tsbond(abcd, abdsh);
10470 }
10471 if (bcdsh.sh != dummysh) {
10472 abcd.loc = 2;
10473 tsbond(abcd, bcdsh);
10474 }
10475 if (cadsh.sh != dummysh) {
10476 abcd.loc = 3;
10477 tsbond(abcd, cadsh);
10478 }
10479 if (baesh.sh != dummysh) {
10480 bace.loc = 1;
10481 tsbond(bace, baesh);
10482 }
10483 if (cbesh.sh != dummysh) {
10484 bace.loc = 3;
10485 tsbond(bace, cbesh);
10486 }
10487 if (acesh.sh != dummysh) {
10488 bace.loc = 2;
10489 tsbond(bace, acesh);
10490 }
10491 } else if (checksubsegs) {
10492 for (i = 0; i < 6; i++) {
10493 abcd.tet[8 + i] = (tetrahedron) dummysh;
10494 }
10495 for (i = 0; i < 6; i++) {
10496 bace.tet[8 + i] = (tetrahedron) dummysh;
10497 }
10498 abcd.loc = abcd.ver = 0;
10499 bace.loc = bace.ver = 0;
10500 tssbond1(abcd, abseg); // 1
10501 enext(abcd, worktet);
10502 tssbond1(worktet, bcseg); // 2
10503 enext2(abcd, worktet);
10504 tssbond1(worktet, caseg); // 3
10505 fnext(abcd, worktet);
10506 enext2self(worktet);
10507 tssbond1(worktet, adseg); // 4
10508 enextfnext(abcd, worktet);
10509 enext2self(worktet);
10510 tssbond1(worktet, bdseg); // 5
10511 enext2fnext(abcd, worktet);
10512 enext2self(worktet);
10513 tssbond1(worktet, cdseg); // 6
10514 tssbond1(bace, abseg);
10515 enext2(bace, worktet);
10516 tssbond1(worktet, bcseg);
10517 enext(bace, worktet);
10518 tssbond1(worktet, caseg);
10519 fnext(bace, worktet);
10520 enextself(worktet);
10521 tssbond1(worktet, aeseg); // 7
10522 enext2fnext(bace, worktet);
10523 enextself(worktet);
10524 tssbond1(worktet, beseg); // 8
10525 enextfnext(bace, worktet);
10526 enextself(worktet);
10527 tssbond1(worktet, ceseg); // 9
10528 }
10529
10530 abcd.loc = 0;
10531 bace.loc = 0;
10532 if (b->verbose > 3) {
10533 printf(" Updating abcd ");
10534 printtet(&abcd);
10535 printf(" Updating bace ");
10536 printtet(&bace);
10537 printf(" Deleting edca ");
10538 // printtet(&edca);
10539 }
10540
10541 if (flipqueue != (queue *) NULL) {
10542 fnext(abcd, abdcasing);
10543 enqueueflipface(abdcasing, flipqueue);
10544 fnext(bace, baecasing);
10545 enqueueflipface(baecasing, flipqueue);
10546 enextfnext(abcd, bcdcasing);
10547 enqueueflipface(bcdcasing, flipqueue);
10548 enextfnext(bace, cbecasing);
10549 enqueueflipface(cbecasing, flipqueue);
10550 enext2fnext(abcd, cadcasing);
10551 enqueueflipface(cadcasing, flipqueue);
10552 enext2fnext(bace, acecasing);
10553 enqueueflipface(acecasing, flipqueue);
10554 }
10555
10556 // Save a live handle in 'recenttet'.
10557 recenttet = abcd;
10558 // Set the return handle be abcd.
10559 *flipface = abcd;
10560}
10561
10563// //
10564// flip22() Perform a 2-to-2 (or 4-to-4) flip. //
10565// //
10566// On input, 'flipface' represents the face will be flipped. Let it is abe, //
10567// ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,//
10568// hence a, b, c and d are coplanar. If abc, bad are interior faces, the two //
10569// tetrahedra opposite to e are bacf and abdf. ab is not a subsegment. //
10570// //
10571// A 2-to-2 flip is to change two tetrahedra abce and bade into another two //
10572// tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf //
10573// and dcbf, thus a 4-to-4 flip. As a result, two or four tetrahedra have //
10574// rotated counterclockwise (using right-hand rule with thumb points to e): //
10575// abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf. //
10576// //
10577// If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by //
10578// calling routine flip22sub(), hence abc->dca, bad->cdb. The edge rings of //
10579// the flipped subfaces dca and cdb have the same orientation as abc and bad.//
10580// Hence, they have the same orientation as other subfaces of the facet with //
10581// respect to the lift point of this facet. //
10582// //
10583// On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue' //
10584// contains all possibly non-Delaunay faces if it is not NULL. //
10585// //
10587
10588void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
10589{
10590 triface abce, bade;
10591 triface oldbce, oldcae, oldade, olddbe;
10592 triface bcecasing, caecasing, adecasing, dbecasing;
10593 face bcesh, caesh, adesh, dbesh;
10594 triface bacf, abdf;
10595 triface oldacf, oldcbf, oldbdf, olddaf;
10596 triface acfcasing, cbfcasing, bdfcasing, dafcasing;
10597 triface worktet;
10598 face acfsh, cbfsh, bdfsh, dafsh;
10599 face abc, bad;
10600 face adseg, dbseg, bcseg, caseg; // Coplanar segs.
10601 face aeseg, deseg, beseg, ceseg; // Above segs.
10602 face afseg, dfseg, bfseg, cfseg; // Below segs.
10603 point pa, pb, pc, pd;
10604#ifdef SELF_CHECK
10605 point pe, pf;
10606#endif
10607 int mirrorflag, i;
10608
10609 adjustedgering(*flipface, CCW); // 'flipface' is bae.
10610 fnext(*flipface, abce);
10611 esymself(abce);
10612 adjustedgering(*flipface, CW); // 'flipface' is abe.
10613 fnext(*flipface, bade);
10614#ifdef SELF_CHECK
10615 assert(bade.tet != dummytet);
10616#endif
10617 esymself(bade);
10618 pa = org(abce);
10619 pb = dest(abce);
10620 pc = apex(abce);
10621 pd = apex(bade);
10622#ifdef SELF_CHECK
10623 pe = oppo(bade);
10624 assert(oppo(abce) == pe);
10625#endif
10626 sym(abce, bacf);
10627 mirrorflag = bacf.tet != dummytet;
10628 if (mirrorflag) {
10629 // findedge(&bacf, pb, pa);
10630 bacf.ver = 0;
10631 for (i = 0; (i < 3) && (org(bacf) != pb); i++) {
10632 enextself(bacf);
10633 }
10634 sym(bade, abdf);
10635#ifdef SELF_CHECK
10636 assert(abdf.tet != dummytet);
10637#endif
10638 // findedge(&abdf, pa, pb);
10639 abdf.ver = 0;
10640 for (i = 0; (i < 3) && (org(abdf) != pa); i++) {
10641 enextself(abdf);
10642 }
10643
10644#ifdef SELF_CHECK
10645 pf = oppo(bacf);
10646 assert(oppo(abdf) == pf);
10647#endif
10648 }
10649
10650 if (b->verbose > 2) {
10651 printf(" Do %s on edge (%d, %d).\n", mirrorflag ? "T44" : "T22",
10652 pointmark(pa), pointmark(pb));
10653 }
10654 mirrorflag ? flip44s++ : flip22s++;
10655
10656 // Save the old configuration at the convex hull.
10657 enextfnext(abce, oldbce);
10658 enext2fnext(abce, oldcae);
10659 enextfnext(bade, oldade);
10660 enext2fnext(bade, olddbe);
10661 sym(oldbce, bcecasing);
10662 sym(oldcae, caecasing);
10663 sym(oldade, adecasing);
10664 sym(olddbe, dbecasing);
10665 if (checksubfaces) {
10666 tspivot(oldbce, bcesh);
10667 tspivot(oldcae, caesh);
10668 tspivot(oldade, adesh);
10669 tspivot(olddbe, dbesh);
10670 tspivot(abce, abc);
10671 tspivot(bade, bad);
10672 } else if (checksubsegs) {
10673 // Coplanar segs: a->d->b->c.
10674 enext(bade, worktet);
10675 tsspivot1(worktet, adseg);
10676 enext2(bade, worktet);
10677 tsspivot1(worktet, dbseg);
10678 enext(abce, worktet);
10679 tsspivot1(worktet, bcseg);
10680 enext2(abce, worktet);
10681 tsspivot1(worktet, caseg);
10682 // Above segs: a->e, d->e, b->e, c->e.
10683 fnext(bade, worktet);
10684 enextself(worktet);
10685 tsspivot1(worktet, aeseg);
10686 enextfnext(bade, worktet);
10687 enextself(worktet);
10688 tsspivot1(worktet, deseg);
10689 enext2fnext(bade, worktet);
10690 enextself(worktet);
10691 tsspivot1(worktet, beseg);
10692 enextfnext(abce, worktet);
10693 enextself(worktet);
10694 tsspivot1(worktet, ceseg);
10695 }
10696 if (mirrorflag) {
10697 enextfnext(bacf, oldacf);
10698 enext2fnext(bacf, oldcbf);
10699 enextfnext(abdf, oldbdf);
10700 enext2fnext(abdf, olddaf);
10701 sym(oldacf, acfcasing);
10702 sym(oldcbf, cbfcasing);
10703 sym(oldbdf, bdfcasing);
10704 sym(olddaf, dafcasing);
10705 if (checksubfaces) {
10706 tspivot(oldacf, acfsh);
10707 tspivot(oldcbf, cbfsh);
10708 tspivot(oldbdf, bdfsh);
10709 tspivot(olddaf, dafsh);
10710 } else if (checksubsegs) {
10711 // Below segs: a->f, d->f, b->f, c->f.
10712 fnext(abdf, worktet);
10713 enext2self(worktet);
10714 tsspivot1(worktet, afseg);
10715 enext2fnext(abdf, worktet);
10716 enext2self(worktet);
10717 tsspivot1(worktet, dfseg);
10718 enextfnext(abdf, worktet);
10719 enext2self(worktet);
10720 tsspivot1(worktet, bfseg);
10721 enextfnext(bacf, worktet);
10722 enextself(worktet);
10723 tsspivot1(worktet, cfseg);
10724 }
10725 }
10726
10727 // Rotate abce, bade one-quarter turn counterclockwise.
10728 bond(oldbce, caecasing);
10729 bond(oldcae, adecasing);
10730 bond(oldade, dbecasing);
10731 bond(olddbe, bcecasing);
10732 if (checksubfaces) {
10733 // Check for subfaces and rebond them to the rotated tets.
10734 if (caesh.sh == dummysh) {
10735 tsdissolve(oldbce);
10736 } else {
10737 tsbond(oldbce, caesh);
10738 }
10739 if (adesh.sh == dummysh) {
10740 tsdissolve(oldcae);
10741 } else {
10742 tsbond(oldcae, adesh);
10743 }
10744 if (dbesh.sh == dummysh) {
10745 tsdissolve(oldade);
10746 } else {
10747 tsbond(oldade, dbesh);
10748 }
10749 if (bcesh.sh == dummysh) {
10750 tsdissolve(olddbe);
10751 } else {
10752 tsbond(olddbe, bcesh);
10753 }
10754 } else if (checksubsegs) {
10755 // 5 edges in abce are changed.
10756 enext(abce, worktet); // fit b->c into c->a.
10757 if (caseg.sh == dummysh) {
10758 tssdissolve1(worktet);
10759 } else {
10760 tssbond1(worktet, caseg);
10761 }
10762 enext2(abce, worktet); // fit c->a into a->d.
10763 if (adseg.sh == dummysh) {
10764 tssdissolve1(worktet);
10765 } else {
10766 tssbond1(worktet, adseg);
10767 }
10768 fnext(abce, worktet); // fit b->e into c->e.
10769 enextself(worktet);
10770 if (ceseg.sh == dummysh) {
10771 tssdissolve1(worktet);
10772 } else {
10773 tssbond1(worktet, ceseg);
10774 }
10775 enextfnext(abce, worktet); // fit c->e into a->e.
10776 enextself(worktet);
10777 if (aeseg.sh == dummysh) {
10778 tssdissolve1(worktet);
10779 } else {
10780 tssbond1(worktet, aeseg);
10781 }
10782 enext2fnext(abce, worktet); // fit a->e into d->e.
10783 enextself(worktet);
10784 if (deseg.sh == dummysh) {
10785 tssdissolve1(worktet);
10786 } else {
10787 tssbond1(worktet, deseg);
10788 }
10789 // 5 edges in bade are changed.
10790 enext(bade, worktet); // fit a->d into d->b.
10791 if (dbseg.sh == dummysh) {
10792 tssdissolve1(worktet);
10793 } else {
10794 tssbond1(worktet, dbseg);
10795 }
10796 enext2(bade, worktet); // fit d->b into b->c.
10797 if (bcseg.sh == dummysh) {
10798 tssdissolve1(worktet);
10799 } else {
10800 tssbond1(worktet, bcseg);
10801 }
10802 fnext(bade, worktet); // fit a->e into d->e.
10803 enextself(worktet);
10804 if (deseg.sh == dummysh) {
10805 tssdissolve1(worktet);
10806 } else {
10807 tssbond1(worktet, deseg);
10808 }
10809 enextfnext(bade, worktet); // fit d->e into b->e.
10810 enextself(worktet);
10811 if (beseg.sh == dummysh) {
10812 tssdissolve1(worktet);
10813 } else {
10814 tssbond1(worktet, beseg);
10815 }
10816 enext2fnext(bade, worktet); // fit b->e into c->e.
10817 enextself(worktet);
10818 if (ceseg.sh == dummysh) {
10819 tssdissolve1(worktet);
10820 } else {
10821 tssbond1(worktet, ceseg);
10822 }
10823 }
10824 if (mirrorflag) {
10825 // Rotate bacf, abdf one-quarter turn counterclockwise.
10826 bond(oldcbf, acfcasing);
10827 bond(oldacf, dafcasing);
10828 bond(olddaf, bdfcasing);
10829 bond(oldbdf, cbfcasing);
10830 if (checksubfaces) {
10831 // Check for subfaces and rebond them to the rotated tets.
10832 if (acfsh.sh == dummysh) {
10833 tsdissolve(oldcbf);
10834 } else {
10835 tsbond(oldcbf, acfsh);
10836 }
10837 if (dafsh.sh == dummysh) {
10838 tsdissolve(oldacf);
10839 } else {
10840 tsbond(oldacf, dafsh);
10841 }
10842 if (bdfsh.sh == dummysh) {
10843 tsdissolve(olddaf);
10844 } else {
10845 tsbond(olddaf, bdfsh);
10846 }
10847 if (cbfsh.sh == dummysh) {
10848 tsdissolve(oldbdf);
10849 } else {
10850 tsbond(oldbdf, cbfsh);
10851 }
10852 } else if (checksubsegs) {
10853 // 5 edges in bacf are changed.
10854 enext2(bacf, worktet); // fit b->c into c->a.
10855 if (caseg.sh == dummysh) {
10856 tssdissolve1(worktet);
10857 } else {
10858 tssbond1(worktet, caseg);
10859 }
10860 enext(bacf, worktet); // fit c->a into a->d.
10861 if (adseg.sh == dummysh) {
10862 tssdissolve1(worktet);
10863 } else {
10864 tssbond1(worktet, adseg);
10865 }
10866 fnext(bacf, worktet); // fit b->f into c->f.
10867 enext2self(worktet);
10868 if (cfseg.sh == dummysh) {
10869 tssdissolve1(worktet);
10870 } else {
10871 tssbond1(worktet, cfseg);
10872 }
10873 enext2fnext(bacf, worktet); // fit c->f into a->f.
10874 enext2self(worktet);
10875 if (afseg.sh == dummysh) {
10876 tssdissolve1(worktet);
10877 } else {
10878 tssbond1(worktet, afseg);
10879 }
10880 enextfnext(bacf, worktet); // fit a->f into d->f.
10881 enext2self(worktet);
10882 if (dfseg.sh == dummysh) {
10883 tssdissolve1(worktet);
10884 } else {
10885 tssbond1(worktet, dfseg);
10886 }
10887 // 5 edges in abdf are changed.
10888 enext2(abdf, worktet); // fit a->d into d->b.
10889 if (dbseg.sh == dummysh) {
10890 tssdissolve1(worktet);
10891 } else {
10892 tssbond1(worktet, dbseg);
10893 }
10894 enext(abdf, worktet); // fit d->b into b->c.
10895 if (bcseg.sh == dummysh) {
10896 tssdissolve1(worktet);
10897 } else {
10898 tssbond1(worktet, bcseg);
10899 }
10900 fnext(abdf, worktet); // fit a->f into d->f.
10901 enext2self(worktet);
10902 if (dfseg.sh == dummysh) {
10903 tssdissolve1(worktet);
10904 } else {
10905 tssbond1(worktet, dfseg);
10906 }
10907 enext2fnext(abdf, worktet); // fit d->f into b->f.
10908 enext2self(worktet);
10909 if (bfseg.sh == dummysh) {
10910 tssdissolve1(worktet);
10911 } else {
10912 tssbond1(worktet, bfseg);
10913 }
10914 enextfnext(abdf, worktet); // fit b->f into c->f.
10915 enext2self(worktet);
10916 if (cfseg.sh == dummysh) {
10917 tssdissolve1(worktet);
10918 } else {
10919 tssbond1(worktet, cfseg);
10920 }
10921 }
10922 }
10923
10924 // New vertex assignments for the rotated tetrahedra.
10925 setorg(abce, pd); // Update abce to dcae
10926 setdest(abce, pc);
10927 setapex(abce, pa);
10928 setorg(bade, pc); // Update bade to cdbe
10929 setdest(bade, pd);
10930 setapex(bade, pb);
10931 if (mirrorflag) {
10932 setorg(bacf, pc); // Update bacf to cdaf
10933 setdest(bacf, pd);
10934 setapex(bacf, pa);
10935 setorg(abdf, pd); // Update abdf to dcbf
10936 setdest(abdf, pc);
10937 setapex(abdf, pb);
10938 }
10939
10940 // Are there subfaces need to be flipped?
10941 if (checksubfaces && abc.sh != dummysh) {
10942#ifdef SELF_CHECK
10943 assert(bad.sh != dummysh);
10944#endif
10945 // Adjust the edge be ab, so the rotation of subfaces is according with
10946 // the rotation of tetrahedra.
10947 findedge(&abc, pa, pb);
10948 // Flip an edge of two subfaces, ignore non-Delaunay edges.
10949 flip22sub(&abc, NULL);
10950 }
10951
10952 if (b->verbose > 3) {
10953 printf(" Updating abce ");
10954 printtet(&abce);
10955 printf(" Updating bade ");
10956 printtet(&bade);
10957 if (mirrorflag) {
10958 printf(" Updating bacf ");
10959 printtet(&bacf);
10960 printf(" Updating abdf ");
10961 printtet(&abdf);
10962 }
10963 }
10964
10965 if (flipqueue != (queue *) NULL) {
10966 enextfnext(abce, bcecasing);
10967 enqueueflipface(bcecasing, flipqueue);
10968 enext2fnext(abce, caecasing);
10969 enqueueflipface(caecasing, flipqueue);
10970 enextfnext(bade, adecasing);
10971 enqueueflipface(adecasing, flipqueue);
10972 enext2fnext(bade, dbecasing);
10973 enqueueflipface(dbecasing, flipqueue);
10974 if (mirrorflag) {
10975 enextfnext(bacf, acfcasing);
10976 enqueueflipface(acfcasing, flipqueue);
10977 enext2fnext(bacf, cbfcasing);
10978 enqueueflipface(cbfcasing, flipqueue);
10979 enextfnext(abdf, bdfcasing);
10980 enqueueflipface(bdfcasing, flipqueue);
10981 enext2fnext(abdf, dafcasing);
10982 enqueueflipface(dafcasing, flipqueue);
10983 }
10984 // The two new faces dcae (abce), cdbe (bade) may still not be locally
10985 // Delaunay, and may need be flipped (flip23). On the other hand, in
10986 // conforming Delaunay algorithm, two new subfaces dca (abc), and cdb
10987 // (bad) may be non-conforming Delaunay, they need be queued if they
10988 // are locally Delaunay but non-conforming Delaunay.
10989 enqueueflipface(abce, flipqueue);
10990 enqueueflipface(bade, flipqueue);
10991 }
10992
10993 // Save a live handle in 'recenttet'.
10994 recenttet = abce;
10995}
10996
10998// //
10999// flip22sub() Perform a 2-to-2 flip on a subface edge. //
11000// //
11001// The flip edge is given by subface 'flipedge'. Let it is abc, where ab is //
11002// the flipping edge. The other subface is bad, where a, b, c, d form a //
11003// convex quadrilateral. ab is not a subsegment. //
11004// //
11005// A 2-to-2 subface flip is to change two subfaces abc and bad to another //
11006// two subfaces dca and cdb. Hence, edge ab has been removed and dc becomes //
11007// an edge. If a point e is above abc, this flip is equal to rotate abc and //
11008// bad counterclockwise using right-hand rule with thumb points to e. It is //
11009// important to know that the edge rings of the flipped subfaces dca and cdb //
11010// are keeping the same orientation as their original subfaces. So they have //
11011// the same orientation with respect to the lift point of this facet. //
11012// //
11013// During rotating, the face rings of the four edges bc, ca, ad, and de need //
11014// be re-connected. If the edge is not a subsegment, then its face ring has //
11015// only two faces, a sbond() will bond them together. If it is a subsegment, //
11016// one should use sbond1() twice to bond two different handles to the rotat- //
11017// ing subface, one is predecssor (-casin), another is successor (-casout). //
11018// //
11019// If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which //
11020// may be non-Delaunay. //
11021// //
11023
11024void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue)
11025{
11026 face abc, bad;
11027 face oldbc, oldca, oldad, olddb;
11028 face bccasin, bccasout, cacasin, cacasout;
11029 face adcasin, adcasout, dbcasin, dbcasout;
11030 face bc, ca, ad, db;
11031 face spinsh;
11032 point pa, pb, pc, pd;
11033
11034 abc = *flipedge;
11035 spivot(abc, bad);
11036 if (sorg(bad) != sdest(abc)) {
11037 sesymself(bad);
11038 }
11039 pa = sorg(abc);
11040 pb = sdest(abc);
11041 pc = sapex(abc);
11042 pd = sapex(bad);
11043
11044 if (b->verbose > 2) {
11045 printf(" Flip sub edge (%d, %d).\n", pointmark(pa), pointmark(pb));
11046 }
11047
11048 // Save the old configuration outside the quadrilateral.
11049 senext(abc, oldbc);
11050 senext2(abc, oldca);
11051 senext(bad, oldad);
11052 senext2(bad, olddb);
11053 // Get the outside connection. Becareful if there is a subsegment on the
11054 // quadrilateral, two casings (casin and casout) are needed to save for
11055 // keeping the face link.
11056 spivot(oldbc, bccasout);
11057 sspivot(oldbc, bc);
11058 if (bc.sh != dummysh) {
11059 // 'bc' is a subsegment.
11060 if (bccasout.sh != dummysh) {
11061 if (oldbc.sh != bccasout.sh) {
11062 // 'oldbc' is not self-bonded.
11063 spinsh = bccasout;
11064 do {
11065 bccasin = spinsh;
11066 spivotself(spinsh);
11067 } while (spinsh.sh != oldbc.sh);
11068 } else {
11069 bccasout.sh = dummysh;
11070 }
11071 }
11072 ssdissolve(oldbc);
11073 }
11074 spivot(oldca, cacasout);
11075 sspivot(oldca, ca);
11076 if (ca.sh != dummysh) {
11077 // 'ca' is a subsegment.
11078 if (cacasout.sh != dummysh) {
11079 if (oldca.sh != cacasout.sh) {
11080 // 'oldca' is not self-bonded.
11081 spinsh = cacasout;
11082 do {
11083 cacasin = spinsh;
11084 spivotself(spinsh);
11085 } while (spinsh.sh != oldca.sh);
11086 } else {
11087 cacasout.sh = dummysh;
11088 }
11089 }
11090 ssdissolve(oldca);
11091 }
11092 spivot(oldad, adcasout);
11093 sspivot(oldad, ad);
11094 if (ad.sh != dummysh) {
11095 // 'ad' is a subsegment.
11096 if (adcasout.sh != dummysh) {
11097 if (oldad.sh != adcasout.sh) {
11098 // 'adcasout' is not self-bonded.
11099 spinsh = adcasout;
11100 do {
11101 adcasin = spinsh;
11102 spivotself(spinsh);
11103 } while (spinsh.sh != oldad.sh);
11104 } else {
11105 adcasout.sh = dummysh;
11106 }
11107 }
11108 ssdissolve(oldad);
11109 }
11110 spivot(olddb, dbcasout);
11111 sspivot(olddb, db);
11112 if (db.sh != dummysh) {
11113 // 'db' is a subsegment.
11114 if (dbcasout.sh != dummysh) {
11115 if (olddb.sh != dbcasout.sh) {
11116 // 'dbcasout' is not self-bonded.
11117 spinsh = dbcasout;
11118 do {
11119 dbcasin = spinsh;
11120 spivotself(spinsh);
11121 } while (spinsh.sh != olddb.sh);
11122 } else {
11123 dbcasout.sh = dummysh;
11124 }
11125 }
11126 ssdissolve(olddb);
11127 }
11128
11129 // Rotate abc and bad one-quarter turn counterclockwise.
11130 if (ca.sh != dummysh) {
11131 if (cacasout.sh != dummysh) {
11132 sbond1(cacasin, oldbc);
11133 sbond1(oldbc, cacasout);
11134 } else {
11135 // Bond 'oldbc' to itself.
11136 sbond(oldbc, oldbc);
11137 // Make sure that dummysh always correctly bonded.
11138 dummysh[0] = sencode(oldbc);
11139 }
11140 ssbond(oldbc, ca);
11141 } else {
11142 sbond(oldbc, cacasout);
11143 }
11144 if (ad.sh != dummysh) {
11145 if (adcasout.sh != dummysh) {
11146 sbond1(adcasin, oldca);
11147 sbond1(oldca, adcasout);
11148 } else {
11149 // Bond 'oldca' to itself.
11150 sbond(oldca, oldca);
11151 // Make sure that dummysh always correctly bonded.
11152 dummysh[0] = sencode(oldca);
11153 }
11154 ssbond(oldca, ad);
11155 } else {
11156 sbond(oldca, adcasout);
11157 }
11158 if (db.sh != dummysh) {
11159 if (dbcasout.sh != dummysh) {
11160 sbond1(dbcasin, oldad);
11161 sbond1(oldad, dbcasout);
11162 } else {
11163 // Bond 'oldad' to itself.
11164 sbond(oldad, oldad);
11165 // Make sure that dummysh always correctly bonded.
11166 dummysh[0] = sencode(oldad);
11167 }
11168 ssbond(oldad, db);
11169 } else {
11170 sbond(oldad, dbcasout);
11171 }
11172 if (bc.sh != dummysh) {
11173 if (bccasout.sh != dummysh) {
11174 sbond1(bccasin, olddb);
11175 sbond1(olddb, bccasout);
11176 } else {
11177 // Bond 'olddb' to itself.
11178 sbond(olddb, olddb);
11179 // Make sure that dummysh always correctly bonded.
11180 dummysh[0] = sencode(olddb);
11181 }
11182 ssbond(olddb, bc);
11183 } else {
11184 sbond(olddb, bccasout);
11185 }
11186
11187 // New vertex assignments for the rotated subfaces.
11188 setsorg(abc, pd); // Update abc to dca.
11189 setsdest(abc, pc);
11190 setsapex(abc, pa);
11191 setsorg(bad, pc); // Update bad to cdb.
11192 setsdest(bad, pd);
11193 setsapex(bad, pb);
11194
11195 if (flipqueue != (queue *) NULL) {
11196 enqueueflipedge(bccasout, flipqueue);
11197 enqueueflipedge(cacasout, flipqueue);
11198 enqueueflipedge(adcasout, flipqueue);
11199 enqueueflipedge(dbcasout, flipqueue);
11200 }
11201}
11202
11204// //
11205// flip() Flips non-locally Delaunay faces in flipqueue until it is empty.//
11206// //
11207// Assumpation: Current tetrahedralization is non-Delaunay after inserting //
11208// a point or performing a flip operation, all possibly non-Delaunay faces //
11209// are in 'flipqueue'. //
11210// //
11211// If 'plastflip' is not NULL, it is used to return a stack of recently //
11212// flipped faces. This stack will be used to reverse the flips done in this //
11213// routine later for removing a newly inserted point because it encroaches //
11214// any subfaces or subsegments. //
11215// //
11216// The return value is the total number of flips done during this invocation.//
11217// //
11219
11220long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
11221{
11222 badface *qface, *newflip;
11223 triface flipface, symface;
11224 point pa, pb, pc, pd, pe;
11225 enum fliptype fc;
11226 REAL sign, bakepsilon;
11227 long flipcount; //, maxfaces; - commented out to get gcc4.6 working
11228 int epscount, fcount;
11229 int ia, ib, ic, id, ie;
11230
11231 if (b->verbose > 1) {
11232 printf(" Do flipface queue: %ld faces.\n", flipqueue->len());
11233 }
11234
11235 flipcount = flip23s + flip32s + flip22s + flip44s;
11236 if (checksubfaces) {
11237 //maxfaces = (4l * tetrahedrons->items + hullsize) / 2l; // commented out to get gcc 4.6 working
11238 fcount = 0;
11239 }
11240
11241 if (plastflip != (badface **) NULL) {
11242 // Initialize the stack of the flip sequence.
11243 flipstackers->restart();
11244 *plastflip = (badface *) NULL;
11245 }
11246
11247 // Loop until the queue is empty.
11248 while (!flipqueue->empty()) {
11249 qface = (badface *) flipqueue->pop();
11250 flipface = qface->tt;
11251 if (isdead(&flipface)) continue;
11252 sym(flipface, symface);
11253 // Only do check when the adjacent tet exists and it's not a "fake" tet.
11254 if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
11255 // For positive orientation that insphere() test requires.
11256 adjustedgering(flipface, CW);
11257 pa = org(flipface);
11258 pb = dest(flipface);
11259 pc = apex(flipface);
11260 pd = oppo(flipface);
11261 pe = oppo(symface);
11262 if (symbolic) {
11263 ia = pointmark(pa);
11264 ib = pointmark(pb);
11265 ic = pointmark(pc);
11266 id = pointmark(pd);
11267 ie = pointmark(pe);
11268 sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
11269 assert(sign != 0.0);
11270 } else {
11271 sign = insphere(pa, pb, pc, pd, pe);
11272 }
11273 } else {
11274 sign = -1.0; // A hull face is locally Delaunay.
11275 }
11276 if (sign > 0.0) {
11277 // 'flipface' is non-locally Delaunay, try to flip it.
11278 if (checksubfaces) {
11279 fcount++;
11280 bakepsilon = b->epsilon;
11281 epscount = 0;
11282 while (epscount < 32) {
11283 fc = categorizeface(flipface);
11284 if (fc == N40) {
11285 b->epsilon *= 1e-1;
11286 epscount++;
11287 continue;
11288 }
11289 break;
11290 }
11291 b->epsilon = bakepsilon;
11292 if (epscount >= 32) {
11293 if (b->verbose > 0) {
11294 printf("Warning: Can't flip a degenerate tetrahedron.\n");
11295 }
11296 fc = N40;
11297 }
11298 } else {
11299 fc = categorizeface(flipface);
11300#ifdef SELF_CHECK
11301 assert(fc != N40);
11302#endif
11303 }
11304 switch (fc) {
11305 // The following face types are flipable.
11306 case T44:
11307 case T22:
11308 flip22(&flipface, flipqueue);
11309 break;
11310 case T23:
11311 flip23(&flipface, flipqueue);
11312 break;
11313 case T32:
11314 flip32(&flipface, flipqueue);
11315 break;
11316 // The following face types are unflipable.
11317 case N32:
11318 break;
11319 case FORBIDDENFACE:
11320 break;
11321 case FORBIDDENEDGE:
11322 break;
11323 // This case is only possible when the domain is nonconvex.
11324 case N40:
11325 // assert(nonconvex);
11326 break;
11327 }
11328 if (plastflip != (badface **) NULL) {
11329 if ((fc == T44) || (fc == T22) || (fc == T23) || (fc == T32)) {
11330 // Push the flipped face into stack.
11331 newflip = (badface *) flipstackers->alloc();
11332 newflip->tt = flipface;
11333 newflip->key = (REAL) fc;
11334 newflip->forg = org(flipface);
11335 newflip->fdest = dest(flipface);
11336 newflip->fapex = apex(flipface);
11337 newflip->previtem = *plastflip;
11338 *plastflip = newflip;
11339 }
11340 }
11341 }
11342 }
11343
11344 flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
11345 if (b->verbose > 1) {
11346 printf(" %ld flips.\n", flipcount);
11347 }
11348
11349 return flipcount;
11350}
11351
11353// //
11354// lawson() Flip locally non-Delaunay faces by Lawson's algorithm. //
11355// //
11357
11358long tetgenmesh::lawson(list *misseglist, queue* flipqueue)
11359{
11360 badface *qface, *misseg;
11361 triface flipface, symface;
11362 triface starttet, spintet;
11363 face checksh, checkseg;
11364 point pa, pb, pc, pd, pe;
11365 point swappt;
11366 REAL sign, ori;
11367 long flipcount;
11368 int ia, ib, ic, id, ie;
11369 int hitbdry, i;
11370
11371 if (b->verbose > 1) {
11372 printf(" Do flipface queue: %ld faces.\n", flipqueue->len());
11373 }
11374 flipcount = flip23s + flip32s + flip22s + flip44s;
11375
11376 // Go through the stack of possible flips and decide whether to do them.
11377 // Note that during the loop new possible flips will be pushed onto
11378 // this stack, while they popped in this loop.
11379 while (!flipqueue->empty()) {
11380 qface = (badface *) flipqueue->pop();
11381 flipface = qface->tt;
11382 // Check if tet has already been flipped out of existence.
11383 if (!isdead(&flipface)) {
11384 sym(flipface, symface);
11385 // Check if this tet is the same as the one which was stacked.
11386 if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
11387 flipface.ver = 0; // Select the CCW ring.
11388 pa = org(flipface);
11389 pb = dest(flipface);
11390 pc = apex(flipface);
11391 pd = oppo(flipface);
11392 pe = oppo(symface);
11393 if (symbolic) {
11394 ia = pointmark(pa);
11395 ib = pointmark(pb);
11396 ic = pointmark(pc);
11397 id = pointmark(pd);
11398 ie = pointmark(pe);
11399 sign = insphere_sos(pb, pa, pc, pd, pe, ib, ia, ic, id, ie);
11400 } else {
11401 sign = insphere(pb, pa, pc, pd, pe);
11402 }
11403 if (sign > 0.0) {
11404 for (i = 0; i < 3; i++) {
11405 ori = orient3d(pa, pb, pd, pe);
11406 if (ori > 0.0) {
11407 // Goto and check the next edge.
11408 swappt = pa;
11409 pa = pb;
11410 pb = pc;
11411 pc = swappt;
11412 enextself(flipface);
11413 } else {
11414 break; // either (ori < 0.0) or (ori == 0.0)
11415 }
11416 } // for (i = 0; ....)
11417 if (ori > 0.0) {
11418 // All three edges are convex, a 2-3 flip is possible.
11419 if (checksubfaces) {
11420 tspivot(flipface, checksh);
11421 if (checksh.sh != dummysh) {
11422 // A subface is not flipable.
11423 continue;
11424 }
11425 }
11426 flip23(&flipface, flipqueue);
11427 } else if (ori < 0.0) {
11428 // The edge (a, b) is non-convex, check for a 3-2 flip.
11429 fnext(flipface, symface);
11430 symself(symface);
11431 if (oppo(symface) == pe) {
11432 // Only three tets adjoining this edge.
11433 if (checksubfaces) {
11434 tsspivot(&flipface, &checkseg);
11435 if (checkseg.sh != dummysh) {
11436 // A subsegment is not flipable.
11437 continue;
11438 }
11439 } else if (checksubsegs) {
11440 tsspivot1(flipface, checkseg);
11441 if (checkseg.sh != dummysh) {
11442 if (b->verbose > 2) {
11443 printf(" Queuing missing segment (%d, %d).\n",
11444 pointmark(org(flipface)), pointmark(dest(flipface)));
11445 }
11446 misseg = (badface *) misseglist->append(NULL);
11447 misseg->ss = checkseg;
11448 misseg->forg = sorg(checkseg);
11449 misseg->fdest = sdest(checkseg);
11450 // Detach all tets having this seg.
11451 starttet = flipface;
11452 adjustedgering(starttet, CCW);
11453 fnextself(starttet);
11454 spintet = starttet;
11455 hitbdry = 0;
11456 do {
11457 tssdissolve1(spintet);
11458 if (!fnextself(spintet)) {
11459 hitbdry++;
11460 if (hitbdry < 2) {
11461 esym(starttet, spintet);
11462 if (!fnextself(spintet)) {
11463 hitbdry++;
11464 }
11465 }
11466 }
11467 } while ((apex(spintet) != apex(starttet)) && (hitbdry < 2));
11468 }
11469 } // if (checksubfaces)
11470 flip32(&flipface, flipqueue);
11471 }
11472 } else {
11473 // Four points (a, b, d, e) are coplanar.
11474 fnext(flipface, symface);
11475 if (fnextself(symface)) {
11476 // Check for a 4-4 flip.
11477 fnextself(symface);
11478 if (apex(symface) == pe) {
11479 if (checksubfaces) {
11480 tsspivot(&flipface, &checkseg);
11481 if (checkseg.sh != dummysh) {
11482 // A subsegment is not flippable.
11483 continue;
11484 }
11485 } else if (checksubsegs) {
11486 tsspivot1(flipface, checkseg);
11487 if (checkseg.sh != dummysh) {
11488 if (b->verbose > 2) {
11489 printf(" Queuing missing segment (%d, %d).\n",
11490 pointmark(org(flipface)), pointmark(dest(flipface)));
11491 }
11492 misseg = (badface *) misseglist->append(NULL);
11493 misseg->ss = checkseg;
11494 misseg->forg = sorg(checkseg);
11495 misseg->fdest = sdest(checkseg);
11496 // Detach all tets having this seg.
11497 starttet = flipface;
11498 adjustedgering(starttet, CCW);
11499 fnextself(starttet);
11500 spintet = starttet;
11501 hitbdry = 0;
11502 do {
11503 tssdissolve1(spintet);
11504 if (!fnextself(spintet)) {
11505 hitbdry++;
11506 if (hitbdry < 2) {
11507 esym(starttet, spintet);
11508 if (!fnextself(spintet)) {
11509 hitbdry++;
11510 }
11511 }
11512 }
11513 } while ((apex(spintet) != apex(starttet)) &&
11514 (hitbdry < 2));
11515 }
11516 } // if (checksubfaces)
11517 flip22(&flipface, flipqueue);
11518 }
11519 } else {
11520 // Check for a 2-2 flip.
11521 esym(flipface, symface);
11522 fnextself(symface);
11523 symself(symface);
11524 if (symface.tet == dummytet) {
11525 if (checksubfaces) {
11526 tsspivot(&flipface, &checkseg);
11527 if (checkseg.sh != dummysh) {
11528 // A subsegment is not flipable.
11529 continue;
11530 }
11531 } else if (checksubsegs) {
11532 tsspivot1(flipface, checkseg);
11533 if (checkseg.sh != dummysh) {
11534 if (b->verbose > 2) {
11535 printf(" Queuing missing segment (%d, %d).\n",
11536 pointmark(org(flipface)), pointmark(dest(flipface)));
11537 }
11538 misseg = (badface *) misseglist->append(NULL);
11539 misseg->ss = checkseg;
11540 misseg->forg = sorg(checkseg);
11541 misseg->fdest = sdest(checkseg);
11542 // Detach all tets having this seg.
11543 starttet = flipface;
11544 adjustedgering(starttet, CCW);
11545 fnextself(starttet);
11546 spintet = starttet;
11547 hitbdry = 0;
11548 do {
11549 tssdissolve1(spintet);
11550 if (!fnextself(spintet)) {
11551 hitbdry++;
11552 if (hitbdry < 2) {
11553 esym(starttet, spintet);
11554 if (!fnextself(spintet)) {
11555 hitbdry++;
11556 }
11557 }
11558 }
11559 } while ((apex(spintet) != apex(starttet)) &&
11560 (hitbdry < 2));
11561 }
11562 } // if (checksubfaces)
11563 flip22(&flipface, flipqueue);
11564 }
11565 }
11566 } // if (ori > 0.0)
11567 } // if (sign > 0.0)
11568 }
11569 } // !isdead(&qface->tt)
11570 } // while (!flipqueue->empty())
11571
11572 flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
11573 if (b->verbose > 1) {
11574 printf(" %ld flips.\n", flipcount);
11575 }
11576 return flipcount;
11577}
11578
11580// //
11581// undoflip() Undo the most recent flip sequence induced by flip(). //
11582// //
11583// 'lastflip' is the stack of recently flipped faces. Walks through the list //
11584// of flips, in the reverse of the order in which they were done, and undoes //
11585// them. //
11586// //
11588
11589void tetgenmesh::undoflip(badface *lastflip)
11590{
11591 enum fliptype fc;
11592
11593 while (lastflip != (badface *) NULL) {
11594 // Get the right flipped face.
11595 findface(&lastflip->tt, lastflip->forg, lastflip->fdest, lastflip->fapex);
11596 fc = (enum fliptype) (int) lastflip->key;
11597 switch (fc) {
11598 case T23:
11599 // The reverse operation of T23 is T32.
11600 flip32(&lastflip->tt, NULL);
11601 break;
11602 case T32:
11603 // The reverse operation of T32 is T23.
11604 flip23(&lastflip->tt, NULL);
11605 break;
11606 case T22:
11607 case T44:
11608 // The reverse operation of T22 or T44 is again T22 or T44.
11609 flip22(&lastflip->tt, NULL);
11610 break;
11611 default: // To omit compile warnings.
11612 break;
11613 }
11614 // Go on and process the next transformation.
11615 lastflip = lastflip->previtem;
11616 }
11617}
11618
11620// //
11621// flipsub() Flip non-Delaunay edges in a queue of (coplanar) subfaces. //
11622// //
11623// Assumpation: Current triangulation T contains non-Delaunay edges (after //
11624// inserting a point or performing a flip). Non-Delaunay edges are queued in //
11625// 'facequeue'. Returns the total number of flips done during this call. //
11626// //
11628
11629long tetgenmesh::flipsub(queue* flipqueue)
11630{
11631 badface *qedge;
11632 face flipedge, symedge;
11633 face checkseg;
11634 point pa, pb, pc, pd;
11635 REAL vab[3], vac[3], vad[3];
11636 REAL dot1, dot2, lac, lad;
11637 REAL sign, ori;
11638 int edgeflips;
11639 int i;
11640
11641 if (b->verbose > 1) {
11642 printf(" Start do edge queue: %ld edges.\n", flipqueue->len());
11643 }
11644
11645 edgeflips = 0;
11646
11647 while (!flipqueue->empty()) {
11648 qedge = (badface *) flipqueue->pop();
11649 flipedge = qedge->ss;
11650 if (flipedge.sh == dummysh) continue;
11651 if ((sorg(flipedge) != qedge->forg) ||
11652 (sdest(flipedge) != qedge->fdest)) continue;
11653 sspivot(flipedge, checkseg);
11654 if (checkseg.sh != dummysh) continue; // Can't flip a subsegment.
11655 spivot(flipedge, symedge);
11656 if (symedge.sh == dummysh) continue; // Can't flip a hull edge.
11657 pa = sorg(flipedge);
11658 pb = sdest(flipedge);
11659 pc = sapex(flipedge);
11660 pd = sapex(symedge);
11661 // Choose the triangle abc or abd as the base depending on the angle1
11662 // (Vac, Vab) and angle2 (Vad, Vab).
11663 for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
11664 for (i = 0; i < 3; i++) vac[i] = pc[i] - pa[i];
11665 for (i = 0; i < 3; i++) vad[i] = pd[i] - pa[i];
11666 dot1 = dot(vac, vab);
11667 dot2 = dot(vad, vab);
11668 dot1 *= dot1;
11669 dot2 *= dot2;
11670 lac = dot(vac, vac);
11671 lad = dot(vad, vad);
11672 if (lad * dot1 <= lac * dot2) {
11673 // angle1 is closer to 90 than angle2, choose abc (flipedge).
11674 abovepoint = facetabovepointarray[shellmark(flipedge)];
11675 if (abovepoint == (point) NULL) {
11676 getfacetabovepoint(&flipedge);
11677 }
11678 sign = insphere(pa, pb, pc, abovepoint, pd);
11679 ori = orient3d(pa, pb, pc, abovepoint);
11680 } else {
11681 // angle2 is closer to 90 than angle1, choose abd (symedge).
11682 abovepoint = facetabovepointarray[shellmark(symedge)];
11683 if (abovepoint == (point) NULL) {
11684 getfacetabovepoint(&symedge);
11685 }
11686 sign = insphere(pa, pb, pd, abovepoint, pc);
11687 ori = orient3d(pa, pb, pd, abovepoint);
11688 }
11689 // Correct the sign.
11690 sign = ori > 0.0 ? sign : -sign;
11691 if (sign > 0.0) {
11692 // Flip the non-Delaunay edge.
11693 flip22sub(&flipedge, flipqueue);
11694 edgeflips++;
11695 }
11696 }
11697
11698 if (b->verbose > 1) {
11699 printf(" Total %d flips.\n", edgeflips);
11700 }
11701
11702 return edgeflips;
11703}
11704
11706// //
11707// removetetbypeeloff() Remove a boundary tet by peeling it off. //
11708// //
11709// 'striptet' (abcd) is on boundary and can be removed by stripping it off. //
11710// Let abc and bad are the external boundary faces. //
11711// //
11712// To strip 'abcd' from the mesh is to detach its two interal faces (dca and //
11713// cdb) from their adjoining tets together with a 2-to-2 flip to transform //
11714// two subfaces (abc and bad) into another two (dca and cdb). //
11715// //
11716// In mesh optimization. It is possible that ab is a segment and abcd is a //
11717// sliver on the hull. Strip abcd will also delete the segment ab. //
11718// //
11720
11721bool tetgenmesh::removetetbypeeloff(triface *striptet)
11722{
11723 triface abcd, badc;
11724 triface dcacasing, cdbcasing;
11725 face abc, bad;
11726 face abseg;
11727 REAL ang;
11728
11729 abcd = *striptet;
11730 adjustedgering(abcd, CCW);
11731 // Get the casing tets at the internal sides.
11732 enextfnext(abcd, cdbcasing);
11733 enext2fnext(abcd, dcacasing);
11734 symself(cdbcasing);
11735 symself(dcacasing);
11736 // Do the neighboring tets exist? During optimization. It is possible
11737 // that the neighboring tets are already dead.
11738 if ((cdbcasing.tet == dummytet) || (dcacasing.tet == dummytet)) {
11739 // Do not strip this tet.
11740 return false;
11741 }
11742
11743 // Are there subfaces?
11744 if (checksubfaces) {
11745 // Get the external subfaces abc, bad.
11746 fnext(abcd, badc);
11747 esymself(badc);
11748 tspivot(abcd, abc);
11749 tspivot(badc, bad);
11750 if (abc.sh != dummysh) {
11751 assert(bad.sh != dummysh);
11752 findedge(&abc, org(abcd), dest(abcd));
11753 findedge(&bad, org(badc), dest(badc));
11754 // Is ab a segment?
11755 sspivot(abc, abseg);
11756 if (abseg.sh != dummysh) {
11757 // Does a segment allow to be removed?
11758 if ((b->optlevel > 3) && (b->nobisect == 0)) {
11759 // Only remove this segment if the dihedal angle at ab is between
11760 // [b->maxdihedral-9, 180] (deg). This avoids mistakely fliping
11761 // ab when it has actually no big dihedral angle while cd has.
11762 ang = facedihedral(org(abcd), dest(abcd), apex(abcd), oppo(abcd));
11763 ang = ang * 180.0 / PI;
11764 if ((ang + 9.0) > b->maxdihedral) {
11765 if (b->verbose > 1) {
11766 printf(" Remove a segment during peeling.\n");
11767 }
11768 face prevseg, nextseg;
11769 // It is only shared by abc and bad (abcd is a tet).
11770 ssdissolve(abc);
11771 ssdissolve(bad);
11772 abseg.shver = 0;
11773 senext(abseg, nextseg);
11774 spivotself(nextseg);
11775 if (nextseg.sh != dummysh) {
11776 ssdissolve(nextseg);
11777 }
11778 senext2(abseg, prevseg);
11779 spivotself(prevseg);
11780 if (prevseg.sh != dummysh) {
11781 ssdissolve(prevseg);
11782 }
11783 shellfacedealloc(subsegs, abseg.sh);
11784 optcount[1]++;
11785 } else {
11786 return false;
11787 }
11788 } else {
11789 return false;
11790 }
11791 }
11792 // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb.
11793 flip22sub(&abc, NULL);
11794 // The two internal faces become boundary faces.
11795 tsbond(cdbcasing, bad);
11796 tsbond(dcacasing, abc);
11797 }
11798 }
11799
11800 // Detach abcd from the two internal faces.
11801 dissolve(cdbcasing);
11802 dissolve(dcacasing);
11803 // Delete abcd.
11804 tetrahedrondealloc(abcd.tet);
11805 return true;
11806}
11807
11809// //
11810// removeedgebyflip22() Remove an edge by a 2-to-2 (or 4-to-4) flip. //
11811// //
11812// 'abtetlist' contains n tets (n is 2 or 4) sharing edge ab, abtetlist[0] //
11813// and abtetlist[1] are tets abec and abde, respectively (NOTE, both are in //
11814// CW edge ring), where a, b, c, and d are coplanar. If n = 4, abtetlist[2] //
11815// and abtetlist[3] are tets abfd and abcf, respectively. This routine uses //
11816// flip22() to replace edge ab with cd, the surrounding tets are rotated. //
11817// //
11818// If 'key' != NULL. The old tets are replaced by the new tets only if the //
11819// local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
11820// is the maximum dihedral angle in the old tets. //
11821// //
11823
11824bool tetgenmesh::removeedgebyflip22(REAL *key, int n, triface *abtetlist,
11825 queue *flipque)
11826{
11827 point pa, pb, pc, pd, pe, pf;
11828 REAL cosmaxd, d1, d2, d3;
11829 bool doflip;
11830
11831 cosmaxd = 0.0;
11832 pf = apex(abtetlist[2]);
11833 doflip = true;
11834 adjustedgering(abtetlist[0], CW);
11835 pa = org(abtetlist[0]);
11836 pb = dest(abtetlist[0]);
11837 pe = apex(abtetlist[0]);
11838 pc = oppo(abtetlist[0]);
11839 pd = apex(abtetlist[1]);
11840 if (n == 4) {
11841 pf = apex(abtetlist[2]);
11842 }
11843 if (key && (*key > -1.0)) {
11844 tetalldihedral(pc, pd, pe, pa, NULL, &d1, NULL);
11845 tetalldihedral(pd, pc, pe, pb, NULL, &d2, NULL);
11846 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
11847 if (n == 4) {
11848 tetalldihedral(pd, pc, pf, pa, NULL, &d1, NULL);
11849 tetalldihedral(pc, pd, pf, pb, NULL, &d2, NULL);
11850 d3 = d1 < d2 ? d1 : d2; // Choose the bigger angle.
11851 cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle.
11852 }
11853 doflip = (*key < cosmaxd); // Can local quality be improved?
11854 }
11855
11856 if (doflip) {
11857 flip22(&abtetlist[0], NULL);
11858 // Return the improved quality value.
11859 if (key) *key = cosmaxd;
11860 }
11861
11862 return doflip;
11863}
11864
11866// //
11867// removefacebyflip23() Remove a face by a 2-to-3 flip. //
11868// //
11869// 'abctetlist' contains 2 tets sharing abc, which are [0]abcd and [1]bace. //
11870// This routine forms three new tets that abc is not a face anymore. Save //
11871// them in 'newtetlist': [0]edab, [1]edbc, and [2]edca. Note that the new //
11872// tets may not valid if one of them get inverted. return false if so. //
11873// //
11874// If 'key' != NULL. The old tets are replaced by the new tets only if the //
11875// local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
11876// is the maximum dihedral angle in the old tets. //
11877// //
11878// If the face is flipped, 'newtetlist' returns the three new tets. The two //
11879// tets in 'abctetlist' are NOT deleted. The caller has the right to either //
11880// delete them or reverse the operation. //
11881// //
11883
11884bool tetgenmesh::removefacebyflip23(REAL *key, triface *abctetlist,
11885 triface *newtetlist, queue *flipque)
11886{
11887 triface edab, edbc, edca; // new configuration.
11888 triface newfront, oldfront, adjfront;
11889 face checksh;
11890 point pa, pb, pc, pd, pe;
11891 REAL ori, cosmaxd, d1, d2, d3;
11892 REAL attrib, volume;
11893 bool doflip;
11894 int i;
11895
11896 cosmaxd = 0.0;
11897
11898 adjustedgering(abctetlist[0], CCW);
11899 pa = org(abctetlist[0]);
11900 pb = dest(abctetlist[0]);
11901 pc = apex(abctetlist[0]);
11902 pd = oppo(abctetlist[0]);
11903 pe = oppo(abctetlist[1]);
11904
11905 // Check if the flip creates valid new tets.
11906 ori = orient3d(pe, pd, pa, pb);
11907 if (ori < 0.0) {
11908 ori = orient3d(pe, pd, pb, pc);
11909 if (ori < 0.0) {
11910 ori = orient3d(pe, pd, pc, pa);
11911 }
11912 }
11913 doflip = (ori < 0.0); // Can abc be flipped away?
11914 if (doflip && (key != (REAL *) NULL)) {
11915 if (*key > -1.0) {
11916 // Test if the new tets reduce the maximal dihedral angle.
11917 tetalldihedral(pe, pd, pa, pb, NULL, &d1, NULL);
11918 tetalldihedral(pe, pd, pb, pc, NULL, &d2, NULL);
11919 tetalldihedral(pe, pd, pc, pa, NULL, &d3, NULL);
11920 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
11921 cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle.
11922 doflip = (*key < cosmaxd); // Can local quality be improved?
11923 }
11924 }
11925
11926 if (doflip) {
11927 // A valid (2-to-3) flip is found.
11928 flip23s++;
11929 // Create the new tets.
11930 maketetrahedron(&edab);
11931 setorg(edab, pe);
11932 setdest(edab, pd);
11933 setapex(edab, pa);
11934 setoppo(edab, pb);
11935 maketetrahedron(&edbc);
11936 setorg(edbc, pe);
11937 setdest(edbc, pd);
11938 setapex(edbc, pb);
11939 setoppo(edbc, pc);
11940 maketetrahedron(&edca);
11941 setorg(edca, pe);
11942 setdest(edca, pd);
11943 setapex(edca, pc);
11944 setoppo(edca, pa);
11945 // Transfer the element attributes.
11946 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
11947 attrib = elemattribute(abctetlist[0].tet, i);
11948 setelemattribute(edab.tet, i, attrib);
11949 setelemattribute(edbc.tet, i, attrib);
11950 setelemattribute(edca.tet, i, attrib);
11951 }
11952 // Transfer the volume constraints.
11953 if (b->varvolume && !b->refine) {
11954 volume = volumebound(abctetlist[0].tet);
11955 setvolumebound(edab.tet, volume);
11956 setvolumebound(edbc.tet, volume);
11957 setvolumebound(edca.tet, volume);
11958 }
11959 // Return two new tets.
11960 newtetlist[0] = edab;
11961 newtetlist[1] = edbc;
11962 newtetlist[2] = edca;
11963 // Glue the three new tets.
11964 for (i = 0; i < 3; i++) {
11965 fnext(newtetlist[i], newfront);
11966 bond(newfront, newtetlist[(i + 1) % 3]);
11967 }
11968 // Substitute the three new tets into the old cavity.
11969 for (i = 0; i < 3; i++) {
11970 fnext(abctetlist[0], oldfront);
11971 sym(oldfront, adjfront); // may be outside.
11972 enextfnext(newtetlist[i], newfront);
11973 bond(newfront, adjfront);
11974 if (checksubfaces) {
11975 tspivot(oldfront, checksh);
11976 if (checksh.sh != dummysh) {
11977 tsbond(newfront, checksh);
11978 }
11979 }
11980 if (flipque != (queue *) NULL) {
11981 enqueueflipface(newfront, flipque);
11982 }
11983 enextself(abctetlist[0]);
11984 }
11985 findedge(&(abctetlist[1]), pb, pa);
11986 for (i = 0; i < 3; i++) {
11987 fnext(abctetlist[1], oldfront);
11988 sym(oldfront, adjfront); // may be outside.
11989 enext2fnext(newtetlist[i], newfront);
11990 bond(newfront, adjfront);
11991 if (checksubfaces) {
11992 tspivot(oldfront, checksh);
11993 if (checksh.sh != dummysh) {
11994 tsbond(newfront, checksh);
11995 }
11996 }
11997 if (flipque != (queue *) NULL) {
11998 enqueueflipface(newfront, flipque);
11999 }
12000 enext2self(abctetlist[1]);
12001 }
12002 // Do not delete the old tets.
12003 // for (i = 0; i < 2; i++) {
12004 // tetrahedrondealloc(abctetlist[i].tet);
12005 // }
12006 // Return the improved quality value.
12007 if (key != (REAL *) NULL) *key = cosmaxd;
12008 return true;
12009 }
12010
12011 return false;
12012}
12013
12015// //
12016// removeedgebyflip32() Remove an edge by a 3-to-2 flip. //
12017// //
12018// 'abtetlist' contains 3 tets sharing ab. Imaging that ab is perpendicular //
12019// to the screen, where a lies in front of and b lies behind it. The 3 tets //
12020// of the list are: [0]abce, [1]abdc, and [2]abed, respectively. //
12021// //
12022// This routine forms two new tets that ab is not an edge of them. Save them //
12023// in 'newtetlist', [0]dcea, [1]cdeb. Note that the new tets may not valid //
12024// if one of them get inverted. return false if so. //
12025// //
12026// If 'key' != NULL. The old tets are replaced by the new tets only if the //
12027// local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
12028// is the maximum dihedral angle in the old tets. //
12029// //
12030// If the edge is flipped, 'newtetlist' returns the two new tets. The three //
12031// tets in 'abtetlist' are NOT deleted. The caller has the right to either //
12032// delete them or reverse the operation. //
12033// //
12035
12036bool tetgenmesh::removeedgebyflip32(REAL *key, triface *abtetlist,
12037 triface *newtetlist, queue *flipque)
12038{
12039 triface dcea, cdeb; // new configuration.
12040 triface newfront, oldfront, adjfront;
12041 face checksh;
12042 point pa, pb, pc, pd, pe;
12043 REAL ori, cosmaxd, d1, d2;
12044 REAL attrib, volume;
12045 bool doflip;
12046 int i;
12047
12048 pa = org(abtetlist[0]);
12049 pb = dest(abtetlist[0]);
12050 pc = apex(abtetlist[0]);
12051 pd = apex(abtetlist[1]);
12052 pe = apex(abtetlist[2]);
12053
12054 ori = orient3d(pd, pc, pe, pa);
12055 if (ori < 0.0) {
12056 ori = orient3d(pc, pd, pe, pb);
12057 }
12058 doflip = (ori < 0.0); // Can ab be flipped away?
12059
12060 // Does the caller ensure a valid configuration?
12061 if (doflip && (key != (REAL *) NULL)) {
12062 if (*key > -1.0) {
12063 // Test if the new tets reduce the maximal dihedral angle.
12064 tetalldihedral(pd, pc, pe, pa, NULL, &d1, NULL);
12065 tetalldihedral(pc, pd, pe, pb, NULL, &d2, NULL);
12066 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
12067 doflip = (*key < cosmaxd); // Can local quality be improved?
12068 // Return the key
12069 *key = cosmaxd;
12070 }
12071 }
12072
12073 if (doflip) {
12074 // Create the new tets.
12075 maketetrahedron(&dcea);
12076 setorg(dcea, pd);
12077 setdest(dcea, pc);
12078 setapex(dcea, pe);
12079 setoppo(dcea, pa);
12080 maketetrahedron(&cdeb);
12081 setorg(cdeb, pc);
12082 setdest(cdeb, pd);
12083 setapex(cdeb, pe);
12084 setoppo(cdeb, pb);
12085 // Transfer the element attributes.
12086 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
12087 attrib = elemattribute(abtetlist[0].tet, i);
12088 setelemattribute(dcea.tet, i, attrib);
12089 setelemattribute(cdeb.tet, i, attrib);
12090 }
12091 // Transfer the volume constraints.
12092 if (b->varvolume && !b->refine) {
12093 volume = volumebound(abtetlist[0].tet);
12094 setvolumebound(dcea.tet, volume);
12095 setvolumebound(cdeb.tet, volume);
12096 }
12097 // Return two new tets.
12098 newtetlist[0] = dcea;
12099 newtetlist[1] = cdeb;
12100 // Glue the two new tets.
12101 bond(dcea, cdeb);
12102 // Substitute the two new tets into the old three-tets cavity.
12103 for (i = 0; i < 3; i++) {
12104 fnext(dcea, newfront); // face dca, cea, eda.
12105 esym(abtetlist[(i + 1) % 3], oldfront);
12106 enextfnextself(oldfront);
12107 // Get the adjacent tet at the face (may be a dummytet).
12108 sym(oldfront, adjfront);
12109 bond(newfront, adjfront);
12110 if (checksubfaces) {
12111 tspivot(oldfront, checksh);
12112 if (checksh.sh != dummysh) {
12113 tsbond(newfront, checksh);
12114 }
12115 }
12116 if (flipque != (queue *) NULL) {
12117 enqueueflipface(newfront, flipque);
12118 }
12119 enext2self(dcea);
12120 }
12121 for (i = 0; i < 3; i++) {
12122 fnext(cdeb, newfront); // face cdb, deb, ecb.
12123 esym(abtetlist[(i + 1) % 3], oldfront);
12124 enext2fnextself(oldfront);
12125 // Get the adjacent tet at the face (may be a dummytet).
12126 sym(oldfront, adjfront);
12127 bond(newfront, adjfront);
12128 if (checksubfaces) {
12129 tspivot(oldfront, checksh);
12130 if (checksh.sh != dummysh) {
12131 tsbond(newfront, checksh);
12132 }
12133 }
12134 if (flipque != (queue *) NULL) {
12135 enqueueflipface(newfront, flipque);
12136 }
12137 enextself(cdeb);
12138 }
12139 // Do not delete the old tets.
12140 // for (i = 0; i < 3; i++) {
12141 // tetrahedrondealloc(abtetlist[i].tet);
12142 // }
12143 return true;
12144 } // if (doflip)
12145
12146 return false;
12147}
12148
12150// //
12151// removeedgebytranNM() Remove an edge by transforming n-to-m tets. //
12152// //
12153// This routine attempts to remove a given edge (ab) by transforming the set //
12154// T of tets surrounding ab into another set T' of tets. T and T' have the //
12155// same outer faces and ab is not an edge of T' anymore. Let |T|=n, and |T'| //
12156// =m, it is actually a n-to-m flip for n > 3. The relation between n and m //
12157// depends on the method, ours is found below. //
12158// //
12159// 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular //
12160// to the screen, where a lies in front of and b lies behind it. Let the //
12161// projections of the n apexes onto screen in clockwise order are: p_0, ... //
12162// p_n-1, respectively. The tets in the list are: [0]abp_0p_n-1,[1]abp_1p_0, //
12163// ..., [n-1]abp_n-1p_n-2, respectively. //
12164// //
12165// The principle of the approach is: Recursively reduce the link of ab by //
12166// using flip23 until only three faces remain, hence a flip32 can be applied //
12167// to remove ab. For a given face a.b.p_0, check a flip23 can be applied on //
12168// it, i.e, edge p_1.p_n-1 crosses it. NOTE*** We do the flip even p_1.p_n-1 //
12169// intersects with a.b (they are coplanar). If so, a degenerate tet (a.b.p_1.//
12170// p_n-1) is temporarily created, but it will be eventually removed by the //
12171// final flip32. This relaxation splits a flip44 into flip23 + flip32. *NOTE //
12172// Now suppose a.b.p_0 gets flipped, p_0 is not on the link of ab anymore. //
12173// The link is then reduced (by 1). 2 of the 3 new tets, p_n-1.p_1.p_0.a and //
12174// p_1.p_n-1.p_0.b, will be part of the new configuration. The left new tet,//
12175// a.b.p_1.p_n-1, goes into the new link of ab. A recurrence can be applied. //
12176// //
12177// If 'e1' and 'e2' are not NULLs, they specify an wanted edge to appear in //
12178// the new tet configuration. In such case, only do flip23 if edge e1<->e2 //
12179// can be recovered. It is used in removeedgebycombNM(). //
12180// //
12181// If ab gets removed. 'newtetlist' contains m new tets. By using the above //
12182// approach, the pairs (n, m) can be easily enumerated. For example, (3, 2),//
12183// (4, 4), (5, 6), (6, 8), (7, 10), (8, 12), (9, 14), (10, 16), and so on. //
12184// It is easy to deduce, that m = (n - 2) * 2, when n >= 3. The n tets in //
12185// 'abtetlist' are NOT deleted in this routine. The caller has the right to //
12186// either delete them or reverse this operation. //
12187// //
12189
12190bool tetgenmesh::removeedgebytranNM(REAL *key, int n, triface *abtetlist,
12191 triface *newtetlist, point e1, point e2, queue *flipque)
12192{
12193 triface tmpabtetlist[9]; // Temporary max 9 tets configuration.
12194 triface newfront, oldfront, adjfront;
12195 face checksh;
12196 point pa, pb, p[10];
12197 REAL ori, cosmaxd, d1, d2;
12198 REAL tmpkey;
12199 REAL attrib, volume;
12200 bool doflip, copflag, success;
12201 int i, j, k;
12202
12203 cosmaxd = 0.0;
12204 // Maximum 10 tets.
12205 assert(n <= 10);
12206 // Two points a and b are fixed.
12207 pa = org(abtetlist[0]);
12208 pb = dest(abtetlist[0]);
12209 // The points p_0, p_1, ..., p_n-1 are permuted in each new configuration.
12210 // These permutations can be easily done in the following loop.
12211 // Loop through all the possible new tets configurations. Stop on finding
12212 // a valid new tet configuration which also immproves the quality value.
12213 for (i = 0; i < n; i++) {
12214 // Get other n points for the current configuration.
12215 for (j = 0; j < n; j++) {
12216 p[j] = apex(abtetlist[(i + j) % n]);
12217 }
12218 // Is there a wanted edge?
12219 if ((e1 != (point) NULL) && (e2 != (point) NULL)) {
12220 // Yes. Skip this face if p[1]<->p[n-1] is not the edge.
12221 if (!(((p[1] == e1) && (p[n - 1] == e2)) ||
12222 ((p[1] == e2) && (p[n - 1] == e1)))) continue;
12223 }
12224 // Test if face a.b.p_0 can be flipped (by flip23), ie, to check if the
12225 // edge p_n-1.p_1 crosses face a.b.p_0 properly.
12226 // Note. It is possible that face a.b.p_0 has type flip44, ie, a,b,p_1,
12227 // and p_n-1 are coplanar. A trick is to split the flip44 into two
12228 // steps: frist a flip23, then a flip32. The first step creates a
12229 // degenerate tet (vol=0) which will be removed by the second flip.
12230 ori = orient3d(pa, pb, p[1], p[n - 1]);
12231 copflag = (ori == 0.0); // Are they coplanar?
12232 if (ori >= 0.0) {
12233 // Accept the coplanar case which supports flip44.
12234 ori = orient3d(pb, p[0], p[1], p[n - 1]);
12235 if (ori > 0.0) {
12236 ori = orient3d(p[0], pa, p[1], p[n - 1]);
12237 }
12238 }
12239 // Is face abc flipable?
12240 if (ori > 0.0) {
12241 // A valid (2-to-3) flip (or 4-to-4 flip) is found.
12242 copflag ? flip44s++ : flip23s++;
12243 doflip = true;
12244 if (key != (REAL *) NULL) {
12245 if (*key > -1.0) {
12246 // Test if the new tets reduce the maximal dihedral angle. Only 2
12247 // tets, p_n-1.p_1.p_0.a and p_1.p_n-1.p_0.b, need to be tested
12248 // The left one a.b.p_n-1.p_1 goes into the new link of ab.
12249 tetalldihedral(p[n - 1], p[1], p[0], pa, NULL, &d1, NULL);
12250 tetalldihedral(p[1], p[n - 1], p[0], pb, NULL, &d2, NULL);
12251 cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
12252 doflip = *key < cosmaxd; // Can the local quality be improved?
12253 }
12254 }
12255 if (doflip) {
12256 tmpkey = key != NULL ? *key : -1.0;
12257 // Create the two new tets.
12258 maketetrahedron(&(newtetlist[0]));
12259 setorg(newtetlist[0], p[n - 1]);
12260 setdest(newtetlist[0], p[1]);
12261 setapex(newtetlist[0], p[0]);
12262 setoppo(newtetlist[0], pa);
12263 maketetrahedron(&(newtetlist[1]));
12264 setorg(newtetlist[1], p[1]);
12265 setdest(newtetlist[1], p[n - 1]);
12266 setapex(newtetlist[1], p[0]);
12267 setoppo(newtetlist[1], pb);
12268 // Create the n - 1 temporary new tets (the new Star(ab)).
12269 maketetrahedron(&(tmpabtetlist[0]));
12270 setorg(tmpabtetlist[0], pa);
12271 setdest(tmpabtetlist[0], pb);
12272 setapex(tmpabtetlist[0], p[n - 1]);
12273 setoppo(tmpabtetlist[0], p[1]);
12274 for (j = 1; j < n - 1; j++) {
12275 maketetrahedron(&(tmpabtetlist[j]));
12276 setorg(tmpabtetlist[j], pa);
12277 setdest(tmpabtetlist[j], pb);
12278 setapex(tmpabtetlist[j], p[j]);
12279 setoppo(tmpabtetlist[j], p[j + 1]);
12280 }
12281 // Transfer the element attributes.
12282 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
12283 attrib = elemattribute(abtetlist[0].tet, j);
12284 setelemattribute(newtetlist[0].tet, j, attrib);
12285 setelemattribute(newtetlist[1].tet, j, attrib);
12286 for (k = 0; k < n - 1; k++) {
12287 setelemattribute(tmpabtetlist[k].tet, j, attrib);
12288 }
12289 }
12290 // Transfer the volume constraints.
12291 if (b->varvolume && !b->refine) {
12292 volume = volumebound(abtetlist[0].tet);
12293 setvolumebound(newtetlist[0].tet, volume);
12294 setvolumebound(newtetlist[1].tet, volume);
12295 for (k = 0; k < n - 1; k++) {
12296 setvolumebound(tmpabtetlist[k].tet, volume);
12297 }
12298 }
12299 // Glue the new tets at their internal faces: 2 + (n - 1).
12300 bond(newtetlist[0], newtetlist[1]); // p_n-1.p_1.p_0.
12301 fnext(newtetlist[0], newfront);
12302 enext2fnext(tmpabtetlist[0], adjfront);
12303 bond(newfront, adjfront); // p_n-1.p_1.a.
12304 fnext(newtetlist[1], newfront);
12305 enextfnext(tmpabtetlist[0], adjfront);
12306 bond(newfront, adjfront); // p_n-1.p_1.b.
12307 // Glue n - 1 internal faces around ab.
12308 for (j = 0; j < n - 1; j++) {
12309 fnext(tmpabtetlist[j], newfront);
12310 bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1
12311 }
12312 // Substitute the old tets with the new tets by connecting the new
12313 // tets to the adjacent tets in the mesh. There are n * 2 (outer)
12314 // faces of the new tets need to be operated.
12315 // Note, after the substitution, the old tets still have pointers to
12316 // their adjacent tets in the mesh. These pointers can be re-used
12317 // to inverse the substitution.
12318 for (j = 0; j < n; j++) {
12319 // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0).
12320 oldfront = abtetlist[(i + j) % n];
12321 esymself(oldfront);
12322 enextfnextself(oldfront);
12323 // Get an adjacent tet at face: [0]a.p_0.p_n-1 or [j]a.p_j.p_j-1.
12324 sym(oldfront, adjfront); // adjfront may be dummy.
12325 // Get the corresponding face from the new tets.
12326 if (j == 0) {
12327 enext2fnext(newtetlist[0], newfront); // a.p_0.n_n-1
12328 } else if (j == 1) {
12329 enextfnext(newtetlist[0], newfront); // a.p_1.p_0
12330 } else { // j >= 2.
12331 enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1
12332 }
12333 bond(newfront, adjfront);
12334 if (checksubfaces) {
12335 tspivot(oldfront, checksh);
12336 if (checksh.sh != dummysh) {
12337 tsbond(newfront, checksh);
12338 }
12339 }
12340 if (flipque != (queue *) NULL) {
12341 // Only queue the faces of the two new tets.
12342 if (j < 2) enqueueflipface(newfront, flipque);
12343 }
12344 }
12345 for (j = 0; j < n; j++) {
12346 // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0).
12347 oldfront = abtetlist[(i + j) % n];
12348 esymself(oldfront);
12349 enext2fnextself(oldfront);
12350 // Get an adjacent tet at face: [0]b.p_0.p_n-1 or [j]b.p_j.p_j-1.
12351 sym(oldfront, adjfront); // adjfront may be dummy.
12352 // Get the corresponding face from the new tets.
12353 if (j == 0) {
12354 enextfnext(newtetlist[1], newfront); // b.p_0.n_n-1
12355 } else if (j == 1) {
12356 enext2fnext(newtetlist[1], newfront); // b.p_1.p_0
12357 } else { // j >= 2.
12358 enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1
12359 }
12360 bond(newfront, adjfront);
12361 if (checksubfaces) {
12362 tspivot(oldfront, checksh);
12363 if (checksh.sh != dummysh) {
12364 tsbond(newfront, checksh);
12365 }
12366 }
12367 if (flipque != (queue *) NULL) {
12368 // Only queue the faces of the two new tets.
12369 if (j < 2) enqueueflipface(newfront, flipque);
12370 }
12371 }
12372 // Adjust the faces in the temporary new tets at ab for recursively
12373 // processing on the n-1 tets.(See the description at beginning)
12374 for (j = 0; j < n - 1; j++) {
12375 fnextself(tmpabtetlist[j]);
12376 }
12377 if (n > 4) {
12378 success = removeedgebytranNM(&tmpkey, n-1, tmpabtetlist,
12379 &(newtetlist[2]), NULL, NULL, flipque);
12380 } else { // assert(n == 4);
12381 success = removeedgebyflip32(&tmpkey, tmpabtetlist,
12382 &(newtetlist[2]), flipque);
12383 }
12384 // No matter it was success or not, delete the temporary tets.
12385 for (j = 0; j < n - 1; j++) {
12386 tetrahedrondealloc(tmpabtetlist[j].tet);
12387 }
12388 if (success) {
12389 // The new configuration is good.
12390 // Do not delete the old tets.
12391 // for (j = 0; j < n; j++) {
12392 // tetrahedrondealloc(abtetlist[j].tet);
12393 // }
12394 // Save the minimal improved quality value.
12395 if (key != (REAL *) NULL) {
12396 *key = (tmpkey < cosmaxd ? tmpkey : cosmaxd);
12397 }
12398 return true;
12399 } else {
12400 // The new configuration is bad, substitue back the old tets.
12401 for (j = 0; j < n; j++) {
12402 oldfront = abtetlist[(i + j) % n];
12403 esymself(oldfront);
12404 enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1.
12405 sym(oldfront, adjfront); // adjfront may be dummy.
12406 bond(oldfront, adjfront);
12407 if (checksubfaces) {
12408 tspivot(oldfront, checksh);
12409 if (checksh.sh != dummysh) {
12410 tsbond(oldfront, checksh);
12411 }
12412 }
12413 }
12414 for (j = 0; j < n; j++) {
12415 oldfront = abtetlist[(i + j) % n];
12416 esymself(oldfront);
12417 enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
12418 sym(oldfront, adjfront); // adjfront may be dummy
12419 bond(oldfront, adjfront);
12420 if (checksubfaces) {
12421 tspivot(oldfront, checksh);
12422 if (checksh.sh != dummysh) {
12423 tsbond(oldfront, checksh);
12424 }
12425 }
12426 }
12427 // Delete the new tets.
12428 tetrahedrondealloc(newtetlist[0].tet);
12429 tetrahedrondealloc(newtetlist[1].tet);
12430 // If tmpkey has been modified, then the failure was not due to
12431 // unflipable configuration, but the non-improvement.
12432 if (key && (tmpkey < *key)) {
12433 *key = tmpkey;
12434 return false;
12435 }
12436 } // if (success)
12437 } // if (doflip)
12438 } // if (ori > 0.0)
12439 } // for (i = 0; i < n; i++)
12440
12441 return false;
12442}
12443
12445// //
12446// removeedgebycombNM() Remove an edge by combining two flipNMs. //
12447// //
12448// Given a set T of tets surrounding edge ab. The premise is that ab can not //
12449// be removed by a flipNM. This routine attempts to remove ab by two flipNMs,//
12450// i.e., first find and flip an edge af (or bf) by flipNM, then flip ab by //
12451// flipNM. If it succeeds, two sets T(ab) and T(af) of tets are replaced by //
12452// a new set T' and both ab and af are not edges in T' anymore. //
12453// //
12454// 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular //
12455// to the screen, such that a lies in front of and b lies behind it. Let the //
12456// projections of the n apexes on the screen in clockwise order are: p_0,...,//
12457// p_n-1, respectively. So the list of tets are: [0]abp_0p_n-1, [1]abp_1p_0, //
12458// ..., [n-1]abp_n-1p_n-2, respectively. //
12459// //
12460// The principle of the approach is: for a face a.b.p_0, check if edge b.p_0 //
12461// is of type N32 (or N44). If it is, then try to do a flipNM on it. If the //
12462// flip is successful, then try to do another flipNM on a.b. If one of the //
12463// two flipNMs fails, restore the old tets as they have never been flipped. //
12464// Then try the next face a.b.p_1. The process can be looped for all faces //
12465// having ab. Stop if ab is removed or all faces have been visited. Note in //
12466// the above description only b.p_0 is considered, a.p_0 is done by swapping //
12467// the position of a and b. //
12468// //
12469// Similar operations have been described in [Joe,1995]. My approach checks //
12470// more cases for finding flips than Joe's. For instance, the cases (1)-(7) //
12471// of Joe only consider abf for finding a flip (T23/T32). My approach looks //
12472// all faces at ab for finding flips. Moreover, the flipNM can flip an edge //
12473// whose star may have more than 3 tets while Joe's only works on 3-tet case.//
12474// //
12475// If ab is removed, 'newtetlist' contains the new tets. Two sets 'abtetlist'//
12476// (n tets) and 'bftetlist' (n1 tets) have been replaced. The number of new //
12477// tets can be calculated by follows: the 1st flip transforms n1 tets into //
12478// (n1 - 2) * 2 new tets, however,one of the new tets goes into the new link //
12479// of ab, i.e., the reduced tet number in Star(ab) is n - 1; the 2nd flip //
12480// transforms n - 1 tets into (n - 3) * 2 new tets. Hence the number of new //
12481// tets are: m = ((n1 - 2) * 2 - 1) + (n - 3) * 2. The old tets are NOT del-//
12482// eted. The caller has the right to delete them or reverse the operation. //
12483// //
12485
12486bool tetgenmesh::removeedgebycombNM(REAL *key, int n, triface *abtetlist,
12487 int *n1, triface *bftetlist, triface *newtetlist, queue *flipque)
12488{
12489 triface tmpabtetlist[11];
12490 triface newfront, oldfront, adjfront;
12491 face checksh;
12492 point pa, pb, p[10];
12493 REAL ori, tmpkey, tmpkey2;
12494 REAL attrib, volume;
12495 bool doflip, success;
12496 int twice, count;
12497 int i, j, k, m;
12498
12499 // Maximal 10 tets in Star(ab).
12500 assert(n <= 10);
12501
12502 // Do the following procedure twice, one for flipping edge b.p_0 and the
12503 // other for p_0.a which is symmetric to the first.
12504 twice = 0;
12505 do {
12506 // Two points a and b are fixed.
12507 pa = org(abtetlist[0]);
12508 pb = dest(abtetlist[0]);
12509 // The points p_0, ..., p_n-1 are permuted in the following loop.
12510 for (i = 0; i < n; i++) {
12511 // Get the n points for the current configuration.
12512 for (j = 0; j < n; j++) {
12513 p[j] = apex(abtetlist[(i + j) % n]);
12514 }
12515 // Check if b.p_0 is of type N32 or N44.
12516 ori = orient3d(pb, p[0], p[1], p[n - 1]);
12517 if ((ori > 0) && (key != (REAL *) NULL)) {
12518 // b.p_0 is not N32. However, it is possible that the tet b.p_0.p_1.
12519 // p_n-1 has worse quality value than the key. In such case, also
12520 // try to flip b.p_0.
12521 tetalldihedral(pb, p[0], p[n - 1], p[1], NULL, &tmpkey, NULL);
12522 if (tmpkey < *key) ori = 0.0;
12523 }
12524 if (ori <= 0.0) {
12525 // b.p_0 is either N32 or N44. Try the 1st flipNM.
12526 bftetlist[0] = abtetlist[i];
12527 enextself(bftetlist[0]);// go to edge b.p_0.
12528 adjustedgering(bftetlist[0], CW); // edge p_0.b.
12529 assert(apex(bftetlist[0]) == pa);
12530 // Form Star(b.p_0).
12531 doflip = true;
12532 *n1 = 0;
12533 do {
12534 // Is the list full?
12535 if (*n1 == 10) break;
12536 if (checksubfaces) {
12537 // Stop if a subface appears.
12538 tspivot(bftetlist[*n1], checksh);
12539 if (checksh.sh != dummysh) {
12540 doflip = false; break;
12541 }
12542 }
12543 // Get the next tet at p_0.b.
12544 fnext(bftetlist[*n1], bftetlist[(*n1) + 1]);
12545 (*n1)++;
12546 } while (apex(bftetlist[*n1]) != pa);
12547 // 2 <= n1 <= 10.
12548 if (doflip) {
12549 success = false;
12550 tmpkey = -1.0; // = acos(pi).
12551 if (key != (REAL *) NULL) tmpkey = *key;
12552 m = 0;
12553 if (*n1 == 3) {
12554 // Three tets case. Try flip32.
12555 success = removeedgebyflip32(&tmpkey,bftetlist,newtetlist,flipque);
12556 m = 2;
12557 } else if ((*n1 > 3) && (*n1 < 7)) {
12558 // Four or more tets case. Try flipNM.
12559 success = removeedgebytranNM(&tmpkey, *n1, bftetlist, newtetlist,
12560 p[1], p[n - 1], flipque);
12561 // If success, the number of new tets.
12562 m = ((*n1) - 2) * 2;
12563 } else {
12564 if (b->verbose > 1) {
12565 printf(" !! Unhandled case: n1 = %d.\n", *n1);
12566 }
12567 }
12568 if (success) {
12569 // b.p_0 is flipped. The link of ab is reduced (by 1), i.e., p_0
12570 // is not on the link of ab. Two old tets a.b.p_0.p_n-1 and
12571 // a.b.p_1.p_0 have been removed from the Star(ab) and one new
12572 // tet t = a.b.p_1.p_n-1 belongs to Star(ab).
12573 // Find t in the 'newtetlist' and remove it from the list.
12574 setpointmark(pa, -pointmark(pa) - 1);
12575 setpointmark(pb, -pointmark(pb) - 1);
12576 assert(m > 0);
12577 for (j = 0; j < m; j++) {
12578 tmpabtetlist[0] = newtetlist[j];
12579 // Does it has ab?
12580 count = 0;
12581 for (k = 0; k < 4; k++) {
12582 if (pointmark((point)(tmpabtetlist[0].tet[4+k])) < 0) count++;
12583 }
12584 if (count == 2) {
12585 // It is. Adjust t to be the edge ab.
12586 for (tmpabtetlist[0].loc = 0; tmpabtetlist[0].loc < 4;
12587 tmpabtetlist[0].loc++) {
12588 if ((oppo(tmpabtetlist[0]) != pa) &&
12589 (oppo(tmpabtetlist[0]) != pb)) break;
12590 }
12591 // The face of t must contain ab.
12592 assert(tmpabtetlist[0].loc < 4);
12593 findedge(&(tmpabtetlist[0]), pa, pb);
12594 break;
12595 }
12596 }
12597 assert(j < m); // The tet must exist.
12598 // Remove t from list. Fill t's position by the last tet.
12599 newtetlist[j] = newtetlist[m - 1];
12600 setpointmark(pa, -(pointmark(pa) + 1));
12601 setpointmark(pb, -(pointmark(pb) + 1));
12602 // Create the temporary Star(ab) for the next flipNM.
12603 adjustedgering(tmpabtetlist[0], CCW);
12604 if (org(tmpabtetlist[0]) != pa) {
12605 fnextself(tmpabtetlist[0]);
12606 esymself(tmpabtetlist[0]);
12607 }
12608#ifdef SELF_CHECK
12609 // Make sure current edge is a->b.
12610 assert(org(tmpabtetlist[0]) == pa);
12611 assert(dest(tmpabtetlist[0]) == pb);
12612 assert(apex(tmpabtetlist[0]) == p[n - 1]);
12613 assert(oppo(tmpabtetlist[0]) == p[1]);
12614#endif // SELF_CHECK
12615 // There are n - 2 left temporary tets.
12616 for (j = 1; j < n - 1; j++) {
12617 maketetrahedron(&(tmpabtetlist[j]));
12618 setorg(tmpabtetlist[j], pa);
12619 setdest(tmpabtetlist[j], pb);
12620 setapex(tmpabtetlist[j], p[j]);
12621 setoppo(tmpabtetlist[j], p[j + 1]);
12622 }
12623 // Transfer the element attributes.
12624 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
12625 attrib = elemattribute(abtetlist[0].tet, j);
12626 for (k = 0; k < n - 1; k++) {
12627 setelemattribute(tmpabtetlist[k].tet, j, attrib);
12628 }
12629 }
12630 // Transfer the volume constraints.
12631 if (b->varvolume && !b->refine) {
12632 volume = volumebound(abtetlist[0].tet);
12633 for (k = 0; k < n - 1; k++) {
12634 setvolumebound(tmpabtetlist[k].tet, volume);
12635 }
12636 }
12637 // Glue n - 1 internal faces of Star(ab).
12638 for (j = 0; j < n - 1; j++) {
12639 fnext(tmpabtetlist[j], newfront);
12640 bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1
12641 }
12642 // Substitute the old tets with the new tets by connecting the
12643 // new tets to the adjacent tets in the mesh. There are (n-2)
12644 // * 2 (outer) faces of the new tets need to be operated.
12645 // Note that the old tets still have the pointers to their
12646 // adjacent tets in the mesh. These pointers can be re-used
12647 // to inverse the substitution.
12648 for (j = 2; j < n; j++) {
12649 // Get an old tet: [j]a.b.p_j.p_j-1, (j > 1).
12650 oldfront = abtetlist[(i + j) % n];
12651 esymself(oldfront);
12652 enextfnextself(oldfront);
12653 // Get an adjacent tet at face: [j]a.p_j.p_j-1.
12654 sym(oldfront, adjfront); // adjfront may be dummy.
12655 // Get the corresponding face from the new tets.
12656 // j >= 2.
12657 enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1
12658 bond(newfront, adjfront);
12659 if (checksubfaces) {
12660 tspivot(oldfront, checksh);
12661 if (checksh.sh != dummysh) {
12662 tsbond(newfront, checksh);
12663 }
12664 }
12665 }
12666 for (j = 2; j < n; j++) {
12667 // Get an old tet: [j]a.b.p_j.p_j-1, (j > 2).
12668 oldfront = abtetlist[(i + j) % n];
12669 esymself(oldfront);
12670 enext2fnextself(oldfront);
12671 // Get an adjacent tet at face: [j]b.p_j.p_j-1.
12672 sym(oldfront, adjfront); // adjfront may be dummy.
12673 // Get the corresponding face from the new tets.
12674 // j >= 2.
12675 enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1
12676 bond(newfront, adjfront);
12677 if (checksubfaces) {
12678 tspivot(oldfront, checksh);
12679 if (checksh.sh != dummysh) {
12680 tsbond(newfront, checksh);
12681 }
12682 }
12683 }
12684 // Adjust the faces in the temporary new tets at ab for
12685 // recursively processing on the n-1 tets.
12686 for (j = 0; j < n - 1; j++) {
12687 fnextself(tmpabtetlist[j]);
12688 }
12689 tmpkey2 = -1;
12690 if (key) tmpkey2 = *key;
12691 if ((n - 1) == 3) {
12692 success = removeedgebyflip32(&tmpkey2, tmpabtetlist,
12693 &(newtetlist[m - 1]), flipque);
12694 } else { // assert((n - 1) >= 4);
12695 success = removeedgebytranNM(&tmpkey2, n - 1, tmpabtetlist,
12696 &(newtetlist[m - 1]), NULL, NULL, flipque);
12697 }
12698 // No matter it was success or not, delete the temporary tets.
12699 for (j = 0; j < n - 1; j++) {
12700 tetrahedrondealloc(tmpabtetlist[j].tet);
12701 }
12702 if (success) {
12703 // The new configuration is good.
12704 // Do not delete the old tets.
12705 // for (j = 0; j < n; j++) {
12706 // tetrahedrondealloc(abtetlist[j].tet);
12707 // }
12708 // Return the bigger dihedral in the two sets of new tets.
12709 if (key != (REAL *) NULL) {
12710 *key = tmpkey2 < tmpkey ? tmpkey2 : tmpkey;
12711 }
12712 return true;
12713 } else {
12714 // The new configuration is bad, substitue back the old tets.
12715 for (j = 0; j < n; j++) {
12716 oldfront = abtetlist[(i + j) % n];
12717 esymself(oldfront);
12718 enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1.
12719 sym(oldfront, adjfront); // adjfront may be dummy.
12720 bond(oldfront, adjfront);
12721 if (checksubfaces) {
12722 tspivot(oldfront, checksh);
12723 if (checksh.sh != dummysh) {
12724 tsbond(oldfront, checksh);
12725 }
12726 }
12727 }
12728 for (j = 0; j < n; j++) {
12729 oldfront = abtetlist[(i + j) % n];
12730 esymself(oldfront);
12731 enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
12732 sym(oldfront, adjfront); // adjfront may be dummy
12733 bond(oldfront, adjfront);
12734 if (checksubfaces) {
12735 tspivot(oldfront, checksh);
12736 if (checksh.sh != dummysh) {
12737 tsbond(oldfront, checksh);
12738 }
12739 }
12740 }
12741 // Substitute back the old tets of the first flip.
12742 for (j = 0; j < *n1; j++) {
12743 oldfront = bftetlist[j];
12744 esymself(oldfront);
12745 enextfnextself(oldfront);
12746 sym(oldfront, adjfront); // adjfront may be dummy.
12747 bond(oldfront, adjfront);
12748 if (checksubfaces) {
12749 tspivot(oldfront, checksh);
12750 if (checksh.sh != dummysh) {
12751 tsbond(oldfront, checksh);
12752 }
12753 }
12754 }
12755 for (j = 0; j < *n1; j++) {
12756 oldfront = bftetlist[j];
12757 esymself(oldfront);
12758 enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
12759 sym(oldfront, adjfront); // adjfront may be dummy
12760 bond(oldfront, adjfront);
12761 if (checksubfaces) {
12762 tspivot(oldfront, checksh);
12763 if (checksh.sh != dummysh) {
12764 tsbond(oldfront, checksh);
12765 }
12766 }
12767 }
12768 // Delete the new tets of the first flip. Note that one new
12769 // tet has already been removed from the list.
12770 for (j = 0; j < m - 1; j++) {
12771 tetrahedrondealloc(newtetlist[j].tet);
12772 }
12773 } // if (success)
12774 } // if (success)
12775 } // if (doflip)
12776 } // if (ori <= 0.0)
12777 } // for (i = 0; i < n; i++)
12778 // Inverse a and b and the tets configuration.
12779 for (i = 0; i < n; i++) newtetlist[i] = abtetlist[i];
12780 for (i = 0; i < n; i++) {
12781 oldfront = newtetlist[n - i - 1];
12782 esymself(oldfront);
12783 fnextself(oldfront);
12784 abtetlist[i] = oldfront;
12785 }
12786 twice++;
12787 } while (twice < 2);
12788
12789 return false;
12790}
12791
12793// //
12794// splittetrahedron() Insert a point into a tetrahedron, split it into //
12795// four tetrahedra. //
12796// //
12797// The tetrahedron is given by 'splittet'. Let it is abcd. The inserting //
12798// point 'newpoint' v should lie strictly inside abcd. //
12799// //
12800// Splitting a tetrahedron is to shrink abcd to abcv, and create three new //
12801// tetrahedra badv, cbdv, and acdv. //
12802// //
12803// On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it //
12804// contains all possibly non-locally Delaunay faces. //
12805// //
12807
12808void tetgenmesh::splittetrahedron(point newpoint, triface* splittet,
12809 queue* flipqueue)
12810{
12811 triface oldabd, oldbcd, oldcad; // Old configuration.
12812 triface abdcasing, bcdcasing, cadcasing;
12813 face abdsh, bcdsh, cadsh;
12814 triface abcv, badv, cbdv, acdv; // New configuration.
12815 triface worktet;
12816 face abseg, bcseg, caseg;
12817 face adseg, bdseg, cdseg;
12818 point pa, pb, pc, pd;
12819 REAL attrib, volume;
12820 int i;
12821
12822 abcv = *splittet;
12823 abcv.ver = 0;
12824 // Set the changed vertices and new tetrahedron.
12825 pa = org(abcv);
12826 pb = dest(abcv);
12827 pc = apex(abcv);
12828 pd = oppo(abcv);
12829
12830 if (b->verbose > 1) {
12831 printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n",
12832 pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc),
12833 pointmark(pd));
12834 }
12835
12836 fnext(abcv, oldabd);
12837 enextfnext(abcv, oldbcd);
12838 enext2fnext(abcv, oldcad);
12839 sym(oldabd, abdcasing);
12840 sym(oldbcd, bcdcasing);
12841 sym(oldcad, cadcasing);
12842 maketetrahedron(&badv);
12843 maketetrahedron(&cbdv);
12844 maketetrahedron(&acdv);
12845
12846 // Set 'badv' vertices.
12847 setorg (badv, pb);
12848 setdest(badv, pa);
12849 setapex(badv, pd);
12850 setoppo(badv, newpoint);
12851 // Set 'cbdv' vertices.
12852 setorg (cbdv, pc);
12853 setdest(cbdv, pb);
12854 setapex(cbdv, pd);
12855 setoppo(cbdv, newpoint);
12856 // Set 'acdv' vertices.
12857 setorg (acdv, pa);
12858 setdest(acdv, pc);
12859 setapex(acdv, pd);
12860 setoppo(acdv, newpoint);
12861 // Set 'abcv' vertices
12862 setoppo(abcv, newpoint);
12863
12864 // Set the element attributes of the new tetrahedra.
12865 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
12866 attrib = elemattribute(abcv.tet, i);
12867 setelemattribute(badv.tet, i, attrib);
12868 setelemattribute(cbdv.tet, i, attrib);
12869 setelemattribute(acdv.tet, i, attrib);
12870 }
12871 // Set the volume constraint of the new tetrahedra.
12872 if (b->varvolume) {
12873 volume = volumebound(abcv.tet);
12874 setvolumebound(badv.tet, volume);
12875 setvolumebound(cbdv.tet, volume);
12876 setvolumebound(acdv.tet, volume);
12877 }
12878
12879 // Bond the new triangles to the surrounding tetrahedron.
12880 bond(badv, abdcasing);
12881 bond(cbdv, bcdcasing);
12882 bond(acdv, cadcasing);
12883 // There may exist subfaces need to be bonded to the new tetrahedra.
12884 if (checksubfaces) {
12885 tspivot(oldabd, abdsh);
12886 if (abdsh.sh != dummysh) {
12887 tsdissolve(oldabd);
12888 tsbond(badv, abdsh);
12889 }
12890 tspivot(oldbcd, bcdsh);
12891 if (bcdsh.sh != dummysh) {
12892 tsdissolve(oldbcd);
12893 tsbond(cbdv, bcdsh);
12894 }
12895 tspivot(oldcad, cadsh);
12896 if (cadsh.sh != dummysh) {
12897 tsdissolve(oldcad);
12898 tsbond(acdv, cadsh);
12899 }
12900 } else if (checksubsegs) {
12901 tsspivot1(abcv, abseg);
12902 if (abseg.sh != dummysh) {
12903 tssbond1(badv, abseg);
12904 }
12905 enext(abcv, worktet);
12906 tsspivot1(worktet, bcseg);
12907 if (bcseg.sh != dummysh) {
12908 tssbond1(cbdv, bcseg);
12909 }
12910 enext2(abcv, worktet);
12911 tsspivot1(worktet, caseg);
12912 if (caseg.sh != dummysh) {
12913 tssbond1(acdv, caseg);
12914 }
12915 fnext(abcv, worktet);
12916 enext2self(worktet);
12917 tsspivot1(worktet, adseg);
12918 if (adseg.sh != dummysh) {
12919 tssdissolve1(worktet);
12920 enext(badv, worktet);
12921 tssbond1(worktet, adseg);
12922 enext2(acdv, worktet);
12923 tssbond1(worktet, adseg);
12924 }
12925 enextfnext(abcv, worktet);
12926 enext2self(worktet);
12927 tsspivot1(worktet, bdseg);
12928 if (bdseg.sh != dummysh) {
12929 tssdissolve1(worktet);
12930 enext(cbdv, worktet);
12931 tssbond1(worktet, bdseg);
12932 enext2(badv, worktet);
12933 tssbond1(worktet, bdseg);
12934 }
12935 enext2fnext(abcv, worktet);
12936 enext2self(worktet);
12937 tsspivot1(worktet, cdseg);
12938 if (cdseg.sh != dummysh) {
12939 tssdissolve1(worktet);
12940 enext(acdv, worktet);
12941 tssbond1(worktet, cdseg);
12942 enext2(cbdv, worktet);
12943 tssbond1(worktet, cdseg);
12944 }
12945 }
12946 badv.loc = 3;
12947 cbdv.loc = 2;
12948 bond(badv, cbdv);
12949 cbdv.loc = 3;
12950 acdv.loc = 2;
12951 bond(cbdv, acdv);
12952 acdv.loc = 3;
12953 badv.loc = 2;
12954 bond(acdv, badv);
12955 badv.loc = 1;
12956 bond(badv, oldabd);
12957 cbdv.loc = 1;
12958 bond(cbdv, oldbcd);
12959 acdv.loc = 1;
12960 bond(acdv, oldcad);
12961
12962 badv.loc = 0;
12963 cbdv.loc = 0;
12964 acdv.loc = 0;
12965 if (b->verbose > 3) {
12966 printf(" Updating abcv ");
12967 printtet(&abcv);
12968 printf(" Creating badv ");
12969 printtet(&badv);
12970 printf(" Creating cbdv ");
12971 printtet(&cbdv);
12972 printf(" Creating acdv ");
12973 printtet(&acdv);
12974 }
12975
12976 if (flipqueue != (queue *) NULL) {
12977 enqueueflipface(abcv, flipqueue);
12978 enqueueflipface(badv, flipqueue);
12979 enqueueflipface(cbdv, flipqueue);
12980 enqueueflipface(acdv, flipqueue);
12981 }
12982
12983 // Save a handle for quick point location.
12984 recenttet = abcv;
12985 // Set the return handle be abcv.
12986 *splittet = abcv;
12987}
12988
12990// //
12991// unsplittetrahedron() Reverse the operation of inserting a point into a //
12992// tetrahedron, so as to remove the newly inserted //
12993// point from the mesh. //
12994// //
12995// Assume the origional tetrahedron is abcd, it was split by v into four //
12996// tetrahedra abcv, badv, cbdv, and acdv. 'splittet' represents face abc of //
12997// abcv (i.e., its opposite is v). //
12998// //
12999// Point v is removed by expanding abcv to abcd, deleting three tetrahedra //
13000// badv, cbdv and acdv. On return, point v is not deleted in this routine. //
13001// //
13003
13004void tetgenmesh::unsplittetrahedron(triface* splittet)
13005{
13006 triface abcv, badv, cbdv, acdv;
13007 triface oldabv, oldbcv, oldcav;
13008 triface badcasing, cbdcasing, acdcasing;
13009 face badsh, cbdsh, acdsh;
13010
13011 abcv = *splittet;
13012 adjustedgering(abcv, CCW); // for sure.
13013 fnext(abcv, oldabv);
13014 fnext(oldabv, badv);
13015 esymself(badv);
13016 enextfnext(abcv, oldbcv);
13017 fnext(oldbcv, cbdv);
13018 esymself(cbdv);
13019 enext2fnext(abcv, oldcav);
13020 fnext(oldcav, acdv);
13021 esymself(acdv);
13022
13023 if (b->verbose > 1) {
13024 printf(" Removing point %d in tetrahedron (%d, %d, %d, %d).\n",
13025 pointmark(oppo(abcv)), pointmark(org(abcv)), pointmark(dest(abcv)),
13026 pointmark(apex(abcv)), pointmark(apex(badv)));
13027 }
13028
13029 sym(badv, badcasing);
13030 tspivot(badv, badsh);
13031 sym(cbdv, cbdcasing);
13032 tspivot(cbdv, cbdsh);
13033 sym(acdv, acdcasing);
13034 tspivot(acdv, acdsh);
13035
13036 // Expanding abcv to abcd.
13037 setoppo(abcv, apex(badv));
13038 bond(oldabv, badcasing);
13039 if (badsh.sh != dummysh) {
13040 tsbond(oldabv, badsh);
13041 }
13042 bond(oldbcv, cbdcasing);
13043 if (cbdsh.sh != dummysh) {
13044 tsbond(oldbcv, cbdsh);
13045 }
13046 bond(oldcav, acdcasing);
13047 if (acdsh.sh != dummysh) {
13048 tsbond(oldcav, acdsh);
13049 }
13050
13051 // Delete the three split-out tetrahedra.
13052 tetrahedrondealloc(badv.tet);
13053 tetrahedrondealloc(cbdv.tet);
13054 tetrahedrondealloc(acdv.tet);
13055}
13056
13058// //
13059// splittetface() Insert a point on a face of a mesh. //
13060// //
13061// 'splittet' is the splitting face. Let it is abcd, where abc is the face //
13062// will be split. If abc is not a hull face, abce is the tetrahedron at the //
13063// opposite of d. //
13064// //
13065// To split face abc by a point v is to shrink the tetrahedra abcd to abvd, //
13066// create two new tetrahedra bcvd, cavd. If abc is not a hull face, shrink //
13067// the tetrahedra bace to bave, create two new tetrahedra cbve, acve. //
13068// //
13069// If abc is a subface, it is split into three subfaces simultaneously by //
13070// calling routine splitsubface(), hence, abv, bcv, cav. The edge rings of //
13071// the split subfaces have the same orientation as abc's. //
13072// //
13073// On completion, 'splittet' returns abvd. If 'flipqueue' is not NULL, it //
13074// contains all possibly non-locally Delaunay faces. //
13075// //
13077
13078void tetgenmesh::splittetface(point newpoint, triface* splittet,
13079 queue* flipqueue)
13080{
13081 triface abcd, bace; // Old configuration.
13082 triface oldbcd, oldcad, oldace, oldcbe;
13083 triface bcdcasing, cadcasing, acecasing, cbecasing;
13084 face abcsh, bcdsh, cadsh, acesh, cbesh;
13085 triface abvd, bcvd, cavd, bave, cbve, acve; // New configuration.
13086 triface worktet;
13087 face bcseg, caseg;
13088 face adseg, bdseg, cdseg;
13089 face aeseg, beseg, ceseg;
13090 point pa, pb, pc, pd, pe;
13091 REAL attrib, volume;
13092 bool mirrorflag;
13093 int i;
13094
13095 abcd = *splittet;
13096 // abcd.ver = 0; // Adjust to be CCW edge ring.
13097 adjustedgering(abcd, CCW);
13098 pa = org(abcd);
13099 pb = dest(abcd);
13100 pc = apex(abcd);
13101 pd = oppo(abcd);
13102 pe = (point) NULL; // avoid a compile warning.
13103 // Is there a second tetrahderon?
13104 mirrorflag = issymexist(&abcd);
13105 if (mirrorflag) {
13106 // This is an interior face.
13107 sym(abcd, bace);
13108 findedge(&bace, dest(abcd), org(abcd));
13109 pe = oppo(bace);
13110 }
13111 if (checksubfaces) {
13112 // Is there a subface need to be split together?
13113 tspivot(abcd, abcsh);
13114 if (abcsh.sh != dummysh) {
13115 // Exists! Keep the edge ab of both handles be the same.
13116 findedge(&abcsh, org(abcd), dest(abcd));
13117 }
13118 }
13119
13120 if (b->verbose > 1) {
13121 printf(" Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint),
13122 pointmark(pa), pointmark(pb), pointmark(pc));
13123 }
13124
13125 // Save the old configuration at faces bcd and cad.
13126 enextfnext(abcd, oldbcd);
13127 enext2fnext(abcd, oldcad);
13128 sym(oldbcd, bcdcasing);
13129 sym(oldcad, cadcasing);
13130 // Create two new tetrahedra.
13131 maketetrahedron(&bcvd);
13132 maketetrahedron(&cavd);
13133 if (mirrorflag) {
13134 // Save the old configuration at faces bce and cae.
13135 enextfnext(bace, oldace);
13136 enext2fnext(bace, oldcbe);
13137 sym(oldace, acecasing);
13138 sym(oldcbe, cbecasing);
13139 // Create two new tetrahedra.
13140 maketetrahedron(&acve);
13141 maketetrahedron(&cbve);
13142 } else {
13143 // Splitting a boundary face increases the number of boundary faces.
13144 hullsize += 2;
13145 }
13146
13147 // Set vertices to the changed tetrahedron and new tetrahedra.
13148 abvd = abcd; // Update 'abcd' to 'abvd'.
13149 setapex(abvd, newpoint);
13150 setorg (bcvd, pb); // Set 'bcvd'.
13151 setdest(bcvd, pc);
13152 setapex(bcvd, newpoint);
13153 setoppo(bcvd, pd);
13154 setorg (cavd, pc); // Set 'cavd'.
13155 setdest(cavd, pa);
13156 setapex(cavd, newpoint);
13157 setoppo(cavd, pd);
13158 // Set the element attributes of the new tetrahedra.
13159 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
13160 attrib = elemattribute(abvd.tet, i);
13161 setelemattribute(bcvd.tet, i, attrib);
13162 setelemattribute(cavd.tet, i, attrib);
13163 }
13164 if (b->varvolume) {
13165 // Set the area constraint of the new tetrahedra.
13166 volume = volumebound(abvd.tet);
13167 setvolumebound(bcvd.tet, volume);
13168 setvolumebound(cavd.tet, volume);
13169 }
13170 if (mirrorflag) {
13171 bave = bace; // Update 'bace' to 'bave'.
13172 setapex(bave, newpoint);
13173 setorg (acve, pa); // Set 'acve'.
13174 setdest(acve, pc);
13175 setapex(acve, newpoint);
13176 setoppo(acve, pe);
13177 setorg (cbve, pc); // Set 'cbve'.
13178 setdest(cbve, pb);
13179 setapex(cbve, newpoint);
13180 setoppo(cbve, pe);
13181 // Set the element attributes of the new tetrahedra.
13182 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
13183 attrib = elemattribute(bave.tet, i);
13184 setelemattribute(acve.tet, i, attrib);
13185 setelemattribute(cbve.tet, i, attrib);
13186 }
13187 if (b->varvolume) {
13188 // Set the area constraint of the new tetrahedra.
13189 volume = volumebound(bave.tet);
13190 setvolumebound(acve.tet, volume);
13191 setvolumebound(cbve.tet, volume);
13192 }
13193 }
13194
13195 // Bond the new tetrahedra to the surrounding tetrahedra.
13196 bcvd.loc = 1;
13197 bond(bcvd, bcdcasing);
13198 cavd.loc = 1;
13199 bond(cavd, cadcasing);
13200 bcvd.loc = 3;
13201 bond(bcvd, oldbcd);
13202 cavd.loc = 2;
13203 bond(cavd, oldcad);
13204 bcvd.loc = 2;
13205 cavd.loc = 3;
13206 bond(bcvd, cavd);
13207 if (mirrorflag) {
13208 acve.loc = 1;
13209 bond(acve, acecasing);
13210 cbve.loc = 1;
13211 bond(cbve, cbecasing);
13212 acve.loc = 3;
13213 bond(acve, oldace);
13214 cbve.loc = 2;
13215 bond(cbve, oldcbe);
13216 acve.loc = 2;
13217 cbve.loc = 3;
13218 bond(acve, cbve);
13219 // Bond two new coplanar facets.
13220 bcvd.loc = 0;
13221 cbve.loc = 0;
13222 bond(bcvd, cbve);
13223 cavd.loc = 0;
13224 acve.loc = 0;
13225 bond(cavd, acve);
13226 }
13227
13228 // There may exist subface needed to be bonded to the new tetrahedra.
13229 if (checksubfaces) {
13230 tspivot(oldbcd, bcdsh);
13231 if (bcdsh.sh != dummysh) {
13232 tsdissolve(oldbcd);
13233 bcvd.loc = 1;
13234 tsbond(bcvd, bcdsh);
13235 }
13236 tspivot(oldcad, cadsh);
13237 if (cadsh.sh != dummysh) {
13238 tsdissolve(oldcad);
13239 cavd.loc = 1;
13240 tsbond(cavd, cadsh);
13241 }
13242 if (mirrorflag) {
13243 tspivot(oldace, acesh);
13244 if (acesh.sh != dummysh) {
13245 tsdissolve(oldace);
13246 acve.loc = 1;
13247 tsbond(acve, acesh);
13248 }
13249 tspivot(oldcbe, cbesh);
13250 if (cbesh.sh != dummysh) {
13251 tsdissolve(oldcbe);
13252 cbve.loc = 1;
13253 tsbond(cbve, cbesh);
13254 }
13255 }
13256 // Is there a subface needs to be split together?
13257 if (abcsh.sh != dummysh) {
13258 // Split this subface 'abc' into three i.e, abv, bcv, cav.
13259 splitsubface(newpoint, &abcsh, (queue *) NULL);
13260 }
13261 } else if (checksubsegs) {
13262 // abvd.loc = abvd.ver = 0;
13263 bcvd.loc = bcvd.ver = 0;
13264 cavd.loc = cavd.ver = 0;
13265 if (mirrorflag) {
13266 // bave.loc = bave.ver = 0;
13267 cbve.loc = cbve.ver = 0;
13268 acve.loc = acve.ver = 0;
13269 }
13270 enext(abvd, worktet);
13271 tsspivot1(worktet, bcseg);
13272 if (bcseg.sh != dummysh) {
13273 tssdissolve1(worktet);
13274 tssbond1(bcvd, bcseg);
13275 if (mirrorflag) {
13276 enext2(bave, worktet);
13277 tssdissolve1(worktet);
13278 tssbond1(cbve, bcseg);
13279 }
13280 }
13281 enext2(abvd, worktet);
13282 tsspivot1(worktet, caseg);
13283 if (caseg.sh != dummysh) {
13284 tssdissolve1(worktet);
13285 tssbond1(cavd, caseg);
13286 if (mirrorflag) {
13287 enext(bave, worktet);
13288 tssdissolve1(worktet);
13289 tssbond1(acve, caseg);
13290 }
13291 }
13292 fnext(abvd, worktet);
13293 enext2self(worktet);
13294 tsspivot1(worktet, adseg);
13295 if (adseg.sh != dummysh) {
13296 fnext(cavd, worktet);
13297 enextself(worktet);
13298 tssbond1(worktet, adseg);
13299 }
13300 fnext(abvd, worktet);
13301 enextself(worktet);
13302 tsspivot1(worktet, bdseg);
13303 if (bdseg.sh != dummysh) {
13304 fnext(bcvd, worktet);
13305 enext2self(worktet);
13306 tssbond1(worktet, bdseg);
13307 }
13308 enextfnext(abvd, worktet);
13309 enextself(worktet);
13310 tsspivot1(worktet, cdseg);
13311 if (cdseg.sh != dummysh) {
13312 tssdissolve1(worktet);
13313 fnext(bcvd, worktet);
13314 enextself(worktet);
13315 tssbond1(worktet, cdseg);
13316 fnext(cavd, worktet);
13317 enext2self(worktet);
13318 tssbond1(worktet, cdseg);
13319 }
13320 if (mirrorflag) {
13321 fnext(bave, worktet);
13322 enextself(worktet);
13323 tsspivot1(worktet, aeseg);
13324 if (aeseg.sh != dummysh) {
13325 fnext(acve, worktet);
13326 enext2self(worktet);
13327 tssbond1(worktet, aeseg);
13328 }
13329 fnext(bave, worktet);
13330 enext2self(worktet);
13331 tsspivot1(worktet, beseg);
13332 if (beseg.sh != dummysh) {
13333 fnext(cbve, worktet);
13334 enextself(worktet);
13335 tssbond1(worktet, beseg);
13336 }
13337 enextfnext(bave, worktet);
13338 enextself(worktet);
13339 tsspivot1(worktet, ceseg);
13340 if (ceseg.sh != dummysh) {
13341 tssdissolve1(worktet);
13342 fnext(cbve, worktet);
13343 enext2self(worktet);
13344 tssbond1(worktet, ceseg);
13345 fnext(acve, worktet);
13346 enextself(worktet);
13347 tssbond1(worktet, ceseg);
13348 }
13349 }
13350 }
13351
13352 // Save a handle for quick point location.
13353 recenttet = abvd;
13354 // Set the return handle be abvd.
13355 *splittet = abvd;
13356
13357 bcvd.loc = 0;
13358 cavd.loc = 0;
13359 if (mirrorflag) {
13360 cbve.loc = 0;
13361 acve.loc = 0;
13362 }
13363 if (b->verbose > 3) {
13364 printf(" Updating abvd ");
13365 printtet(&abvd);
13366 printf(" Creating bcvd ");
13367 printtet(&bcvd);
13368 printf(" Creating cavd ");
13369 printtet(&cavd);
13370 if (mirrorflag) {
13371 printf(" Updating bave ");
13372 printtet(&bave);
13373 printf(" Creating cbve ");
13374 printtet(&cbve);
13375 printf(" Creating acve ");
13376 printtet(&acve);
13377 }
13378 }
13379
13380 if (flipqueue != (queue *) NULL) {
13381 fnextself(abvd);
13382 enqueueflipface(abvd, flipqueue);
13383 fnextself(bcvd);
13384 enqueueflipface(bcvd, flipqueue);
13385 fnextself(cavd);
13386 enqueueflipface(cavd, flipqueue);
13387 if (mirrorflag) {
13388 fnextself(bave);
13389 enqueueflipface(bave, flipqueue);
13390 fnextself(cbve);
13391 enqueueflipface(cbve, flipqueue);
13392 fnextself(acve);
13393 enqueueflipface(acve, flipqueue);
13394 }
13395 }
13396}
13397
13399// //
13400// unsplittetface() Reverse the operation of inserting a point on a face, //
13401// so as to remove the newly inserted point. //
13402// //
13403// Assume the original face is abc, the tetrahedron containing abc is abcd. //
13404// If abc is not a hull face, bace is the tetrahedron at the opposite of d. //
13405// After face abc was split by a point v, tetrahedron abcd had been split //
13406// into three tetrahedra, abvd, bcvd, cavd, and bace (if it exists) had been //
13407// split into bave, cbve, acve. 'splittet' represents abvd (its apex is v). //
13408// //
13409// Point v is removed by expanding abvd to abcd, deleting two tetrahedra //
13410// bcvd, cavd. Expanding bave(if it exists) to bace, deleting two tetrahedra //
13411// cbve, acve. If abv is a subface, routine unsplitsubface() will be called //
13412// to reverse the operation of splitting a subface. On completion, point v //
13413// is not deleted in this routine. //
13414// //
13416
13417void tetgenmesh::unsplittetface(triface* splittet)
13418{
13419 triface abvd, bcvd, cavd, bave, cbve, acve;
13420 triface oldbvd, oldvad, oldvbe, oldave;
13421 triface bcdcasing, cadcasing, cbecasing, acecasing;
13422 face bcdsh, cadsh, cbesh, acesh;
13423 face abvsh;
13424 bool mirrorflag;
13425
13426 abvd = *splittet;
13427 adjustedgering(abvd, CCW); // for sure.
13428 enextfnext(abvd, oldbvd);
13429 fnext(oldbvd, bcvd);
13430 esymself(bcvd);
13431 enextself(bcvd);
13432 enext2fnext(abvd, oldvad);
13433 fnext(oldvad, cavd);
13434 esymself(cavd);
13435 enext2self(cavd);
13436 // Is there a second tetrahedron?
13437 sym(abvd, bave);
13438 mirrorflag = bave.tet != dummytet;
13439 if (mirrorflag) {
13440 findedge(&bave, dest(abvd), org(abvd));
13441 enextfnext(bave, oldave);
13442 fnext(oldave, acve);
13443 esymself(acve);
13444 enextself(acve);
13445 enext2fnext(bave, oldvbe);
13446 fnext(oldvbe, cbve);
13447 esymself(cbve);
13448 enext2self(cbve);
13449 } else {
13450 // Unsplit a hull face decrease the number of boundary faces.
13451 hullsize -= 2;
13452 }
13453 // Is there a subface at abv.
13454 tspivot(abvd, abvsh);
13455 if (abvsh.sh != dummysh) {
13456 // Exists! Keep the edge ab of both handles be the same.
13457 findedge(&abvsh, org(abvd), dest(abvd));
13458 }
13459
13460 if (b->verbose > 1) {
13461 printf(" Removing point %d on face (%d, %d, %d).\n",
13462 pointmark(apex(abvd)), pointmark(org(abvd)), pointmark(dest(abvd)),
13463 pointmark(dest(bcvd)));
13464 }
13465
13466 fnextself(bcvd); // bcvd has changed to bcdv.
13467 sym(bcvd, bcdcasing);
13468 tspivot(bcvd, bcdsh);
13469 fnextself(cavd); // cavd has changed to cadv.
13470 sym(cavd, cadcasing);
13471 tspivot(cavd, cadsh);
13472 if (mirrorflag) {
13473 fnextself(acve); // acve has changed to acev.
13474 sym(acve, acecasing);
13475 tspivot(acve, acesh);
13476 fnextself(cbve); // cbve has changed to cbev.
13477 sym(cbve, cbecasing);
13478 tspivot(cbve, cbesh);
13479 }
13480
13481 // Expand abvd to abcd.
13482 setapex(abvd, dest(bcvd));
13483 bond(oldbvd, bcdcasing);
13484 if (bcdsh.sh != dummysh) {
13485 tsbond(oldbvd, bcdsh);
13486 }
13487 bond(oldvad, cadcasing);
13488 if (cadsh.sh != dummysh) {
13489 tsbond(oldvad, cadsh);
13490 }
13491 if (mirrorflag) {
13492 // Expanding bave to bace.
13493 setapex(bave, dest(acve));
13494 bond(oldave, acecasing);
13495 if (acesh.sh != dummysh) {
13496 tsbond(oldave, acesh);
13497 }
13498 bond(oldvbe, cbecasing);
13499 if (cbesh.sh != dummysh) {
13500 tsbond(oldvbe, cbesh);
13501 }
13502 }
13503
13504 // Unsplit a subface if there exists.
13505 if (abvsh.sh != dummysh) {
13506 unsplitsubface(&abvsh);
13507 }
13508
13509 // Delete the split-out tetrahedra.
13510 tetrahedrondealloc(bcvd.tet);
13511 tetrahedrondealloc(cavd.tet);
13512 if (mirrorflag) {
13513 tetrahedrondealloc(acve.tet);
13514 tetrahedrondealloc(cbve.tet);
13515 }
13516}
13517
13519// //
13520// splitsubface() Insert a point on a subface, split it into three. //
13521// //
13522// The subface is 'splitface'. Let it is abc. The inserting point 'newpoint'//
13523// v should lie inside abc. If the neighbor tetrahedra of abc exist, i.e., //
13524// abcd and bace, they should have been split by routine splittetface() //
13525// before calling this routine, so the connection between the new tetrahedra //
13526// and new subfaces can be correctly set. //
13527// //
13528// To split subface abc by point v is to shrink abc to abv, create two new //
13529// subfaces bcv and cav. Set the connection between updated and new created //
13530// subfaces. If there is a subsegment at edge bc or ca, connection of new //
13531// subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is //
13532// the predecessor and 'casingout' is the successor. It is important to keep //
13533// the orientations of the edge rings of the updated and created subfaces be //
13534// the same as abc's. So they have the same orientation as other subfaces of //
13535// this facet with respect to the lift point of this facet. //
13536// //
13537// On completion, 'splitface' returns abv. If 'flipqueue' is not NULL, it //
13538// returns all possibly non-Delaunay edges. //
13539// //
13541
13542void tetgenmesh::splitsubface(point newpoint, face* splitface,
13543 queue* flipqueue)
13544{
13545 triface abvd, bcvd, cavd, bave, cbve, acve;
13546 face abc, oldbc, oldca, bc, ca, spinsh;
13547 face bccasin, bccasout, cacasin, cacasout;
13548 face abv, bcv, cav;
13549 point pa, pb, pc;
13550
13551 abc = *splitface;
13552 // The newly created subfaces will have the same edge ring as abc.
13553 adjustedgering(abc, CCW);
13554 pa = sorg(abc);
13555 pb = sdest(abc);
13556 pc = sapex(abc);
13557
13558 if (b->verbose > 1) {
13559 printf(" Inserting point %d on subface (%d, %d, %d).\n",
13560 pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc));
13561 }
13562
13563 // Save the old configuration at edge bc and ca. Subsegments may appear
13564 // at both sides, save the face links and dissolve them.
13565 senext(abc, oldbc);
13566 senext2(abc, oldca);
13567 spivot(oldbc, bccasout);
13568 sspivot(oldbc, bc);
13569 if (bc.sh != dummysh) {
13570 if (oldbc.sh != bccasout.sh) {
13571 // 'oldbc' is not self-bonded.
13572 spinsh = bccasout;
13573 do {
13574 bccasin = spinsh;
13575 spivotself(spinsh);
13576 } while (spinsh.sh != oldbc.sh);
13577 } else {
13578 bccasout.sh = dummysh;
13579 }
13580 ssdissolve(oldbc);
13581 }
13582 spivot(oldca, cacasout);
13583 sspivot(oldca, ca);
13584 if (ca.sh != dummysh) {
13585 if (oldca.sh != cacasout.sh) {
13586 // 'oldca' is not self-bonded.
13587 spinsh = cacasout;
13588 do {
13589 cacasin = spinsh;
13590 spivotself(spinsh);
13591 } while (spinsh.sh != oldca.sh);
13592 } else {
13593 cacasout.sh = dummysh;
13594 }
13595 ssdissolve(oldca);
13596 }
13597 // Create two new subfaces.
13598 makeshellface(subfaces, &bcv);
13599 makeshellface(subfaces, &cav);
13600
13601 // Set the vertices of changed and new subfaces.
13602 abv = abc; // Update 'abc' to 'abv'.
13603 setsapex(abv, newpoint);
13604 setsorg(bcv, pb); // Set 'bcv'.
13605 setsdest(bcv, pc);
13606 setsapex(bcv, newpoint);
13607 setsorg(cav, pc); // Set 'cav'.
13608 setsdest(cav, pa);
13609 setsapex(cav, newpoint);
13610 if (b->quality && varconstraint) {
13611 // Copy yhr area bound into the new subfaces.
13612 setareabound(bcv, areabound(abv));
13613 setareabound(cav, areabound(abv));
13614 }
13615 // Copy the boundary mark into the new subfaces.
13616 setshellmark(bcv, shellmark(abv));
13617 setshellmark(cav, shellmark(abv));
13618 // Copy the subface type into the new subfaces.
13619 setshelltype(bcv, shelltype(abv));
13620 setshelltype(cav, shelltype(abv));
13621 if (checkpbcs) {
13622 // Copy the pbcgroup into the new subfaces.
13623 setshellpbcgroup(bcv, shellpbcgroup(abv));
13624 setshellpbcgroup(cav, shellpbcgroup(abv));
13625 }
13626 // Bond the new subfaces to the surrounding subfaces.
13627 if (bc.sh != dummysh) {
13628 if (bccasout.sh != dummysh) {
13629 sbond1(bccasin, bcv);
13630 sbond1(bcv, bccasout);
13631 } else {
13632 // Bond 'bcv' to itsself.
13633 sbond(bcv, bcv);
13634 }
13635 ssbond(bcv, bc);
13636 } else {
13637 sbond(bcv, bccasout);
13638 }
13639 if (ca.sh != dummysh) {
13640 if (cacasout.sh != dummysh) {
13641 sbond1(cacasin, cav);
13642 sbond1(cav, cacasout);
13643 } else {
13644 // Bond 'cav' to itself.
13645 sbond(cav, cav);
13646 }
13647 ssbond(cav, ca);
13648 } else {
13649 sbond(cav, cacasout);
13650 }
13651 senext2self(bcv);
13652 sbond(bcv, oldbc);
13653 senextself(cav);
13654 sbond(cav, oldca);
13655 senext2self(bcv);
13656 senextself(cav);
13657 sbond(bcv, cav);
13658
13659 // Bond the new subfaces to the new tetrahedra if they exist.
13660 stpivot(abv, abvd);
13661 if (abvd.tet != dummytet) {
13662 // Get two new tetrahedra and their syms.
13663 findedge(&abvd, sorg(abv), sdest(abv));
13664 enextfnext(abvd, bcvd);
13665#ifdef SELF_CHECK
13666 assert(bcvd.tet != dummytet);
13667#endif
13668 fnextself(bcvd);
13669 enext2fnext(abvd, cavd);
13670#ifdef SELF_CHECK
13671 assert(cavd.tet != dummytet);
13672#endif
13673 fnextself(cavd);
13674 // Bond two new subfaces to the two new tetrahedra.
13675 tsbond(bcvd, bcv);
13676 tsbond(cavd, cav);
13677 }
13678 // Set the connection at the other sides if the tetrahedra exist.
13679 sesymself(abv); // bav
13680 stpivot(abv, bave);
13681 if (bave.tet != dummytet) {
13682 sesymself(bcv); // cbv
13683 sesymself(cav); // acv
13684 // Get two new tetrahedra and their syms.
13685 findedge(&bave, sorg(abv), sdest(abv));
13686 enextfnext(bave, acve);
13687#ifdef SELF_CHECK
13688 assert(acve.tet != dummytet);
13689#endif
13690 fnextself(acve);
13691 enext2fnext(bave, cbve);
13692#ifdef SELF_CHECK
13693 assert(cbve.tet != dummytet);
13694#endif
13695 fnextself(cbve);
13696 // Bond two new subfaces to the two new tetrahedra.
13697 tsbond(acve, cav);
13698 tsbond(cbve, bcv);
13699 }
13700
13701 bcv.shver = 0;
13702 cav.shver = 0;
13703 if (b->verbose > 3) {
13704 printf(" Updating abv ");
13705 printsh(&abv);
13706 printf(" Creating bcv ");
13707 printsh(&bcv);
13708 printf(" Creating cav ");
13709 printsh(&cav);
13710 }
13711
13712 if (flipqueue != (queue *) NULL) {
13713 enqueueflipedge(abv, flipqueue);
13714 enqueueflipedge(bcv, flipqueue);
13715 enqueueflipedge(cav, flipqueue);
13716 }
13717
13718 // Set the return handle be abv.
13719 *splitface = abv;
13720}
13721
13723// //
13724// unsplitsubface() Reverse the operation of inserting a point on a //
13725// subface, so as to remove the newly inserted point. //
13726// //
13727// Assume the original subface is abc, it was split by a point v into three //
13728// subfaces abv, bcv and cav. 'splitsh' represents abv. //
13729// //
13730// To remove point v is to expand abv to abc, delete bcv and cav. If edge bc //
13731// or ca is a subsegment, the connection at a subsegment is a subface link, //
13732// '-casin' and '-casout' are used to save the predecessor and successor of //
13733// bcv or cav. On completion, point v is not deleted in this routine. //
13734// //
13736
13737void tetgenmesh::unsplitsubface(face* splitsh)
13738{
13739 face abv, bcv, cav;
13740 face oldbv, oldva, bc, ca, spinsh;
13741 face bccasin, bccasout, cacasin, cacasout;
13742
13743 abv = *splitsh;
13744 senext(abv, oldbv);
13745 spivot(oldbv, bcv);
13746 if (sorg(bcv) != sdest(oldbv)) {
13747 sesymself(bcv);
13748 }
13749 senextself(bcv);
13750 senext2(abv, oldva);
13751 spivot(oldva, cav);
13752 if (sorg(cav) != sdest(oldva)) {
13753 sesymself(cav);
13754 }
13755 senext2self(cav);
13756
13757 if (b->verbose > 1) {
13758 printf(" Removing point %d on subface (%d, %d, %d).\n",
13759 pointmark(sapex(abv)), pointmark(sorg(abv)), pointmark(sdest(abv)),
13760 pointmark(sdest(bcv)));
13761 }
13762
13763 spivot(bcv, bccasout);
13764 sspivot(bcv, bc);
13765 if (bc.sh != dummysh) {
13766 if (bcv.sh != bccasout.sh) {
13767 // 'bcv' is not self-bonded.
13768 spinsh = bccasout;
13769 do {
13770 bccasin = spinsh;
13771 spivotself(spinsh);
13772 } while (spinsh.sh != bcv.sh);
13773 } else {
13774 bccasout.sh = dummysh;
13775 }
13776 }
13777 spivot(cav, cacasout);
13778 sspivot(cav, ca);
13779 if (ca.sh != dummysh) {
13780 if (cav.sh != cacasout.sh) {
13781 // 'cav' is not self-bonded.
13782 spinsh = cacasout;
13783 do {
13784 cacasin = spinsh;
13785 spivotself(spinsh);
13786 } while (spinsh.sh != cav.sh);
13787 } else {
13788 cacasout.sh = dummysh;
13789 }
13790 }
13791
13792 // Expand abv to abc.
13793 setsapex(abv, sdest(bcv));
13794 if (bc.sh != dummysh) {
13795 if (bccasout.sh != dummysh) {
13796 sbond1(bccasin, oldbv);
13797 sbond1(oldbv, bccasout);
13798 } else {
13799 // Bond 'oldbv' to itself.
13800 sbond(oldbv, oldbv);
13801 }
13802 ssbond(oldbv, bc);
13803 } else {
13804 sbond(oldbv, bccasout);
13805 }
13806 if (ca.sh != dummysh) {
13807 if (cacasout.sh != dummysh) {
13808 sbond1(cacasin, oldva);
13809 sbond1(oldva, cacasout);
13810 } else {
13811 // Bond 'oldva' to itself.
13812 sbond(oldva, oldva);
13813 }
13814 ssbond(oldva, ca);
13815 } else {
13816 sbond(oldva, cacasout);
13817 }
13818
13819 // Delete two split-out subfaces.
13820 shellfacedealloc(subfaces, bcv.sh);
13821 shellfacedealloc(subfaces, cav.sh);
13822}
13823
13825// //
13826// splittetedge() Insert a point on an edge of the mesh. //
13827// //
13828// The edge is given by 'splittet'. Assume its four corners are a, b, n1 and //
13829// n2, where ab is the edge will be split. Around ab may exist any number of //
13830// tetrahedra. For convenience, they're ordered in a sequence following the //
13831// right-hand rule with your thumb points from a to b. Let the vertex set of //
13832// these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around //
13833// ab may not connect to each other (can only happen when ab is a subsegment,//
13834// hence some faces abn(i) are subfaces). If ab is a subsegment, abn1 must //
13835// be a subface. //
13836// //
13837// To split edge ab by a point v is to split all tetrahedra containing ab by //
13838// v. More specifically, for each such tetrahedron, an1n2b, it is shrunk to //
13839// an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or //
13840// some faces of the splitting tetrahedra are subfaces, they must be split //
13841// either by calling routine 'splitsubedge()'. //
13842// //
13843// On completion, 'splittet' returns avn1n2. If 'flipqueue' is not NULL, it //
13844// returns all faces which may become non-Delaunay after this operation. //
13845// //
13847
13848void tetgenmesh::splittetedge(point newpoint, triface* splittet,
13849 queue* flipqueue)
13850{
13851 triface *bots, *newtops;
13852 triface oldtop, topcasing;
13853 triface spintet, tmpbond0, tmpbond1;
13854 face abseg, splitsh, topsh, spinsh;
13855 triface worktet;
13856 face n1n2seg, n2vseg, n1vseg;
13857 point pa, pb, n1, n2;
13858 REAL attrib, volume;
13859 int wrapcount, hitbdry;
13860 int i, j;
13861
13862 if (checksubfaces) {
13863 // Is there a subsegment need to be split together?
13864 tsspivot(splittet, &abseg);
13865 if (abseg.sh != dummysh) {
13866 abseg.shver = 0;
13867 // Orient the edge direction of 'splittet' be abseg.
13868 if (org(*splittet) != sorg(abseg)) {
13869 esymself(*splittet);
13870 }
13871 }
13872 }
13873 spintet = *splittet;
13874 pa = org(spintet);
13875 pb = dest(spintet);
13876
13877 if (b->verbose > 1) {
13878 printf(" Inserting point %d on edge (%d, %d).\n",
13879 pointmark(newpoint), pointmark(pa), pointmark(pb));
13880 }
13881
13882 // Collect the tetrahedra containing the splitting edge (ab).
13883 n1 = apex(spintet);
13884 hitbdry = 0;
13885 wrapcount = 1;
13886 if (checksubfaces && abseg.sh != dummysh) {
13887 // It may happen that some tetrahedra containing ab (a subsegment) are
13888 // completely disconnected with others. If it happens, use the face
13889 // link of ab to cross the boundary.
13890 while (true) {
13891 if (!fnextself(spintet)) {
13892 // Meet a boundary, walk through it.
13893 hitbdry ++;
13894 tspivot(spintet, spinsh);
13895#ifdef SELF_CHECK
13896 assert(spinsh.sh != dummysh);
13897#endif
13898 findedge(&spinsh, pa, pb);
13899 sfnextself(spinsh);
13900 stpivot(spinsh, spintet);
13901#ifdef SELF_CHECK
13902 assert(spintet.tet != dummytet);
13903#endif
13904 findedge(&spintet, pa, pb);
13905 // Remember this position (hull face) in 'splittet'.
13906 *splittet = spintet;
13907 // Split two hull faces increase the hull size;
13908 hullsize += 2;
13909 }
13910 if (apex(spintet) == n1) break;
13911 wrapcount ++;
13912 }
13913 if (hitbdry > 0) {
13914 wrapcount -= hitbdry;
13915 }
13916 } else {
13917 // All the tetrahedra containing ab are connected together. If there
13918 // are subfaces, 'splitsh' keeps one of them.
13919 splitsh.sh = dummysh;
13920 while (hitbdry < 2) {
13921 if (checksubfaces && splitsh.sh == dummysh) {
13922 tspivot(spintet, splitsh);
13923 }
13924 if (fnextself(spintet)) {
13925 if (apex(spintet) == n1) break;
13926 wrapcount++;
13927 } else {
13928 hitbdry ++;
13929 if (hitbdry < 2) {
13930 esym(*splittet, spintet);
13931 }
13932 }
13933 }
13934 if (hitbdry > 0) {
13935 // ab is on the hull.
13936 wrapcount -= 1;
13937 // 'spintet' now is a hull face, inverse its edge direction.
13938 esym(spintet, *splittet);
13939 // Split two hull faces increases the number of hull faces.
13940 hullsize += 2;
13941 }
13942 }
13943
13944 // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
13945 bots = new triface[wrapcount];
13946 newtops = new triface[wrapcount];
13947 // Spin around ab, gather tetrahedra and set up new tetrahedra.
13948 spintet = *splittet;
13949 for (i = 0; i < wrapcount; i++) {
13950 // Get 'bots[i] = an1n2b'.
13951 enext2fnext(spintet, bots[i]);
13952 esymself(bots[i]);
13953 // Create 'newtops[i]'.
13954 maketetrahedron(&(newtops[i]));
13955 // Go to the next.
13956 fnextself(spintet);
13957 if (checksubfaces && abseg.sh != dummysh) {
13958 if (!issymexist(&spintet)) {
13959 // We meet a hull face, walk through it.
13960 tspivot(spintet, spinsh);
13961#ifdef SELF_CHECK
13962 assert(spinsh.sh != dummysh);
13963#endif
13964 findedge(&spinsh, pa, pb);
13965 sfnextself(spinsh);
13966 stpivot(spinsh, spintet);
13967#ifdef SELF_CHECK
13968 assert(spintet.tet != dummytet);
13969#endif
13970 findedge(&spintet, pa, pb);
13971 }
13972 }
13973 }
13974
13975 // Set the vertices of updated and new tetrahedra.
13976 for (i = 0; i < wrapcount; i++) {
13977 // Update 'bots[i] = an1n2v'.
13978 setoppo(bots[i], newpoint);
13979 // Set 'newtops[i] = bn2n1v'.
13980 n1 = dest(bots[i]);
13981 n2 = apex(bots[i]);
13982 // Set 'newtops[i]'.
13983 setorg(newtops[i], pb);
13984 setdest(newtops[i], n2);
13985 setapex(newtops[i], n1);
13986 setoppo(newtops[i], newpoint);
13987 // Set the element attributes of a new tetrahedron.
13988 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
13989 attrib = elemattribute(bots[i].tet, j);
13990 setelemattribute(newtops[i].tet, j, attrib);
13991 }
13992 if (b->varvolume) {
13993 // Set the area constraint of a new tetrahedron.
13994 volume = volumebound(bots[i].tet);
13995 setvolumebound(newtops[i].tet, volume);
13996 }
13997#ifdef SELF_CHECK
13998 // Make sure no inversed tetrahedron has been created.
13999 // volume = orient3d(pa, n1, n2, newpoint);
14000 // if (volume >= 0.0) {
14001 // printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
14002 // }
14003 // volume = orient3d(pb, n2, n1, newpoint);
14004 // if (volume >= 0.0) {
14005 // printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
14006 // }
14007#endif
14008 }
14009
14010 // Bond newtops to topcasings and bots.
14011 for (i = 0; i < wrapcount; i++) {
14012 // Get 'oldtop = n1n2va' from 'bots[i]'.
14013 enextfnext(bots[i], oldtop);
14014 sym(oldtop, topcasing);
14015 bond(newtops[i], topcasing);
14016 if (checksubfaces) {
14017 tspivot(oldtop, topsh);
14018 if (topsh.sh != dummysh) {
14019 tsdissolve(oldtop);
14020 tsbond(newtops[i], topsh);
14021 }
14022 }
14023 enextfnext(newtops[i], tmpbond0);
14024 bond(oldtop, tmpbond0);
14025 }
14026 // Bond between newtops.
14027 fnext(newtops[0], tmpbond0);
14028 enext2fnext(bots[0], spintet);
14029 for (i = 1; i < wrapcount; i ++) {
14030 if (issymexist(&spintet)) {
14031 enext2fnext(newtops[i], tmpbond1);
14032 bond(tmpbond0, tmpbond1);
14033 }
14034 fnext(newtops[i], tmpbond0);
14035 enext2fnext(bots[i], spintet);
14036 }
14037 // Bond the last to the first if no boundary.
14038 if (issymexist(&spintet)) {
14039 enext2fnext(newtops[0], tmpbond1);
14040 bond(tmpbond0, tmpbond1);
14041 }
14042 if (checksubsegs) {
14043 for (i = 0; i < wrapcount; i++) {
14044 enextfnext(bots[i], worktet); // edge n1->n2.
14045 tsspivot1(worktet, n1n2seg);
14046 if (n1n2seg.sh != dummysh) {
14047 enext(newtops[i], tmpbond0);
14048 tssbond1(tmpbond0, n1n2seg);
14049 }
14050 enextself(worktet); // edge n2->v ==> n2->b
14051 tsspivot1(worktet, n2vseg);
14052 if (n2vseg.sh != dummysh) {
14053 tssdissolve1(worktet);
14054 tssbond1(newtops[i], n2vseg);
14055 }
14056 enextself(worktet); // edge v->n1 ==> b->n1
14057 tsspivot1(worktet, n1vseg);
14058 if (n1vseg.sh != dummysh) {
14059 tssdissolve1(worktet);
14060 enext2(newtops[i], tmpbond0);
14061 tssbond1(tmpbond0, n1vseg);
14062 }
14063 }
14064 }
14065
14066 // Is there exist subfaces and subsegment need to be split?
14067 if (checksubfaces) {
14068 if (abseg.sh != dummysh) {
14069 // A subsegment needs be split.
14070 spivot(abseg, splitsh);
14071#ifdef SELF_CHECK
14072 assert(splitsh.sh != dummysh);
14073#endif
14074 }
14075 if (splitsh.sh != dummysh) {
14076 // Split subfaces (and subsegment).
14077 findedge(&splitsh, pa, pb);
14078 splitsubedge(newpoint, &splitsh, (queue *) NULL);
14079 }
14080 }
14081
14082 if (b->verbose > 3) {
14083 for (i = 0; i < wrapcount; i++) {
14084 printf(" Updating bots[%i] ", i);
14085 printtet(&(bots[i]));
14086 printf(" Creating newtops[%i] ", i);
14087 printtet(&(newtops[i]));
14088 }
14089 }
14090
14091 if (flipqueue != (queue *) NULL) {
14092 for (i = 0; i < wrapcount; i++) {
14093 enqueueflipface(bots[i], flipqueue);
14094 enqueueflipface(newtops[i], flipqueue);
14095 }
14096 }
14097
14098 // Set the return handle be avn1n2. It is got by transforming from
14099 // 'bots[0]' (which is an1n2v).
14100 fnext(bots[0], spintet); // spintet is an1vn2.
14101 esymself(spintet); // spintet is n1avn2.
14102 enextself(spintet); // spintet is avn1n2.
14103 *splittet = spintet;
14104
14105 delete [] bots;
14106 delete [] newtops;
14107}
14108
14110// //
14111// unsplittetedge() Reverse the operation of splitting an edge, so as to //
14112// remove the newly inserted point. //
14113// //
14114// Assume the original edge is ab, the tetrahedron containing ab is abn1n2. //
14115// After ab was split by a point v, every tetrahedron containing ab (e.g., //
14116// abn1n2) has been split into two (e.g., an1n2v and bn2n1v). 'splittet' //
14117// represents avn1n2 (i.e., its destination is v). //
14118// //
14119// To remove point v is to expand each split tetrahedron containing ab (e.g.,//
14120// (avn1n2 to abn1n2), then delete the redundant one(e.g., vbn1n2). If there //
14121// exists any subface around ab, routine unsplitsubedge() will be called to //
14122// reverse the operation of splitting a edge (or a subsegment) of subfaces. //
14123// On completion, point v is not deleted in this routine. //
14124// //
14126
14127void tetgenmesh::unsplittetedge(triface* splittet)
14128{
14129 triface *bots, *newtops;
14130 triface oldtop, topcasing;
14131 triface spintet;
14132 face avseg, splitsh, topsh, spinsh;
14133 point pa, pv, n1;
14134 int wrapcount, hitbdry;
14135 int i;
14136
14137 spintet = *splittet;
14138 pa = org(spintet);
14139 pv = dest(spintet);
14140 if (checksubfaces) {
14141 // Is there a subsegment need to be unsplit together?
14142 tsspivot(splittet, &avseg);
14143 if (avseg.sh != dummysh) {
14144 // The subsegment's direction should conform to 'splittet'.
14145 if (sorg(avseg) != pa) {
14146 sesymself(avseg);
14147 }
14148 }
14149 }
14150
14151 n1 = apex(spintet);
14152 hitbdry = 0;
14153 wrapcount = 1;
14154 if (checksubfaces && avseg.sh != dummysh) {
14155 // It may happen that some tetrahedra containing ab (a subsegment) are
14156 // completely disconnected with others. If it happens, use the face
14157 // link of ab to cross the boundary.
14158 while (true) {
14159 if (!fnextself(spintet)) {
14160 // Meet a boundary, walk through it.
14161 hitbdry ++;
14162 tspivot(spintet, spinsh);
14163#ifdef SELF_CHECK
14164 assert(spinsh.sh != dummysh);
14165#endif
14166 findedge(&spinsh, pa, pv);
14167 sfnextself(spinsh);
14168 stpivot(spinsh, spintet);
14169#ifdef SELF_CHECK
14170 assert(spintet.tet != dummytet);
14171#endif
14172 findedge(&spintet, pa, pv);
14173 // Remember this position (hull face) in 'splittet'.
14174 *splittet = spintet;
14175 // Split two hull faces increase the hull size;
14176 hullsize += 2;
14177 }
14178 if (apex(spintet) == n1) break;
14179 wrapcount ++;
14180 }
14181 if (hitbdry > 0) {
14182 wrapcount -= hitbdry;
14183 }
14184 } else {
14185 // All the tetrahedra containing ab are connected together. If there
14186 // are subfaces, 'splitsh' keeps one of them.
14187 splitsh.sh = dummysh;
14188 while (hitbdry < 2) {
14189 if (checksubfaces && splitsh.sh == dummysh) {
14190 tspivot(spintet, splitsh);
14191 }
14192 if (fnextself(spintet)) {
14193 if (apex(spintet) == n1) break;
14194 wrapcount++;
14195 } else {
14196 hitbdry ++;
14197 if (hitbdry < 2) {
14198 esym(*splittet, spintet);
14199 }
14200 }
14201 }
14202 if (hitbdry > 0) {
14203 // ab is on the hull.
14204 wrapcount -= 1;
14205 // 'spintet' now is a hull face, inverse its edge direction.
14206 esym(spintet, *splittet);
14207 // Split two hull faces increases the number of hull faces.
14208 hullsize += 2;
14209 }
14210 }
14211
14212 // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
14213 bots = new triface[wrapcount];
14214 newtops = new triface[wrapcount];
14215 // Spin around av, gather tetrahedra and set up new tetrahedra.
14216 spintet = *splittet;
14217 for (i = 0; i < wrapcount; i++) {
14218 // Get 'bots[i] = an1n2v'.
14219 enext2fnext(spintet, bots[i]);
14220 esymself(bots[i]);
14221 // Get 'oldtop = n1n2va'.
14222 enextfnext(bots[i], oldtop);
14223 // Get 'newtops[i] = 'bn1n2v'
14224 fnext(oldtop, newtops[i]); // newtop = n1n2bv
14225 esymself(newtops[i]); // newtop = n2n1bv
14226 enext2self(newtops[i]); // newtop = bn2n1v
14227 // Go to the next.
14228 fnextself(spintet);
14229 if (checksubfaces && avseg.sh != dummysh) {
14230 if (!issymexist(&spintet)) {
14231 // We meet a hull face, walk through it.
14232 tspivot(spintet, spinsh);
14233#ifdef SELF_CHECK
14234 assert(spinsh.sh != dummysh);
14235#endif
14236 findedge(&spinsh, pa, pv);
14237 sfnextself(spinsh);
14238 stpivot(spinsh, spintet);
14239#ifdef SELF_CHECK
14240 assert(spintet.tet != dummytet);
14241#endif
14242 findedge(&spintet, pa, pv);
14243 }
14244 }
14245 }
14246
14247 if (b->verbose > 1) {
14248 printf(" Removing point %d from edge (%d, %d).\n",
14249 pointmark(oppo(bots[0])), pointmark(org(bots[0])),
14250 pointmark(org(newtops[0])));
14251 }
14252
14253 for (i = 0; i < wrapcount; i++) {
14254 // Expand an1n2v to an1n2b.
14255 setoppo(bots[i], org(newtops[i]));
14256 // Get 'oldtop = n1n2va' from 'bot[i]'.
14257 enextfnext(bots[i], oldtop);
14258 // Get 'topcasing' from 'newtop[i]'
14259 sym(newtops[i], topcasing);
14260 // Bond them.
14261 bond(oldtop, topcasing);
14262 if (checksubfaces) {
14263 tspivot(newtops[i], topsh);
14264 if (topsh.sh != dummysh) {
14265 tsbond(oldtop, topsh);
14266 }
14267 }
14268 // Delete the tetrahedron above an1n2v.
14269 tetrahedrondealloc(newtops[i].tet);
14270 }
14271
14272 // If there exists any subface, unsplit them.
14273 if (checksubfaces) {
14274 if (avseg.sh != dummysh) {
14275 spivot(avseg, splitsh);
14276#ifdef SELF_CHECK
14277 assert(splitsh.sh != dummysh);
14278#endif
14279 }
14280 if (splitsh.sh != dummysh) {
14281 findedge(&splitsh, pa, pv);
14282 unsplitsubedge(&splitsh);
14283 }
14284 }
14285
14286 delete [] bots;
14287 delete [] newtops;
14288}
14289
14291// //
14292// splitsubedge() Insert a point on an edge of the surface mesh. //
14293// //
14294// The splitting edge is given by 'splitsh'. Assume its three corners are a, //
14295// b, c, where ab is the edge will be split. ab may be a subsegment. //
14296// //
14297// To split edge ab is to split all subfaces conatining ab. If ab is not a //
14298// subsegment, there are only two subfaces need be split, otherwise, there //
14299// may have any number of subfaces need be split. Each splitting subface abc //
14300// is shrunk to avc, a new subface vbc is created. It is important to keep //
14301// the orientations of edge rings of avc and vbc be the same as abc's. If ab //
14302// is a subsegment, it is shrunk to av and a new subsegment vb is created. //
14303// //
14304// If there are tetrahedra adjoining to the splitting subfaces, they should //
14305// be split before calling this routine, so the connection between the new //
14306// tetrahedra and the new subfaces can be correctly set. //
14307// //
14308// On completion, 'splitsh' returns avc. If 'flipqueue' is not NULL, it //
14309// returns all edges which may be non-Delaunay. //
14310// //
14312
14313void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue)
14314{
14315 triface abcd, bace, vbcd, bvce;
14316 face startabc, spinabc, spinsh;
14317 face oldbc, bccasin, bccasout;
14318 face ab, bc;
14319 face avc, vbc, vbc1;
14320 face av, vb;
14321 point pa, pb;
14322
14323 startabc = *splitsh;
14324 // Is there a subsegment?
14325 sspivot(startabc, ab);
14326 if (ab.sh != dummysh) {
14327 ab.shver = 0;
14328 if (sorg(startabc) != sorg(ab)) {
14329 sesymself(startabc);
14330 }
14331 }
14332 pa = sorg(startabc);
14333 pb = sdest(startabc);
14334
14335 if (b->verbose > 1) {
14336 printf(" Inserting point %d on subedge (%d, %d) %s.\n",
14337 pointmark(newpoint), pointmark(pa), pointmark(pb),
14338 (ab.sh != dummysh ? "(seg)" : " "));
14339 }
14340
14341 // Spin arround ab, split every subface containing ab.
14342 spinabc = startabc;
14343 do {
14344 // Adjust spinabc be edge ab.
14345 if (sorg(spinabc) != pa) {
14346 sesymself(spinabc);
14347 }
14348 // Save old configuration at edge bc, if bc has a subsegment, save the
14349 // face link of it and dissolve it from bc.
14350 senext(spinabc, oldbc);
14351 spivot(oldbc, bccasout);
14352 sspivot(oldbc, bc);
14353 if (bc.sh != dummysh) {
14354 if (spinabc.sh != bccasout.sh) {
14355 // 'spinabc' is not self-bonded.
14356 spinsh = bccasout;
14357 do {
14358 bccasin = spinsh;
14359 spivotself(spinsh);
14360 } while (spinsh.sh != oldbc.sh);
14361 } else {
14362 bccasout.sh = dummysh;
14363 }
14364 ssdissolve(oldbc);
14365 }
14366 // Create a new subface.
14367 makeshellface(subfaces, &vbc);
14368 // Split abc.
14369 avc = spinabc; // Update 'abc' to 'avc'.
14370 setsdest(avc, newpoint);
14371 // Make 'vbc' be in the same edge ring as 'avc'.
14372 vbc.shver = avc.shver;
14373 setsorg(vbc, newpoint); // Set 'vbc'.
14374 setsdest(vbc, pb);
14375 setsapex(vbc, sapex(avc));
14376 if (b->quality && varconstraint) {
14377 // Copy the area bound into the new subface.
14378 setareabound(vbc, areabound(avc));
14379 }
14380 // Copy the shell marker and shell type into the new subface.
14381 setshellmark(vbc, shellmark(avc));
14382 setshelltype(vbc, shelltype(avc));
14383 if (checkpbcs) {
14384 // Copy the pbcgroup into the new subface.
14385 setshellpbcgroup(vbc, shellpbcgroup(avc));
14386 }
14387 // Set the connection between updated and new subfaces.
14388 senext2self(vbc);
14389 sbond(vbc, oldbc);
14390 // Set the connection between new subface and casings.
14391 senext2self(vbc);
14392 if (bc.sh != dummysh) {
14393 if (bccasout.sh != dummysh) {
14394 // Insert 'vbc' into face link.
14395 sbond1(bccasin, vbc);
14396 sbond1(vbc, bccasout);
14397 } else {
14398 // Bond 'vbc' to itself.
14399 sbond(vbc, vbc);
14400 }
14401 ssbond(vbc, bc);
14402 } else {
14403 sbond(vbc, bccasout);
14404 }
14405 // Go to next subface at edge ab.
14406 spivotself(spinabc);
14407 if (spinabc.sh == dummysh) {
14408 break; // 'ab' is a hull edge.
14409 }
14410 } while (spinabc.sh != startabc.sh);
14411
14412 // Get the new subface vbc above the updated subface avc (= startabc).
14413 senext(startabc, oldbc);
14414 spivot(oldbc, vbc);
14415 if (sorg(vbc) == newpoint) {
14416 sesymself(vbc);
14417 }
14418#ifdef SELF_CHECK
14419 assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc));
14420#endif
14421 senextself(vbc);
14422 // Set the face link for the new created subfaces around edge vb.
14423 spinabc = startabc;
14424 do {
14425 // Go to the next subface at edge av.
14426 spivotself(spinabc);
14427 if (spinabc.sh == dummysh) {
14428 break; // 'ab' is a hull edge.
14429 }
14430 if (sorg(spinabc) != pa) {
14431 sesymself(spinabc);
14432 }
14433 // Get the new subface vbc1 above the updated subface avc (= spinabc).
14434 senext(spinabc, oldbc);
14435 spivot(oldbc, vbc1);
14436 if (sorg(vbc1) == newpoint) {
14437 sesymself(vbc1);
14438 }
14439#ifdef SELF_CHECK
14440 assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc));
14441#endif
14442 senextself(vbc1);
14443 // Set the connection: vbc->vbc1.
14444 sbond1(vbc, vbc1);
14445 // For the next connection.
14446 vbc = vbc1;
14447 } while (spinabc.sh != startabc.sh);
14448
14449 // Split ab if it is a subsegment.
14450 if (ab.sh != dummysh) {
14451 // Update subsegment ab to av.
14452 av = ab;
14453 setsdest(av, newpoint);
14454 // Create a new subsegment vb.
14455 makeshellface(subsegs, &vb);
14456 setsorg(vb, newpoint);
14457 setsdest(vb, pb);
14458 // vb gets the same mark and segment type as av.
14459 setshellmark(vb, shellmark(av));
14460 setshelltype(vb, shelltype(av));
14461 if (b->quality && varconstraint) {
14462 // Copy the area bound into the new subsegment.
14463 setareabound(vb, areabound(av));
14464 }
14465 // Save the old connection at ab (re-use the handles oldbc, bccasout).
14466 senext(av, oldbc);
14467 spivot(oldbc, bccasout);
14468 // Bond av and vb (bonded at their "fake" edges).
14469 senext2(vb, bccasin);
14470 sbond(bccasin, oldbc);
14471 if (bccasout.sh != dummysh) {
14472 // There is a subsegment connecting with ab at b. It will connect
14473 // to vb at b after splitting.
14474 bccasout.shver = 0;
14475 if (sorg(bccasout) != pb) sesymself(bccasout);
14476#ifdef SELF_CHECK
14477 assert(sorg(bccasout) == pb);
14478#endif
14479 senext2self(bccasout);
14480 senext(vb, bccasin);
14481 sbond(bccasin, bccasout);
14482 }
14483 // Bond all new subfaces (vbc) to vb.
14484 spinabc = startabc;
14485 do {
14486 // Adjust spinabc be edge av.
14487 if (sorg(spinabc) != pa) {
14488 sesymself(spinabc);
14489 }
14490 // Get new subface vbc above the updated subface avc (= spinabc).
14491 senext(spinabc, oldbc);
14492 spivot(oldbc, vbc);
14493 if (sorg(vbc) == newpoint) {
14494 sesymself(vbc);
14495 }
14496 senextself(vbc);
14497 // Bond the new subface and the new subsegment.
14498 ssbond(vbc, vb);
14499 // Go to the next.
14500 spivotself(spinabc);
14501#ifdef SELF_CHECK
14502 assert(spinabc.sh != dummysh);
14503#endif
14504 } while (spinabc.sh != startabc.sh);
14505 }
14506
14507 // Bond the new subfaces to new tetrahedra if they exist. New tetrahedra
14508 // should have been created before calling this routine.
14509 spinabc = startabc;
14510 do {
14511 // Adjust spinabc be edge av.
14512 if (sorg(spinabc) != pa) {
14513 sesymself(spinabc);
14514 }
14515 // Get new subface vbc above the updated subface avc (= spinabc).
14516 senext(spinabc, oldbc);
14517 spivot(oldbc, vbc);
14518 if (sorg(vbc) == newpoint) {
14519 sesymself(vbc);
14520 }
14521 senextself(vbc);
14522 // Get the adjacent tetrahedra at 'spinabc'.
14523 stpivot(spinabc, abcd);
14524 if (abcd.tet != dummytet) {
14525 findedge(&abcd, sorg(spinabc), sdest(spinabc));
14526 enextfnext(abcd, vbcd);
14527 fnextself(vbcd);
14528#ifdef SELF_CHECK
14529 assert(vbcd.tet != dummytet);
14530#endif
14531 tsbond(vbcd, vbc);
14532 sym(vbcd, bvce);
14533 sesymself(vbc);
14534 tsbond(bvce, vbc);
14535 } else {
14536 // One side is empty, check the other side.
14537 sesymself(spinabc);
14538 stpivot(spinabc, bace);
14539 if (bace.tet != dummytet) {
14540 findedge(&bace, sorg(spinabc), sdest(spinabc));
14541 enext2fnext(bace, bvce);
14542 fnextself(bvce);
14543#ifdef SELF_CHECK
14544 assert(bvce.tet != dummytet);
14545#endif
14546 sesymself(vbc);
14547 tsbond(bvce, vbc);
14548 }
14549 }
14550 // Go to the next.
14551 spivotself(spinabc);
14552 if (spinabc.sh == dummysh) {
14553 break; // 'ab' is a hull edge.
14554 }
14555 } while (spinabc.sh != startabc.sh);
14556
14557 if (b->verbose > 3) {
14558 spinabc = startabc;
14559 do {
14560 // Adjust spinabc be edge av.
14561 if (sorg(spinabc) != pa) {
14562 sesymself(spinabc);
14563 }
14564 printf(" Updating abc:\n");
14565 printsh(&spinabc);
14566 // Get new subface vbc above the updated subface avc (= spinabc).
14567 senext(spinabc, oldbc);
14568 spivot(oldbc, vbc);
14569 if (sorg(vbc) == newpoint) {
14570 sesymself(vbc);
14571 }
14572 senextself(vbc);
14573 printf(" Creating vbc:\n");
14574 printsh(&vbc);
14575 // Go to the next.
14576 spivotself(spinabc);
14577 if (spinabc.sh == dummysh) {
14578 break; // 'ab' is a hull edge.
14579 }
14580 } while (spinabc.sh != startabc.sh);
14581 }
14582
14583 if (flipqueue != (queue *) NULL) {
14584 spinabc = startabc;
14585 do {
14586 // Adjust spinabc be edge av.
14587 if (sorg(spinabc) != pa) {
14588 sesymself(spinabc);
14589 }
14590 senext2(spinabc, oldbc); // Re-use oldbc.
14591 enqueueflipedge(oldbc, flipqueue);
14592 // Get new subface vbc above the updated subface avc (= spinabc).
14593 senext(spinabc, oldbc);
14594 spivot(oldbc, vbc);
14595 if (sorg(vbc) == newpoint) {
14596 sesymself(vbc);
14597 }
14598 senextself(vbc);
14599 senext(vbc, oldbc); // Re-use oldbc.
14600 enqueueflipedge(oldbc, flipqueue);
14601 // Go to the next.
14602 spivotself(spinabc);
14603 if (spinabc.sh == dummysh) {
14604 break; // 'ab' is a hull edge.
14605 }
14606 } while (spinabc.sh != startabc.sh);
14607 }
14608}
14609
14611// //
14612// unsplitsubedge() Reverse the operation of splitting an edge of subface,//
14613// so as to remove a point from the edge. //
14614// //
14615// Assume the original edge is ab, the subface containing it is abc. It was //
14616// split by a point v into avc, and vbc. 'splitsh' represents avc, further- //
14617// more, if av is a subsegment, av should be the zero version of the split //
14618// subsegment (i.e., av.shver = 0), so we are sure that the destination (v) //
14619// of both avc and av is the deleting point. //
14620// //
14621// To remove point v is to expand avc to abc, delete vbc, do the same for //
14622// other subfaces containing av and vb. If av and vb are subsegments, expand //
14623// av to ab, delete vb. On completion, point v is not deleted. //
14624// //
14626
14627void tetgenmesh::unsplitsubedge(face* splitsh)
14628{
14629 face startavc, spinavc, spinbcv;
14630 face oldvc, bccasin, bccasout, spinsh;
14631 face av, vb, bc;
14632 point pa, pv, pb;
14633
14634 startavc = *splitsh;
14635 sspivot(startavc, av);
14636 if (av.sh != dummysh) {
14637 // Orient the direction of subsegment to conform the subface.
14638 if (sorg(av) != sorg(startavc)) {
14639 sesymself(av);
14640 }
14641#ifdef SELF_CHECK
14642 assert(av.shver == 0);
14643#endif
14644 }
14645 senext(startavc, oldvc);
14646 spivot(oldvc, vb); // vb is subface vbc
14647 if (sorg(vb) != sdest(oldvc)) {
14648 sesymself(vb);
14649 }
14650 senextself(vb);
14651 pa = sorg(startavc);
14652 pv = sdest(startavc);
14653 pb = sdest(vb);
14654
14655 if (b->verbose > 1) {
14656 printf(" Removing point %d from subedge (%d, %d).\n",
14657 pointmark(pv), pointmark(pa), pointmark(pb));
14658 }
14659
14660 // Spin arround av, unsplit every subface containing av.
14661 spinavc = startavc;
14662 do {
14663 // Adjust spinavc be edge av.
14664 if (sorg(spinavc) != pa) {
14665 sesymself(spinavc);
14666 }
14667 // Save old configuration at edge bc, if bc has a subsegment, save the
14668 // face link of it.
14669 senext(spinavc, oldvc);
14670 spivot(oldvc, spinbcv);
14671 if (sorg(spinbcv) != sdest(oldvc)) {
14672 sesymself(spinbcv);
14673 }
14674 senext2self(spinbcv);
14675 spivot(spinbcv, bccasout);
14676 sspivot(spinbcv, bc);
14677 if (bc.sh != dummysh) {
14678 if (spinbcv.sh != bccasout.sh) {
14679 // 'spinbcv' is not self-bonded.
14680 spinsh = bccasout;
14681 do {
14682 bccasin = spinsh;
14683 spivotself(spinsh);
14684 } while (spinsh.sh != spinbcv.sh);
14685 } else {
14686 bccasout.sh = dummysh;
14687 }
14688 }
14689 // Expand avc to abc.
14690 setsdest(spinavc, pb);
14691 if (bc.sh != dummysh) {
14692 if (bccasout.sh != dummysh) {
14693 sbond1(bccasin, oldvc);
14694 sbond1(oldvc, bccasout);
14695 } else {
14696 // Bond 'oldbc' to itself.
14697 sbond(oldvc, oldvc);
14698 }
14699 ssbond(oldvc, bc);
14700 } else {
14701 sbond(oldvc, bccasout);
14702 }
14703 // Delete bcv.
14704 shellfacedealloc(subfaces, spinbcv.sh);
14705 // Go to next subface at edge av.
14706 spivotself(spinavc);
14707 if (spinavc.sh == dummysh) {
14708 break; // 'av' is a hull edge.
14709 }
14710 } while (spinavc.sh != startavc.sh);
14711
14712 // Is there a subsegment need to be unsplit?
14713 if (av.sh != dummysh) {
14714 senext(av, oldvc); // Re-use oldvc.
14715 spivot(oldvc, vb);
14716 vb.shver = 0;
14717#ifdef SELF_CHECK
14718 assert(sdest(av) == sorg(vb));
14719#endif
14720 senext(vb, spinbcv); // Re-use spinbcv.
14721 spivot(spinbcv, bccasout);
14722 // Expand av to ab.
14723 setsdest(av, pb);
14724 sbond(oldvc, bccasout);
14725 // Delete vb.
14726 shellfacedealloc(subsegs, vb.sh);
14727 }
14728}
14729
14731// //
14732// insertsite() Insert a point into the mesh. //
14733// //
14734// The 'newpoint' is located. If 'searchtet->tet' is not NULL, the search //
14735// for the containing tetrahedron begins from 'searchtet', otherwise, a full //
14736// point location procedure is called. If 'newpoint' is found inside a //
14737// tetrahedron, the tetrahedron is split into four (by splittetrahedron()); //
14738// if 'newpoint' lies on a face, the face is split into three, thereby //
14739// splitting the two adjacent tetrahedra into six (by splittetface()); if //
14740// 'newpoint' lies on an edge, the edge is split into two, thereby, every //
14741// tetrahedron containing this edge is split into two. If 'newpoint' lies on //
14742// an existing vertex, no action is taken, and the value DUPLICATEPOINT is //
14743// returned and 'searchtet' is set to a handle whose origin is the vertex. //
14744// //
14745// If 'flipqueue' is not NULL, after 'newpoint' is inserted, it returns all //
14746// faces which may become non-Delaunay due to the newly inserted point. Flip //
14747// operations can be performed as necessary on them to maintain the Delaunay //
14748// property. //
14749// //
14751
14752enum tetgenmesh::insertsiteresult tetgenmesh::insertsite(point newpoint,
14753 triface* searchtet, bool approx, queue* flipqueue)
14754{
14755 enum locateresult intersect, exactloc;
14756 point checkpt;
14757 REAL epspp, checklen;
14758 int count;
14759
14760 if (b->verbose > 1) {
14761 printf(" Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n",
14762 newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint));
14763 }
14764
14765 if (searchtet->tet == (tetrahedron *) NULL) {
14766 // Search for a tetrahedron containing 'newpoint'.
14767 searchtet->tet = dummytet;
14768 exactloc = locate(newpoint, searchtet);
14769 } else {
14770 // Start searching from the tetrahedron provided by the caller.
14771 exactloc = preciselocate(newpoint, searchtet, tetrahedrons->items);
14772 }
14773 intersect = exactloc;
14774 if (approx && (exactloc != ONVERTEX)) {
14775 // Adjust the exact location to an approx. location wrt. epsilon.
14776 epspp = b->epsilon;
14777 count = 0;
14778 while (count < 16) {
14779 intersect = adjustlocate(newpoint, searchtet, exactloc, epspp);
14780 if (intersect == ONVERTEX) {
14781 checkpt = org(*searchtet);
14782 checklen = distance(checkpt, newpoint);
14783 if (checklen / longest > b->epsilon) {
14784 epspp *= 1e-2;
14785 count++;
14786 continue;
14787 }
14788 }
14789 break;
14790 }
14791 }
14792 // Keep current search state for next searching.
14793 recenttet = *searchtet;
14794
14795 // Insert the point using the right routine
14796 switch (intersect) {
14797 case ONVERTEX:
14798 // There's already a vertex there. Return in 'searchtet' a tetrahedron
14799 // whose origin is the existing vertex.
14800 if (b->verbose > 1) {
14801 printf(" Not insert for duplicating point.\n");
14802 }
14803 return DUPLICATEPOINT;
14804
14805 case OUTSIDE:
14806 if (b->verbose > 1) {
14807 printf(" Not insert for locating outside the mesh.\n");
14808 }
14809 return OUTSIDEPOINT;
14810
14811 case ONEDGE:
14812 // 'newpoint' falls on an edge.
14813 splittetedge(newpoint, searchtet, flipqueue);
14814 return SUCCESSONEDGE;
14815
14816 case ONFACE:
14817 // 'newpoint' falls on a face.
14818 splittetface(newpoint, searchtet, flipqueue);
14819 return SUCCESSONFACE;
14820
14821 case INTETRAHEDRON:
14822 // 'newpoint' falls inside a tetrahedron.
14823 splittetrahedron(newpoint, searchtet, flipqueue);
14824 return SUCCESSINTET;
14825
14826 default:
14827 // Impossible case.
14828 return OUTSIDEPOINT;
14829 }
14830}
14831
14833// //
14834// undosite() Undo the most recently point insertion. //
14835// //
14836// 'insresult' indicates in where the newpoint has been inserted, i.e., in a //
14837// tetrahedron, on a face, or on an edge. A correspoding routine will be //
14838// called to undo the point insertion. 'splittet' is a handle represent one //
14839// of the resulting tetrahedra, but it may be changed after transformation, //
14840// even may be dead. Four points 'torg', ... 'toppo' are the corners which //
14841// 'splittet' should have. On finish, 'newpoint' is not removed. //
14842// //
14844
14845void tetgenmesh::undosite(enum insertsiteresult insresult, triface* splittet,
14846 point torg, point tdest, point tapex, point toppo)
14847{
14848 // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'.
14849 findface(splittet, torg, tdest, tapex);
14850 if (oppo(*splittet) != toppo) {
14851 symself(*splittet);
14852#ifdef SELF_CHECK
14853 assert(oppo(*splittet) == toppo);
14854#endif
14855 // The sym() operation may inverse the edge, correct it if so.
14856 findedge(splittet, torg, tdest);
14857 }
14858
14859 // Unsplit the tetrahedron according to 'insresult'.
14860 switch (insresult) {
14861 case SUCCESSINTET:
14862 // 'splittet' should be the face with 'newpoint' as its opposite.
14863 unsplittetrahedron(splittet);
14864 break;
14865 case SUCCESSONFACE:
14866 // 'splittet' should be the one of three splitted face with 'newpoint'
14867 // as its apex.
14868 unsplittetface(splittet);
14869 break;
14870 case SUCCESSONEDGE:
14871 // 'splittet' should be the tet with destination is 'newpoint'.
14872 unsplittetedge(splittet);
14873 break;
14874 default: // To omit compile warnings.
14875 break;
14876 }
14877}
14878
14880// //
14881// closeopenface() Close "open" faces recursively. //
14882// //
14883// This is the support routine of inserthullsite(). A point p which lies out-//
14884// side of CH(T). p is inserted to T by forming a tet t from p and a visible //
14885// CH face f. The three sides of f which have p as a vertex is called "open" //
14886// face. Each open face will be closed by either creating a tet on top of it //
14887// or become a new CH face. //
14888// //
14890
14891void tetgenmesh::closeopenface(triface* openface, queue* flipque)
14892{
14893 triface newtet, oldhull;
14894 triface newopenface, closeface;
14895 point inspoint, pa, pb, pc;
14896 REAL attrib, volume;
14897 int i;
14898
14899 // Get the new point p.
14900 inspoint = apex(*openface);
14901 // Find the old CH face f_o (f and f_o share the same edge).
14902 esym(*openface, oldhull);
14903 while (fnextself(oldhull)) ;
14904 if (apex(oldhull) != inspoint) {
14905 // Is f_o visible by p?
14906 pa = org(oldhull);
14907 pb = dest(oldhull);
14908 pc = apex(oldhull);
14909 if (orient3d(pa, pb, pc, inspoint) < 0.0) {
14910 // Yes. Create a new tet t above f_o.
14911 maketetrahedron(&newtet);
14912 setorg(newtet, pa);
14913 setdest(newtet, pb);
14914 setapex(newtet, pc);
14915 setoppo(newtet, inspoint);
14916 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
14917 attrib = elemattribute(oldhull.tet, i);
14918 setelemattribute(newtet.tet, i, attrib);
14919 }
14920 if (b->varvolume) {
14921 volume = volumebound(oldhull.tet);
14922 setvolumebound(newtet.tet, volume);
14923 }
14924 // Connect t to T.
14925 bond(newtet, oldhull);
14926 // Close f.
14927 fnext(newtet, newopenface);
14928 bond(newopenface, *openface);
14929 // f_o becomes an interior face.
14930 enqueueflipface(oldhull, flipque);
14931 // Hull face number decreases.
14932 hullsize--;
14933 // Two faces of t become open face.
14934 enextself(newtet);
14935 for (i = 0; i < 2; i++) {
14936 fnext(newtet, newopenface);
14937 sym(newopenface, closeface);
14938 if (closeface.tet == dummytet) {
14939 closeopenface(&newopenface, flipque);
14940 }
14941 enextself(newtet);
14942 }
14943 } else {
14944 // Inivisible. f becomes a new CH face.
14945 hullsize++;
14946 // Let 'dummytet' holds f for the next point location.
14947 dummytet[0] = encode(*openface);
14948 }
14949 } else {
14950 // f_o is co-incident with f --> f is closed by f_o.
14951 bond(*openface, oldhull);
14952 // f is an interior face.
14953 enqueueflipface(*openface, flipque);
14954 }
14955}
14956
14958// //
14959// inserthullsite() Insert a point which lies outside the convex hull. //
14960// //
14961// The 'inspoint' p lies outside the tetrahedralization T. The 'horiz' f is //
14962// on the convex hull of T, CH(T), which is visible by p (Imagine f is para- //
14963// llel to the horizon). To insert p into T we have to enlarge the CH(T) and //
14964// update T so that p is on the new CH(T). //
14965// //
14966// To enlarge the CH(T). We need to find the set F of faces which are on CH //
14967// (T) and visible by p (F can be formed by a depth-first search from f). p //
14968// is then inserted into T by mounting new tets formed by p and these faces. //
14969// Faces of F become interior faces and may non-locally Delaunay. They are //
14970// queued in 'flipqueue' for flip tests. //
14971// //
14973
14974void tetgenmesh::inserthullsite(point inspoint, triface* horiz, queue* flipque)
14975{
14976 triface firstnewtet;
14977 triface openface, closeface;
14978 REAL attrib, volume;
14979 int i;
14980
14981 // Let f face to p.
14982 adjustedgering(*horiz, CW);
14983 // Create the first tet t (from f and p).
14984 maketetrahedron(&firstnewtet);
14985 setorg (firstnewtet, org(*horiz));
14986 setdest(firstnewtet, dest(*horiz));
14987 setapex(firstnewtet, apex(*horiz));
14988 setoppo(firstnewtet, inspoint);
14989 for (i = 0; i < in->numberoftetrahedronattributes; i++) {
14990 attrib = elemattribute(horiz->tet, i);
14991 setelemattribute(firstnewtet.tet, i, attrib);
14992 }
14993 if (b->varvolume) {
14994 volume = volumebound(horiz->tet);
14995 setvolumebound(firstnewtet.tet, volume);
14996 }
14997 // Connect t to T.
14998 bond(firstnewtet, *horiz);
14999 // f is not on CH(T) anymore.
15000 enqueueflipface(*horiz, flipque);
15001 // Hull face number decreases.
15002 hullsize--;
15003
15004 // Call the faces of t which have p as a vertex "open" face.
15005 for (i = 0; i < 3; i++) {
15006 // Get an open face f_i of t.
15007 fnext(firstnewtet, openface);
15008 // Close f_i if it is still open.
15009 sym(openface, closeface);
15010 if (closeface.tet == dummytet) {
15011 closeopenface(&openface, flipque);
15012 }
15013 // Go to the next open face of t.
15014 enextself(firstnewtet);
15015 }
15016}
15017
15019// //
15020// Terminology: BC(p) and CBC(p), B(p) and C(p). //
15021// //
15022// Given an arbitrary point p, the Bowyer-Watson cavity BC(p) is formed by //
15023// tets whose circumspheres containing p. The outer faces of BC(p) form a //
15024// polyhedron B(p). //
15025// //
15026// If p is on a facet F, the constrained Bowyer-Watson cavity CBC(p) on F is //
15027// formed by subfaces of F whose circumspheres containing p. The outer edges //
15028// of CBC(p) form a polygon C(p). B(p) is separated into two parts by C(p), //
15029// denoted as B_1(p) and B_2(p), one of them may be empty (F is on the hull).//
15030// //
15031// If p is on a segment S which is shared by n facets. There exist n C(p)s, //
15032// each one is a non-closed polygon (without S). B(p) is split into n parts, //
15033// each of them is denoted as B_i(p), some B_i(p) may be empty. //
15034// //
15036
15038// //
15039// formbowatcavitysub() Form CBC(p) and C(p) on a facet F. //
15040// //
15041// Parameters: bp = p, bpseg = S, sublist = CBC(p), subceillist = C(p). //
15042// //
15043// CBC(p) contains at least one subface on input; S may be NULL which means //
15044// that p is inside a facet. On output, all subfaces of CBC(p) are infected, //
15045// and the edge rings are oriented to the same halfspace. //
15046// //
15048
15049void tetgenmesh::formbowatcavitysub(point bp, face* bpseg, list* sublist,
15050 list* subceillist)
15051{
15052 triface adjtet;
15053 face startsh, neighsh;
15054 face checkseg;
15055 point pa, pb, pc, pd;
15056 REAL sign;
15057 int i, j;
15058
15059 // Form CBC(p) and C(p) by a broadth-first searching.
15060 for (i = 0; i < sublist->len(); i++) {
15061 startsh = * (face *)(* sublist)[i]; // startsh = f.
15062 // Look for three neighbors of f.
15063 for (j = 0; j < 3; j++) {
15064 sspivot(startsh, checkseg);
15065 if (checkseg.sh == dummysh) {
15066 // Get its neighbor n.
15067 spivot(startsh, neighsh);
15068 // Is n already in CBC(p)?
15069 if (!sinfected(neighsh)) {
15070 stpivot(neighsh, adjtet);
15071 if (adjtet.tet == dummytet) {
15072 sesymself(neighsh);
15073 stpivot(neighsh, adjtet);
15074 }
15075 // For positive orientation that insphere() test requires.
15076 adjustedgering(adjtet, CW);
15077 pa = org(adjtet);
15078 pb = dest(adjtet);
15079 pc = apex(adjtet);
15080 pd = oppo(adjtet);
15081 sign = insphere(pa, pb, pc, pd, bp);
15082 if (sign >= 0.0) {
15083 // Orient edge ring of n according to that of f.
15084 if (sorg(neighsh) != sdest(startsh)) sesymself(neighsh);
15085 // Collect it into CBC(p).
15086 sinfect(neighsh);
15087 sublist->append(&neighsh);
15088 } else {
15089 subceillist->append(&startsh); // Found an edge of C(p).
15090 }
15091 }
15092 } else {
15093 // Do not cross a segment.
15094 if (bpseg != (face *) NULL) {
15095 if (checkseg.sh != bpseg->sh) {
15096 subceillist->append(&startsh); // Found an edge of C(p).
15097 }
15098 } else {
15099 subceillist->append(&startsh); // Found an edge of C(p).
15100 }
15101 }
15102 senextself(startsh);
15103 }
15104 }
15105
15106 if (b->verbose > 2) {
15107 printf(" Collect CBC(%d): %d subfaces, %d edges.\n", pointmark(bp),
15108 sublist->len(), subceillist->len());
15109 }
15110}
15111
15113// //
15114// formbowatcavityquad() Form BC_i(p) and B_i(p) in a quadrant. //
15115// //
15116// Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). //
15117// //
15118// BC_i(p) contains at least one tet on input. On finish, all tets collected //
15119// in BC_i(p) are infected. B_i(p) may not closed when p is on segment or in //
15120// facet. C(p) must be formed before this routine. Check the infect flag of //
15121// a subface to identify the unclosed side of B_i(p). These sides will be //
15122// closed by new subfaces of C(p)s. //
15123// //
15125
15126void tetgenmesh::formbowatcavityquad(point bp, list* tetlist, list* ceillist)
15127{
15128 triface starttet, neightet;
15129 face checksh;
15130 point pa, pb, pc, pd;
15131 REAL sign;
15132 int i;
15133
15134 // Form BC_i(p) and B_i(p) by a broadth-first searching.
15135 for (i = 0; i < tetlist->len(); i++) {
15136 starttet = * (triface *)(* tetlist)[i];
15137 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
15138 // Try to collect the neighbor of the face (f).
15139 tspivot(starttet, checksh);
15140 if (checksh.sh == dummysh) {
15141 // Get its neighbor n.
15142 sym(starttet, neightet);
15143 // Is n already in BC_i(p)?
15144 if (!infected(neightet)) {
15145 // For positive orientation that insphere() test requires.
15146 adjustedgering(neightet, CW);
15147 pa = org(neightet);
15148 pb = dest(neightet);
15149 pc = apex(neightet);
15150 pd = oppo(neightet);
15151 sign = insphere(pa, pb, pc, pd, bp);
15152 if (sign >= 0.0) {
15153 // Collect it into BC_i(p).
15154 infect(neightet);
15155 tetlist->append(&neightet);
15156 } else {
15157 ceillist->append(&starttet); // Found a face of B_i(p).
15158 }
15159 }
15160 } else {
15161 // Do not cross a boundary face.
15162 if (!sinfected(checksh)) {
15163 ceillist->append(&starttet); // Found a face of B_i(p).
15164 }
15165 }
15166 }
15167 }
15168
15169 if (b->verbose > 2) {
15170 printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp),
15171 tetlist->len(), ceillist->len());
15172 }
15173}
15174
15176// //
15177// formbowatcavitysegquad() Form BC_i(p) and B_i(p) in a segment quadrant.//
15178// //
15179// Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). //
15180// //
15181// BC_i(p) contains at least one tet on input. On finish, all tets collected //
15182// in BC_i(p) are infected. B_i(p) is not closed. C(p) must be formed before //
15183// this routine. Check the infect flag of a subface to identify the unclosed //
15184// sides of B_i(p). These sides will be closed by new subfaces of C(p)s. //
15185// //
15186// During the repair of encroaching subsegments, there may exist locally non-//
15187// Delaunay faces. These faces are collected in BC_i(p) either. B_i(p) has //
15188// to be formed later than BC_i(p). //
15189// //
15191
15192void tetgenmesh::formbowatcavitysegquad(point bp, list* tetlist,list* ceillist)
15193{
15194 triface starttet, neightet, cavtet;
15195 face checksh;
15196 point pa, pb, pc, pd, pe;
15197 REAL sign;
15198 int i;
15199
15200 // Form BC_i(p) by a broadth-first searching.
15201 for (i = 0; i < tetlist->len(); i++) {
15202 starttet = * (triface *)(* tetlist)[i];
15203 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
15204 // Try to collect the neighbor of the face f.
15205 tspivot(starttet, checksh);
15206 if (checksh.sh == dummysh) {
15207 // Get its neighbor n.
15208 sym(starttet, neightet);
15209 // Is n already in BC_i(p)?
15210 if (!infected(neightet)) {
15211 // For positive orientation that insphere() test requires.
15212 adjustedgering(neightet, CW);
15213 pa = org(neightet);
15214 pb = dest(neightet);
15215 pc = apex(neightet);
15216 pd = oppo(neightet);
15217 sign = insphere(pa, pb, pc, pd, bp);
15218 if (sign >= 0.0) {
15219 // Collect it into BC_i(p).
15220 infect(neightet);
15221 tetlist->append(&neightet);
15222 } else {
15223 // Check if the face is locally non-Delaunay.
15224 pe = oppo(starttet);
15225 sign = insphere(pa, pb, pc, pd, pe);
15226 if (sign >= 0.0) {
15227 // Collect it into BC_i(p).
15228 infect(neightet);
15229 tetlist->append(&neightet);
15230 }
15231 }
15232 }
15233 }
15234 }
15235 }
15236
15237 // Generate B_i(p).
15238 for (i = 0; i < tetlist->len(); i++) {
15239 cavtet = * (triface *)(* tetlist)[i];
15240 for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) {
15241 tspivot(cavtet, checksh);
15242 if (checksh.sh == dummysh) {
15243 sym(cavtet, neightet);
15244 if (!infected(neightet)) {
15245 ceillist->append(&cavtet); // Found a face of B(p).
15246 }
15247 } else {
15248 // Do not cross a boundary face.
15249 if (!sinfected(checksh)) {
15250 ceillist->append(&cavtet); // Found a face of B(p).
15251 }
15252 }
15253 }
15254 }
15255
15256 if (b->verbose > 2) {
15257 printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp),
15258 tetlist->len(), ceillist->len());
15259 }
15260}
15261
15263// //
15264// formbowatcavity() Form BC(p), B(p), CBC(p)s, and C(p)s. //
15265// //
15266// If 'bpseg'(S) != NULL, p is on segment S, else, p is on facet containing //
15267// 'bpsh' (F). 'n' returns the number of quadrants in BC(p). 'nmax' is the //
15268// maximum pre-allocated array length for the lists. //
15269// //
15271
15272void tetgenmesh::formbowatcavity(point bp, face* bpseg, face* bpsh, int* n,
15273 int* nmax, list** sublists, list** subceillists, list** tetlists,
15274 list** ceillists)
15275{
15276 list *sublist;
15277 triface adjtet;
15278 face startsh, spinsh;
15279 point pa, pb;
15280 int i, j;
15281
15282 *n = 0;
15283 if (bpseg != (face *) NULL) {
15284 // p is on segment S.
15285 bpseg->shver = 0;
15286 pa = sorg(*bpseg);
15287 pb = sdest(*bpseg);
15288 // Count the number of facets sharing at S.
15289 spivot(*bpseg, startsh);
15290 spinsh = startsh;
15291 do {
15292 (*n)++; // spinshlist->append(&spinsh);
15293 spivotself(spinsh);
15294 } while (spinsh.sh != startsh.sh);
15295 // *n is the number of quadrants around S.
15296 if (*n > *nmax) {
15297 // Reallocate arrays. Should not happen very often.
15298 delete [] tetlists;
15299 delete [] ceillists;
15300 delete [] sublists;
15301 delete [] subceillists;
15302 tetlists = new list*[*n];
15303 ceillists = new list*[*n];
15304 sublists = new list*[*n];
15305 subceillists = new list*[*n];
15306 *nmax = *n;
15307 }
15308 // Form CBC(p)s and C(p)s.
15309 spinsh = startsh;
15310 for (i = 0; i < *n; i++) {
15311 sublists[i] = new list(sizeof(face), NULL, 256);
15312 subceillists[i] = new list(sizeof(face), NULL, 256);
15313 // Set a subface f to start search.
15314 startsh = spinsh;
15315 // Let f face to the quadrant of interest (used in forming BC(p)).
15316 findedge(&startsh, pa, pb);
15317 sinfect(startsh);
15318 sublists[i]->append(&startsh);
15319 formbowatcavitysub(bp, bpseg, sublists[i], subceillists[i]);
15320 // Go to the next facet.
15321 spivotself(spinsh);
15322 }
15323 } else if (sublists != (list **) NULL) {
15324 // p is on a facet.
15325 *n = 2;
15326 // Form CBC(p) and C(p).
15327 sublists[0] = new list(sizeof(face), NULL, 256);
15328 subceillists[0] = new list(sizeof(face), NULL, 256);
15329 sinfect(*bpsh);
15330 sublists[0]->append(bpsh);
15331 formbowatcavitysub(bp, NULL, sublists[0], subceillists[0]);
15332 } else {
15333 // p is inside a tet.
15334 *n = 1;
15335 }
15336
15337 // Form BC_i(p) and B_i(p).
15338 for (i = 0; i < *n; i++) {
15339 tetlists[i] = new list(sizeof(triface), NULL, 256);
15340 ceillists[i] = new list(sizeof(triface), NULL, 256);
15341 if (sublists != (list **) NULL) {
15342 // There are C(p)s.
15343 sublist = ((bpseg == (face *) NULL) ? sublists[0] : sublists[i]);
15344 // Add all adjacent tets of C_i(p) into BC_i(p).
15345 for (j = 0; j < sublist->len(); j++) {
15346 startsh = * (face *)(* sublist)[j];
15347 // Adjust the side facing to the right quadrant for C(p).
15348 if ((bpseg == (face *) NULL) && (i == 1)) sesymself(startsh);
15349 stpivot(startsh, adjtet);
15350 if (adjtet.tet != dummytet) {
15351 if (!infected(adjtet)) {
15352 infect(adjtet);
15353 tetlists[i]->append(&adjtet);
15354 }
15355 }
15356 }
15357 if (bpseg != (face *) NULL) {
15358 // The quadrant is bounded by another facet.
15359 sublist = ((i < *n - 1) ? sublists[i + 1] : sublists[0]);
15360 for (j = 0; j < sublist->len(); j++) {
15361 startsh = * (face *)(* sublist)[j];
15362 // Adjust the side facing to the right quadrant for C(p).
15363 sesymself(startsh);
15364 stpivot(startsh, adjtet);
15365 if (adjtet.tet != dummytet) {
15366 if (!infected(adjtet)) {
15367 infect(adjtet);
15368 tetlists[i]->append(&adjtet);
15369 }
15370 }
15371 }
15372 }
15373 }
15374 // It is possible that BC_i(p) is empty.
15375 if (tetlists[i]->len() == 0) continue;
15376 // Collect the rest of tets of BC_i(p) and form B_i(p).
15377 // if (b->conformdel) {
15378 // formbowatcavitysegquad(bp, tetlists[i], ceillists[i]);
15379 // } else {
15380 formbowatcavityquad(bp, tetlists[i], ceillists[i]);
15381 // }
15382 }
15383}
15384
15386// //
15387// releasebowatcavity() Undo and free the memory allocated in routine //
15388// formbowatcavity(). //
15389// //
15391
15392void tetgenmesh::releasebowatcavity(face* bpseg, int n, list** sublists,
15393 list** subceillist, list** tetlists, list** ceillists)
15394{
15395 triface oldtet;
15396 face oldsh;
15397 int i, j;
15398
15399 if (sublists != (list **) NULL) {
15400 // Release CBC(p)s.
15401 for (i = 0; i < n; i++) {
15402 // Uninfect subfaces of CBC(p).
15403 for (j = 0; j < sublists[i]->len(); j++) {
15404 oldsh = * (face *)(* (sublists[i]))[j];
15405#ifdef SELF_CHECK
15406 assert(sinfected(oldsh));
15407#endif
15408 suninfect(oldsh);
15409 }
15410 delete sublists[i];
15411 delete subceillist[i];
15412 sublists[i] = (list *) NULL;
15413 subceillist[i] = (list *) NULL;
15414 if (bpseg == (face *) NULL) break;
15415 }
15416 }
15417 // Release BC(p).
15418 for (i = 0; i < n; i++) {
15419 // Uninfect tets of BC_i(p).
15420 for (j = 0; j < tetlists[i]->len(); j++) {
15421 oldtet = * (triface *)(* (tetlists[i]))[j];
15422#ifdef SELF_CHECK
15423 assert(infected(oldtet));
15424#endif
15425 uninfect(oldtet);
15426 }
15427 delete tetlists[i];
15428 delete ceillists[i];
15429 tetlists[i] = (list *) NULL;
15430 ceillists[i] = (list *) NULL;
15431 }
15432}
15433
15435// //
15436// validatebowatcavityquad() Valid B_i(p). //
15437// //
15438// B_i(p) is valid if all faces of B_i(p) are visible by p, else B_i(p) is //
15439// invalid. Each tet of BC_i(p) which has such a face is marked (uninfect). //
15440// They will be removed in updatebowatcavityquad(). //
15441// //
15442// Return TRUE if B(p) is valid, else, return FALSE. //
15443// //
15445
15446bool tetgenmesh::validatebowatcavityquad(point bp,list* ceillist,REAL maxcosd)
15447{
15448 triface ceiltet;
15449 point pa, pb, pc;
15450 REAL ori, cosd;
15451 int remcount, i;
15452
15453 // Check the validate of B(p), cut tets having invisible faces.
15454 remcount = 0;
15455 for (i = 0; i < ceillist->len(); i++) {
15456 ceiltet = * (triface *)(* ceillist)[i];
15457 if (infected(ceiltet)) {
15458 adjustedgering(ceiltet, CCW);
15459 pa = org(ceiltet);
15460 pb = dest(ceiltet);
15461 pc = apex(ceiltet);
15462 ori = orient3d(pa, pb, pc, bp);
15463 if (ori >= 0.0) {
15464 // Found an invisible face.
15465 uninfect(ceiltet);
15466 remcount++;
15467 continue;
15468 }
15469 // If a non-trival 'maxcosd' is given.
15470 if (maxcosd > -1.0) {
15471 // Get the maximal dihedral angle of tet abcp.
15472 tetalldihedral(pa, pb, pc, bp, NULL, &cosd, NULL);
15473 // Do not form the tet if the maximal dihedral angle is not reduced.
15474 if (cosd < maxcosd) {
15475 uninfect(ceiltet);
15476 remcount++;
15477 }
15478 }
15479 }
15480 }
15481 return remcount == 0;
15482}
15483
15485// //
15486// updatebowatcavityquad() Update BC_i(p) and reform B_i(p). //
15487// //
15488// B_i(p) is invalid and some tets in BC_i(p) have been marked to be removed //
15489// in validatebowatcavityquad(). This routine actually remove the cut tets //
15490// of BC_i(p) and re-form the B_i(p). //
15491// //
15493
15494void tetgenmesh::updatebowatcavityquad(list* tetlist, list* ceillist)
15495{
15496 triface cavtet, neightet;
15497 face checksh;
15498 int remcount, i;
15499
15500 remcount = 0;
15501 for (i = 0; i < tetlist->len(); i++) {
15502 cavtet = * (triface *)(* tetlist)[i];
15503 if (!infected(cavtet)) {
15504 tetlist->del(i, 1);
15505 remcount++;
15506 i--;
15507 }
15508 }
15509
15510 // Are there tets have been cut in BC_i(p)?
15511 if (remcount > 0) {
15512 // Re-form B_i(p).
15513 ceillist->clear();
15514 for (i = 0; i < tetlist->len(); i++) {
15515 cavtet = * (triface *)(* tetlist)[i];
15516 for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) {
15517 tspivot(cavtet, checksh);
15518 if (checksh.sh == dummysh) {
15519 sym(cavtet, neightet);
15520 if (!infected(neightet)) {
15521 ceillist->append(&cavtet); // Found a face of B_i(p).
15522 }
15523 } else {
15524 // Do not cross a boundary face.
15525 if (!sinfected(checksh)) {
15526 ceillist->append(&cavtet); // Found a face of B_i(p).
15527 }
15528 }
15529 }
15530 }
15531 if (b->verbose > 2) {
15532 printf(" Update BC_i(p): %d tets, %d faces.\n", tetlist->len(),
15533 ceillist->len());
15534 }
15535 }
15536}
15537
15539// //
15540// updatebowatcavitysub() Check and update CBC(p) and C(p). //
15541// //
15542// A CBC(p) is valid if all its subfaces are inside or on the hull of BC(p). //
15543// A subface s of CBC(p) is invalid if it is in one of the two cases: //
15544// (1) s is completely outside BC(p); //
15545// (2) s has two adjacent tets but only one of them is in BC(p); //
15546// s is removed from CBC(p) if it is invalid. If there is an adjacent tet of //
15547// s which is in BC(p), it gets removed from BC(p) too. If CBC(p) is updated,//
15548// C(p) is re-formed. //
15549// //
15550// A C(p) is valid if all its edges are on the hull of BC(p). An edge e of //
15551// C(p) may be inside BC(p) if e is a segment and belongs to only one facet. //
15552// To correct C(p), a tet of BC(p) which shields e gets removed. //
15553// //
15554// If BC(p) is formed with locally non-Delaunay check (b->conformdel > 0). //
15555// A boundary-consistent check is needed for non-segment edges of C(p). Let //
15556// e be such an edge, the subface f contains e and outside C(p) may belong //
15557// to B(p) due to the non-coplanarity of the facet definition. The tet of //
15558// BC(p) containing f gets removed to avoid creating a degenerate new tet. //
15559// //
15560// 'cutcount' accumulates the total number of cuttets(not only by this call).//
15561// //
15563
15564void tetgenmesh::updatebowatcavitysub(list* sublist, list* subceillist,
15565 int* cutcount)
15566{
15567 triface adjtet, rotface;
15568 face checksh, neighsh;
15569 face checkseg;
15570 point pa, pb, pc;
15571 REAL ori1, ori2;
15572 int remcount;
15573 int i, j;
15574
15575 remcount = 0;
15576 // Check the validity of CBC(p).
15577 for (i = 0; i < sublist->len(); i++) {
15578 checksh = * (face *)(* sublist)[i];
15579 // Check two adjacent tets of s.
15580 for (j = 0; j < 2; j++) {
15581 stpivot(checksh, adjtet);
15582 if (adjtet.tet != dummytet) {
15583 if (!infected(adjtet)) {
15584 // Could be either case (1) or (2).
15585 suninfect(checksh); // s survives.
15586 // If the sym. adjtet exists, it should remove from BC(p) too.
15587 sesymself(checksh);
15588 stpivot(checksh, adjtet);
15589 if (adjtet.tet != dummytet) {
15590 if (infected(adjtet)) {
15591 // Found an adj. tet in BC(p), remove it.
15592 uninfect(adjtet);
15593 (*cutcount)++;
15594 }
15595 }
15596 // Remove s from C(p).
15597 sublist->del(i, 1);
15598 i--;
15599 remcount++;
15600 break;
15601 }
15602 }
15603 sesymself(checksh);
15604 }
15605 }
15606 if (remcount > 0) {
15607 if (b->verbose > 2) {
15608 printf(" Removed %d subfaces from CBC(p).\n", remcount);
15609 }
15610 // Re-generate C(p).
15611 subceillist->clear();
15612 for (i = 0; i < sublist->len(); i++) {
15613 checksh = * (face *)(* sublist)[i];
15614 for (j = 0; j < 3; j++) {
15615 spivot(checksh, neighsh);
15616 if (!sinfected(neighsh)) {
15617 subceillist->append(&checksh);
15618 }
15619 senextself(checksh);
15620 }
15621 }
15622 if (b->verbose > 2) {
15623 printf(" Update CBC(p): %d subs, %d edges.\n", sublist->len(),
15624 subceillist->len());
15625 }
15626 }
15627
15628 // Check the validity of C(p).
15629 for (i = 0; i < subceillist->len(); i++) {
15630 checksh = * (face *)(* subceillist)[i];
15631 sspivot(checksh, checkseg);
15632 if (checkseg.sh != dummysh) {
15633 // A segment. Check if it is inside BC(p).
15634 stpivot(checksh, adjtet);
15635 if (adjtet.tet == dummytet) {
15636 sesym(checksh, neighsh);
15637 stpivot(neighsh, adjtet);
15638 }
15639 findedge(&adjtet, sorg(checkseg), sdest(checkseg));
15640 adjustedgering(adjtet, CCW);
15641 fnext(adjtet, rotface); // It's the same tet.
15642 // Rotate rotface (f), stop on either of the following cases:
15643 // (a) meet a subface, or
15644 // (b) enter an uninfected tet, or
15645 // (c) rewind back to adjtet.
15646 do {
15647 if (!infected(rotface)) break; // case (b)
15648 tspivot(rotface, neighsh);
15649 if (neighsh.sh != dummysh) break; // case (a)
15650 // Go to the next tet of the facing ring.
15651 fnextself(rotface);
15652 } while (apex(rotface) != apex(adjtet));
15653 // Is it case (c)?
15654 if (apex(rotface) == apex(adjtet)) {
15655 // The segment is enclosed by BC(p), invalid cavity.
15656 pa = org(adjtet);
15657 pb = dest(adjtet);
15658 pc = apex(adjtet);
15659 // Find the shield tet and cut it. Notice that the shield tet may
15660 // not be unique when there are four coplanar points, ie.,
15661 // ori1 * ori2 == 0.0. In such case, choose either of them.
15662 fnext(adjtet, rotface);
15663 do {
15664 fnextself(rotface);
15665 assert(infected(rotface));
15666 ori1 = orient3d(pa, pb, pc, apex(rotface));
15667 ori2 = orient3d(pa, pb, pc, oppo(rotface));
15668 } while (ori1 * ori2 > 0.0);
15669 // Cut this tet from BC(p).
15670 uninfect(rotface);
15671 (*cutcount)++;
15672 }
15673 } else {
15674 /*// An edge. Check if boundary-consistency should be enforced.
15675 if (b->conformdel > 0) {
15676 // Get the adj-sub n at e, it must be outside C(p).
15677 spivot(checksh, neighsh);
15678 assert(!sinfected(neighsh));
15679 // Check if n is on B(p).
15680 for (j = 0; j < 2; j++) {
15681 stpivot(neighsh, adjtet);
15682 if (adjtet.tet != dummytet) {
15683 if (infected(adjtet)) {
15684 uninfect(adjtet);
15685 (*cutcount)++;
15686 }
15687 }
15688 sesymself(neighsh);
15689 }
15690 } */
15691 }
15692 }
15693}
15694
15696// //
15697// trimbowatcavity() Validate B(p), CBC(p)s and C(p)s, update BC(p). //
15698// //
15699// A B(p) is valid if all its faces are visible by p. If a face f of B(p) is //
15700// found invisible by p, the tet of BC(p) containing f gets removed and B(p) //
15701// is refromed. The new B(p) may still contain invisible faces by p. Iterat- //
15702// ively do the above procedure until B(p) is satisfied. //
15703// //
15704// A CBC(p) is valid if each subface of CBC(p) is either on the hull of BC(p)//
15705// or completely inside BC(p). If a subface s of CBC(p) is not valid, it is //
15706// removed from CBC(p) and C(p) is reformed. If there exists a tet t of BC(p)//
15707// containg s, t is removed from BC(p). The process for validating BC(p) and //
15708// B(p) is re-excuted. //
15709// //
15710// A C(p) is valid if each edge of C(p) is on the hull of BC(p). If an edge //
15711// e of C(p) is invalid (e should be a subsegment which only belong to one //
15712// facet), a tet of BC(p) which contains e and has two other faces shielding //
15713// e is removed. The process for validating BC(p) and B(p) is re-excuted. //
15714// //
15715// If either BC(p) or CBC(p) becomes empty. No valid BC(p) is found, return //
15716// FALSE. else, return TRUE. //
15717// //
15719
15720bool tetgenmesh::trimbowatcavity(point bp, face* bpseg, int n, list** sublists,
15721 list** subceillists, list** tetlists, list** ceillists, REAL maxcosd)
15722{
15723 bool valflag;
15724 int oldnum, cutnum, cutcount;
15725 int i;
15726
15727 cutnum = 0; // Count the total number of cut-off tets of BC(p).
15728 valflag = true;
15729
15730 do {
15731 // Validate BC(p), B(p).
15732 for (i = 0; i < n && valflag; i++) {
15733 oldnum = tetlists[i]->len();
15734 // Iteratively validate BC_i(p) and B_i(p).
15735 while (!validatebowatcavityquad(bp, ceillists[i], maxcosd)) {
15736 // Update BC_i(p) and B_i(p).
15737 updatebowatcavityquad(tetlists[i], ceillists[i]);
15738 valflag = tetlists[i]->len() > 0;
15739 }
15740 cutnum += (oldnum - tetlists[i]->len());
15741 }
15742 if (valflag && (sublists != (list **) NULL)) {
15743 // Validate CBC(p), C(p).
15744 cutcount = 0;
15745 for (i = 0; i < n; i++) {
15746 updatebowatcavitysub(sublists[i], subceillists[i], &cutcount);
15747 // Only do once if p is on a facet.
15748 if (bpseg == (face *) NULL) break;
15749 }
15750 // Are there cut tets?
15751 if (cutcount > 0) {
15752 // Squeeze all cut tets in BC(p), keep valflag once it gets FLASE.
15753 for (i = 0; i < n; i++) {
15754 if (tetlists[i]->len() > 0) {
15755 updatebowatcavityquad(tetlists[i], ceillists[i]);
15756 if (valflag) {
15757 valflag = tetlists[i]->len() > 0;
15758 }
15759 }
15760 }
15761 cutnum += cutcount;
15762 // Go back to valid the updated BC(p).
15763 continue;
15764 }
15765 }
15766 break; // Leave the while-loop.
15767 } while (true);
15768
15769 // Check if any CBC(p) becomes non-empty.
15770 if (valflag && (sublists != (list **) NULL)) {
15771 for (i = 0; i < n && valflag; i++) {
15772 valflag = (sublists[i]->len() > 0);
15773 if (bpseg == (face *) NULL) break;
15774 }
15775 }
15776
15777 if (valflag && (cutnum > 0)) {
15778 // Accumulate counters.
15779 if (bpseg != (face *) NULL) {
15780 updsegcount++;
15781 } else if (sublists != (list **) NULL) {
15782 updsubcount++;
15783 } else {
15784 updvolcount++;
15785 }
15786 }
15787
15788 if (!valflag) {
15789 // Accumulate counters.
15790 if (bpseg != (face *) NULL) {
15791 failsegcount++;
15792 } else if (sublists != (list **) NULL) {
15793 failsubcount++;
15794 } else {
15795 failvolcount++;
15796 }
15797 }
15798
15799 return valflag;
15800}
15801
15803// //
15804// bowatinsertsite() Insert a point using the Bowyer-Watson method. //
15805// //
15806// Parameters: 'bp' = p, 'splitseg' = S, 'n' = the number of quadrants, //
15807// 'sublists', an array of CBC_i(p)s, 'subceillists', an array of C_i(p)s, //
15808// 'tetlists', an array of BC_i(p)s, 'ceillists', an array of B_i(p)s. //
15809// //
15810// If p is inside the mesh domain, then S = NULL, n = 1, CBC(p) and C(p) are //
15811// NULLs. 'tetlists[0]' = BC(p), 'ceillists[0]' = B(p). //
15812// If p is on a facet F, then S = NULL, n = 2, and 'subceillists[0]' = C(p), //
15813// 'subceillists[1]' is not needed (set it to NULL). B_1(p) and B_2(p) are //
15814// in 'ceillists[0]' and 'ceillists[1]'. //
15815// If p is on a segment S, then F(S) is a list of subfaces around S, and n = //
15816// len(F(S)), there are n C_i(p)s and B_i(p)s supplied in 'subceillists[i]'//
15817// and 'ceillists[i]'. //
15818// //
15819// If 'verlist' != NULL, it returns a list of vertices which connect to p. //
15820// This vertices are used for interpolating size of p. //
15821// //
15822// If 'flipque' != NULL, it returns a list of internal faces of new tets in //
15823// BC(p), faces on C(p)s are excluded. These faces may be locally non- //
15824// Delaunay and will be flipped if they are flippable. Such non-Delaunay //
15825// faces may exist when p is inserted to split an encroaching segment. //
15826// //
15827// 'chkencseg', 'chkencsub', and 'chkbadtet' are flags that indicate whether //
15828// or not there should be checks for the creation of encroached subsegments, //
15829// subfaces, or bad quality tets. If 'chkencseg' = TRUE, the encroached sub- //
15830// segments are added to the list of subsegments to be split. //
15831// //
15832// On return, 'ceillists' returns Star(p). //
15833// //
15835
15836void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists,
15837 list** subceillists, list** tetlists, list** ceillists, list* verlist,
15838 queue* flipque, bool chkencseg, bool chkencsub, bool chkbadtet)
15839{
15840 list *ceillist, *subceillist;
15841 triface oldtet, newtet, newface, rotface, neightet;
15842 face oldsh, newsh, newedge, checksh;
15843 face spinsh, casingin, casingout;
15844 face *apsegshs, *pbsegshs;
15845 face apseg, pbseg, checkseg;
15846 point pa, pb, pc;
15847 pa=NULL;
15848 pb=NULL;
15849 REAL attrib, volume;
15850 int idx, i, j, k;
15851
15852 apsegshs = NULL;
15853 pbsegshs = NULL;
15854
15855 if (b->verbose > 1) {
15856 printf(" Insert point %d (%.12g, %.12g, %.12g)", pointmark(bp), bp[0],
15857 bp[1], bp[2]);
15858 }
15859 if (splitseg != (face *) NULL) {
15860 if (b->verbose > 1) {
15861 printf(" on segment.\n");
15862 }
15863 bowatsegcount++;
15864 } else {
15865 if (subceillists != (list **) NULL) {
15866 if (b->verbose > 1) {
15867 printf(" on facet.\n");
15868 }
15869 bowatsubcount++;
15870 } else {
15871 if (b->verbose > 1) {
15872 printf(" in volume.\n");
15873 }
15874 bowatvolcount++;
15875 }
15876 }
15877
15878 // Create new tets to fill B(p).
15879 for (k = 0; k < n; k++) {
15880 // Create new tets from each B_i(p).
15881 ceillist = ceillists[k];
15882 for (i = 0; i < ceillist->len(); i++) {
15883 oldtet = * (triface *)(* ceillist)[i];
15884 adjustedgering(oldtet, CCW);
15885 pa = org(oldtet);
15886 pb = dest(oldtet);
15887 pc = apex(oldtet);
15888 maketetrahedron(&newtet);
15889 setorg(newtet, pa);
15890 setdest(newtet, pb);
15891 setapex(newtet, pc);
15892 setoppo(newtet, bp);
15893 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
15894 attrib = elemattribute(oldtet.tet, j);
15895 setelemattribute(newtet.tet, j, attrib);
15896 }
15897 if (b->varvolume) {
15898 volume = volumebound(oldtet.tet);
15899 if (volume > 0.0) {
15900 if (!b->fixedvolume && b->refine) {
15901 // '-r -a' switches and a .vol file case. Enlarge the maximum
15902 // volume constraint for the new tets. Hence the new points
15903 // only spread near the original constrained tet.
15904 volume *= 1.2;
15905 }
15906 }
15907 setvolumebound(newtet.tet, volume);
15908 }
15909 sym(oldtet, neightet);
15910 tspivot(oldtet, checksh);
15911 if (neightet.tet != dummytet) {
15912 bond(newtet, neightet);
15913 }
15914 if (checksh.sh != dummysh) {
15915 tsbond(newtet, checksh);
15916 }
15917 if (verlist != (list *) NULL) {
15918 // Collect vertices connecting to p.
15919 idx = pointmark(pa);
15920 if (idx >= 0) {
15921 setpointmark(pa, -idx - 1);
15922 verlist->append(&pa);
15923 }
15924 idx = pointmark(pb);
15925 if (idx >= 0) {
15926 setpointmark(pb, -idx - 1);
15927 verlist->append(&pb);
15928 }
15929 idx = pointmark(pc);
15930 if (idx >= 0) {
15931 setpointmark(pc, -idx - 1);
15932 verlist->append(&pc);
15933 }
15934 }
15935 // Replace the tet by the newtet for checking the quality.
15936 * (triface *)(* ceillist)[i] = newtet;
15937 }
15938 }
15939 if (verlist != (list *) NULL) {
15940 // Uninfect collected vertices.
15941 for (i = 0; i < verlist->len(); i++) {
15942 pa = * (point *)(* verlist)[i];
15943 idx = pointmark(pa);
15944 setpointmark(pa, -(idx + 1));
15945 }
15946 }
15947
15948 // Connect new tets of B(p). Not all faces of new tets can be connected,
15949 // e.g., if there are empty B_i(p)s.
15950 for (k = 0; k < n; k++) {
15951 ceillist = ceillists[k];
15952 for (i = 0; i < ceillist->len(); i++) {
15953 newtet = * (triface *)(* ceillist)[i];
15954 newtet.ver = 0;
15955 for (j = 0; j < 3; j++) {
15956 fnext(newtet, newface);
15957 sym(newface, neightet);
15958 if (neightet.tet == dummytet) {
15959 // Find the neighbor face by rotating the faces at edge ab.
15960 esym(newtet, rotface);
15961 pa = org(rotface);
15962 pb = dest(rotface);
15963 while (fnextself(rotface));
15964 // Do we meet a boundary face?
15965 tspivot(rotface, checksh);
15966 if (checksh.sh != dummysh) {
15967 // Walk through the boundary and continue to rotate faces.
15968 do {
15969 findedge(&checksh, pa, pb);
15970 sfnextself(checksh);
15971 assert((sorg(checksh) == pa) && (sdest(checksh) == pb));
15972 stpivot(checksh, rotface);
15973 if (infected(rotface)) {
15974 // Meet an old tet of B_i(p). This side is on the hull and
15975 // will be connected to a new subface created in C(p).
15976 break;
15977 }
15978 findedge(&rotface, pa, pb);
15979 while (fnextself(rotface));
15980 tspivot(rotface, checksh);
15981 } while (checksh.sh != dummysh);
15982 }
15983 // The rotface has edge ab, but it may not have newpt.
15984 if (apex(rotface) == apex(newface)) {
15985 // Bond the two tets together.
15986 bond(newface, rotface);
15987 // Queue (uniquely) this face if 'flipque' is given.
15988 if (flipque != (queue *) NULL) {
15989 enqueueflipface(newface, flipque);
15990 }
15991 }
15992 }
15993 enextself(newtet);
15994 }
15995 }
15996 }
15997
15998 if (subceillists != (list **) NULL) {
15999 // There are C(p)s.
16000 if (splitseg != (face *) NULL) {
16001 // S (ab) is split by p.
16002 splitseg->shver = 0;
16003 pa = sorg(*splitseg);
16004 pb = sdest(*splitseg);
16005 // Allcate two arrays for saving the subface rings of the two new
16006 // segments a->p and p->b.
16007 apsegshs = new face[n];
16008 pbsegshs = new face[n];
16009 }
16010
16011 // For each C_k(p), do the following:
16012 // (1) Create new subfaces to fill C_k(p), insert them into B(p);
16013 // (2) Connect new subfaces to each other;
16014 for (k = 0; k < n; k++) {
16015 subceillist = subceillists[k];
16016
16017 // Check if 'hullsize' should be updated.
16018 oldsh = * (face *)(* subceillist)[0];
16019 stpivot(oldsh, neightet);
16020 if (neightet.tet != dummytet) {
16021 sesymself(oldsh);
16022 stpivot(oldsh, neightet);
16023 }
16024 if (neightet.tet == dummytet) {
16025 // The hull size changes.
16026 hullsize += (subceillist->len() - sublists[k]->len());
16027 }
16028
16029 // (1) Create new subfaces to fill C_k(p), insert them into B(p).
16030 for (i = 0; i < subceillist->len(); i++) {
16031 oldsh = * (face *)(* subceillist)[i];
16032 makeshellface(subfaces, &newsh);
16033 setsorg(newsh, sorg(oldsh));
16034 setsdest(newsh, sdest(oldsh));
16035 setsapex(newsh, bp);
16036 if (b->quality && varconstraint) {
16037 setareabound(newsh, areabound(oldsh));
16038 }
16039 setshellmark(newsh, shellmark(oldsh));
16040 setshelltype(newsh, shelltype(oldsh));
16041 if (checkpbcs) {
16042 setshellpbcgroup(newsh, shellpbcgroup(oldsh));
16043 }
16044 // Replace oldsh by newsh at the edge.
16045 spivot(oldsh, casingout);
16046 sspivot(oldsh, checkseg);
16047 if (checkseg.sh != dummysh) {
16048 // A segment. Insert s into the face ring, ie, s_in -> s -> s_out.
16049 if (oldsh.sh != casingout.sh) {
16050 // s is not bonded to itself.
16051 spinsh = casingout;
16052 do {
16053 casingin = spinsh;
16054 spivotself(spinsh);
16055 } while (sapex(spinsh) != sapex(oldsh));
16056 assert(casingin.sh != oldsh.sh);
16057 // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out).
16058 sbond1(casingin, newsh);
16059 sbond1(newsh, casingout);
16060 } else {
16061 // Bond newsh -> newsh.
16062 sbond(newsh, newsh);
16063 }
16064 // Bond the segment.
16065 ssbond(newsh, checkseg);
16066 } else {
16067 // Bond s <-> s_out (and dissolve s_out -> s_old).
16068 sbond(newsh, casingout);
16069 }
16070
16071 // Insert newsh into B(p). Use the coonections of oldsh.
16072 stpivot(oldsh, neightet);
16073 if (neightet.tet == dummytet) {
16074 sesymself(oldsh);
16075 sesymself(newsh); // Keep the same orientation as oldsh.
16076 stpivot(oldsh, neightet);
16077 }
16078 assert(infected(neightet));
16079 // Set on the rotating edge.
16080 findedge(&neightet, sorg(oldsh), sdest(oldsh));
16081 // Choose the rotating direction (to the inside of B(p)).
16082 adjustedgering(neightet, CCW);
16083 rotface = neightet;
16084 // Rotate face. Stop at a non-infected tet t (not in B(p)) or a
16085 // hull face f (on B(p)). Get the neighbor n of t or f. n is
16086 // a new tet that has just been created to fill B(p).
16087 do {
16088 fnextself(rotface);
16089 sym(rotface, neightet);
16090 if (neightet.tet == dummytet) {
16091 tspivot(rotface, checksh);
16092 assert(checksh.sh != dummysh);
16093 stpivot(checksh, newtet);
16094 break;
16095 } else if (!infected(neightet)) {
16096 sym(neightet, newtet);
16097 break;
16098 }
16099 } while (true);
16100 assert(newtet.tet != rotface.tet);
16101 // Set the rotating edge of n.
16102 findedge(&newtet, sorg(oldsh), sdest(oldsh));
16103 // Choose the rotating direction (to the inside of B(p)).
16104 adjustedgering(newtet, CCW);
16105 fnext(newtet, newface);
16106 assert(apex(newface) == bp);
16107 // newsh has already been oriented toward n.
16108 tsbond(newface, newsh);
16109 sym(newface, neightet); // 'neightet' maybe outside.
16110 sesymself(newsh);
16111 tsbond(neightet, newsh); // Bond them anyway.
16112
16113 // Replace oldsh by newsh in list.
16114 * (face *)(* subceillist)[i] = newsh;
16115 }
16116
16117 // (2) Connect new subfaces to each other.
16118 for (i = 0; i < subceillist->len(); i++) {
16119 // Get a face cdp.
16120 newsh = * (face *)(* subceillist)[i];
16121 // Get a new tet containing cdp.
16122 stpivot(newsh, newtet);
16123 if (newtet.tet == dummytet) {
16124 sesymself(newsh);
16125 stpivot(newsh, newtet);
16126 }
16127 for (j = 0; j < 2; j++) {
16128 if (j == 0) {
16129 senext(newsh, newedge); // edge dp.
16130 } else {
16131 senext2(newsh, newedge); // edge pc.
16132 sesymself(newedge); // edge cp.
16133 }
16134 if (splitseg != (face *) NULL) {
16135 // Don not operate on newedge if it is ap or pb.
16136 if (sorg(newedge) == pa) {
16137 apsegshs[k] = newedge;
16138 continue;
16139 } else if (sorg(newedge) == pb) {
16140 pbsegshs[k] = newedge;
16141 continue;
16142 }
16143 }
16144 // There should no segment inside the cavity. Check it.
16145 sspivot(newedge, checkseg);
16146 assert(checkseg.sh == dummysh);
16147 spivot(newedge, casingout);
16148 if (casingout.sh == dummysh) {
16149 rotface = newtet;
16150 findedge(&rotface, sorg(newedge), sdest(newedge));
16151 // Rotate newtet until meeting a new subface which contains
16152 // newedge. It must exist since newedge is not a seg.
16153 adjustedgering(rotface, CCW);
16154 do {
16155 fnextself(rotface);
16156 tspivot(rotface, checksh);
16157 if (checksh.sh != dummysh) break;
16158 } while (true);
16159 findedge(&checksh, sorg(newedge), sdest(newedge));
16160 sbond(newedge, checksh);
16161 }
16162 }
16163 }
16164 // Only do once if p is on a facet.
16165 if (splitseg == (face *) NULL) break;
16166 } // for (k = 0; k < n; k++)
16167
16168 if (splitseg != (face *) NULL) {
16169 // Update a->b to be a->p.
16170 apseg = *splitseg;
16171 setsdest(apseg, bp);
16172 // Create a new subsegment p->b.
16173 makeshellface(subsegs, &pbseg);
16174 setsorg(pbseg, bp);
16175 setsdest(pbseg, pb);
16176 // p->b gets the same mark and segment type as a->p.
16177 setshellmark(pbseg, shellmark(apseg));
16178 setshelltype(pbseg, shelltype(apseg));
16179 if (b->quality && varconstraint) {
16180 // Copy the area bound into the new subsegment.
16181 setareabound(pbseg, areabound(apseg));
16182 }
16183 senext(apseg, checkseg);
16184 // Get the old connection at b of a->b.
16185 spivot(checkseg, casingout);
16186 // Bond a->p and p->b together.
16187 senext2(pbseg, casingin);
16188 sbond(casingin, checkseg);
16189 if (casingout.sh != dummysh) {
16190 // There is a subsegment connect at b of p->b.
16191 casingout.shver = 0;
16192#ifdef SELF_CHECK
16193 assert(sorg(casingout) == pb);
16194#endif
16195 senext2self(casingout);
16196 senext(pbseg, casingin);
16197 sbond(casingin, casingout);
16198 }
16199
16200 // Bond all new subfaces to a->p and p->b.
16201 for (i = 0; i < n; i++) {
16202 spinsh = apsegshs[i];
16203 findedge(&spinsh, pa, bp);
16204 ssbond(spinsh, apseg);
16205 spinsh = pbsegshs[i];
16206 findedge(&spinsh, bp, pb);
16207 ssbond(spinsh, pbseg);
16208 }
16209 // Bond all subfaces share at a->p together.
16210 for (i = 0; i < n; i++) {
16211 spinsh = apsegshs[i];
16212 if (i < (n - 1)) {
16213 casingout = apsegshs[i + 1];
16214 } else {
16215 casingout = apsegshs[0];
16216 }
16217 sbond1(spinsh, casingout);
16218 }
16219 // Bond all subfaces share at p->b together.
16220 for (i = 0; i < n; i++) {
16221 spinsh = pbsegshs[i];
16222 if (i < (n - 1)) {
16223 casingout = pbsegshs[i + 1];
16224 } else {
16225 casingout = pbsegshs[0];
16226 }
16227 sbond1(spinsh, casingout);
16228 }
16229 delete [] apsegshs;
16230 delete [] pbsegshs;
16231
16232 // Check for newly encroached subsegments if the flag is set.
16233 if (chkencseg) {
16234 // Check if a->p and p->b are encroached by other vertices.
16235 checkseg4encroach(&apseg, NULL, NULL, true);
16236 checkseg4encroach(&pbseg, NULL, NULL, true);
16237 // Check if the adjacent segments are encroached by p.
16238 tallencsegs(bp, n, ceillists);
16239 }
16240 } // if (splitseg != (face *) NULL)
16241
16242 // Delete subfaces of old CBC_i(p)s.
16243 for (k = 0; k < n; k++) {
16244 for (i = 0; i < sublists[k]->len(); i++) {
16245 oldsh = * (face *)(* (sublists[k]))[i];
16246 shellfacedealloc(subfaces, oldsh.sh);
16247 }
16248 // Clear the list so that the subs will not get unmarked later in
16249 // routine releasebowatcavity() which only frees the memory.
16250 sublists[k]->clear();
16251 // Only do once if p is on a facet.
16252 if (splitseg == (face *) NULL) break;
16253 }
16254
16255 // Check for newly encroached subfaces if the flag is set.
16256 if (chkencsub) {
16257 // Check if new subfaces of C_i(p) are encroached by other vertices.
16258 for (k = 0; k < n; k++) {
16259 subceillist = subceillists[k];
16260 for (i = 0; i < subceillist->len(); i++) {
16261 newsh = * (face *)(* subceillist)[i];
16262 checksub4encroach(&newsh, NULL, true);
16263 }
16264 // Only do once if p is on a facet.
16265 if (splitseg == (face *) NULL) break;
16266 }
16267 // Check if the adjacent subfaces are encroached by p.
16268 tallencsubs(bp, n, ceillists);
16269 }
16270 } // if (subceillists != (list **) NULL)
16271
16272 // Delete tets of old BC_i(p)s.
16273 for (k = 0; k < n; k++) {
16274 for (i = 0; i < tetlists[k]->len(); i++) {
16275 oldtet = * (triface *)(* (tetlists[k]))[i];
16276 tetrahedrondealloc(oldtet.tet);
16277 }
16278 // Clear the list so that the tets will not get unmarked later in
16279 // routine releasebowatcavity() which only frees the memory.
16280 tetlists[k]->clear();
16281 }
16282
16283 // check for bad quality tets if the flags is set.
16284 if (chkbadtet) {
16285 for (k = 0; k < n; k++) {
16286 ceillist = ceillists[k];
16287 for (i = 0; i < ceillist->len(); i++) {
16288 newtet = * (triface *)(* ceillist)[i];
16289 checktet4badqual(&newtet, true);
16290 }
16291 }
16292 }
16293
16294 if (flipque != (queue *) NULL) {
16295 // Newly created internal faces of BC(p) (excluding faces on C(p)s) are
16296 // in 'flipque'. Some of these faces may be locally non-Delaunay due,
16297 // to the existence of non-constrained tets. check and fix them.
16298 repairflipcount += flip(flipque, NULL);
16299 }
16300}
16301
16302//
16303// End of mesh transformation routines
16304//
16305
16306//
16307// Begin Delaunay tetrahedralization routines
16308//
16309
16311// //
16312// formstarpolyhedron() Get the star ployhedron of a point 'pt'. //
16313// //
16314// The polyhedron P is formed by faces of tets having 'pt' as a vertex. If //
16315// 'complete' is TRUE, P is the complete star of 'pt'. Otherwise, P is boun- //
16316// ded by subfaces, i.e. P is only part of the star of 'pt'. //
16317// //
16318// 'tetlist' T returns the tets, it has one of such tets on input. Moreover, //
16319// if t is in T, then oppo(t) = p. Topologically, T is the star of p; and //
16320// the faces of T is the link of p. 'verlist' V returns the vertices of T. //
16321// //
16323
16324void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist,
16325 bool complete)
16326{
16327 triface starttet, neightet;
16328 face checksh;
16329 point ver[3];
16330 int idx, i, j;
16331
16332 // Get a tet t containing p.
16333 starttet = * (triface *)(* tetlist)[0];
16334 // Let oppo(t) = p.
16335 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
16336 if (oppo(starttet) == pt) break;
16337 }
16338 assert(starttet.loc < 4);
16339 // Add t into T.
16340 * (triface *)(* tetlist)[0] = starttet;
16341 infect(starttet);
16342 if (verlist != (list *) NULL) {
16343 // Add three verts of t into V.
16344 ver[0] = org(starttet);
16345 ver[1] = dest(starttet);
16346 ver[2] = apex(starttet);
16347 for (i = 0; i < 3; i++) {
16348 // Mark the vert by inversing the index of the vert.
16349 idx = pointmark(ver[i]);
16350 setpointmark(ver[i], -idx - 1); // -1 to distinguish the zero.
16351 verlist->append(&(ver[i]));
16352 }
16353 }
16354
16355 // Find other tets by a broadth-first search.
16356 for (i = 0; i < tetlist->len(); i++) {
16357 starttet = * (triface *)(* tetlist)[i];
16358 starttet.ver = 0;
16359 for (j = 0; j < 3; j++) {
16360 fnext(starttet, neightet);
16361 tspivot(neightet, checksh);
16362 // Should we cross a subface.
16363 if ((checksh.sh == dummysh) || complete) {
16364 // Get the neighbor n.
16365 symself(neightet);
16366 if ((neightet.tet != dummytet) && !infected(neightet)) {
16367 // Let oppo(n) = p.
16368 for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
16369 if (oppo(neightet) == pt) break;
16370 }
16371 assert(neightet.loc < 4);
16372 // Add n into T.
16373 infect(neightet);
16374 tetlist->append(&neightet);
16375 if (verlist != (list *) NULL) {
16376 // Add the apex vertex in n into V.
16377 ver[0] = org(starttet);
16378 ver[1] = dest(starttet);
16379 findedge(&neightet, ver[0], ver[1]);
16380 ver[2] = apex(neightet);
16381 idx = pointmark(ver[2]);
16382 if (idx >= 0) {
16383 setpointmark(ver[2], -idx - 1);
16384 verlist->append(&(ver[2]));
16385 }
16386 }
16387 }
16388 }
16389 enextself(starttet);
16390 }
16391 }
16392
16393 // Uninfect tets.
16394 for (i = 0; i < tetlist->len(); i++) {
16395 starttet = * (triface *)(* tetlist)[i];
16396 uninfect(starttet);
16397 }
16398 if (verlist != (list *) NULL) {
16399 // Uninfect vertices.
16400 for (i = 0; i < verlist->len(); i++) {
16401 ver[0] = * (point *)(* verlist)[i];
16402 idx = pointmark(ver[0]);
16403 setpointmark(ver[0], -(idx + 1));
16404 }
16405 }
16406}
16407
16409// //
16410// unifypoint() Unify two distinct points if they're very close. //
16411// //
16412// This function is used for dealing with inputs from CAD tools. Two points //
16413// p and q are unified if: dist(p, q) / longest < eps. Where dist() is the //
16414// Euclidean distance between p and q, longest is the maximum edge size of //
16415// the input point set, eps is the tolerrence specified by user, default is //
16416// 1e-6, it can be adjusted by '-T' switch. //
16417// //
16419
16420bool tetgenmesh::unifypoint(point testpt, triface *starttet, enum locateresult
16421 loc, REAL eps)
16422{
16423 triface symtet, spintet;
16424 point checkpt, tapex;
16425 REAL tol;
16426 bool merged;
16427 int hitbdry;
16428 int i;
16429
16430 merged = false;
16431 tol = longest * eps;
16432 if ((loc == OUTSIDE) || (loc == INTETRAHEDRON) || (loc == ONFACE)) {
16433 // Check p is close to the four corners of the tet.
16434 for (i = 0; i < 4; i++) {
16435 checkpt = (point) starttet->tet[4 + i];
16436 if (distance(testpt, checkpt) < tol) {
16437 merged = true; // Found a merge point p'.
16438 break;
16439 }
16440 }
16441 if (!merged && (loc == ONFACE)) {
16442 // Check the opposite point of the neighbor tet if it exists.
16443 sym(*starttet, symtet);
16444 if (symtet.tet != dummytet) {
16445 checkpt = oppo(symtet);
16446 if (distance(testpt, checkpt) < tol) {
16447 merged = true; // Found a merge point p'.
16448 }
16449 }
16450 }
16451 } else if (loc == ONEDGE) {
16452 // Check two endpoints of the edge.
16453 checkpt = org(*starttet);
16454 if (distance(testpt, checkpt) < tol) {
16455 merged = true; // Found a merge point p'.
16456 }
16457 if (!merged) {
16458 checkpt = dest(*starttet);
16459 if (distance(testpt, checkpt) < tol) {
16460 merged = true; // Found a merge point p'.
16461 }
16462 }
16463 if (!merged) {
16464 // Check apexes of the faces having the edge.
16465 spintet = *starttet;
16466 tapex = apex(*starttet);
16467 hitbdry = 0;
16468 do {
16469 checkpt = apex(spintet);
16470 if (distance(testpt, checkpt) < tol) {
16471 merged = true; // Found a merge point p'.
16472 break;
16473 }
16474 if (!fnextself(spintet)) {
16475 hitbdry++;
16476 if (hitbdry < 2) {
16477 esym(*starttet, spintet);
16478 if (!fnextself(spintet)) {
16479 hitbdry++;
16480 }
16481 }
16482 }
16483 } while ((apex(spintet) != tapex) && (hitbdry < 2));
16484 }
16485 }
16486 if (merged) {
16487 if (b->object != tetgenbehavior::STL) {
16488 if (!b->quiet) {
16489 printf("Warning: Point %d is unified to point %d.\n",
16490 pointmark(testpt), pointmark(checkpt));
16491 }
16492 // Count the number of duplicated points.
16493 dupverts++;
16494 }
16495 // Remember it is a duplicated point.
16496 setpointtype(testpt, DUPLICATEDVERTEX);
16497 // Set a pointer to the point it duplicates.
16498 setpoint2ppt(testpt, checkpt);
16499 }
16500 return merged;
16501}
16502
16504// //
16505// incrflipdelaunay() Construct a delaunay tetrahedrization from a set of //
16506// 3D points by the incremental flip algorithm. //
16507// //
16508// The incremental flip algorithm (by Edelsbrunner and Shah) can be describ- //
16509// ed as follows: //
16510// //
16511// S be a set of points in 3D, Let 4 <= i <= n and assume that the //
16512// Delaunay tetrahedralization of the first i-1 points in S is already //
16513// constructed; call it D(i-1). Add the i-th point p_i (belong to S) to //
16514// D(i-1), and restore Delaunayhood by flipping; this result in D(i). //
16515// Repeat this procedure until i = n. //
16516// //
16517// This strategy always leads to the Delaunay triangulation of a point set. //
16518// The return value is the number of convex hull faces of D. //
16519// //
16521
16522void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
16523 long arraysize, bool jump, bool merge, REAL eps, queue* flipque)
16524{
16525 triface newtet, searchtet;
16526 point swappt, lastpt;
16527 enum locateresult loc;
16528 REAL det, n[3];
16529 REAL attrib, volume;
16530 int i, j;
16531#ifdef SELF_CHECK
16532 clock_t loc_start, loc_end;
16533#endif
16534
16535 det = 0.0;
16536 if (b->verbose > 0) {
16537 printf(" Creating initial tetrahedralization.\n");
16538 }
16539
16540 // The initial tetrahedralization T only has one tet formed by 4 affinely
16541 // linear independent vertices of the point set V = 'insertarray'. The
16542 // first point a = insertarray[0].
16543
16544 // Get the second point b, that is not identical or very close to a.
16545 for (i = 1; i < arraysize; i++) {
16546 det = distance(insertarray[0], insertarray[i]);
16547 if (det > (longest * eps)) break;
16548 }
16549 if (i == arraysize) {
16550 printf("\nAll points seem to be identical.\n");
16551 return;
16552 } else {
16553 // Swap to move b from index i to index 1.
16554 swappt = insertarray[i];
16555 insertarray[i] = insertarray[1];
16556 insertarray[1] = swappt;
16557 }
16558 // Get the third point c, that is not collinear with a and b.
16559 for (i++; i < arraysize; i++) {
16560 if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps))
16561 break;
16562 }
16563 if (i == arraysize) {
16564 printf("\nAll points seem to be collinear.\n");
16565 return;
16566 } else {
16567 // Swap to move c from index i to index 2.
16568 swappt = insertarray[i];
16569 insertarray[i] = insertarray[2];
16570 insertarray[2] = swappt;
16571 }
16572 // Get the fourth point d, that is not coplanar with a, b, and c.
16573 for (i++; i < arraysize; i++) {
16574 det = orient3d(insertarray[0], insertarray[1], insertarray[2],
16575 insertarray[i]);
16576 if (det == 0.0) continue;
16577 if (!iscoplanar(insertarray[0], insertarray[1], insertarray[2],
16578 insertarray[i], det, eps)) break;
16579 }
16580 if (i == arraysize) {
16581 // It's a 2D problem.
16582 in->mesh_dim = 2;
16583 // All points are coplanar.
16584 if (b->plc) {
16585 // Create an abovepoint. Maybe a surface triangulation can be formed.
16586 facenormal(insertarray[0], insertarray[1], insertarray[2], n, &det);
16587 if (det != 0.0) for (j = 0; j < 3; j++) n[j] /= det;
16588 // Take the average edge length of the bounding box.
16589 det = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0;
16590 // Temporarily create a point. It will be removed by jettison();
16591 makepoint(&lastpt);
16592 for (j = 0; j < 3; j++) lastpt[j] = insertarray[0][j] + det * n[j];
16593 abovepoint = lastpt;
16594 det = orient3d(insertarray[0], insertarray[1], insertarray[2], lastpt);
16595 // The index of the next inserting point is 3.
16596 i = 3;
16597 } else {
16598 printf("\nAll points seem to be coplanar.\n");
16599 return;
16600 }
16601 } else {
16602 // Swap to move d from index i to index 3.
16603 swappt = insertarray[i];
16604 insertarray[i] = insertarray[3];
16605 insertarray[3] = swappt;
16606 lastpt = insertarray[3];
16607 // The index of the next inserting point is 4.
16608 i = 4;
16609 }
16610
16611 // Create the initial tet.
16612 maketetrahedron(&newtet);
16613 if (det > 0.0) {
16614 // For keeping the positive orientation.
16615 swappt = insertarray[0];
16616 insertarray[0] = insertarray[1];
16617 insertarray[1] = swappt;
16618 }
16619 if (b->verbose > 2) {
16620 printf(" Create the first tet (%d, %d, %d, %d).\n",
16621 pointmark(insertarray[0]), pointmark(insertarray[1]),
16622 pointmark(insertarray[2]), pointmark(lastpt));
16623 }
16624 setorg(newtet, insertarray[0]);
16625 setdest(newtet, insertarray[1]);
16626 setapex(newtet, insertarray[2]);
16627 setoppo(newtet, lastpt);
16628 if (oldtet != (triface *) NULL) {
16629 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
16630 attrib = elemattribute(oldtet->tet, j);
16631 setelemattribute(newtet.tet, j, attrib);
16632 }
16633 if (b->varvolume) {
16634 volume = volumebound(oldtet->tet);
16635 setvolumebound(newtet.tet, volume);
16636 }
16637 }
16638 // Set vertex type be FREEVOLVERTEX if it has no type yet.
16639 if (pointtype(insertarray[0]) == UNUSEDVERTEX) {
16640 setpointtype(insertarray[0], FREEVOLVERTEX);
16641 }
16642 if (pointtype(insertarray[1]) == UNUSEDVERTEX) {
16643 setpointtype(insertarray[1], FREEVOLVERTEX);
16644 }
16645 if (pointtype(insertarray[2]) == UNUSEDVERTEX) {
16646 setpointtype(insertarray[2], FREEVOLVERTEX);
16647 }
16648 if (pointtype(lastpt) == UNUSEDVERTEX) {
16649 setpointtype(lastpt, FREEVOLVERTEX);
16650 }
16651 // Bond to 'dummytet' for point location.
16652 dummytet[0] = encode(newtet);
16653 if (b->verbose > 3) {
16654 printf(" Creating tetra ");
16655 printtet(&newtet);
16656 }
16657 // At init, all faces of this tet are hull faces.
16658 hullsize = 4;
16659
16660 if (b->verbose > 0) {
16661 printf(" Incrementally inserting points.\n");
16662 }
16663
16664 flip23s = flip32s = flip22s = flip44s = 0;
16665 searchtet.tet = (tetrahedron *) NULL;
16666
16667 // Insert the rest of points, one by one.
16668 for (; i < arraysize; i++) {
16669 // Locate p_i in T.
16670#ifdef SELF_CHECK
16671 loc_start = clock();
16672#endif
16673 if (jump) {
16674 loc = locate(insertarray[i], &searchtet);
16675 } else {
16676 loc = preciselocate(insertarray[i], &searchtet, tetrahedrons->items);
16677 }
16678#ifdef SELF_CHECK
16679 loc_end = clock();
16680 tloctime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
16681#endif
16682 // Keep current search state for next searching.
16683 recenttet = searchtet;
16684 if (loc == ONVERTEX) {
16685 if (b->object != tetgenbehavior::STL) {
16686 if (!b->quiet) {
16687 printf("Warning: Point %d is identical with point %d.\n",
16688 pointmark(insertarray[i]), pointmark(org(searchtet)));
16689 }
16690 }
16691 // Count the number of duplicated points.
16692 dupverts++;
16693 // Remember it is a duplicated point.
16694 setpointtype(insertarray[i], DUPLICATEDVERTEX);
16695 if (b->plc || b->refine) {
16696 // Set a pointer to the point it duplicates.
16697 setpoint2ppt(insertarray[i], org(searchtet));
16698 }
16699 continue; // p_i is not inserted.
16700 }
16701 if (merge) {
16702 // Unify p_i if it is too close to a point of T.
16703 if (unifypoint(insertarray[i], &searchtet, loc, eps)) {
16704 continue; // p_i is not inserted.
16705 }
16706 }
16707 // Insert p_i in T.
16708 if (loc != OUTSIDE) {
16709 if (b->verbose > 1) {
16710 printf(" Insert point %d in tetrahedralization.\n",
16711 pointmark(insertarray[i]));
16712 }
16713 if (loc == INTETRAHEDRON) {
16714 splittetrahedron(insertarray[i], &searchtet, flipque);
16715 } else if (loc == ONFACE) {
16716 splittetface(insertarray[i], &searchtet, flipque);
16717 } else if (loc == ONEDGE) {
16718 splittetedge(insertarray[i], &searchtet, flipque);
16719 }
16720 } else {
16721 if (b->verbose > 1) {
16722 printf(" Insert point %d on convex hull.\n",
16723 pointmark(insertarray[i]));
16724 }
16725 inserthullsite(insertarray[i], &searchtet, flipque);
16726 }
16727 if (pointtype(insertarray[i]) == UNUSEDVERTEX) {
16728 // p_i becomes a (volume) vertex of T.
16729 setpointtype(insertarray[i], FREEVOLVERTEX);
16730 }
16731#ifdef SELF_CHECK
16732 loc_start = clock();
16733#endif
16734 if (!b->noflip) {
16735 // Recover Delaunayness of T by flipping.
16736 flip(flipque, NULL);
16737 } else {
16738 lawson(NULL, flipque);
16739 // T remains regular.
16740 // flipque->clear();
16741 }
16742#ifdef SELF_CHECK
16743 loc_end = clock();
16744 tfliptime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
16745#endif
16746 }
16747
16748 if (b->verbose > 0) {
16749 printf(" %ld Flips (T23 %ld, T32 %ld, T22 %ld, T44 %ld)\n",
16750 flip23s+flip32s+flip22s+flip44s, flip23s, flip32s, flip22s, flip44s);
16751 }
16752}
16753
16755// //
16756// delaunizevertices() Form a Delaunay tetrahedralization. //
16757// //
16758// Given a point set V (saved in 'points'). The Delaunay tetrahedralization //
16759// D of V is created by incrementally inserting vertices. Returns the number //
16760// of triangular faces bounding the convex hull of D. //
16761// //
16763
16764long tetgenmesh::delaunizevertices()
16765{
16766 queue *flipque;
16767 point *insertarray;
16768 long arraysize;
16769 int i, j;
16770
16771 if (!b->quiet) {
16772 if (!b->noflip) {
16773 printf("Constructing Delaunay tetrahedralization.\n");
16774 } else {
16775 printf("Constructing regular tetrahedralization.\n");
16776 }
16777 }
16778
16779 flipque = new queue(sizeof(badface));
16780 // Prepare the array of points for inserting.
16781 arraysize = points->items;
16782 insertarray = new point[arraysize];
16783 points->traversalinit();
16784
16785 // Randomize the point order.
16786 // randomseed = b->srandseed;
16787 for (i = 0; i < arraysize; i++) {
16788 j = (int) randomnation(i + 1); // 0 <= j <= i;
16789 insertarray[i] = insertarray[j];
16790 insertarray[j] = pointtraverse();
16791 }
16792
16793 // Use lawson flip.
16794 b->noflip = 1;
16795
16796 // Form the DT by incremental flip Delaunay algorithm.
16797 incrflipdelaunay(NULL, insertarray, arraysize, true, b->plc, b->epsilon,
16798 flipque);
16799
16800 b->noflip = 0;
16801
16802 delete [] insertarray;
16803 delete flipque;
16804 return hullsize;
16805}
16806
16807//
16808// End Delaunay tetrahedralization routines
16809//
16810
16811//
16812// Begin of surface triangulation routines
16813//
16814
16816// //
16817// formstarpolygon() Form the star polygon of a point in facet. //
16818// //
16819// The polygon P is formed by all coplanar subfaces having 'pt' as a vertex. //
16820// P is bounded by segments, e.g, if no segments, P is the full star of pt. //
16821// //
16822// 'trilist' T returns the subfaces, it has one of such subfaces on input. //
16823// In addition, if f is in T, then sapex(f) = p. 'vertlist' V are verts of P.//
16824// Topologically, T is the star of p; V and the edges of T are the link of p.//
16825// //
16827
16828void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
16829{
16830 face steinsh, lnextsh, rnextsh;
16831 face checkseg;
16832 point pa, pb, pc, pd;
16833 int i;
16834
16835 // Get a subface f containing p.
16836 steinsh = * (face *)(* trilist)[0];
16837 steinsh.shver = 0; // CCW
16838 // Let sapex(f) be p.
16839 for (i = 0; i < 3; i++) {
16840 if (sapex(steinsh) == pt) break;
16841 senextself(steinsh);
16842 }
16843 assert(i < 3);
16844 // Add the edge f into list.
16845 * (face *)(* trilist)[0] = steinsh;
16846 pa = sorg(steinsh);
16847 pb = sdest(steinsh);
16848 if (vertlist != (list *) NULL) {
16849 // Add two verts a, b into V,
16850 vertlist->append(&pa);
16851 vertlist->append(&pb);
16852 }
16853
16854 // Rotate edge pa to the left (CW) until meet pb or a segment.
16855 lnextsh = steinsh;
16856 pc = pa;
16857 do {
16858 senext2self(lnextsh);
16859 assert(sorg(lnextsh) == pt);
16860 sspivot(lnextsh, checkseg);
16861 if (checkseg.sh != dummysh) break; // Do not cross a segment.
16862 // Get neighbor subface n (must exist).
16863 spivotself(lnextsh);
16864 if (lnextsh.sh == dummysh) break; // It's a hull edge.
16865 // Go to the edge ca opposite to p.
16866 if (sdest(lnextsh) != pt) sesymself(lnextsh);
16867 assert(sdest(lnextsh) == pt);
16868 senext2self(lnextsh);
16869 // Add n (at edge ca) to T.
16870 trilist->append(&lnextsh);
16871 // Add edge ca to E.
16872 pc = sorg(lnextsh);
16873 if (pc == pb) break; // Rotate back.
16874 if (vertlist != (list *) NULL) {
16875 // Add vert c into V.
16876 vertlist->append(&pc);
16877 }
16878 } while (true);
16879
16880 if (pc != pb) {
16881 // Rotate edge bp to the right (CCW) until meet a segment.
16882 rnextsh = steinsh;
16883 do {
16884 senextself(rnextsh);
16885 assert(sdest(rnextsh) == pt);
16886 sspivot(rnextsh, checkseg);
16887 if (checkseg.sh != dummysh) break; // Do not cross a segment.
16888 // Get neighbor subface n (must exist).
16889 spivotself(rnextsh);
16890 if (rnextsh.sh == dummysh) break; // It's a hull edge.
16891 // Go to the edge bd opposite to p.
16892 if (sorg(rnextsh) != pt) sesymself(rnextsh);
16893 assert(sorg(rnextsh) == pt);
16894 senextself(rnextsh);
16895 // Add n (at edge bd) to T.
16896 trilist->append(&rnextsh);
16897 // Add edge bd to E.
16898 pd = sdest(rnextsh);
16899 if (pd == pa) break; // Rotate back.
16900 if (vertlist != (list *) NULL) {
16901 // Add vert d into V.
16902 vertlist->append(&pd);
16903 }
16904 } while (true);
16905 }
16906}
16907
16909// //
16910// About the 'abovepoint' //
16911// //
16912// The 'abovepoint' of a facet is a point which is exactly non-coplanar with //
16913// the plane containing that facet. With such an point, the 3D predicates: //
16914// orient3d(), and insphere() can be used to substitute the corresponding 2D //
16915// siblings, e.g. orient2d(), and incircle(). Its location is not critical, //
16916// but floating-point accuracy is improved if it is nicely placed over the //
16917// facet, not too close or too far away. //
16918// //
16919// We take the convention that the abovepoint of a facet always lies above //
16920// the facet. By this convention, given three points a, b, and c in a facet, //
16921// we say c has the counterclockwise order with ab is corresponding to say //
16922// that c is below the plane abp, where p is the lift point. //
16923// //
16925
16927// //
16928// getfacetabovepoint() Get a point above a plane pass through a facet. //
16929// //
16930// The calculcated point is saved in 'facetabovepointarray'. The 'abovepoint'//
16931// is set on return. //
16932// //
16934
16935void tetgenmesh::getfacetabovepoint(face* facetsh)
16936{
16937 list *verlist, *trilist, *tetlist;
16938 triface adjtet;
16939 face symsh;
16940 point p1, p2, p3, pa;
16941 enum locateresult loc;
16942 REAL smallcos, cosa;
16943 REAL largevol, volume;
16944 REAL v1[3], v2[3], len;
16945 int smallidx, largeidx;
16946 int shmark;
16947 int i, j;
16948
16949 abovecount++;
16950 // Initialize working lists.
16951 verlist = new list(sizeof(point *), NULL);
16952 trilist = new list(sizeof(face), NULL);
16953 tetlist = new list(sizeof(triface), NULL);
16954
16955 // Get three pivotal points p1, p2, and p3 in the facet as a base triangle
16956 // which is non-trivil and has good base angle (close to 90 degree).
16957
16958 // p1 is chosen as the one which has the smallest index in pa, pb, pc.
16959 p1 = sorg(*facetsh);
16960 pa = sdest(*facetsh);
16961 if (pointmark(pa) < pointmark(p1)) p1 = pa;
16962 pa = sapex(*facetsh);
16963 if (pointmark(pa) < pointmark(p1)) p1 = pa;
16964 // Form the star polygon of p1.
16965 trilist->append(facetsh);
16966 formstarpolygon(p1, trilist, verlist);
16967
16968 // Get the second pivotal point p2.
16969 p2 = * (point *)(* verlist)[0];
16970 // Get vector v1 = p1->p2.
16971 for (i = 0; i < 3; i++) v1[i] = p2[i] - p1[i];
16972 len = sqrt(dot(v1, v1));
16973 assert(len > 0.0); // p2 != p1.
16974 for (i = 0; i < 3; i++) v1[i] /= len;
16975
16976 // Get the third pivotal point p3. p3 is chosen as the one in 'verlist'
16977 // which forms an angle with v1 closer to 90 degree than others do.
16978 smallcos = 1.0; // The cosine value of 0 degree.
16979 smallidx = 1; // Default value.
16980 for (i = 1; i < verlist->len(); i++) {
16981 p3 = * (point *)(* verlist)[i];
16982 for (j = 0; j < 3; j++) v2[j] = p3[j] - p1[j];
16983 len = sqrt(dot(v2, v2));
16984 if (len > 0.0) { // v2 is not too small.
16985 cosa = fabs(dot(v1, v2)) / len;
16986 if (cosa < smallcos) {
16987 smallidx = i;
16988 smallcos = cosa;
16989 }
16990 }
16991 }
16992 assert(smallcos < 1.0); // p1->p3 != p1->p2.
16993 p3 = * (point *)(* verlist)[smallidx];
16994 verlist->clear();
16995
16996 if (tetrahedrons->items > 0l) {
16997 // Get a tet having p1 as a vertex.
16998 stpivot(*facetsh, adjtet);
16999 if (adjtet.tet == dummytet) {
17000 sesym(*facetsh, symsh);
17001 stpivot(symsh, adjtet);
17002 }
17003 if (adjtet.tet == dummytet) {
17004 decode(point2tet(p1), adjtet);
17005 if (isdead(&adjtet)) {
17006 adjtet.tet = dummytet;
17007 } else {
17008 if (!findorg(&adjtet, p1)) {
17009 adjtet.tet = dummytet;
17010 }
17011 }
17012 }
17013 if (adjtet.tet == dummytet) {
17014 loc = locate(p1, &adjtet);
17015 if (loc == ONVERTEX) {
17016 setpoint2tet(p1, encode(adjtet));
17017 } else {
17018 adjtet.tet = dummytet;
17019 }
17020 }
17021 if (adjtet.tet != dummytet) {
17022 // Get the star polyhedron of p1.
17023 tetlist->append(&adjtet);
17024 formstarpolyhedron(p1, tetlist, verlist, false);
17025 }
17026 }
17027
17028 // Get the abovepoint in 'verlist'. It is the one form the largest valid
17029 // volumw with the base triangle over other points in 'verlist.
17030 largevol = 0.0;
17031 largeidx = 0;
17032 for (i = 0; i < verlist->len(); i++) {
17033 pa = * (point *)(* verlist)[i];
17034 volume = orient3d(p1, p2, p3, pa);
17035 if (!iscoplanar(p1, p2, p3, pa, volume, b->epsilon * 1e+2)) {
17036 if (fabs(volume) > largevol) {
17037 largevol = fabs(volume);
17038 largeidx = i;
17039 }
17040 }
17041 }
17042
17043 // Do we have the abovepoint?
17044 if (largevol > 0.0) {
17045 abovepoint = * (point *)(* verlist)[largeidx];
17046 if (b->verbose > 1) {
17047 printf(" Chosen abovepoint %d for facet %d.\n", pointmark(abovepoint),
17048 shellmark(*facetsh));
17049 }
17050 } else {
17051 // Calculate an abovepoint for this facet.
17052 facenormal(p1, p2, p3, v1, &len);
17053 if (len != 0.0) for (i = 0; i < 3; i++) v1[i] /= len;
17054 // Take the average edge length of the bounding box.
17055 len = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0;
17056 // Temporarily create a point. It will be removed by jettison();
17057 makepoint(&abovepoint);
17058 setpointtype(abovepoint, UNUSEDVERTEX);
17059 unuverts++;
17060 for (i = 0; i < 3; i++) abovepoint[i] = p1[i] + len * v1[i];
17061 if (b->verbose > 1) {
17062 printf(" Calculated abovepoint %d for facet %d.\n",
17063 pointmark(abovepoint), shellmark(*facetsh));
17064 }
17065 }
17066 // Save the abovepoint in 'facetabovepointarray'.
17067 shmark = shellmark(*facetsh);
17068 facetabovepointarray[shmark] = abovepoint;
17069
17070 delete trilist;
17071 delete tetlist;
17072 delete verlist;
17073}
17074
17076// //
17077// collectcavsubs() Collect non-locally Delaunay subfaces wrt a point. //
17078// //
17079// 'cavsublist' returns the list of subfaces. On input, it conatins at least //
17080// one subface. //
17081// //
17083
17084void tetgenmesh::collectcavsubs(point newpoint, list* cavsublist)
17085{
17086 face startsub, neighsub;
17087 face checkseg;
17088 point pa, pb, pc;
17089 REAL sign, ori;
17090 int i, j;
17091
17092 // First infect subfaces in 'cavsublist'.
17093 for (i = 0; i < cavsublist->len(); i++) {
17094 startsub = * (face *)(* cavsublist)[i];
17095 sinfect(startsub);
17096 }
17097 // Find the other subfaces by a broadth-first searching.
17098 for (i = 0; i < cavsublist->len(); i++) {
17099 startsub = * (face *)(* cavsublist)[i];
17100 for (j = 0; j < 3; j++) {
17101 sspivot(startsub, checkseg);
17102 // Is there a segment?
17103 if (checkseg.sh == dummysh) {
17104 // No segment. Get the neighbor.
17105 spivot(startsub, neighsub);
17106 if (!sinfected(neighsub)) {
17107 pa = sorg(neighsub);
17108 pb = sdest(neighsub);
17109 pc = sapex(neighsub);
17110 sign = insphere(pa, pb, pc, abovepoint, newpoint);
17111 ori = orient3d(pa, pb, pc, abovepoint);
17112 if (sign != 0.0) {
17113 // Correct the sign.
17114 sign = ori > 0.0 ? sign : -sign;
17115 }
17116 if (sign > 0.0) {
17117 // neighsub is encroached by newpoint.
17118 sinfect(neighsub);
17119 cavsublist->append(&neighsub);
17120 }
17121 }
17122 }
17123 senextself(startsub);
17124 }
17125 }
17126 // Having found all subfaces, uninfect them before return.
17127 for (i = 0; i < cavsublist->len(); i++) {
17128 startsub = * (face *)(* cavsublist)[i];
17129 suninfect(startsub);
17130 }
17131}
17132
17134// //
17135// collectvisiblesubs() Collect convex hull edges which are visible from //
17136// the inserting point. Construct new subfaces from //
17137// these edges and the point. //
17138// //
17139// Let T be the current Delaunay triangulation (of vertices of a facet F). //
17140// 'shmark', the index of F in 'in->facetlist' (starts from 1); 'inspoint' //
17141// lies outside of T; 'horiz' is a hull edge of T which is visible by it. //
17142// //
17144
17145void tetgenmesh::collectvisiblesubs(int shmark, point inspoint, face* horiz,
17146 queue* flipqueue)
17147{
17148 face newsh, hullsh;
17149 face rightsh, leftsh, spinedge;
17150 point horg, hdest;
17151 bool aboveflag;
17152 REAL ori, sign;
17153
17154 // Get the sign of abovepoint (so we can assume it is above the plane).
17155 adjustedgering(*horiz, CCW);
17156 horg = sorg(*horiz);
17157 hdest = sdest(*horiz);
17158 ori = orient3d(horg, hdest, sapex(*horiz), abovepoint);
17159 sign = ori > 0.0 ? -1 : 1;
17160
17161 // Create a new subface above 'horiz'.
17162 makeshellface(subfaces, &newsh);
17163 setsorg(newsh, hdest);
17164 setsdest(newsh, horg);
17165 setsapex(newsh, inspoint);
17166 setshellmark(newsh, shmark);
17167 if (b->quality && varconstraint) {
17168 setareabound(newsh, areabound(*horiz));
17169 }
17170 if (checkpbcs) {
17171 setshellpbcgroup(newsh, shellpbcgroup(*horiz));
17172 }
17173 // Make the connection.
17174 sbond(newsh, *horiz);
17175 // 'horiz' becomes interior edge.
17176 enqueueflipedge(*horiz, flipqueue);
17177
17178 // Finish the hull edges at the right side of the newsh.
17179 hullsh = *horiz;
17180 while (1) {
17181 senext(newsh, rightsh);
17182 // Get the right hull edge of 'horiz' by spinning inside edges around
17183 // 'horg' until reaching the 'dummysh'.
17184 spinedge = hullsh;
17185 do {
17186 hullsh = spinedge;
17187 senext2self(hullsh);
17188 spivot(hullsh, spinedge);
17189 if (spinedge.sh == dummysh) break;
17190 if (sorg(spinedge) != horg) sesymself(spinedge);
17191 assert(sorg(spinedge) == horg);
17192 } while (true);
17193 horg = sorg(hullsh);
17194 // Test whether 'inspoint' is visible by 'hullsh'.
17195 ori = orient3d(horg, sdest(hullsh), abovepoint, inspoint);
17196 ori *= sign;
17197 aboveflag = ori < 0.0;
17198 if (aboveflag) {
17199 // It's visible.
17200 makeshellface(subfaces, &newsh);
17201 setsorg(newsh, sdest(hullsh));
17202 setsdest(newsh, horg);
17203 setsapex(newsh, inspoint);
17204 setshellmark(newsh, shmark);
17205 if (b->quality && varconstraint) {
17206 setareabound(newsh, areabound(hullsh));
17207 }
17208 if (checkpbcs) {
17209 setshellpbcgroup(newsh, shellpbcgroup(hullsh));
17210 }
17211 // Make the connection.
17212 sbond(newsh, hullsh);
17213 senext2(newsh, leftsh);
17214 sbond(leftsh, rightsh);
17215 // 'hullsh' becomes interior edge.
17216 enqueueflipedge(hullsh, flipqueue);
17217 } else {
17218 // 'rightsh' is a new hull edge.
17219 dummysh[0] = sencode(rightsh);
17220 break;
17221 }
17222 }
17223
17224 // Finish the hull edges at the left side of the newsh.
17225 hullsh = *horiz;
17226 spivot(*horiz, newsh);
17227 while (1) {
17228 senext2(newsh, leftsh);
17229 // Get the left hull edge of 'horiz' by spinning edges around 'hdest'.
17230 spinedge = hullsh;
17231 do {
17232 hullsh = spinedge;
17233 senextself(hullsh);
17234 spivot(hullsh, spinedge);
17235 if (spinedge.sh == dummysh) break;
17236 if (sdest(spinedge) != hdest) sesymself(spinedge);
17237 assert(sdest(spinedge) == hdest);
17238 } while (true);
17239 // Update 'hdest'.
17240 hdest = sdest(hullsh);
17241 // Test whether 'inspoint' is visible from 'hullsh'.
17242 ori = orient3d(sorg(hullsh), hdest, abovepoint, inspoint);
17243 ori *= sign;
17244 aboveflag = ori < 0.0;
17245 if (aboveflag) {
17246 // It's a visible hull edge.
17247 makeshellface(subfaces, &newsh);
17248 setsorg(newsh, hdest);
17249 setsdest(newsh, sorg(hullsh));
17250 setsapex(newsh, inspoint);
17251 setshellmark(newsh, shmark);
17252 if (b->quality && varconstraint) {
17253 setareabound(newsh, areabound(hullsh));
17254 }
17255 if (checkpbcs) {
17256 setshellpbcgroup(newsh, shellpbcgroup(hullsh));
17257 }
17258 // Make the connection.
17259 sbond(newsh, hullsh);
17260 senext(newsh, rightsh);
17261 sbond(rightsh, leftsh);
17262 // 'horiz' becomes interior edge.
17263 enqueueflipedge(hullsh, flipqueue);
17264 } else {
17265 // 'leftsh' is a new hull edge.
17266 dummysh[0] = sencode(leftsh);
17267 break;
17268 }
17269 }
17270}
17271
17273// //
17274// incrflipdelaunaysub() Create a DT from a 3D coplanar point set using //
17275// the incremental flip algorithm. //
17276// //
17277// Let T be the current Delaunay triangulation (of vertices of a facet F). //
17278// 'shmark', the index of F in 'in->facetlist' (starts from 1). //
17279// //
17281
17282void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
17283 int holes, REAL* holelist, queue* flipque)
17284{
17285 face newsh, startsh;
17286 point *insertarray;
17287 point swappt;
17288 pbcdata *pd;
17289 enum locateresult loc;
17290 REAL det, area;
17291 bool aboveflag;
17292 int arraysize;
17293 int epscount;
17294 int fmarker;
17295 int idx, i, j, k;
17296
17297 // Get the point array (saved in 'ptlist').
17298 insertarray = (point *) ptlist->base;
17299 arraysize = ptlist->len();
17300 if (arraysize < 3) return;
17301
17302 // Do calculation of 'abovepoint' if number of points > 3.
17303 aboveflag = (arraysize > 3);
17304
17305 // The initial triangulation T only has one triangle formed by 3 not
17306 // cillinear points of the set V = 'insertarray'. The first point:
17307 // a = insertarray[0].
17308
17309 epscount = 0;
17310 while (true) {
17311 for (i = 1; i < arraysize; i++) {
17312 det = distance(insertarray[0], insertarray[i]);
17313 if (det > (longest * eps)) break;
17314 }
17315 if (i < arraysize) {
17316 // Swap to move b from index i to index 1.
17317 swappt = insertarray[i];
17318 insertarray[i] = insertarray[1];
17319 insertarray[1] = swappt;
17320 }
17321 // Get the third point c, that is not collinear with a and b.
17322 for (i++; i < arraysize; i++) {
17323 if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps))
17324 break;
17325 }
17326 if (i < arraysize) {
17327 // Swap to move c from index i to index 2.
17328 swappt = insertarray[i];
17329 insertarray[i] = insertarray[2];
17330 insertarray[2] = swappt;
17331 i = 3; // The next inserting point.
17332 } else {
17333 // The set of vertices is not good (or nearly degenerate). However,
17334 // a trivial triangulation can be formed (using 3 vertices). It may
17335 // be corrected (or deleted) by mergefacet().
17336 if ((eps == 0.0) || (epscount > 16)) {
17337 printf("Error: Invalid PLC.\n");
17338 printf(" Facet (%d, %d, %d", pointmark(insertarray[0]),
17339 pointmark(insertarray[1]), pointmark(insertarray[2]));
17340 if (ptlist->len() > 3) {
17341 printf(", ...");
17342 }
17343 printf(") (%d) is not a valid polygon.\n", shmark);
17344 terminatetetgen(1);
17345 }
17346 // Decrease the eps, and continue to try.
17347 eps *= 1e-2;
17348 epscount++;
17349 continue;
17350 }
17351 break;
17352 } // while (true);
17353
17354 // Create the initial triangle.
17355 makeshellface(subfaces, &newsh);
17356 setsorg(newsh, insertarray[0]);
17357 setsdest(newsh, insertarray[1]);
17358 setsapex(newsh, insertarray[2]);
17359 // Remeber the facet it belongs to.
17360 setshellmark(newsh, shmark);
17361 // Set vertex type be FREESUBVERTEX if it has no type yet.
17362 if (pointtype(insertarray[0]) == FREEVOLVERTEX) {
17363 setpointtype(insertarray[0], FREESUBVERTEX);
17364 }
17365 if (pointtype(insertarray[1]) == FREEVOLVERTEX) {
17366 setpointtype(insertarray[1], FREESUBVERTEX);
17367 }
17368 if (pointtype(insertarray[2]) == FREEVOLVERTEX) {
17369 setpointtype(insertarray[2], FREESUBVERTEX);
17370 }
17371 // Let 'dummysh' point to it (for point location).
17372 dummysh[0] = sencode(newsh);
17373
17374 // Are there area constraints?
17375 if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
17376 idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
17377 for (k = 0; k < in->numberoffacetconstraints; k++) {
17378 fmarker = (int) in->facetconstraintlist[k * 2];
17379 if (fmarker == idx) {
17380 area = in->facetconstraintlist[k * 2 + 1];
17381 setareabound(newsh, area);
17382 break;
17383 }
17384 }
17385 }
17386
17387 // Are there pbc conditions?
17388 if (checkpbcs) {
17389 idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
17390 for (k = 0; k < in->numberofpbcgroups; k++) {
17391 pd = &subpbcgrouptable[k];
17392 for (j = 0; j < 2; j++) {
17393 if (pd->fmark[j] == idx) {
17394 setshellpbcgroup(newsh, k);
17395 pd->ss[j] = newsh;
17396 }
17397 }
17398 }
17399 }
17400
17401 if (aboveflag) {
17402 // Compute the 'abovepoint' for orient3d().
17403 abovepoint = facetabovepointarray[shmark];
17404 if (abovepoint == (point) NULL) {
17405 getfacetabovepoint(&newsh);
17406 }
17407 }
17408
17409 if (holes > 0) {
17410 // Project hole points onto the plane containing the facet.
17411 REAL prj[3];
17412 for (k = 0; k < holes; k++) {
17413 projpt2face(&(holelist[k * 3]), insertarray[0], insertarray[1],
17414 insertarray[2], prj);
17415 for (j = 0; j < 3; j++) holelist[k * 3 + j] = prj[j];
17416 }
17417 }
17418
17419 // Incrementally insert the rest of points into T.
17420 for (; i < arraysize; i++) {
17421 // Insert p_i.
17422 startsh.sh = dummysh;
17423 loc = locatesub(insertarray[i], &startsh, 0, 0.0);
17424 if (loc == ONFACE) {
17425 splitsubface(insertarray[i], &startsh, flipque);
17426 } else if (loc == ONEDGE) {
17427 splitsubedge(insertarray[i], &startsh, flipque);
17428 } else if (loc == OUTSIDE) {
17429 collectvisiblesubs(shmark, insertarray[i], &startsh, flipque);
17430 } else if (loc == ONVERTEX) {
17431 // !should not happen!
17432 }
17433 // Set p_i's type FREESUBVERTEX if it has no type yet.
17434 if (pointtype(insertarray[i]) == FREEVOLVERTEX) {
17435 setpointtype(insertarray[i], FREESUBVERTEX);
17436 }
17437 flipsub(flipque);
17438 }
17439}
17440
17442// //
17443// finddirectionsub() Find the first subface in a facet on the path from //
17444// one point to another. //
17445// //
17446// Finds the subface in the facet that intersects a line segment drawn from //
17447// the origin of `searchsh' to the point `tend', and returns the result in //
17448// `searchsh'. The origin of `searchsh' does not change, even though the //
17449// subface returned may differ from the one passed in. //
17450// //
17451// The return value notes whether the destination or apex of the found face //
17452// is collinear with the two points in question. //
17453// //
17455
17456enum tetgenmesh::finddirectionresult tetgenmesh::finddirectionsub(
17457 face* searchsh, point tend)
17458{
17459 face checksh;
17460 point startpoint, leftpoint, rightpoint;
17461 REAL leftccw, rightccw;
17462 REAL ori, sign;
17463 int leftflag, rightflag;
17464
17465 startpoint = sorg(*searchsh);
17466 // Find the sign to simulate that abovepoint is 'above' the facet.
17467 adjustedgering(*searchsh, CCW);
17468 // Make sure 'startpoint' is the origin.
17469 if (sorg(*searchsh) != startpoint) senextself(*searchsh);
17470 rightpoint = sdest(*searchsh);
17471 leftpoint = sapex(*searchsh);
17472 ori = orient3d(startpoint, rightpoint, leftpoint, abovepoint);
17473 sign = ori > 0.0 ? -1 : 1;
17474
17475 // Is `tend' to the left?
17476 ori = orient3d(tend, startpoint, abovepoint, leftpoint);
17477 leftccw = ori * sign;
17478 leftflag = leftccw > 0.0;
17479 // Is `tend' to the right?
17480 ori = orient3d(startpoint, tend, abovepoint, rightpoint);
17481 rightccw = ori * sign;
17482 rightflag = rightccw > 0.0;
17483 if (leftflag && rightflag) {
17484 // `searchsh' faces directly away from `tend'. We could go left or
17485 // right. Ask whether it's a triangle or a boundary on the left.
17486 senext2(*searchsh, checksh);
17487 spivotself(checksh);
17488 if (checksh.sh == dummysh) {
17489 leftflag = 0;
17490 } else {
17491 rightflag = 0;
17492 }
17493 }
17494 while (leftflag) {
17495 // Turn left until satisfied.
17496 senext2self(*searchsh);
17497 spivotself(*searchsh);
17498 if (searchsh->sh == dummysh) {
17499 printf("Internal error in finddirectionsub(): Unable to find a\n");
17500 printf(" subface leading from %d to %d.\n", pointmark(startpoint),
17501 pointmark(tend));
17502 internalerror();
17503 }
17504 if (sorg(*searchsh) != startpoint) sesymself(*searchsh);
17505 assert(sorg(*searchsh) == startpoint);
17506 leftpoint = sapex(*searchsh);
17507 rightccw = leftccw;
17508 ori = orient3d(tend, startpoint, abovepoint, leftpoint);
17509 leftccw = ori * sign;
17510 leftflag = leftccw > 0.0;
17511 }
17512 while (rightflag) {
17513 // Turn right until satisfied.
17514 spivotself(*searchsh);
17515 if (searchsh->sh == dummysh) {
17516 printf("Internal error in finddirectionsub(): Unable to find a\n");
17517 printf(" subface leading from %d to %d.\n", pointmark(startpoint),
17518 pointmark(tend));
17519 internalerror();
17520 }
17521 if (sdest(*searchsh) != startpoint) sesymself(*searchsh);
17522 assert(sdest(*searchsh) == startpoint);
17523 senextself(*searchsh);
17524 rightpoint = sdest(*searchsh);
17525 leftccw = rightccw;
17526 ori = orient3d(startpoint, tend, abovepoint, rightpoint);
17527 rightccw = ori * sign;
17528 rightflag = rightccw > 0.0;
17529 }
17530 if (leftccw == 0.0) {
17531 return LEFTCOLLINEAR;
17532 } else if (rightccw == 0.0) {
17533 return RIGHTCOLLINEAR;
17534 } else {
17535 return ACROSSEDGE;
17536 }
17537}
17538
17540// //
17541// insertsubseg() Create a subsegment and insert it between two subfaces. //
17542// //
17543// The new subsegment ab is inserted at the edge of subface 'tri'. If ab is //
17544// not a hull edge, it is inserted between two subfaces. If 'tri' is a hull //
17545// face, the initial face ring of ab will be set only one face which is self-//
17546// bonded. The final face ring will be constructed in 'unifysegments()'. //
17547// //
17549
17550void tetgenmesh::insertsubseg(face* tri)
17551{
17552 face oppotri;
17553 face newsubseg;
17554 point pa, pb;
17555 REAL len;
17556 int e1, e2;
17557 int i;
17558
17559 // Check if there's already a subsegment here.
17560 sspivot(*tri, newsubseg);
17561 if (newsubseg.sh == dummysh) {
17562 // Make new subsegment and initialize its vertices.
17563 makeshellface(subsegs, &newsubseg);
17564 pa = sorg(*tri);
17565 pb = sdest(*tri);
17566 setsorg(newsubseg, pa);
17567 setsdest(newsubseg, pb);
17568 // Are there length constraints?
17569 if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
17570 for (i = 0; i < in->numberofsegmentconstraints; i++) {
17571 e1 = (int) in->segmentconstraintlist[i * 3];
17572 e2 = (int) in->segmentconstraintlist[i * 3 + 1];
17573 if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
17574 ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
17575 len = in->segmentconstraintlist[i * 3 + 2];
17576 setareabound(newsubseg, len);
17577 break;
17578 }
17579 }
17580 }
17581 // Bond new subsegment to the two subfaces it is sandwiched between.
17582 ssbond(*tri, newsubseg);
17583 spivot(*tri, oppotri);
17584 // 'oppotri' might be "out space".
17585 if (oppotri.sh != dummysh) {
17586 ssbond(oppotri, newsubseg);
17587 } /* else {
17588 // Outside! Bond '*tri' to itself.
17589 sbond(*tri, *tri);
17590 } */
17591 }
17592}
17593
17595// //
17596// scoutsegmentsub() Scout the first triangle on the path from one point //
17597// to another, and check for completion (reaching the //
17598// second point), a collinear point,or the intersection //
17599// of two segments. //
17600// //
17601// Returns true if the entire segment is successfully inserted, and false if //
17602// the job must be finished by constrainededge(). //
17603// //
17605
17606bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend)
17607{
17608 face newsubseg;
17609 face crosssub, crosssubseg;
17610 point leftpoint, rightpoint;
17611 enum finddirectionresult collinear;
17612
17613 collinear = finddirectionsub(searchsh, tend);
17614 rightpoint = sdest(*searchsh);
17615 leftpoint = sapex(*searchsh);
17616 if (rightpoint == tend || leftpoint == tend) {
17617 // The segment is already an edge.
17618 if (leftpoint == tend) {
17619 senext2self(*searchsh);
17620 }
17621 // Insert a subsegment.
17622 insertsubseg(searchsh);
17623 return true;
17624 } else if (collinear == LEFTCOLLINEAR) {
17625 // We've collided with a vertex between the segment's endpoints.
17626 // Make the collinear vertex be the triangle's origin.
17627 senextself(*searchsh); // lprevself(*searchtri);
17628 // Insert a subsegment.
17629 insertsubseg(searchsh);
17630 // Insert the remainder of the segment.
17631 return scoutsegmentsub(searchsh, tend);
17632 } else if (collinear == RIGHTCOLLINEAR) {
17633 // We've collided with a vertex between the segment's endpoints.
17634 // Insert a subsegment.
17635 insertsubseg(searchsh);
17636 // Make the collinear vertex be the triangle's origin.
17637 senextself(*searchsh); // lnextself(*searchtri);
17638 // Insert the remainder of the segment.
17639 return scoutsegmentsub(searchsh, tend);
17640 } else {
17641 senext(*searchsh, crosssub); // lnext(*searchtri, crosstri);
17642 // Check for a crossing segment.
17643 sspivot(crosssub, crosssubseg);
17644#ifdef SELF_CHECK
17645 assert(crosssubseg.sh == dummysh);
17646#endif
17647 return false;
17648 }
17649}
17650
17652// //
17653// flipedgerecursive() Flip an edge. //
17654// //
17655// This is a support routine for inserting segments into a CDT. //
17656// //
17657// Let 'flipedge' be ab, and two triangles abc, abd share at it. ab may not //
17658// flipable if the four vertices a, b, c, and d are non-convex. If it is the //
17659// case, recursively flip ad or bd. Return when ab is flipped. //
17660// //
17662
17663void tetgenmesh::flipedgerecursive(face* flipedge, queue* flipqueue)
17664{
17665 face fixupsh;
17666 point pa, pb, pc, pd;
17667 REAL oria, orib;
17668 bool doflip;
17669
17670 pa = sorg(*flipedge);
17671 pb = sdest(*flipedge);
17672 pc = sapex(*flipedge);
17673 do {
17674 spivot(*flipedge, fixupsh);
17675 pd = sapex(fixupsh);
17676 oria = orient3d(pc, pd, abovepoint, pa);
17677 orib = orient3d(pc, pd, abovepoint, pb);
17678 doflip = (oria * orib < 0.0);
17679 if (doflip) {
17680 // Flip the edge (a, b) away.
17681 flip22sub(flipedge, flipqueue);
17682 // Fix flipedge on edge e (c, d).
17683 findedge(flipedge, pc, pd);
17684 } else {
17685 // ab is unflipable. Get the next edge (bd, or da) to flip.
17686 if (sorg(fixupsh) != pb) sesymself(fixupsh);
17687 assert(sdest(fixupsh) == pa);
17688 if (fabs(oria) > fabs(orib)) {
17689 // acd has larger area. Choose da.
17690 senextself(fixupsh);
17691 } else {
17692 // bcd has larger area. Choose bd.
17693 senext2self(fixupsh);
17694 }
17695 // Flip the edge.
17696 flipedgerecursive(&fixupsh, flipqueue);
17697 }
17698 } while (!doflip);
17699}
17700
17702// //
17703// constrainededge() Force a segment into a CDT. //
17704// //
17705// The segment s is recovered by flipping away the edges it intersects, and //
17706// triangulating the polygons that form on each side of it. //
17707// //
17708// Generates a single subsegment connecting `tstart' to `tend'. The triangle //
17709// `startsh' has `tstart' as its origin. //
17710// //
17712
17713void tetgenmesh::constrainededge(face* startsh, point tend, queue* flipqueue)
17714{
17715 point tstart, tright, tleft;
17716 REAL rori, lori;
17717 bool collision;
17718
17719 tstart = sorg(*startsh);
17720 do {
17721 // Loop edges oppo to tstart until find one crosses the segment.
17722 do {
17723 tright = sdest(*startsh);
17724 tleft = sapex(*startsh);
17725 // Is edge (tright, tleft) corss the segment.
17726 rori = orient3d(tstart, tright, abovepoint, tend);
17727 collision = (rori == 0.0);
17728 if (collision) break; // tright is on the segment.
17729 lori = orient3d(tstart, tleft, abovepoint, tend);
17730 collision = (lori == 0.0);
17731 if (collision) { // tleft is on the segment.
17732 senext2self(*startsh);
17733 break;
17734 }
17735 if (rori * lori < 0.0) break; // Find the crossing edge.
17736 // Both points are at one side of the segment.
17737 finddirectionsub(startsh, tend);
17738 } while (true);
17739 if (collision) break;
17740 // Get the neighbor face at edge e (tright, tleft).
17741 senextself(*startsh);
17742 // Flip the crossing edge.
17743 flipedgerecursive(startsh, flipqueue);
17744 // After flip, sorg(*startsh) == tstart.
17745 assert(sorg(*startsh) == tstart);
17746 } while (sdest(*startsh) != tend);
17747
17748 // Insert a subsegment to make the segment permanent.
17749 insertsubseg(startsh);
17750 // If there was a collision with an interceding vertex, install another
17751 // segment connecting that vertex with endpoint2.
17752 if (collision) {
17753 // Insert the remainder of the segment.
17754 if (!scoutsegmentsub(startsh, tend)) {
17755 constrainededge(startsh, tend, flipqueue);
17756 }
17757 }
17758}
17759
17761// //
17762// recoversegment() Recover a segment in the surface triangulation. //
17763// //
17765
17766void tetgenmesh::recoversegment(point tstart, point tend, queue* flipqueue)
17767{
17768 face searchsh;
17769
17770 if (b->verbose > 2) {
17771 printf(" Insert seg (%d, %d).\n", pointmark(tstart), pointmark(tend));
17772 }
17773
17774 // Find a triangle whose origin is the segment's first endpoint.
17775 searchsh.sh = dummysh;
17776 // Search for the segment's first endpoint by point location.
17777 if (locatesub(tstart, &searchsh, 0, 0.0) != ONVERTEX) {
17778 // Possibly caused by a degenerate subface. Do a brute-force search.
17779 list *newshlist;
17780 int i, j;
17781 newshlist = new list(sizeof(face), NULL, 256);
17782 // Get new subfaces, do not remove protected segments.
17783 retrievenewsubs(newshlist, false);
17784 // Search for a sub contain tstart.
17785 for (i = 0; i < newshlist->len(); i++) {
17786 searchsh = * (face *)(* newshlist)[i];
17787 for (j = 0; j < 3; j++) {
17788 if (sorg(searchsh) == tstart) break;
17789 senextself(searchsh);
17790 }
17791 if (j < 3) break;
17792 }
17793 delete newshlist;
17794 if (sorg(searchsh) != tstart) {
17795 printf("Internal error in recoversegment(): Vertex location failed.\n");
17796 internalerror();
17797 }
17798 }
17799 // Scout the segment and insert it if it is found.
17800 if (scoutsegmentsub(&searchsh, tend)) {
17801 // The segment was easily inserted.
17802 return;
17803 }
17804 // Insert the segment into the triangulation by flips.
17805 constrainededge(&searchsh, tend, flipqueue);
17806 // Some edges may need flipping.
17807 flipsub(flipqueue);
17808}
17809
17811// //
17812// infecthullsub() Virally infect all of the triangles of the convex hull //
17813// that are not protected by subsegments. //
17814// //
17816
17817void tetgenmesh::infecthullsub(memorypool* viri)
17818{
17819 face hulltri, nexttri, starttri;
17820 face hullsubseg;
17821 shellface **deadshellface;
17822
17823 // Find a triangle handle on the hull.
17824 hulltri.sh = dummysh;
17825 hulltri.shver = 0;
17826 spivotself(hulltri);
17827 adjustedgering(hulltri, CCW);
17828 // Remember where we started so we know when to stop.
17829 starttri = hulltri;
17830 // Go once counterclockwise around the convex hull.
17831 do {
17832 // Ignore triangles that are already infected.
17833 if (!sinfected(hulltri)) {
17834 // Is the triangle protected by a subsegment?
17835 sspivot(hulltri, hullsubseg);
17836 if (hullsubseg.sh == dummysh) {
17837 // The triangle is not protected; infect it.
17838 if (!sinfected(hulltri)) {
17839 sinfect(hulltri);
17840 deadshellface = (shellface **) viri->alloc();
17841 *deadshellface = hulltri.sh;
17842 }
17843 }
17844 }
17845 // To find the next hull edge, go clockwise around the next vertex.
17846 senextself(hulltri); // lnextself(hulltri);
17847 spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
17848 if (nexttri.sh == hulltri.sh) {
17849 nexttri.sh = dummysh; // 'hulltri' is self-bonded.
17850 } else {
17851 adjustedgering(nexttri, CCW);
17852 senextself(nexttri);
17853 }
17854 while (nexttri.sh != dummysh) {
17855 hulltri = nexttri;
17856 spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
17857 if (nexttri.sh == hulltri.sh) {
17858 nexttri.sh = dummysh; // 'hulltri' is self-bonded.
17859 } else {
17860 adjustedgering(nexttri, CCW);
17861 senextself(nexttri);
17862 }
17863 }
17864 } while (hulltri != starttri);
17865}
17866
17868// //
17869// plaguesub() Spread the virus from all infected triangles to any //
17870// neighbors not protected by subsegments. Delete all //
17871// infected triangles. //
17872// //
17873// This is the procedure that actually creates holes and concavities. //
17874// //
17876
17877void tetgenmesh::plaguesub(memorypool* viri)
17878{
17879 face testtri, neighbor, ghostsh;
17880 face neighborsubseg;
17881 shellface **virusloop;
17882 shellface **deadshellface;
17883 int i;
17884
17885 // Loop through all the infected triangles, spreading the virus to
17886 // their neighbors, then to their neighbors' neighbors.
17887 viri->traversalinit();
17888 virusloop = (shellface **) viri->traverse();
17889 while (virusloop != (shellface **) NULL) {
17890 testtri.sh = *virusloop;
17891 // Check each of the triangle's three neighbors.
17892 for (i = 0; i < 3; i++) {
17893 // Find the neighbor.
17894 spivot(testtri, neighbor);
17895 // Check for a subsegment between the triangle and its neighbor.
17896 sspivot(testtri, neighborsubseg);
17897 // Check if the neighbor is nonexistent or already infected.
17898 if ((neighbor.sh == dummysh) || sinfected(neighbor)) {
17899 if (neighborsubseg.sh != dummysh) {
17900 // There is a subsegment separating the triangle from its
17901 // neighbor, but both triangles are dying, so the subsegment
17902 // dies too.
17903 shellfacedealloc(subsegs, neighborsubseg.sh);
17904 if (neighbor.sh != dummysh) {
17905 // Make sure the subsegment doesn't get deallocated again
17906 // later when the infected neighbor is visited.
17907 ssdissolve(neighbor);
17908 }
17909 }
17910 } else { // The neighbor exists and is not infected.
17911 if (neighborsubseg.sh == dummysh) {
17912 // There is no subsegment protecting the neighbor, so the
17913 // neighbor becomes infected.
17914 sinfect(neighbor);
17915 // Ensure that the neighbor's neighbors will be infected.
17916 deadshellface = (shellface **) viri->alloc();
17917 *deadshellface = neighbor.sh;
17918 } else { // The neighbor is protected by a subsegment.
17919 // Remove this triangle from the subsegment.
17920 ssbond(neighbor, neighborsubseg);
17921 }
17922 }
17923 senextself(testtri);
17924 }
17925 virusloop = (shellface **) viri->traverse();
17926 }
17927
17928 ghostsh.sh = dummysh; // A handle of outer space.
17929 viri->traversalinit();
17930 virusloop = (shellface **) viri->traverse();
17931 while (virusloop != (shellface **) NULL) {
17932 testtri.sh = *virusloop;
17933 // Record changes in the number of boundary edges, and disconnect
17934 // dead triangles from their neighbors.
17935 for (i = 0; i < 3; i++) {
17936 spivot(testtri, neighbor);
17937 if (neighbor.sh != dummysh) {
17938 // Disconnect the triangle from its neighbor.
17939 // sdissolve(neighbor);
17940 sbond(neighbor, ghostsh);
17941 }
17942 senextself(testtri);
17943 }
17944 // Return the dead triangle to the pool of triangles.
17945 shellfacedealloc(subfaces, testtri.sh);
17946 virusloop = (shellface **) viri->traverse();
17947 }
17948 // Empty the virus pool.
17949 viri->restart();
17950}
17951
17953// //
17954// carveholessub() Find the holes and infect them. Find the area //
17955// constraints and infect them. Infect the convex hull. //
17956// Spread the infection and kill triangles. Spread the //
17957// area constraints. //
17958// //
17959// This routine mainly calls other routines to carry out all these functions.//
17960// //
17962
17963void tetgenmesh::carveholessub(int holes, REAL* holelist, memorypool *viri)
17964{
17965 face searchtri, triangleloop;
17966 shellface **holetri;
17967 enum locateresult intersect;
17968 int i;
17969
17970 // Mark as infected any unprotected triangles on the boundary.
17971 // This is one way by which concavities are created.
17972 infecthullsub(viri);
17973
17974 if (holes > 0) {
17975 // Infect each triangle in which a hole lies.
17976 for (i = 0; i < 3 * holes; i += 3) {
17977 // Ignore holes that aren't within the bounds of the mesh.
17978 if ((holelist[i] >= xmin) && (holelist[i] <= xmax)
17979 && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)
17980 && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) {
17981 // Start searching from some triangle on the outer boundary.
17982 searchtri.sh = dummysh;
17983 // Find a triangle that contains the hole.
17984 intersect = locatesub(&holelist[i], &searchtri, 0, 0.0);
17985 if ((intersect != OUTSIDE) && (!sinfected(searchtri))) {
17986 // Infect the triangle. This is done by marking the triangle
17987 // as infected and including the triangle in the virus pool.
17988 sinfect(searchtri);
17989 holetri = (shellface **) viri->alloc();
17990 *holetri = searchtri.sh;
17991 }
17992 }
17993 }
17994 }
17995
17996 if (viri->items > 0) {
17997 // Carve the holes and concavities.
17998 plaguesub(viri);
17999 }
18000 // The virus pool should be empty now.
18001}
18002
18004// //
18005// triangulate() Triangulate a PSLG into a CDT. //
18006// //
18007// A Planar Straight Line Graph (PSLG) P is actually a 2D polygonal region, //
18008// possibly contains holes, segments and vertices in its interior. P is tri- //
18009// angulated into a set of _subfaces_ forming a CDT of P. //
18010// //
18011// The vertices and segments of P are found in 'ptlist' and 'conlist', resp- //
18012// ectively. 'holelist' contains a list of hole points. 'shmark' will be set //
18013// to all subfaces of P. //
18014// //
18015// The CDT is created directly in the pools 'subfaces' and 'subsegs'. It can //
18016// be retrived by a broadth-first searching starting from 'dummysh[0]'(debug //
18017// function 'outsurfmesh()' does it). //
18018// //
18020
18021void tetgenmesh::triangulate(int shmark, REAL eps, list* ptlist, list* conlist,
18022 int holes, REAL* holelist, memorypool* viri, queue* flipqueue)
18023{
18024 face newsh;
18025 point *cons;
18026 int i;
18027
18028 if (b->verbose > 1) {
18029 printf(" %d vertices, %d segments", ptlist->len(), conlist->len());
18030 if (holes > 0) {
18031 printf(", %d holes", holes);
18032 }
18033 printf(", shmark: %d.\n", shmark);
18034 }
18035
18036 // Create the DT of V by the 2D incremental flip algorithm.
18037 incrflipdelaunaysub(shmark, eps, ptlist, holes, holelist, flipqueue);
18038 // Recover boundary edges.
18039 if (ptlist->len() > 3) {
18040 // Insert segments into the DT.
18041 for (i = 0; i < conlist->len(); i++) {
18042 cons = (point *)(* conlist)[i];
18043 recoversegment(cons[0], cons[1], flipqueue);
18044 }
18045 // Carve holes and concavities.
18046 carveholessub(holes, holelist, viri);
18047 } else if (ptlist->len() == 3) {
18048 // Insert 3 segments directly.
18049 newsh.sh = dummysh;
18050 newsh.shver = 0;
18051 spivotself(newsh);
18052 for (i = 0; i < 3; i++) {
18053 insertsubseg(&newsh);
18054 senextself(newsh);
18055 }
18056 } else if (ptlist->len() == 2) {
18057 // This facet is actually a segment. It is not support by the mesh data
18058 // strcuture. Hence the segment will not be maintained in the mesh.
18059 // However, during segment recovery, the segment can be processed.
18060 cons = (point *)(* conlist)[0];
18061 makeshellface(subsegs, &newsh);
18062 setsorg(newsh, cons[0]);
18063 setsdest(newsh, cons[1]);
18064 }
18065}
18066
18068// //
18069// retrievenewsubs() Retrieve newly created subfaces. //
18070// //
18071// The new subfaces created by triangulate() can be found by a broadth-first //
18072// searching starting from 'dummysh[0]'. //
18073// //
18074// 'newshlist' (empty on input) returns the retrieved subfaces. Each edge on //
18075// the hull is bound to 'dummysh' and protected by a segment. If 'removeseg' //
18076// is TRUE, the segment is removed. //
18077// //
18079
18080void tetgenmesh::retrievenewsubs(list* newshlist, bool removeseg)
18081{
18082 face startsh, neighsh;
18083 face deadseg;
18084 int i, j;
18085
18086 // The first new subface is found at dummysh[0].
18087 startsh.sh = dummysh;
18088 startsh.shver = 0;
18089 spivotself(startsh);
18090 assert(startsh.sh != dummysh);
18091 sinfect(startsh);
18092 newshlist->append(&startsh);
18093
18094 // Find the rest of new subfaces by a broadth-first searching.
18095 for (i = 0; i < newshlist->len(); i++) {
18096 // Get a new subface s.
18097 startsh = * (face *)(* newshlist)[i];
18098 for (j = 0; j < 3; j++) {
18099 spivot(startsh, neighsh);
18100 if (neighsh.sh != dummysh) {
18101 if (!sinfected(neighsh)) {
18102 // Discovered a new subface.
18103 sinfect(neighsh);
18104 newshlist->append(&neighsh);
18105 }
18106 } else {
18107 // Found a boundary edge.
18108 if (removeseg) {
18109 // This side of s may be protected by a segment.
18110 sspivot(startsh, deadseg);
18111 if (deadseg.sh != dummysh) {
18112 // Detach it from s.
18113 ssdissolve(startsh);
18114 // Delete the segment.
18115 shellfacedealloc(subsegs, deadseg.sh);
18116 }
18117 }
18118 }
18119 senextself(startsh);
18120 }
18121 }
18122 for (i = 0; i < newshlist->len(); i++) {
18123 startsh = * (face *)(* newshlist)[i];
18124 suninfect(startsh);
18125 }
18126}
18127
18129// //
18130// unifysegments() Unify identical segments and build facet connections. //
18131// //
18132// After creating the surface mesh. Each facet has its own segments. There //
18133// are duplicated segments between adjacent facets. This routine has three //
18134// purposes: //
18135// (1) identify the set of segments which have the same endpoints and //
18136// unify them into one segment, remove redundant ones; //
18137// (2) create the face rings of the unified segments, hence setup the //
18138// connections between facets; and //
18139// (3) set a unique marker (1-based) for each segment. //
18140// On finish, each segment is unique and the face ring around it (right-hand //
18141// rule) is constructed. The connections between facets-facets are setup. //
18142// //
18144
18145void tetgenmesh::unifysegments()
18146{
18147 list *sfacelist;
18148 shellface **facesperverlist;
18149 face subsegloop, testseg;
18150 face sface, sface1, sface2;
18151 point torg, tdest;
18152 REAL da1, da2;
18153 int *idx2facelist;
18154 int segmarker;
18155 int idx, k, m;
18156
18157 if (b->verbose > 0) {
18158 printf(" Unifying segments.\n");
18159 }
18160
18161 // Compute a mapping from indices of vertices to subfaces.
18162 makesubfacemap(idx2facelist, facesperverlist);
18163 // Initialize 'sfacelist' for constructing the face link of each segment.
18164 sfacelist = new list(sizeof(face), NULL);
18165
18166 segmarker = 1;
18167 subsegs->traversalinit();
18168 subsegloop.sh = shellfacetraverse(subsegs);
18169 while (subsegloop.sh != (shellface *) NULL) {
18170 subsegloop.shver = 0; // For sure.
18171 torg = sorg(subsegloop);
18172 tdest = sdest(subsegloop);
18173 idx = pointmark(torg) - in->firstnumber;
18174 // Loop through the set of subfaces containing 'torg'. Get all the
18175 // subfaces containing the edge (torg, tdest). Save and order them
18176 // in 'sfacelist', the ordering is defined by the right-hand rule
18177 // with thumb points from torg to tdest.
18178 for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) {
18179 sface.sh = facesperverlist[k];
18180 sface.shver = 0;
18181 // sface may be died due to the removing of duplicated subfaces.
18182 if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) {
18183 // 'sface' contains this segment.
18184 findedge(&sface, torg, tdest);
18185 // Save it in 'sfacelist'.
18186 if (sfacelist->len() < 2) {
18187 sfacelist->append(&sface);
18188 } else {
18189 for (m = 0; m < sfacelist->len() - 1; m++) {
18190 sface1 = * (face *)(* sfacelist)[m];
18191 sface2 = * (face *)(* sfacelist)[m + 1];
18192 da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface));
18193 da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2));
18194 if (da1 < da2) {
18195 break; // Insert it after m.
18196 }
18197 }
18198 sfacelist->insert(m + 1, &sface);
18199 }
18200 }
18201 }
18202 if (b->verbose > 1) {
18203 printf(" Identifying %d segments of (%d %d).\n", sfacelist->len(),
18204 pointmark(torg), pointmark(tdest));
18205 }
18206 // Set the connection between this segment and faces containing it,
18207 // at the same time, remove redundant segments.
18208 for (k = 0; k < sfacelist->len(); k++) {
18209 sface = *(face *)(* sfacelist)[k];
18210 sspivot(sface, testseg);
18211 // If 'testseg' is not 'subsegloop', it is a redundant segment that
18212 // needs be removed. BE CAREFUL it may already be removed. Do not
18213 // remove it twice, i.e., do test 'isdead()' together.
18214 if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) {
18215 shellfacedealloc(subsegs, testseg.sh);
18216 }
18217 // 'ssbond' bonds the subface and the segment together, and dissloves
18218 // the old bond as well.
18219 ssbond(sface, subsegloop);
18220 }
18221 // Set connection between these faces.
18222 sface = *(face *)(* sfacelist)[0];
18223 for (k = 1; k <= sfacelist->len(); k++) {
18224 if (k < sfacelist->len()) {
18225 sface1 = *(face *)(* sfacelist)[k];
18226 } else {
18227 sface1 = *(face *)(* sfacelist)[0]; // Form a face loop.
18228 }
18229 /*
18230 // Check if these two subfaces are the same. It is possible when user
18231 // defines one facet (or polygon) two or more times. If they are,
18232 // they should not be bonded together, instead of that, one of them
18233 // should be delete from the surface mesh.
18234 if ((sfacelist->len() > 1) && sapex(sface) == sapex(sface1)) {
18235 // They are duplicated faces.
18236 if (b->verbose > 0) {
18237 printf(" A duplicated subface (%d, %d, %d) is removed.\n",
18238 pointmark(torg), pointmark(tdest), pointmark(sapex(sface)));
18239 }
18240 if (k == sfacelist->len()) {
18241 // 'sface' is the last face, however, it is same as the first one.
18242 // In order to form the ring, we have to let the second last
18243 // face bond to the first one 'sface1'.
18244 shellfacedealloc(subfaces, sface.sh);
18245 assert(sfacelist->len() >= 2);
18246 assert(k == sfacelist->len());
18247 sface = *(face *)(* sfacelist)[k - 2];
18248 } else {
18249 // 'sface1' is in the middle and may be the last one.
18250 shellfacedealloc(subfaces, sface1.sh);
18251 // Skip this face and go to the next one.
18252 continue;
18253 }
18254 }
18255 */
18256 if (b->verbose > 2) {
18257 printf(" Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n",
18258 pointmark(torg), pointmark(tdest), pointmark(sapex(sface)),
18259 pointmark(torg), pointmark(tdest), pointmark(sapex(sface1)));
18260 }
18261 sbond1(sface, sface1);
18262 sface = sface1;
18263 }
18264 // Set the unique segment marker into the unified segment.
18265 setshellmark(subsegloop, segmarker);
18266 // Increase the marker.
18267 segmarker++;
18268 // Clear the working list.
18269 sfacelist->clear();
18270 subsegloop.sh = shellfacetraverse(subsegs);
18271 }
18272
18273 delete [] idx2facelist;
18274 delete [] facesperverlist;
18275 delete sfacelist;
18276}
18277
18279// //
18280// mergefacets() Merge adjacent facets to be one facet if they are //
18281// coplanar and have the same boundary marker. //
18282// //
18283// Segments between two merged facets will be removed from the mesh. If all //
18284// segments around a vertex have been removed, change its vertex type to be //
18285// FREESUBVERTEX. Edge flips will be performed to ensure the Delaunayness of //
18286// the triangulation of merged facets. //
18287// //
18289
18290void tetgenmesh::mergefacets(queue* flipqueue)
18291{
18292 face parentsh, neighsh, neineighsh;
18293 face segloop;
18294 point eorg, edest;
18295 REAL ori;
18296 bool mergeflag, pbcflag;
18297 int* segspernodelist;
18298 int fidx1, fidx2;
18299 int i, j;
18300
18301 if (b->verbose > 0) {
18302 printf(" Merging coplanar facets.\n");
18303 }
18304 // Create and initialize 'segspernodelist'.
18305 segspernodelist = new int[points->items + 1];
18306 for (i = 0; i < points->items + 1; i++) segspernodelist[i] = 0;
18307
18308 // Loop the segments, counter the number of segments sharing each vertex.
18309 subsegs->traversalinit();
18310 segloop.sh = shellfacetraverse(subsegs);
18311 while (segloop.sh != (shellface *) NULL) {
18312 // Increment the number of sharing segments for each endpoint.
18313 for (i = 0; i < 2; i++) {
18314 j = pointmark((point) segloop.sh[3 + i]);
18315 segspernodelist[j]++;
18316 }
18317 segloop.sh = shellfacetraverse(subsegs);
18318 }
18319
18320 // Loop the segments, find out dead segments.
18321 subsegs->traversalinit();
18322 segloop.sh = shellfacetraverse(subsegs);
18323 while (segloop.sh != (shellface *) NULL) {
18324 eorg = sorg(segloop);
18325 edest = sdest(segloop);
18326 spivot(segloop, parentsh);
18327 spivot(parentsh, neighsh);
18328 spivot(neighsh, neineighsh);
18329 if (parentsh.sh != neighsh.sh && parentsh.sh == neineighsh.sh) {
18330 // Exactly two subfaces at this segment.
18331 fidx1 = shellmark(parentsh) - 1;
18332 fidx2 = shellmark(neighsh) - 1;
18333 pbcflag = false;
18334 if (checkpbcs) {
18335 pbcflag = (shellpbcgroup(parentsh) >= 0)
18336 || (shellpbcgroup(neighsh) >= 0);
18337 }
18338 // Possibly merge them if they are not in the same facet.
18339 if ((fidx1 != fidx2) && !pbcflag) {
18340 // Test if they are coplanar.
18341 ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh));
18342 if (ori != 0.0) {
18343 if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori,
18344 b->epsilon)) {
18345 ori = 0.0; // They are assumed as coplanar.
18346 }
18347 }
18348 if (ori == 0.0) {
18349 mergeflag = (in->facetmarkerlist == (int *) NULL ||
18350 in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]);
18351 if (mergeflag) {
18352 // This segment becomes dead.
18353 if (b->verbose > 1) {
18354 printf(" Removing segment (%d, %d).\n", pointmark(eorg),
18355 pointmark(edest));
18356 }
18357 ssdissolve(parentsh);
18358 ssdissolve(neighsh);
18359 shellfacedealloc(subsegs, segloop.sh);
18360 j = pointmark(eorg);
18361 segspernodelist[j]--;
18362 if (segspernodelist[j] == 0) {
18363 setpointtype(eorg, FREESUBVERTEX);
18364 }
18365 j = pointmark(edest);
18366 segspernodelist[j]--;
18367 if (segspernodelist[j] == 0) {
18368 setpointtype(edest, FREESUBVERTEX);
18369 }
18370 // Add 'parentsh' to queue checking for flip.
18371 enqueueflipedge(parentsh, flipqueue);
18372 }
18373 }
18374 }
18375 }
18376 segloop.sh = shellfacetraverse(subsegs);
18377 }
18378
18379 if (!flipqueue->empty()) {
18380 // Restore the Delaunay property in the facet triangulation.
18381 flipsub(flipqueue);
18382 }
18383
18384 delete [] segspernodelist;
18385}
18386
18388// //
18389// meshsurface() Create the surface mesh of a PLC. //
18390// //
18391// Let X be the PLC, the surface mesh S of X consists of triangulated facets.//
18392// S is created mainly in the following steps: //
18393// //
18394// (1) Form the CDT of each facet of X separately (by routine triangulate()).//
18395// After it is done, the subfaces of each facet are connected to each other, //
18396// however there is no connection between facets yet. Notice each facet has //
18397// its own segments, some of them are duplicated. //
18398// //
18399// (2) Remove the redundant segments created in step (1) (by routine unify- //
18400// segment()). The subface ring of each segment is created, the connection //
18401// between facets are established as well. //
18402// //
18403// The return value indicates the number of segments of X. //
18404// //
18406
18407long tetgenmesh::meshsurface()
18408{
18409 list *ptlist, *conlist;
18410 queue *flipqueue;
18411 tetgenio::facet *f;
18412 tetgenio::polygon *p;
18413 memorypool *viri;
18414 point *idx2verlist;
18415 point tstart, tend, *cons;
18416 int *worklist;
18417 int end1, end2;
18418 int shmark, i, j;
18419
18420 if (!b->quiet) {
18421 printf("Creating surface mesh.\n");
18422 }
18423
18424 // Compute a mapping from indices to points.
18425 makeindex2pointmap(idx2verlist);
18426 // Compute a mapping from points to tets for computing abovepoints.
18427 makepoint2tetmap();
18428 // Initialize 'facetabovepointarray'.
18429 facetabovepointarray = new point[in->numberoffacets + 1];
18430 for (i = 0; i < in->numberoffacets + 1; i++) {
18431 facetabovepointarray[i] = (point) NULL;
18432 }
18433 if (checkpbcs) {
18434 // Initialize the global array 'subpbcgrouptable'.
18435 createsubpbcgrouptable();
18436 }
18437
18438 // Initialize working lists.
18439 viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
18440 flipqueue = new queue(sizeof(badface));
18441 ptlist = new list(sizeof(point *), NULL, 256);
18442 conlist = new list(sizeof(point *) * 2, NULL, 256);
18443 worklist = new int[points->items + 1];
18444 for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
18445
18446 // Loop the facet list, triangulate each facet. On finish, all subfaces
18447 // are in 'subfaces', all segments are in 'subsegs'. Notice: there're
18448 // redundant segments. Remember: All facet indices count from 1.
18449 for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
18450 // Get a facet F.
18451 f = &in->facetlist[shmark - 1];
18452
18453 // Process the duplicated points first, they are marked with type
18454 // DUPLICATEDVERTEX by incrflipdelaunay(). Let p and q are dup.
18455 // and the index of p is larger than q's, p is substituted by q.
18456 // In a STL mesh, duplicated points are implicitly included.
18457 if ((b->object == tetgenbehavior::STL) || dupverts) {
18458 // Loop all polygons of this facet.
18459 for (i = 0; i < f->numberofpolygons; i++) {
18460 p = &(f->polygonlist[i]);
18461 // Loop other vertices of this polygon.
18462 for (j = 0; j < p->numberofvertices; j++) {
18463 end1 = p->vertexlist[j];
18464 tstart = idx2verlist[end1 - in->firstnumber];
18465 if (pointtype(tstart) == DUPLICATEDVERTEX) {
18466 // Reset the index of vertex-j.
18467 tend = point2ppt(tstart);
18468 end2 = pointmark(tend);
18469 p->vertexlist[j] = end2;
18470 }
18471 }
18472 }
18473 }
18474
18475 // Loop polygons of F, get the set V of vertices and S of segments.
18476 for (i = 0; i < f->numberofpolygons; i++) {
18477 // Get a polygon.
18478 p = &(f->polygonlist[i]);
18479 // Get the first vertex.
18480 end1 = p->vertexlist[0];
18481 if ((end1 < in->firstnumber) ||
18482 (end1 >= in->firstnumber + in->numberofpoints)) {
18483 if (!b->quiet) {
18484 printf("Warning: Invalid the 1st vertex %d of polygon", end1);
18485 printf(" %d in facet %d.\n", i + 1, shmark);
18486 }
18487 continue; // Skip this polygon.
18488 }
18489 tstart = idx2verlist[end1 - in->firstnumber];
18490 // Add tstart to V if it haven't been added yet.
18491 if (worklist[end1] == 0) {
18492 ptlist->append(&tstart);
18493 worklist[end1] = 1;
18494 }
18495 // Loop other vertices of this polygon.
18496 for (j = 1; j <= p->numberofvertices; j++) {
18497 // get a vertex.
18498 if (j < p->numberofvertices) {
18499 end2 = p->vertexlist[j];
18500 } else {
18501 end2 = p->vertexlist[0]; // Form a loop from last to first.
18502 }
18503 if ((end2 < in->firstnumber) ||
18504 (end2 >= in->firstnumber + in->numberofpoints)) {
18505 if (!b->quiet) {
18506 printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1);
18507 printf(" in facet %d.\n", shmark);
18508 }
18509 } else {
18510 if (end1 != end2) {
18511 // 'end1' and 'end2' form a segment.
18512 tend = idx2verlist[end2 - in->firstnumber];
18513 // Add tstart to V if it haven't been added yet.
18514 if (worklist[end2] == 0) {
18515 ptlist->append(&tend);
18516 worklist[end2] = 1;
18517 }
18518 // Save the segment in S (conlist).
18519 cons = (point *) conlist->append(NULL);
18520 cons[0] = tstart;
18521 cons[1] = tend;
18522 // Set the start for next continuous segment.
18523 end1 = end2;
18524 tstart = tend;
18525 } else {
18526 // Two identical vertices represent an isolated vertex of F.
18527 if (p->numberofvertices > 2) {
18528 // This may be an error in the input, anyway, we can continue
18529 // by simply skipping this segment.
18530 if (!b->quiet) {
18531 printf("Warning: Polygon %d has two identical verts", i + 1);
18532 printf(" in facet %d.\n", shmark);
18533 }
18534 }
18535 // Ignore this vertex.
18536 }
18537 }
18538 // Is the polygon degenerate (a segment or a vertex)?
18539 if (p->numberofvertices == 2) break;
18540 }
18541 }
18542 // Unmark vertices.
18543 for (i = 0; i < ptlist->len(); i++) {
18544 tstart = * (point *)(* ptlist)[i];
18545 end1 = pointmark(tstart);
18546 assert(worklist[end1] == 1);
18547 worklist[end1] = 0;
18548 }
18549
18550 // Create a CDT of F.
18551 triangulate(shmark, b->epsilon * 1e+2, ptlist, conlist, f->numberofholes,
18552 f->holelist, viri, flipqueue);
18553 // Clear working lists.
18554 ptlist->clear();
18555 conlist->clear();
18556 viri->restart();
18557 }
18558
18559 // Unify segments in 'subsegs', remove redundant segments. Face links
18560 // of segments are also built.
18561 unifysegments();
18562 // Remember the number of input segments (for output).
18563 insegments = subsegs->items;
18564
18565 if (checkpbcs) {
18566 // Create the global array 'segpbcgrouptable'.
18567 createsegpbcgrouptable();
18568 }
18569
18570 if (b->object == tetgenbehavior::STL) {
18571 // Remove redundant vertices (for .stl input mesh).
18572 jettisonnodes();
18573 }
18574
18575 if (!b->nomerge && !b->nobisect && !checkpbcs) {
18576 // No '-M' switch - merge adjacent facets if they are coplanar.
18577 mergefacets(flipqueue);
18578 }
18579
18580 delete [] idx2verlist;
18581 delete [] worklist;
18582 delete ptlist;
18583 delete conlist;
18584 delete flipqueue;
18585 delete viri;
18586
18587 return subsegs->items;
18588}
18589
18590//
18591// End of surface triangulation routines
18592//
18593
18595// //
18596// interecursive() Recursively do intersection test on a set of triangles.//
18597// //
18598// Recursively split the set 'subfacearray' of subfaces into two sets using //
18599// a cut plane parallel to x-, or, y-, or z-axies. The split criteria are //
18600// follows. Assume the cut plane is H, and H+ denotes the left halfspace of //
18601// H, and H- denotes the right halfspace of H; and s be a subface: //
18602// //
18603// (1) If all points of s lie at H+, put it into left array; //
18604// (2) If all points of s lie at H-, put it into right array; //
18605// (3) If some points of s lie at H+ and some of lie at H-, or some //
18606// points lie on H, put it into both arraies. //
18607// //
18608// Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis //
18609// if axis == '2'. If current cut plane is parallel to the x-axis, the next //
18610// one will be parallel to y-axis, and the next one after the next is z-axis,//
18611// and then alternately return back to x-axis. //
18612// //
18613// Stop splitting when the number of triangles of the input array is not //
18614// decreased anymore. Do tests on the current set. //
18615// //
18617
18618void tetgenmesh::
18619interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin,
18620 REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax,
18621 int* internum)
18622{
18623 shellface **leftarray, **rightarray;
18624 face sface1, sface2;
18625 point p1, p2, p3;
18626 point p4, p5, p6;
18627 enum interresult intersect;
18628 REAL split;
18629 bool toleft, toright;
18630 int leftsize, rightsize;
18631 int i, j;
18632
18633 if (b->verbose > 1) {
18634 printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
18635 arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
18636 axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
18637 }
18638
18639 leftarray = new shellface*[arraysize];
18640 if (leftarray == NULL) {
18641 printf("Error in interecursive(): Insufficient memory.\n");
18642 terminatetetgen(1);
18643 }
18644 rightarray = new shellface*[arraysize];
18645 if (rightarray == NULL) {
18646 printf("Error in interecursive(): Insufficient memory.\n");
18647 terminatetetgen(1);
18648 }
18649 leftsize = rightsize = 0;
18650
18651 if (axis == 0) {
18652 // Split along x-axis.
18653 split = 0.5 * (bxmin + bxmax);
18654 } else if (axis == 1) {
18655 // Split along y-axis.
18656 split = 0.5 * (bymin + bymax);
18657 } else {
18658 // Split along z-axis.
18659 split = 0.5 * (bzmin + bzmax);
18660 }
18661
18662 for (i = 0; i < arraysize; i++) {
18663 sface1.sh = subfacearray[i];
18664 p1 = (point) sface1.sh[3];
18665 p2 = (point) sface1.sh[4];
18666 p3 = (point) sface1.sh[5];
18667 toleft = toright = false;
18668 if (p1[axis] < split) {
18669 toleft = true;
18670 if (p2[axis] >= split || p3[axis] >= split) {
18671 toright = true;
18672 }
18673 } else if (p1[axis] > split) {
18674 toright = true;
18675 if (p2[axis] <= split || p3[axis] <= split) {
18676 toleft = true;
18677 }
18678 } else {
18679 // p1[axis] == split;
18680 toleft = true;
18681 toright = true;
18682 }
18683 // At least one is true;
18684#ifdef SELF_CHECK
18685 assert(!(toleft == false && toright == false));
18686#endif
18687 if (toleft) {
18688 leftarray[leftsize] = sface1.sh;
18689 leftsize++;
18690 }
18691 if (toright) {
18692 rightarray[rightsize] = sface1.sh;
18693 rightsize++;
18694 }
18695 }
18696
18697 if (leftsize < arraysize && rightsize < arraysize) {
18698 // Continue to partition the input set. Now 'subfacearray' has been
18699 // split into two sets, it's memory can be freed. 'leftarray' and
18700 // 'rightarray' will be freed in the next recursive (after they're
18701 // partitioned again or performing tests).
18702 delete [] subfacearray;
18703 // Continue to split these two sets.
18704 if (axis == 0) {
18705 interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
18706 bzmin, bzmax, internum);
18707 interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
18708 bzmin, bzmax, internum);
18709 } else if (axis == 1) {
18710 interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
18711 bzmin, bzmax, internum);
18712 interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
18713 bzmin, bzmax, internum);
18714 } else {
18715 interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
18716 bzmin, split, internum);
18717 interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
18718 split, bzmax, internum);
18719 }
18720 } else {
18721 if (b->verbose > 1) {
18722 printf(" Checking intersecting faces.\n");
18723 }
18724 // Perform a brute-force compare on the set.
18725 for (i = 0; i < arraysize; i++) {
18726 sface1.sh = subfacearray[i];
18727 p1 = (point) sface1.sh[3];
18728 p2 = (point) sface1.sh[4];
18729 p3 = (point) sface1.sh[5];
18730 for (j = i + 1; j < arraysize; j++) {
18731 sface2.sh = subfacearray[j];
18732 p4 = (point) sface2.sh[3];
18733 p5 = (point) sface2.sh[4];
18734 p6 = (point) sface2.sh[5];
18735 intersect = tri_tri_inter(p1, p2, p3, p4, p5, p6);
18736 if (intersect == INTERSECT || intersect == SHAREFACE) {
18737 if (!b->quiet) {
18738 if (intersect == INTERSECT) {
18739 printf(" Facet #%d intersects facet #%d at triangles:\n",
18740 shellmark(sface1), shellmark(sface2));
18741 printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
18742 pointmark(p1), pointmark(p2), pointmark(p3),
18743 pointmark(p4), pointmark(p5), pointmark(p6));
18744 } else {
18745 printf(" Facet #%d duplicates facet #%d at triangle:\n",
18746 shellmark(sface1), shellmark(sface2));
18747 printf(" (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2),
18748 pointmark(p3));
18749 }
18750 }
18751 // Increase the number of intersecting pairs.
18752 (*internum)++;
18753 // Infect these two faces (although they may already be infected).
18754 sinfect(sface1);
18755 sinfect(sface2);
18756 }
18757 }
18758 }
18759 // Don't forget to free all three arrays. No further partition.
18760 delete [] leftarray;
18761 delete [] rightarray;
18762 delete [] subfacearray;
18763 }
18764}
18765
18767// //
18768// detectinterfaces() Detect intersecting triangles. //
18769// //
18770// Given a set of triangles, find the pairs of intersecting triangles from //
18771// them. Here the set of triangles is in 'subfaces' which is a surface mesh //
18772// of a PLC (.poly or .smesh). //
18773// //
18774// To detect whether two triangles are intersecting is done by the routine //
18775// 'tri_tri_inter()'. The algorithm for the test is very simple and stable. //
18776// It is based on geometric orientation test which uses exact arithmetics. //
18777// //
18778// Use divide-and-conquer algorithm for reducing the number of intersection //
18779// tests. Start from the bounding box of the input point set, recursively //
18780// partition the box into smaller boxes, until the number of triangles in a //
18781// box is not decreased anymore. Then perform triangle-triangle tests on the //
18782// remaining set of triangles. The memory allocated in the input set is //
18783// freed immediately after it has been partitioned into two arrays. So it //
18784// can be re-used for the consequent partitions. //
18785// //
18786// On return, the pool 'subfaces' will be cleared, and only the intersecting //
18787// triangles remain for output (to a .face file). //
18788// //
18790
18791void tetgenmesh::detectinterfaces()
18792{
18793 shellface **subfacearray;
18794 face shloop;
18795 int internum;
18796 int i;
18797
18798 if (!b->quiet) {
18799 printf("Detecting intersecting facets.\n");
18800 }
18801
18802 // Construct a map from indices to subfaces;
18803 subfacearray = new shellface*[subfaces->items];
18804 subfaces->traversalinit();
18805 shloop.sh = shellfacetraverse(subfaces);
18806 i = 0;
18807 while (shloop.sh != (shellface *) NULL) {
18808 subfacearray[i] = shloop.sh;
18809 shloop.sh = shellfacetraverse(subfaces);
18810 i++;
18811 }
18812
18813 internum = 0;
18814 // Recursively split the set of triangles into two sets using a cut plane
18815 // parallel to x-, or, y-, or z-axies. Stop splitting when the number
18816 // of subfaces is not decreasing anymore. Do tests on the current set.
18817 interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
18818 zmin, zmax, &internum);
18819
18820 if (!b->quiet) {
18821 if (internum > 0) {
18822 printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
18823 } else {
18824 printf("\nNo faces are intersecting.\n\n");
18825 }
18826 }
18827
18828 if (internum > 0) {
18829 // Traverse all subfaces, deallocate those have not been infected (they
18830 // are not intersecting faces). Uninfect those have been infected.
18831 // After this loop, only intersecting faces remain.
18832 subfaces->traversalinit();
18833 shloop.sh = shellfacetraverse(subfaces);
18834 while (shloop.sh != (shellface *) NULL) {
18835 if (sinfected(shloop)) {
18836 suninfect(shloop);
18837 } else {
18838 shellfacedealloc(subfaces, shloop.sh);
18839 }
18840 shloop.sh = shellfacetraverse(subfaces);
18841 }
18842 } else {
18843 // Deallocate all subfaces.
18844 subfaces->restart();
18845 }
18846}
18847
18848//
18849// Begin of periodic boundary condition routines
18850//
18851
18853// //
18854// createsubpbcgrouptable() Create the 'subpbcgrouptable'. //
18855// //
18856// Allocate the memory for 'subpbcgrouptable'. Each entry i (a pbcdata) of //
18857// the table represents a pbcgroup. Most of the fields of a group-i are set //
18858// in this routine. 'fmark[0]', 'fmark[1]', and 'transmat[0]' are directly //
18859// copied from the corresponding data of 'in->numberofpbcgroups'. 'transmat //
18860// [1]' is calculated as the inverse matrix of 'transmat[0]'. 'ss[0]' and //
18861// 'ss[1]' are initilized be 'dummysh'. They are set in 'trangulatefacet()' //
18862// (when -p is in use) or 'reconstructmesh()' (when -r is in use). //
18863// //
18865
18866void tetgenmesh::createsubpbcgrouptable()
18867{
18868 tetgenio::pbcgroup *pg;
18869 pbcdata *pd;
18870 REAL A[4][4], rhs[4], D;
18871 int indx[4];
18872 int i, j, k;
18873
18874 subpbcgrouptable = new pbcdata[in->numberofpbcgroups];
18875 for (i = 0; i < in->numberofpbcgroups; i++) {
18876 pg = &(in->pbcgrouplist[i]);
18877 pd = &(subpbcgrouptable[i]);
18878 // Copy data from pg to pd.
18879 pd->fmark[0] = pg->fmark1;
18880 pd->fmark[1] = pg->fmark2;
18881 // Initialize array 'pd->ss'.
18882 pd->ss[0].sh = dummysh;
18883 pd->ss[1].sh = dummysh;
18884 // Copy the transform matrix from pg to pd->transmat[0].
18885 for (j = 0; j < 4; j++) {
18886 for (k = 0; k < 4; k++) {
18887 pd->transmat[0][j][k] = pg->transmat[j][k];
18888 // Prepare for inverting the matrix.
18889 A[j][k] = pg->transmat[j][k];
18890 }
18891 }
18892 // Calculate the inverse matrix (pd->transmat[1]) of pd->transmat[0].
18893 lu_decmp(A, 4, indx, &D, 0);
18894 for (j = 0; j < 4; j++) {
18895 for (k = 0; k < 4; k++) rhs[k] = 0.0;
18896 rhs[j] = 1.0;
18897 lu_solve(A, 4, indx, rhs, 0);
18898 for (k = 0; k < 4; k++) pd->transmat[1][k][j] = rhs[k];
18899 }
18900 }
18901}
18902
18904// //
18905// getsubpbcgroup() Get the pbcgroup of a subface. //
18906// //
18907// 'pbcsub' has pbc defined. Its pbcgroup is returned in 'pd'. In addition, //
18908// 'f1' (0 or 1) indicates the position of 'pbcsub' in 'pd'; 'f2' (= 1 - f1) //
18909// is the position where the symmetric subface of 'pbcsub' is found. //
18910// //
18912
18913void tetgenmesh::getsubpbcgroup(face* pbcsub, pbcdata** pd, int *f1, int *f2)
18914{
18915 int groupid, fmark, idx;
18916
18917 groupid = shellpbcgroup(*pbcsub);
18918 *pd = &subpbcgrouptable[groupid];
18919
18920 // Get the facet index (1 - based).
18921 idx = shellmark(*pbcsub);
18922 // Get the facet marker from array (0 - based).
18923 fmark = in->facetmarkerlist[idx - 1];
18924 if ((*pd)->fmark[0] == fmark) {
18925 *f1 = 0;
18926 } else {
18927#ifdef SELF_CHECK
18928 assert((*pd)->fmark[1] == fmark);
18929#endif
18930 *f1 = 1;
18931 }
18932 *f2 = 1 - (*f1);
18933}
18934
18936// //
18937// getsubpbcsympoint() Compute the symmetric point for a subface point. //
18938// //
18939// 'newpoint' lies on 'splitsub'. This routine calculates a 'sympoint' which //
18940// locates on 'symsplitsub' and symmtric to 'newpoint'. Return the location //
18941// of sympoint wrt. symsplitsub. //
18942// //
18944
18945enum tetgenmesh::locateresult tetgenmesh:: getsubpbcsympoint(point newpoint,
18946 face* splitsub, point sympoint, face* symsplitsub)
18947{
18948 pbcdata *pd;
18949 face subloop;
18950 point pa, pb, pc;
18951 enum locateresult symloc;
18952 REAL ori;
18953 int f1, f2, i;
18954
18955 // Get the pbcgroup of 'splitsub'.
18956 getsubpbcgroup(splitsub, &pd, &f1, &f2);
18957
18958 // Transform newpoint from f1 -> f2.
18959 for (i = 0; i < 3; i++) {
18960 sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
18961 + pd->transmat[f1][i][1] * newpoint[1]
18962 + pd->transmat[f1][i][2] * newpoint[2]
18963 + pd->transmat[f1][i][3] * 1.0;
18964 }
18965 // Locate sympoint in f2.
18966 symloc = OUTSIDE;
18967 *symsplitsub = pd->ss[f2];
18968 // Is the stored subface valid? Hole removal may delete the subface.
18969 if ((symsplitsub->sh != dummysh) && !isdead(symsplitsub)) {
18970 // 'symsplitsub' should lie on the symmetric facet. Check it.
18971 i = shellmark(*symsplitsub);
18972 if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
18973 // 'symsplitsub' has the symmetric boundary marker.
18974 pa = sorg(*symsplitsub);
18975 pb = sdest(*symsplitsub);
18976 pc = sapex(*symsplitsub);
18977 // Test if they are (nearly) coplanar. Some facets may have the
18978 // same boundary marker but not coplanar with this point.
18979 ori = orient3d(pa, pb, pc, sympoint);
18980 if (iscoplanar(pa, pb, pc, sympoint, ori, b->epsilon * 1e+2)) {
18981 // Locate sympoint in facet. Don't stop at subsegment.
18982 abovepoint = facetabovepointarray[shellmark(*symsplitsub)];
18983 if (abovepoint == (point) NULL) {
18984 getfacetabovepoint(symsplitsub);
18985 }
18986 symloc = locatesub(sympoint, symsplitsub, 0, b->epsilon * 1e+2);
18987 }
18988 }
18989 }
18990 if (symloc == OUTSIDE) {
18991 // Do a brute-force searching for the symmetric subface.
18992 REAL epspp = b->epsilon * 1e+2;
18993 int lcount = 0;
18994 do {
18995 // Locate sympoint in the pool of subfaces (with fmark pd->fmark[f2]).
18996 subfaces->traversalinit();
18997 subloop.sh = shellfacetraverse(subfaces);
18998 while (subloop.sh != (shellface *) NULL) {
18999 i = shellmark(subloop);
19000 if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
19001 // Found a facet have the symmetric boundary marker.
19002 pa = sorg(subloop);
19003 pb = sdest(subloop);
19004 pc = sapex(subloop);
19005 // Test if they are (nearly) coplanar. Some facets may have the
19006 // same boundary marker but not coplanar with this point.
19007 ori = orient3d(pa, pb, pc, sympoint);
19008 if (iscoplanar(pa, pb, pc, sympoint, ori, epspp)) {
19009 // Test if sympoint is (nearly) inside this facet.
19010 // Get the abovepoint of the facet.
19011 abovepoint = facetabovepointarray[shellmark(subloop)];
19012 // Do we need to calculate the abovepoint?
19013 if (abovepoint == (point) NULL) {
19014 getfacetabovepoint(&subloop);
19015 }
19016 // subloop is on the facet, search sympoint.
19017 symloc = locatesub(sympoint, &subloop, 0, epspp);
19018 if (symloc != OUTSIDE) break;
19019 }
19020 }
19021 subloop.sh = shellfacetraverse(subfaces);
19022 }
19023 lcount++;
19024 epspp *= 10.0;
19025 } while ((symloc == OUTSIDE) && (lcount < 3));
19026#ifdef SELF_CHECK
19027 // sympoint should be inside the facet.
19028 assert(symloc != OUTSIDE);
19029#endif
19030 // Set the returning subface.
19031 *symsplitsub = subloop;
19032 // Update the stored subface for next searching.
19033 pd->ss[f2] = *symsplitsub;
19034 }
19035
19036 return adjustlocatesub(sympoint, symsplitsub, symloc, b->epsilon);
19037}
19038
19040// //
19041// createsegpbcgrouptable() Create the 'segpbcgrouptable'. //
19042// //
19043// Each segment may belong to more than one pbcgroups. For example, segment //
19044// ab may need to be symmteric to both segments cd, and ef, then ab and cd, //
19045// cd and ef, ef and ab form three pbcgroups. //
19046// //
19047// 'segpbcgrouptable' is implemented as a list of pbcdatas. Each item i is //
19048// a pbcgroup. //
19049// //
19051
19052void tetgenmesh::createsegpbcgrouptable()
19053{
19054 shellface** segsperverlist;
19055 pbcdata *pd, *ppd, pd1, pd2;
19056 face segloop, symseg;
19057 face startsh, spinsh, symsh;
19058 point pa, pb, syma, symb;
19059 enum locateresult symloc;
19060 REAL testpt[3], sympt[3];
19061 bool inflag;
19062 int *idx2seglist;
19063 int segid1, segid2;
19064 int f1, f2;
19065 int i, j, k, l;
19066
19067 // Allocate memory for 'subpbcgrouptable'.
19068 segpbcgrouptable = new list(sizeof(pbcdata), NULL, 256);
19069
19070 if (b->refine) {
19071 // Create a point-to-seg map for quickly finding PBC seg pairs.
19072 makesegmentmap(idx2seglist, segsperverlist);
19073 }
19074
19075 // Loop through the segment list.
19076 subsegs->traversalinit();
19077 segloop.sh = shellfacetraverse(subsegs);
19078 while (segloop.sh != (shellface *) NULL) {
19079 // Loop the subface ring of segloop ab.
19080 pa = sorg(segloop);
19081 pb = sdest(segloop);
19082 segid1 = shellmark(segloop);
19083 spivot(segloop, startsh);
19084 spinsh = startsh;
19085 do {
19086 // Adjust spinsh be edge ab.
19087 if (sorg(spinsh) != pa) {
19088 sesymself(spinsh);
19089 }
19090 // Does spinsh belong to a pbcgroup?
19091 if (shellpbcgroup(spinsh) != -1) {
19092 // Yes! There exists a segment cd. ab and cd form a pbcgroup.
19093 if (b->refine) {
19094 getsubpbcgroup(&spinsh, &pd, &f1, &f2);
19095 // Transform pa from f1 -> f2.
19096 for (i = 0; i < 3; i++) {
19097 sympt[i] = pd->transmat[f1][i][0] * pa[0]
19098 + pd->transmat[f1][i][1] * pa[1]
19099 + pd->transmat[f1][i][2] * pa[2]
19100 + pd->transmat[f1][i][3] * 1.0;
19101 }
19102 syma = point2pbcpt(pa);
19103 // Is 'sympt == syma'?
19104 if (distance(sympt, syma) > (longest * b->epsilon)) {
19105 // No. Search the symmetric vertex of pa.
19106 symloc = getsubpbcsympoint(pa, &spinsh, sympt, &symsh);
19107 syma = sorg(symsh);
19108 if (symloc != ONVERTEX) {
19109 // Do a brute force search. Not done yet.
19110 assert(0);
19111 }
19112 }
19113 // Transform pb from f1 -> f2.
19114 for (i = 0; i < 3; i++) {
19115 sympt[i] = pd->transmat[f1][i][0] * pb[0]
19116 + pd->transmat[f1][i][1] * pb[1]
19117 + pd->transmat[f1][i][2] * pb[2]
19118 + pd->transmat[f1][i][3] * 1.0;
19119 }
19120 // Search sym subface from the point-to-subface map.
19121 symseg.shver = 0;
19122 j = pointmark(syma) - in->firstnumber;
19123 for (i = idx2seglist[j]; i < idx2seglist[j + 1]; i++) {
19124 symseg.sh = segsperverlist[i];
19125 if (sorg(symseg) == syma) symb = sdest(symseg);
19126 else symb = sorg(symseg);
19127 if (distance(sympt, symb) <= (longest * b->epsilon)) break;
19128 }
19129 assert(i < idx2seglist[j + 1]);
19130 } else {
19131 // 'testpt' is the midpoint of ab used to find cd.
19132 for (i = 0; i < 3; i++) testpt[i] = 0.5 * (pa[i] + pb[i]);
19133 symloc = getsubpbcsympoint(testpt, &spinsh, sympt, &symsh);
19134#ifdef SELF_CHECK
19135 assert(symloc == ONEDGE);
19136#endif
19137 sspivot(symsh, symseg);
19138 }
19139#ifdef SELF_CHECK
19140 assert(symseg.sh != dummysh);
19141#endif
19142 // Check whether this group has already been created in list.
19143 segid2 = shellmark(symseg);
19144 inflag = false;
19145 for (i = 0; i < segpbcgrouptable->len() && !inflag; i++) {
19146 pd = (pbcdata *)(* segpbcgrouptable)[i];
19147 if (pd->segid[0] == segid1) {
19148 if (pd->segid[1] == segid2) inflag = true;
19149 } else if (pd->segid[0] == segid2) {
19150 if (pd->segid[1] == segid1) inflag = true;
19151 }
19152 }
19153 if (!inflag) {
19154 // Create a segment pbcgroup in list for ab and cd.
19155 pd = (pbcdata *) segpbcgrouptable->append(NULL);
19156 // Save the markers of ab and cd.
19157 pd->segid[0] = segid1;
19158 pd->segid[1] = segid2;
19159 // Save the handles of ab and cd.
19160 pd->ss[0] = segloop;
19161 pd->ss[1] = symseg;
19162 // Find the map from ab to cd.
19163 getsubpbcgroup(&spinsh, &ppd, &f1, &f2);
19164 pd->fmark[0] = ppd->fmark[f1];
19165 pd->fmark[1] = ppd->fmark[f2];
19166 // Set the map from ab to cd.
19167 for (i = 0; i < 4; i++) {
19168 for (j = 0; j < 4; j++) {
19169 pd->transmat[0][i][j] = ppd->transmat[f1][i][j];
19170 }
19171 }
19172 // Set the map from cd to ab.
19173 for (i = 0; i < 4; i++) {
19174 for (j = 0; j < 4; j++) {
19175 pd->transmat[1][i][j] = ppd->transmat[f2][i][j];
19176 }
19177 }
19178 }
19179 }
19180 // Go to the next subface in the ring of ab.
19181 spivotself(spinsh);
19182 } while (spinsh.sh != startsh.sh);
19183 segloop.sh = shellfacetraverse(subsegs);
19184 }
19185
19186 if (b->refine) {
19187 delete [] segsperverlist;
19188 delete [] idx2seglist;
19189 }
19190
19191 // Create the indirect segment pbcgroups.
19192 // Bug-fixed (08 Sept. 2006). The total size of 'segpbcgrouptable' may get
19193 // increased. Do not use pointers for 'pd1' and 'pd2'. The addresses may
19194 // be invaild after realloc().
19195 for (i = 0; i < segpbcgrouptable->len(); i++) {
19196 pd1 = * (pbcdata *)(* segpbcgrouptable)[i];
19197 for (f1 = 0; f1 < 2; f1++) {
19198 // Search for a group (except i) contains pd1.segid[f1].
19199 for (j = 0; j < segpbcgrouptable->len(); j++) {
19200 if (j == i) continue;
19201 pd2 = * (pbcdata *)(* segpbcgrouptable)[j];
19202 f2 = -1;
19203 if (pd1.segid[f1] == pd2.segid[0]) {
19204 f2 = 0;
19205 } else if (pd1.segid[f1] == pd2.segid[1]) {
19206 f2 = 1;
19207 }
19208 if (f2 != -1) {
19209#ifdef SELF_CHECK
19210 assert(pd1.segid[f1] == pd2.segid[f2]);
19211#endif
19212 segid1 = pd1.segid[1 - f1];
19213 segid2 = pd2.segid[1 - f2];
19214 // Search for the existence of segment pbcgroup (segid1, segid2).
19215 inflag = false;
19216 for (k = 0; k < segpbcgrouptable->len() && !inflag; k++) {
19217 pd = (pbcdata *)(* segpbcgrouptable)[k];
19218 if (pd->segid[0] == segid1) {
19219 if (pd->segid[1] == segid2) inflag = true;
19220 } else if (pd->segid[0] == segid2) {
19221 if (pd->segid[1] == segid1) inflag = true;
19222 }
19223 }
19224 if (!inflag) {
19225 pd = (pbcdata *) segpbcgrouptable->append(NULL);
19226 pd->segid[0] = pd1.segid[1 - f1];
19227 pd->segid[1] = pd2.segid[1 - f2];
19228 pd->ss[0] = pd1.ss[1 - f1];
19229 pd->ss[1] = pd2.ss[1 - f2];
19230 // Invalid the fmark[0] == fmark[1].
19231 pd->fmark[0] = pd->fmark[1] = 0;
19232 // Translate matrix pd->transmat[0] = m2 * m1, where m1 =
19233 // pd1.transmat[1 - f1], m2 = pd2.transmat[f2].
19234 for (k = 0; k < 4; k++) {
19235 for (l = 0; l < 4; l++) {
19236 pd->transmat[0][k][l] = pd2.transmat[f2][k][l];
19237 }
19238 }
19239 m4xm4(pd->transmat[0], pd1.transmat[1 - f1]);
19240 // Translate matrix pd->transmat[1] = m4 * m3, where m3 =
19241 // pd2.transmat[1 - f2], m4 = pd1.transmat[f1].
19242 for (k = 0; k < 4; k++) {
19243 for (l = 0; l < 4; l++) {
19244 pd->transmat[1][k][l] = pd1.transmat[f1][k][l];
19245 }
19246 }
19247 m4xm4(pd->transmat[1], pd2.transmat[1 - f2]);
19248 }
19249 }
19250 }
19251 }
19252 }
19253
19254 // Form a map from segment index to pbcgroup list of this segment.
19255 idx2segpglist = new int[subsegs->items + 1];
19256 for (i = 0; i < subsegs->items + 1; i++) idx2segpglist[i] = 0;
19257 // Loop through 'segpbcgrouptable', counter the number of pbcgroups of
19258 // each segment.
19259 for (i = 0; i < segpbcgrouptable->len(); i++) {
19260 pd = (pbcdata *)(* segpbcgrouptable)[i];
19261 for (j = 0; j < 2; j++) {
19262 k = pd->segid[j] - 1;
19263 idx2segpglist[k]++;
19264 }
19265 }
19266 // Calculate the total length of array 'segpglist'.
19267 j = idx2segpglist[0];
19268 idx2segpglist[0] = 0; // Array starts from 0 element.
19269 for (i = 0; i < subsegs->items; i++) {
19270 k = idx2segpglist[i + 1];
19271 idx2segpglist[i + 1] = idx2segpglist[i] + j;
19272 j = k;
19273 }
19274 // The total length is in the last unit of idx2segpglist.
19275 segpglist = new int[idx2segpglist[i]];
19276 // Loop the set of pbcgroups again, set the data into segpglist.
19277 for (i = 0; i < segpbcgrouptable->len(); i++) {
19278 pd = (pbcdata *)(* segpbcgrouptable)[i];
19279 for (j = 0; j < 2; j++) {
19280 k = pd->segid[j] - 1;
19281 segpglist[idx2segpglist[k]] = i;
19282 idx2segpglist[k]++;
19283 }
19284 }
19285 // Contents in 'idx2segpglist' are shifted, now shift them back.
19286 for (i = subsegs->items - 1; i >= 0; i--) {
19287 idx2segpglist[i + 1] = idx2segpglist[i];
19288 }
19289 idx2segpglist[0] = 0;
19290}
19291
19293// //
19294// getsegpbcsympoint() Compute the symmetric point for a segment point. //
19295// //
19296// 'newpoint' lies on 'splitseg'. This routine calculates a 'sympoint' which //
19297// locates on 'symsplitseg' and symmtric to 'newpoint'. Return the location //
19298// of sympoint wrt. symsplitseg. //
19299// //
19301
19302enum tetgenmesh::locateresult tetgenmesh::
19303getsegpbcsympoint(point newpoint, face* splitseg, point sympoint,
19304 face* symsplitseg, int groupid)
19305{
19306 pbcdata *pd;
19307 enum locateresult symloc;
19308 int segid, f1, f2, i;
19309
19310 pd = (pbcdata *)(* segpbcgrouptable)[groupid];
19311 segid = shellmark(*splitseg);
19312 if (pd->segid[0] == segid) {
19313 f1 = 0;
19314 } else {
19315#ifdef SELF_CHECK
19316 assert(pd->segid[1] == segid);
19317#endif
19318 f1 = 1;
19319 }
19320 f2 = 1 - f1;
19321
19322 // Transform newpoint from f1 -> f2.
19323 for (i = 0; i < 3; i++) {
19324 sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
19325 + pd->transmat[f1][i][1] * newpoint[1]
19326 + pd->transmat[f1][i][2] * newpoint[2]
19327 + pd->transmat[f1][i][3] * 1.0;
19328 }
19329 // Locate sympoint in f2.
19330 *symsplitseg = pd->ss[f2];
19331#ifdef SELF_CHECK
19332 assert(symsplitseg->sh != dummysh);
19333#endif
19334 // Locate sympoint in facet. Stop at subsegment.
19335 symloc = locateseg(sympoint, symsplitseg);
19336 symloc = adjustlocateseg(sympoint, symsplitseg, symloc, b->epsilon * 1e+2);
19337 return symloc;
19338}
19339
19340//
19341// End of periodic boundary condition routines
19342//
19343
19344//
19345// Begin of vertex perturbation routines
19346//
19347
19349// //
19350// randgenerator() Generate a random REAL number between (0, |range|). //
19351// //
19353
19354REAL tetgenmesh::randgenerator(REAL range)
19355{
19356 REAL worknumber, result;
19357 int expo;
19358
19359 if (range == 0.0) return 0.0;
19360
19361 expo = 0;
19362 worknumber = fabs(range);
19363 // Normalize worknumber (i.e., 1.xxxExx)
19364 if (worknumber > 10.0) {
19365 while (worknumber > 10.0) {
19366 worknumber /= 10.0;
19367 expo++;
19368 }
19369 } else if (worknumber < 1.0) {
19370 while (worknumber < 1.0) {
19371 worknumber *= 10.0;
19372 expo--;
19373 }
19374 }
19375#ifdef SELF_CHECK
19376 assert(worknumber >= 1.0 && worknumber <= 10.0);
19377#endif
19378
19379 // Enlarge worknumber 1000 times.
19380 worknumber *= 1e+3;
19381 expo -= 3;
19382 // Generate a randome number between (0, worknumber).
19383 result = (double) randomnation((int) worknumber);
19384
19385 // Scale result back into the original size.
19386 if (expo > 0) {
19387 while (expo != 0) {
19388 result *= 10.0;
19389 expo--;
19390 }
19391 } else if (expo < 0) {
19392 while (expo != 0) {
19393 result /= 10.0;
19394 expo++;
19395 }
19396 }
19397#ifdef SELF_CHECK
19398 assert((result >= 0.0) && (result <= fabs(range)));
19399#endif
19400
19401 return result;
19402}
19403
19405// //
19406// checksub4cocir() Test a subface to find co-circular pair of subfaces. //
19407// //
19408// 'eps' is a relative tolerance for testing approximately cospherical case. //
19409// Set it to zero if only exact test is desired. //
19410// //
19411// An edge(not a segment) of 'testsub' is locally degenerate if the opposite //
19412// vertex of the adjacent subface is cocircular with the vertices of testsub.//
19413// If 'once' is TRUE, operate on the edge only if the pointer 'testsub->sh' //
19414// is smaller than its neighbor (for each edge is considered only once). //
19415// //
19416// Return TRUE if find an edge of testsub is locally degenerate. //
19417// //
19419
19420bool tetgenmesh::checksub4cocir(face* testsub, REAL eps, bool once,
19421 bool enqflag)
19422{
19423 badface *cocirsub;
19424 face subloop, neighsub;
19425 face checkseg;
19426 point pa, pb, pc, pd;
19427 REAL sign;
19428 int i;
19429
19430 subloop = *testsub;
19431 subloop.shver = 0; // Keep the CCW orientation.
19432 // Get the abovepoint of the facet.
19433 abovepoint = facetabovepointarray[shellmark(subloop)];
19434 // Do we need to calculate the abovepoint?
19435 if (abovepoint == (point) NULL) {
19436 getfacetabovepoint(&subloop);
19437 }
19438 // Check the three edges of subloop.
19439 for (i = 0; i < 3; i++) {
19440 sspivot(subloop, checkseg);
19441 if (checkseg.sh == dummysh) {
19442 // It is not a segment, get the adjacent subface.
19443 spivot(subloop, neighsub);
19444 // assert(neighsub.sh != dummysh);
19445 if (!once || (once && (neighsub.sh > subloop.sh))) {
19446 pa = sorg(subloop);
19447 pb = sdest(subloop);
19448 pc = sapex(subloop);
19449 pd = sapex(neighsub);
19450 sign = insphere(pa, pb, pc, abovepoint, pd);
19451 if ((sign != 0.0) && (eps > 0.0)) {
19452 if (iscospheric(pa, pb, pc, abovepoint, pd, sign, eps)) sign = 0.0;
19453 }
19454 if (sign == 0.0) {
19455 // It's locally degenerate!
19456 if (enqflag && badsubfaces != (memorypool *) NULL) {
19457 // Save it.
19458 cocirsub = (badface *) badsubfaces->alloc();
19459 cocirsub->ss = subloop;
19460 cocirsub->forg = pa;
19461 cocirsub->fdest = pb;
19462 cocirsub->fapex = pc;
19463 cocirsub->foppo = pd;
19464 setshell2badface(cocirsub->ss, cocirsub);
19465 }
19466 if (b->verbose > 1) {
19467 printf(" Found set (%d, %d, %d, %d).\n", pointmark(pa),
19468 pointmark(pb), pointmark(pc), pointmark(pd));
19469 }
19470 return true;
19471 }
19472 }
19473 }
19474 senextself(subloop);
19475 }
19476
19477 return false;
19478}
19479
19481// //
19482// tallcocirsubs() Find all co-circular subfaces and save them in list. //
19483// //
19485
19486void tetgenmesh::tallcocirsubs(REAL eps, bool enqflag)
19487{
19488 face subloop;
19489
19490 // Loop over all subfaces.
19491 subfaces->traversalinit();
19492 subloop.sh = shellfacetraverse(subfaces);
19493 while (subloop.sh != (shellface *) NULL) {
19494 checksub4cocir(&subloop, eps, true, enqflag);
19495 subloop.sh = shellfacetraverse(subfaces);
19496 }
19497}
19498
19500// //
19501// tallencsegsfsubs() Check for encroached segs from a list of subfaces. //
19502// //
19504
19505bool tetgenmesh::tallencsegsfsubs(point testpt, list* cavsublist)
19506{
19507 face startsub, checkseg;
19508 long oldencnum;
19509 int i, j;
19510
19511 // Remember the current number of encroached segments.
19512 oldencnum = badsubsegs->items;
19513
19514 // Check segments in the list of subfaces.
19515 for (i = 0; i < cavsublist->len(); i++) {
19516 startsub = * (face *)(* cavsublist)[i];
19517 // Test all three edges of startsub.
19518 for (j = 0; j < 3; j++) {
19519 sspivot(startsub, checkseg);
19520 if (checkseg.sh != dummysh) {
19521 if (!shell2badface(checkseg)) {
19522 checkseg4encroach(&checkseg, testpt, NULL, true);
19523 }
19524 }
19525 senextself(startsub);
19526 }
19527 }
19528
19529 return (badsubsegs->items > oldencnum);
19530}
19531
19533// //
19534// collectflipedges() Collect edges of split subfaces for flip checking. //
19535// //
19536// 'inspoint' is a newly inserted segment point (inserted by insertsite()). //
19537// 'splitseg' is one of the two split subsegments. Some subfaces may be non- //
19538// Delaunay since they're still not bonded to CDT. This routine collect all //
19539// such possible subfaces in 'flipqueue'. //
19540// //
19542
19543void tetgenmesh::
19544collectflipedges(point inspoint, face* splitseg, queue* flipqueue)
19545{
19546 face startsh, spinsh, checksh;
19547 face nextseg;
19548 point pa, pb;
19549
19550 // Let the dest of splitseg be inspoint.
19551 splitseg->shver = 0;
19552 if (sdest(*splitseg) != inspoint) {
19553 sesymself(*splitseg);
19554 }
19555#ifdef SELF_CHECK
19556 assert(sdest(*splitseg) == inspoint);
19557#endif
19558 pa = sorg(*splitseg);
19559 spivot(*splitseg, startsh);
19560 spinsh = startsh;
19561 do {
19562 findedge(&spinsh, pa, inspoint);
19563 senext2(spinsh, checksh);
19564 enqueueflipedge(checksh, flipqueue);
19565 spivotself(spinsh);
19566 } while (spinsh.sh != startsh.sh);
19567
19568 // Get the next subsegment.
19569 senext(*splitseg, nextseg);
19570 spivotself(nextseg);
19571#ifdef SELF_CHECK
19572 assert(nextseg.sh != (shellface *) NULL);
19573#endif
19574
19575 // Let the org of nextseg be inspoint.
19576 nextseg.shver = 0;
19577 if (sorg(nextseg) != inspoint) {
19578 sesymself(nextseg);
19579 }
19580#ifdef SELF_CHECK
19581 assert(sorg(nextseg) == inspoint);
19582#endif
19583 pb = sdest(nextseg);
19584 spivot(nextseg, startsh);
19585 spinsh = startsh;
19586 do {
19587 findedge(&spinsh, inspoint, pb);
19588 senext(spinsh, checksh);
19589 enqueueflipedge(checksh, flipqueue);
19590 spivotself(spinsh);
19591 } while (spinsh.sh != startsh.sh);
19592}
19593
19595// //
19596// perturbrepairencsegs() Repair all encroached segments. //
19597// //
19598// All encroached segments are stored in 'badsubsegs'. Each segment will be //
19599// split by adding a perturbed point near its circumcenter. //
19600// //
19602
19603void tetgenmesh::perturbrepairencsegs(queue* flipqueue)
19604{
19605 badface *encloop;
19606 tetrahedron encodedtet;
19607 triface splittet;
19608 face splitsub, symsplitsub;
19609 face splitseg, symsplitseg;
19610 point newpoint, sympoint;
19611 point pa, pb, pc;
19612 enum insertsiteresult success;
19613 enum locateresult loc, symloc;
19614 REAL cent[3], d1, ps, rs;
19615 int i, j;
19616
19617 // Note that steinerleft == -1 if an unlimited number of Steiner points
19618 // is allowed. Loop until 'badsubsegs' is empty.
19619 badsubsegs->traversalinit();
19620 encloop = badfacetraverse(badsubsegs);
19621 while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
19622 splitseg = encloop->ss;
19623#ifdef SELF_CHECK
19624 assert(shell2badface(splitseg) == encloop);
19625#endif
19626 setshell2badface(splitseg, NULL);
19627 pa = sorg(splitseg);
19628 pb = sdest(splitseg);
19629 if ((pa == encloop->forg) && (pb == encloop->fdest)) {
19630 if (b->verbose > 1) {
19631 printf(" Get seg (%d, %d).\n", pointmark(pa), pointmark(pb));
19632 }
19633 // Create the newpoint.
19634 makepoint(&newpoint);
19635 // Get the circumcenter and radius of ab.
19636 for (i = 0; i < 3; i++) cent[i] = 0.5 * (pa[i] + pb[i]);
19637 d1 = 0.5 * distance(pa, pb);
19638 // Add a random perturbation to newpoint along the vector ab.
19639 ps = randgenerator(d1 * 1.0e-3);
19640 rs = ps / d1;
19641 // Set newpoint (be at the perturbed circumcenter of ab).
19642 for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
19643 setpointtype(newpoint, FREESEGVERTEX);
19644 // Set splitseg into the newpoint.
19645 setpoint2sh(newpoint, sencode(splitseg));
19646
19647 // Is there periodic boundary condition?
19648 if (checkpbcs) {
19649 // Insert points on other segments of incident pbcgroups.
19650 i = shellmark(splitseg) - 1;
19651 for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
19652 makepoint(&sympoint);
19653 symloc = getsegpbcsympoint(newpoint, &splitseg, sympoint,
19654 &symsplitseg, segpglist[j]);
19655#ifdef SELF_CHECK
19656 assert(symloc != OUTSIDE);
19657#endif
19658 // Note: the symsplitseg and splitseg may be identical, in case
19659 // when the the splitseg is the axis of the rotational sym.
19660 if ((symloc == ONEDGE) && (symsplitseg.sh != splitseg.sh)) {
19661 setpointtype(sympoint, FREESEGVERTEX);
19662 setpoint2sh(sympoint, sencode(symsplitseg));
19663 // Insert sympoint into DT.
19664 pc = sorg(symsplitseg);
19665 splittet.tet = dummytet;
19666 // Find a good start point to search.
19667 encodedtet = point2tet(pc);
19668 if (encodedtet != (tetrahedron) NULL) {
19669 decode(encodedtet, splittet);
19670 if (isdead(&splittet)) {
19671 splittet.tet = dummytet;
19672 }
19673 }
19674 // Locate sympoint in DT. Do exact location.
19675 success = insertsite(sympoint, &splittet, false, flipqueue);
19676#ifdef SELF_CHECK
19677 assert(success != DUPLICATEPOINT);
19678#endif
19679 if (success == OUTSIDEPOINT) {
19680 inserthullsite(sympoint, &splittet, flipqueue);
19681 }
19682 if (steinerleft > 0) steinerleft--;
19683 // Let sympoint remember splittet.
19684 setpoint2tet(sympoint, encode(splittet));
19685 // Do flip in DT.
19686 flip(flipqueue, NULL);
19687 // Insert sympoint into F.
19688 symloc = locateseg(sympoint, &symsplitseg);
19689 if (symloc == ONEDGE) {
19690 symsplitseg.shver = 0;
19691 spivot(symsplitseg, symsplitsub);
19692 // sympoint should on the edge of symsplitsub.
19693 splitsubedge(sympoint, &symsplitsub, flipqueue);
19694 } else {
19695 // insertsite() has done the whole job.
19696#ifdef SELF_CHECK
19697 assert(symloc == ONVERTEX);
19698 assert(checksubfaces);
19699#endif
19700 // Some edges may need to be flipped.
19701 collectflipedges(sympoint, &symsplitseg, flipqueue);
19702 }
19703 // Do flip in facet.
19704 flipsub(flipqueue);
19705 } else { // if (symloc == ONVERTEX) {
19706 // The symmtric point already exists. It is possible when two
19707 // pbc group are idebtical. Omit sympoint.
19708 pointdealloc(sympoint);
19709 }
19710 }
19711 }
19712
19713 // Insert newpoint into DT.
19714 splittet.tet = dummytet;
19715 // Find a good start point to search.
19716 encodedtet = point2tet(pa);
19717 if (encodedtet != (tetrahedron) NULL) {
19718 decode(encodedtet, splittet);
19719 if (isdead(&splittet)) {
19720 splittet.tet = dummytet;
19721 }
19722 }
19723 if (splittet.tet == dummytet) { // Try pb.
19724 encodedtet = point2tet(pb);
19725 if (encodedtet != (tetrahedron) NULL) {
19726 decode(encodedtet, splittet);
19727 if (isdead(&splittet)) {
19728 splittet.tet = dummytet;
19729 }
19730 }
19731 }
19732 // Locate the newpoint in DT. Do exact location.
19733 success = insertsite(newpoint, &splittet, false, flipqueue);
19734#ifdef SELF_CHECK
19735 assert(success != DUPLICATEPOINT);
19736#endif
19737 if (success == OUTSIDEPOINT) {
19738 // A convex hull edge is mssing, and the inserting point lies
19739 // (slightly) outside the convex hull due to the significant
19740 // digits lost in the calculation. Enlarge the convex hull.
19741 inserthullsite(newpoint, &splittet, flipqueue);
19742 }
19743 if (steinerleft > 0) steinerleft--;
19744 // Let newpoint remember splittet.
19745 setpoint2tet(newpoint, encode(splittet));
19746 // Do flip in DT.
19747 flip(flipqueue, NULL);
19748 // Insert newpoint into F.
19749 loc = locateseg(newpoint, &splitseg);
19750 if (loc == ONEDGE) {
19751 splitseg.shver = 0;
19752 spivot(splitseg, splitsub);
19753 // newpoint should on the edge of splitsub.
19754 splitsubedge(newpoint, &splitsub, flipqueue);
19755 } else {
19756 // insertsite() has done the whole job.
19757#ifdef SELF_CHECK
19758 assert(loc == ONVERTEX);
19759 assert(checksubfaces);
19760#endif
19761 // Some edges may need to be flipped.
19762 collectflipedges(newpoint, &splitseg, flipqueue);
19763 }
19764 // Do flip in facet.
19765 flipsub(flipqueue);
19766 }
19767 // Remove this entry from list.
19768 badfacedealloc(badsubsegs, encloop);
19769 // Get the next encroached segments.
19770 encloop = badfacetraverse(badsubsegs);
19771 }
19772}
19773
19775// //
19776// perturbrepairencsubs() Repair all encroached subfaces. //
19777// //
19778// All encroached subfaces are stored in 'badsubfaces'. Each subface will be //
19779// split by adding a perturbed point near its circumcenter. However, if the //
19780// point encroaches some segments, it will not be inserted. Instead, the //
19781// encroached segments are split. //
19782// //
19784
19785void tetgenmesh::perturbrepairencsubs(list* cavsublist, queue* flipqueue)
19786{
19787 badface *encloop, *encsubseg;
19788 tetrahedron encodedtet;
19789 triface splittet;
19790 face splitsub, symsplitsub;
19791 face checkseg, symsplitseg;
19792 point newpoint, sympoint;
19793 point pa, pb, pc, pd;
19794 enum insertsiteresult success;
19795 enum locateresult loc, symloc;
19796 REAL cent[3], d1, ps, rs;
19797 bool reject;
19798 int i;
19799
19800 // Note that steinerleft == -1 if an unlimited number of Steiner points
19801 // is allowed. Loop until the list 'badsubfaces' is empty.
19802 while ((badsubfaces->items > 0) && (steinerleft != 0)) {
19803 badsubfaces->traversalinit();
19804 encloop = badfacetraverse(badsubfaces);
19805 while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
19806 splitsub = encloop->ss;
19807#ifdef SELF_CHECK
19808 assert(shell2badface(splitsub) == encloop);
19809#endif
19810 setshell2badface(splitsub, NULL);
19811 pa = sorg(splitsub);
19812 pb = sdest(splitsub);
19813 pc = sapex(splitsub);
19814 // The subface may be not the same one when it was determined to be
19815 // encroached. If its adjacent encroached subface was split, the
19816 // consequent flips may change it into another subface.
19817 if ((pa == encloop->forg) && (pb == encloop->fdest) &&
19818 (pc == encloop->fapex)) {
19819 if (b->verbose > 1) {
19820 printf(" Get subface (%d, %d, %d).\n", pointmark(pa),
19821 pointmark(pb), pointmark(pc));
19822 }
19823 // Create the newpoint.
19824 makepoint(&newpoint);
19825 // Get the circumcenter of abc.
19826 circumsphere(pa, pb, pc, NULL, cent, &d1);
19827#ifdef SELF_CHECK
19828 assert(d1 > 0.0);
19829#endif
19830 // Add a random perturbation to newpoint along the vector a->cent.
19831 // This way, the perturbed point still lies in the plane of abc.
19832 ps = randgenerator(d1 * 1.0e-3);
19833 rs = ps / d1;
19834 // Set newpoint (be at the perturbed circumcenter of abc).
19835 for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
19836 // Get the abovepoint of the facet.
19837 abovepoint = facetabovepointarray[shellmark(splitsub)];
19838 // Do we need to calculate the abovepoint?
19839 if (abovepoint == (point) NULL) {
19840 getfacetabovepoint(&splitsub);
19841 }
19842 loc = locatesub(newpoint, &splitsub, 1, 0.0);
19843#ifdef SELF_CHECK
19844 assert(loc != ONVERTEX);
19845#endif
19846 if (loc != OUTSIDE) {
19847 // Add 'splitsub' into 'cavsublist'.
19848 cavsublist->append(&splitsub);
19849 // Collect all subfaces that encroached by newpoint.
19850 collectcavsubs(newpoint, cavsublist);
19851 // Find if there are encroached segments.
19852 reject = tallencsegsfsubs(newpoint, cavsublist);
19853 // Clear cavsublist for the next use.
19854 cavsublist->clear();
19855 } else {
19856 // newpoint lies outside. splitsub contains the boundary segment.
19857 sspivot(splitsub, checkseg);
19858#ifdef SELF_CHECK
19859 assert(checkseg.sh != dummysh);
19860#endif
19861 // Add this segment into list for splitting.
19862 if (b->verbose > 2) {
19863 printf(" Queuing boundary segment (%d, %d).\n",
19864 pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
19865 }
19866 encsubseg = (badface *) badsubsegs->alloc();
19867 encsubseg->ss = checkseg;
19868 encsubseg->forg = sorg(checkseg);
19869 encsubseg->fdest = sdest(checkseg);
19870 encsubseg->foppo = (point) NULL;
19871 setshell2badface(encsubseg->ss, encsubseg);
19872 // Reject newpoint.
19873 reject = true;
19874 }
19875
19876 if (!reject) {
19877 // newpoint is going to be inserted.
19878
19879 // Is there periodic boundary condition?
19880 if (checkpbcs) {
19881 if (shellpbcgroup(splitsub) >= 0) {
19882 // Insert a point on another facet of the pbcgroup.
19883 makepoint(&sympoint);
19884 // Note: 'abovepoint' will be changed.
19885 symloc = getsubpbcsympoint(newpoint, &splitsub, sympoint,
19886 &symsplitsub);
19887#ifdef SELF_CHECK
19888 assert(symloc != ONVERTEX);
19889#endif
19890 setpoint2pbcpt(newpoint, sympoint);
19891 setpoint2pbcpt(sympoint, newpoint);
19892 setpointtype(sympoint, FREESUBVERTEX);
19893 // setpoint2sh(sympoint, sencode(symsplitsub));
19894 // Insert sympoint into DT.
19895 pd = sorg(symsplitsub);
19896 splittet.tet = dummytet;
19897 // Find a good start point to search.
19898 encodedtet = point2tet(pd);
19899 if (encodedtet != (tetrahedron) NULL) {
19900 decode(encodedtet, splittet);
19901 if (isdead(&splittet)) {
19902 splittet.tet = dummytet;
19903 }
19904 }
19905 // Locate sympoint in DT. Do exact location.
19906 success = insertsite(sympoint, &splittet, false, flipqueue);
19907#ifdef SELF_CHECK
19908 assert(success != DUPLICATEPOINT);
19909#endif
19910 if (success == OUTSIDEPOINT) {
19911 inserthullsite(sympoint, &splittet, flipqueue);
19912 }
19913 if (steinerleft > 0) steinerleft--;
19914 // Let sympoint remember splittet.
19915 setpoint2tet(sympoint, encode(splittet));
19916 // Do flip in DT.
19917 flip(flipqueue, NULL);
19918 // Insert sympoint into F.
19919 // getabovepoint(&symsplitsub);
19920 // symloc = locatesub(sympoint, &symsplitsub, 1, 0.0);
19921 if (symloc == ONFACE) {
19922 splitsubface(sympoint, &symsplitsub, flipqueue);
19923 } else if (symloc == ONEDGE) {
19924 splitsubedge(sympoint, &symsplitsub, flipqueue);
19925 } else {
19926 // 'insertsite()' has done the whole job.
19927#ifdef SELF_CHECK
19928 assert(symloc == ONVERTEX);
19929 assert(checksubfaces);
19930#endif
19931 // Split subfaces have been flipped.
19932 flipqueue->clear();
19933 }
19934 // Do flip in facet.
19935 flipsub(flipqueue);
19936 }
19937 }
19938
19939 // Insert newpoint into DT.
19940 splittet.tet = dummytet;
19941 // Find a good start point to search.
19942 encodedtet = point2tet(pa);
19943 if (encodedtet != (tetrahedron) NULL) {
19944 decode(encodedtet, splittet);
19945 if (isdead(&splittet)) {
19946 splittet.tet = dummytet;
19947 }
19948 }
19949 if (splittet.tet == dummytet) { // Try pb.
19950 encodedtet = point2tet(pb);
19951 if (encodedtet != (tetrahedron) NULL) {
19952 decode(encodedtet, splittet);
19953 if (isdead(&splittet)) {
19954 splittet.tet = dummytet;
19955 }
19956 }
19957 }
19958 // Locate the newpoint in DT. Do exact location.
19959 success = insertsite(newpoint, &splittet, false, flipqueue);
19960#ifdef SELF_CHECK
19961 assert(success != DUPLICATEPOINT);
19962#endif
19963 if (success == OUTSIDEPOINT) {
19964 inserthullsite(newpoint, &splittet, flipqueue);
19965 }
19966 if (steinerleft > 0) steinerleft--;
19967 // Let newpoint remember splittet.
19968 setpoint2tet(newpoint, encode(splittet));
19969 // Do flip in DT.
19970 flip(flipqueue, NULL);
19971 // Insert newpoint into F.
19972 // if (checkpbcs) {
19973 // 'abovepoint' has been changed.
19974 // getabovepoint(&splitsub);
19975 // loc = locatesub(newpoint, &splitsub, 1, 0.0);
19976 // }
19977 if (loc == ONFACE) {
19978 // Insert the newpoint in facet.
19979 splitsubface(newpoint, &splitsub, flipqueue);
19980 } else if (loc == ONEDGE) {
19981 // Insert the newpoint in facet.
19982 splitsubedge(newpoint, &splitsub, flipqueue);
19983 } else {
19984 // 'insertsite()' has done the whole job.
19985#ifdef SELF_CHECK
19986 assert(loc == ONVERTEX);
19987 assert(checksubfaces);
19988#endif
19989 // Split subfaces have been flipped.
19990 flipqueue->clear();
19991 }
19992 // Set the type of the newpoint.
19993 setpointtype(newpoint, FREESUBVERTEX);
19994 // Set splitsub into the newpoint.
19995 // setpoint2sh(newpoint, sencode(splitsub));
19996 // Do flip in the facet.
19997 flipsub(flipqueue);
19998
19999 // Remove this entry from list.
20000 badfacedealloc(badsubfaces, encloop);
20001 } else {
20002 // newpoint is rejected. Remove it from points.
20003 pointdealloc(newpoint);
20004 // Repair all encroached segments.
20005 perturbrepairencsegs(flipqueue);
20006 // Do not remove 'encloop'. Later it will be tested again.
20007 setshell2badface(encloop->ss, encloop);
20008 }
20009 } else {
20010 // This subface has been changed. Remove this entry from list.
20011 badfacedealloc(badsubfaces, encloop);
20012 // It may be co-circular with its neighbors.
20013 // checksub4cocir(&splitsub, eps, false, true);
20014 }
20015 // Get the next encroached subfaces.
20016 encloop = badfacetraverse(badsubfaces);
20017 }
20018 }
20019}
20020
20022// //
20023// incrperturbvertices() Remove the local degeneracies in DT. //
20024// //
20025// A local degeneracy of a DT D is a set of 5 or more vertices which share a //
20026// common sphere S and no other vertex of D in S. D is not unique if it has //
20027// local degeneracies. This routine removes the local degeneracies from D by //
20028// inserting break points (as described in reference [2]). //
20029// //
20030// 'eps' is a user-provided error tolerance. It is used to detect whether or //
20031// not five points are approximate cospherical (evaluated in iscospheric()). //
20032// Set it to 0.0 to disable it, i.e., only test pure degenerate point set. //
20033// //
20035
20036void tetgenmesh::incrperturbvertices(REAL eps)
20037{
20038 queue *flipqueue;
20039 list *cavsublist;
20040 long vertcount;
20041
20042 if (!b->quiet) {
20043 printf("Perturbing vertices.\n");
20044 }
20045
20046 vertcount = points->items;
20047 // Create a map from points to tets for fastening search.
20048 // makepoint2tetmap(); // This has been done in meshsurface().
20049
20050 // Initialize working queues, lists.
20051 flipqueue = new queue(sizeof(badface));
20052 cavsublist = new list(sizeof(face), NULL, 256);
20053 // Initialize the pool of encroached subfaces and subsegments.
20054 badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
20055 badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
20056 // Find all pairs of co-circular subfaces.
20057 tallcocirsubs(eps, true);
20058 if (b->verbose && badsubfaces->items > 0) {
20059 printf(" Removing degenerate subfaces.\n");
20060 }
20061 perturbrepairencsubs(cavsublist, flipqueue);
20062
20063 if (b->verbose > 0) {
20064 printf(" %ld break points.\n", points->items - vertcount);
20065 }
20066
20067 delete cavsublist;
20068 delete flipqueue;
20069 delete badsubfaces;
20070 delete badsubsegs;
20071 badsubsegs = (memorypool *) NULL;
20072 badsubfaces = (memorypool *) NULL;
20073}
20074
20075//
20076// End of vertex perturbation routines
20077//
20078
20079//
20080// Begin of segment recovery routines
20081//
20082
20084// //
20085// markacutevertices() Mark acute vertices. //
20086// //
20087// A vertex v is called acute if there are two segments sharing at v forming //
20088// an acute angle (i.e. smaller than 90 degree). //
20089// //
20090// This routine finds all acute vertices in the PLC and marks them as point- //
20091// type ACUTEVERTEX. The other vertices of segments which are non-acute will //
20092// be marked as NACUTEVERTEX. Vertices which are not endpoints of segments //
20093// (such as DUPLICATEDVERTEX, UNUSEDVERTEX, etc) are not infected. //
20094// //
20095// NOTE: This routine should be called before Steiner points are introduced. //
20096// That is, no point has type like FREESEGVERTEX, etc. //
20097// //
20099
20100void tetgenmesh::markacutevertices(REAL acuteangle)
20101{
20102 shellface **segsperverlist;
20103 face segloop, nextseg;
20104 point pointloop, edest, eapex;
20105 REAL cosbound, anglearc;
20106 REAL v1[3], v2[3], L, D;
20107 bool isacute;
20108 int *idx2seglist;
20109 int acutecount;
20110 int idx, i, j, k;
20111
20112 if (b->verbose > 0) {
20113 printf(" Marking acute vertices.\n");
20114 }
20115
20116 anglearc = acuteangle * PI / 180.0;
20117 cosbound = cos(anglearc);
20118 acutecount = 0;
20119 // Constructing a map from vertex to segments.
20120 makesegmentmap(idx2seglist, segsperverlist);
20121
20122 // Loop over the set of vertices.
20123 points->traversalinit();
20124 pointloop = pointtraverse();
20125 while (pointloop != (point) NULL) {
20126 idx = pointmark(pointloop) - in->firstnumber;
20127 // Only do test if p is an endpoint of some segments.
20128 if (idx2seglist[idx + 1] > idx2seglist[idx]) {
20129 // Init p to be non-acute.
20130 setpointtype(pointloop, NACUTEVERTEX);
20131 isacute = false;
20132 // Loop through all segments sharing at p.
20133 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) {
20134 segloop.sh = segsperverlist[i];
20135 // segloop.shver = 0;
20136 if (sorg(segloop) != pointloop) sesymself(segloop);
20137 edest = sdest(segloop);
20138 for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) {
20139 nextseg.sh = segsperverlist[j];
20140 // nextseg.shver = 0;
20141 if (sorg(nextseg) != pointloop) sesymself(nextseg);
20142 eapex = sdest(nextseg);
20143 // Check the angle formed by segs (p, edest) and (p, eapex).
20144 for (k = 0; k < 3; k++) {
20145 v1[k] = edest[k] - pointloop[k];
20146 v2[k] = eapex[k] - pointloop[k];
20147 }
20148 L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
20149 for (k = 0; k < 3; k++) v1[k] /= L;
20150 L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
20151 for (k = 0; k < 3; k++) v2[k] /= L;
20152 D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
20153 // Is D acute?
20154 isacute = (D >= cosbound);
20155 }
20156 }
20157 if (isacute) {
20158 // Mark p to be acute.
20159 setpointtype(pointloop, ACUTEVERTEX);
20160 acutecount++;
20161 }
20162 }
20163 pointloop = pointtraverse();
20164 }
20165
20166 delete [] idx2seglist;
20167 delete [] segsperverlist;
20168
20169 if ((b->verbose > 0) && (acutecount > 0)) {
20170 printf(" %d acute vertices.\n", acutecount);
20171 }
20172}
20173
20175// //
20176// finddirection() Find the first tetrahedron on the path from one point //
20177// to another. //
20178// //
20179// Find the tetrahedron that intersects a line segment L (from the origin of //
20180// 'searchtet' to the point 'tend'), and returns the result in 'searchtet'. //
20181// The origin of 'searchtet' does not change, even though the tetrahedron //
20182// returned may differ from the one passed in. This routine is used to find //
20183// the direction to move in to get from one point to another. //
20184// //
20185// The return value notes the location of the line segment L with respect to //
20186// 'searchtet': //
20187// - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment //
20188// from the origin to the destination of 'searchtet'. //
20189// - Returns LEFTCOLLINEAR indicates L is collinear with the line segment //
20190// from the origin to the apex of 'searchtet'. //
20191// - Returns TOPCOLLINEAR indicates L is collinear with the line segment //
20192// from the origin to the opposite of 'searchtet'. //
20193// - Returns ACROSSEDGE indicates L intersects with the line segment from //
20194// the destination to the apex of 'searchtet'. //
20195// - Returns ACROSSFACE indicates L intersects with the face opposite to //
20196// the origin of 'searchtet'. //
20197// - Returns BELOWHULL indicates L crosses outside the mesh domain. This //
20198// can only happen when the domain is non-convex. //
20199// //
20200// NOTE: This routine only works correctly when the mesh is exactly Delaunay.//
20201// //
20202// If 'maxtetnumber' > 0, stop the searching process if the number of passed //
20203// tets is larger than it. Return BELOWHULL. //
20204// //
20206
20207enum tetgenmesh::finddirectionresult tetgenmesh::
20208finddirection(triface *searchtet, point tend, long maxtetnumber)
20209{
20210 triface neightet;
20211 point tstart, tdest, tapex, toppo;
20212 REAL ori1, ori2, ori3;
20213 long tetnumber;
20214
20215 tstart = org(*searchtet);
20216#ifdef SELF_CHECK
20217 assert(tstart != tend);
20218#endif
20219 adjustedgering(*searchtet, CCW);
20220 if (tstart != org(*searchtet)) {
20221 enextself(*searchtet); // For keeping the same origin.
20222 }
20223 tdest = dest(*searchtet);
20224 if (tdest == tend) {
20225 return RIGHTCOLLINEAR;
20226 }
20227 tapex = apex(*searchtet);
20228 if (tapex == tend) {
20229 return LEFTCOLLINEAR;
20230 }
20231
20232 ori1 = orient3d(tstart, tdest, tapex, tend);
20233 if (ori1 > 0.0) {
20234 // 'tend' is below the face, get the neighbor of this side.
20235 sym(*searchtet, neightet);
20236 if (neightet.tet != dummytet) {
20237 findorg(&neightet, tstart);
20238 adjustedgering(neightet, CCW);
20239 if (org(neightet) != tstart) {
20240 enextself(neightet); // keep the same origin.
20241 }
20242 // Set the changed configuratiuon.
20243 *searchtet = neightet;
20244 ori1 = -1.0;
20245 tdest = dest(*searchtet);
20246 tapex = apex(*searchtet);
20247 } else {
20248 // A hull face. Only possible for a nonconvex mesh.
20249#ifdef SELF_CHECK
20250 assert(nonconvex);
20251#endif
20252 return BELOWHULL;
20253 }
20254 }
20255
20256 // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until
20257 // find a tetrahedron contains 'tend' or is crossed by the line segment
20258 // from 'tstart' to 'tend'.
20259 tetnumber = 0l;
20260 while ((maxtetnumber > 0) && (tetnumber <= maxtetnumber)) {
20261 tetnumber++;
20262 toppo = oppo(*searchtet);
20263 if (toppo == tend) {
20264 return TOPCOLLINEAR;
20265 }
20266 ori2 = orient3d(tstart, toppo, tdest, tend);
20267 if (ori2 > 0.0) {
20268 // 'tend' is below the face, get the neighbor at this side.
20269 fnext(*searchtet, neightet);
20270 symself(neightet);
20271 if (neightet.tet != dummytet) {
20272 findorg(&neightet, tstart);
20273 adjustedgering(neightet, CCW);
20274 if (org(neightet) != tstart) {
20275 enextself(neightet); // keep the same origin.
20276 }
20277 // Set the changed configuration.
20278 *searchtet = neightet;
20279 ori1 = -1.0;
20280 tdest = dest(*searchtet);
20281 tapex = apex(*searchtet);
20282 // Continue the search from the changed 'searchtet'.
20283 continue;
20284 } else {
20285 // A hull face. Only possible for a nonconvex mesh.
20286#ifdef SELF_CHECK
20287 assert(nonconvex);
20288#endif
20289 return BELOWHULL;
20290 }
20291 }
20292 ori3 = orient3d(tapex, toppo, tstart, tend);
20293 if (ori3 > 0.0) {
20294 // 'tend' is below the face, get the neighbor at this side.
20295 enext2fnext(*searchtet, neightet);
20296 symself(neightet);
20297 if (neightet.tet != dummytet) {
20298 findorg(&neightet, tstart);
20299 adjustedgering(neightet, CCW);
20300 if (org(neightet) != tstart) {
20301 enextself(neightet); // keep the same origin.
20302 }
20303 // Set the changed configuration.
20304 *searchtet = neightet;
20305 ori1 = -1.0;
20306 tdest = dest(*searchtet);
20307 tapex = apex(*searchtet);
20308 // Continue the search from the changed 'searchtet'.
20309 continue;
20310 } else {
20311 // A hull face. Only possible for a nonconvex mesh.
20312#ifdef SELF_CHECK
20313 assert(nonconvex);
20314#endif
20315 return BELOWHULL;
20316 }
20317 }
20318 // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0;
20319 if (ori1 < 0.0) {
20320 // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR.
20321 if (ori2 < 0.0) {
20322 if (ori3 < 0.0) {
20323 return ACROSSFACE;
20324 } else { // ori3 == 0.0;
20325 // Cross edge (apex, oppo)
20326 enext2fnextself(*searchtet);
20327 esymself(*searchtet); // org(*searchtet) == tstart;
20328 return ACROSSEDGE;
20329 }
20330 } else { // ori2 == 0.0;
20331 if (ori3 < 0.0) {
20332 // Cross edge (dest, oppo)
20333 fnextself(*searchtet);
20334 esymself(*searchtet);
20335 enextself(*searchtet); // org(*searchtet) == tstart;
20336 return ACROSSEDGE;
20337 } else { // ori3 == 0.0;
20338 // Collinear with edge (org, oppo)
20339 return TOPCOLLINEAR;
20340 }
20341 }
20342 } else { // ori1 == 0.0;
20343 // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE.
20344 if (ori2 < 0.0) {
20345 if (ori3 < 0.0) {
20346 // Cross edge (tdest, tapex)
20347 return ACROSSEDGE;
20348 } else { // ori3 == 0.0
20349 // Collinear with edge (torg, tapex)
20350 return LEFTCOLLINEAR;
20351 }
20352 } else { // ori2 == 0.0;
20353#ifdef SELF_CHECK
20354 assert(ori3 != 0.0);
20355#endif
20356 // Collinear with edge (torg, tdest)
20357 return RIGHTCOLLINEAR;
20358 }
20359 }
20360 }
20361 // Loop breakout. It may happen when the mesh is non-Delaunay.
20362 return BELOWHULL;
20363}
20364
20366// //
20367// getsearchtet() Find a tetrahedron whose origin is either 'p1' or 'p2'. //
20368// //
20369// On return, the origin of 'searchtet' is either 'p1' or 'p2', and 'tend' //
20370// returns the other point. 'searchtet' serves as the starting tetrahedron //
20371// for searching of the line segment from 'p1' to 'p2' or vice versa. //
20372// //
20374
20375void tetgenmesh::getsearchtet(point p1, point p2, triface* searchtet,
20376 point* tend)
20377{
20378 tetrahedron encodedtet1, encodedtet2;
20379
20380 // Is there a valid handle provided by the user?
20381 if ((searchtet->tet != (tetrahedron *) NULL) && !isdead(searchtet)) {
20382 // Find which endpoint the handle holds.
20383 if (findorg(searchtet, p1)) {
20384 *tend = p2;
20385 return;
20386 } else {
20387 if (findorg(searchtet, p2)) {
20388 *tend = p1;
20389 return;
20390 }
20391 }
20392 }
20393 // If not, search the tet handle stored in 'p1' or 'p2'.
20394 *tend = (point) NULL;
20395 encodedtet1 = point2tet(p1);
20396 encodedtet2 = point2tet(p2);
20397 if (encodedtet1 != (tetrahedron) NULL) {
20398 decode(encodedtet1, *searchtet);
20399 // Be careful, here 'searchtet' may be dead.
20400 if (findorg(searchtet, p1)) {
20401 *tend = p2;
20402 }
20403 } else if (encodedtet2 != (tetrahedron) NULL) {
20404 decode(encodedtet2, *searchtet);
20405 // Be careful, here 'searchtet' may be dead.
20406 if (findorg(searchtet, p2)) {
20407 *tend = p1;
20408 }
20409 }
20410 // If still not, perform a full point location. The starting tet is
20411 // chosen as follows: Use the handle stored in 'p1' or 'p2' if it is
20412 // alive; otherwise, start from a tet on the convex hull.
20413 if (*tend == (point) NULL) {
20414 if (encodedtet1 != (tetrahedron) NULL) {
20415 decode(encodedtet1, *searchtet);
20416 // Be careful, here 'searchtet' may be dead.
20417 }
20418 if (isdead(searchtet)) {
20419 if (encodedtet2 != (tetrahedron) NULL) {
20420 decode(encodedtet2, *searchtet);
20421 // Be careful, here 'searchtet' may be dead.
20422 }
20423 if (isdead(searchtet)) {
20424 searchtet->tet = dummytet;
20425 searchtet->loc = 0;
20426 symself(*searchtet);
20427 }
20428#ifdef SELF_CHECK
20429 assert(!isdead(searchtet));
20430#endif
20431 }
20432 if (locate(p1, searchtet) != ONVERTEX) {
20433 printf("Internal error in getsearchtet(): Failed to locate point\n");
20434 internalerror();
20435 }
20436 // Remember this handle in 'p1' to enhance the search speed.
20437 setpoint2tet(p1, encode(*searchtet));
20438 *tend = p2;
20439 }
20440}
20441
20443// //
20444// isedgeencroached() Check whether or not a subsegment is encroached. //
20445// //
20446// A segment with endpoints 'p1' and 'p2' is encroached by the point 'testpt'//
20447// if it lies in the diametral sphere of this segment. The degenerate case //
20448// that 'testpt' lies on the sphere is treated as encroached if 'degflag' is //
20449// set to be TRUE. //
20450// //
20452
20453bool tetgenmesh::isedgeencroached(point p1, point p2, point testpt,
20454 bool degflag)
20455{
20456 REAL dotproduct;
20457
20458 // Check if the segment is facing an angle larger than 90 degree?
20459 dotproduct = (p1[0] - testpt[0]) * (p2[0] - testpt[0])
20460 + (p1[1] - testpt[1]) * (p2[1] - testpt[1])
20461 + (p1[2] - testpt[2]) * (p2[2] - testpt[2]);
20462 if (dotproduct < 0) {
20463 return true;
20464 } else if (dotproduct == 0 && degflag) {
20465 return true;
20466 } else {
20467 return false;
20468 }
20469}
20470
20472// //
20473// scoutrefpoint() Search the reference point of a missing segment. //
20474// //
20475// A segment S is missing in current Delaunay tetrahedralization DT and will //
20476// be split by inserting a point V in it. The two end points of S are the //
20477// origin of 'searchtet' and 'tend'. And we know that S is crossing the face //
20478// of 'searchtet' opposite to its origin (may be intersecting with the edge //
20479// from the destination to the apex of the 'searchtet'). The search of P is //
20480// completed by walking through all faces of DT across by S. //
20481// //
20482// Warning: This routine is correct when the tetrahedralization is Delaunay //
20483// and convex. Otherwise, the search loop may not terminate. //
20484// //
20486
20487tetgenmesh::point tetgenmesh::scoutrefpoint(triface* searchtet, point tend)
20488{
20489 triface checkface;
20490 point tstart, testpt, refpoint;
20491 REAL cent[3], radius, largest;
20492 REAL ahead;
20493 bool ncollinear;
20494 int sides;
20495
20496 if (b->verbose > 2) {
20497 printf(" Scout the reference point of segment (%d, %d).\n",
20498 pointmark(org(*searchtet)), pointmark(tend));
20499 }
20500
20501 tstart = org(*searchtet);
20502 refpoint = (point) NULL;
20503 largest = 0; // avoid compile warning.
20504
20505 // Check the three vertices of the crossing face.
20506 testpt = apex(*searchtet);
20507 if (isedgeencroached(tstart, tend, testpt, true)) {
20508 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20509#ifdef SELF_CHECK
20510 assert(ncollinear);
20511#endif
20512 refpoint = testpt;
20513 largest = radius;
20514 }
20515 testpt = dest(*searchtet);
20516 if (isedgeencroached(tstart, tend, testpt, true)) {
20517 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20518#ifdef SELF_CHECK
20519 assert(ncollinear);
20520#endif
20521 if (refpoint == (point) NULL) {
20522 refpoint = testpt;
20523 largest = radius;
20524 } else {
20525 if (radius > largest) {
20526 refpoint = testpt;
20527 largest = radius;
20528 }
20529 }
20530 }
20531 testpt = oppo(*searchtet);
20532 if (isedgeencroached(tstart, tend, testpt, true)) {
20533 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20534#ifdef SELF_CHECK
20535 assert(ncollinear);
20536#endif
20537 if (refpoint == (point) NULL) {
20538 refpoint = testpt;
20539 largest = radius;
20540 } else {
20541 if (radius > largest) {
20542 refpoint = testpt;
20543 largest = radius;
20544 }
20545 }
20546 }
20547 // Check the opposite vertex of the neighboring tet in case the segment
20548 // crosses the edge (leftpoint, rightpoint) of the crossing face.
20549 sym(*searchtet, checkface);
20550 if (checkface.tet != dummytet) {
20551 testpt = oppo(checkface);
20552 if (isedgeencroached(tstart, tend, testpt, true)) {
20553 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20554#ifdef SELF_CHECK
20555 assert(ncollinear);
20556#endif
20557 if (refpoint == (point) NULL) {
20558 refpoint = testpt;
20559 largest = radius;
20560 } else {
20561 if (radius > largest) {
20562 refpoint = testpt;
20563 largest = radius;
20564 }
20565 }
20566 }
20567 }
20568
20569 // Walk through all crossing faces.
20570 enextfnext(*searchtet, checkface);
20571 sym(checkface, *searchtet);
20572 while (true) {
20573 // Check if we are reaching the boundary of the triangulation.
20574#ifdef SELF_CHECK
20575 assert(searchtet->tet != dummytet);
20576#endif
20577 // Search for an adjoining tetrahedron we can walk through.
20578 searchtet->ver = 0;
20579 // 'testpt' is the shared vertex for the following orientation tests.
20580 testpt = oppo(*searchtet);
20581 if (testpt == tend) {
20582 // The searching is finished.
20583 break;
20584 } else {
20585 // 'testpt' may encroach the segment.
20586 if ((testpt != tstart) && (testpt != refpoint)) {
20587 if (isedgeencroached(tstart, tend, testpt, true)) {
20588 ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20589 if (!ncollinear) {
20590 // 'testpt' is collinear with the segment. It may happen when a
20591 // set of collinear and continuous segments is defined by two
20592 // extreme endpoints. In this case, we should choose 'testpt'
20593 // as the splitting point immediately. No new point should be
20594 // created.
20595 refpoint = testpt;
20596 break;
20597 }
20598 if (refpoint == (point) NULL) {
20599 refpoint = testpt;
20600 largest = radius;
20601 } else {
20602 if (radius > largest) {
20603 refpoint = testpt;
20604 largest = radius;
20605 }
20606 }
20607 }
20608 }
20609 }
20610 // Check three side-faces of 'searchtet' to find the one through
20611 // which we can walk next.
20612 for (sides = 0; sides < 3; sides++) {
20613 fnext(*searchtet, checkface);
20614 ahead = orient3d(org(checkface), dest(checkface), testpt, tend);
20615 if (ahead < 0.0) {
20616 // We can walk through this face and continue the searching.
20617 sym(checkface, *searchtet);
20618 break;
20619 }
20620 enextself(*searchtet);
20621 }
20622#ifdef SELF_CHECK
20623 assert (sides < 3);
20624#endif
20625 }
20626
20627#ifdef SELF_CHECK
20628 assert(refpoint != (point) NULL);
20629#endif
20630 return refpoint;
20631}
20632
20634// //
20635// getsegmentorigin() Return the origin of the (unsplit) segment. //
20636// //
20637// After a segment (or a subsegment) is split. Two resulting subsegments are //
20638// connecting each other through the pointers saved in their data fields. //
20639// With these pointers, the whole (unsplit) segment can be found. 'splitseg' //
20640// may be a split subsegment. Returns the origin of the unsplit segment. //
20641// //
20643
20644tetgenmesh::point tetgenmesh::getsegmentorigin(face* splitseg)
20645{
20646 face workseg;
20647 point farorg;
20648
20649 farorg = sorg(*splitseg);
20650 if ((pointtype(farorg) != ACUTEVERTEX) &&
20651 (pointtype(farorg) != NACUTEVERTEX)) {
20652 workseg = *splitseg;
20653 do {
20654 senext2self(workseg);
20655 spivotself(workseg);
20656 if (workseg.sh != dummysh) {
20657 workseg.shver = 0; // It's a subsegment.
20658 if (sdest(workseg) != farorg) {
20659 sesymself(workseg);
20660#ifdef SELF_CHECK
20661 assert(sdest(workseg) == farorg);
20662#endif
20663 }
20664 farorg = sorg(workseg);
20665 if ((pointtype(farorg) == ACUTEVERTEX) ||
20666 (pointtype(farorg) == NACUTEVERTEX)) break;
20667 }
20668 } while (workseg.sh != dummysh);
20669 }
20670#ifdef SELF_CHECK
20671 assert((pointtype(farorg) == ACUTEVERTEX) ||
20672 (pointtype(farorg) == NACUTEVERTEX));
20673#endif
20674 return farorg;
20675}
20676
20678// //
20679// getsplitpoint() Get a point for splitting a segment. //
20680// //
20681// 'splitseg' is the segment will be split. 'refpoint' is a reference point //
20682// for splitting this segment. Moreover, it should not collinear with the //
20683// splitting segment. (The collinear case will be detected by iscollinear() //
20684// before entering this routine.) The calculation of the splitting point is //
20685// governed by three rules introduced in my paper. //
20686// //
20687// After the position is calculated, a new point is created at this location.//
20688// The new point has one of the two pointtypes: FREESEGVERTEX indicating it //
20689// is an inserting vertex on segment, and NACUTEVERTEX indicating it is an //
20690// endpoint of a segment which original has type-3 now becomes type-2. //
20691// //
20693
20694tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
20695{
20696 point splitpoint;
20697 point farorg, fardest;
20698 point ei, ej, ek, c;
20699 REAL v[3], r, split;
20700 REAL d1, d2, ps, rs;
20701 bool acuteorg, acutedest;
20702 int stype, rule;
20703 int i;
20704
20705 // First determine the type of the segment (type-1, type-2, or type-3).
20706 farorg = getsegmentorigin(splitseg);
20707 acuteorg = (pointtype(farorg) == ACUTEVERTEX);
20708 sesymself(*splitseg);
20709 fardest = getsegmentorigin(splitseg);
20710 acutedest = (pointtype(fardest) == ACUTEVERTEX);
20711 sesymself(*splitseg);
20712
20713 ek = (point) NULL; // avoid a compilation warning.
20714
20715 if (acuteorg) {
20716 if (acutedest) {
20717 stype = 3;
20718 } else {
20719 stype = 2;
20720 ek = farorg;
20721 }
20722 } else {
20723 if (acutedest) {
20724 stype = 2;
20725 // Adjust splitseg, so that its origin is acute.
20726 sesymself(*splitseg);
20727 ek = fardest;
20728 } else {
20729 stype = 1;
20730 }
20731 }
20732 ei = sorg(*splitseg);
20733 ej = sdest(*splitseg);
20734
20735 if (b->verbose > 1) {
20736 printf(" Splitting segment (%d, %d) type-%d with refpoint %d.\n",
20737 pointmark(ei), pointmark(ej), stype, pointmark(refpoint));
20738 }
20739
20740 if (stype == 1 || stype == 3) {
20741 // Use rule-1.
20742 REAL eij, eip, ejp;
20743 eij = distance(ei, ej);
20744 eip = distance(ei, refpoint);
20745 ejp = distance(ej, refpoint);
20746 if ((eip < ejp) && (eip < 0.5 * eij)) {
20747 c = ei;
20748 r = eip;
20749 } else if ((eip > ejp) && (ejp < 0.5 * eij)) {
20750 c = ej;
20751 ej = ei;
20752 r = ejp;
20753 } else {
20754 c = ei;
20755 r = 0.5 * eij;
20756 }
20757 split = r / eij;
20758 for (i = 0; i < 3; i++) {
20759 v[i] = c[i] + split * (ej[i] - c[i]);
20760 }
20761 rule = 1;
20762 } else {
20763 // Use rule-2 or rule-3.
20764 REAL eki, ekj, ekp, evj, evp, eiv;
20765 c = ek;
20766 eki = distance(ek, ei); // eki may equal zero.
20767 ekj = distance(ek, ej);
20768 ekp = distance(ek, refpoint);
20769 // Calculate v (the going to split position between ei, ej).
20770 r = ekp;
20771 // Check the validity of the position.
20772 if (!(eki < r && r < ekj)) {
20773 printf("Error: Invalid PLC.\n");
20774 printf(" Hint: Use -d switch to check it.\n");
20775 terminatetetgen(1);
20776 }
20777 split = r / ekj;
20778 for (i = 0; i < 3; i++) {
20779 v[i] = c[i] + split * (ej[i] - c[i]);
20780 }
20781 rule = 2;
20782 evj = ekj - r; // distance(v, ej);
20783 evp = distance(v, refpoint);
20784 if (evj < evp) {
20785 // v is rejected, use rule-3.
20786 eiv = distance(ei, v);
20787 if (evp <= 0.5 * eiv) {
20788 r = eki + eiv - evp;
20789 } else {
20790 r = eki + 0.5 * eiv;
20791 }
20792#ifdef SELF_CHECK
20793 assert(eki < r && r < ekj);
20794#endif
20795 split = r / ekj;
20796 for (i = 0; i < 3; i++) {
20797 v[i] = c[i] + split * (ej[i] - c[i]);
20798 }
20799 if (b->verbose > 1) {
20800 printf(" Using rule-3.\n");
20801 }
20802 rule = 3;
20803 }
20804 }
20805
20806 // Accumulate the corresponding counters.
20807 if (rule == 1) r1count++;
20808 else if (rule == 2) r2count++;
20809 else if (rule == 3) r3count++;
20810
20811 if (b->verbose > 1) {
20812 if (stype == 2) {
20813 printf(" Split = %.12g.\n", distance(ei, v) / distance(ei, ej));
20814 } else {
20815 printf(" Split = %.12g.\n", distance(c, v) / distance(c, ej));
20816 }
20817 }
20818
20819 // Create the newpoint.
20820 makepoint(&splitpoint);
20821 // Add a random perturbation on splitpoint.
20822 d1 = distance(c, v);
20823 d2 = distance(refpoint, v);
20824 if (stype == 1 || stype == 3) {
20825 ps = randgenerator(d1 * 1.0e-3);
20826 } else {
20827 // For type-2 segment, add a smaller perturbation.
20828 // ps = randgenerator(d1 * 1.0e-5);
20829 // REAL d2 = distance(refpoint, v);
20830 ps = randgenerator(d2 * 1.0e-5);
20831 }
20832 rs = ps / d1;
20833 // Perturb splitpoint away from c.
20834 for (i = 0; i < 3; i++) {
20835 splitpoint[i] = c[i] + (1.0 + rs) * (v[i] - c[i]);
20836 }
20837 // for (i = 0; i < in->numberofpointattributes; i++) {
20838 // splitpoint[i + 3] = c[i + 3] + (split + rs) * (ej[i + 3] - c[i + 3]);
20839 // }
20840 if (stype == 3) {
20841 // Change a type-3 segment into two type-2 segments.
20842 setpointtype(splitpoint, NACUTEVERTEX);
20843 } else {
20844 // Set it's type be FREESEGVERTEX.
20845 setpointtype(splitpoint, FREESEGVERTEX);
20846 }
20847 setpoint2sh(splitpoint, sencode(*splitseg));
20848
20849 return splitpoint;
20850}
20851
20853// //
20854// insertsegment() Insert segment into DT. Queue it if it does not exist. //
20855// //
20857
20858bool tetgenmesh::insertsegment(face *insseg, list *misseglist)
20859{
20860 badface *misseg;
20861 triface searchtet, spintet;
20862 point tend, checkpoint;
20863 point p1, p2;
20864 enum finddirectionresult collinear;
20865 int hitbdry;
20866
20867 // Search segment ab in DT.
20868 p1 = (point) insseg->sh[3];
20869 p2 = (point) insseg->sh[4];
20870 getsearchtet(p1, p2, &searchtet, &tend);
20871 collinear = finddirection(&searchtet, tend, tetrahedrons->items);
20872 if (collinear == LEFTCOLLINEAR) {
20873 checkpoint = apex(searchtet);
20874 enext2self(searchtet);
20875 esymself(searchtet);
20876 } else if (collinear == RIGHTCOLLINEAR) {
20877 checkpoint = dest(searchtet);
20878 } else if (collinear == TOPCOLLINEAR) {
20879 checkpoint = oppo(searchtet);
20880 fnextself(searchtet);
20881 enext2self(searchtet);
20882 esymself(searchtet);
20883 } else {
20884 // assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
20885 checkpoint = (point) NULL;
20886 }
20887 if (checkpoint == tend) {
20888 // Segment exist. Bond it to all tets containing it.
20889 hitbdry = 0;
20890 adjustedgering(searchtet, CCW);
20891 fnextself(searchtet);
20892 spintet = searchtet;
20893 do {
20894 tssbond1(spintet, *insseg);
20895 if (!fnextself(spintet)) {
20896 hitbdry++;
20897 if (hitbdry < 2) {
20898 esym(searchtet, spintet);
20899 if (!fnextself(spintet)) {
20900 hitbdry++;
20901 }
20902 }
20903 }
20904 } while ((apex(spintet) != apex(searchtet)) && (hitbdry < 2));
20905 return true;
20906 } else {
20907 // Segment is missing.
20908 if (misseglist != (list *) NULL) {
20909 if (b->verbose > 2) {
20910 printf(" Queuing missing segment (%d, %d).\n", pointmark(p1),
20911 pointmark(p2));
20912 }
20913 misseg = (badface *) misseglist->append(NULL);
20914 misseg->ss = *insseg;
20915 misseg->forg = p1;
20916 misseg->fdest = p2;
20917 misseg->foppo = (point) NULL; // Not used.
20918 // setshell2badface(misseg->ss, misseg);
20919 }
20920 return false;
20921 }
20922}
20923
20925// //
20926// tallmissegs() Find and queue all missing segments in DT. //
20927// //
20929
20930void tetgenmesh::tallmissegs(list *misseglist)
20931{
20932 face segloop;
20933
20934 if (b->verbose) {
20935 printf(" Queuing missing segments.\n");
20936 }
20937
20938 subsegs->traversalinit();
20939 segloop.sh = shellfacetraverse(subsegs);
20940 while (segloop.sh != (shellface *) NULL) {
20941 insertsegment(&segloop, misseglist);
20942 segloop.sh = shellfacetraverse(subsegs);
20943 }
20944}
20945
20947// //
20948// delaunizesegments() Split segments repeatedly until they appear in a //
20949// Delaunay tetrahedralization. //
20950// //
20951// Given a PLC X, which has a set V of vertices and a set of segments. Start //
20952// from a Delaunay tetrahedralization D of V, this routine recovers segments //
20953// of X in D by incrementally inserting points on missing segments, updating //
20954// D with the newly inserted points into D', which remains to be a Delaunay //
20955// tetrahedralization and respects the segments of X. Hence, each segment of //
20956// X appears as a union of edges in D'. //
20957// //
20958// This routine dynamically maintains two meshes, one is DT, another is the //
20959// surface mesh F of X. DT and F have exactly the same vertices. They are //
20960// updated simultaneously with the newly inserted points. //
20961// //
20962// Missing segments are found by looping the set S of segments, checking the //
20963// existence of each segment in DT. Once a segment is found missing in DT, //
20964// it is split into two subsegments by inserting a point into both DT and F, //
20965// and S is updated accordingly. However, the inserted point may cause some //
20966// other existing segments be non-Delaunay, hence are missing from the DT. //
20967// In order to force all segments to appear in DT, we have to loop S again //
20968// after some segments are split. (A little ugly method) Use a handle to //
20969// remember the last segment be split in one loop, hence all segments after //
20970// it are existing and need not be checked. //
20971// //
20972// In priciple, a segment on the convex hull should exist in DT. However, if //
20973// there are four coplanar points on the convex hull, and the DT only can //
20974// contain one diagonal edge which is unfortunately not the segment, then it //
20975// is missing. During the recovery of the segment, it is possible that the //
20976// calculated inserting point for recovering this convex hull segment is not //
20977// exact enough and lies (slightly) outside the DT. In order to insert the //
20978// point, we enlarge the convex hull of the DT, so it can contain the point //
20979// and remains convex. 'inserthullsite()' is called for this case. //
20980// //
20982
20983void tetgenmesh::delaunizesegments()
20984{
20985 list *misseglist;
20986 queue *flipqueue;
20987 badface *misloop;
20988 tetrahedron encodedtet;
20989 triface searchtet, splittet;
20990 face splitsh, symsplitsub;
20991 face segloop, symsplitseg;
20992 point refpoint, splitpoint, sympoint;
20993 point tend, checkpoint;
20994 point p1, p2, pa;
20995 enum finddirectionresult collinear;
20996 enum insertsiteresult success;
20997 enum locateresult symloc;
20998 bool coll;
20999 long vertcount;
21000 int i, j;
21001
21002 if (!b->quiet) {
21003 printf("Delaunizing segments.\n");
21004 }
21005
21006 // Construct a map from points to tets for speeding point location.
21007 makepoint2tetmap();
21008 // Initialize a flipqueue.
21009 flipqueue = new queue(sizeof(badface));
21010 // Initialize the pool of missing segments.
21011 misseglist = new list(sizeof(badface), NULL, SUBPERBLOCK);
21012 // Looking for missing segments.
21013 tallmissegs(misseglist);
21014 // The DT contains segments now.
21015 checksubsegs = 1;
21016 // Remember the current number of points.
21017 vertcount = points->items;
21018 // Initialize the counters.
21019 r1count = r2count = r3count = 0l;
21020
21021 // Loop until 'misseglist' is empty.
21022 while (misseglist->items > 0) {
21023 // Randomly pick a missing segment to recover.
21024 i = randomnation(misseglist->items);
21025 misloop = (badface *)(* misseglist)[i];
21026 segloop = misloop->ss;
21027 // Fill the "hole" in the list by filling the last one.
21028 *misloop = *(badface *)(* misseglist)[misseglist->items - 1];
21029 misseglist->items--;
21030 // Now recover the segment.
21031 p1 = (point) segloop.sh[3];
21032 p2 = (point) segloop.sh[4];
21033 if (b->verbose > 1) {
21034 printf(" Recover segment (%d, %d).\n", pointmark(p1), pointmark(p2));
21035 }
21036 getsearchtet(p1, p2, &searchtet, &tend);
21037 collinear = finddirection(&searchtet, tend, tetrahedrons->items);
21038 if (collinear == LEFTCOLLINEAR) {
21039 checkpoint = apex(searchtet);
21040 } else if (collinear == RIGHTCOLLINEAR) {
21041 checkpoint = dest(searchtet);
21042 } else if (collinear == TOPCOLLINEAR) {
21043 checkpoint = oppo(searchtet);
21044 } else {
21045#ifdef SELF_CHECK
21046 assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
21047#endif
21048 checkpoint = (point) NULL;
21049 }
21050 if (checkpoint != tend) {
21051 // ab is missing.
21052 splitpoint = (point) NULL;
21053 if (checkpoint != (point) NULL) {
21054 // An existing point c is found on the segment. It can happen when
21055 // ab is defined by a long segment with c inside it. Use c to
21056 // split ab. No new point is created.
21057 splitpoint = checkpoint;
21058 if (pointtype(checkpoint) == FREEVOLVERTEX) {
21059 // c is not a segment vertex yet. It becomes NACUTEVERTEX.
21060 setpointtype(splitpoint, NACUTEVERTEX);
21061 } else if (pointtype(checkpoint) == ACUTEVERTEX) {
21062 // c is an acute vertex. The definition of PLC is wrong.
21063 } else if (pointtype(checkpoint) == NACUTEVERTEX) {
21064 // c is an nonacute vertex. The definition of PLC is wrong.
21065 } else {
21066 // assert(0);
21067 }
21068 } else {
21069 // Find a reference point p of ab.
21070 refpoint = scoutrefpoint(&searchtet, tend);
21071 if (pointtype(refpoint) == FREEVOLVERTEX) {
21072 // p is an input point, check if it is nearly collinear with ab.
21073 coll = iscollinear(p1, p2, refpoint, b->epsilon);
21074 if (coll) {
21075 // a, b, and p are collinear. We insert p into ab. p becomes
21076 // a segment vertex with type NACUTEVERTEX.
21077 splitpoint = refpoint;
21078 setpointtype(splitpoint, NACUTEVERTEX);
21079 }
21080 }
21081 if (splitpoint == (point) NULL) {
21082 // Calculate a split point v using rule 1, or 2, or 3.
21083 splitpoint = getsplitpoint(&segloop, refpoint);
21084
21085 // Is there periodic boundary conditions?
21086 if (checkpbcs) {
21087 // Yes! Insert points on other segments of incident pbcgroups.
21088 i = shellmark(segloop) - 1;
21089 for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
21090 makepoint(&sympoint);
21091 symloc = getsegpbcsympoint(splitpoint, &segloop, sympoint,
21092 &symsplitseg, segpglist[j]);
21093#ifdef SELF_CHECK
21094 assert(symloc != OUTSIDE);
21095#endif
21096 if ((symloc == ONEDGE) && (symsplitseg.sh != segloop.sh)) {
21097#ifdef SELF_CHECK
21098 assert(symsplitseg.sh != dummysh);
21099#endif
21100 setpointtype(sympoint, FREESEGVERTEX);
21101 setpoint2sh(sympoint, sencode(symsplitseg));
21102 // Insert sympoint into DT.
21103 pa = sorg(symsplitseg);
21104 splittet.tet = dummytet;
21105 // Find a good start point to search.
21106 encodedtet = point2tet(pa);
21107 if (encodedtet != (tetrahedron) NULL) {
21108 decode(encodedtet, splittet);
21109 if (isdead(&splittet)) {
21110 splittet.tet = dummytet;
21111 }
21112 }
21113 // Locate sympoint in DT. Do exact location.
21114 success = insertsite(sympoint, &splittet, false, flipqueue);
21115#ifdef SELF_CHECK
21116 assert(success != DUPLICATEPOINT);
21117#endif
21118 if (success == OUTSIDEPOINT) {
21119 inserthullsite(sympoint, &splittet, flipqueue);
21120 }
21121 if (steinerleft > 0) steinerleft--;
21122 // Let sympoint remember splittet.
21123 setpoint2tet(sympoint, encode(splittet));
21124 // Do flip in DT.
21125 lawson(misseglist, flipqueue);
21126 // Insert sympoint into F.
21127 symsplitseg.shver = 0;
21128 spivot(symsplitseg, symsplitsub);
21129 // sympoint should on the edge of symsplitsub.
21130 splitsubedge(sympoint, &symsplitsub, flipqueue);
21131 // Do flip in facet.
21132 flipsub(flipqueue);
21133 // Insert the two subsegments.
21134 symsplitseg.shver = 0;
21135 insertsegment(&symsplitseg, misseglist);
21136 senextself(symsplitseg);
21137 spivotself(symsplitseg);
21138 symsplitseg.shver = 0;
21139 insertsegment(&symsplitseg, misseglist);
21140 } else { // if (symloc == ONVERTEX) {
21141 // The sympoint already exists. It is possible when two
21142 // pbc groups are exactly the same. Omit this point.
21143 pointdealloc(sympoint);
21144 }
21145 }
21146 }
21147
21148 // Insert 'splitpoint' into DT.
21149 if (isdead(&searchtet)) searchtet.tet = dummytet;
21150 success = insertsite(splitpoint, &searchtet, false, flipqueue);
21151 if (success == OUTSIDEPOINT) {
21152 // A convex hull edge is missing, and the inserting point lies
21153 // (slightly) outside the convex hull due to the significant
21154 // digits lost in the calculation. Enlarge the convex hull.
21155 inserthullsite(splitpoint, &searchtet, flipqueue);
21156 }
21157 if (steinerleft > 0) steinerleft--;
21158 // Remember a handle in 'splitpoint' to enhance the speed of
21159 // consequent point location.
21160 setpoint2tet(splitpoint, encode(searchtet));
21161 // Maintain Delaunayness in DT.
21162 lawson(misseglist, flipqueue);
21163 }
21164 }
21165 // Insert 'splitpoint' into F.
21166 spivot(segloop, splitsh);
21167 splitsubedge(splitpoint, &splitsh, flipqueue);
21168 flipsub(flipqueue);
21169 // Insert the two subsegments.
21170 segloop.shver = 0;
21171 insertsegment(&segloop, misseglist);
21172 senextself(segloop);
21173 spivotself(segloop);
21174 segloop.shver = 0;
21175 insertsegment(&segloop, misseglist);
21176 }
21177 }
21178
21179 // Detach all segments from tets.
21180 tetrahedrons->traversalinit();
21181 searchtet.tet = tetrahedrontraverse();
21182 while (searchtet.tet != (tetrahedron *) NULL) {
21183 for (i = 0; i < 6; i++) {
21184 searchtet.tet[8 + i] = (tetrahedron) dummysh;
21185 }
21186 searchtet.tet = tetrahedrontraverse();
21187 }
21188 // No segments now.
21189 checksubsegs = 0;
21190
21191 if (b->verbose > 0) {
21192 printf(" %ld protect points.\n", points->items - vertcount);
21193 printf(" R1: %ld, R2: %ld, R3: %ld.\n", r1count, r2count, r3count);
21194 }
21195
21196 delete flipqueue;
21197 delete misseglist;
21198}
21199
21200//
21201// End of segments recovery routines
21202//
21203
21204//
21205// Begin of facet recovery routines
21206//
21207
21209// //
21210// insertsubface() Fix a subface in place. //
21211// //
21212// Search a subface s in current tetrahedralization T. If s is found a face //
21213// face of T, it is inserted into T. Return FALSE if s is not found in T. //
21214// //
21216
21217bool tetgenmesh::insertsubface(face* insertsh, triface* searchtet)
21218{
21219 triface spintet, symtet;
21220 face testsh, testseg;
21221 face spinsh, casin, casout;
21222 point tapex, checkpoint;
21223 enum finddirectionresult collinear;
21224 int hitbdry;
21225
21226 // Search an edge of s.
21227 getsearchtet(sorg(*insertsh), sdest(*insertsh), searchtet, &checkpoint);
21228 collinear = finddirection(searchtet, checkpoint, tetrahedrons->items);
21229 if (collinear == LEFTCOLLINEAR) {
21230 enext2self(*searchtet);
21231 esymself(*searchtet);
21232 } else if (collinear == TOPCOLLINEAR) {
21233 fnextself(*searchtet);
21234 enext2self(*searchtet);
21235 esymself(*searchtet);
21236 }
21237 if (dest(*searchtet) != checkpoint) {
21238 // The edge doesn't exist => s is missing.
21239 return false;
21240 }
21241
21242 // Search s by spinning faces around the edge.
21243 tapex = sapex(*insertsh);
21244 spintet = *searchtet;
21245 hitbdry = 0;
21246 do {
21247 if (apex(spintet) == tapex) {
21248 // Found s in T. Check if s has already been inserted.
21249 tspivot(spintet, testsh);
21250 if (testsh.sh == dummysh) {
21251 adjustedgering(spintet, CCW);
21252 findedge(insertsh, org(spintet), dest(spintet));
21253 tsbond(spintet, *insertsh);
21254 sym(spintet, symtet); // 'symtet' maybe outside, use it anyway.
21255 sesymself(*insertsh);
21256 tsbond(symtet, *insertsh);
21257 } else {
21258 // Found a duplicated subface (due to the redundant input).
21259 if (!b->quiet) {
21260 printf("Warning: Two subfaces are found duplicated at ");
21261 printf("(%d, %d, %d)\n", pointmark(sorg(testsh)),
21262 pointmark(sdest(testsh)), pointmark(sapex(testsh)));
21263 printf(" Subface of facet #%d is deleted.\n", shellmark(*insertsh));
21264 // printf(" Hint: -d switch can find all duplicated facets.\n");
21265 }
21266 shellfacedealloc(subfaces, insertsh->sh);
21267 }
21268 return true;
21269 }
21270 if (!fnextself(spintet)) {
21271 hitbdry ++;
21272 if (hitbdry < 2) {
21273 esym(*searchtet, spintet);
21274 if (!fnextself(spintet)) {
21275 hitbdry ++;
21276 }
21277 }
21278 }
21279 } while (hitbdry < 2 && apex(spintet) != apex(*searchtet));
21280
21281 // s is missing.
21282 return false;
21283}
21284
21286// //
21287// tritritest() Test if two triangles are intersecting in their interior. //
21288// //
21289// One triangle t1 is the face of 'checktet', the other t2 is given by three //
21290// corners 'p1', 'p2' and 'p3'. This routine calls tri_tri_inter() to detect //
21291// whether t1 and t2 exactly intersect in their interior. Cases like share a //
21292// vertex, share an edge, or coincidence are considered not intersect. //
21293// //
21295
21296bool tetgenmesh::tritritest(triface* checktet, point p1, point p2, point p3)
21297{
21298 point forg, fdest, fapex;
21299 enum interresult intersect;
21300
21301 forg = org(*checktet);
21302 fdest = dest(*checktet);
21303 fapex = apex(*checktet);
21304
21305#ifdef SELF_CHECK
21306 REAL ax, ay, az, bx, by, bz;
21307 REAL n[3];
21308 // face (torg, tdest, tapex) should not be degenerate. However p1, p2,
21309 // and p3 may be collinear. Check it.
21310 ax = forg[0] - fdest[0];
21311 ay = forg[1] - fdest[1];
21312 az = forg[2] - fdest[2];
21313 bx = forg[0] - fapex[0];
21314 by = forg[1] - fapex[1];
21315 bz = forg[2] - fapex[2];
21316 n[0] = ay * bz - by * az;
21317 n[1] = az * bx - bz * ax;
21318 n[2] = ax * by - bx * ay;
21319 assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
21320 // The components of n should not smaller than the machine epsilon.
21321
21322 ax = p1[0] - p2[0];
21323 ay = p1[1] - p2[1];
21324 az = p1[2] - p2[2];
21325 bx = p1[0] - p3[0];
21326 by = p1[1] - p3[1];
21327 bz = p1[2] - p3[2];
21328 n[0] = ay * bz - by * az;
21329 n[1] = az * bx - bz * ax;
21330 n[2] = ax * by - bx * ay;
21331 assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
21332 // The components of n should not smaller than the machine epsilon.
21333#endif
21334
21335 intersect = tri_tri_inter(forg, fdest, fapex, p1, p2, p3);
21336 return intersect == INTERSECT;
21337}
21338
21340// //
21341// initializecavity() Initialize the cavity. //
21342// //
21343// A cavity C is bounded by a list of faces, called fronts. Each front f is //
21344// hold by a tet t adjacent to C, t is not in C (uninfected). If f is a hull //
21345// face, t does't exist, a fake tet t' is created to hold f. t' has the same //
21346// vertices as f but no opposite. t' will be removed automatically after C //
21347// is filled with new tets (by carvecavity()). //
21348// //
21349// The faces of C are given in two lists. 'floorlist' is a set of subfaces, //
21350// each subface has been oriented to face to the inside of C. 'ceillist' is //
21351// a set of tetrahedral faces. 'frontlist' returns the initialized fronts. //
21352// //
21354
21355void tetgenmesh::initializecavity(list* floorlist, list* ceillist,
21356 list* frontlist)
21357{
21358 triface neightet, casingtet;
21359 triface faketet;
21360 face worksh;
21361 int i;
21362
21363 // Initialize subfaces of C.
21364 for (i = 0; i < floorlist->len(); i++) {
21365 // Get a subface s.
21366 worksh = * (face *)(* floorlist)[i];
21367#ifdef SELF_CHECK
21368 // Current side of s should be empty.
21369 stpivot(worksh, neightet);
21370 assert(neightet.tet == dummytet);
21371#endif
21372 // Get the adjacent tet t.
21373 sesymself(worksh);
21374 stpivot(worksh, casingtet);
21375 // Does t exist?
21376 if (casingtet.tet == dummytet) {
21377 // Create a fake tet t' to hold f temporarily.
21378 maketetrahedron(&faketet);
21379 setorg(faketet, sorg(worksh));
21380 setdest(faketet, sdest(worksh));
21381 setapex(faketet, sapex(worksh));
21382 setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
21383 tsbond(faketet, worksh);
21384 frontlist->append(&faketet);
21385 } else {
21386 frontlist->append(&casingtet);
21387 }
21388 }
21389 // Initialize tet faces of C.
21390 for (i = 0; i < ceillist->len(); i++) {
21391 // Get a tet face c.
21392 neightet = * (triface *) (* ceillist)[i];
21393#ifdef SELF_CHECK
21394 // The tet of c must be inside C (going to be deleted).
21395 assert(infected(neightet));
21396#endif
21397 // Get the adjacent tet t.
21398 sym(neightet, casingtet);
21399 // Does t exist?
21400 if (casingtet.tet == dummytet) {
21401 // No. Create a fake tet t' to hold f temporarily.
21402 maketetrahedron(&faketet);
21403 // Be sure that the vertices of t' are CCW oriented.
21404 adjustedgering(neightet, CW); // CW edge ring.
21405 setorg(faketet, org(neightet));
21406 setdest(faketet, dest(neightet));
21407 setapex(faketet, apex(neightet));
21408 setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
21409 // Bond t' to a subface if it exists.
21410 tspivot(neightet, worksh);
21411 if (worksh.sh != dummysh) {
21412 sesymself(worksh);
21413 tsbond(faketet, worksh);
21414 }
21415 // Bond c <--> t'. So we're able to find t' and remove it.
21416 bond(faketet, neightet);
21417 // c may become uninfected due to the bond().
21418 infect(neightet);
21419 frontlist->append(&faketet);
21420 } else {
21421 frontlist->append(&casingtet);
21422 }
21423 }
21424}
21425
21427// //
21428// retrievenewtets() Retrieve the newly created tets. //
21429// //
21430// On input, 'newtetlist' contains at least one alive new tet. From this tet,//
21431// other new tets can be found by a broadth-first searching. //
21432// //
21434
21435void tetgenmesh::retrievenewtets(list* newtetlist)
21436{
21437 triface searchtet, casingtet;
21438 int i;
21439
21440 // There may be dead tets due to flip32(). Delete them first.
21441 for (i = 0; i < newtetlist->len(); i++) {
21442 searchtet = * (triface *)(* newtetlist)[i];
21443 if (isdead(&searchtet)) {
21444 newtetlist->del(i, 0); i--;
21445 continue;
21446 }
21447 infect(searchtet);
21448 }
21449 // Find all new tets.
21450 for (i = 0; i < newtetlist->len(); i++) {
21451 searchtet = * (triface *)(* newtetlist)[i];
21452 for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
21453 sym(searchtet, casingtet);
21454 if ((casingtet.tet != dummytet) && !infected(casingtet)) {
21455 infect(casingtet);
21456 newtetlist->append(&casingtet);
21457 }
21458 }
21459 }
21460 // Uninfect new tets.
21461 for (i = 0; i < newtetlist->len(); i++) {
21462 searchtet = * (triface *)(* newtetlist)[i];
21463 uninfect(searchtet);
21464 }
21465}
21466
21468// //
21469// delaunizecavvertices() Form a DT of the vertices of a cavity. //
21470// //
21471// 'floorptlist' and 'ceilptlist' are the vertices of the cavity. //
21472// //
21473// The tets of the DT are created directly in the pool 'tetrahedrons', i.e., //
21474// no auxiliary data structure and memory are required. The trick is at the //
21475// time they're created, there are no connections between them to the other //
21476// tets in the pool. You can imagine they form an ioslated island. //
21477// //
21479
21480void tetgenmesh::delaunizecavvertices(triface* oldtet, list* floorptlist,
21481 list* ceilptlist, list* newtetlist, queue* flipque)
21482{
21483 point *insertarray;
21484 triface bakhulltet, newtet;
21485 long bakhullsize;
21486 long arraysize;
21487 int bakchksub;
21488 int i, j;
21489
21490 // Prepare the array of points for inserting.
21491 arraysize = floorptlist->len();
21492 if (ceilptlist != (list *) NULL) {
21493 arraysize += ceilptlist->len();
21494 }
21495 insertarray = new point[arraysize];
21496 for (i = 0; i < floorptlist->len(); i++) {
21497 insertarray[i] = * (point *)(* floorptlist)[i];
21498 }
21499 if (ceilptlist != (list *) NULL) {
21500 for (j = 0; j < ceilptlist->len(); j++) {
21501 insertarray[i + j] = * (point *)(* ceilptlist)[j];
21502 }
21503 }
21504
21505 // The incrflipdelaunay() is re-used. Backup global variables.
21506 decode(dummytet[0], bakhulltet);
21507 bakhullsize = hullsize;
21508 bakchksub = checksubfaces;
21509 checksubfaces = 0;
21510 b->verbose--;
21511
21512 // Form the DT by incremental flip Delaunay algorithm. Do not jump for
21513 // point location, do not merge points.
21514 incrflipdelaunay(oldtet, insertarray, arraysize, false, false, 0.0, flipque);
21515
21516 // Get a tet in D.
21517 decode(dummytet[0], newtet);
21518 newtetlist->append(&newtet);
21519 // Get all tets of D.
21520 retrievenewtets(newtetlist);
21521
21522 // Restore global variables.
21523 dummytet[0] = encode(bakhulltet);
21524 hullsize = bakhullsize;
21525 checksubfaces = bakchksub;
21526 b->verbose++;
21527
21528 delete [] insertarray;
21529}
21530
21532// //
21533// insertauxsubface() Fix an auxilary subface in place. //
21534// //
21535// An auxilary subface s is fixed in D as it is a real subface, but s has no //
21536// vertices and neighbors. It has two uses: (1) it protects an identfied //
21537// front f in D; (2) it serves the link to bond a tet in C and f later. The //
21538// first neighbor of s (s->sh[0]) stores a pointer to f. //
21539// //
21540// 'front' is a front f of C. idfront' t is a tet in D where f is identified //
21541// be a face of it. s will be fixed between t and its neighbor. //
21542// //
21544
21545void tetgenmesh::insertauxsubface(triface* front, triface* idfront)
21546{
21547 triface neightet;
21548 face auxsh;
21549
21550 // Create the aux subface s.
21551 makeshellface(subfaces, &auxsh);
21552 // Bond s <--> t.
21553 tsbond(*idfront, auxsh);
21554 // Does t's neighbor n exist?
21555 sym(*idfront, neightet);
21556 if (neightet.tet != dummytet) {
21557 // Bond s <--> n.
21558 sesymself(auxsh);
21559 tsbond(neightet, auxsh);
21560 }
21561 // Let s remember f.
21562 auxsh.sh[0] = (shellface) encode(*front);
21563}
21564
21566// //
21567// scoutfront() Scout a face in D. //
21568// //
21569// Search a 'front' f in D. If f is found, return TRUE and the face of D is //
21570// returned in 'idfront'. Otherwise, return FALSE. //
21571// //
21573
21574bool tetgenmesh::scoutfront(triface* front, triface* idfront, list* newtetlist)
21575{
21576 triface spintet;
21577 point pa, pb, pc;
21578 enum locateresult loc;
21579 enum finddirectionresult col;
21580 int hitbdry;
21581 int i;
21582
21583 // Let the front we're searching is abc.
21584 pa = org(*front);
21585 pb = dest(*front);
21586 // Get a tet in D for searching.
21587 *idfront = recenttet;
21588 // Make sure the tet is valid (it may be killed by flips).
21589 if (isdead(idfront)) {
21590 // The tet is dead. Search a live tet in D. !!!
21591 for (i = 0; i < newtetlist->len(); i++) {
21592 recenttet = * (triface *)(* newtetlist)[i];
21593 if (!isdead(&recenttet)) break;
21594 }
21595 assert(i < newtetlist->len());
21596 }
21597
21598 // Search a tet having vertex a.
21599 loc = preciselocate(pa, idfront, (long) newtetlist->len());
21600 UNUSED_OPT(loc);
21601 assert(loc == ONVERTEX);
21602 recenttet = *idfront;
21603 // Search a tet having edge ab.
21604 col = finddirection(idfront, pb, (long) newtetlist->len());
21605 if (col == RIGHTCOLLINEAR) {
21606 // b is just the destination.
21607 } else if (col == LEFTCOLLINEAR) {
21608 enext2self(*idfront);
21609 esymself(*idfront);
21610 } else if (col == TOPCOLLINEAR) {
21611 fnextself(*idfront);
21612 enext2self(*idfront);
21613 esymself(*idfront);
21614 }
21615
21616 if (dest(*idfront) == pb) {
21617 // Search a tet having face abc
21618 pc = apex(*front);
21619 spintet = *idfront;
21620 hitbdry = 0;
21621 do {
21622 if (apex(spintet) == pc) {
21623 // Found abc. Insert an auxilary subface s at idfront.
21624 // insertauxsubface(front, &spintet);
21625 *idfront = spintet;
21626 return true;
21627 }
21628 if (!fnextself(spintet)) {
21629 hitbdry ++;
21630 if (hitbdry < 2) {
21631 esym(*idfront, spintet);
21632 if (!fnextself(spintet)) {
21633 hitbdry ++;
21634 }
21635 }
21636 }
21637 if (apex(spintet) == apex(*idfront)) break;
21638 } while (hitbdry < 2);
21639 }
21640
21641 // f is missing in D.
21642 if (b->verbose > 2) {
21643 printf(" Front (%d, %d, %d) is missing.\n", pointmark(pa),
21644 pointmark(pb), pointmark(apex(*front)));
21645 }
21646 return false;
21647}
21648
21650// //
21651// gluefronts() Glue two fronts together. //
21652// //
21653// This is a support routine for identifyfront(). Two fronts f and f1 are //
21654// found indentical. This is caused by the non-coplanarity of vertices of a //
21655// facet. Hence f and f1 are a subface and a tet. They are not fronts of the //
21656// cavity anymore. This routine glues f and f1 together. //
21657// //
21659
21660void tetgenmesh::gluefronts(triface* front, triface* front1)
21661{
21662 face consh;
21663
21664 // Glue f and f1 together. There're four cases:
21665 // (1) both f and f1 are not fake;
21666 // (2) f is not fake, f1 is fake;
21667 // (3) f is fake and f1 is not fake;
21668 // (4) both f and f1 are fake.
21669 // Case (4) should be not possible.
21670
21671 // Is there a concrete subface c at f.
21672 tspivot(*front, consh);
21673 if (consh.sh != dummysh) {
21674 sesymself(consh);
21675 tsbond(*front1, consh); // Bond: f1 <--> c.
21676 sesymself(consh);
21677 }
21678 // Does f hold by a fake tet.
21679 if (oppo(*front) == (point) NULL) {
21680 // f is fake. Case (3) or (4).
21681 assert(oppo(*front1) != (point) NULL); // Eliminate (4).
21682 // Case (3).
21683 if (consh.sh != dummysh) {
21684 stdissolve(consh); // Dissolve: c -x-> f.
21685 }
21686 // Dealloc f.
21687 tetrahedrondealloc(front->tet);
21688 // f1 becomes a hull. let 'dummytet' bond to it.
21689 dummytet[0] = encode(*front1);
21690 } else {
21691 // Case (1) or (2).
21692 bond(*front, *front1); // Bond f1 <--> f.
21693 }
21694 // Is f a fake tet?
21695 if (!isdead(front)) {
21696 // No. Check for case (2).
21697 tspivot(*front1, consh);
21698 // Is f1 fake?
21699 if (oppo(*front1) == (point) NULL) {
21700 // Case (2) or (4)
21701 assert(oppo(*front) != (point) NULL); // Eliminate (4).
21702 // Case (2).
21703 if (consh.sh != dummysh) {
21704 stdissolve(consh); // Dissolve: c -x-> f1.
21705 sesymself(consh); // Bond: f <--> c.
21706 tsbond(*front, consh);
21707 }
21708 // Dissolve: f -x->f1.
21709 dissolve(*front);
21710 // Dealloc f1.
21711 tetrahedrondealloc(front1->tet);
21712 // f becomes a hull. let 'dummytet' bond to it.
21713 dummytet[0] = encode(*front);
21714 } else {
21715 // Case (1).
21716 if (consh.sh != dummysh) {
21717 sesymself(consh);
21718 tsbond(*front, consh); // Bond: f <--> c.
21719 }
21720 }
21721 }
21722}
21723
21725// //
21726// identifyfronts() Identify cavity faces in D. //
21727// //
21728// 'frontlist' are fronts of C need indentfying. This routine searches each //
21729// front f in D. Once f is found, an auxilary subface s is inserted in D at //
21730// the face. If f is not found in D, remove it from frontlist and save it in //
21731// 'misfrontlist'. //
21732// //
21734
21735bool tetgenmesh::identifyfronts(list* frontlist, list* misfrontlist,
21736 list* newtetlist)
21737{
21738 triface front, front1, tfront;
21739 triface idfront, neightet;
21740 face auxsh;
21741 int len, i, j;
21742
21743 misfrontlist->clear();
21744 // Set a new tet in D for searching.
21745 recenttet = * (triface *)(* newtetlist)[0];
21746
21747 // Identify all fronts in D.
21748 for (i = 0; i < frontlist->len(); i++) {
21749 // Get a front f.
21750 front = * (triface *)( *frontlist)[i];
21751 if (scoutfront(&front, &idfront, newtetlist)) {
21752 // Found f. Insert an aux subface s.
21753 assert((idfront.tet != dummytet) && !isdead(&idfront));
21754 // Does s already exist?
21755 tspivot(idfront, auxsh);
21756 if (auxsh.sh != dummysh) {
21757 // There're two identical fronts, f (front) and f1 (s.sh[0])!
21758 decode((tetrahedron) auxsh.sh[0], front1);
21759 assert((front1.tet != dummytet) && !infected(front1));
21760 // Detach s in D.
21761 tsdissolve(idfront);
21762 sym(idfront, neightet);
21763 if (neightet.tet != dummytet) {
21764 tsdissolve(neightet);
21765 }
21766 // s has fulfilled its duty. Can be deleted.
21767 shellfacedealloc(subfaces, auxsh.sh);
21768 // Remove f from frontlist.
21769 frontlist->del(i, 1); i--;
21770 // Remove f1 from frontlist.
21771 len = frontlist->len();
21772 for (j = 0; j < frontlist->len(); j++) {
21773 tfront = * (triface *)(* frontlist)[j];
21774 if ((tfront.tet == front1.tet) && (tfront.loc == front1.loc)) {
21775 // Found f1 in list. Check f1 != f.
21776 assert((tfront.tet != front.tet) || (tfront.loc != front.loc));
21777 frontlist->del(j, 1); i--;
21778 break;
21779 }
21780 }
21781 assert((frontlist->len() + 1) == len);
21782 UNUSED_OPT(len);
21783 // Glue f and f1 together.
21784 gluefronts(&front, &front1);
21785 } else {
21786 // Insert an aux subface to protect f in D.
21787 insertauxsubface(&front, &idfront);
21788 }
21789 } else {
21790 // f is missing.
21791 frontlist->del(i, 1); i--;
21792 // Are there two identical fronts, f (front) and f1 (front1)?
21793 for (j = 0; j < misfrontlist->len(); j++) {
21794 front1 = * (triface *)(* misfrontlist)[j];
21795 if (isfacehaspoint(&front1, org(front)) &&
21796 isfacehaspoint(&front1, dest(front)) &&
21797 isfacehaspoint(&front1, apex(front))) break;
21798 }
21799 if (j < misfrontlist->len()) {
21800 // Found an identical front f1. Remove f1 from the list.
21801 misfrontlist->del(j, 1);
21802 // Glue f and f1 together.
21803 gluefronts(&front, &front1);
21804 } else {
21805 // Add f into misfrontlist.
21806 misfrontlist->append(&front);
21807 }
21808 }
21809 }
21810 return misfrontlist->len() == 0;
21811}
21812
21814// //
21815// detachauxsubfaces() Detach auxilary subfaces in D. //
21816// //
21817// This is a reverse routine of identifyfronts(). Some fronts are missing in //
21818// D. C can not be easily tetrahedralized. It needs remediation (expansion, //
21819// or constrained flips, or adding a Steiner point). This routine detaches //
21820// the auxilary subfaces have been inserted in D and delete them. //
21821// //
21823
21824void tetgenmesh::detachauxsubfaces(list* newtetlist)
21825{
21826 triface newtet, neightet;
21827 face auxsh;
21828 int i;
21829
21830 for (i = 0; i < newtetlist->len(); i++) {
21831 // Get a new tet t.
21832 newtet = * (triface *)(* newtetlist)[i];
21833 // t may e dead due to flips.
21834 if (isdead(&newtet)) continue;
21835 assert(!infected(newtet));
21836 // Check the four faces of t.
21837 for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
21838 tspivot(newtet, auxsh);
21839 if (auxsh.sh != dummysh) {
21840 // An auxilary subface s.
21841 assert(sorg(auxsh) == (point) NULL);
21842 tsdissolve(newtet); // t -x-> s.
21843 sym(newtet, neightet);
21844 if (neightet.tet != dummytet) {
21845 assert(!isdead(&neightet));
21846 tsdissolve(neightet); // n -x-> s.
21847 }
21848 // Delete s.
21849 shellfacedealloc(subfaces, auxsh.sh);
21850 }
21851 }
21852 }
21853}
21854
21856// //
21857// expandcavity() Expand the cavity by adding new fronts. //
21858// //
21859// This is the support routine for delaunizecavity(). Some fronts of C are //
21860// missing in D since they're not strongly Delaunay. Such fronts are removed //
21861// and the faces of the tets abutting to them are added. C is then expanded. //
21862// Some removed faces may be subfaces, they're queued to recover later. D is //
21863// expanded simultaneously with the new vertices of the new fronts. //
21864// //
21866
21867void tetgenmesh::expandcavity(list* frontlist, list* misfrontlist,
21868 list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque)
21869{
21870 triface misfront, newfront, casingtet, crosstet;
21871 triface searchtet, faketet, bakhulltet;
21872 face checksh;
21873 point pd;
21874 enum insertsiteresult success;
21875 long bakhullsize;
21876 int bakchksub;
21877 int i, j, k;
21878
21879 if (b->verbose > 1) {
21880 printf(" Expand cavity (%d missing fronts).\n", misfrontlist->len());
21881 }
21882 // Increase the number of expanded times.
21883 expcavcount++;
21884 // The incrflipdelaunay() is re-used. Backup global variables.
21885 decode(dummytet[0], bakhulltet);
21886 bakhullsize = hullsize;
21887 bakchksub = checksubfaces;
21888 checksubfaces = 0;
21889 b->verbose--;
21890
21891 // Choose a tet in D for searching.
21892 recenttet = * (triface *)(* newtetlist)[0];
21893 assert((recenttet.tet != dummytet) && !isdead(&recenttet));
21894
21895 // Loop through 'misfrontlist'.
21896 for (i = 0; i < misfrontlist->len(); i++) {
21897 // Get a missing front f.
21898 misfront = * (triface *)(* misfrontlist)[i];
21899 // C will be expanded at f.
21900 if (b->verbose > 1) {
21901 printf(" Get misfront (%d, %d, %d).\n", pointmark(org(misfront)),
21902 pointmark(dest(misfront)), pointmark(apex(misfront)));
21903 }
21904 // Is f has a subface s?
21905 tspivot(misfront, checksh);
21906 if (checksh.sh != dummysh) {
21907 // A subface s is found. Check whether f is expandable at s.
21908 sym(misfront, crosstet);
21909 if (!infected(crosstet)) {
21910 // f is not expandable. In principle is should not happen. However,
21911 // it can happen when PBC is in use.
21912 assert(checkpbcs);
21913 // Skip expanding f. It will be processed later.
21914 continue;
21915 }
21916 // Temporarily remove s. Queue and recover it later.
21917 if (b->verbose > 1) {
21918 printf(" Queuing subface (%d, %d, %d).\n",
21919 pointmark(sorg(checksh)), pointmark(sdest(checksh)),
21920 pointmark(sapex(checksh)));
21921 }
21922 // Detach s from tets at its both sides.
21923 tsdissolve(misfront);
21924 tsdissolve(crosstet);
21925 // Detach tets at from s.
21926 stdissolve(checksh);
21927 sesymself(checksh);
21928 stdissolve(checksh);
21929 // Mark and queue it.
21930 sinfect(checksh);
21931 missingshqueue->push(&checksh);
21932 }
21933 // f may already be processed (become a cross tet of C).
21934 if (infected(misfront)) continue;
21935 // Get the point p = oppo(t), t is the tet holds f.
21936 pd = oppo(misfront);
21937#ifdef SELF_CHECK
21938 // t must not be fake.
21939 assert(pd != (point) NULL);
21940#endif
21941 // Insert p in D. p may not be inserted if it is one of the two cases:
21942 // (1) p is already a vertex of D;
21943 // (2) p lies outside the CH of D;
21944 searchtet = recenttet;
21945 // Make sure the tet is valid (it may be killed by flips).
21946 if (isdead(&searchtet)) {
21947 // The tet is dead. Get a live tet in D. !!!
21948 for (j = 0; j < newtetlist->len(); j++) {
21949 recenttet = * (triface *)(* newtetlist)[j];
21950 if (!isdead(&recenttet)) break;
21951 }
21952 assert(j < newtetlist->len());
21953 searchtet = recenttet;
21954 }
21955 success = insertsite(pd, &searchtet, false, flipque);
21956 if (success == OUTSIDEPOINT) {
21957 // case (2). Insert p onto CH of D.
21958 inserthullsite(pd, &searchtet, flipque);
21959 }
21960 if (success != DUPLICATEPOINT) {
21961 // p is inserted. Recover Delaunness of D by flips.
21962 flip(flipque, NULL);
21963 }
21964 // Expand C by adding new fronts. The three faces of t which have p as a
21965 // vertex become new fronts. However, if a new front is coincident with
21966 // an old front of C, it is not added and the old front is removed.
21967 adjustedgering(misfront, CCW);
21968 for (j = 0; j < 3; j++) {
21969 // Notice: Below I mis-used the names. 'newfront' is not exactly a new
21970 // front, instead the 'casingtet' should be called new front.
21971 // Get a new front f_n.
21972 fnext(misfront, newfront);
21973 // Get the neighbor tet n at f_n.
21974 sym(newfront, casingtet);
21975 // Is n a cross tet?
21976 if (!infected(casingtet)) {
21977 // f_n becomes a new front of C.
21978 // Does n exist?
21979 if (casingtet.tet == dummytet) {
21980 // Create a fake tet n' to hold f_n temporarily.
21981 maketetrahedron(&faketet);
21982 // Be sure that the vertices of fake tet are CCW oriented.
21983 adjustedgering(newfront, CW); // CW edge ring.
21984 setorg(faketet, org(newfront));
21985 setdest(faketet, dest(newfront));
21986 setapex(faketet, apex(newfront));
21987 setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
21988 // Bond n' to a subface if it exists.
21989 tspivot(newfront, checksh);
21990 if (checksh.sh != dummysh) {
21991 sesymself(checksh);
21992 tsbond(faketet, checksh);
21993 }
21994 // Bond f_n <--> n'. So we're able to find n' and remove it.
21995 bond(faketet, newfront);
21996 frontlist->append(&faketet);
21997 } else {
21998 // Add n to frontlist.
21999 frontlist->append(&casingtet);
22000 }
22001 } else {
22002 // f_n is coincident with an existing front f' of C. f' is no longer
22003 // a front, remove it from frontlist. Use the inverse order to
22004 // search f' (most likely, a newly added front may be f').
22005 for (k = frontlist->len() - 1; k >= 0; k--) {
22006 searchtet = * (triface *)(* frontlist)[k];
22007 if ((newfront.tet == searchtet.tet) &&
22008 (newfront.loc == searchtet.loc)) {
22009 frontlist->del(k, 0);
22010 break;
22011 }
22012 }
22013 // Is f_n a subface?
22014 tspivot(newfront, checksh);
22015 if (checksh.sh != dummysh) {
22016 // Temporarily remove checksh. Make it missing. recover it later.
22017 if (b->verbose > 2) {
22018 printf(" Queuing subface (%d, %d, %d).\n",
22019 pointmark(sorg(checksh)), pointmark(sdest(checksh)),
22020 pointmark(sapex(checksh)));
22021 }
22022 tsdissolve(newfront);
22023 tsdissolve(casingtet);
22024 // Detach tets at the both sides of checksh.
22025 stdissolve(checksh);
22026 sesymself(checksh);
22027 stdissolve(checksh);
22028 sinfect(checksh);
22029 missingshqueue->push(&checksh);
22030 }
22031 }
22032 enextself(misfront);
22033 }
22034 // C has been expanded at f. t becomes a cross tet.
22035 if (!infected(misfront)) {
22036 // t will be deleted, queue it.
22037 infect(misfront);
22038 crosstetlist->append(&misfront);
22039 }
22040 }
22041
22042 // Loop through misfrontlist, remove infected misfronts.
22043 for (i = 0; i < misfrontlist->len(); i++) {
22044 misfront = * (triface *)(* misfrontlist)[i];
22045 if (infected(misfront)) {
22046 // Remove f, keep original list order.
22047 misfrontlist->del(i, 1);
22048 i--;
22049 }
22050 }
22051
22052 // Are we done?
22053 if (misfrontlist->len() > 0) {
22054 // No. There are unexpandable fronts.
22055 // expandcavity_sos(misfrontlist);
22056 assert(0); // Not done yet.
22057 }
22058
22059 // D has been updated (by added new tets or dead tets) (due to flips).
22060 retrievenewtets(newtetlist);
22061
22062 // Restore global variables.
22063 dummytet[0] = encode(bakhulltet);
22064 hullsize = bakhullsize;
22065 checksubfaces = bakchksub;
22066 b->verbose++;
22067}
22068
22070// //
22071// carvecavity() Remove redundant (outside) tetrahedra from D. //
22072// //
22073// The fronts of C have been identified in D. Hence C can be tetrahedralized //
22074// by removing the tets outside C. The CDT is then updated by filling C with //
22075// the remaining tets (inside C) of D. //
22076// //
22077// Each front is protected by an auxilary subface s in D. s has a pointer to //
22078// f (s.sh[0]). f can be used to classified the in- and out- tets of C (the //
22079// CW orientation of f faces to the inside of C). The classified out-tets of //
22080// C are marked (infected) for removing. //
22081// //
22082// Notice that the out-tets may not only the tets on the CH of C, but also //
22083// tets completely inside D, eg., there is a "hole" in D. Such tets must be //
22084// marked during classification. The hole tets are poped up and removed too. //
22085// //
22087
22088void tetgenmesh::carvecavity(list* newtetlist, list* outtetlist,
22089 queue* flipque)
22090{
22091 triface newtet, neightet, front, outtet;
22092 face auxsh, consh;
22093 point pointptr;
22094 REAL ori;
22095 int i;
22096
22097 // Clear work list.
22098 outtetlist->clear();
22099
22100 // Classify in- and out- tets in D. Mark and queue classified out-tets.
22101 for (i = 0; i < newtetlist->len(); i++) {
22102 // Get a new tet t.
22103 newtet = * (triface *)(* newtetlist)[i];
22104 assert(!isdead(&newtet));
22105 // Look for aux subfaces attached at t.
22106 for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
22107 tspivot(newtet, auxsh);
22108 if (auxsh.sh != dummysh) {
22109 // Has this side a neighbor n?
22110 sym(newtet, neightet);
22111 if (neightet.tet != dummytet) {
22112 // Classify t and n (one is "in" and another is "out").
22113 // Get the front f.
22114 decode((tetrahedron) auxsh.sh[0], front);
22115 // Let f face to the inside of C.
22116 adjustedgering(front, CW);
22117 ori = orient3d(org(front), dest(front), apex(front), oppo(newtet));
22118 assert(ori != 0.0);
22119 if (ori < 0.0) {
22120 // t is in-tet. n is out-tet.
22121 outtet = neightet;
22122 } else {
22123 // n is in-tet. t is out-tet.
22124 outtet = newtet;
22125 }
22126 // Add the out-tet into list.
22127 if (!infected(outtet)) {
22128 infect(outtet);
22129 outtetlist->append(&outtet);
22130 }
22131 }
22132 }
22133 }
22134 }
22135
22136 // Find and mark all out-tets.
22137 for (i = 0; i < outtetlist->len(); i++) {
22138 outtet = * (triface *)(* outtetlist)[i];
22139 for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) {
22140 sym(outtet, neightet);
22141 // Does the neighbor exist and unmarked?
22142 if ((neightet.tet != dummytet) && !infected(neightet)) {
22143 // Is it protected by an aux subface?
22144 tspivot(outtet, auxsh);
22145 if (auxsh.sh == dummysh) {
22146 // It's an out-tet.
22147 infect(neightet);
22148 outtetlist->append(&neightet);
22149 }
22150 }
22151 }
22152 }
22153
22154 // Remove the out- (and hole) tets.
22155 for (i = 0; i < outtetlist->len(); i++) {
22156 // Get an out-tet t.
22157 outtet = * (triface *)(* outtetlist)[i];
22158 // Detach t from the in-tets.
22159 for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) {
22160 // Is there an aux subface s?
22161 tspivot(outtet, auxsh);
22162 if (auxsh.sh != dummysh) {
22163 // Get the neighbor n.
22164 sym(outtet, neightet);
22165 assert(!infected(neightet)); // t must be in-tet.
22166 // Detach n -x-> t.
22167 dissolve(neightet);
22168 }
22169 }
22170 // Dealloc the tet.
22171 tetrahedrondealloc(outtet.tet);
22172 }
22173
22174 // Connect the in-tets of C to fronts. Remove aux subfaces and fake tets.
22175 for (i = 0; i < newtetlist->len(); i++) {
22176 // Get a new tet t.
22177 newtet = * (triface *)(* newtetlist)[i];
22178 // t may be an out-tet and has got deleted.
22179 if (isdead(&newtet)) continue;
22180 // t is an in-tet. Look for aux subfaces attached at t.
22181 for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
22182 // Is there an aux subface s?
22183 tspivot(newtet, auxsh);
22184 if (auxsh.sh != dummysh) {
22185 // Get the front f.
22186 decode((tetrahedron) auxsh.sh[0], front);
22187 assert((front.tet != dummytet) && !infected(front));
22188 // s has fulfilled its duty. Can be deleted.
22189 tsdissolve(newtet); // dissolve: t -x-> s.
22190 // Delete s.
22191 shellfacedealloc(subfaces, auxsh.sh);
22192 // Connect the newtet t and front f.
22193 // Is there a concrete subface c at f.
22194 tspivot(front, consh);
22195 if (consh.sh != dummysh) {
22196 sesymself(consh);
22197 // Bond: t <--> c.
22198 tsbond(newtet, consh);
22199 }
22200 // Does f hold by a fake tet.
22201 if (oppo(front) == (point) NULL) {
22202 // f is fake.
22203 if (consh.sh != dummysh) {
22204 sesymself(consh);
22205 // Dissolve: c -x-> f.
22206 stdissolve(consh);
22207 }
22208 // Dealloc f.
22209 tetrahedrondealloc(front.tet);
22210 // f becomes a hull. let 'dummytet' bond to it.
22211 dummytet[0] = encode(newtet);
22212 } else {
22213 // Bond t <--> f.
22214 bond(newtet, front);
22215 }
22216 // t may be non-locally Delaunay and flipable.
22217 if (flipque != (queue *) NULL) {
22218 enqueueflipface(newtet, flipque);
22219 }
22220 }
22221 }
22222 // Let the corners of t2 point to it for fast searching.
22223 pointptr = org(newtet);
22224 setpoint2tet(pointptr, encode(newtet));
22225 pointptr = dest(newtet);
22226 setpoint2tet(pointptr, encode(newtet));
22227 pointptr = apex(newtet);
22228 setpoint2tet(pointptr, encode(newtet));
22229 pointptr = oppo(newtet);
22230 setpoint2tet(pointptr, encode(newtet));
22231 }
22232 // The cavity has been re-tetrahedralized.
22233}
22234
22236// //
22237// delaunizecavity() Tetrahedralize a cavity by Delaunay tetrahedra. //
22238// //
22239// The cavity C is bounded by a set of triangles in 'floorlist' (a list of //
22240// coplanar subfaces) and 'ceillist' (a list of tetrahedral faces lie above //
22241// the subfaces). 'floorptlist' and 'ceilptlist' are the vertices of C. //
22242// //
22244
22245void tetgenmesh::delaunizecavity(list* floorlist, list* ceillist,
22246 list* ceilptlist, list* floorptlist, list* frontlist, list* misfrontlist,
22247 list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque)
22248{
22249 int vertnum;
22250
22251 vertnum = floorptlist->len();
22252 vertnum += (ceilptlist != (list *) NULL ? ceilptlist->len() : 0);
22253 if (b->verbose > 1) {
22254 printf(" Delaunizing cavity (%d floors, %d ceilings, %d vertices).\n",
22255 floorlist->len(), ceillist->len(), vertnum);
22256 }
22257 // Save the size of the largest cavity.
22258 if ((floorlist->len() + ceillist->len()) > maxcavfaces) {
22259 maxcavfaces = floorlist->len() + ceillist->len();
22260 }
22261 if (vertnum > maxcavverts) {
22262 maxcavverts = vertnum;
22263 }
22264
22265 // Clear these lists.
22266 frontlist->clear();
22267 misfrontlist->clear();
22268 newtetlist->clear();
22269
22270 // Initialize the cavity C.
22271 initializecavity(floorlist, ceillist, frontlist);
22272 // Form the D of the vertices of C.
22273 delaunizecavvertices(NULL, floorptlist, ceilptlist, newtetlist, flipque);
22274 // Identify faces of C in D.
22275 while (!identifyfronts(frontlist, misfrontlist, newtetlist)) {
22276 // Remove protecting subfaces, keep new tets.
22277 detachauxsubfaces(newtetlist);
22278 // Expand C and updateing D.
22279 expandcavity(frontlist, misfrontlist, newtetlist, crosstetlist,
22280 missingshqueue, flipque);
22281 }
22282 // All fronts have identified in D. Get the shape of C by removing out
22283 // tets of C. 'misfrontlist' is reused for removing out tets.
22284 carvecavity(newtetlist, misfrontlist, NULL);
22285}
22286
22288// //
22289// formmissingregion() Form the missing region. //
22290// //
22291// 'missingsh' is a missing subface. Start from it we can form the missing //
22292// region R (a set of connected missing subfaces). Because all missing sub- //
22293// faces have been marked (infected) before. R can be formed by checking the //
22294// neighbors of 'missingsh', and the neighbors of the neighbors, and so on. //
22295// Stop checking further at either a segment or an unmarked subface. //
22296// //
22297// 'missingshlist' returns R. The edge ring of subfaces of R are oriented in //
22298// the same direction. 'equatptlist' returns the vertices of R, each vertex //
22299// is marked with '1' (in 'worklist'). //
22300// //
22302
22303void tetgenmesh::formmissingregion(face* missingsh, list* missingshlist,
22304 list* equatptlist, int* worklist)
22305{
22306 face neighsh, worksh, workseg;
22307 point workpt[3];
22308 int idx, i, j;
22309
22310 // Add 'missingsh' into 'missingshlist'.
22311 missingshlist->append(missingsh);
22312 // Save and mark its three vertices.
22313 workpt[0] = sorg(*missingsh);
22314 workpt[1] = sdest(*missingsh);
22315 workpt[2] = sapex(*missingsh);
22316 for (i = 0; i < 3; i++) {
22317 idx = pointmark(workpt[i]) - in->firstnumber;
22318 worklist[idx] = 1;
22319 equatptlist->append(&workpt[i]);
22320 }
22321 // Temporarily uninfect it (avoid to save it again).
22322 suninfect(*missingsh);
22323
22324 // Find the other missing subfaces.
22325 for (i = 0; i < missingshlist->len(); i++) {
22326 // Get a missing subface.
22327 worksh = * (face *)(* missingshlist)[i];
22328 // Check three neighbors of this face.
22329 for (j = 0; j < 3; j++) {
22330 sspivot(worksh, workseg);
22331 if (workseg.sh == dummysh) {
22332 spivot(worksh, neighsh);
22333 if (sinfected(neighsh)) {
22334 // Find a missing subface, adjust the face orientation.
22335 if (sorg(neighsh) != sdest(worksh)) {
22336 sesymself(neighsh);
22337 }
22338 if (b->verbose > 2) {
22339 printf(" Add missing subface (%d, %d, %d).\n",
22340 pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
22341 pointmark(sapex(neighsh)));
22342 }
22343 missingshlist->append(&neighsh);
22344 // Save and mark its apex.
22345 workpt[0] = sapex(neighsh);
22346 idx = pointmark(workpt[0]) - in->firstnumber;
22347 // Has workpt[0] been added?
22348 if (worklist[idx] == 0) {
22349 worklist[idx] = 1;
22350 equatptlist->append(&workpt[0]);
22351 }
22352 // Temporarily uninfect it (avoid to save it again).
22353 suninfect(neighsh);
22354 }
22355 }
22356 senextself(worksh);
22357 }
22358 }
22359
22360 // R has been formed. Infect missing subfaces again.
22361 for (i = 0; i < missingshlist->len(); i++) {
22362 worksh = * (face *)(* missingshlist)[i];
22363 sinfect(worksh);
22364 }
22365}
22366
22368// //
22369// rearrangesubfaces() Rearrange the set of subfaces of a missing region //
22370// so that they conform to the faces of DT. //
22371// //
22372// The missing region formed by subfaces of 'missingshlist' contains a set //
22373// of degenerate vertices, hence the set of subfaces don't match the set of //
22374// faces in DT. Instead of forcing them to present in DT, we re-arrange the //
22375// connection of them so that the new subfaces conform to the faces of DT. //
22376// 'boundedgelist' is a set of boundary edges of the region, these edges(may //
22377// be subsegments) must exist in DT. //
22378// //
22379// On completion, we have created and inserted a set of new subfaces which //
22380// conform to faces of DT. The set of old subfaces in 'missingshlist' are //
22381// deleted. The region vertices in 'equatptlist' are unmarked. //
22382// //
22384
22385void tetgenmesh::rearrangesubfaces(list* missingshlist, list* boundedgelist,
22386 list* equatptlist, int* worklist)
22387{
22388 link *boundedgelink;
22389 link *newshlink;
22390 triface starttet, spintet, neightet, worktet;
22391 face shloop, newsh, neighsh, spinsh, worksh;
22392 face workseg, casingin, casingout;
22393 point torg, tdest, workpt;
22394 point spt1, spt2, spt3;
22395 enum finddirectionresult collinear;
22396 enum shestype shtype;
22397 REAL area;
22398 bool matchflag, finishflag;
22399 int shmark, pbcgp, idx, hitbdry;
22400 int i, j;
22401
22402 // Initialize the boundary edge link.
22403 boundedgelink = new link(sizeof(face), NULL, 256);
22404 // Initialize the new subface link.
22405 newshlink = new link(sizeof(face), NULL, 256);
22406 // Remember the type (skinny or not) of replaced subfaces. They should
22407 // all have the same type since there is no segment inside the region.
22408 worksh = * (face *)(* missingshlist)[0];
22409 shtype = shelltype(worksh);
22410 // The following loop is only for checking purpose.
22411 for (i = 1; i < missingshlist->len(); i++) {
22412 worksh = * (face *)(* missingshlist)[i];
22413 assert(shelltype(worksh) == shtype);
22414 }
22415 // To avoid compilation warnings.
22416 shmark = pbcgp = 0;
22417 area = 0.0;
22418
22419 // Create an initial boundary link.
22420 for (i = 0; i < boundedgelist->len(); i++) {
22421 shloop = * (face *)(* boundedgelist)[i];
22422 if (i == 0) {
22423 // 'shmark' will be set to all new created subfaces.
22424 shmark = shellmark(shloop);
22425 if (b->quality && varconstraint) {
22426 // area will be copied to all new created subfaces.
22427 area = areabound(shloop);
22428 }
22429 if (checkpbcs) {
22430 // pbcgp will be copied to all new created subfaces.
22431 pbcgp = shellpbcgroup(shloop);
22432 }
22433 // Get the abovepoint of this facet.
22434 abovepoint = facetabovepointarray[shellmark(shloop)];
22435 if (abovepoint == (point) NULL) {
22436 getfacetabovepoint(&shloop);
22437 }
22438 }
22439 sspivot(shloop, workseg);
22440 if (workseg.sh == dummysh) {
22441 // This edge is an interior edge.
22442 spivot(shloop, neighsh);
22443 boundedgelink->add(&neighsh);
22444 } else {
22445 // This side has a segment, the edge exists.
22446 boundedgelink->add(&shloop);
22447 }
22448 }
22449
22450 // Each edge ab of boundedgelink will be finished by finding a vertex c
22451 // which is a vertex of the missing region, such that:
22452 // (1) abc is inside the missing region, i.e., abc intersects at least
22453 // one of missing subfaces (saved in missingshlist);
22454 // (2) abc is not intersect with any previously created new subfaces
22455 // in the missing region (saved in newshlink).
22456 // After abc is created, it will be inserted into both the surface mesh
22457 // and the DT. The boundedgelink will be updated, ab is removed, bc and
22458 // ca will be added if they are open.
22459
22460 while (boundedgelink->len() > 0) {
22461 // Remove an edge (ab) from the link.
22462 shloop = * (face *) boundedgelink->del(1);
22463 // 'workseg' indicates it is a segment or not.
22464 sspivot(shloop, workseg);
22465 torg = sorg(shloop); // torg = a;
22466 tdest = sdest(shloop); // tdest = b;
22467 // Find a tetrahedron containing ab.
22468 getsearchtet(torg, tdest, &starttet, &workpt);
22469 collinear = finddirection(&starttet, workpt, tetrahedrons->items);
22470 if (collinear == LEFTCOLLINEAR) {
22471 enext2self(starttet);
22472 esymself(starttet);
22473 } else if (collinear == TOPCOLLINEAR) {
22474 fnextself(starttet);
22475 enext2self(starttet);
22476 esymself(starttet);
22477 }
22478 assert(dest(starttet) == workpt);
22479 // Checking faces around ab until a valid face is found.
22480 matchflag = false;
22481 spintet = starttet;
22482 hitbdry = 0;
22483 do {
22484 workpt = apex(spintet);
22485 idx = pointmark(workpt) - in->firstnumber;
22486 if (worklist[idx] == 1) {
22487 // (trog, tdest, workpt) is on the facet. Check if it satisfies (1).
22488 finishflag = false;
22489 for (i = 0; i < missingshlist->len(); i++) {
22490 worksh = * (face *)(* missingshlist)[i];
22491 spt1 = sorg(worksh);
22492 spt2 = sdest(worksh);
22493 spt3 = sapex(worksh);
22494 // Does bc intersect the face?
22495 if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint)
22496 == INTERSECT) {
22497 finishflag = true; break;
22498 }
22499 // Does ca intersect the face?
22500 if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint)
22501 == INTERSECT) {
22502 finishflag = true; break;
22503 }
22504 // Does c inside the face?
22505 if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint)
22506 == INTERSECT) {
22507 finishflag = true; break;
22508 }
22509 }
22510 if (finishflag) {
22511 // Satisfying (1). Check if it satisfies (2).
22512 matchflag = true;
22513 for (i = 0; i < newshlink->len() && matchflag; i++) {
22514 worksh = * (face *) newshlink->getnitem(i + 1);
22515 spt1 = sorg(worksh);
22516 spt2 = sdest(worksh);
22517 spt3 = sapex(worksh);
22518 // Does bc intersect the face?
22519 if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint)
22520 == INTERSECT) {
22521 matchflag = false; break;
22522 }
22523 // Does ca intersect the face?
22524 if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint)
22525 == INTERSECT) {
22526 matchflag = false; break;
22527 }
22528 // Does c inside the face?
22529 if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint)
22530 == INTERSECT) {
22531 matchflag = false; break;
22532 }
22533 }
22534 }
22535 if (matchflag == true) {
22536 // Satisfying both (1) and (2). Find abc.
22537 break;
22538 }
22539 }
22540 if (!fnextself(spintet)) {
22541 hitbdry ++;
22542 if (hitbdry < 2) {
22543 esym(starttet, spintet);
22544 if (!fnextself(spintet)) {
22545 hitbdry ++;
22546 }
22547 }
22548 }
22549 } while (hitbdry < 2 && apex(spintet) != apex(starttet));
22550 assert(matchflag == true);
22551 tspivot(spintet, neighsh);
22552 if (neighsh.sh != dummysh) {
22553 printf("Error: Invalid PLC.\n");
22554 printf(" Facet #%d and facet #%d overlap each other.\n",
22555 shellmark(neighsh), shellmark(shloop));
22556 printf(" It might be caused by a facet is defined more than once.\n");
22557 printf(" Hint: Use -d switch to find all overlapping facets.\n");
22558 exit(1);
22559 }
22560 // The side of 'spintet' is at which a new subface will be attached.
22561 adjustedgering(spintet, CCW);
22562 // Create the new subface.
22563 makeshellface(subfaces, &newsh);
22564 setsorg(newsh, org(spintet));
22565 setsdest(newsh, dest(spintet));
22566 setsapex(newsh, apex(spintet));
22567 if (b->quality && varconstraint) {
22568 setareabound(newsh, area);
22569 }
22570 if (checkpbcs) {
22571 setshellpbcgroup(newsh, pbcgp);
22572 }
22573 setshellmark(newsh, shmark);
22574 setshelltype(newsh, shtype); // It may be a skinny subface.
22575 // Add newsh into newshlink for intersecting checking.
22576 newshlink->add(&newsh);
22577 // Insert it into the current mesh.
22578 tsbond(spintet, newsh);
22579 sym(spintet, neightet);
22580 if (neightet.tet != dummytet) {
22581 sesym(newsh, neighsh);
22582 tsbond(neightet, neighsh);
22583 }
22584 // Insert it into the surface mesh.
22585 sspivot(shloop, workseg);
22586 if (workseg.sh == dummysh) {
22587 sbond(shloop, newsh);
22588 } else {
22589 // There is a subsegment, 'shloop' is the subface which is going to
22590 // die. Insert the 'newsh' at the place of 'shloop' into its face
22591 // link, so as to dettach 'shloop'. The original connection is:
22592 // -> casingin -> shloop -> casingout ->, it will be changed with:
22593 // -> casingin -> newsh -> casingout ->. Pay attention to the
22594 // case when this subsegment is dangling in the mesh, i.e., 'shloop'
22595 // is bonded to itself.
22596 spivot(shloop, casingout);
22597 if (shloop.sh != casingout.sh) {
22598 // 'shloop' is not bonded to itself.
22599 spinsh = casingout;
22600 do {
22601 casingin = spinsh;
22602 spivotself(spinsh);
22603 } while (sapex(spinsh) != sapex(shloop));
22604 assert(casingin.sh != shloop.sh);
22605 // Bond casingin -> newsh -> casingout.
22606 sbond1(casingin, newsh);
22607 sbond1(newsh, casingout);
22608 } else {
22609 // Bond newsh -> newsh.
22610 sbond(newsh, newsh);
22611 }
22612 // Bond the segment.
22613 ssbond(newsh, workseg);
22614 }
22615 // Check other two sides of this new subface. If a side is not bonded
22616 // to any edge in the link, it will be added to the link.
22617 for (i = 0; i < 2; i++) {
22618 if (i == 0) {
22619 senext(newsh, worksh);
22620 } else {
22621 senext2(newsh, worksh);
22622 }
22623 torg = sorg(worksh);
22624 tdest = sdest(worksh);
22625 finishflag = false;
22626 for (j = 0; j < boundedgelink->len() && !finishflag; j++) {
22627 neighsh = * (face *) boundedgelink->getnitem(j + 1);
22628 if ((sorg(neighsh) == torg && sdest(neighsh) == tdest) ||
22629 (sorg(neighsh) == tdest && sdest(neighsh) == torg)) {
22630 // Find a boundary edge. Bond them and exit the loop.
22631 sspivot(neighsh, workseg);
22632 if (workseg.sh == dummysh) {
22633 sbond(neighsh, worksh);
22634 } else {
22635 // There is a subsegment, 'neighsh' is the subface which is
22636 // going to die. Do the same as above for 'worksh'.
22637 spivot(neighsh, casingout);
22638 if (neighsh.sh != casingout.sh) {
22639 // 'neighsh' is not bonded to itself.
22640 spinsh = casingout;
22641 do {
22642 casingin = spinsh;
22643 spivotself(spinsh);
22644 } while (sapex(spinsh) != sapex(neighsh));
22645 assert(casingin.sh != neighsh.sh);
22646 // Bond casingin -> worksh -> casingout.
22647 sbond1(casingin, worksh);
22648 sbond1(worksh, casingout);
22649 } else {
22650 // Bond worksh -> worksh.
22651 sbond(worksh, worksh);
22652 }
22653 // Bond the segment.
22654 ssbond(worksh, workseg);
22655 }
22656 // Remove this boundary edge from the link.
22657 boundedgelink->del(j + 1);
22658 finishflag = true;
22659 }
22660 }
22661 if (!finishflag) {
22662 // It's a new boundary edge, add it to link.
22663 boundedgelink->add(&worksh);
22664 }
22665 }
22666 }
22667
22668 // Deallocate the set of old missing subfaces.
22669 for (i = 0; i < missingshlist->len(); i++) {
22670 worksh = * (face *)(* missingshlist)[i];
22671 shellfacedealloc(subfaces, worksh.sh);
22672 }
22673 // Unmark region vertices in 'worklist'.
22674 for (i = 0; i < equatptlist->len(); i++) {
22675 workpt = * (point *)(* equatptlist)[i];
22676 idx = pointmark(workpt) - in->firstnumber;
22677 worklist[idx] = 0;
22678 }
22679
22680 delete boundedgelink;
22681 delete newshlink;
22682}
22683
22685// //
22686// scoutcrossingedge() Search an edge crossing the missing region. //
22687// //
22688// 'missingshlist' forms the missing region R. This routine searches for an //
22689// edge crossing R. It first forms a 'boundedgelist' consisting of the //
22690// boundary edges of R. Such edges are existing in CDT. A crossing edge is //
22691// found by rotating faces around one of the boundary edges. It is possible //
22692// there is no edge crosses R (e.g. R has a degenerate point set). //
22693// //
22694// If find a croosing edge, return TRUE, 'crossedgelist' contains this edge. //
22695// Otherwise, return FALSE. //
22696// //
22698
22699bool tetgenmesh::scoutcrossingedge(list* missingshlist, list* boundedgelist,
22700 list* crossedgelist, int* worklist)
22701{
22702 triface starttet, spintet, worktet;
22703 face startsh, neighsh, worksh, workseg;
22704 point torg, tdest, tapex;
22705 point workpt[3], pa, pb, pc;
22706 enum finddirectionresult collinear;
22707 REAL ori1, ori2;
22708 bool crossflag;
22709 int hitbdry;
22710 int i, j, k;
22711
22712 // Form the 'boundedgelist'. Loop through 'missingshlist', check each
22713 // edge of these subfaces. If an edge is a segment or the neighbor
22714 // subface is uninfected, add it to 'boundedgelist'.
22715 for (i = 0; i < missingshlist->len(); i++) {
22716 worksh = * (face *)(* missingshlist)[i];
22717 for (j = 0; j < 3; j++) {
22718 sspivot(worksh, workseg);
22719 if (workseg.sh == dummysh) {
22720 spivot(worksh, neighsh);
22721 if (!sinfected(neighsh)) {
22722 boundedgelist->append(&worksh);
22723 }
22724 } else {
22725 boundedgelist->append(&worksh);
22726 }
22727 senextself(worksh);
22728 }
22729 }
22730
22731 crossflag = false;
22732 // Find a crossing edge. It is possible there is no such edge. We need to
22733 // loop through all edges of 'boundedgelist' for sure we don't miss any.
22734 for (i = 0; i < boundedgelist->len() && !crossflag; i++) {
22735 startsh = * (face *)(* boundedgelist)[i];
22736 // 'startsh' (abc) holds an existing edge of the DT, find it.
22737 torg = sorg(startsh);
22738 tdest = sdest(startsh);
22739 tapex = sapex(startsh);
22740 getsearchtet(torg, tdest, &starttet, &workpt[0]);
22741 collinear = finddirection(&starttet, workpt[0], tetrahedrons->items);
22742 if (collinear == LEFTCOLLINEAR) {
22743 enext2self(starttet);
22744 esymself(starttet);
22745 } else if (collinear == TOPCOLLINEAR) {
22746 fnextself(starttet);
22747 enext2self(starttet);
22748 esymself(starttet);
22749 }
22750#ifdef SELF_CHECK
22751 assert(dest(starttet) == workpt[0]);
22752#endif
22753 // Now starttet holds edge ab. Find is edge de crossing R.
22754 spintet = starttet;
22755 hitbdry = 0;
22756 do {
22757 if (fnextself(spintet)) {
22758 // splittet = abde. Check if de crosses abc.
22759 workpt[1] = apex(spintet); // workpt[1] = d.
22760 workpt[2] = oppo(spintet); // workpt[2] = e.
22761 j = pointmark(workpt[1]) - in->firstnumber;
22762 k = pointmark(workpt[2]) - in->firstnumber;
22763 if (worklist[j] == 1) {
22764 ori1 = 0.0; // d is a vertex of the missing region.
22765 } else {
22766 // Get the orientation of d wrt. abc.
22767 ori1 = orient3d(torg, tdest, tapex, workpt[1]);
22768 }
22769 if (worklist[k] == 1) {
22770 ori2 = 0.0; // e is a vertex of the missing region.
22771 } else {
22772 // Get the orientation of e wrt. abc.
22773 ori2 = orient3d(torg, tdest, tapex, workpt[2]);
22774 }
22775 // Only do check if d and e locate on different sides of abc.
22776 if (ori1 * ori2 < 0.0) {
22777 // Check if de crosses any subface of R.
22778 for (j = 0; j < missingshlist->len(); j++) {
22779 worksh = * (face *)(* missingshlist)[j];
22780 pa = sorg(worksh);
22781 pb = sdest(worksh);
22782 pc = sapex(worksh);
22783 crossflag = (tri_tri_inter(pa, pb, pc, workpt[0], workpt[1],
22784 workpt[2]) == INTERSECT);
22785 if (crossflag) {
22786 // Find a crossing edge. We're done.
22787 worktet = spintet;
22788 adjustedgering(worktet, CCW);
22789 enextfnextself(worktet);
22790 enextself(worktet);
22791 // Add this edge (worktet) into 'crossedgelist'.
22792 crossedgelist->append(&worktet);
22793 break;
22794 }
22795 }
22796 if (crossflag) break;
22797 }
22798 if (apex(spintet) == apex(starttet)) break;
22799 } else {
22800 hitbdry++;
22801 // It is only possible to hit boundary once.
22802 if (hitbdry < 2) {
22803 esym(starttet, spintet);
22804 }
22805 }
22806 } while (hitbdry < 2);
22807 }
22808
22809 return crossflag;
22810}
22811
22813// //
22814// formcavity() Form the cavity for recovering the missing region. //
22815// //
22816// The cavity C is bounded by faces of current CDT. All tetrahedra inside C //
22817// will be removed, intead a set of constrained Delaunay tetrahedra will be //
22818// filled in and the missing region are recovered. //
22819// //
22820// 'missingshlist' contains a set of subfaces forming the missing region R. //
22821// C is formed by first finding all the tetrahedra in CDT that intersect the //
22822// relative interior of R; then deleting them from the CDT, this will form C //
22823// inside the CDT. At the beginning, 'crossedgelist' contains an edge which //
22824// is crossing R. All tets containing this edge must cross R. Start from it, //
22825// other crossing edges can be found incrementally. The discovered crossing //
22826// tets are saved in 'crosstetlist'. //
22827// //
22828// Notice that not all tets in 'crosstetlist' are crossing R. The discovered //
22829// tets are connected each other. However, there may be other tets crossing //
22830// R but disjoint with the found tets. Due to this fact we need to check the //
22831// 'missingshlist' once more. Only recover those subfaces which are crossed //
22832// by the set of discovered tets, i.e., R may be shrinked to conform the set //
22833// of discovered tets. The extra subfaces of R will be recovered later. //
22834// //
22835// Notice that some previous recovered subfaces may completely included in C.//
22836// This can happen when R is very big and these subfaces lie above R and so //
22837// close to it. Such subfaces have to be queued (and sinfected()) to recover //
22838// them later. Otherwise, we lost the connection to these subfaces forever. //
22839// //
22841
22842void tetgenmesh::formcavity(list* missingshlist, list* crossedgelist,
22843 list* equatptlist, list* crossshlist, list* crosstetlist,
22844 list* belowfacelist, list* abovefacelist, list* horizptlist,
22845 list* belowptlist, list* aboveptlist, queue* missingshqueue, int* worklist)
22846{
22847 triface starttet, spintet, neightet, worktet;
22848 face startsh, neighsh, worksh, workseg;
22849 point torg, tdest, tapex, workpt[3];
22850 REAL checksign, orgori, destori;
22851 bool crossflag, inlistflag;
22852 bool belowflag, aboveflag;
22853 int idx, share;
22854 int i, j, k;
22855
22856 // Get a face at horizon.
22857 startsh = * (face *)(* missingshlist)[0];
22858 torg = sorg(startsh);
22859 tdest = sdest(startsh);
22860 tapex = sapex(startsh);
22861
22862 // Collect the set of crossing tetrahedra by rotating crossing edges.
22863 for (i = 0; i < crossedgelist->len(); i++) {
22864 // Get a tet abcd, ab is a crossing edge.
22865 starttet = * (triface *)(* crossedgelist)[i];
22866 adjustedgering(starttet, CCW);
22867 if (b->verbose > 2) {
22868 printf(" Collect tets containing edge (%d, %d).\n",
22869 pointmark(org(starttet)), pointmark(dest(starttet)));
22870 }
22871 orgori = orient3d(torg, tdest, tapex, org(starttet));
22872 destori = orient3d(torg, tdest, tapex, dest(starttet));
22873 UNUSED_OPT(destori);
22874#ifdef SELF_CHECK
22875 assert(orgori * destori < 0.0);
22876#endif
22877 spintet = starttet;
22878 do {
22879 // The face rotation should not meet boundary.
22880 fnextself(spintet);
22881 // Check the validity of the PLC.
22882 tspivot(spintet, worksh);
22883 if (worksh.sh != dummysh) {
22884 printf("Error: Invalid PLC.\n");
22885 printf(" Two subfaces (%d, %d, %d) and (%d, %d, %d)\n",
22886 pointmark(torg), pointmark(tdest), pointmark(tapex),
22887 pointmark(sorg(worksh)), pointmark(sdest(worksh)),
22888 pointmark(sapex(worksh)));
22889 printf(" are found intersecting each other.\n");
22890 printf(" Hint: Use -d switch to find all intersecting facets.\n");
22891 terminatetetgen(1);
22892 }
22893 if (!infected(spintet)) {
22894 if (b->verbose > 2) {
22895 printf(" Add crossing tet (%d, %d, %d, %d).\n",
22896 pointmark(org(spintet)), pointmark(dest(spintet)),
22897 pointmark(apex(spintet)), pointmark(oppo(spintet)));
22898 }
22899 infect(spintet);
22900 crosstetlist->append(&spintet);
22901 }
22902 // Check whether other two edges of 'spintet' is a crossing edge.
22903 // It can be quickly checked from the apex of 'spintet', if it is
22904 // not on the facet, then there exists a crossing edge.
22905 workpt[0] = apex(spintet);
22906 idx = pointmark(workpt[0]) - in->firstnumber;
22907 if (worklist[idx] != 1) {
22908 // Either edge (dest, apex) or edge (apex, org) crosses.
22909 checksign = orient3d(torg, tdest, tapex, workpt[0]);
22910#ifdef SELF_CHECK
22911 assert(checksign != 0.0);
22912#endif
22913 if (checksign * orgori < 0.0) {
22914 enext2(spintet, worktet); // edge (apex, org).
22915 workpt[1] = org(spintet);
22916 } else {
22917//#ifdef SELF_CHECK // commented out to get gcc 4.6 working
22918 assert(checksign * destori < 0.0);
22919//#endif
22920 enext(spintet, worktet); // edge (dest, apex).
22921 workpt[1] = dest(spintet);
22922 }
22923 // 'worktet' represents the crossing edge. Add it into list only
22924 // it doesn't exist in 'crossedgelist'.
22925 inlistflag = false;
22926 for (j = 0; j < crossedgelist->len() && !inlistflag; j++) {
22927 neightet = * (triface *)(* crossedgelist)[j];
22928 if (org(neightet) == workpt[0]) {
22929 if (dest(neightet) == workpt[1]) inlistflag = true;
22930 } else if (org(neightet) == workpt[1]) {
22931 if (dest(neightet) == workpt[0]) inlistflag = true;
22932 }
22933 }
22934 if (!inlistflag) {
22935 crossedgelist->append(&worktet);
22936 }
22937 }
22938 } while (apex(spintet) != apex(starttet));
22939 }
22940
22941 // Identifying the boundary faces and vertices of C. Sort them into
22942 // 'abovefacelist', 'aboveptlist, 'belowfacelist', and 'belowptlist',
22943 // respectively. "above" and "below" are wrt.(torg, tdest, tapex).
22944 for (i = 0; i < crosstetlist->len(); i++) {
22945 // Get a tet abcd, ab is the crossing edge.
22946 starttet = * (triface *)(* crosstetlist)[i];
22947#ifdef SELF_CHECK
22948 assert(infected(starttet));
22949#endif
22950 adjustedgering(starttet, CCW);
22951 // abc and abd are sharing the crossing edge, the two neighbors must
22952 // be crossing tetrahedra too. They can't be boundaries of C.
22953 for (j = 0; j < 2; j++) {
22954 if (j == 0) {
22955 enextfnext(starttet, worktet); // Check bcd.
22956 } else {
22957 enext2fnext(starttet, worktet); // Check acd.
22958 }
22959 sym(worktet, neightet);
22960 // If the neighbor doesn't exist or exists but doesn't be infected,
22961 // it's a boundary face of C, save it.
22962 if ((neightet.tet == dummytet) || !infected(neightet)) {
22963 workpt[0] = org(worktet);
22964 workpt[1] = dest(worktet);
22965 workpt[2] = apex(worktet);
22966 belowflag = aboveflag = false;
22967 share = 0;
22968 for (k = 0; k < 3; k++) {
22969 idx = pointmark(workpt[k]) - in->firstnumber;
22970 if (worklist[idx] == 0) {
22971 // It's not a vertices of facet, find which side it lies.
22972 checksign = orient3d(torg, tdest, tapex, workpt[k]);
22973#ifdef SELF_CHECK
22974 assert(checksign != 0.0);
22975#endif
22976 if (checksign > 0.0) {
22977 // It lies "below" the facet wrt. 'startsh'.
22978 worklist[idx] = 2;
22979 belowptlist->append(&workpt[k]);
22980 } else if (checksign < 0.0) {
22981 // It lies "above" the facet wrt. 'startsh'.
22982 worklist[idx] = 3;
22983 aboveptlist->append(&workpt[k]);
22984 }
22985 }
22986 if (worklist[idx] == 2) {
22987 // This face lies "below" the facet wrt. 'startsh'.
22988 belowflag = true;
22989 } else if (worklist[idx] == 3) {
22990 // This face lies "above" the facet wrt. 'startsh'.
22991 aboveflag = true;
22992 } else {
22993#ifdef SELF_CHECK
22994 // In degenerate case, this face may just be the equator.
22995 assert(worklist[idx] == 1);
22996#endif
22997 share++;
22998 }
22999 }
23000#ifdef SELF_CHECK
23001 // The degenerate case has been ruled out.
23002 assert(share < 3);
23003 // Only one flag is possible for a cavity face.
23004 assert(belowflag ^ aboveflag);
23005#endif
23006 if (belowflag) {
23007 belowfacelist->append(&worktet);
23008 } else if (aboveflag) {
23009 abovefacelist->append(&worktet);
23010 }
23011 }
23012 }
23013 }
23014
23015 // Shrink R if not all its subfaces are crossing by the discovered tets.
23016 // 'crossshlist' and 'horizptlist' represent the set of subfaces and
23017 // vertices of the shrinked missing region, respectively.
23018 for (i = 0; i < missingshlist->len(); i++) {
23019 worksh = * (face *)(* missingshlist)[i];
23020#ifdef SELF_CHECK
23021 assert(sinfected(worksh));
23022#endif
23023 workpt[0] = sorg(worksh);
23024 workpt[1] = sdest(worksh);
23025 workpt[2] = sapex(worksh);
23026 crossflag = false;
23027 for (j = 0; j < crosstetlist->len() && !crossflag; j++) {
23028 // Get a tet abcd, ab is a crossing edge.
23029 starttet = * (triface *)(* crosstetlist)[j];
23030 adjustedgering(starttet, CCW);
23031 // Only need to check two sides of worktet.
23032 for (k = 0; k < 2 && !crossflag; k++) {
23033 if (k == 0) {
23034 worktet = starttet; // Check abc.
23035 } else {
23036 fnext(starttet, worktet); // Check abd.
23037 }
23038 crossflag = tritritest(&worktet, workpt[0], workpt[1], workpt[2]);
23039 }
23040 }
23041 if (crossflag) {
23042 // 'worksh' is crossed by 'worktet', uninfect it.
23043 suninfect(worksh);
23044 crossshlist->append(&worksh);
23045 // Add its corners into 'horizptlist'.
23046 for (k = 0; k < 3; k++) {
23047 idx = pointmark(workpt[k]) - in->firstnumber;
23048 if (worklist[idx] != 4) {
23049 worklist[idx] = 4;
23050 horizptlist->append(&workpt[k]);
23051 }
23052 }
23053 }
23054 }
23055
23056 // Check 'crossingtetlist'. Queue subfaces inside them.
23057 for (i = 0; i < crosstetlist->len(); i++) {
23058 starttet = * (triface *)(* crosstetlist)[i];
23059 for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
23060 sym(starttet, neightet);
23061 // If the neighbor exist and is infected, check it.
23062 if ((neightet.tet != dummytet) && infected(neightet)) {
23063 tspivot(starttet, worksh);
23064 if (worksh.sh != dummysh) {
23065 // Temporarily remove worksh. Make it missing. recover it later.
23066 if (b->verbose > 2) {
23067 printf(" Queuing subface (%d, %d, %d).\n",
23068 pointmark(sorg(worksh)), pointmark(sdest(worksh)),
23069 pointmark(sapex(worksh)));
23070 }
23071 tsdissolve(neightet);
23072 tsdissolve(starttet);
23073 // Detach tets at the both sides of this subface.
23074 stdissolve(worksh);
23075 sesymself(worksh);
23076 stdissolve(worksh);
23077 sinfect(worksh);
23078 missingshqueue->push(&worksh);
23079 }
23080 }
23081 }
23082 }
23083
23084 // Clear flags set in 'worklist'.
23085 for (i = 0; i < equatptlist->len(); i++) {
23086 workpt[0] = * (point *)(* equatptlist)[i];
23087 idx = pointmark(workpt[0]) - in->firstnumber;
23088#ifdef SELF_CHECK
23089 assert((worklist[idx] == 1) || (worklist[idx] == 4));
23090#endif
23091 worklist[idx] = 0;
23092 }
23093 for (i = 0; i < belowptlist->len(); i++) {
23094 workpt[0] = * (point *)(* belowptlist)[i];
23095 idx = pointmark(workpt[0]) - in->firstnumber;
23096#ifdef SELF_CHECK
23097 assert(worklist[idx] == 2);
23098#endif
23099 worklist[idx] = 0;
23100 }
23101 for (i = 0; i < aboveptlist->len(); i++) {
23102 workpt[0] = * (point *)(* aboveptlist)[i];
23103 idx = pointmark(workpt[0]) - in->firstnumber;
23104#ifdef SELF_CHECK
23105 assert(worklist[idx] == 3);
23106#endif
23107 worklist[idx] = 0;
23108 }
23109}
23110
23112// //
23113// insertallsubfaces() Insert all subfaces, queue missing subfaces. //
23114// //
23115// Loop through all subfaces, insert each into the DT. If one already exists,//
23116// bond it to the tetrahedra having it. Otherwise, it is missing, infect it //
23117// and save it in 'missingshqueue'. //
23118// //
23120
23121void tetgenmesh::insertallsubfaces(queue* missingshqueue)
23122{
23123 triface searchtet;
23124 face subloop;
23125
23126 searchtet.tet = (tetrahedron *) NULL;
23127 subfaces->traversalinit();
23128 subloop.sh = shellfacetraverse(subfaces);
23129 while (subloop.sh != (shellface *) NULL) {
23130 if (!insertsubface(&subloop, &searchtet)) {
23131 if (b->verbose > 1) {
23132 printf(" Queuing subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
23133 pointmark(sdest(subloop)), pointmark(sapex(subloop)));
23134 }
23135 sinfect(subloop);
23136 missingshqueue->push(&subloop);
23137 }
23138 subloop.sh = shellfacetraverse(subfaces);
23139 }
23140}
23141
23143// //
23144// constrainedfacets() Recover subfaces in a Delaunay tetrahedralization. //
23145// //
23146// This routine creates a CDT by incrementally updating a DT D into a CDT T. //
23147// The process of recovering facets can be imagined by "merging" the surface //
23148// mesh F into D. At the beginning, F and D are completely seperated. Some //
23149// faces of them are matching some are not because they are crossed by some //
23150// tetrahedra of D. The non-matching subfaces will be forced to appear in T //
23151// by locally retetrahedralizing the regions where F and D are intersecting. //
23152// //
23153// When a subface s of F is found missing in D, probably some other subfaces //
23154// near to s are missing too. The set of adjoining coplanar missing faces //
23155// forms a missing region R (R may not simply connected). //
23156// //
23157// There are two possibilities can result a mssing region R: (1) Some edges //
23158// of D cross R; (2) No edge of D crosses R, but some faces of D spans R, ie,//
23159// D is locally degenerate at R. In case (1), D is modified so that it resp- //
23160// ects R (done by a cavity retetrahedralization algorithm). In case (2), F //
23161// is modified so that the set of subfaces of R matches faces in D (done by //
23162// a face rearrangment algorithm). //
23163// //
23165
23166void tetgenmesh::constrainedfacets()
23167{
23168 queue *missingshqueue, *flipque;
23169 list *missingshlist, *equatptlist;
23170 list *boundedgelist, *crossedgelist, *crosstetlist;
23171 list *crossshlist, *belowfacelist, *abovefacelist;
23172 list *horizptlist, *belowptlist, *aboveptlist;
23173 list *frontlist, *misfrontlist, *newtetlist;
23174 triface searchtet, worktet;
23175 face subloop, worksh;
23176 int *worklist;
23177 int i;
23178
23179 if (!b->quiet) {
23180 printf("Constraining facets.\n");
23181 }
23182
23183 // Initialize queues.
23184 missingshqueue = new queue(sizeof(face));
23185 flipque = new queue(sizeof(badface));
23186 // Initialize the working lists.
23187 missingshlist = new list(sizeof(face), NULL);
23188 boundedgelist = new list(sizeof(face), NULL);
23189 crossedgelist = new list(sizeof(triface), NULL);
23190 equatptlist = new list((char*) "point *");
23191 crossshlist = new list(sizeof(face), NULL);
23192 crosstetlist = new list(sizeof(triface), NULL);
23193 belowfacelist = new list(sizeof(triface), NULL);
23194 abovefacelist = new list(sizeof(triface), NULL);
23195 horizptlist = new list((char*)"point *");
23196 belowptlist = new list((char*)"point *");
23197 aboveptlist = new list((char*)"point *");
23198 frontlist = new list(sizeof(triface), NULL);
23199 misfrontlist = new list(sizeof(triface), NULL);
23200 newtetlist = new list(sizeof(triface), NULL);
23201 // Initialize the array for marking vertices.
23202 worklist = new int[points->items + 1];
23203 for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
23204
23205 // Compute a mapping from points to tetrahedra for fast searching.
23206 makepoint2tetmap();
23207
23208 // Match subfaces in D, queue all missing subfaces.
23209 insertallsubfaces(missingshqueue);
23210
23211 // Recover all missing subfaces.
23212 while (!missingshqueue->empty()) {
23213 // Get a queued face s.
23214 subloop = * (face *) missingshqueue->pop();
23215 // s may have been deleted in a face rearrangment operation.
23216 if (isdead(&subloop)) continue;
23217 // s may have been recovered in a previous missing region.
23218 if (!sinfected(subloop)) continue;
23219 // s may match a face in D now due to previous transformations.
23220 if (insertsubface(&subloop, &searchtet)) {
23221 suninfect(subloop);
23222 continue;
23223 }
23224 if (b->verbose > 1) {
23225 printf(" Recover subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
23226 pointmark(sdest(subloop)), pointmark(sapex(subloop)));
23227 }
23228 // Form the missing region R containing s.
23229 formmissingregion(&subloop, missingshlist, equatptlist, worklist);
23230 // Is R crossing by any tetrahedron?
23231 if (scoutcrossingedge(missingshlist, boundedgelist, crossedgelist,
23232 worklist)) {
23233 // Form the cavity C containing R.
23234 formcavity(missingshlist, crossedgelist, equatptlist, crossshlist,
23235 crosstetlist, belowfacelist, abovefacelist, horizptlist,
23236 belowptlist, aboveptlist, missingshqueue, worklist);
23237 // Recover the above part of C.
23238 delaunizecavity(crossshlist, abovefacelist, aboveptlist, horizptlist,
23239 frontlist, misfrontlist, newtetlist, crosstetlist,
23240 missingshqueue, flipque);
23241 // Inverse the direction of subfaces in R.
23242 for (i = 0; i < crossshlist->len(); i++) {
23243 worksh = * (face *)(* crossshlist)[i];
23244 sesymself(worksh);
23245 * (face *)(* crossshlist)[i] = worksh;
23246 }
23247 // Recover the below part of C.
23248 delaunizecavity(crossshlist, belowfacelist, belowptlist, horizptlist,
23249 frontlist, misfrontlist, newtetlist, crosstetlist,
23250 missingshqueue, flipque);
23251 // Delete tetrahedra in C.
23252 for (i = 0; i < crosstetlist->len(); i++) {
23253 worktet = * (triface *)(* crosstetlist)[i];
23254 tetrahedrondealloc(worktet.tet);
23255 }
23256 // There may have some un-recovered subfaces of R. Put them back into
23257 // queue. Otherwise, they will be missing on the boundary.
23258 for (i = 0; i < missingshlist->len(); i++) {
23259 worksh = * (face *)(* missingshlist)[i];
23260 if (sinfected(worksh)) {
23261 // An unrecovered subface, put it back into queue.
23262 missingshqueue->push(&worksh);
23263 }
23264 }
23265 crossshlist->clear();
23266 belowfacelist->clear();
23267 abovefacelist->clear();
23268 horizptlist->clear();
23269 belowptlist->clear();
23270 aboveptlist->clear();
23271 crosstetlist->clear();
23272 } else {
23273 // No. Rearrange subfaces of F conforming to that of D in R. It can
23274 // happen when the facet has non-coplanar vertices.
23275 rearrangesubfaces(missingshlist, boundedgelist, equatptlist, worklist);
23276 }
23277 // Clear all working lists.
23278 missingshlist->clear();
23279 boundedgelist->clear();
23280 crossedgelist->clear();
23281 equatptlist->clear();
23282 }
23283
23284 // Subfaces have been merged into D.
23285 checksubfaces = 1;
23286
23287 if (b->verbose > 0) {
23288 printf(" The biggest cavity: %d faces, %d vertices\n", maxcavfaces,
23289 maxcavverts);
23290 printf(" Enlarged %d times\n", expcavcount);
23291 }
23292
23293 delete missingshqueue;
23294 delete flipque;
23295 delete missingshlist;
23296 delete boundedgelist;
23297 delete crossedgelist;
23298 delete equatptlist;
23299 delete crossshlist;
23300 delete crosstetlist;
23301 delete belowfacelist;
23302 delete abovefacelist;
23303 delete horizptlist;
23304 delete belowptlist;
23305 delete aboveptlist;
23306 delete frontlist;
23307 delete misfrontlist;
23308 delete newtetlist;
23309 delete [] worklist;
23310}
23311
23312//
23313// End of facet recovery routines
23314//
23315
23316//
23317// Begin of carving out holes and concavities routines
23318//
23319
23321// //
23322// infecthull() Virally infect all of the tetrahedra of the convex hull //
23323// that are not protected by subfaces. Where there are //
23324// subfaces, set boundary markers as appropriate. //
23325// //
23326// Memorypool 'viri' is used to return all the infected tetrahedra. //
23327// //
23329
23330void tetgenmesh::infecthull(memorypool *viri)
23331{
23332 triface tetloop, tsymtet;
23333 tetrahedron **deadtet;
23334 face hullface;
23335 // point horg, hdest, hapex;
23336
23337 if (b->verbose > 0) {
23338 printf(" Marking concavities for elimination.\n");
23339 }
23340 tetrahedrons->traversalinit();
23341 tetloop.tet = tetrahedrontraverse();
23342 while (tetloop.tet != (tetrahedron *) NULL) {
23343 // Is this tetrahedron on the hull?
23344 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
23345 sym(tetloop, tsymtet);
23346 if (tsymtet.tet == dummytet) {
23347 // Is the tetrahedron protected by a subface?
23348 tspivot(tetloop, hullface);
23349 if (hullface.sh == dummysh) {
23350 // The tetrahedron is not protected; infect it.
23351 if (!infected(tetloop)) {
23352 infect(tetloop);
23353 deadtet = (tetrahedron **) viri->alloc();
23354 *deadtet = tetloop.tet;
23355 break; // Go and get next tet.
23356 }
23357 } else {
23358 // The tetrahedron is protected; set boundary markers if appropriate.
23359 if (shellmark(hullface) == 0) {
23360 setshellmark(hullface, 1);
23361 /*
23362 horg = sorg(hullface);
23363 hdest = sdest(hullface);
23364 hapex = sapex(hullface);
23365 if (pointmark(horg) == 0) {
23366 setpointmark(horg, 1);
23367 }
23368 if (pointmark(hdest) == 0) {
23369 setpointmark(hdest, 1);
23370 }
23371 if (pointmark(hapex) == 0) {
23372 setpointmark(hapex, 1);
23373 }
23374 */
23375 }
23376 }
23377 }
23378 }
23379 tetloop.tet = tetrahedrontraverse();
23380 }
23381}
23382
23384// //
23385// plague() Spread the virus from all infected tets to any neighbors not //
23386// protected by subfaces. //
23387// //
23388// This routine identifies all the tetrahedra that will die, and marks them //
23389// as infected. They are marked to ensure that each tetrahedron is added to //
23390// the virus pool only once, so the procedure will terminate. 'viri' returns //
23391// all infected tetrahedra which are outside the domian. //
23392// //
23394
23395void tetgenmesh::plague(memorypool *viri)
23396{
23397 tetrahedron **virusloop;
23398 tetrahedron **deadtet;
23399 triface testtet, neighbor;
23400 face neighsh, testseg;
23401 face spinsh, casingin, casingout;
23402 int firstdadsub;
23403 int i;
23404
23405 if (b->verbose > 0) {
23406 printf(" Marking neighbors of marked tetrahedra.\n");
23407 }
23408 firstdadsub = 0;
23409 // Loop through all the infected tetrahedra, spreading the virus to
23410 // their neighbors, then to their neighbors' neighbors.
23411 viri->traversalinit();
23412 virusloop = (tetrahedron **) viri->traverse();
23413 while (virusloop != (tetrahedron **) NULL) {
23414 testtet.tet = *virusloop;
23415 // Temporarily uninfect this tetrahedron, not necessary.
23416 uninfect(testtet);
23417 // Check each of the tetrahedron's four neighbors.
23418 for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
23419 // Find the neighbor.
23420 sym(testtet, neighbor);
23421 // Check for a shell between the tetrahedron and its neighbor.
23422 tspivot(testtet, neighsh);
23423 // Check if the neighbor is nonexistent or already infected.
23424 if ((neighbor.tet == dummytet) || infected(neighbor)) {
23425 if (neighsh.sh != dummysh) {
23426 // There is a subface separating the tetrahedron from its neighbor,
23427 // but both tetrahedra are dying, so the subface dies too.
23428 // Before deallocte this subface, dissolve the connections between
23429 // other subfaces, subsegments and tetrahedra.
23430 neighsh.shver = 0;
23431 if (!firstdadsub) {
23432 firstdadsub = 1; // Report the problem once.
23433 if (!b->quiet) {
23434 printf("Warning: Detecting an open face (%d, %d, %d).\n",
23435 pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
23436 pointmark(sapex(neighsh)));
23437 }
23438 }
23439 // For keep the same enext() direction.
23440 findedge(&testtet, sorg(neighsh), sdest(neighsh));
23441 for (i = 0; i < 3; i++) {
23442 sspivot(neighsh, testseg);
23443 if (testseg.sh != dummysh) {
23444 // A subsegment is found at this side, dissolve this subface
23445 // from the face link of this subsegment.
23446 testseg.shver = 0;
23447 spinsh = neighsh;
23448 if (sorg(spinsh) != sorg(testseg)) {
23449 sesymself(spinsh);
23450 }
23451 spivot(spinsh, casingout);
23452 if (casingout.sh == spinsh.sh) {
23453 // This is a trivial face link, only 'neighsh' itself,
23454 // the subsegment at this side is also died.
23455 shellfacedealloc(subsegs, testseg.sh);
23456 } else {
23457 spinsh = casingout;
23458 do {
23459 casingin = spinsh;
23460 spivotself(spinsh);
23461 } while (spinsh.sh != neighsh.sh);
23462 // Set the link casingin->casingout.
23463 sbond1(casingin, casingout);
23464 // Bond the subsegment anyway.
23465 ssbond(casingin, testseg);
23466 }
23467 }
23468 senextself(neighsh);
23469 enextself(testtet);
23470 }
23471 if (neighbor.tet != dummytet) {
23472 // Make sure the subface doesn't get deallocated again later
23473 // when the infected neighbor is visited.
23474 tsdissolve(neighbor);
23475 }
23476 // This subface has been separated.
23477 if (in->mesh_dim > 2) {
23478 shellfacedealloc(subfaces, neighsh.sh);
23479 } else {
23480 // Dimension is 2. keep it for output.
23481 // Dissolve tets at both sides of this subface.
23482 stdissolve(neighsh);
23483 sesymself(neighsh);
23484 stdissolve(neighsh);
23485 }
23486 }
23487 } else { // The neighbor exists and is not infected.
23488 if (neighsh.sh == dummysh) {
23489 // There is no subface protecting the neighbor, infect it.
23490 infect(neighbor);
23491 // Ensure that the neighbor's neighbors will be infected.
23492 deadtet = (tetrahedron **) viri->alloc();
23493 *deadtet = neighbor.tet;
23494 } else { // The neighbor is protected by a subface.
23495 // Remove this tetrahedron from the subface.
23496 stdissolve(neighsh);
23497 // The subface becomes a boundary. Set markers accordingly.
23498 if (shellmark(neighsh) == 0) {
23499 setshellmark(neighsh, 1);
23500 }
23501 // This side becomes hull. Update the handle in dummytet.
23502 dummytet[0] = encode(neighbor);
23503 }
23504 }
23505 }
23506 // Remark the tetrahedron as infected, so it doesn't get added to the
23507 // virus pool again.
23508 infect(testtet);
23509 virusloop = (tetrahedron **) viri->traverse();
23510 }
23511}
23512
23514// //
23515// regionplague() Spread regional attributes and/or volume constraints //
23516// (from a .poly file) throughout the mesh. //
23517// //
23518// This procedure operates in two phases. The first phase spreads an attri- //
23519// bute and/or a volume constraint through a (facet-bounded) region. The //
23520// second phase uninfects all infected tetrahedra, returning them to normal. //
23521// //
23523
23524void tetgenmesh::
23525regionplague(memorypool *regionviri, REAL attribute, REAL volume)
23526{
23527 tetrahedron **virusloop;
23528 tetrahedron **regiontet;
23529 triface testtet, neighbor;
23530 face neighsh;
23531
23532 if (b->verbose > 1) {
23533 printf(" Marking neighbors of marked tetrahedra.\n");
23534 }
23535 // Loop through all the infected tetrahedra, spreading the attribute
23536 // and/or volume constraint to their neighbors, then to their neighbors'
23537 // neighbors.
23538 regionviri->traversalinit();
23539 virusloop = (tetrahedron **) regionviri->traverse();
23540 while (virusloop != (tetrahedron **) NULL) {
23541 testtet.tet = *virusloop;
23542 // Temporarily uninfect this tetrahedron, not necessary.
23543 uninfect(testtet);
23544 if (b->regionattrib) {
23545 // Set an attribute.
23546 setelemattribute(testtet.tet, in->numberoftetrahedronattributes,
23547 attribute);
23548 }
23549 if (b->varvolume) {
23550 // Set a volume constraint.
23551 setvolumebound(testtet.tet, volume);
23552 }
23553 // Check each of the tetrahedron's four neighbors.
23554 for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
23555 // Find the neighbor.
23556 sym(testtet, neighbor);
23557 // Check for a subface between the tetrahedron and its neighbor.
23558 tspivot(testtet, neighsh);
23559 // Make sure the neighbor exists, is not already infected, and
23560 // isn't protected by a subface, or is protected by a nonsolid
23561 // subface.
23562 if ((neighbor.tet != dummytet) && !infected(neighbor)
23563 && (neighsh.sh == dummysh)) {
23564 // Infect the neighbor.
23565 infect(neighbor);
23566 // Ensure that the neighbor's neighbors will be infected.
23567 regiontet = (tetrahedron **) regionviri->alloc();
23568 *regiontet = neighbor.tet;
23569 }
23570 }
23571 // Remark the tetrahedron as infected, so it doesn't get added to the
23572 // virus pool again.
23573 infect(testtet);
23574 virusloop = (tetrahedron **) regionviri->traverse();
23575 }
23576
23577 // Uninfect all tetrahedra.
23578 if (b->verbose > 1) {
23579 printf(" Unmarking marked tetrahedra.\n");
23580 }
23581 regionviri->traversalinit();
23582 virusloop = (tetrahedron **) regionviri->traverse();
23583 while (virusloop != (tetrahedron **) NULL) {
23584 testtet.tet = *virusloop;
23585 uninfect(testtet);
23586 virusloop = (tetrahedron **) regionviri->traverse();
23587 }
23588 // Empty the virus pool.
23589 regionviri->restart();
23590}
23591
23593// //
23594// removeholetets() Remove tetrahedra which are outside the domain. //
23595// //
23597
23598void tetgenmesh::removeholetets(memorypool* viri)
23599{
23600 tetrahedron **virusloop;
23601 triface testtet, neighbor;
23602 point checkpt;
23603 int *tetspernodelist;
23604 int i, j;
23605
23606 if (b->verbose > 0) {
23607 printf(" Deleting marked tetrahedra.\n");
23608 }
23609
23610 // Create and initialize 'tetspernodelist'.
23611 tetspernodelist = new int[points->items + 1];
23612 for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0;
23613
23614 // Loop the tetrahedra list, counter the number of tets sharing each node.
23615 tetrahedrons->traversalinit();
23616 testtet.tet = tetrahedrontraverse();
23617 while (testtet.tet != (tetrahedron *) NULL) {
23618 // Increment the number of sharing tets for each endpoint.
23619 for (i = 0; i < 4; i++) {
23620 j = pointmark((point) testtet.tet[4 + i]);
23621 tetspernodelist[j]++;
23622 }
23623 testtet.tet = tetrahedrontraverse();
23624 }
23625
23626 viri->traversalinit();
23627 virusloop = (tetrahedron **) viri->traverse();
23628 while (virusloop != (tetrahedron **) NULL) {
23629 testtet.tet = *virusloop;
23630 // Record changes in the number of boundary faces, and disconnect
23631 // dead tetrahedra from their neighbors.
23632 for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
23633 sym(testtet, neighbor);
23634 if (neighbor.tet == dummytet) {
23635 // There is no neighboring tetrahedron on this face, so this face
23636 // is a boundary face. This tetrahedron is being deleted, so this
23637 // boundary face is deleted.
23638 hullsize--;
23639 } else {
23640 // Disconnect the tetrahedron from its neighbor.
23641 dissolve(neighbor);
23642 // There is a neighboring tetrahedron on this face, so this face
23643 // becomes a boundary face when this tetrahedron is deleted.
23644 hullsize++;
23645 }
23646 }
23647 // Check the four corners of this tet if they're isolated.
23648 for (i = 0; i < 4; i++) {
23649 checkpt = (point) testtet.tet[4 + i];
23650 j = pointmark(checkpt);
23651 tetspernodelist[j]--;
23652 if (tetspernodelist[j] == 0) {
23653 // If it is added volume vertex or '-j' is not used, delete it.
23654 if ((pointtype(checkpt) == FREEVOLVERTEX) || !b->nojettison) {
23655 setpointtype(checkpt, UNUSEDVERTEX);
23656 unuverts++;
23657 }
23658 }
23659 }
23660 // Return the dead tetrahedron to the pool of tetrahedra.
23661 tetrahedrondealloc(testtet.tet);
23662 virusloop = (tetrahedron **) viri->traverse();
23663 }
23664
23665 delete [] tetspernodelist;
23666}
23667
23669// //
23670// assignregionattribs() Assign each tetrahedron a region number. //
23671// //
23672// This routine is called when '-AA' switch is specified. Every tetrahedron //
23673// of a (bounded) region will get a integer number to that region. Default, //
23674// regions are numbered as 1, 2, 3, etc. However, if a number has already //
23675// been used (set by user in the region section in .poly or .smesh), it is //
23676// skipped and the next available number will be used. //
23677// //
23679
23680void tetgenmesh::assignregionattribs()
23681{
23682 list *regionnumlist;
23683 list *regiontetlist;
23684 triface tetloop, regiontet, neightet;
23685 face checksh;
23686 bool flag;
23687 int regionnum, num;
23688 int attridx, count;
23689 int i;
23690
23691 if (b->verbose > 0) {
23692 printf(" Assign region numbers.\n");
23693 }
23694
23695 regionnumlist = new list(sizeof(int), NULL, 256);
23696 regiontetlist = new list(sizeof(triface), NULL, 1024);
23697 attridx = in->numberoftetrahedronattributes;
23698
23699 // Loop through all tets. Infect tets which already have a region number,
23700 // and save the used numbers in 'regionnumlist'.
23701 tetrahedrons->traversalinit();
23702 tetloop.tet = tetrahedrontraverse();
23703 while (tetloop.tet != (tetrahedron *) NULL) {
23704 if (!infected(tetloop)) {
23705 regionnum = (int) elemattribute(tetloop.tet, attridx);
23706 if (regionnum != 0.0) {
23707 // Found a numbered region tet.
23708 infect(tetloop);
23709 regiontetlist->append(&tetloop);
23710 // Found and infect all tets in this region.
23711 for (i = 0; i < regiontetlist->len(); i++) {
23712 regiontet = * (triface *)(* regiontetlist)[i];
23713 for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) {
23714 // Is there a boundary face?
23715 tspivot(regiontet, checksh);
23716 if (checksh.sh == dummysh) {
23717 sym(regiontet, neightet);
23718 if ((neightet.tet != dummytet) && !infected(neightet)) {
23719#ifdef SELF_CHECK
23720 // neightet should have the same region number. Check it.
23721 num = (int) elemattribute(neightet.tet, attridx);
23722 assert(num == regionnum);
23723#endif
23724 infect(neightet);
23725 regiontetlist->append(&neightet);
23726 }
23727 }
23728 }
23729 }
23730 // Add regionnum to list if it is not exist.
23731 flag = false;
23732 for (i = 0; i < regionnumlist->len() && !flag; i++) {
23733 num = * (int *)(* regionnumlist)[i];
23734 flag = (num == regionnum);
23735 }
23736 if (!flag) regionnumlist->append(&regionnum);
23737 // Clear list for the next region.
23738 regiontetlist->clear();
23739 }
23740 }
23741 tetloop.tet = tetrahedrontraverse();
23742 }
23743
23744 if (b->verbose > 0) {
23745 printf(" %d user-specified regions.\n", regionnumlist->len());
23746 }
23747
23748 // Now loop the tets again. Assign region numbers to uninfected tets.
23749 tetrahedrons->traversalinit();
23750 tetloop.tet = tetrahedrontraverse();
23751 regionnum = 1; // Start region number.
23752 count = 0;
23753 while (tetloop.tet != (tetrahedron *) NULL) {
23754 if (!infected(tetloop)) {
23755 // An unassigned region tet.
23756 count++;
23757 do {
23758 flag = false;
23759 // Check if the region number has been used.
23760 for (i = 0; i < regionnumlist->len() && !flag; i++) {
23761 num = * (int *)(* regionnumlist)[i];
23762 flag = (num == regionnum);
23763 }
23764 if (flag) regionnum++;
23765 } while (flag);
23766 setelemattribute(tetloop.tet, attridx, (REAL) regionnum);
23767 infect(tetloop);
23768 regiontetlist->append(&tetloop);
23769 // Found and infect all tets in this region.
23770 for (i = 0; i < regiontetlist->len(); i++) {
23771 regiontet = * (triface *)(* regiontetlist)[i];
23772 for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) {
23773 // Is there a boundary face?
23774 tspivot(regiontet, checksh);
23775 if (checksh.sh == dummysh) {
23776 sym(regiontet, neightet);
23777 if ((neightet.tet != dummytet) && !infected(neightet)) {
23778#ifdef SELF_CHECK
23779 // neightet should have not been assigned yet. Check it.
23780 num = (int) elemattribute(neightet.tet, attridx);
23781 assert(num == 0);
23782#endif
23783 setelemattribute(neightet.tet, attridx, (REAL) regionnum);
23784 infect(neightet);
23785 regiontetlist->append(&neightet);
23786 }
23787 }
23788 }
23789 }
23790 regiontetlist->clear();
23791 regionnum++; // The next region number.
23792 }
23793 tetloop.tet = tetrahedrontraverse();
23794 }
23795
23796 // Uninfect all tets.
23797 tetrahedrons->traversalinit();
23798 tetloop.tet = tetrahedrontraverse();
23799 while (tetloop.tet != (tetrahedron *) NULL) {
23800#ifdef SELF_CHECK
23801 assert(infected(tetloop));
23802#endif
23803 uninfect(tetloop);
23804 tetloop.tet = tetrahedrontraverse();
23805 }
23806
23807 if (b->verbose > 0) {
23808 printf(" %d regions are numbered.\n", count);
23809 }
23810
23811 delete regionnumlist;
23812 delete regiontetlist;
23813}
23814
23816// //
23817// carveholes() Find the holes and infect them. Find the volume //
23818// constraints and infect them. Infect the convex hull. //
23819// Spread the infection and kill tetrahedra. Spread the //
23820// volume constraints. //
23821// //
23822// This routine mainly calls other routines to carry out all these functions.//
23823// //
23825
23826void tetgenmesh::carveholes()
23827{
23828 memorypool *holeviri, *regionviri;
23829 tetrahedron *tptr, **holetet, **regiontet;
23830 triface searchtet, *holetets, *regiontets;
23831 enum locateresult intersect;
23832 int i;
23833
23834 if (!b->quiet) {
23835 printf("Removing unwanted tetrahedra.\n");
23836 if (b->verbose && (in->numberofholes > 0)) {
23837 printf(" Marking holes for elimination.\n");
23838 }
23839 }
23840
23841 // Initialize a pool of viri to be used for holes, concavities.
23842 holeviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
23843 // Mark as infected any unprotected tetrahedra on the boundary.
23844 infecthull(holeviri);
23845
23846 if (in->numberofholes > 0) {
23847 // Allocate storage for the tetrahedra in which hole points fall.
23848 holetets = (triface *) new triface[in->numberofholes];
23849 // Infect each tetrahedron in which a hole lies.
23850 for (i = 0; i < 3 * in->numberofholes; i += 3) {
23851 // Ignore holes that aren't within the bounds of the mesh.
23852 if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax)
23853 && (in->holelist[i + 1] >= ymin)
23854 && (in->holelist[i + 1] <= ymax)
23855 && (in->holelist[i + 2] >= zmin)
23856 && (in->holelist[i + 2] <= zmax)) {
23857 searchtet.tet = dummytet;
23858 // Find a tetrahedron that contains the hole.
23859 intersect = locate(&in->holelist[i], &searchtet);
23860 if ((intersect != OUTSIDE) && (!infected(searchtet))) {
23861 // Record the tetrahedron for processing carve hole.
23862 holetets[i / 3] = searchtet;
23863 }
23864 }
23865 }
23866 // Infect the hole tetrahedron. This is done by marking the tet as
23867 // infected and including the tetrahedron in the virus pool.
23868 for (i = 0; i < in->numberofholes; i++) {
23869 infect(holetets[i]);
23870 holetet = (tetrahedron **) holeviri->alloc();
23871 *holetet = holetets[i].tet;
23872 }
23873 // Free up memory.
23874 delete [] holetets;
23875 }
23876
23877 // Mark as infected all tets of the holes and concavities.
23878 plague(holeviri);
23879 // The virus pool contains all outside tets now.
23880
23881 // Is -A switch in use.
23882 if (b->regionattrib) {
23883 // Assign every tetrahedron a regional attribute of zero.
23884 tetrahedrons->traversalinit();
23885 tptr = tetrahedrontraverse();
23886 while (tptr != (tetrahedron *) NULL) {
23887 setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0);
23888 tptr = tetrahedrontraverse();
23889 }
23890 }
23891
23892 if (in->numberofregions > 0) {
23893 if (!b->quiet) {
23894 if (b->regionattrib) {
23895 if (b->varvolume) {
23896 printf("Spreading regional attributes and volume constraints.\n");
23897 } else {
23898 printf("Spreading regional attributes.\n");
23899 }
23900 } else {
23901 printf("Spreading regional volume constraints.\n");
23902 }
23903 }
23904 // Allocate storage for the tetrahedra in which region points fall.
23905 regiontets = (triface *) new triface[in->numberofregions];
23906 // Find the starting tetrahedron for each region.
23907 for (i = 0; i < in->numberofregions; i++) {
23908 regiontets[i].tet = dummytet;
23909 // Ignore region points that aren't within the bounds of the mesh.
23910 if ((in->regionlist[5 * i] >= xmin)
23911 && (in->regionlist[5 * i] <= xmax)
23912 && (in->regionlist[5 * i + 1] >= ymin)
23913 && (in->regionlist[5 * i + 1] <= ymax)
23914 && (in->regionlist[5 * i + 2] >= zmin)
23915 && (in->regionlist[5 * i + 2] <= zmax)) {
23916 searchtet.tet = dummytet;
23917 // Find a tetrahedron that contains the region point.
23918 intersect = locate(&in->regionlist[5 * i], &searchtet);
23919 if ((intersect != OUTSIDE) && (!infected(searchtet))) {
23920 // Record the tetrahedron for processing after the
23921 // holes have been carved.
23922 regiontets[i] = searchtet;
23923 }
23924 }
23925 }
23926 // Initialize a pool to be used for regional attrs, and/or regional
23927 // volume constraints.
23928 regionviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
23929 // Find and set all regions.
23930 for (i = 0; i < in->numberofregions; i++) {
23931 if (regiontets[i].tet != dummytet) {
23932 // Make sure the tetrahedron under consideration still exists.
23933 // It may have been eaten by the virus.
23934 if (!isdead(&(regiontets[i]))) {
23935 // Put one tetrahedron in the virus pool.
23936 infect(regiontets[i]);
23937 regiontet = (tetrahedron **) regionviri->alloc();
23938 *regiontet = regiontets[i].tet;
23939 // Apply one region's attribute and/or volume constraint.
23940 regionplague(regionviri, in->regionlist[5 * i + 3],
23941 in->regionlist[5 * i + 4]);
23942 // The virus pool should be empty now.
23943 }
23944 }
23945 }
23946 // Free up memory.
23947 delete [] regiontets;
23948 delete regionviri;
23949 }
23950
23951 // Now acutually remove the outside and hole tets.
23952 removeholetets(holeviri);
23953 // The mesh is nonconvex now.
23954 nonconvex = 1;
23955
23956 if (b->regionattrib) {
23957 if (b->regionattrib > 1) {
23958 // -AA switch. Assign each tet a region number (> 0).
23959 assignregionattribs();
23960 }
23961 // Note the fact that each tetrahedron has an additional attribute.
23962 in->numberoftetrahedronattributes++;
23963 }
23964
23965 // Free up memory.
23966 delete holeviri;
23967}
23968
23969//
23970// End of carving out holes and concavities routines
23971//
23972
23973//
23974// Begin of boundary Steiner points removing routines
23975//
23976
23978// //
23979// replacepolygonsubs() Substitute the subfaces of a polygon. //
23980// //
23981// 'oldshlist' (T_old) contains the old subfaces of P. It will be replaced //
23982// by 'newshlist' (T_new) of new subfaces. Each boundary edge of P is bonded //
23983// to 'dummysh' in T_new. //
23984// //
23985// Notice that Not every boundary edge of T_new is able to bond to a subface,//
23986// e.g., when it is a segment recovered by removing a Steiner point in it. //
23987// //
23989
23990void tetgenmesh::replacepolygonsubs(list* oldshlist, list* newshlist)
23991{
23992 face newsh, oldsh, spinsh;
23993 face casingout, casingin;
23994 face checkseg;
23995 point pa, pb;
23996 int i, j, k, l;
23997
23998 for (i = 0; i < newshlist->len(); i++) {
23999 // Get a new subface s.
24000 newsh = * (face *)(* newshlist)[i];
24001 // Check the three edges of s.
24002 for (k = 0; k < 3; k++) {
24003 spivot(newsh, casingout);
24004 // Is it a boundary edge?
24005 if (casingout.sh == dummysh) {
24006 // Find the old subface s_o having the same edge as s.
24007 pa = sorg(newsh);
24008 pb = sdest(newsh);
24009 for (j = 0; j < oldshlist->len(); j++) {
24010 oldsh = * (face *)(* oldshlist)[j];
24011 for (l = 0; l < 3; l++) {
24012 if (((sorg(oldsh) == pa) && (sdest(oldsh) == pb)) ||
24013 ((sorg(oldsh) == pb) && (sdest(oldsh) == pa))) break;
24014 senextself(oldsh);
24015 }
24016 if (l < 3) break;
24017 }
24018 // Is there a matched edge?
24019 if (j < oldshlist->len()) {
24020 // Get the neighbor subface s_out.
24021 spivot(oldsh, casingout);
24022 sspivot(oldsh, checkseg);
24023 if (checkseg.sh != dummysh) {
24024 // A segment. Insert s into the face ring, ie, s_in -> s -> s_out.
24025 if (oldsh.sh != casingout.sh) {
24026 // s is not bonded to itself.
24027 spinsh = casingout;
24028 do {
24029 casingin = spinsh;
24030 spivotself(spinsh);
24031 } while (sapex(spinsh) != sapex(oldsh));
24032 assert(casingin.sh != oldsh.sh);
24033 // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out).
24034 sbond1(casingin, newsh);
24035 sbond1(newsh, casingout);
24036 } else {
24037 // Bond newsh -> newsh.
24038 sbond(newsh, newsh);
24039 }
24040 // Bond the segment.
24041 ssbond(newsh, checkseg);
24042 } else {
24043 // Bond s <-> s_out (and dissolve s_out -> s_old).
24044 sbond(newsh, casingout);
24045 }
24046 // Unbound oldsh to indicate it's neighbor has been replaced.
24047 // It will be used to indentfy the edge in the inverse.
24048 sdissolve(oldsh);
24049 ssdissolve(oldsh);
24050 }
24051 }
24052 // Go to the next edge of s.
24053 senextself(newsh);
24054 }
24055 }
24056}
24057
24059// //
24060// orientnewsubs() Orient new subfaces facing to the inside of cavity. //
24061// //
24062// 'newshlist' contains new subfaces of the cavity C (created by re-triangu- //
24063// lation the polygon P). They're not necessary facing to the inside of C. //
24064// 'orientsh', faces to the inside of C, is used to adjust new subfaces. The //
24065// normal of the new subfaces is returned in 'norm'. //
24066// //
24068
24069void tetgenmesh::orientnewsubs(list* newshlist, face* orientsh, REAL* norm)
24070{
24071 face *newsh;
24072 point pa, pb, pc;
24073 REAL ref[3], ori, len;
24074 int i;
24075
24076 // Calculate the normal of 'orientsh'.
24077 pa = sorg(*orientsh);
24078 pb = sdest(*orientsh);
24079 pc = sapex(*orientsh);
24080 facenormal(pa, pb, pc, norm, &len);
24081 for (i = 0; i < 3; i++) ref[i] = pa[i] + norm[i];
24082 for (i = 0; i < 3; i++) norm[i] /= len;
24083
24084 // Orient new subfaces. Let the normal above each one.
24085 for (i = 0; i < newshlist->len(); i++) {
24086 newsh = (face *)(* newshlist)[i];
24087 pa = sorg(*newsh);
24088 pb = sdest(*newsh);
24089 pc = sapex(*newsh);
24090 ori = orient3d(pa, pb, pc, ref);
24091 assert(ori != 0.0);
24092 if (ori > 0.0) {
24093 sesymself(*newsh);
24094 }
24095 }
24096}
24097
24099// //
24100// constrainedflip() Flip a non-constrained face. //
24101// //
24102// 'flipface' f (abc) is a face we want to flip. In addition, if 'front' is //
24103// given (not a NULL), f is a crossface. f may not be flippable if it is one //
24104// of the following cases: //
24105// (1) f has an aux subface attached; //
24106// (2) f is on the convex hull; //
24107// (3) f is not locally Delaunay (f must be recovered by a previous flip, //
24108// we should keep it, otherwise, we may fall into a flip loop); //
24109// (4) f is T32 at ab, but abd or abe has an aux subface attached; //
24110// (5) f is T22 or T44 at ab, but abd, or abe, or abf has an aux subface //
24111// attached; //
24112// (6) f is unflipable at ab, and abd, abe, ... are all unflippable due to //
24113// the cases (1) - (5). //
24114// If f is a crssface ('front' != NULL) and it is unflipable due to case (3),//
24115// (4), (5) and (6). Try to flip the next crossing face of front first. //
24116// //
24118
24119bool tetgenmesh::constrainedflip(triface* flipface, triface* front,
24120 queue* flipque)
24121{
24122 triface symface, spintet;
24123 face checksh;
24124 point pa, pb, pc, pd, pe;
24125 enum fliptype fc;
24126 REAL sign;
24127 bool doflip;
24128 int ia, ib, ic, id, ie;
24129 int i;
24130
24131 // (1) Is f protected by an (auxilary) subface?
24132 tspivot(*flipface, checksh);
24133 if (checksh.sh != dummysh) return false;
24134 // (2) Is f on the convex hull?
24135 sym(*flipface, symface);
24136 if (symface.tet == dummytet) return false;
24137 // (3) Is f not locally Delaunay?
24138 adjustedgering(*flipface, CCW);
24139 pa = dest(*flipface);
24140 pb = org(*flipface);
24141 pc = apex(*flipface);
24142 pd = oppo(*flipface);
24143 pe = oppo(symface);
24144 // if (symbolic) {
24145 ia = pointmark(pa);
24146 ib = pointmark(pb);
24147 ic = pointmark(pc);
24148 id = pointmark(pd);
24149 ie = pointmark(pe);
24150 sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
24151 assert(sign != 0.0);
24152 // } else {
24153 // sign = insphere(pa, pb, pc, pd, pe);
24154 // }
24155 if (sign <= 0.0) {
24156 // Get the fliptype of f.
24157 checksubfaces = 0; // switch off subface test.
24158 fc = categorizeface(*flipface);
24159 checksubfaces = 1; // switch on subface test.
24160 if (fc == T23) {
24161 doflip = true;
24162 // Avoid one tet created by the 2-3 flip is nearly degenerate.
24163 /* pc = oppo(*flipface);
24164 pd = oppo(symface);
24165 adjustedgering(*flipface, CCW);
24166 for (i = 0; i < 3; i++) {
24167 pa = org(*flipface);
24168 pb = dest(*flipface);
24169 ori = orient3d(pa, pb, pc, pd);
24170 if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) {
24171 doflip = false; break;
24172 }
24173 enextself(*flipface);
24174 } */
24175 if (doflip) {
24176 flip23(flipface, flipque);
24177 return true;
24178 }
24179 } else if (fc == T32) {
24180 // (4) Is abd, or abe protected?
24181 doflip = true;
24182 spintet = *flipface;
24183 for (i = 0; i < 2; i++) {
24184 fnextself(spintet);
24185 tspivot(spintet, checksh);
24186 if (checksh.sh != dummysh) {
24187 doflip = false; break; // f is protected. Unflipable.
24188 }
24189 }
24190 if (doflip) {
24191 flip32(flipface, flipque);
24192 return true;
24193 }
24194 } else if (fc == T22 || fc == T44) {
24195 // (5) Is abd, abe, or abf protected?
24196 doflip = true;
24197 if (fc == T22) {
24198 for (i = 0; i < 2; i++) {
24199 spintet = *flipface;
24200 if (i == 1) {
24201 esymself(spintet);
24202 }
24203 fnextself(spintet);
24204 tspivot(spintet, checksh);
24205 if (checksh.sh != dummysh) {
24206 doflip = false; break; // f is protected. Unflipable.
24207 }
24208 }
24209 } else if (fc == T44) {
24210 spintet = *flipface;
24211 for (i = 0; i < 3; i++) {
24212 fnextself(spintet);
24213 tspivot(spintet, checksh);
24214 if (checksh.sh != dummysh) {
24215 doflip = false; break; // f is protected. Unflipable.
24216 }
24217 }
24218 }
24219 if (doflip) {
24220 flip22(flipface, flipque);
24221 return true;
24222 }
24223 } else if (fc == N32) {
24224 // Is f a crossface?
24225 if (front != (triface *) NULL) {
24226 // (6) Is any obstacle face (abd, or abe, ...) flipable?
24227 spintet = *flipface;
24228 while (fnextself(spintet)) {
24229 if (apex(spintet) == apex(*flipface)) break;
24230 // Check if spintet is flipable, no recursive.
24231 if (constrainedflip(&spintet, NULL, flipque)) {
24232 // One obstacle face has been flipped.
24233 return true;
24234 }
24235 // Unflipable. Go to the next obstacle face.
24236 findedge(&spintet, org(*flipface), dest(*flipface));
24237 }
24238 }
24239 }
24240 }
24241
24242 // f is unflipable. Is f a crossface?
24243 if (front != (triface *) NULL) {
24244 // Look if there is another crossface.
24245 pa = org(*front);
24246 pb = dest(*front);
24247 pc = apex(*front);
24248 // sym(*flipface, symface);
24249 // Have we reach the end of abc (We've started from edge ab).
24250 if (oppo(symface) != pc) {
24251 adjustedgering(symface, CCW);
24252 for (i = 0; i < 3; i++) {
24253 fnext(symface, spintet);
24254 // Is c ahead of this face?
24255 sign = orient3d(org(spintet), dest(spintet), apex(spintet), pc);
24256 if (sign < 0.0) {
24257 if (tritritest(&spintet, pa, pb, pc)) {
24258 if (b->verbose > 2) {
24259 printf(" Next crossface (%d, %d, %d).\n",
24260 pointmark(org(spintet)), pointmark(dest(spintet)),
24261 pointmark(apex(spintet)));
24262 }
24263 return constrainedflip(&spintet, front, flipque);
24264 // return constrainedflip(&spintet, NULL, flipque);
24265 }
24266 }
24267 enextself(symface);
24268 }
24269 }
24270 }
24271 return false;
24272}
24273
24275// //
24276// recoverfront() Recover a missing front by flips. //
24277// //
24278// 'front' f is missing in D - it was crossed by faces of D. The cross faces //
24279// may be flippable, so f can be recovered by flipping them away. //
24280// //
24282
24283bool tetgenmesh::recoverfront(triface* front, list* newtetlist, queue* flipque)
24284{
24285 triface idfront, starttet, spintet;
24286 point pa, pb, pc, pd, ref;
24287 enum locateresult loc;
24288 enum finddirectionresult col;
24289 REAL ori, ori1, ori2, sign;
24290 int hitbdry;
24291 int i, j;
24292
24293 // Find an existing edge of f in D to start with.
24294 for (i = 0; i < 3; i++) {
24295 pa = org(*front);
24296 pb = dest(*front);
24297 // Get a tet for searching.
24298 idfront = recenttet;
24299 // Make sure the tet is valid (flip32() may kill a tet).
24300 if (isdead(&idfront)) {
24301 // The tet is dead. Get a live tet in D. !!!
24302 for (j = 0; j < newtetlist->len(); j++) {
24303 recenttet = * (triface *)(* newtetlist)[j];
24304 if (!isdead(&recenttet)) break;
24305 }
24306 assert(j < newtetlist->len());
24307 }
24308 loc = preciselocate(pa, &idfront, (long) newtetlist->len());
24309 if (loc != ONVERTEX) {
24310 // Do a brute-force search in D.
24311 for (j = 0; j < newtetlist->len(); j++) {
24312 idfront = * (triface *)(* newtetlist)[j];
24313 if (isdead(&idfront)) continue;
24314 if (findorg(&idfront, pa)) break;
24315 }
24316 assert(j < newtetlist->len()); // a must belong to one tet.
24317 }
24318 recenttet = idfront;
24319 // Search for a tet having edge ab.
24320 col = finddirection(&idfront, pb, (long) newtetlist->len());
24321 if (col == BELOWHULL) {
24322 // Do a brute-force search in D.
24323 for (j = 0; j < newtetlist->len(); j++) {
24324 idfront = * (triface *)(* newtetlist)[j];
24325 if (isdead(&idfront)) continue;
24326 if (findorg(&idfront, pa)) {
24327 assert(org(idfront) == pa);
24328 if (dest(idfront) == pb) {
24329 col = RIGHTCOLLINEAR; break;
24330 } else if (apex(idfront) == pb) {
24331 col = LEFTCOLLINEAR; break;
24332 } else if (oppo(idfront) == pb) {
24333 col = TOPCOLLINEAR; break;
24334 }
24335 }
24336 }
24337 }
24338 if (col == RIGHTCOLLINEAR) {
24339 // b is just the destination.
24340 } else if (col == LEFTCOLLINEAR) {
24341 enext2self(idfront);
24342 esymself(idfront);
24343 } else if (col == TOPCOLLINEAR) {
24344 fnextself(idfront);
24345 enext2self(idfront);
24346 esymself(idfront);
24347 }
24348 if (dest(idfront) == pb) break; // Found.
24349 // Missing. Go to the next edge of f.
24350 enextself(*front);
24351 }
24352 if (i == 3) {
24353 // All three edges of f are missing - unrecoverable.
24354 return false;
24355 }
24356
24357 // Search for a tet having f (abc).
24358 pc = apex(*front);
24359 spintet = idfront;
24360 hitbdry = 0;
24361 do {
24362 if (apex(spintet) == pc) {
24363 // Found abc. Insert an auxilary subface s at idfront.
24364 insertauxsubface(front, &spintet);
24365 return true;
24366 }
24367 if (!fnextself(spintet)) {
24368 hitbdry ++;
24369 if (hitbdry < 2) {
24370 esym(idfront, spintet);
24371 if (!fnextself(spintet)) {
24372 hitbdry ++;
24373 }
24374 }
24375 }
24376 if (apex(spintet) == apex(idfront)) break;
24377 } while (hitbdry < 2);
24378
24379 // Search for a crossing face to flip.
24380 pd = apex(idfront);
24381 assert(pd != pc);
24382 // Decide the orientation of d with abc.
24383 ori = orient3d(pa, pb, pc, pd);
24384 if (ori < 0.0) {
24385 // d is above abc. Rotate downwards.
24386 esym(idfront, starttet);
24387 sign = -1.0;
24388 } else if (ori > 0.0) {
24389 // d is below abc. Rotate upwards.
24390 starttet = idfront;
24391 sign = 1.0;
24392 } else {
24393 assert(ori == 0.0);
24394 // d is coplanar with abc. Do abc and abd intersect?
24395 ref = oppo(idfront);
24396 ori1 = orient3d(pa, pb, ref, pc);
24397 ori2 = orient3d(pa, pb, ref, pd);
24398 assert(ori1 * ori2 != 0.0);
24399 if (ori1 * ori2 > 0) {
24400 // abc and abd intersect. There're two possible intersections:
24401 // ad and bc, or ac and bd. Find it out.
24402 ori1 = orient3d(pb, pc, ref, pd);
24403 ori2 = orient3d(pb, pc, ref, pa);
24404 assert(ori1 * ori2 != 0.0);
24405 if (ori1 * ori2 > 0) {
24406 // ac intersects bd.
24407 enextself(idfront); // go to edge bd.
24408 } else {
24409 // ad intersects bc.
24410 enext2self(idfront); // go to edge ad.
24411 }
24412 adjustedgering(idfront, CCW);
24413 fnextself(idfront); // face ade or bce need a 4-to-4 flip.
24414 if (b->verbose > 2) {
24415 printf(" Get crossface (%d, %d, %d).\n", pointmark(org(idfront)),
24416 pointmark(dest(idfront)), pointmark(apex(idfront)));
24417 }
24418 if (constrainedflip(&idfront, front, flipque)) {
24419 // A crossface has been flipped. Continue to recover f.
24420 return recoverfront(front, newtetlist, flipque);
24421 }
24422 // Unable to recover f.
24423 return false; // sign = 0.0;
24424 } else {
24425 // Not intersect. We can go either direction.
24426 starttet = idfront;
24427 if (fnextself(starttet)) {
24428 // Choose to rotate upwards.
24429 sign = 1.0;
24430 } else {
24431 // Hit convex hull. Choose to rotate downwrads.
24432 esym(idfront, starttet);
24433 sign = -1.0;
24434 }
24435 }
24436 }
24437
24438 assert(sign != 0.0);
24439 if (sign == -1) {
24440 // The edge ab has be changed. Reverse it.
24441 pa = org(starttet);
24442 pb = dest(starttet);
24443 // The sign has been reversed as well.
24444 sign = -sign;
24445 }
24446 // Rotate face abd around edge ab. Moreover, we've chosen the rotate
24447 // direction such that no convex hull face will be reach.
24448 spintet = starttet;
24449 while (fnextself(spintet)) {
24450 pd = apex(spintet);
24451 assert(pd != pc);
24452 // Check if the orientation of d (with abc) has changed.
24453 ori = orient3d(pa, pb, pc, pd);
24454 if (ori == 0.0) {
24455 // abc and abd must coplanar intersect (4-to-4 flip is needed).
24456 ref = oppo(spintet);
24457 ori1 = orient3d(pb, pc, ref, pd);
24458 ori2 = orient3d(pb, pc, ref, pa);
24459 assert(ori1 * ori2 != 0.0);
24460 if (ori1 * ori2 > 0) {
24461 // ac intersects bd.
24462 enextself(spintet); // go to edge bd.
24463 } else {
24464 // ad intersects bc.
24465 enext2self(spintet); // go to edge ad.
24466 }
24467 adjustedgering(spintet, CCW);
24468 fnextself(spintet); // face ade or bce need a 4-to-4 flip.
24469 if (b->verbose > 2) {
24470 printf(" Get crossface (%d, %d, %d).\n", pointmark(org(spintet)),
24471 pointmark(dest(spintet)), pointmark(apex(spintet)));
24472 }
24473 if (constrainedflip(&spintet, front, flipque)) {
24474 // A crossface has been flipped. Continue to recover f.
24475 return recoverfront(front, newtetlist, flipque);
24476 }
24477 // Unable to recover f.
24478 return false; // sign = 0.0;
24479 } else if (ori * sign < 0.0) {
24480 // Sign has changed. The face dea or deb must cross abc.
24481 adjustedgering(spintet, CCW);
24482 enextself(spintet);
24483 for (i = 0; i < 2; i++) {
24484 // Get the face dea or deb.
24485 fnext(spintet, starttet);
24486 if (tritritest(&starttet, pa, pb, pc)) {
24487 if (b->verbose > 2) {
24488 printf(" Get crossface (%d, %d, %d).\n",
24489 pointmark(org(starttet)), pointmark(dest(starttet)),
24490 pointmark(apex(starttet)));
24491 }
24492 if (constrainedflip(&starttet, front, flipque)) {
24493 // A crossface has been flipped. Continue to recover f.
24494 return recoverfront(front, newtetlist, flipque);
24495 }
24496 }
24497 enextself(spintet);
24498 }
24499 // Unable to recover f.
24500 return false;
24501 }
24502 }
24503 // Impossible to be here.
24504 assert(0);
24505 return false;
24506}
24507
24509// //
24510// repairflips() Flip non-Delaunay and non-constrained faces. //
24511// //
24513
24514void tetgenmesh::repairflips(queue* flipque)
24515{
24516 badface *qface;
24517 triface flipface, symface, spintet;
24518 face checksh;
24519 point pa, pb, pc, pd, pe;
24520 enum fliptype fc;
24521 REAL sign;
24522 long flipcount;
24523 bool doflip;
24524 int ia, ib, ic, id, ie;
24525 int i;
24526
24527 if (b->verbose > 1) {
24528 printf(" Repair flip %ld faces.\n", flipque->len());
24529 }
24530 flipcount = flip23s + flip32s + flip22s + flip44s;
24531 // Loop until the queue is empty.
24532 while (!flipque->empty()) {
24533 qface = (badface *) flipque->pop();
24534 flipface = qface->tt;
24535 // Check the validity of this face.
24536 if (isdead(&flipface) || flipface.tet == dummytet ||
24537 (org(flipface) != qface->forg) ||
24538 (dest(flipface) != qface->fdest) ||
24539 (apex(flipface) != qface->fapex) ||
24540 (oppo(flipface) == (point) NULL)) continue;
24541 // (1) Is f protected by an (auxilary) subface?
24542 tspivot(flipface, checksh);
24543 if (checksh.sh != dummysh) continue;
24544 // (2) Is f on the convex hull?
24545 sym(flipface, symface);
24546 if (symface.tet == dummytet) continue;
24547 // For positive orientation that insphere() test requires.
24548 adjustedgering(flipface, CW);
24549 pa = org(flipface);
24550 pb = dest(flipface);
24551 pc = apex(flipface);
24552 pd = oppo(flipface);
24553 pe = oppo(symface);
24554 // if (symbolic) {
24555 ia = pointmark(pa);
24556 ib = pointmark(pb);
24557 ic = pointmark(pc);
24558 id = pointmark(pd);
24559 ie = pointmark(pe);
24560 sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
24561 assert(sign != 0.0);
24562 // } else {
24563 // sign = insphere(pa, pb, pc, pd, pe);
24564 // }
24565 if (sign > 0.0) {
24566 // f is non-lcally Delaunay. Get the fliptype of f.
24567 checksubfaces = 0; // switch off subface test.
24568 fc = categorizeface(flipface);
24569 checksubfaces = 1; // switch on subface test.
24570 if (fc == T23) {
24571 doflip = true;
24572 // Avoid to create a nearly degenerate tet.
24573 /* pc = oppo(flipface);
24574 pd = oppo(symface);
24575 adjustedgering(flipface, CCW);
24576 for (i = 0; i < 3; i++) {
24577 pa = org(flipface);
24578 pb = dest(flipface);
24579 ori = orient3d(pa, pb, pc, pd);
24580 if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) {
24581 doflip = false; break;
24582 }
24583 enextself(flipface);
24584 } */
24585 if (doflip) {
24586 flip23(&flipface, flipque);
24587 }
24588 } else if (fc == T32) {
24589 // (4) Is abd, or abe protected?
24590 doflip = true;
24591 spintet = flipface;
24592 for (i = 0; i < 2; i++) {
24593 fnextself(spintet);
24594 tspivot(spintet, checksh);
24595 if (checksh.sh != dummysh) {
24596 doflip = false; break; // f is protected. Unflipable.
24597 }
24598 }
24599 if (doflip) {
24600 flip32(&flipface, flipque);
24601 }
24602 } else if (fc == T22 || fc == T44) {
24603 // (5) Is abd, abe, or abf protected?
24604 doflip = true;
24605 if (fc == T22) {
24606 for (i = 0; i < 2; i++) {
24607 spintet = flipface;
24608 if (i == 1) {
24609 esymself(spintet);
24610 }
24611 fnextself(spintet);
24612 tspivot(spintet, checksh);
24613 if (checksh.sh != dummysh) {
24614 doflip = false; break; // f is protected. Unflipable.
24615 }
24616 }
24617 } else if (fc == T44) {
24618 spintet = flipface;
24619 for (i = 0; i < 3; i++) {
24620 fnextself(spintet);
24621 tspivot(spintet, checksh);
24622 if (checksh.sh != dummysh) {
24623 doflip = false; break; // f is protected. Unflipable.
24624 }
24625 }
24626 }
24627 if (doflip) {
24628 flip22(&flipface, flipque);
24629 }
24630 }
24631 }
24632 }
24633 flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
24634 if (b->verbose > 1) {
24635 printf(" %ld flips.\n", flipcount);
24636 }
24637}
24638
24640// //
24641// constrainedcavity() Tetrahedralize a cavity by constrained tetrahedra. //
24642// //
24643// The cavity C is bounded by faces F in 'floorlist' and 'ceillist'. 'ptlist'//
24644// V is the set of vertices of C. //
24645// //
24647
24648bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist,
24649 list* ceillist, list* ptlist, list* frontlist, list* misfrontlist,
24650 list* newtetlist, queue* flipque)
24651{
24652 triface misfront, newtet;
24653 long facenum;
24654 int i;
24655
24656 if (b->verbose > 1) {
24657 printf(" Constrained cavity (%d floors, %d ceilings, %d vertices).\n",
24658 floorlist->len(), ceillist->len(), ptlist->len());
24659 }
24660
24661 // symbolic = 1;
24662
24663 // Initialize the cavity C.
24664 initializecavity(floorlist, ceillist, frontlist);
24665 // Form the D of the vertices of C.
24666 delaunizecavvertices(oldtet, ptlist, NULL, newtetlist, flipque);
24667
24668 // Identify faces of C in D.
24669 if (!identifyfronts(frontlist, misfrontlist, newtetlist)) {
24670 // Some faces are missing.
24671 recenttet = * (triface *)(* newtetlist)[0];
24672 assert((recenttet.tet != dummytet) && !isdead(&recenttet));
24673 // Try to recover missing faces by flips.
24674 do {
24675 facenum = misfrontlist->len();
24676 for (i = 0; i < misfrontlist->len(); i++) {
24677 // Get a missing front f.
24678 misfront = * (triface *)(* misfrontlist)[i];
24679 // Let f face toward the inside of C.
24680 adjustedgering(misfront, CW);
24681 if (b->verbose > 1) {
24682 printf(" Recover face (%d, %d, %d).\n", pointmark(org(misfront)),
24683 pointmark(dest(misfront)), pointmark(apex(misfront)));
24684 }
24685 if (recoverfront(&misfront, newtetlist, flipque)) {
24686 // f has been recovered.
24687 frontlist->append(&misfront);
24688 misfrontlist->del(i, 0); i--;
24689 }
24690 // Flip non-locally non-constrained Delaunay faces.
24691 repairflips(flipque);
24692 }
24693 // Have all faces been recovered?
24694 if (misfrontlist->len() == 0) break;
24695 // No! There are still un-recovered faces. Continue the loop if any
24696 // face has been recovered.
24697 } while (misfrontlist->len() < facenum);
24698 // Retrieve new tets and purge dead tets in D.
24699 retrievenewtets(newtetlist);
24700 }
24701
24702 // symbolic = 0;
24703
24704 if (misfrontlist->len() == 0) {
24705 // All fronts have identified in D. Get the shape of C by removing out
24706 // tets of C. 'misfrontlist' is reused for removing out tets.
24707 // Don't do flip since the new tets may get deleted later.
24708 carvecavity(newtetlist, misfrontlist, NULL);
24709 // Recover locally Delaunay faces.
24710 // flip(flipque, NULL);
24711 return true;
24712 } else {
24713 // Fail to tetrahedralize C.
24714 // Remove aux subfaces.
24715 detachauxsubfaces(newtetlist);
24716 // Remove new tets.
24717 for (i = 0; i < newtetlist->len(); i++) {
24718 newtet = * (triface *)(* newtetlist)[i];
24719 assert(!isdead(&newtet));
24720 tetrahedrondealloc(newtet.tet);
24721 }
24722 newtetlist->clear();
24723 // Restore faces of C in frontlist.
24724 for (i = 0; i < misfrontlist->len(); i++) {
24725 misfront = * (triface *)(* misfrontlist)[i];
24726 frontlist->append(&misfront);
24727 }
24728 return false;
24729 }
24730}
24731
24733// //
24734// expandsteinercavity() Expand the cavity of a Steiner point. //
24735// //
24736// Expand the cavity C if there fronts (except fronts having subfaces) which //
24737// are either (nearly) coplanar or invisible by the Steiner point. //
24738// //
24740
24741void tetgenmesh::expandsteinercavity(point steinpt, REAL eps, list* frontlist,
24742 list* oldtetlist)
24743{
24744 triface front, symfront, newfront, oldfront;
24745 face frontsh;
24746 point pa, pb, pc;
24747 REAL ori;
24748 bool expflag, newflag;
24749 int i, j;
24750
24751 do {
24752 expflag = false;
24753 for (i = 0; i < frontlist->len(); i++) {
24754 // Get a front f.
24755 front = * (triface *)(* frontlist)[i];
24756 // f can be expanded if it is not a subface.
24757 tspivot(front, frontsh);
24758 if (frontsh.sh == dummysh) {
24759 // Let f face to the inside of C.
24760 adjustedgering(front, CW);
24761 pa = org(front);
24762 pb = dest(front);
24763 pc = apex(front);
24764 ori = orient3d(pa, pb, pc, steinpt);
24765 if (ori != 0.0) {
24766 if (iscoplanar(pa, pb, pc, steinpt, ori, eps)) {
24767 ori = 0.0; // f is nearly coplanar with p.
24768 }
24769 }
24770 if (ori >= 0.0) {
24771 // f is either invisible or coplanar with p.
24772 if (b->verbose > 2) {
24773 printf(" Remove front (%d, %d, %d).\n", pointmark(pa),
24774 pointmark(pb), pointmark(pc));
24775 }
24776 frontlist->del(i, 1);
24777 expflag = true;
24778 break;
24779 }
24780 }
24781 }
24782 if (expflag) {
24783 assert(!infected(front) && (oppo(front) != NULL));
24784 // Expand C at f by including new fronts.
24785 adjustedgering(front, CCW);
24786 for (i = 0; i < 3; i++) {
24787 newflag = true;
24788 // Get a new boundary n of the cavity.
24789 fnext(front, symfront);
24790 tspivot(symfront, frontsh);
24791 sym(symfront, newfront);
24792 if (frontsh.sh == dummysh) {
24793 assert(newfront.tet != dummytet);
24794 // Is n a front of the unexp. cavity?
24795 if (infected(newfront)) {
24796 for (j = 0; j < frontlist->len(); j++) {
24797 oldfront = * (triface *)(* frontlist)[j];
24798 if ((oldfront.tet == symfront.tet) &&
24799 (oldfront.loc == symfront.loc)) {
24800 // n is not a front anymore.
24801 if (b->verbose > 2) {
24802 printf(" Remove front (%d, %d, %d).\n",
24803 pointmark(org(oldfront)), pointmark(dest(oldfront)),
24804 pointmark(apex(oldfront)));
24805 }
24806 frontlist->del(j, 1);
24807 newflag = false;
24808 break;
24809 }
24810 }
24811 }
24812 } else {
24813 // n is a subface.
24814 if (newfront.tet == dummytet) {
24815 sesymself(frontsh);
24816 // Create a fake tet to hold n.
24817 maketetrahedron(&newfront);
24818 setorg(newfront, sorg(frontsh));
24819 setdest(newfront, sdest(frontsh));
24820 setapex(newfront, sapex(frontsh));
24821 setoppo(newfront, (point) NULL);
24822 tsbond(newfront, frontsh);
24823 } else {
24824 // n should not be a front of cavity yet.
24825 assert(!infected(newfront));
24826 }
24827 }
24828 if (newflag) {
24829 if (b->verbose > 2) {
24830 printf(" Add front (%d, %d, %d).\n", pointmark(org(newfront)),
24831 pointmark(dest(newfront)), pointmark(apex(newfront)));
24832 }
24833 frontlist->append(&newfront);
24834 }
24835 enextself(front);
24836 }
24837 // Add f into oldtetlist (to be deleted).
24838 infect(front);
24839 oldtetlist->append(&front);
24840 expcavcount++;
24841 }
24842 } while (expflag);
24843}
24844
24846// //
24847// findrelocatepoint() Find new location for relocating a point. //
24848// //
24849// 'frontlist' contains the boundary faces of the cavity C. Some fronts are //
24850// visible by 'stpt' p, some are coplanar with p. //
24851// //
24853
24854bool tetgenmesh::findrelocatepoint(point sp, point np, REAL* n,
24855 list* frontlist, list* oldtetlist)
24856{
24857 triface front;
24858 point pa, pb, pc;
24859 REAL tp[3], tvol, mvol;
24860 REAL ori, eps;
24861 bool visible;
24862 int i, j, k;
24863
24864 if (b->verbose > 1) {
24865 printf(" Find new location for point %d.\n", pointmark(sp));
24866 }
24867
24868 // Avoid compilation warnings.
24869 tvol = mvol = 0.0;
24870 visible = false;
24871
24872 eps = b->epsilon;
24873 // Initialize np far enough from p (outside C).
24874 for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i];
24875 // Let tp = np;
24876 for (i = 0; i < 3; i++) tp[i] = np[i];
24877 // Interation to adjust np until it is visible by all fronts.
24878 j = 0;
24879 do {
24880 for (i = 0; i < frontlist->len(); i++) {
24881 // Get a front face f.
24882 front = * (triface *)(* frontlist)[i];
24883 // Let f face to the interior of C.
24884 adjustedgering(front, CW);
24885 pa = org(front);
24886 pb = dest(front);
24887 pc = apex(front);
24888 ori = orient3d(pa, pb, pc, np);
24889 visible = (ori < 0.0);
24890 if (!visible) {
24891 // A front is invisible by np. Move it towards p along the normal.
24892 for (i = 0; i < 3; i++) np[i] = sp[i] + 0.5 * (sp[i] - np[i]);
24893 // Failed if tp = np.
24894 if ((tp[0] == np[0]) && (tp[1] == np[1]) && (tp[2] == np[2])) {
24895 // Try to expand the cavity.
24896 expandsteinercavity(sp, eps, frontlist, oldtetlist);
24897 eps *= 10.0;
24898 if (eps > b->epsilon * 1000.0) {
24899 // printf("Internal error: Fail to relocate pt %d.\n",pointmark(sp));
24900 // internalerror();
24901 return false;
24902 }
24903 // Restart the point relocation.
24904 for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i];
24905 }
24906 if (j % 2) {
24907 // Set tp = np (at every 2 steps) to catch the stop state.
24908 for (i = 0; i < 3; i++) tp[i] = np[i];
24909 }
24910 break;
24911 } else {
24912 // Save the smallest volume.
24913 if (i == 0) {
24914 mvol = fabs(ori);
24915 } else {
24916 mvol = fabs(ori) < mvol ? fabs(ori) : mvol;
24917 }
24918 }
24919 }
24920 j++;
24921 } while (!visible);
24922
24923 if (b->verbose > 1) {
24924 printf(" %d iterations. minvol = %.12g.\n", j, mvol);
24925 }
24926
24927 // Continue to adjust np until the minimal volume of tets formed by
24928 // fronts and np doesn't increase (all fronts are visible by np).
24929 k = 0;
24930 do {
24931 j = 0;
24932 do {
24933 if (k == 0) {
24934 // Initial tp := np + 0.9 * (p - np). Move toward p.
24935 for (i = 0; i < 3; i++) tp[i] = sp[i] + 0.9 * (np[i] - sp[i]);
24936 } else {
24937 // Initial tp := np + 1.1 * (p - np). Move away from p.
24938 for (i = 0; i < 3; i++) tp[i] = sp[i] + 1.1 * (np[i] - sp[i]);
24939 }
24940 // Get the minial volume formed by tp with one of the fronts.
24941 for (i = 0; i < frontlist->len(); i++) {
24942 // Get a front face f.
24943 front = * (triface *)(* frontlist)[i];
24944 // Let f face to the interior of C.
24945 adjustedgering(front, CW);
24946 pa = org(front);
24947 pb = dest(front);
24948 pc = apex(front);
24949 ori = orient3d(pa, pb, pc, tp);
24950 visible = (ori < 0.0);
24951 if (visible) {
24952 // Save the smallest volume.
24953 if (i == 0) {
24954 tvol = fabs(ori);
24955 } else {
24956 tvol = fabs(ori) < tvol ? fabs(ori) : tvol;
24957 }
24958 } else {
24959 // A front is invisible by tp. Stop.
24960 tvol = 0.0;
24961 break;
24962 }
24963 }
24964 if (tvol > mvol) {
24965 // Get a larger minimal volume.
24966 for (i = 0; i < 3; i++) np[i] = tp[i];
24967 mvol = tvol;
24968 } else {
24969 // Minimal volume decreases. Stop.
24970 break;
24971 }
24972 // Continue to adjust np.
24973 j++;
24974 } while (true);
24975 // Has np been adjusted?
24976 if (j > 0) break;
24977 // Try to move np to anoter direction.
24978 k++;
24979 } while (k < 2);
24980
24981 if (b->verbose > 1) {
24982 printf(" %d adjust iterations. minvol = %.12g.\n", j, mvol);
24983 }
24984 return true;
24985}
24986
24988// //
24989// relocatepoint() Relocate a point into the cavity. //
24990// //
24991// 'frontlist' contains the boundary faces of the cavity C. All fronts must //
24992// be visible by 'steinpt'. Some fronts may hold by 'fake' tets (they are //
24993// hull faces). Fake tets will be removed when they're finished. //
24994// //
24996
24997void tetgenmesh::relocatepoint(point steinpt, triface* oldtet, list* frontlist,
24998 list* newtetlist, queue* flipque)
24999{
25000 triface front, newtet, newface, neightet;
25001 face checksh;
25002 point pa, pb;
25003 REAL attrib, volume;
25004 bool bdflag;
25005 int i, j, k, l;
25006
25007 if (b->verbose > 1) {
25008 printf(" Insert Steiner point (%.12g, %.12g, %.12g) %d.\n",
25009 steinpt[0], steinpt[1], steinpt[2], pointmark(steinpt));
25010 }
25011 // Clear the list first.
25012 newtetlist->clear();
25013
25014 // Create the tets formed by fronts and 'steinpt'.
25015 for (i = 0; i < frontlist->len(); i++) {
25016 // Get a front f.
25017 front = * (triface *)(* frontlist)[i];
25018 // Let f face inside C. (f is a face of tet adjacent to C).
25019 adjustedgering(front, CW);
25020 if (b->verbose > 2) {
25021 printf(" Get front (%d, %d, %d).\n", pointmark(org(front)),
25022 pointmark(dest(front)), pointmark(apex(front)));
25023 }
25024 maketetrahedron(&newtet);
25025 newtetlist->append(&newtet);
25026 setorg(newtet, org(front));
25027 setdest(newtet, dest(front));
25028 setapex(newtet, apex(front));
25029 setoppo(newtet, steinpt);
25030 if (oldtet != (triface *) NULL) {
25031 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
25032 attrib = elemattribute(oldtet->tet, j);
25033 setelemattribute(newtet.tet, j, attrib);
25034 }
25035 if (b->varvolume) {
25036 volume = volumebound(oldtet->tet);
25037 setvolumebound(newtet.tet, volume);
25038 }
25039 }
25040 // 'front' may be a 'fake' tet.
25041 tspivot(front, checksh);
25042 if (oppo(front) == (point) NULL) {
25043 if (checksh.sh != dummysh) {
25044 stdissolve(checksh);
25045 }
25046 // Dealloc the 'fake' tet.
25047 tetrahedrondealloc(front.tet);
25048 // This side (newtet) is a boundary face, let 'dummytet' bond to it.
25049 // Otherwise, 'dummytet' may point to a dead tetrahedron after the
25050 // old cavity tets are removed.
25051 dummytet[0] = encode(newtet);
25052 } else {
25053 // Bond two tetrahedra, also dissolve the old bond at 'front'.
25054 bond(newtet, front);
25055 }
25056 if (checksh.sh != dummysh) {
25057 sesymself(checksh);
25058 tsbond(newtet, checksh);
25059 }
25060 if (flipque != (queue *) NULL) {
25061 // f may be non-locally Delaunay and flipable.
25062 enqueueflipface(newtet, flipque);
25063 }
25064 // The three neighbors are open. Will be finished later.
25065 }
25066
25067 // Connect new tets in C. All connecting faces must contain 'steinpt'.
25068 for (i = 0; i < newtetlist->len(); i++) {
25069 newtet = * (triface *)(* newtetlist)[i];
25070 newtet.ver = 0;
25071 for (j = 0; j < 3; j++) {
25072 fnext(newtet, newface);
25073 sym(newface, neightet);
25074 if (neightet.tet == dummytet) {
25075 // Find a neightet to connect it.
25076 bdflag = false;
25077 pa = org(newface);
25078 pb = dest(newface);
25079 assert(apex(newface) == steinpt);
25080 for (k = i + 1; k < newtetlist->len() && !bdflag; k++) {
25081 neightet = * (triface *)(* newtetlist)[k];
25082 neightet.ver = 0;
25083 for (l = 0; l < 3; l++) {
25084 if ((org(neightet) == pa && dest(neightet) == pb) ||
25085 (org(neightet) == pb && dest(neightet) == pa)) {
25086 // Find the neighbor.
25087 fnextself(neightet);
25088 assert(apex(neightet) == steinpt);
25089 // Now neightet is a face same as newface, bond them.
25090 bond(newface, neightet);
25091 bdflag = true;
25092 break;
25093 }
25094 enextself(neightet);
25095 }
25096 }
25097 assert(bdflag);
25098 }
25099 enextself(newtet);
25100 }
25101 // Let the corners of newtet point to it for fast searching.
25102 pa = org(newtet);
25103 setpoint2tet(pa, encode(newtet));
25104 pa = dest(newtet);
25105 setpoint2tet(pa, encode(newtet));
25106 pa = apex(newtet);
25107 setpoint2tet(pa, encode(newtet));
25108 pa = oppo(newtet);
25109 setpoint2tet(pa, encode(newtet));
25110 }
25111
25112 if (flipque != (queue *) NULL) {
25113 // Recover locally Delaunay faces.
25114 flip(flipque, NULL);
25115 }
25116}
25117
25119// //
25120// findcollapseedge() Find collapseable edge to suppress an endpoint. //
25121// //
25123
25124bool tetgenmesh::findcollapseedge(point suppt, point *conpt, list* oldtetlist,
25125 list* ptlist)
25126{
25127 triface front;
25128 point pt, pa, pb, pc;
25129 REAL *lenarray, ltmp, ori;
25130 bool visflag;
25131 int *idxarray, itmp;
25132 int n, i, j;
25133
25134 if (b->verbose > 2) {
25135 printf(" Search an edge (in %d edges) for collapse %d.\n",
25136 ptlist->len(), pointmark(suppt));
25137 }
25138
25139 // Candidate edges are p to the points of B(p) (in 'ptlist').
25140 n = ptlist->len();
25141 lenarray = new REAL[n];
25142 idxarray = new int[n];
25143 // Sort the points of B(p) by distance to p.
25144 for (i = 0; i < n; i++) {
25145 pt = * (point *)(* ptlist)[i];
25146 lenarray[i] = distance(suppt, pt);
25147 idxarray[i] = i;
25148 }
25149 // Bubble sort.
25150 for (i = 0; i < n - 1; i++) {
25151 for (j = 0; j < n - 1 - i; j++) {
25152 if (lenarray[j + 1] < lenarray[j]) { // compare the two neighbors
25153 ltmp = lenarray[j]; // swap a[j] and a[j + 1]
25154 lenarray[j] = lenarray[j + 1];
25155 lenarray[j + 1] = ltmp;
25156 itmp = idxarray[j]; // swap a[j] and a[j + 1]
25157 idxarray[j] = idxarray[j + 1];
25158 idxarray[j + 1] = itmp;
25159 }
25160 }
25161 }
25162 // For each point q of B(p), test if the edge (p, q) can be collapseed.
25163 for (i = 0; i < n; i++) {
25164 pt = * (point *)(* ptlist)[idxarray[i]];
25165 // Is q visible by faces of B(p) not with q as a vertex.
25166 lenarray[i] = 0.0; // zero volume.
25167 visflag = true;
25168 for (j = 0; j < oldtetlist->len() && visflag; j++) {
25169 front = * (triface *)(* oldtetlist)[j];
25170 // Let f face to inside of B(p).
25171 adjustedgering(front, CCW);
25172 pa = org(front);
25173 pb = dest(front);
25174 pc = apex(front);
25175 // Is f contains q?
25176 if ((pa != pt) && (pb != pt) && (pc != pt)) {
25177 ori = orient3d(pa, pb, pc, pt);
25178 if (ori != 0.0) {
25179 if (iscoplanar(pa, pb, pc, pt, ori, b->epsilon * 1e+2)) ori = 0.0;
25180 }
25181 visflag = ori < 0.0;
25182 if (visflag) {
25183 // Visible, set the smallest volume.
25184 if (j == 0) {
25185 lenarray[i] = fabs(ori);
25186 } else {
25187 lenarray[i] = fabs(ori) < lenarray[i] ? fabs(ori) : lenarray[i];
25188 }
25189 } else {
25190 // Invisible. Do not collapse (p, q).
25191 lenarray[i] = 0.0;
25192 }
25193 }
25194 }
25195 if ((b->verbose > 2) && visflag) {
25196 printf(" Got candidate %d vol(%g).\n", pointmark(pt), lenarray[i]);
25197 }
25198 }
25199
25200 // Select the largest non-zero volume (result in ltmp).
25201 ltmp = lenarray[0];
25202 itmp = idxarray[0];
25203 for (i = 1; i < n; i++) {
25204 if (lenarray[i] != 0.0) {
25205 if (lenarray[i] > ltmp) {
25206 ltmp = lenarray[i];
25207 itmp = idxarray[i]; // The index to find the point.
25208 }
25209 }
25210 }
25211
25212 delete [] lenarray;
25213 delete [] idxarray;
25214
25215 if (ltmp == 0.0) {
25216 // No edge can be collapseed.
25217 *conpt = (point) NULL;
25218 return false;
25219 } else {
25220 pt = * (point *)(* ptlist)[itmp];
25221 *conpt = pt;
25222 return true;
25223 }
25224}
25225
25227// //
25228// collapseedge() Remove a point by edge collapse. //
25229// //
25231
25232void tetgenmesh::collapseedge(point suppt, point conpt, list* oldtetlist,
25233 list* deadtetlist)
25234{
25235 triface oldtet, deadtet;
25236 triface adjtet1, adjtet2;
25237 face adjsh;
25238 point pa, pb, pc;
25239 int i, j;
25240
25241 if (b->verbose > 2) {
25242 printf(" Collapse edge (%d,%d).\n", pointmark(suppt), pointmark(conpt));
25243 }
25244
25245 // Loop in B(p), replace p with np, queue dead tets, uninfect old tets.
25246 for (i = 0; i < oldtetlist->len(); i++) {
25247 oldtet = * (triface *)(* oldtetlist)[i]; // assert(infected(oldtet));
25248 uninfect(oldtet);
25249 pa = org(oldtet);
25250 pb = dest(oldtet);
25251 pc = apex(oldtet);
25252 assert(oppo(oldtet) == suppt);
25253 setoppo(oldtet, conpt);
25254 if ((pa == conpt) || (pb == conpt) || (pc == conpt)) {
25255 deadtetlist->append(&oldtet); // a collpased tet.
25256 }
25257 }
25258 // Loop in deadtetlist, glue adjacent tets of dead tets.
25259 for (i = 0; i < deadtetlist->len(); i++) {
25260 deadtet = * (triface *)(* deadtetlist)[i];
25261 // Get the adjacent tet n1 (outside B(p)).
25262 sym(deadtet, adjtet1);
25263 tspivot(deadtet, adjsh);
25264 // Find the edge in deadtet opposite to conpt.
25265 adjustedgering(deadtet, CCW);
25266 for (j = 0; j < 3; j++) {
25267 if (apex(deadtet) == conpt) break;
25268 enextself(deadtet);
25269 }
25270 assert(j < 3);
25271 // Get another adjacent tet n2.
25272 fnext(deadtet, adjtet2);
25273 symself(adjtet2);
25274 assert(adjtet2.tet != dummytet); // n2 is inside B(p).
25275 if (adjtet1.tet != dummytet) {
25276 bond(adjtet1, adjtet2); // Bond n1 <--> n2.
25277 } else {
25278 dissolve(adjtet2); // Dissolve at n2.
25279 dummytet[0] = encode(adjtet2); // Let dummytet holds n2.
25280 }
25281 if (adjsh.sh != dummysh) {
25282 tsbond(adjtet2, adjsh); // Bond s <--> n2.
25283 }
25284 // Collapse deadtet.
25285 tetrahedrondealloc(deadtet.tet);
25286 }
25287 deadtetlist->clear();
25288}
25289
25291// //
25292// deallocfaketets() Deleted fake tets at fronts. //
25293// //
25294// This routine is only called when the findrelocatepoint() routine fails. //
25295// In other cases, the fake tets are removed automatically in carvecavity() //
25296// or relocatepoint(). //
25297// //
25299
25300void tetgenmesh::deallocfaketets(list* frontlist)
25301{
25302 triface front, neightet;
25303 face checksh;
25304 bool infectflag;
25305 int i;
25306
25307 for (i = 0; i < frontlist->len(); i++) {
25308 // Get a front f.
25309 front = * (triface *)(* frontlist)[i];
25310 // Let f face inside C. (f is a face of tet adjacent to C).
25311 adjustedgering(front, CW);
25312 sym(front, neightet);
25313 tspivot(front, checksh);
25314 if (oppo(front) == (point) NULL) {
25315 if (b->verbose > 2) {
25316 printf(" Get fake tet (%d, %d, %d).\n", pointmark(org(front)),
25317 pointmark(dest(front)), pointmark(apex(front)));
25318 }
25319 if (neightet.tet != dummytet) {
25320 // The neightet may be infected. After dissolve it, the infect flag
25321 // will be lost. Save the flag and restore it later.
25322 infectflag = infected(neightet);
25323 dissolve(neightet);
25324 if (infectflag) {
25325 infect(neightet);
25326 }
25327 }
25328 if (checksh.sh != dummysh) {
25329 infectflag = sinfected(checksh);
25330 stdissolve(checksh);
25331 if (infectflag) {
25332 sinfect(checksh);
25333 }
25334 }
25335 // Dealloc the 'fake' tet.
25336 tetrahedrondealloc(front.tet);
25337 // If 'neightet' is a hull face, let 'dummytet' bond to it. It is
25338 // a 'dummytet' when this front was created from a new subface.
25339 // In such case, it should not be bounded.
25340 if (neightet.tet != dummytet) {
25341 dummytet[0] = encode(neightet);
25342 }
25343 }
25344 }
25345}
25346
25348// //
25349// restorepolyhedron() Restore the tetrahedralization in a polyhedron. //
25350// //
25351// This routine is only called when the operation of suppressing a point is //
25352// aborted (eg., findrelocatepoint() routine fails). The polyhedron has been //
25353// remeshed by new tets. This routine restore the old tets in it. //
25354// //
25355// 'oldtetlist' contains the list of old tets. Each old tet t_o assumes that //
25356// it still connects to a tet t_b of the mesh, however, t_b does not connect //
25357// to t_o, this routine resets the connection such that t_b <--> t_o. //
25358// //
25360
25361void tetgenmesh::restorepolyhedron(list* oldtetlist)
25362{
25363 triface oldtet, neightet, neineitet;
25364 face checksh;
25365 int i;
25366
25367 for (i = 0; i < oldtetlist->len(); i++) {
25368 // Get an old tet t_o.
25369 oldtet = * (triface *)(* oldtetlist)[i];
25370 // Check the four sides of t_o.
25371 for (oldtet.loc = 0; oldtet.loc < 4; oldtet.loc++) {
25372 sym(oldtet, neightet);
25373 tspivot(oldtet, checksh);
25374 if (neightet.tet != dummytet) {
25375 sym(neightet, neineitet);
25376 if (neineitet.tet != oldtet.tet) {
25377 // This face of t_o is a boundary of P.
25378 bond(neightet, oldtet);
25379 if (checksh.sh != dummysh) {
25380 tsbond(oldtet, checksh);
25381 }
25382 }
25383 } else {
25384 // t_o has a hull face. It should be the boundary of P.
25385#ifdef SELF_CHECK
25386 assert(checksh.sh != dummysh);
25387 stpivot(checksh, neineitet);
25388 assert(neineitet.tet != oldtet.tet);
25389#endif
25390 tsbond(oldtet, checksh);
25391 // Let dummytet[0] points to it.
25392 dummytet[0] = encode(oldtet);
25393 }
25394 }
25395 }
25396}
25397
25399// //
25400// suppressfacetpoint() Suppress a point inside a facet. //
25401// //
25402// The point p inside a facet F will be suppressed from F by either being //
25403// deleted from the mesh or being relocated into the volume. //
25404// //
25405// 'supsh' is a subface f of F, and p = sapex(f); the other parameters are //
25406// working lists which are empty at the beginning and the end. //
25407// //
25408// 'optflag' is used for mesh optimization. If it is set, after removing p, //
25409// test the object function on each new tet, queue bad tets. //
25410// //
25412
25413bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
25414 list* misfrontlist, list* ptlist, list* conlist, memorypool* viri,
25415 queue* flipque, bool noreloc, bool optflag)
25416{
25417 list *oldtetlist[2], *newtetlist[2];
25418 list *oldshlist, *newshlist;
25419 triface oldtet, newtet;
25420 face oldsh, newsh;
25421 point suppt, newpt[2];
25422 point *cons;
25423 REAL norm[3];
25424 bool success;
25425 int shmark;
25426 int i, j;
25427
25428 suppt = sapex(*supsh);
25429 if (b->verbose > 1) {
25430 printf(" Suppress point %d in facet.\n", pointmark(suppt));
25431 }
25432
25433 // Initialize working lists, variables.
25434 for (i = 0; i < 2; i++) {
25435 oldtetlist[i] = (list *) NULL;
25436 newtetlist[i] = (list *) NULL;
25437 newpt[i] = (point) NULL;
25438 }
25439 oldshlist = new list(sizeof(face), NULL, 256);
25440 newshlist = new list(sizeof(face), NULL, 256);
25441 success = true; // Assume p can be suppressed.
25442
25443 // Find subs of C(p).
25444 oldshlist->append(supsh);
25445 formstarpolygon(suppt, oldshlist, ptlist);
25446 // Get the edges of C(p). They form a closed polygon.
25447 for (i = 0; i < oldshlist->len(); i++) {
25448 oldsh = * (face *)(* oldshlist)[i];
25449 cons = (point *) conlist->append(NULL);
25450 cons[0] = sorg(oldsh);
25451 cons[1] = sdest(oldsh);
25452 }
25453 // Re-triangulate the old C(p).
25454 shmark = shellmark(*supsh);
25455 triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque);
25456 // Get new subs of C(p), remove protected segments.
25457 retrievenewsubs(newshlist, true);
25458 // Substitute the old C(p) with the new C(p)
25459 replacepolygonsubs(oldshlist, newshlist);
25460 // Clear work lists.
25461 ptlist->clear();
25462 conlist->clear();
25463 flipque->clear();
25464 viri->restart();
25465
25466 // B(p) (tets with p as a vertex) has been separated into two parts
25467 // (B_0(p) and B_1(p)) by F. Process them individually.
25468 for (i = 0; i < 2 && success; i++) {
25469 if (i == 1) sesymself(*supsh);
25470 // Get a tet containing p.
25471 stpivot(*supsh, oldtet);
25472 // Is this part empty?
25473 if (oldtet.tet == dummytet) continue;
25474 // Allocate spaces for storing (old and new) B_i(p).
25475 oldtetlist[i] = new list(sizeof(triface), NULL, 256);
25476 newtetlist[i] = new list(sizeof(triface), NULL, 256);
25477 // Form old B_i(p) in oldtetlist[i].
25478 assert(!isdead(&oldtet));
25479 oldtetlist[i]->append(&oldtet);
25480 formstarpolyhedron(suppt, oldtetlist[i], ptlist, false);
25481 // Infect the tets in old B_i(p) (they're going to be delete).
25482 for (j = 0; j < oldtetlist[i]->len(); j++) {
25483 oldtet = * (triface *)(* (oldtetlist[i]))[j];
25484 infect(oldtet);
25485 }
25486 // Preparation for re-tetrahedralzing old B_i(p).
25487 orientnewsubs(newshlist, supsh, norm);
25488 // Tetrahedralize old B_i(p).
25489 success = constrainedcavity(&oldtet, newshlist, oldtetlist[i], ptlist,
25490 frontlist, misfrontlist, newtetlist[i], flipque);
25491 // If p is not suppressed, do relocation if 'noreloc' is not set.
25492 if (!success && !noreloc) {
25493 // Try to relocate p into the old B_i(p).
25494 makepoint(&(newpt[i]));
25495 success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
25496 oldtetlist[i]);
25497 // Initialize newpt = suppt.
25498 // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j];
25499 // success = smoothvolpoint(newpt[i], frontlist, true);
25500 if (success) {
25501 // p is relocated by newpt[i]. Now insert it. Don't do flip since
25502 // the new tets may get deleted again.
25503 relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL);
25504 setpointtype(newpt[i], FREEVOLVERTEX);
25505 relverts++;
25506 } else {
25507 // Fail to relocate p. Clean fake tets and quit this option.
25508 deallocfaketets(frontlist);
25509 pointdealloc(newpt[i]);
25510 newpt[i] = (point) NULL;
25511 assert(newtetlist[i]->len() == 0);
25512 }
25513 }
25514 if (!success && noreloc) {
25515 // Failed and no point relocation. Clean fake tets.
25516 deallocfaketets(frontlist);
25517 }
25518 // Clear work lists.
25519 ptlist->clear();
25520 frontlist->clear();
25521 misfrontlist->clear();
25522 flipque->clear();
25523 }
25524
25525 if (success) {
25526 // p has been removed! (Still in the pool).
25527 setpointtype(suppt, UNUSEDVERTEX);
25528 unuverts++;
25529 // Delete old C(p).
25530 for (i = 0; i < oldshlist->len(); i++) {
25531 oldsh = * (face *)(* oldshlist)[i];
25532 if (i == 0) {
25533 // Update the 'hullsize' if C(p) is on the hull.
25534 stpivot(oldsh, oldtet);
25535 if (oldtet.tet != dummytet) {
25536 sesymself(oldsh);
25537 stpivot(oldsh, oldtet);
25538 }
25539 if (oldtet.tet == dummytet) {
25540 // A boundary face. Update the 'hullsize'.
25541 j = oldshlist->len() - newshlist->len();
25542 assert(j > 0);
25543 hullsize -= j;
25544 }
25545 }
25546 shellfacedealloc(subfaces, oldsh.sh);
25547 }
25548 // Delete old B_i(p).
25549 for (i = 0; i < 2; i++) {
25550 if (oldtetlist[i] != (list *) NULL) {
25551 // Delete tets of the old B_i(p).
25552 for (j = 0; j < oldtetlist[i]->len(); j++) {
25553 oldtet = * (triface *)(* (oldtetlist[i]))[j];
25554 assert(!isdead(&oldtet));
25555 tetrahedrondealloc(oldtet.tet);
25556 }
25557 }
25558 }
25559 if (optflag) {
25560 // Check for new bad-quality tets.
25561 for (i = 0; i < 2; i++) {
25562 if (newtetlist[i] != (list *) NULL) {
25563 for (j = 0; j < newtetlist[i]->len(); j++) {
25564 newtet = * (triface *)(* (newtetlist[i]))[j];
25565 if (!isdead(&newtet)) checktet4opt(&newtet, true);
25566 }
25567 }
25568 }
25569 }
25570 } else {
25571 // p is not suppressed. Recover the original state.
25572 unsupverts++;
25573 // Restore the old C(p).
25574 replacepolygonsubs(newshlist, oldshlist);
25575 // Delete subs of the new C(p)
25576 for (i = 0; i < newshlist->len(); i++) {
25577 newsh = * (face *)(* newshlist)[i];
25578 shellfacedealloc(subfaces, newsh.sh);
25579 }
25580 // Restore old B_i(p).
25581 for (i = 0; i < 2; i++) {
25582 if (oldtetlist[i] != (list *) NULL) {
25583 // Uninfect tets of old B_i(p).
25584 for (j = 0; j < oldtetlist[i]->len(); j++) {
25585 oldtet = * (triface *)(* (oldtetlist[i]))[j];
25586 assert(infected(oldtet));
25587 uninfect(oldtet);
25588 }
25589 // Has it been re-meshed?
25590 if (newtetlist[i]->len() > 0) {
25591 // Restore the old B_i(p).
25592 restorepolyhedron(oldtetlist[i]);
25593 // Delete tets of the new B_i(p);
25594 for (j = 0; j < newtetlist[i]->len(); j++) {
25595 newtet = * (triface *)(* (newtetlist[i]))[j];
25596 // Some new tets may already be deleted (by carvecavity()).
25597 if (!isdead(&newtet)) {
25598 tetrahedrondealloc(newtet.tet);
25599 }
25600 }
25601 }
25602 // Dealloc newpt[i] if it exists.
25603 if (newpt[i] != (point) NULL) {
25604 pointdealloc(newpt[i]);
25605 relverts--;
25606 }
25607 }
25608 }
25609 }
25610
25611 // Delete work lists.
25612 delete oldshlist;
25613 delete newshlist;
25614 for (i = 0; i < 2; i++) {
25615 if (oldtetlist[i] != (list *) NULL) {
25616 delete oldtetlist[i];
25617 delete newtetlist[i];
25618 }
25619 }
25620
25621 return success;
25622}
25623
25625// //
25626// suppresssegpoint() Suppress a point on a segment. //
25627// //
25628// The point p on a segment S will be suppressed from S by either being //
25629// deleted from the mesh or being relocated into the volume. //
25630// //
25631// 'supseg' is the segment S, and p = sdest(S); the other parameters are //
25632// working lists which are empty at the beginning and the end. //
25633// //
25635
25636bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
25637 list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist,
25638 list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag)
25639{
25640 list **oldtetlist, **newtetlist;
25641 list **oldshlist, **newshlist;
25642 list *pnewshlist, *dnewshlist;
25643 triface oldtet, newtet;
25644 face oldsh, newsh;
25645 face startsh, spinsh, segsh1, segsh2;
25646 face nsupseg, newseg, prevseg, nextseg;
25647 point suppt, *newpt;
25648 point pa, pb, *cons;
25649 REAL pnorm[2][3], norm[3];
25650 bool success;
25651 int shmark;
25652 int n, i, j, k;
25653
25654 // Get the Steiner point p.
25655 assert(supseg->shver < 2);
25656 suppt = sdest(*supseg);
25657 // Find the segment ab split by p.
25658 senext(*supseg, nsupseg);
25659 spivotself(nsupseg);
25660 assert(nsupseg.sh != dummysh);
25661 nsupseg.shver = 0;
25662 if (sorg(nsupseg) != suppt) sesymself(nsupseg);
25663 assert(sorg(nsupseg) == suppt);
25664 pa = sorg(*supseg);
25665 pb = sdest(nsupseg);
25666 if (b->verbose > 1) {
25667 printf(" Remove point %d on segment (%d, %d).\n",
25668 pointmark(suppt), pointmark(pa), pointmark(pb));
25669 }
25670
25671 // Let startsh s containing p.
25672 spivot(*supseg, startsh);
25673 spinsh = startsh;
25674 do {
25675 // Save it in list.
25676 spinshlist->append(&spinsh);
25677 // Go to the next facet.
25678 spivotself(spinsh);
25679 } while (spinsh.sh != startsh.sh);
25680 if (spinshlist->len() == 1) {
25681 // This case has not handled yet.
25682 // printf("Unhandled case: segment only belongs to one facet.\n");
25683 spinshlist->clear();
25684 unsupverts++;
25685 return false;
25686 }
25687
25688 // Suppose ab is shared by n facets (n > 1), then there are n B(p) (tets
25689 // with p as a vertex). Some B(p) may be empty, eg, outside.
25690 n = spinshlist->len();
25691 oldtetlist = new list*[n];
25692 newtetlist = new list*[n];
25693 oldshlist = new list*[n];
25694 newshlist = new list*[n];
25695 newpt = new point[n];
25696 for (i = 0; i < n; i++) {
25697 oldtetlist[i] = (list *) NULL;
25698 newtetlist[i] = (list *) NULL;
25699 oldshlist[i] = (list *) NULL;
25700 newshlist[i] = (list *) NULL;
25701 newpt[i] = (point) NULL;
25702 }
25703
25704 // Create a new segment ab (result in newseg).
25705 makeshellface(subsegs, &newseg);
25706 setsorg(newseg, pa);
25707 setsdest(newseg, pb);
25708 // ab gets the same mark and segment type as ap.
25709 setshellmark(newseg, shellmark(*supseg));
25710 setshelltype(newseg, shelltype(*supseg));
25711 if (b->quality && varconstraint) {
25712 // Copy the areabound into the new subsegment.
25713 setareabound(newseg, areabound(*supseg));
25714 }
25715 // Save the old connection at a.
25716 senext2(*supseg, prevseg);
25717 spivotself(prevseg);
25718 if (prevseg.sh != dummysh) {
25719 prevseg.shver = 0;
25720 if (sdest(prevseg) != pa) sesymself(prevseg);
25721 assert(sdest(prevseg) == pa);
25722 senextself(prevseg);
25723 senext2self(newseg);
25724 sbond(newseg, prevseg);
25725 newseg.shver = 0;
25726 }
25727 // Save the old connection at b.
25728 senext(nsupseg, nextseg);
25729 spivotself(nextseg);
25730 if (nextseg.sh != dummysh) {
25731 nextseg.shver = 0;
25732 if (sorg(nextseg) != pb) sesymself(nextseg);
25733 assert(sorg(nextseg) == pb);
25734 senext2self(nextseg);
25735 senextself(newseg);
25736 sbond(newseg, nextseg);
25737 newseg.shver = 0;
25738 }
25739
25740 // Re-triangulate C(p) (subs with p as a vertex) to remove p.
25741 for (i = 0; i < spinshlist->len(); i++) {
25742 spinsh = * (face *)(* spinshlist)[i];
25743 // Allocate spaces for C_i(p).
25744 oldshlist[i] = new list(sizeof(face), NULL, 256);
25745 newshlist[i] = new list(sizeof(face), NULL, 256);
25746 // Get the subs of C_i(p).
25747 oldshlist[i]->append(&spinsh);
25748 formstarpolygon(suppt, oldshlist[i], ptlist);
25749 // Find the edges of C_i(p). It DOES NOT form a closed polygon.
25750 for (j = 0; j < oldshlist[i]->len(); j++) {
25751 oldsh = * (face *)(* (oldshlist[i]))[j];
25752 cons = (point *) conlist->append(NULL);
25753 cons[0] = sorg(oldsh);
25754 cons[1] = sdest(oldsh);
25755 }
25756 // The C_i(p) isn't closed without ab. Add it to it.
25757 cons = (point *) conlist->append(NULL);
25758 cons[0] = pa;
25759 cons[1] = pb;
25760 // Re-triangulate C_i(p).
25761 shmark = shellmark(spinsh);
25762 triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque);
25763 // Get new subs of C_i(p), remove protected segments.
25764 retrievenewsubs(newshlist[i], true);
25765 // Substitute old C_i(p) with the new C_i(p). !IT IS NOT COMPLETE!
25766 replacepolygonsubs(oldshlist[i], newshlist[i]);
25767 // Find the new subface s having edge ab.
25768 for (j = 0; j < newshlist[i]->len(); j++) {
25769 segsh1 = * (face *)(* (newshlist[i]))[j];
25770 for (k = 0; k < 3; k++) {
25771 if (((sorg(segsh1) == pa) && (sdest(segsh1) == pb)) ||
25772 ((sorg(segsh1) == pb) && (sdest(segsh1) == pa))) break;
25773 senextself(segsh1);
25774 }
25775 if (k < 3) break; // Found.
25776 }
25777 assert(j < newshlist[i]->len()); // ab must exist.
25778 // Bond s and ab together. The C_i(p) is completedly substituted.
25779 ssbond(segsh1, newseg);
25780 // Save s for forming the face ring of ab.
25781 newsegshlist->append(&segsh1);
25782 // Clear work lists.
25783 ptlist->clear();
25784 conlist->clear();
25785 flipque->clear();
25786 viri->restart();
25787 }
25788 // Form the face ring of ab.
25789 for (i = 0; i < newsegshlist->len(); i++) {
25790 segsh1 = * (face *)(* newsegshlist)[i];
25791 if ((i + 1) == newsegshlist->len()) {
25792 segsh2 = * (face *)(* newsegshlist)[0];
25793 } else {
25794 segsh2 = * (face *)(* newsegshlist)[i + 1];
25795 }
25796 sbond1(segsh1, segsh2);
25797 }
25798
25799 // A work list for keeping subfaces from two facets.
25800 dnewshlist = new list(sizeof(face), NULL, 256);
25801 success = true; // Assume p is suppressable.
25802
25803 // Suppress p in all B(p). B_i(p) is looped wrt the right-hand rule of ab.
25804 for (i = 0; i < spinshlist->len() && success; i++) {
25805 // Get an old subface s (ap) of a facet.
25806 spinsh = * (face *)(* spinshlist)[i];
25807 // Let the edge direction of s be a->b. Hence all subfaces follow
25808 // the right-hand rule of ab.
25809 if (sorg(spinsh) != pa) sesymself(spinsh);
25810 // Get a tet t of B_i(p).
25811 stpivot(spinsh, oldtet);
25812 // Is B_i(p) empty?
25813 if (oldtet.tet == dummytet) continue;
25814 // Allocate spaces for B_i(p).
25815 oldtetlist[i] = new list(sizeof(triface), NULL, 256);
25816 newtetlist[i] = new list(sizeof(triface), NULL, 256);
25817 // Find all tets of old B_i(p).
25818 oldtetlist[i]->append(&oldtet);
25819 formstarpolyhedron(suppt, oldtetlist[i], ptlist, false);
25820 // Infect tets of old B_i(p) (they're going to be deleted).
25821 for (j = 0; j < oldtetlist[i]->len(); j++) {
25822 oldtet = * (triface *)(* (oldtetlist[i]))[j];
25823 infect(oldtet);
25824 }
25825 // Collect new subfaces (of two facets) bounded B_i(p).
25826 for (k = 0; k < 2; k++) {
25827 if ((i + k) < spinshlist->len()) {
25828 pnewshlist = newshlist[i + k];
25829 segsh1 = * (face *)(* spinshlist)[i + k];
25830 } else {
25831 pnewshlist = newshlist[0];
25832 segsh1 = * (face *)(* spinshlist)[0];
25833 }
25834 // Adjust the orientation of segsh1 to face to the inside of C.
25835 if (k == 0) {
25836 if (sorg(segsh1) != pa) sesymself(segsh1);
25837 assert(sorg(segsh1) == pa);
25838 } else {
25839 if (sdest(segsh1) != pa) sesymself(segsh1);
25840 assert(sdest(segsh1) == pa);
25841 }
25842 // Preparation for re-tetrahedralzing old B_i(p).
25843 orientnewsubs(pnewshlist, &segsh1, pnorm[k]);
25844 for (j = 0; j < pnewshlist->len(); j++) {
25845 dnewshlist->append((face *)(* pnewshlist)[j]);
25846 }
25847 }
25848 // Tetrahedralize B_i(p).
25849 success = constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
25850 frontlist, misfrontlist, newtetlist[i], flipque);
25851 if (!success && !noreloc) {
25852 // C must be finished by re-locating the steiner point.
25853 makepoint(&(newpt[i]));
25854 for (j = 0; j < 3; j++) norm[j] = 0.5 * (pnorm[0][j] + pnorm[1][j]);
25855 success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
25856 oldtetlist[i]);
25857 // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j];
25858 // success = smoothvolpoint(newpt[i], frontlist, true);
25859 if (success) {
25860 // p is relocated by newpt[i]. Now insert it. Don't do flip since
25861 // the new tets may get deleted again.
25862 relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL);
25863 setpointtype(newpt[i], FREEVOLVERTEX);
25864 relverts++;
25865 } else {
25866 // Fail to relocate p. Clean fake tets and quit this option.
25867 deallocfaketets(frontlist);
25868 pointdealloc(newpt[i]);
25869 newpt[i] = (point) NULL;
25870 assert(newtetlist[i]->len() == 0);
25871 }
25872 }
25873 if (!success && noreloc) {
25874 // Failed and no point relocation. Clean fake tets.
25875 deallocfaketets(frontlist);
25876 }
25877 // Clear work lists.
25878 dnewshlist->clear();
25879 ptlist->clear();
25880 frontlist->clear();
25881 misfrontlist->clear();
25882 flipque->clear();
25883 }
25884
25885 if (success) {
25886 // p has been suppressed. (Still in the pool).
25887 setpointtype(suppt, UNUSEDVERTEX);
25888 unuverts++;
25889 // Update the segmnet pointers saved in a and b.
25890 setpoint2sh(pa, sencode(newseg));
25891 setpoint2sh(pb, sencode(newseg));
25892 // Delete old segments ap, pb.
25893 shellfacedealloc(subsegs, supseg->sh);
25894 shellfacedealloc(subsegs, nsupseg.sh);
25895 // Delete subs of old C_i(p).
25896 for (i = 0; i < spinshlist->len(); i++) {
25897 for (j = 0; j < oldshlist[i]->len(); j++) {
25898 oldsh = * (face *)(* (oldshlist[i]))[j];
25899 if (j == 0) {
25900 // Update 'hullsize' if C_i(p) is on the hull.
25901 stpivot(oldsh, oldtet);
25902 if (oldtet.tet != dummytet) {
25903 sesymself(oldsh);
25904 stpivot(oldsh, oldtet);
25905 }
25906 if (oldtet.tet == dummytet) {
25907 // Update 'hullsize'.
25908 k = oldshlist[i]->len() - newshlist[i]->len();
25909 assert(k > 0);
25910 hullsize -= k;
25911 }
25912 }
25913 shellfacedealloc(subfaces, oldsh.sh);
25914 }
25915 }
25916 // Delete tets old B_i(p).
25917 for (i = 0; i < spinshlist->len(); i++) {
25918 // Delete them if it is not empty.
25919 if (oldtetlist[i] != (list *) NULL) {
25920 for (j = 0; j < oldtetlist[i]->len(); j++) {
25921 oldtet = * (triface *)(* (oldtetlist[i]))[j];
25922 assert(!isdead(&oldtet));
25923 tetrahedrondealloc(oldtet.tet);
25924 }
25925 }
25926 }
25927 if (optflag) {
25928 for (i = 0; i < spinshlist->len(); i++) {
25929 // Check for new bad-quality tets.
25930 if (newtetlist[i] != (list *) NULL) {
25931 for (j = 0; j < newtetlist[i]->len(); j++) {
25932 newtet = * (triface *)(* (newtetlist[i]))[j];
25933 if (!isdead(&newtet)) checktet4opt(&newtet, true);
25934 }
25935 }
25936 }
25937 }
25938 } else {
25939 // p is not suppressed. Recover the original state.
25940 unsupverts++;
25941 // Restore old connection at a.
25942 senext2(*supseg, prevseg);
25943 spivotself(prevseg);
25944 if (prevseg.sh != dummysh) {
25945 prevseg.shver = 0;
25946 if (sdest(prevseg) != pa) sesymself(prevseg);
25947 assert(sdest(prevseg) == pa);
25948 senextself(prevseg);
25949 senext2self(*supseg);
25950 sbond(*supseg, prevseg);
25951 senextself(*supseg); // Restore original state.
25952 assert(supseg->shver < 2);
25953 }
25954 // Restore old connection at b.
25955 senext(nsupseg, nextseg);
25956 spivotself(nextseg);
25957 if (nextseg.sh != dummysh) {
25958 nextseg.shver = 0;
25959 if (sorg(nextseg) != pb) sesymself(nextseg);
25960 assert(sorg(nextseg) == pb);
25961 senext2self(nextseg);
25962 senextself(nsupseg);
25963 sbond(nsupseg, nextseg);
25964 // nsupseg.shver = 0;
25965 senext2self(nsupseg); // Restore original state
25966 assert(nsupseg.shver < 2);
25967 }
25968 // Delete the new segment ab.
25969 shellfacedealloc(subsegs, newseg.sh);
25970 // Restore old C_i(p).
25971 for (i = 0; i < spinshlist->len(); i++) {
25972 replacepolygonsubs(newshlist[i], oldshlist[i]);
25973 // Delete subs of the new C_i(p)
25974 for (j = 0; j < newshlist[i]->len(); j++) {
25975 newsh = * (face *)(* (newshlist[i]))[j];
25976 shellfacedealloc(subfaces, newsh.sh);
25977 }
25978 }
25979 // Restore old B_i(p).
25980 for (i = 0; i < spinshlist->len(); i++) {
25981 if (oldtetlist[i] != (list *) NULL) {
25982 // Uninfect tets of old B_i(p).
25983 for (j = 0; j < oldtetlist[i]->len(); j++) {
25984 oldtet = * (triface *)(* (oldtetlist[i]))[j];
25985 assert(infected(oldtet));
25986 uninfect(oldtet);
25987 }
25988 // Has it been re-meshed?
25989 if (newtetlist[i]->len() > 0) {
25990 // Restore the old B_i(p).
25991 restorepolyhedron(oldtetlist[i]);
25992 // Delete tets of the new B_i(p);
25993 for (j = 0; j < newtetlist[i]->len(); j++) {
25994 newtet = * (triface *)(* (newtetlist[i]))[j];
25995 // Some new tets may already be deleted (by carvecavity()).
25996 if (!isdead(&newtet)) {
25997 tetrahedrondealloc(newtet.tet);
25998 }
25999 }
26000 }
26001 // Dealloc newpt[i] if it exists.
26002 if (newpt[i] != (point) NULL) {
26003 pointdealloc(newpt[i]);
26004 relverts--;
26005 }
26006 }
26007 }
26008 }
26009
26010 // Delete work lists.
26011 delete dnewshlist;
26012 for (i = 0; i < spinshlist->len(); i++) {
26013 delete oldshlist[i];
26014 delete newshlist[i];
26015 }
26016 delete [] oldshlist;
26017 delete [] newshlist;
26018 for (i = 0; i < spinshlist->len(); i++) {
26019 if (oldtetlist[i] != (list *) NULL) {
26020 delete oldtetlist[i];
26021 delete newtetlist[i];
26022 }
26023 }
26024 delete [] oldtetlist;
26025 delete [] newtetlist;
26026 // Clear work lists.
26027 newsegshlist->clear();
26028 spinshlist->clear();
26029
26030 return success;
26031}
26032
26034// //
26035// suppressvolpoint() Suppress a point inside mesh. //
26036// //
26037// The point p = org(suptet) is inside the mesh and will be suppressed from //
26038// the mesh. Note that p may not be suppressed. //
26039// //
26040// 'optflag' is used for mesh optimization. If it is set, after removing p, //
26041// test the object function on each new tet, queue bad tets. //
26042// //
26044
26045bool tetgenmesh::suppressvolpoint(triface* suptet, list* frontlist,
26046 list* misfrontlist, list* ptlist, queue* flipque, bool optflag)
26047{
26048 list *myfrontlist, *mymisfrontlist, *myptlist;
26049 list *oldtetlist, *newtetlist;
26050 list *newshlist; // a dummy list.
26051 queue *myflipque;
26052 triface oldtet, newtet;
26053 point suppt, conpt;
26054 bool success;
26055 int j;
26056
26057 // Allocate spaces for storing (old and new) B(p).
26058 oldtetlist = new list(sizeof(triface), NULL, 256);
26059 newtetlist = new list(sizeof(triface), NULL, 256);
26060 newshlist = new list(sizeof(face), NULL, 256);
26061 // Allocate work lists if user doesn't supply them.
26062 myfrontlist = mymisfrontlist = myptlist = (list *) NULL;
26063 myflipque = (queue *) NULL;
26064 if (frontlist == (list *) NULL) {
26065 myfrontlist = new list(sizeof(triface), NULL, 256);
26066 frontlist = myfrontlist;
26067 mymisfrontlist = new list(sizeof(triface), NULL, 256);
26068 misfrontlist = mymisfrontlist;
26069 myptlist = new list(sizeof(point *), NULL, 256);
26070 ptlist = myptlist;
26071 myflipque = new queue(sizeof(badface));
26072 flipque = myflipque;
26073 }
26074
26075 suppt = org(*suptet);
26076 oldtet = *suptet;
26077 success = true; // Assume p can be suppressed.
26078
26079 if (b->verbose > 1) {
26080 printf(" Remove point %d in mesh.\n", pointmark(suppt));
26081 }
26082
26083 // Form old B(p) in oldtetlist.
26084 oldtetlist->append(&oldtet);
26085 formstarpolyhedron(suppt, oldtetlist, ptlist, false);
26086 // Infect the tets in old B(p) (they're going to be delete).
26087 for (j = 0; j < oldtetlist->len(); j++) {
26088 oldtet = * (triface *)(* oldtetlist)[j];
26089 infect(oldtet);
26090 }
26091 // Tetrahedralize old B(p).
26092 success = constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist,
26093 frontlist, misfrontlist, newtetlist, flipque);
26094 if (!success) {
26095 // Unable to suppress p.
26096 deallocfaketets(frontlist);
26097 // Try to collapse an edge at p.
26098 conpt = (point) NULL;
26099 assert(newtetlist->len() == 0);
26100 if (findcollapseedge(suppt, &conpt, oldtetlist, ptlist)) {
26101 // Collapse the edge suppt->conpt. Re-use newtetlist.
26102 collapseedge(suppt, conpt, oldtetlist, newtetlist);
26103 // The oldtetlist contains newtetlist.
26104 if (optflag) {
26105 assert(newtetlist->len() == 0);
26106 for (j = 0; j < oldtetlist->len(); j++) {
26107 newtet = * (triface *)(* oldtetlist)[j];
26108 newtetlist->append(&newtet);
26109 }
26110 }
26111 oldtetlist->clear(); // Do not delete them.
26112 collapverts++;
26113 success = true;
26114 }
26115 }
26116 if (success) {
26117 // p has been removed! (Still in the pool).
26118 setpointtype(suppt, UNUSEDVERTEX);
26119 unuverts++;
26120 suprelverts++;
26121 // Delete old B(p).
26122 for (j = 0; j < oldtetlist->len(); j++) {
26123 oldtet = * (triface *)(* oldtetlist)[j];
26124 assert(!isdead(&oldtet));
26125 tetrahedrondealloc(oldtet.tet);
26126 }
26127 if (optflag) {
26128 // Check for new bad tets.
26129 for (j = 0; j < newtetlist->len(); j++) {
26130 newtet = * (triface *)(* newtetlist)[j];
26131 if (!isdead(&newtet)) checktet4opt(&newtet, true);
26132 }
26133 }
26134 } else {
26135 // p is not suppressed. Recover the original state.
26136 // Uninfect tets of old B(p).
26137 for (j = 0; j < oldtetlist->len(); j++) {
26138 oldtet = * (triface *)(* oldtetlist)[j];
26139 assert(infected(oldtet));
26140 uninfect(oldtet);
26141 }
26142 }
26143
26144 // Clear work lists.
26145 ptlist->clear();
26146 frontlist->clear();
26147 misfrontlist->clear();
26148 flipque->clear();
26149 // Deallocate work lists.
26150 if (myfrontlist != (list *) NULL) {
26151 delete myfrontlist;
26152 delete mymisfrontlist;
26153 delete myptlist;
26154 delete myflipque;
26155 }
26156 delete oldtetlist;
26157 delete newtetlist;
26158 delete newshlist;
26159
26160 return success;
26161}
26162
26164// //
26165// smoothpoint() Smooth a volume/segment point. //
26166// //
26167// 'smthpt' (p) is inside the polyhedron (C) bounded by faces in 'starlist'. //
26168// This routine moves p inside C until an object function is maximized. //
26169// //
26170// Default, the CCW edge ring of the faces on C points to p. If 'invtori' is //
26171// TRUE, the orientation is inversed. //
26172// //
26173// If 'key' != NULL, it contains an object value to be improved. Current it //
26174// means the cosine of the largest dihedral angle. In such case, the point //
26175// is smoothed only if the final configuration improves the object value, it //
26176// is returned by the 'key'. //
26177// //
26179
26180bool tetgenmesh::smoothpoint(point smthpt, point e1, point e2, list *starlist,
26181 bool invtori, REAL *key)
26182{
26183 triface starttet;
26184 point pa, pb, pc;
26185 REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
26186 REAL iniTmax, oldTmax, newTmax;
26187 REAL ori, aspT, aspTmax, imprate;
26188 REAL cosd, maxcosd;
26189 bool segflag, randflag; //, subflag;
26190 int numdirs;
26191 int iter, i, j;
26192
26193 // Is p a segment vertex?
26194 segflag = (e1 != (point) NULL);
26195 // Decide the number of moving directions.
26196 numdirs = segflag ? 2 : starlist->len();
26197 randflag = numdirs > 10;
26198 if (randflag) {
26199 numdirs = 10; // Maximum 10 directions.
26200 }
26201
26202 aspTmax = 0.0;
26203 // Calculate the initial object value (the largest aspect ratio).
26204 for (i = 0; i < starlist->len(); i++) {
26205 starttet = * (triface *)(* starlist)[i];
26206 adjustedgering(starttet, !invtori ? CCW : CW);
26207 pa = org(starttet);
26208 pb = dest(starttet);
26209 pc = apex(starttet);
26210 aspT = tetaspectratio(pa, pb, pc, smthpt);
26211 if (i == 0) {
26212 aspTmax = aspT;
26213 } else {
26214 aspTmax = aspT > aspTmax ? aspT : aspTmax;
26215 }
26216 }
26217 iniTmax = aspTmax;
26218
26219 if (b->verbose > 1) {
26220 printf(" Smooth %s point %d (%g, %g, %g).\n", segflag ? "seg" : "vol",
26221 pointmark(smthpt), smthpt[0], smthpt[1], smthpt[2]);
26222 printf(" Initial max L/h = %g.\n", iniTmax);
26223 }
26224 for (i = 0; i < 3; i++) {
26225 bestpt[i] = startpt[i] = smthpt[i];
26226 }
26227
26228 // Do iteration until the new aspTmax does not decrease.
26229 newTmax = iniTmax;
26230 iter = 0;
26231 while (true) {
26232 // Find the best next location.
26233 oldTmax = newTmax;
26234 for (i = 0; i < numdirs; i++) {
26235 // Calculate the moved point (saved in 'nextpt').
26236 if (!segflag) {
26237 if (randflag) {
26238 // Randomly pick a direction.
26239 j = (int) randomnation(starlist->len());
26240 } else {
26241 j = i;
26242 }
26243 starttet = * (triface *)(* starlist)[j];
26244 adjustedgering(starttet, !invtori ? CCW : CW);
26245 pa = org(starttet);
26246 pb = dest(starttet);
26247 pc = apex(starttet);
26248 for (j = 0; j < 3; j++) {
26249 fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
26250 }
26251 } else {
26252 for (j = 0; j < 3; j++) {
26253 fcent[j] = (i == 0 ? e1[j] : e2[j]);
26254 }
26255 }
26256 for (j = 0; j < 3; j++) {
26257 nextpt[j] = startpt[j] + 0.01 * (fcent[j] - startpt[j]);
26258 }
26259 // Get the largest object value for the new location.
26260 for (j = 0; j < starlist->len(); j++) {
26261 starttet = * (triface *)(* starlist)[j];
26262 adjustedgering(starttet, !invtori ? CCW : CW);
26263 pa = org(starttet);
26264 pb = dest(starttet);
26265 pc = apex(starttet);
26266 ori = orient3d(pa, pb, pc, nextpt);
26267 if (ori < 0.0) {
26268 aspT = tetaspectratio(pa, pb, pc, nextpt);
26269 if (j == 0) {
26270 aspTmax = aspT;
26271 } else {
26272 aspTmax = aspT > aspTmax ? aspT : aspTmax;
26273 }
26274 } else {
26275 // An invalid new tet. Discard this point.
26276 aspTmax = newTmax;
26277 } // if (ori < 0.0)
26278 // Stop looping when the object value is bigger than before.
26279 if (aspTmax >= newTmax) break;
26280 } // for (j = 0; j < starlist->len(); j++)
26281 if (aspTmax < newTmax) {
26282 // Save the improved object value and the location.
26283 newTmax = aspTmax;
26284 for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
26285 }
26286 } // for (i = 0; i < starlist->len(); i++)
26287 // Does the object value improved much?
26288 imprate = fabs(oldTmax - newTmax) / oldTmax;
26289 if (imprate < 1e-3) break;
26290 // Yes, move p to the new location and continue.
26291 for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
26292 iter++;
26293 } // while (true)
26294
26295 if (iter > 0) {
26296 // The point is moved.
26297 if (key) {
26298 // Check if the quality is improved by the smoothed point.
26299 maxcosd = 0.0; // = cos(90.0).
26300 for (j = 0; j < starlist->len(); j++) {
26301 starttet = * (triface *)(* starlist)[j];
26302 adjustedgering(starttet, !invtori ? CCW : CW);
26303 pa = org(starttet);
26304 pb = dest(starttet);
26305 pc = apex(starttet);
26306 tetalldihedral(pa, pb, pc, startpt, NULL, &cosd, NULL);
26307 if (cosd < *key) {
26308 // This quality will not be improved. Stop.
26309 iter = 0; break;
26310 } else {
26311 // Remeber the worst quality value (of the new configuration).
26312 maxcosd = maxcosd < cosd ? maxcosd : cosd;
26313 }
26314 }
26315 if (iter > 0) *key = maxcosd;
26316 }
26317 }
26318
26319 if (iter > 0) {
26320 segflag ? smoothsegverts++ : smoothvolverts++;
26321 for (i = 0; i < 3; i++) smthpt[i] = startpt[i];
26322 if (b->verbose > 1) {
26323 printf(" Move to new location (%g, %g, %g).\n", smthpt[0], smthpt[1],
26324 smthpt[2]);
26325 printf(" Final max L/h = %g. (%d iterations)\n", newTmax, iter);
26326 if (key) {
26327 printf(" Max. dihed = %g (degree).\n", acos(*key) / PI * 180.0);
26328 }
26329 }
26330 return true;
26331 } else {
26332 if (b->verbose > 1) {
26333 printf(" Not smoothed.\n");
26334 }
26335 return false;
26336 }
26337}
26338
26340// //
26341// removesteiners() Delete or relocate Steiner points on facets. //
26342// //
26344
26345void tetgenmesh::removesteiners(bool coarseflag)
26346{
26347 list *frontlist, *misfrontlist;
26348 list *spinshlist, *newsegshlist;
26349 list *ptlist, *conlist;
26350 memorypool *viri;
26351 queue *flipque;
26352 triface checktet;
26353 face shloop;
26354 face segloop, nextseg;
26355 point pa, neipt;
26356 REAL len;
26357 bool remflag;
26358 int *worklist;
26359 int oldnum, rmstein;
26360 int i, j;
26361
26362 if (!b->quiet) {
26363 if (!coarseflag) {
26364 printf("Removing Steiner points.\n");
26365 } else {
26366 printf("Coarsening mesh.\n");
26367 }
26368 }
26369
26370 // Initialize work lists.
26371 frontlist = new list(sizeof(triface), NULL);
26372 misfrontlist = new list(sizeof(triface), NULL);
26373 spinshlist = new list(sizeof(face), NULL);
26374 newsegshlist = new list(sizeof(face), NULL);
26375 ptlist = new list(sizeof(point *), NULL);
26376 conlist = new list(sizeof(point *) * 2, NULL);
26377 flipque = new queue(sizeof(badface));
26378 viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
26379 oldnum = unuverts;
26380 relverts = suprelverts = collapverts = unsupverts;
26381 smoothvolverts = 0;
26382 expcavcount = 0;
26383
26384 // Suppress Steiner points inside facets.
26385 do {
26386 rmstein = unuverts;
26387 subfaces->traversalinit();
26388 shloop.sh = shellfacetraverse(subfaces);
26389 while (shloop.sh != (shellface *) NULL) {
26390 remflag = false;
26391 // Is s contains a Steiner point?
26392 shloop.shver = 0;
26393 for (i = 0; i < 3; i++) {
26394 pa = sapex(shloop);
26395 if (pointtype(pa) == FREESUBVERTEX) {
26396 if (!coarseflag) {
26397 // Remove it if it is not an input point.
26398 j = pointmark(pa) - in->firstnumber;
26399 if (j >= in->numberofpoints) {
26400 if (b->nobisect == 1) {
26401 // '-Y'. Remove p if s is a hull face.
26402 stpivot(shloop, checktet);
26403 if (checktet.tet != dummytet) {
26404 sesymself(shloop);
26405 stpivot(shloop, checktet);
26406 }
26407 remflag = (checktet.tet == dummytet);
26408 } else {
26409 // '-YY'. Remove p whatever s is a hull face or not.
26410 remflag = true;
26411 }
26412 }
26413 } else {
26414 // Check if this vertex can be coarsed.
26415 if (b->nobisect == 0) {
26416 // Is a background mesh available?
26417 if (b->metric) {
26418 // assert(pa[pointmtrindex] > 0.0);
26419 // Form the star of pa.
26420 spinshlist->append(&shloop);
26421 formstarpolygon(pa, spinshlist, ptlist);
26422 len = 0.0;
26423 for (j = 0; j < ptlist->len(); j++) {
26424 neipt = * (point *)(* ptlist)[j];
26425 len += distance(pa, neipt);
26426 }
26427 len /= ptlist->len();
26428 // Carse it if the average edge length is small.
26429 remflag = len < pa[pointmtrindex];
26430 spinshlist->clear();
26431 ptlist->clear();
26432 } else {
26433 // Coarse it if (1) it is an input point and its pointmarker
26434 // is zero, or (2) it is a Steiner point.
26435 remflag = true;
26436 j = pointmark(pa) - in->firstnumber;
26437 if (j < in->numberofpoints) {
26438 remflag = (in->pointmarkerlist[j] == 0);
26439 }
26440 } // if (b->metric)
26441 } // if (b->nobisect == 0)
26442 } // if (!coarseflag)
26443 if (remflag) break;
26444 } // if (pointtype(pa) == FREESUBVERTEX)
26445 senextself(shloop);
26446 } // for (i = 0; i < 3; i++)
26447 if (remflag) {
26448 suppressfacetpoint(&shloop, frontlist, misfrontlist, ptlist, conlist,
26449 viri, flipque, coarseflag, false);
26450 }
26451 shloop.sh = shellfacetraverse(subfaces);
26452 }
26453 // Continue if any Steiner point has been removed.
26454 } while (unuverts > rmstein);
26455
26456 if (coarseflag) {
26457 shellface **segsperverlist;
26458 int *idx2seglist;
26459 face seg1, seg2;
26460 point e1, e2;
26461 // Connecting collinear segments. Hence the segment vertices may be
26462 // removed. In fact, this should be done by reconstructmesh().
26463 makesegmentmap(idx2seglist, segsperverlist);
26464 subsegs->traversalinit();
26465 segloop.sh = shellfacetraverse(subsegs);
26466 while (segloop.sh != (shellface *) NULL) {
26467 for (i = 0; i < 2; i++) {
26468 segloop.shver = i;
26469 senext(segloop, nextseg);
26470 spivotself(nextseg);
26471 if ((nextseg.sh == dummysh) || (nextseg.sh > segloop.sh)) {
26472 // No neighbor segment connection or haven't been processed yet.
26473 pa = sdest(segloop);
26474 j = pointmark(pa) - in->firstnumber;
26475 if (idx2seglist[j + 1] - idx2seglist[j] == 2) {
26476 // pa is shared by only two segments. Get the other one.
26477 nextseg.sh = segsperverlist[idx2seglist[j]];
26478 if (nextseg.sh == segloop.sh) {
26479 nextseg.sh = segsperverlist[idx2seglist[j] + 1];
26480 }
26481 nextseg.shver = 0;
26482 if (sorg(nextseg) != pa) sesymself(nextseg);
26483 // Check if the two segments are collinear.
26484 e1 = sorg(segloop);
26485 e2 = sdest(nextseg);
26486 if (iscollinear(e1, pa, e2, b->epsilon)) {
26487 // Connect the two segments together.
26488 if (b->verbose > 1) {
26489 printf(" Glue two insegs (%d, %d) at %d.\n", pointmark(e1),
26490 pointmark(e2), pointmark(pa));
26491 }
26492 senext(segloop, seg1);
26493 senext2(nextseg, seg2);
26494 sbond(seg1, seg2);
26495 }
26496 }
26497 } // if (nextseg.sh == dummysh)
26498 } // for (i = 0;
26499 segloop.sh = shellfacetraverse(subsegs);
26500 }
26501 delete [] segsperverlist;
26502 delete [] idx2seglist;
26503 }
26504
26505 // Suppress Steiner points on segments.
26506 do {
26507 rmstein = unuverts;
26508 subsegs->traversalinit();
26509 segloop.sh = shellfacetraverse(subsegs);
26510 while (segloop.sh != (shellface *) NULL) {
26511 remflag = false;
26512 // for (i = 0; i < 2; i++) {
26513 // Don't check the poinytype of pa, it may be a Steiner point but
26514 // has type NACUTEVERTEX due to splitting a type-3 segment.
26515 segloop.shver = 0; // segloop.shver = i;
26516 senext(segloop, nextseg);
26517 spivotself(nextseg);
26518 if (nextseg.sh != dummysh) {
26519 pa = sdest(segloop); // p is going to be checked for removal.
26520 nextseg.shver = 0;
26521 if (sorg(nextseg) != pa) sesymself(nextseg);
26522 assert(sorg(nextseg) == pa);
26523 if (!coarseflag) {
26524 // try to remove it if it is not an input point.
26525 j = pointmark(pa) - in->firstnumber;
26526 if (j >= in->numberofpoints) {
26527 if (b->nobisect == 1) {
26528 // '-Y'. Remove p if it is on the hull.
26529 sstpivot(&segloop, &checktet);
26530 assert(checktet.tet != dummytet);
26531 pa = apex(checktet);
26532 do {
26533 if (!fnextself(checktet)) {
26534 // Meet a boundary face - p is on the hull.
26535 remflag = true; break;
26536 }
26537 } while (pa != apex(checktet));
26538 } else {
26539 // '-YY'. Remove p whatever it is on the hull or not.
26540 remflag = true;
26541 }
26542 }
26543 } else {
26544 // Check if this vertex can be coarsed.
26545 if (b->nobisect == 0) {
26546 if (b->metric) {
26547 // assert(pa[pointmtrindex] > 0.0);
26548 len = 0.0;
26549 neipt = sorg(segloop);
26550 for (j = 0; j < 2; j++) {
26551 len += distance(pa, neipt);
26552 /*// Is neipt inside the sparse ball of pa?
26553 if (len < pa[pointmtrindex]) {
26554 // Yes, the local of pa is too dense, corse it.
26555 remflag = true; break;
26556 } */
26557 neipt = sdest(nextseg);
26558 }
26559 len /= 2.0;
26560 // Carse it if the average edge lengh is small.
26561 remflag = len < pa[pointmtrindex];
26562 } else {
26563 // Coarse it if (1) it is an input point and its pointmarker
26564 // is zero, or (2) it is a Steiner point.
26565 remflag = true;
26566 j = pointmark(pa) - in->firstnumber;
26567 if (j < in->numberofpoints) {
26568 remflag = (in->pointmarkerlist[j] == 0);
26569 }
26570 } // if (b->metric)
26571 } // if (b->nobisect == 0)
26572 } // if (!coarseflag)
26573 } // if (nextseg.sh != dummysh)
26574 // if (remflag) break;
26575 // } // for (i = 0; i < 2; i++)
26576 if (remflag) {
26577 suppresssegpoint(&segloop, spinshlist, newsegshlist, frontlist,
26578 misfrontlist, ptlist, conlist, viri, flipque, coarseflag, false);
26579 }
26580 segloop.sh = shellfacetraverse(subsegs);
26581 }
26582 // Continue if any Steiner point has been removed.
26583 } while (unuverts > rmstein);
26584
26585 if ((relverts > 0) || coarseflag) {
26586 worklist = new int[points->items + 1];
26587 // Suppress relocated points & coarse free mesh points.
26588 do {
26589 // Initialize the work list. Each entry of the list counts how many
26590 // times the point has been processed.
26591 for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
26592 rmstein = unuverts;
26593 tetrahedrons->traversalinit();
26594 checktet.tet = tetrahedrontraverse();
26595 while (checktet.tet != (tetrahedron *) NULL) {
26596 remflag = false;
26597 for (i = 0; i < 4; i++) {
26598 pa = (point) checktet.tet[4 + i];
26599 if (pointtype(pa) == FREEVOLVERTEX) {
26600 // NOTE. Chenge the number 3 will change the number n of removed
26601 // Steiner points. In my test, n is larger when it is 1. 3
26602 // reduces n in a reasonable way (see example, mech_part,
26603 // thepart), 5 results a larger n than 3 does. While the best
26604 // result is no limit of this number, but it makes the code
26605 // extremely slow.
26606 if (worklist[pointmark(pa)] < 3) {
26607 worklist[pointmark(pa)]++;
26608 if (!coarseflag) {
26609 // Remove p if it is a Steiner point.
26610 if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) {
26611 remflag = true;
26612 }
26613 } else {
26614 if (b->metric) {
26615 // assert(pa[pointmtrindex] > 0.0);
26616 // Form the star of pa.
26617 frontlist->append(&checktet);
26618 formstarpolyhedron(pa, frontlist, ptlist, true);
26619 len = 0.0;
26620 for (j = 0; j < ptlist->len(); j++) {
26621 neipt = * (point *)(* ptlist)[j];
26622 len += distance(pa, neipt);
26623 }
26624 len /= ptlist->len();
26625 // Carse it if the average edge length is small.
26626 remflag = len < pa[pointmtrindex];
26627 frontlist->clear();
26628 ptlist->clear();
26629 } else {
26630 // Coarse it if (1) it is an input point and its pointmarker
26631 // is zero, or (2) it is a Steiner point.
26632 remflag = true;
26633 j = pointmark(pa) - in->firstnumber;
26634 if (j < in->numberofpoints) {
26635 remflag = (in->pointmarkerlist[j] == 0);
26636 }
26637 } // if (b->metric)
26638 } // if (!coarseflag)
26639 if (remflag) break;
26640 } // if (worklist[pointmark(pa)] == 0)
26641 } // if (pointtype(pa) == FREEVOLVERTEX)
26642 } // for (i = 0; i < 4; i++)
26643 if (remflag) {
26644 findorg(&checktet, pa);
26645 assert(org(checktet) == pa);
26646 suppressvolpoint(&checktet, frontlist, misfrontlist, ptlist, flipque,
26647 false);
26648 }
26649 checktet.tet = tetrahedrontraverse();
26650 }
26651 // Continue if any relocated point has been suppressed.
26652 } while (unuverts > rmstein);
26653
26654
26655 // Smooth the unsuppressed points if it is not coarse mesh.
26656 if (!coarseflag && (relverts > suprelverts)) {
26657 if (b->verbose) {
26658 printf(" Smoothing relocated points.\n");
26659 }
26660 for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
26661 tetrahedrons->traversalinit();
26662 checktet.tet = tetrahedrontraverse();
26663 while (checktet.tet != (tetrahedron *) NULL) {
26664 for (i = 0; i < 4; i++) {
26665 pa = (point) checktet.tet[4 + i];
26666 if (pointtype(pa) == FREEVOLVERTEX) {
26667 if (worklist[pointmark(pa)] == 0) {
26668 worklist[pointmark(pa)] = 1;
26669 if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) {
26670 // Smooth pa.
26671 findorg(&checktet, pa);
26672 frontlist->append(&checktet);
26673 formstarpolyhedron(pa, frontlist, NULL, false);
26674 smoothpoint(pa, NULL, NULL, frontlist, false, NULL);
26675 frontlist->clear();
26676 }
26677 } // if (worklist[pointmark(pa)] == 0)
26678 } // if (pointtype(pa) == FREEVOLVERTEX)
26679 } // for (i = 0; i < 4; i++)
26680 checktet.tet = tetrahedrontraverse();
26681 }
26682 }
26683 delete [] worklist;
26684 }
26685
26686 if (b->verbose > 0) {
26687 if (!coarseflag) {
26688 printf(" %d points removed from boundary", unuverts - oldnum);
26689 if (expcavcount > 0) {
26690 printf(" (%d cavity corrections)", expcavcount);
26691 }
26692 printf("\n");
26693 if (relverts > 0) {
26694 printf(" %d points relocated (%d suppressed, %d collapsed).\n",
26695 relverts, suprelverts - collapverts, collapverts);
26696 if (smoothvolverts > 0) {
26697 printf(" %d points are smoothed.\n", smoothvolverts);
26698 }
26699 }
26700 if (unsupverts > 0) {
26701 printf(" !! %d points are unsuppressed.\n", unsupverts);
26702 }
26703 } else {
26704 printf(" %d points are removed.\n", unuverts - oldnum);
26705 }
26706 }
26707
26708 // Delete work lists.
26709 delete frontlist;
26710 delete misfrontlist;
26711 delete spinshlist;
26712 delete newsegshlist;
26713 delete ptlist;
26714 delete conlist;
26715 delete flipque;
26716 delete viri;
26717}
26718
26719//
26720// End of boundary Steiner points removing routines
26721//
26722
26724// //
26725// reconstructmesh() Reconstruct a tetrahedral mesh from a list of //
26726// tetrahedra and possibly a list of boundary faces. //
26727// //
26728// The list of tetrahedra is stored in 'in->tetrahedronlist', the list of //
26729// boundary faces is stored in 'in->trifacelist'. The tetrahedral mesh is //
26730// reconstructed in memorypool 'tetrahedrons', its boundary faces (subfaces) //
26731// are reconstructed in 'subfaces', its boundary edges (subsegments) are //
26732// reconstructed in 'subsegs'. If the -a switch is used, this procedure will //
26733// also read a list of REALs from 'in->tetrahedronvolumelist' and set a //
26734// maximum volume constraint on each tetrahedron. //
26735// //
26736// If the user has provided the boundary faces in 'in->trifacelist', they //
26737// will be inserted the mesh. Otherwise subfaces will be identified from the //
26738// mesh. All hull faces (including faces of the internal holes) will be //
26739// recognized as subfaces, internal faces between two tetrahedra which have //
26740// different attributes will also be recognized as subfaces. //
26741// //
26742// Subsegments will be identified after subfaces are reconstructed. Edges at //
26743// the intersections of non-coplanar subfaces are recognized as subsegments. //
26744// Edges between two coplanar subfaces with different boundary markers are //
26745// also recognized as subsegments. //
26746// //
26747// The facet index of each subface will be set automatically after we have //
26748// recovered subfaces and subsegments. That is, the set of subfaces, which //
26749// are coplanar and have the same boundary marker will be recognized as a //
26750// facet and has a unique index, stored as the facet marker in each subface //
26751// of the set, the real boundary marker of each subface will be found in //
26752// 'in->facetmarkerlist' by the index. Facet index will be used in Delaunay //
26753// refinement for detecting two incident facets. //
26754// //
26755// Points which are not corners of tetrahedra will be inserted into the mesh.//
26756// Return the number of faces on the hull after the reconstruction. //
26757// //
26759
26760long tetgenmesh::reconstructmesh()
26761{
26762 tetrahedron **tetsperverlist;
26763 shellface **facesperverlist;
26764 triface tetloop, neightet, neineightet, spintet;
26765 face subloop, neighsh, neineighsh, subseg;
26766 face sface1, sface2;
26767 point *idx2verlist;
26768 point torg, tdest, tapex, toppo;
26769 point norg, ndest, napex;
26770 list *neighshlist, *markerlist;
26771 REAL sign, attrib, volume;
26772 REAL da1, da2;
26773 bool bondflag, insertsegflag;
26774 int *idx2tetlist;
26775 int *idx2facelist;
26776 int *worklist;
26777 int facetidx, marker;
26778 int iorg, idest, iapex, ioppo;
26779 int inorg, indest, inapex;
26780 int index, i, j;
26781
26782 if (!b->quiet) {
26783 printf("Reconstructing mesh.\n");
26784 }
26785
26786 // Create a map from index to points.
26787 makeindex2pointmap(idx2verlist);
26788
26789 // Create the tetrahedra.
26790 for (i = 0; i < in->numberoftetrahedra; i++) {
26791 // Create a new tetrahedron and set its four corners, make sure that
26792 // four corners form a positive orientation.
26793 maketetrahedron(&tetloop);
26794 index = i * in->numberofcorners;
26795 // Although there may be 10 nodes, we only read the first 4.
26796 iorg = in->tetrahedronlist[index] - in->firstnumber;
26797 idest = in->tetrahedronlist[index + 1] - in->firstnumber;
26798 iapex = in->tetrahedronlist[index + 2] - in->firstnumber;
26799 ioppo = in->tetrahedronlist[index + 3] - in->firstnumber;
26800 torg = idx2verlist[iorg];
26801 tdest = idx2verlist[idest];
26802 tapex = idx2verlist[iapex];
26803 toppo = idx2verlist[ioppo];
26804 sign = orient3d(torg, tdest, tapex, toppo);
26805 if (sign > 0.0) {
26806 norg = torg; torg = tdest; tdest = norg;
26807 } else if (sign == 0.0) {
26808 if (!b->quiet) {
26809 printf("Warning: Tet %d is degenerate.\n", i + in->firstnumber);
26810 }
26811 }
26812 setorg(tetloop, torg);
26813 setdest(tetloop, tdest);
26814 setapex(tetloop, tapex);
26815 setoppo(tetloop, toppo);
26816 // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that
26817 // they belong to the mesh. These types may be changed later.
26818 setpointtype(torg, FREEVOLVERTEX);
26819 setpointtype(tdest, FREEVOLVERTEX);
26820 setpointtype(tapex, FREEVOLVERTEX);
26821 setpointtype(toppo, FREEVOLVERTEX);
26822 // Set element attributes if they exist.
26823 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
26824 index = i * in->numberoftetrahedronattributes;
26825 attrib = in->tetrahedronattributelist[index + j];
26826 setelemattribute(tetloop.tet, j, attrib);
26827 }
26828 // If -a switch is used (with no number follows) Set a volume
26829 // constraint if it exists.
26830 if (b->varvolume) {
26831 if (in->tetrahedronvolumelist != (REAL *) NULL) {
26832 volume = in->tetrahedronvolumelist[i];
26833 } else {
26834 volume = -1.0;
26835 }
26836 setvolumebound(tetloop.tet, volume);
26837 }
26838 }
26839
26840 // Set the connection between tetrahedra.
26841 hullsize = 0l;
26842 // Create a map from nodes to tetrahedra.
26843 maketetrahedronmap(idx2tetlist, tetsperverlist);
26844 // Initialize the worklist.
26845 worklist = new int[points->items];
26846 for (i = 0; i < points->items; i++) worklist[i] = 0;
26847
26848 // Loop all tetrahedra, bond two tetrahedra if they share a common face.
26849 tetrahedrons->traversalinit();
26850 tetloop.tet = tetrahedrontraverse();
26851 while (tetloop.tet != (tetrahedron *) NULL) {
26852 // Loop the four sides of the tetrahedron.
26853 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
26854 sym(tetloop, neightet);
26855 if (neightet.tet != dummytet) continue; // This side has finished.
26856 torg = org(tetloop);
26857 tdest = dest(tetloop);
26858 tapex = apex(tetloop);
26859 iorg = pointmark(torg) - in->firstnumber;
26860 idest = pointmark(tdest) - in->firstnumber;
26861 iapex = pointmark(tapex) - in->firstnumber;
26862 worklist[iorg] = 1;
26863 worklist[idest] = 1;
26864 worklist[iapex] = 1;
26865 bondflag = false;
26866 // Search its neighbor in the adjacent tets of torg.
26867 for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag;
26868 j++) {
26869 if (tetsperverlist[j] == tetloop.tet) continue; // Skip myself.
26870 neightet.tet = tetsperverlist[j];
26871 for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
26872 sym(neightet, neineightet);
26873 if (neineightet.tet == dummytet) {
26874 norg = org(neightet);
26875 ndest = dest(neightet);
26876 napex = apex(neightet);
26877 inorg = pointmark(norg) - in->firstnumber;
26878 indest = pointmark(ndest) - in->firstnumber;
26879 inapex = pointmark(napex) - in->firstnumber;
26880 if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) {
26881 // Find! Bond them together and break the loop.
26882 bond(tetloop, neightet);
26883 bondflag = true;
26884 break;
26885 }
26886 }
26887 }
26888 }
26889 if (!bondflag) {
26890 hullsize++; // It's a hull face.
26891 // Bond this side to outer space.
26892 dummytet[0] = encode(tetloop);
26893 if ((in->pointmarkerlist != (int *) NULL) && !b->coarse) {
26894 // Set its three corners's markers be boundary (hull) vertices.
26895 if (in->pointmarkerlist[iorg] == 0) {
26896 in->pointmarkerlist[iorg] = 1;
26897 }
26898 if (in->pointmarkerlist[idest] == 0) {
26899 in->pointmarkerlist[idest] = 1;
26900 }
26901 if (in->pointmarkerlist[iapex] == 0) {
26902 in->pointmarkerlist[iapex] = 1;
26903 }
26904 }
26905 }
26906 worklist[iorg] = 0;
26907 worklist[idest] = 0;
26908 worklist[iapex] = 0;
26909 }
26910 tetloop.tet = tetrahedrontraverse();
26911 }
26912
26913 // Subfaces will be inserted into the mesh. It has two phases:
26914 // (1) Insert subfaces provided by user (in->trifacelist);
26915 // (2) Create subfaces for hull faces (if they're not subface yet) and
26916 // interior faces which separate two different materials.
26917
26918 // Phase (1). Is there a list of user-provided subfaces?
26919 if (in->trifacelist != (int *) NULL) {
26920 // Recover subfaces from 'in->trifacelist'.
26921 for (i = 0; i < in->numberoftrifaces; i++) {
26922 index = i * 3;
26923 iorg = in->trifacelist[index] - in->firstnumber;
26924 idest = in->trifacelist[index + 1] - in->firstnumber;
26925 iapex = in->trifacelist[index + 2] - in->firstnumber;
26926 // Look for the location of this subface.
26927 worklist[iorg] = 1;
26928 worklist[idest] = 1;
26929 worklist[iapex] = 1;
26930 bondflag = false;
26931 // Search its neighbor in the adjacent tets of torg.
26932 for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag;
26933 j++) {
26934 neightet.tet = tetsperverlist[j];
26935 for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
26936 norg = org(neightet);
26937 ndest = dest(neightet);
26938 napex = apex(neightet);
26939 inorg = pointmark(norg) - in->firstnumber;
26940 indest = pointmark(ndest) - in->firstnumber;
26941 inapex = pointmark(napex) - in->firstnumber;
26942 if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) {
26943 bondflag = true; // Find!
26944 break;
26945 }
26946 }
26947 }
26948 if (bondflag) {
26949 // Create a new subface and insert it into the mesh.
26950 makeshellface(subfaces, &subloop);
26951 torg = idx2verlist[iorg];
26952 tdest = idx2verlist[idest];
26953 tapex = idx2verlist[iapex];
26954 setsorg(subloop, torg);
26955 setsdest(subloop, tdest);
26956 setsapex(subloop, tapex);
26957 // Set the vertices be FREESUBVERTEX to indicate they belong to a
26958 // facet of the domain. They may be changed later.
26959 setpointtype(torg, FREESUBVERTEX);
26960 setpointtype(tdest, FREESUBVERTEX);
26961 setpointtype(tapex, FREESUBVERTEX);
26962 if (in->trifacemarkerlist != (int *) NULL) {
26963 setshellmark(subloop, in->trifacemarkerlist[i]);
26964 }
26965 adjustedgering(neightet, CCW);
26966 findedge(&subloop, org(neightet), dest(neightet));
26967 tsbond(neightet, subloop);
26968 sym(neightet, neineightet);
26969 if (neineightet.tet != dummytet) {
26970 sesymself(subloop);
26971 tsbond(neineightet, subloop);
26972 }
26973 } else {
26974 if (!b->quiet) {
26975 printf("Warning: Subface %d is discarded.\n", i + in->firstnumber);
26976 }
26977 }
26978 worklist[iorg] = 0;
26979 worklist[idest] = 0;
26980 worklist[iapex] = 0;
26981 }
26982 }
26983
26984 // Phase (2). Indentify subfaces from the mesh.
26985 tetrahedrons->traversalinit();
26986 tetloop.tet = tetrahedrontraverse();
26987 while (tetloop.tet != (tetrahedron *) NULL) {
26988 // Loop the four sides of the tetrahedron.
26989 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
26990 tspivot(tetloop, subloop);
26991 if (subloop.sh != dummysh) continue;
26992 bondflag = false;
26993 sym(tetloop, neightet);
26994 if (neightet.tet == dummytet) {
26995 // It's a hull face. Insert a subface at here.
26996 bondflag = true;
26997 } else {
26998 // It's an interior face. Insert a subface if two tetrahedra have
26999 // different attributes (i.e., they belong to two regions).
27000 if (in->numberoftetrahedronattributes > 0) {
27001 if (elemattribute(neightet.tet,
27002 in->numberoftetrahedronattributes - 1) !=
27003 elemattribute(tetloop.tet,
27004 in->numberoftetrahedronattributes - 1)) {
27005 bondflag = true;
27006 }
27007 }
27008 }
27009 if (bondflag) {
27010 adjustedgering(tetloop, CCW);
27011 makeshellface(subfaces, &subloop);
27012 torg = org(tetloop);
27013 tdest = dest(tetloop);
27014 tapex = apex(tetloop);
27015 setsorg(subloop, torg);
27016 setsdest(subloop, tdest);
27017 setsapex(subloop, tapex);
27018 // Set the vertices be FREESUBVERTEX to indicate they belong to a
27019 // facet of the domain. They may be changed later.
27020 setpointtype(torg, FREESUBVERTEX);
27021 setpointtype(tdest, FREESUBVERTEX);
27022 setpointtype(tapex, FREESUBVERTEX);
27023 tsbond(tetloop, subloop);
27024 if (neightet.tet != dummytet) {
27025 sesymself(subloop);
27026 tsbond(neightet, subloop);
27027 }
27028 }
27029 }
27030 tetloop.tet = tetrahedrontraverse();
27031 }
27032
27033 // Set the connection between subfaces. A subsegment may have more than
27034 // two subfaces sharing it, 'neighshlist' stores all subfaces sharing
27035 // one edge.
27036 neighshlist = new list(sizeof(face), NULL);
27037 // Create a map from nodes to subfaces.
27038 makesubfacemap(idx2facelist, facesperverlist);
27039
27040 // Loop over the set of subfaces, setup the connection between subfaces.
27041 subfaces->traversalinit();
27042 subloop.sh = shellfacetraverse(subfaces);
27043 while (subloop.sh != (shellface *) NULL) {
27044 for (i = 0; i < 3; i++) {
27045 spivot(subloop, neighsh);
27046 if (neighsh.sh == dummysh) {
27047 // This side is 'empty', operate on it.
27048 torg = sorg(subloop);
27049 tdest = sdest(subloop);
27050 tapex = sapex(subloop);
27051 neighshlist->append(&subloop);
27052 iorg = pointmark(torg) - in->firstnumber;
27053 // Search its neighbor in the adjacent list of torg.
27054 for (j = idx2facelist[iorg]; j < idx2facelist[iorg + 1]; j++) {
27055 neighsh.sh = facesperverlist[j];
27056 if (neighsh.sh == subloop.sh) continue;
27057 neighsh.shver = 0;
27058 if (isfacehasedge(&neighsh, torg, tdest)) {
27059 findedge(&neighsh, torg, tdest);
27060 // Insert 'neighsh' into 'neighshlist'.
27061 if (neighshlist->len() < 2) {
27062 neighshlist->append(&neighsh);
27063 } else {
27064 for (index = 0; index < neighshlist->len() - 1; index++) {
27065 sface1 = * (face *)(* neighshlist)[index];
27066 sface2 = * (face *)(* neighshlist)[index + 1];
27067 da1 = facedihedral(torg, tdest, sapex(sface1), sapex(neighsh));
27068 da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2));
27069 if (da1 < da2) {
27070 break; // Insert it after index.
27071 }
27072 }
27073 neighshlist->insert(index + 1, &neighsh);
27074 }
27075 }
27076 }
27077 // Bond the subfaces in 'neighshlist'.
27078 if (neighshlist->len() > 1) {
27079 neighsh = * (face *)(* neighshlist)[0];
27080 for (j = 1; j <= neighshlist->len(); j++) {
27081 if (j < neighshlist->len()) {
27082 neineighsh = * (face *)(* neighshlist)[j];
27083 } else {
27084 neineighsh = * (face *)(* neighshlist)[0];
27085 }
27086 sbond1(neighsh, neineighsh);
27087 neighsh = neineighsh;
27088 }
27089 } else {
27090 // No neighbor subface be found, bond 'subloop' to itself.
27091 sbond(subloop, subloop);
27092 }
27093 neighshlist->clear();
27094 }
27095 senextself(subloop);
27096 }
27097 subloop.sh = shellfacetraverse(subfaces);
27098 }
27099
27100 // Segments will be introudced. Each segment has a unique marker (1-based).
27101 marker = 1;
27102 subfaces->traversalinit();
27103 subloop.sh = shellfacetraverse(subfaces);
27104 while (subloop.sh != (shellface *) NULL) {
27105 for (i = 0; i < 3; i++) {
27106 sspivot(subloop, subseg);
27107 if (subseg.sh == dummysh) {
27108 // This side has no subsegment bonded, check it.
27109 torg = sorg(subloop);
27110 tdest = sdest(subloop);
27111 tapex = sapex(subloop);
27112 spivot(subloop, neighsh);
27113 spivot(neighsh, neineighsh);
27114 insertsegflag = false;
27115 if (subloop.sh == neighsh.sh || subloop.sh != neineighsh.sh) {
27116 // This side is either self-bonded or more than two subfaces,
27117 // insert a subsegment at this side.
27118 insertsegflag = true;
27119 } else {
27120 // Only two subfaces case.
27121#ifdef SELF_CHECK
27122 assert(subloop.sh != neighsh.sh);
27123#endif
27124 napex = sapex(neighsh);
27125 sign = orient3d(torg, tdest, tapex, napex);
27126 if (iscoplanar(torg, tdest, tapex, napex, sign, b->epsilon)) {
27127 // Although they are coplanar, we still need to check if they
27128 // have the same boundary marker.
27129 insertsegflag = (shellmark(subloop) != shellmark(neighsh));
27130 } else {
27131 // Non-coplanar.
27132 insertsegflag = true;
27133 }
27134 }
27135 if (insertsegflag) {
27136 // Create a subsegment at this side.
27137 makeshellface(subsegs, &subseg);
27138 setsorg(subseg, torg);
27139 setsdest(subseg, tdest);
27140 // The two vertices have been marked as FREESUBVERTEX. Now mark
27141 // them as NACUTEVERTEX.
27142 setpointtype(torg, NACUTEVERTEX);
27143 setpointtype(tdest, NACUTEVERTEX);
27144 setshellmark(subseg, marker);
27145 marker++;
27146 // Bond all subfaces to this subsegment.
27147 neighsh = subloop;
27148 do {
27149 ssbond(neighsh, subseg);
27150 spivotself(neighsh);
27151 } while (neighsh.sh != subloop.sh);
27152 }
27153 }
27154 senextself(subloop);
27155 }
27156 subloop.sh = shellfacetraverse(subfaces);
27157 }
27158 // Remember the number of input segments.
27159 insegments = subsegs->items;
27160 // Find the acute vertices and set them be type ACUTEVERTEX.
27161
27162 // Indentify facets and set the facet marker (1-based) for subfaces.
27163 markerlist = new list((char*)"int");
27164
27165 subfaces->traversalinit();
27166 subloop.sh = shellfacetraverse(subfaces);
27167 while (subloop.sh != (shellface *) NULL) {
27168 // Only operate on uninfected subface, after operating, infect it.
27169 if (!sinfected(subloop)) {
27170 // A new facet is found.
27171 marker = shellmark(subloop);
27172 markerlist->append(&marker);
27173 facetidx = markerlist->len(); // 'facetidx' starts from 1.
27174 setshellmark(subloop, facetidx);
27175 sinfect(subloop);
27176 neighshlist->append(&subloop);
27177 // Find out all subfaces of this facet (bounded by subsegments).
27178 for (i = 0; i < neighshlist->len(); i++) {
27179 neighsh = * (face *) (* neighshlist)[i];
27180 for (j = 0; j < 3; j++) {
27181 sspivot(neighsh, subseg);
27182 if (subseg.sh == dummysh) {
27183 spivot(neighsh, neineighsh);
27184 if (!sinfected(neineighsh)) {
27185 // 'neineighsh' is in the same facet as 'subloop'.
27186#ifdef SELF_CHECK
27187 assert(shellmark(neineighsh) == marker);
27188#endif
27189 setshellmark(neineighsh, facetidx);
27190 sinfect(neineighsh);
27191 neighshlist->append(&neineighsh);
27192 }
27193 }
27194 senextself(neighsh);
27195 }
27196 }
27197 neighshlist->clear();
27198 }
27199 subloop.sh = shellfacetraverse(subfaces);
27200 }
27201 // Uninfect all subfaces.
27202 subfaces->traversalinit();
27203 subloop.sh = shellfacetraverse(subfaces);
27204 while (subloop.sh != (shellface *) NULL) {
27205#ifdef SELF_CHECK
27206 assert(sinfected(subloop));
27207#endif
27208 suninfect(subloop);
27209 subloop.sh = shellfacetraverse(subfaces);
27210 }
27211 // Save the facet markers in 'in->facetmarkerlist'.
27212 in->numberoffacets = markerlist->len();
27213 in->facetmarkerlist = new int[in->numberoffacets];
27214 for (i = 0; i < in->numberoffacets; i++) {
27215 marker = * (int *) (* markerlist)[i];
27216 in->facetmarkerlist[i] = marker;
27217 }
27218 // Initialize the 'facetabovepointlist'.
27219 facetabovepointarray = new point[in->numberoffacets + 1];
27220 for (i = 0; i < in->numberoffacets + 1; i++) {
27221 facetabovepointarray[i] = (point) NULL;
27222 }
27223
27224 // The mesh contains boundary now.
27225 checksubfaces = 1;
27226 // The mesh is nonconvex now.
27227 nonconvex = 1;
27228
27229 // Is there periodic boundary confitions?
27230 if (checkpbcs) {
27231 tetgenio::pbcgroup *pg;
27232 pbcdata *pd;
27233 // Initialize the global array 'subpbcgrouptable'.
27234 createsubpbcgrouptable();
27235 // Loop for each pbcgroup i.
27236 for (i = 0; i < in->numberofpbcgroups; i++) {
27237 pg = &(in->pbcgrouplist[i]);
27238 pd = &(subpbcgrouptable[i]);
27239 // Find all subfaces of pd, set each subface's group id be i.
27240 for (j = 0; j < 2; j++) {
27241 subfaces->traversalinit();
27242 subloop.sh = shellfacetraverse(subfaces);
27243 while (subloop.sh != (shellface *) NULL) {
27244 facetidx = shellmark(subloop);
27245 marker = in->facetmarkerlist[facetidx - 1];
27246 if (marker == pd->fmark[j]) {
27247 setshellpbcgroup(subloop, i);
27248 pd->ss[j] = subloop;
27249 }
27250 subloop.sh = shellfacetraverse(subfaces);
27251 }
27252 }
27253 if (pg->pointpairlist != (int *) NULL) {
27254 // Set the connections between pbc point pairs.
27255 for (j = 0; j < pg->numberofpointpairs; j++) {
27256 iorg = pg->pointpairlist[j * 2] - in->firstnumber;
27257 idest = pg->pointpairlist[j * 2 + 1] - in->firstnumber;
27258 torg = idx2verlist[iorg];
27259 tdest = idx2verlist[idest];
27260 setpoint2pbcpt(torg, tdest);
27261 setpoint2pbcpt(tdest, torg);
27262 }
27263 }
27264 }
27265 // Create the global array 'segpbcgrouptable'.
27266 createsegpbcgrouptable();
27267 }
27268
27269 delete markerlist;
27270 delete neighshlist;
27271 delete [] worklist;
27272 delete [] idx2tetlist;
27273 delete [] tetsperverlist;
27274 delete [] idx2facelist;
27275 delete [] facesperverlist;
27276 delete [] idx2verlist;
27277
27278 return hullsize;
27279}
27280
27282// //
27283// insertconstrainedpoints() Insert a list of constrained points. //
27284// //
27286
27287void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
27288{
27289 queue *flipqueue;
27290 triface searchtet;
27291 face checksh, checkseg;
27292 point newpoint;
27293 enum locateresult loc;
27294 REAL *attr;
27295 bool insertflag;
27296 int covertices, outvertices;
27297 int index;
27298 int i, j;
27299
27300 if (!b->quiet) {
27301 printf("Insert additional points into mesh.\n");
27302 }
27303 // Initialize 'flipqueue'.
27304 flipqueue = new queue(sizeof(badface));
27305 recenttet.tet = dummytet;
27306 covertices = outvertices = 0;
27307
27308 index = 0;
27309 for (i = 0; i < addio->numberofpoints; i++) {
27310 // Create a newpoint.
27311 makepoint(&newpoint);
27312 newpoint[0] = addio->pointlist[index++];
27313 newpoint[1] = addio->pointlist[index++];
27314 newpoint[2] = addio->pointlist[index++];
27315 // Read the add point attributes if current points have attributes.
27316 if ((addio->numberofpointattributes > 0) &&
27317 (in->numberofpointattributes > 0)) {
27318 attr = addio->pointattributelist + addio->numberofpointattributes * i;
27319 for (j = 0; j < in->numberofpointattributes; j++) {
27320 if (j < addio->numberofpointattributes) {
27321 newpoint[3 + j] = attr[j];
27322 }
27323 }
27324 }
27325 // Find the location of the inserted point.
27326 searchtet = recenttet;
27327 loc = locate(newpoint, &searchtet);
27328 if (loc != ONVERTEX) {
27329 loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon2);
27330 }
27331 if (loc == OUTSIDE) {
27332 loc = hullwalk(newpoint, &searchtet);
27333 if (loc == OUTSIDE) {
27334 // Perform a brute-force search.
27335 tetrahedrons->traversalinit();
27336 searchtet.tet = tetrahedrontraverse();
27337 while (searchtet.tet != (tetrahedron *) NULL) {
27338 loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon2);
27339 if (loc != OUTSIDE) break;
27340 searchtet.tet = tetrahedrontraverse();
27341 }
27342 }
27343 }
27344 // Insert the point if it not lies outside or on a vertex.
27345 insertflag = true;
27346 switch (loc) {
27347 case INTETRAHEDRON:
27348 setpointtype(newpoint, FREEVOLVERTEX);
27349 splittetrahedron(newpoint, &searchtet, flipqueue);
27350 break;
27351 case ONFACE:
27352 tspivot(searchtet, checksh);
27353 if (checksh.sh != dummysh) {
27354 // It is a boundary face. Don't insert it if -Y option is used.
27355 if (b->nobisect) {
27356 insertflag = false;
27357 } else {
27358 setpointtype(newpoint, FREESUBVERTEX);
27359 }
27360 } else {
27361 setpointtype(newpoint, FREEVOLVERTEX);
27362 }
27363 if (insertflag) {
27364 splittetface(newpoint, &searchtet, flipqueue);
27365 }
27366 break;
27367 case ONEDGE:
27368 tsspivot(&searchtet, &checkseg);
27369 if (checkseg.sh != dummysh) {
27370 if (b->nobisect) {
27371 insertflag = false;
27372 } else {
27373 setpointtype(newpoint, FREESEGVERTEX);
27374 setpoint2sh(newpoint, sencode(checkseg));
27375 }
27376 } else {
27377 tspivot(searchtet, checksh);
27378 if (checksh.sh != dummysh) {
27379 if (b->nobisect) {
27380 insertflag = false;
27381 } else {
27382 setpointtype(newpoint, FREESUBVERTEX);
27383 }
27384 } else {
27385 setpointtype(newpoint, FREEVOLVERTEX);
27386 }
27387 }
27388 if (insertflag) {
27389 splittetedge(newpoint, &searchtet, flipqueue);
27390 }
27391 break;
27392 case ONVERTEX:
27393 insertflag = false;
27394 covertices++;
27395 break;
27396 case OUTSIDE:
27397 insertflag = false;
27398 outvertices++;
27399 break;
27400 }
27401 // Remember the tetrahedron for next point searching.
27402 recenttet = searchtet;
27403 if (!insertflag) {
27404 pointdealloc(newpoint);
27405 } else {
27406 flip(flipqueue, NULL);
27407 }
27408 }
27409
27410 if (b->verbose) {
27411 if (covertices > 0) {
27412 printf(" %d constrained points already exist.\n", covertices);
27413 }
27414 if (outvertices > 0) {
27415 printf(" %d constrained points lie outside the mesh.\n", outvertices);
27416 }
27417 printf(" %d constrained points have been inserted.\n",
27418 addio->numberofpoints - covertices - outvertices);
27419 }
27420
27421 delete flipqueue;
27422}
27423
27425// //
27426// p1interpolatebgm() Set pt size by p^1 interpolation in background mesh.//
27427// //
27428// On input, 'bgmtet' is a suggesting tet in background mesh for searching //
27429// 'pt'. It returns the tet containing 'pt'. //
27430// //
27432
27433bool tetgenmesh::p1interpolatebgm(point pt, triface* bgmtet, long *scount)
27434{
27435 point bgmpt[4];
27436 enum locateresult loc;
27437 REAL vol, volpt[4], weights[4];
27438 int i;
27439
27440 loc = bgm->preciselocate(pt, bgmtet, bgm->tetrahedrons->items);
27441 if (loc == OUTSIDE) {
27442 loc = bgm->hullwalk(pt, bgmtet);
27443 if (loc == OUTSIDE) {
27444 // Perform a brute-force search.
27445 if (b->verbose) {
27446 printf("Warning: Global point location.\n");
27447 }
27448 if (scount) (*scount)++;
27449 bgm->tetrahedrons->traversalinit(); // in bgm
27450 bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
27451 while (bgmtet->tet != (tetrahedron *) NULL) {
27452 loc = bgm->adjustlocate(pt, bgmtet, OUTSIDE, b->epsilon);
27453 if (loc != OUTSIDE) break;
27454 bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
27455 }
27456 }
27457 }
27458 if (loc != OUTSIDE) {
27459 // Let p remember t.
27460 setpoint2bgmtet(pt, encode(*bgmtet)); // in m
27461 // get the corners of t.
27462 for (i = 0; i < 4; i++) bgmpt[i] = (point) bgmtet->tet[4 + i];
27463 // Calculate the weighted coordinates of p in t.
27464 vol = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], bgmpt[3]);
27465 volpt[0] = orient3d(pt, bgmpt[1], bgmpt[2], bgmpt[3]);
27466 volpt[1] = orient3d(bgmpt[0], pt, bgmpt[2], bgmpt[3]);
27467 volpt[2] = orient3d(bgmpt[0], bgmpt[1], pt, bgmpt[3]);
27468 volpt[3] = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], pt);
27469 for (i = 0; i < 4; i++) weights[i] = fabs(volpt[i] / vol);
27470 // Interpolate the solution for p.
27471 for (i = 0; i < bgm->in->numberofpointmtrs; i++) {
27472 pt[pointmtrindex + i] = weights[0] * bgmpt[0][bgm->pointmtrindex + i]
27473 + weights[1] * bgmpt[1][bgm->pointmtrindex + i]
27474 + weights[2] * bgmpt[2][bgm->pointmtrindex + i]
27475 + weights[3] * bgmpt[3][bgm->pointmtrindex + i];
27476 }
27477 } else {
27478 setpoint2bgmtet(pt, (tetrahedron) NULL); // in m
27479 }
27480 return loc != OUTSIDE;
27481}
27482
27484// //
27485// interpolatesizemap() Interpolate the point sizes in the given size map.//
27486// //
27487// The size map is specified on each node of the background mesh. The points //
27488// of current mesh get their sizes by interpolating. //
27489// //
27490// This function operation on two meshes simultaneously, the current mesh m, //
27491// and the background mesh bgm. After this function, each point p in m will //
27492// have a pointer to a tet of bgm. //
27493// //
27495
27496void tetgenmesh::interpolatesizemap()
27497{
27498 list *adjtetlist;
27499 triface tetloop, neightet, bgmtet;
27500 point searchpt;
27501 long scount;
27502 int *worklist;
27503 int sepcount;
27504 int i;
27505
27506 if (b->verbose) {
27507 printf(" Interpolating size map.\n");
27508 }
27509
27510 worklist = new int[points->items + 1];
27511 for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
27512 sepcount = 0;
27513 scount = 0l;
27514
27515 tetrahedrons->traversalinit();
27516 tetloop.tet = tetrahedrontraverse();
27517 while (tetloop.tet != (tetrahedron *) NULL) {
27518 if (!infected(tetloop)) {
27519 // Find a new subdomain.
27520 adjtetlist = new list(sizeof(triface), NULL, 1024);
27521 infect(tetloop);
27522 // Search the four corners in background mesh.
27523 for (i = 0; i < 4; i++) {
27524 searchpt = (point) tetloop.tet[4 + i];
27525 // Mark the point for avoiding multiple searchings.
27526 // assert(worklist[pointmark(searchpt)] == 0);
27527 worklist[pointmark(searchpt)] = 1;
27528 // Does it contain a pointer to bgm tet?
27529 bgm->decode(point2bgmtet(searchpt), bgmtet);
27530 if (bgm->isdead(&bgmtet)) {
27531 bgmtet = bgm->recenttet;
27532 }
27533 if (p1interpolatebgm(searchpt, &bgmtet, &scount)) {
27534 bgm->recenttet = bgmtet;
27535 }
27536 } // for (i = 0; i < 4; i++)
27537 // Collect all tets in this region.
27538 adjtetlist->append(&tetloop);
27539 // Collect the tets in the subdomain.
27540 for (i = 0; i < adjtetlist->len(); i++) {
27541 tetloop = * (triface *)(* adjtetlist)[i];
27542 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
27543 sym(tetloop, neightet);
27544 if ((neightet.tet != dummytet) && !infected(neightet)) {
27545 // Only need to search for the opposite point.
27546 searchpt = oppo(neightet);
27547 if (worklist[pointmark(searchpt)] == 0) {
27548 worklist[pointmark(searchpt)] = 1;
27549 decode(point2bgmtet(searchpt), bgmtet);
27550 if (bgm->isdead(&bgmtet)) {
27551 bgmtet = bgm->recenttet;
27552 }
27553 if (p1interpolatebgm(searchpt, &bgmtet, &scount)) {
27554 bgm->recenttet = bgmtet;
27555 }
27556 }
27557 infect(neightet);
27558 adjtetlist->append(&neightet);
27559 }
27560 }
27561 }
27562 // Increase the number of separated domains.
27563 sepcount++;
27564 delete adjtetlist;
27565 } // if (!infect())
27566 tetloop.tet = tetrahedrontraverse();
27567 }
27568
27569 // Unmark all tets.
27570 tetrahedrons->traversalinit();
27571 tetloop.tet = tetrahedrontraverse();
27572 while (tetloop.tet != (tetrahedron *) NULL) {
27573 assert(infected(tetloop));
27574 uninfect(tetloop);
27575 tetloop.tet = tetrahedrontraverse();
27576 }
27577 delete [] worklist;
27578
27579#ifdef SELF_CHECK
27580 if (b->verbose && scount > 0l) {
27581 printf(" %ld brute-force searches.\n", scount);
27582 }
27583 if (b->verbose && sepcount > 0) {
27584 printf(" %d separate domains.\n", sepcount);
27585 }
27586#endif
27587}
27588
27590// //
27591// duplicatebgmesh() Duplicate current mesh to background mesh. //
27592// //
27593// Current mesh 'this' is copied into 'this->bgm'.Both meshes share the same //
27594// input tetgenio object, 'this->in', same tetgenbehavior object 'this->b'. //
27595// //
27597
27598void tetgenmesh::duplicatebgmesh()
27599{
27600 triface tetloop, btetloop;
27601 triface symtet, bsymtet;
27602 face bhullsh, bneighsh;
27603 point *idx2bplist, *tetptbaklist;
27604 point ploop, bploop;
27605 int idx, i;
27606
27607 if (!b->quiet) {
27608 printf("Duplicating background mesh.\n");
27609 }
27610
27611 // The background mesh itself has no background mesh.
27612 // assert(bgm->bgm == (tetgenmesh *) NULL);
27613 // The space for metric tensor should be allocated.
27614 // assert(bgm->sizeoftensor > 0);
27615
27616 // Copy point list.
27617 idx2bplist = new point[points->items + 1];
27618 idx = in->firstnumber;
27619 points->traversalinit();
27620 ploop = pointtraverse();
27621 while (ploop != (point) NULL) {
27622 bgm->makepoint(&bploop);
27623 // Copy coordinates, attributes.
27624 for (i = 0; i < 3 + in->numberofpointattributes; i++) {
27625 bploop[i] = ploop[i];
27626 }
27627 // Transfer the metric tensor.
27628 for (i = 0; i < bgm->sizeoftensor; i++) {
27629 bploop[bgm->pointmtrindex + i] = ploop[pointmtrindex + i];
27630 // Metric tensor should have a positive value.
27631 if (bploop[bgm->pointmtrindex + i] <= 0.0) {
27632 printf("Error: Point %d has non-positive size %g (-m option).\n",
27633 bgm->pointmark(bploop), bploop[bgm->pointmtrindex + i]);
27634 terminatetetgen(1);
27635 }
27636 }
27637 // Remember the point for searching.
27638 idx2bplist[idx++] = bploop;
27639 ploop = pointtraverse();
27640 }
27641
27642 // Copy tetrahedra list.
27643 tetptbaklist = new point[tetrahedrons->items + 1];
27644 idx = in->firstnumber;
27645 tetrahedrons->traversalinit();
27646 tetloop.tet = tetrahedrontraverse();
27647 while (tetloop.tet != (tetrahedron *) NULL) {
27648 bgm->maketetrahedron(&btetloop);
27649 // Set the four corners.
27650 for (i = 0; i < 4; i++) {
27651 ploop = (point) tetloop.tet[4 + i];
27652 bploop = idx2bplist[pointmark(ploop)];
27653 btetloop.tet[4 + i] = (tetrahedron) bploop;
27654 }
27655 // Remember the tet for setting neighbor connections.
27656 tetptbaklist[idx++] = (point) tetloop.tet[4];
27657 tetloop.tet[4] = (tetrahedron) btetloop.tet;
27658 tetloop.tet = tetrahedrontraverse();
27659 }
27660
27661 // Set the connections between background tetrahedra. Create background
27662 // hull subfaces. Create the map of point-to-bgmtet.
27663 idx = in->firstnumber;
27664 tetrahedrons->traversalinit();
27665 tetloop.tet = tetrahedrontraverse();
27666 while (tetloop.tet != (tetrahedron *) NULL) {
27667 // Get the corresponding background tet.
27668 btetloop.tet = (tetrahedron *) tetloop.tet[4];
27669 // Set the four neighbors.
27670 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
27671 btetloop.loc = tetloop.loc;
27672 sym(tetloop, symtet);
27673 if ((symtet.tet != dummytet) && (symtet.tet > tetloop.tet)) {
27674 // Operate on the un-connected interior face.
27675 bsymtet.tet = (tetrahedron *) symtet.tet[4]; // The saved bgm tet.
27676 bsymtet.loc = symtet.loc;
27677 bgm->bond(btetloop, bsymtet);
27678 } else if (symtet.tet == dummytet) {
27679 // Create a subface in background mesh.
27680 bgm->makeshellface(bgm->subfaces, &bhullsh);
27681 bgm->adjustedgering(btetloop, CCW); // face to inside.
27682 bgm->setsorg(bhullsh, bgm->org(btetloop));
27683 bgm->setsdest(bhullsh, bgm->dest(btetloop));
27684 bgm->setsapex(bhullsh, bgm->apex(btetloop));
27685 bgm->tsbond(btetloop, bhullsh);
27686 // Remember a hull face for point location.
27687 bgm->dummytet[0] = bgm->encode(btetloop);
27688 }
27689 }
27690 // Restore the backup tet point.
27691 tetloop.tet[4] = (tetrahedron) tetptbaklist[idx++];
27692 // Make the point-to-bgmtet map for size interpolation.
27693 btetloop.loc = 0;
27694 for (i = 0; i < 4; i++) {
27695 ploop = (point) tetloop.tet[4 + i];
27696 setpoint2bgmtet(ploop, bgm->encode(btetloop));
27697 }
27698 // Go to the next tet, btet.
27699 tetloop.tet = tetrahedrontraverse();
27700 }
27701
27702 // Connect bgm hull subfaces. Note: all hull subfaces form a 2-manifold.
27703 bgm->subfaces->traversalinit();
27704 bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces);
27705 while (bhullsh.sh != (shellface *) NULL) {
27706 bhullsh.shver = 0;
27707 bgm->stpivot(bhullsh, btetloop);
27708 assert(btetloop.tet != bgm->dummytet);
27709 bgm->adjustedgering(btetloop, CCW);
27710 for (i = 0; i < 3; i++) {
27711 bgm->spivot(bhullsh, bneighsh);
27712 if (bneighsh.sh == bgm->dummysh) {
27713 // This side is open, operate on it.
27714 bsymtet = btetloop;
27715 while (bgm->fnextself(bsymtet));
27716 bgm->tspivot(bsymtet, bneighsh);
27717 bgm->findedge(&bneighsh, bgm->sdest(bhullsh), bgm->sorg(bhullsh));
27718 bgm->sbond(bhullsh, bneighsh);
27719 }
27720 bgm->enextself(btetloop);
27721 bgm->senextself(bhullsh);
27722 }
27723 bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces);
27724 }
27725
27726 delete [] tetptbaklist;
27727 delete [] idx2bplist;
27728}
27729
27730//
27731// Begin of Delaunay refinement routines
27732//
27733
27735// //
27736// marksharpsegments() Mark sharp segments. //
27737// //
27738// A segment s is called sharp if it is in one of the two cases: //
27739// (1) There is a segment s' intersecting with s. The internal angle (*) //
27740// between s and s' is acute. //
27741// (2) There are two facets f1 and f2 intersecting at s. The internal //
27742// dihedral angle (*) between f1 and f2 is acute. //
27743// This routine finds the sharp segments and marked them as type SHARP. //
27744// The minimum angle between segments (minfaceang) and the minimum dihedral //
27745// angle between facets (minfacetdihed) are calulcated. //
27746// //
27747// (*) The internal angle (or dihedral) bewteen two features means the angle //
27748// inside the mesh domain. //
27749// //
27751
27752void tetgenmesh::marksharpsegments(REAL sharpangle)
27753{
27754 triface adjtet;
27755 face startsh, spinsh, neighsh;
27756 face segloop, prevseg, nextseg;
27757 point eorg, edest;
27758 REAL ang, smallang;
27759 bool issharp;
27760 int sharpsegcount;
27761
27762 if (b->verbose > 0) {
27763 printf(" Marking sharp segments.\n");
27764 }
27765
27766 smallang = sharpangle * PI / 180.;
27767 sharpsegcount = 0;
27768 eorg = edest = (point) NULL; // To avoid compiler warnings.
27769
27770 // A segment s may have been split into many subsegments. Operate the one
27771 // which contains the origin of s. Then mark the rest of subsegments.
27772 subsegs->traversalinit();
27773 segloop.sh = shellfacetraverse(subsegs);
27774 while (segloop.sh != (shellface *) NULL) {
27775 segloop.shver = 0;
27776 senext2(segloop, prevseg);
27777 spivotself(prevseg);
27778 if (prevseg.sh == dummysh) {
27779 // Operate on this seg s.
27780 assert(shelltype(segloop) != SHARP); // It should be unmarked.
27781 issharp = false;
27782 spivot(segloop, startsh);
27783 if (startsh.sh != dummysh) {
27784 // First check if two facets form an acute dihedral angle at s.
27785 eorg = sorg(segloop);
27786 edest = sdest(segloop);
27787 spinsh = startsh;
27788 do {
27789 if (sorg(spinsh) != eorg) {
27790 sesymself(spinsh);
27791 }
27792 // Only do test when the spinsh is faceing inward.
27793 stpivot(spinsh, adjtet);
27794 if (adjtet.tet != dummytet) {
27795 // Get the subface on the adjacent facet.
27796 spivot(spinsh, neighsh);
27797 // Do not calculate if it is self-bonded.
27798 if (neighsh.sh != spinsh.sh) {
27799 // Calculate the dihedral angle between the two subfaces.
27800 ang = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh));
27801 // Only do check if a sharp angle has not been found.
27802 if (!issharp) issharp = (ang < smallang);
27803 // Remember the smallest facet dihedral angle.
27804 minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang;
27805 }
27806 }
27807 // Go to the next facet.
27808 spivotself(spinsh);
27809 } while (spinsh.sh != startsh.sh);
27810 // if (!issharp) {
27811 // Second check if s forms an acute angle with another seg.
27812 spinsh = startsh;
27813 do {
27814 if (sorg(spinsh) != eorg) {
27815 sesymself(spinsh);
27816 }
27817 // Calculate the angle between s and s' of this facet.
27818 neighsh = spinsh;
27819 // Rotate edges around 'eorg' until meeting another seg s'. Such
27820 // seg (s') must exist since the facet is segment-bounded.
27821 // The sum of the angles of faces at 'eorg' gives the internal
27822 // angle between the two segments.
27823 ang = 0.0;
27824 do {
27825 ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL);
27826 senext2self(neighsh);
27827 sspivot(neighsh, nextseg);
27828 if (nextseg.sh != dummysh) break;
27829 // Go to the next coplanar subface.
27830 spivotself(neighsh);
27831 assert(neighsh.sh != dummysh);
27832 if (sorg(neighsh) != eorg) {
27833 sesymself(neighsh);
27834 }
27835 } while (true);
27836 // Only do check if a sharp angle has not been found.
27837 if (!issharp) issharp = (ang < smallang);
27838 // Remember the smallest input face angle.
27839 minfaceang = minfaceang < ang ? minfaceang : ang;
27840 // Go to the next facet.
27841 spivotself(spinsh);
27842 } while (spinsh.sh != startsh.sh);
27843 // }
27844 }
27845 if (issharp) {
27846 setshelltype(segloop, SHARP);
27847 // Set the type for all subsegments at forwards.
27848 senext(segloop, nextseg);
27849 spivotself(nextseg);
27850 while (nextseg.sh != dummysh) {
27851 nextseg.shver = 0;
27852 setshelltype(nextseg, SHARP);
27853 senextself(nextseg);
27854 spivotself(nextseg);
27855 }
27856 sharpsegcount++;
27857 }
27858 }
27859 segloop.sh = shellfacetraverse(subsegs);
27860 }
27861
27862 // So far we have marked all segments which have an acute dihedral angle
27863 // or whose ORIGINs have an acute angle. In the un-marked subsegments,
27864 // there are possible ones whose DESTINATIONs have an acute angle.
27865 subsegs->traversalinit();
27866 segloop.sh = shellfacetraverse(subsegs);
27867 while (segloop.sh != (shellface *) NULL) {
27868 // Only operate if s is non-sharp and contains the dest.
27869 segloop.shver = 0;
27870 senext(segloop, nextseg);
27871 spivotself(nextseg);
27872 // if ((nextseg.sh == dummysh) && (shelltype(segloop) != SHARP)) {
27873 if (nextseg.sh == dummysh) {
27874 // issharp = false;
27875 issharp = (shelltype(segloop) == SHARP);
27876 spivot(segloop, startsh);
27877 if (startsh.sh != dummysh) {
27878 // Check if s forms an acute angle with another seg.
27879 eorg = sdest(segloop);
27880 spinsh = startsh;
27881 do {
27882 if (sorg(spinsh) != eorg) {
27883 sesymself(spinsh);
27884 }
27885 // Calculate the angle between s and s' of this facet.
27886 neighsh = spinsh;
27887 ang = 0.0;
27888 do {
27889 ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL);
27890 senext2self(neighsh);
27891 sspivot(neighsh, nextseg);
27892 if (nextseg.sh != dummysh) break;
27893 // Go to the next coplanar subface.
27894 spivotself(neighsh);
27895 assert(neighsh.sh != dummysh);
27896 if (sorg(neighsh) != eorg) {
27897 sesymself(neighsh);
27898 }
27899 } while (true);
27900 // Only do check if a sharp angle has not been found.
27901 if (!issharp) issharp = (ang < smallang);
27902 // Remember the smallest input face angle.
27903 minfaceang = minfaceang < ang ? minfaceang : ang;
27904 // Go to the next facet.
27905 spivotself(spinsh);
27906 } while (spinsh.sh != startsh.sh);
27907 }
27908 if (issharp) {
27909 setshelltype(segloop, SHARP);
27910 // Set the type for all subsegments at backwards.
27911 senext2(segloop, prevseg);
27912 spivotself(prevseg);
27913 while (prevseg.sh != dummysh) {
27914 prevseg.shver = 0;
27915 setshelltype(prevseg, SHARP);
27916 senext2self(prevseg);
27917 spivotself(prevseg);
27918 }
27919 sharpsegcount++;
27920 }
27921 }
27922 segloop.sh = shellfacetraverse(subsegs);
27923 }
27924
27925 if ((b->verbose > 0) && (sharpsegcount > 0)) {
27926 printf(" %d sharp segments.\n", sharpsegcount);
27927 }
27928}
27929
27931// //
27932// decidefeaturepointsizes() Decide the sizes for all feature points. //
27933// //
27934// A feature point is a point on a sharp segment. Every feature point p will //
27935// be assigned a positive size which is the radius of the protecting ball. //
27936// //
27937// The size of a feature point may be specified by one of the following ways://
27938// (1) directly specifying on an input vertex (by using .mtr file); //
27939// (2) imposing a fixed maximal volume constraint ('-a__' option); //
27940// (3) imposing a maximal volume constraint in a region ('-a' option); //
27941// (4) imposing a maximal area constraint on a facet (in .var file); //
27942// (5) imposing a maximal length constraint on a segment (in .var file); //
27943// (6) combining (1) - (5). //
27944// (7) automatically deriving a size if none of (1) - (6) is available. //
27945// In case (7),the size of p is set to be the smallest edge length among all //
27946// edges connecting at p. The final size of p is the minimum of (1) - (7). //
27947// //
27949
27950void tetgenmesh::decidefeaturepointsizes()
27951{
27952 list *tetlist, *verlist;
27953 shellface **segsperverlist;
27954 triface starttet;
27955 face shloop;
27956 face checkseg, prevseg, nextseg, testseg;
27957 point ploop, adjpt, e1, e2;
27958 REAL lfs_0, len, vol, maxlen, varlen;
27959 bool isfeature;
27960 int *idx2seglist;
27961 int featurecount;
27962 int idx, i, j;
27963
27964 maxlen = 0.0;
27965
27966 if (b->verbose > 0) {
27967 printf(" Deciding feature-point sizes.\n");
27968 }
27969
27970 // Constructing a map from vertices to segments.
27971 makesegmentmap(idx2seglist, segsperverlist);
27972 // Initialize working lists.
27973 tetlist = new list(sizeof(triface), NULL, 256);
27974 verlist = new list(sizeof(point *), NULL, 256);
27975
27976 if (b->fixedvolume) {
27977 // A fixed volume constraint is imposed. This gives an upper bound of
27978 // the maximal radius of the protect ball of a vertex.
27979 maxlen = pow(6.0 * b->maxvolume, 1.0/3.0);
27980 }
27981
27982 if (!b->refine) {
27983 // Initially correct types for Steiner points.
27984 featurecount = 0;
27985 points->traversalinit();
27986 ploop = pointtraverse();
27987 while (ploop != (point) NULL) {
27988 if (pointtype(ploop) == NACUTEVERTEX) {
27989 if (point2sh(ploop) != (shellface) NULL) {
27990 setpointtype(ploop, FREESEGVERTEX);
27991 featurecount++;
27992 }
27993 }
27994 ploop = pointtraverse();
27995 }
27996#ifdef SELF_CHECK
27997 if ((b->verbose > 0) && (featurecount > 0)) {
27998 printf(" %d Steiner points correction.\n", featurecount);
27999 }
28000#endif
28001 }
28002
28003 // First only assign a size of p if p is not a Steiner point. The size of
28004 // a Steiner point will be interpolated later from the endpoints of the
28005 // segment on which it lies.
28006 featurecount = 0;
28007 points->traversalinit();
28008 ploop = pointtraverse();
28009 while (ploop != (point) NULL) {
28010 if (pointtype(ploop) != FREESEGVERTEX) {
28011 // Is p a feature point?
28012 isfeature = false;
28013 idx = pointmark(ploop) - in->firstnumber;
28014 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) {
28015 checkseg.sh = segsperverlist[i];
28016 isfeature = (shelltype(checkseg) == SHARP);
28017 }
28018 // Decide the size of p if it is on a sharp segment.
28019 if (isfeature) {
28020 // Find a tet containing p (checkseg is a sharp seg which contains p).
28021 sstpivot(&checkseg, &starttet);
28022 // Form star(p).
28023 tetlist->append(&starttet);
28024 formstarpolyhedron(ploop, tetlist, verlist, true);
28025 // Decide the size for p if no input size is given on input.
28026 if (ploop[pointmtrindex] == 0.0) {
28027 // Calculate lfs_0(p).
28028 lfs_0 = longest;
28029 for (i = 0; i < verlist->len(); i++) {
28030 adjpt = * (point *)(* verlist)[i];
28031 if (pointtype(adjpt) == FREESEGVERTEX) {
28032 // A Steiner point q. Find the seg it lies on.
28033 sdecode(point2sh(adjpt), checkseg);
28034 assert(checkseg.sh != dummysh);
28035 checkseg.shver = 0;
28036 // Find the origin of this seg.
28037 prevseg = checkseg;
28038 do {
28039 senext2(prevseg, testseg);
28040 spivotself(testseg);
28041 if (testseg.sh == dummysh) break;
28042 prevseg = testseg; // Go to the previous subseg.
28043 prevseg.shver = 0;
28044 } while (true);
28045 // Find the dest of this seg.
28046 nextseg = checkseg;
28047 do {
28048 senext(nextseg, testseg);
28049 spivotself(testseg);
28050 if (testseg.sh == dummysh) break;
28051 nextseg = testseg; // Go to the next subseg.
28052 nextseg.shver = 0;
28053 } while (true);
28054 e1 = sorg(prevseg);
28055 e2 = sdest(nextseg);
28056 // Check if p is the origin or the dest of this seg.
28057 if (ploop == e1) {
28058 // Set q to be the dest of this seg.
28059 adjpt = e2;
28060 } else if (ploop == e2) {
28061 // Set q to be the org of this seg.
28062 adjpt = e1;
28063 }
28064 }
28065 len = distance(ploop, adjpt);
28066 if (lfs_0 > len) lfs_0 = len;
28067 }
28068 ploop[pointmtrindex] = lfs_0;
28069 }
28070 if (b->fixedvolume) {
28071 // A fixed volume constraint is imposed. Adjust H(p) <= maxlen.
28072 if (ploop[pointmtrindex] > maxlen) {
28073 ploop[pointmtrindex] = maxlen;
28074 }
28075 }
28076 if (b->varvolume) {
28077 // Variant volume constraints are imposed. Adjust H(p) <= varlen.
28078 for (i = 0; i < tetlist->len(); i++) {
28079 starttet = * (triface *)(* tetlist)[i];
28080 vol = volumebound(starttet.tet);
28081 if (vol > 0.0) {
28082 varlen = pow(6 * vol, 1.0/3.0);
28083 if (ploop[pointmtrindex] > varlen) {
28084 ploop[pointmtrindex] = varlen;
28085 }
28086 }
28087 }
28088 }
28089 // Clear working lists.
28090 tetlist->clear();
28091 verlist->clear();
28092 featurecount++;
28093 } else {
28094 // NO feature point, set the size of p be zero.
28095 ploop[pointmtrindex] = 0.0;
28096 }
28097 } // if (pointtype(ploop) != FREESEGVERTEX) {
28098 ploop = pointtraverse();
28099 }
28100
28101 if (b->verbose > 0) {
28102 printf(" %d feature points.\n", featurecount);
28103 }
28104
28105 if (!b->refine) {
28106 // Second only assign sizes for all Steiner points. A Steiner point p
28107 // inserted on a sharp segment s is assigned a size by interpolating
28108 // the sizes of the original endpoints of s.
28109 featurecount = 0;
28110 points->traversalinit();
28111 ploop = pointtraverse();
28112 while (ploop != (point) NULL) {
28113 if (pointtype(ploop) == FREESEGVERTEX) {
28114 if (ploop[pointmtrindex] == 0.0) {
28115 sdecode(point2sh(ploop), checkseg);
28116 assert(checkseg.sh != dummysh);
28117 if (shelltype(checkseg) == SHARP) {
28118 checkseg.shver = 0;
28119 // Find the origin of this seg.
28120 prevseg = checkseg;
28121 do {
28122 senext2(prevseg, testseg);
28123 spivotself(testseg);
28124 if (testseg.sh == dummysh) break;
28125 prevseg = testseg; // Go the previous subseg.
28126 prevseg.shver = 0;
28127 } while (true);
28128 // Find the dest of this seg.
28129 nextseg = checkseg;
28130 do {
28131 senext(nextseg, testseg);
28132 spivotself(testseg);
28133 if (testseg.sh == dummysh) break;
28134 nextseg = testseg; // Go the next subseg.
28135 nextseg.shver = 0;
28136 } while (true);
28137 e1 = sorg(prevseg);
28138 e2 = sdest(nextseg);
28139 len = distance(e1, e2);
28140 lfs_0 = distance(e1, ploop);
28141 // The following assert() happens when -Y option is used.
28142 if (b->nobisect == 0) {
28143 assert(lfs_0 < len);
28144 }
28145 ploop[pointmtrindex] = e1[pointmtrindex]
28146 + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]);
28147 featurecount++;
28148 } else {
28149 // NO feature point, set the size of p be zero.
28150 ploop[pointmtrindex] = 0.0;
28151 } // if (shelltype(checkseg) == SHARP)
28152 } // if (ploop[pointmtrindex] == 0.0)
28153 } // if (pointtype(ploop) != FREESEGVERTEX)
28154 ploop = pointtraverse();
28155 }
28156 if ((b->verbose > 0) && (featurecount > 0)) {
28157 printf(" %d Steiner feature points.\n", featurecount);
28158 }
28159 }
28160
28161 if (varconstraint) {
28162 // A .var file exists. Adjust feature sizes.
28163 if (in->facetconstraintlist) {
28164 // Have facet area constrains.
28165 subfaces->traversalinit();
28166 shloop.sh = shellfacetraverse(subfaces);
28167 while (shloop.sh != (shellface *) NULL) {
28168 varlen = areabound(shloop);
28169 if (varlen > 0.0) {
28170 // Check if the three corners are feature points.
28171 varlen = sqrt(varlen);
28172 for (j = 0; j < 3; j++) {
28173 ploop = (point) shloop.sh[3 + j];
28174 isfeature = false;
28175 idx = pointmark(ploop) - in->firstnumber;
28176 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature;
28177 i++) {
28178 checkseg.sh = segsperverlist[i];
28179 isfeature = (shelltype(checkseg) == SHARP);
28180 }
28181 if (isfeature) {
28182 assert(ploop[pointmtrindex] > 0.0);
28183 if (ploop[pointmtrindex] > varlen) {
28184 ploop[pointmtrindex] = varlen;
28185 }
28186 }
28187 } // for (j = 0; j < 3; j++)
28188 }
28189 shloop.sh = shellfacetraverse(subfaces);
28190 }
28191 }
28192 if (in->segmentconstraintlist) {
28193 // Have facet area constrains.
28194 subsegs->traversalinit();
28195 shloop.sh = shellfacetraverse(subsegs);
28196 while (shloop.sh != (shellface *) NULL) {
28197 varlen = areabound(shloop);
28198 if (varlen > 0.0) {
28199 // Check if the two endpoints are feature points.
28200 for (j = 0; j < 2; j++) {
28201 ploop = (point) shloop.sh[3 + j];
28202 isfeature = false;
28203 idx = pointmark(ploop) - in->firstnumber;
28204 for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature;
28205 i++) {
28206 checkseg.sh = segsperverlist[i];
28207 isfeature = (shelltype(checkseg) == SHARP);
28208 }
28209 if (isfeature) {
28210 assert(ploop[pointmtrindex] > 0.0);
28211 if (ploop[pointmtrindex] > varlen) {
28212 ploop[pointmtrindex] = varlen;
28213 }
28214 }
28215 } // for (j = 0; j < 2; j++)
28216 }
28217 shloop.sh = shellfacetraverse(subsegs);
28218 }
28219 }
28220 } // if (varconstraint)
28221
28222 delete [] segsperverlist;
28223 delete [] idx2seglist;
28224 delete tetlist;
28225 delete verlist;
28226}
28227
28229// //
28230// enqueueencsub() Add an encroached subface into the queue. //
28231// //
28233
28234void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
28235 REAL* cent)
28236{
28237 badface *encsub;
28238 int i;
28239
28240 encsub = (badface *) badsubfaces->alloc();
28241 encsub->ss = *testsub;
28242 encsub->forg = sorg(*testsub);
28243 encsub->fdest = sdest(*testsub);
28244 encsub->fapex = sapex(*testsub);
28245 encsub->foppo = (point) encpt;
28246 for (i = 0; i < 3; i++) encsub->cent[i] = cent[i];
28247 encsub->nextitem = (badface *) NULL;
28248 // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes:
28249 // (1) We can regonize it is encroached; (2) It is uniquely queued.
28250 setshell2badface(encsub->ss, encsub);
28251 // Add the subface to the end of a queue (quenumber = 2, high priority).
28252 *subquetail[quenumber] = encsub;
28253 // Maintain a pointer to the NULL pointer at the end of the queue.
28254 subquetail[quenumber] = &encsub->nextitem;
28255 if (b->verbose > 2) {
28256 printf(" Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg),
28257 pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber);
28258 }
28259}
28260
28262// //
28263// dequeueencsub() Remove an enc-subface from the front of the queue. //
28264// //
28266
28267tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
28268{
28269 badface *result;
28270 int quenumber;
28271
28272 // Look for a nonempty queue.
28273 for (quenumber = 2; quenumber >= 0; quenumber--) {
28274 result = subquefront[quenumber];
28275 if (result != (badface *) NULL) {
28276 // Remove the badface from the queue.
28277 subquefront[quenumber] = result->nextitem;
28278 // Maintain a pointer to the NULL pointer at the end of the queue.
28279 if (subquefront[quenumber] == (badface *) NULL) {
28280 subquetail[quenumber] = &subquefront[quenumber];
28281 }
28282 *pquenumber = quenumber;
28283 return result;
28284 }
28285 }
28286 return (badface *) NULL;
28287}
28288
28290// //
28291// enqueuebadtet() Add a tetrahedron into the queue. //
28292// //
28294
28295void tetgenmesh::enqueuebadtet(triface* testtet, REAL ratio2, REAL* cent)
28296{
28297 badface *newbadtet;
28298 int queuenumber;
28299 int i;
28300
28301 // Allocate space for the bad tetrahedron.
28302 newbadtet = (badface *) badtetrahedrons->alloc();
28303 newbadtet->tt = *testtet;
28304 newbadtet->key = ratio2;
28305 if (cent != NULL) {
28306 for (i = 0; i < 3; i++) newbadtet->cent[i] = cent[i];
28307 } else {
28308 for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
28309 }
28310 newbadtet->forg = org(*testtet);
28311 newbadtet->fdest = dest(*testtet);
28312 newbadtet->fapex = apex(*testtet);
28313 newbadtet->foppo = oppo(*testtet);
28314 newbadtet->nextitem = (badface *) NULL;
28315 // Determine the appropriate queue to put the bad tetrahedron into.
28316 if (ratio2 > b->goodratio) {
28317 // queuenumber = (int) ((ratio2 - b->goodratio) / 0.5);
28318 queuenumber = (int) (64.0 - 64.0 / ratio2);
28319 // 'queuenumber' may overflow (negative) caused by a very large ratio.
28320 if ((queuenumber > 63) || (queuenumber < 0)) {
28321 queuenumber = 63;
28322 }
28323 } else {
28324 // It's not a bad ratio; put the tet in the lowest-priority queue.
28325 queuenumber = 0;
28326 }
28327
28328 // Are we inserting into an empty queue?
28329 if (tetquefront[queuenumber] == (badface *) NULL) {
28330 // Yes. Will this become the highest-priority queue?
28331 if (queuenumber > firstnonemptyq) {
28332 // Yes, this is the highest-priority queue.
28333 nextnonemptyq[queuenumber] = firstnonemptyq;
28334 firstnonemptyq = queuenumber;
28335 } else {
28336 // No. Find the queue with next higher priority.
28337 i = queuenumber + 1;
28338 while (tetquefront[i] == (badface *) NULL) {
28339 i++;
28340 }
28341 // Mark the newly nonempty queue as following a higher-priority queue.
28342 nextnonemptyq[queuenumber] = nextnonemptyq[i];
28343 nextnonemptyq[i] = queuenumber;
28344 }
28345 // Put the bad tetrahedron at the beginning of the (empty) queue.
28346 tetquefront[queuenumber] = newbadtet;
28347 } else {
28348 // Add the bad tetrahedron to the end of an already nonempty queue.
28349 tetquetail[queuenumber]->nextitem = newbadtet;
28350 }
28351 // Maintain a pointer to the last tetrahedron of the queue.
28352 tetquetail[queuenumber] = newbadtet;
28353
28354 if (b->verbose > 2) {
28355 printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n",
28356 pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
28357 pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
28358 sqrt(ratio2), queuenumber);
28359 }
28360}
28361
28363// //
28364// dequeuebadtet() Remove a tetrahedron from the front of the queue. //
28365// //
28367
28368tetgenmesh::badface* tetgenmesh::topbadtetra()
28369{
28370 // Keep a record of which queue was accessed in case dequeuebadtetra()
28371 // is called later.
28372 recentq = firstnonemptyq;
28373 // If no queues are nonempty, return NULL.
28374 if (firstnonemptyq < 0) {
28375 return (badface *) NULL;
28376 } else {
28377 // Return the first tetrahedron of the highest-priority queue.
28378 return tetquefront[firstnonemptyq];
28379 }
28380}
28381
28382void tetgenmesh::dequeuebadtet()
28383{
28384 badface *deadbadtet;
28385 int i;
28386
28387 // If queues were empty last time topbadtetra() was called, do nothing.
28388 if (recentq >= 0) {
28389 // Find the tetrahedron last returned by topbadtetra().
28390 deadbadtet = tetquefront[recentq];
28391 // Remove the tetrahedron from the queue.
28392 tetquefront[recentq] = deadbadtet->nextitem;
28393 // If this queue is now empty, update the list of nonempty queues.
28394 if (deadbadtet == tetquetail[recentq]) {
28395 // Was this the highest-priority queue?
28396 if (firstnonemptyq == recentq) {
28397 // Yes; find the queue with next lower priority.
28398 firstnonemptyq = nextnonemptyq[firstnonemptyq];
28399 } else {
28400 // No; find the queue with next higher priority.
28401 i = recentq + 1;
28402 while (tetquefront[i] == (badface *) NULL) {
28403 i++;
28404 }
28405 nextnonemptyq[i] = nextnonemptyq[recentq];
28406 }
28407 }
28408 // Return the bad tetrahedron to the pool.
28409 badfacedealloc(badtetrahedrons, deadbadtet);
28410 }
28411}
28412
28414// //
28415// checkseg4encroach() Check a subsegment to see if it is encroached. //
28416// //
28417// A segment s is encroached if there is a vertex lies inside or on its dia- //
28418// metral circumsphere, i.e., s faces an angle theta >= 90 degrees. //
28419// //
28420// If 'testpt' (p) != NULL, only test if 'testseg' (s) is encroached by it, //
28421// else, check all apexes of faces around s. Return TRUE if s is encroached. //
28422// If and 'enqflag' is TRUE, add it into 'badsubsegs' if s is encroached. //
28423// //
28424// If 'prefpt' != NULL, it returns the reference point (defined in my paper) //
28425// if it exists. This point is will be used to split s. //
28426// //
28428
28429bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt,
28430 bool enqflag)
28431{
28432 badface *encsubseg;
28433 triface starttet, spintet;
28434 point eorg, edest, eapex, encpt;
28435 REAL cent[3], radius, dist, diff;
28436 REAL maxradius;
28437 bool enq;
28438 int hitbdry;
28439
28440 enq = false;
28441 eorg = sorg(*testseg);
28442 edest = sdest(*testseg);
28443 cent[0] = 0.5 * (eorg[0] + edest[0]);
28444 cent[1] = 0.5 * (eorg[1] + edest[1]);
28445 cent[2] = 0.5 * (eorg[2] + edest[2]);
28446 radius = distance(cent, eorg);
28447
28448 if (varconstraint && (areabound(*testseg) > 0.0)) {
28449 enq = (2.0 * radius) > areabound(*testseg);
28450 }
28451
28452 if (!enq) {
28453 maxradius = 0.0;
28454 if (testpt == (point) NULL) {
28455 // Check if it is encroached by traversing all faces containing it.
28456 sstpivot(testseg, &starttet);
28457 eapex = apex(starttet);
28458 spintet = starttet;
28459 hitbdry = 0;
28460 do {
28461 dist = distance(cent, apex(spintet));
28462 diff = dist - radius;
28463 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28464 if (diff <= 0.0) {
28465 // s is encroached.
28466 enq = true;
28467 if (prefpt != (point *) NULL) {
28468 // Find the reference point.
28469 encpt = apex(spintet);
28470 circumsphere(eorg, edest, encpt, NULL, NULL, &dist);
28471 if (dist > maxradius) {
28472 // Rememebr this point.
28473 *prefpt = encpt;
28474 maxradius = dist;
28475 }
28476 } else {
28477 break;
28478 }
28479 }
28480 if (!fnextself(spintet)) {
28481 hitbdry++;
28482 if (hitbdry < 2) {
28483 esym(starttet, spintet);
28484 if (!fnextself(spintet)) {
28485 hitbdry++;
28486 }
28487 }
28488 }
28489 } while (apex(spintet) != eapex && (hitbdry < 2));
28490 } else {
28491 // Only check if 'testseg' is encroached by 'testpt'.
28492 dist = distance(cent, testpt);
28493 diff = dist - radius;
28494 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28495 enq = (diff <= 0.0);
28496 }
28497 }
28498
28499 if (enq && enqflag) {
28500 if (b->verbose > 2) {
28501 printf(" Queuing encroaching subsegment (%d, %d).\n",
28502 pointmark(eorg), pointmark(edest));
28503 }
28504 encsubseg = (badface *) badsubsegs->alloc();
28505 encsubseg->ss = *testseg;
28506 encsubseg->forg = eorg;
28507 encsubseg->fdest = edest;
28508 encsubseg->foppo = (point) NULL; // Not used.
28509 // Set the pointer of 'encsubseg' into 'testseg'. It has two purposes:
28510 // (1) We can regonize it is encroached; (2) It is uniquely queued.
28511 setshell2badface(encsubseg->ss, encsubseg);
28512 }
28513
28514 return enq;
28515}
28516
28518// //
28519// checksub4encroach() Check a subface to see if it is encroached. //
28520// //
28521// A subface f is encroached if there is a vertex inside or on its diametral //
28522// circumsphere. //
28523// //
28524// If 'testpt (p) != NULL', test if 'testsub' (f) is encroached by it, else, //
28525// test if f is encroached by one of the two opposites of the adjacent tets. //
28526// Return TRUE if f is encroached and queue it if 'enqflag' is set. //
28527// //
28529
28530bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
28531{
28532 triface abuttet;
28533 point pa, pb, pc, encpt;
28534 REAL A[4][4], rhs[4], D;
28535 REAL cent[3], area;
28536 REAL radius, dist, diff;
28537 bool enq;
28538 int indx[4];
28539 int quenumber;
28540
28541 enq = false;
28542 radius = 0.0;
28543 encpt = (point) NULL;
28544
28545 pa = sorg(*testsub);
28546 pb = sdest(*testsub);
28547 pc = sapex(*testsub);
28548
28549 // Compute the coefficient matrix A (3x3).
28550 A[0][0] = pb[0] - pa[0];
28551 A[0][1] = pb[1] - pa[1];
28552 A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
28553 A[1][0] = pc[0] - pa[0];
28554 A[1][1] = pc[1] - pa[1];
28555 A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
28556 cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
28557
28558 if (varconstraint && (areabound(*testsub) > 0.0)) {
28559 // Check if the subface has too big area.
28560 area = 0.5 * sqrt(dot(A[2], A[2]));
28561 enq = area > areabound(*testsub);
28562 if (enq) {
28563 quenumber = 2; // A queue of subfaces having too big area.
28564 }
28565 }
28566
28567 // Compute the right hand side vector b (3x1).
28568 rhs[0] = 0.5 * dot(A[0], A[0]);
28569 rhs[1] = 0.5 * dot(A[1], A[1]);
28570 rhs[2] = 0.0;
28571 // Solve the 3 by 3 equations use LU decomposition with partial pivoting
28572 // and backward and forward substitute..
28573 if (lu_decmp(A, 3, indx, &D, 0)) {
28574 lu_solve(A, 3, indx, rhs, 0);
28575 cent[0] = pa[0] + rhs[0];
28576 cent[1] = pa[1] + rhs[1];
28577 cent[2] = pa[2] + rhs[2];
28578 radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
28579 }
28580
28581 if (!enq) {
28582 // Check if the subface is encroached.
28583 if (testpt == (point) NULL) {
28584 stpivot(*testsub, abuttet);
28585 if (abuttet.tet != dummytet) {
28586 dist = distance(cent, oppo(abuttet));
28587 diff = dist - radius;
28588 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28589 enq = (diff <= 0.0);
28590 if (enq) encpt = oppo(abuttet);
28591 }
28592 if (!enq) {
28593 sesymself(*testsub);
28594 stpivot(*testsub, abuttet);
28595 if (abuttet.tet != dummytet) {
28596 dist = distance(cent, oppo(abuttet));
28597 diff = dist - radius;
28598 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28599 enq = (diff <= 0.0);
28600 if (enq) encpt = oppo(abuttet);
28601 }
28602 }
28603 } else {
28604 dist = distance(cent, testpt);
28605 diff = dist - radius;
28606 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28607 enq = (diff <= 0.0);
28608 }
28609 if (enq) {
28610 quenumber = 0; // A queue of encroached subfaces.
28611 }
28612 }
28613
28614 if (enq && enqflag) {
28615 enqueueencsub(testsub, encpt, quenumber, cent);
28616 }
28617
28618 return enq;
28619}
28620
28622// //
28623// checktet4badqual() Test a tetrahedron for quality measures. //
28624// //
28625// Tests a tetrahedron to see if it satisfies the minimum ratio condition //
28626// and the maximum volume condition. Tetrahedra that aren't upto spec are //
28627// added to the bad tetrahedron queue. //
28628// //
28630
28631bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
28632{
28633 point pa, pb, pc, pd, pe1, pe2;
28634 REAL vda[3], vdb[3], vdc[3];
28635 REAL vab[3], vbc[3], vca[3];
28636 REAL N[4][3], A[4][4], rhs[4], D;
28637 REAL elen[6], circumcent[3];
28638 REAL bicent[3], offcent[3];
28639 offcent[0] = 0.0; // Just to avoid uninitialised value warnings.
28640 offcent[1] = 0.0; // Just to avoid uninitialised value warnings.
28641 offcent[2] = 0.0; // Just to avoid uninitialised value warnings.
28642 REAL volume, L, cosd;
28643 REAL radius2, smlen2, ratio2;
28644 REAL dist, sdist, split;
28645 bool enq;
28646 int indx[4];
28647 int sidx, i, j;
28648
28649 pa = (point) testtet->tet[4];
28650 pb = (point) testtet->tet[5];
28651 pc = (point) testtet->tet[6];
28652 pd = (point) testtet->tet[7];
28653
28654 // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
28655 // Set the matrix A = [vda, vdb, vdc]^T.
28656 for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
28657 for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
28658 for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
28659 // Get the rest edge vectors
28660 for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
28661 for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
28662 for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
28663
28664 // Lu-decompose the matrix A.
28665 lu_decmp(A, 3, indx, &D, 0);
28666 // Get the volume of abcd.
28667 volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
28668 if (volume < 0.0) volume = -volume;
28669 // Check the radiu-edge ratio of the tet.
28670 rhs[0] = 0.5 * dot(vda, vda);
28671 rhs[1] = 0.5 * dot(vdb, vdb);
28672 rhs[2] = 0.5 * dot(vdc, vdc);
28673 lu_solve(A, 3, indx, rhs, 0);
28674 // Get the circumcenter.
28675 for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
28676 // Get the square of the circumradius.
28677 radius2 = dot(rhs, rhs);
28678 // Find the square of the shortest edge length.
28679 elen[0] = dot(vda, vda);
28680 elen[1] = dot(vdb, vdb);
28681 elen[2] = dot(vdc, vdc);
28682 elen[3] = dot(vab, vab);
28683 elen[4] = dot(vbc, vbc);
28684 elen[5] = dot(vca, vca);
28685 smlen2 = elen[0]; sidx = 0;
28686 for (i = 1; i < 6; i++) {
28687 if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; }
28688 }
28689 // Calculate the square of radius-edge ratio.
28690 ratio2 = radius2 / smlen2;
28691 // Check whether the ratio is smaller than permitted.
28692 enq = ratio2 > b->goodratio;
28693 if (!enq) {
28694 // abcd has good ratio.
28695 // ratio2 = 0.0;
28696 // if (b->offcenter) {
28697 // Test if it is a sliver.
28698 // Compute the 4 face normals (N[0], ..., N[3]).
28699 for (j = 0; j < 3; j++) {
28700 for (i = 0; i < 3; i++) rhs[i] = 0.0;
28701 rhs[j] = 1.0; // Positive means the inside direction
28702 lu_solve(A, 3, indx, rhs, 0);
28703 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
28704 }
28705 // Get the fourth normal by summing up the first three.
28706 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
28707 // Normalized the normals.
28708 for (i = 0; i < 4; i++) {
28709 L = sqrt(dot(N[i], N[i]));
28710 if (L > 0.0) {
28711 for (j = 0; j < 3; j++) N[i][j] /= L;
28712 }
28713 }
28714 // N[0] is the normal of face bcd. Test the dihedral angles at edge
28715 // cd, bd, and bc to see if they are too small or too big.
28716 for (i = 1; i < 4 && !enq; i++) {
28717 cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
28718 enq = cosd > cosmindihed;
28719 }
28720 if (!enq) {
28721 for (i = 2; i < 4 && !enq; i++) {
28722 cosd = -dot(N[1], N[i]); // Edge ad, ac
28723 enq = cosd > cosmindihed;
28724 }
28725 if (!enq) {
28726 cosd = -dot(N[2], N[3]); // Edge ab
28727 enq = cosd > cosmindihed;
28728 }
28729 }
28730 // }
28731 } else if (b->offcenter) {
28732 // abcd has bad-quality. Use off-center instead of circumcenter.
28733 switch (sidx) {
28734 case 0: // edge da.
28735 pe1 = pd; pe2 = pa; break;
28736 case 1: // edge db.
28737 pe1 = pd; pe2 = pb; break;
28738 case 2: // edge dc.
28739 pe1 = pd; pe2 = pc; break;
28740 case 3: // edge ab.
28741 pe1 = pa; pe2 = pb; break;
28742 case 4: // edge bc.
28743 pe1 = pb; pe2 = pc; break;
28744 case 5: // edge ca.
28745 pe1 = pc; pe2 = pa; break;
28746 default:
28747 pe1 = pe2 = (point) NULL; // Avoid a compile warning.
28748 }
28749 // The shortest edge is e1->e2.
28750 for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]);
28751 dist = distance(bicent, circumcent);
28752 // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle.
28753 // The following formulae is from
28754 sdist = b->alpha3 * (b->minratio+sqrt(b->goodratio-0.25))* sqrt(smlen2);
28755 split = sdist / dist;
28756 if (split > 1.0) split = 1.0;
28757 // Get the off-center.
28758 for (i = 0; i < 3; i++) {
28759 offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]);
28760 }
28761 }
28762
28763 if (!enq && (b->varvolume || b->fixedvolume)) {
28764 // Check if the tet has too big volume.
28765 enq = b->fixedvolume && (volume > b->maxvolume);
28766 if (!enq && b->varvolume) {
28767 enq = (volume > volumebound(testtet->tet)) &&
28768 (volumebound(testtet->tet) > 0.0);
28769 }
28770 }
28771
28772 if (!enq) {
28773 // Check if the user-defined sizing function is satisfied.
28774 if (b->metric) {
28775 // assert(b->alpha1 > 0.0);
28776 sdist = sqrt(radius2) / b->alpha1;
28777 for (i = 0; i < 4; i++) {
28778 pa = (point) testtet->tet[4 + i];
28779 // Get the indicated size of p.
28780 dist = pa[pointmtrindex]; // dist = b->alpha1 * pa[pointmtrindex];
28781 enq = ((dist < sdist) && (dist > 0.0));
28782 if (enq) break; // It is bad wrt. a node constraint.
28783 // *** Experiment ! Stop test if c is inside H(a).
28784 // if ((dist > 0.0) && (dist > sdist)) break;
28785 }
28786 // *** Experiment !
28787 // enq = (i == 4); // Does c lies outside all sparse-ball?
28788 } // if (b->metric)
28789 }
28790
28791 if (enq && enqflag) {
28792 if (b->offcenter && (ratio2 > b->goodratio)) {
28793 for (i = 0; i < 3; i++) circumcent[i] = offcent[i];
28794 }
28795 enqueuebadtet(testtet, ratio2, circumcent);
28796 }
28797
28798 return enq;
28799}
28800
28802// //
28803// acceptsegpt() Check if a segment point can be inserted or not. //
28804// //
28805// Segment(ab) is indicated to be split by a point p (\in ab). This routine //
28806// decides whether p can be inserted or not. //
28807// //
28808// p can not be inserted either the '-Y' option is used and ab is a hull //
28809// segment or '-YY' option is used. //
28810// //
28811// p can be inserted if it is in one of the following cases: //
28812// (1) if L = |a - b| is too long wrt the edge constraint; or //
28813// (2) if |x - p| > \alpha_2 H(x) for x = a, b; or //
28814// (3) if 'refpt' != NULL. //
28815// //
28817
28818bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg)
28819{
28820 point p[2];
28821 REAL L, lfs;
28822 int i, j;
28823
28824 if (b->nobisect == 1) {
28825 // '-Y'. It can not be split if it is on the hull.
28826 triface spintet;
28827 point pc;
28828 sstpivot(splitseg, &spintet);
28829 assert(spintet.tet != dummytet);
28830 pc = apex(spintet);
28831 do {
28832 if (!fnextself(spintet)) {
28833 // Meet a boundary face - s is on the hull.
28834 return false;
28835 }
28836 } while (pc != apex(spintet));
28837 } else if (b->nobisect > 1) {
28838 // '-YY'. Do not split it.
28839 return false;
28840 }
28841
28842 p[0] = sorg(*splitseg);
28843 p[1] = sdest(*splitseg);
28844 if (varconstraint && (areabound(*splitseg) > 0)) {
28845 lfs = areabound(*splitseg);
28846 L = distance(p[0], p[1]);
28847 if (L > lfs) {
28848 return true; // case (1)
28849 }
28850 }
28851
28852 j = 0; // Use j to count the number of inside balls.
28853 for (i = 0; i < 2; i++) {
28854 // Check if p is inside the protect ball of q.
28855 if (p[i][pointmtrindex] > 0.0) {
28856 lfs = b->alpha2 * p[i][pointmtrindex];
28857 L = distance(p[i], segpt);
28858 if (L < lfs) j++; // p is inside ball.
28859 }
28860 }
28861 if (j == 0) return true; // case (3).
28862
28863 // If 'refpt' != NULL, force p to be inserted.
28864 if (refpt != (point) NULL) {
28865 cdtenforcesegpts++;
28866 return true;
28867 }
28868
28869 // Do not split it.
28870 rejsegpts++;
28871 return false;
28872}
28873
28875// //
28876// acceptfacpt() Check if a facet point can be inserted or not. //
28877// //
28878// 'subceillist' is CBC(p). 'verlist' (V) is empty on input, it returns the //
28879// set of vertices of CBC(p). //
28880// //
28881// p can not be inserted either the '-Y' option is used and the facet is on //
28882// the hull or '-YY' option is used. //
28883// //
28884// p can be inserted if |p - v| > \alpha_2 H(v), for all v \in V. //
28885// //
28887
28888bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
28889{
28890 face *testsh;
28891 point p[2], ploop;
28892 REAL L, lfs;
28893 int idx, i, j;
28894
28895 if (b->nobisect == 1) {
28896 // '-Y'. p can not be inserted if CBC(p) is on the hull.
28897 triface testtet;
28898 testsh = (face *)(* subceillist)[0];
28899 stpivot(*testsh, testtet);
28900 if (testtet.tet != dummytet) {
28901 sesymself(*testsh);
28902 stpivot(*testsh, testtet);
28903 }
28904 if (testtet.tet == dummytet) return false;
28905 } else if (b->nobisect > 1) {
28906 // '-YY'. Do not split s.
28907 return false;
28908 }
28909
28910 // Collect the vertices of CBC(p), save them in V.
28911 for (i = 0; i < subceillist->len(); i++) {
28912 testsh = (face *)(* subceillist)[i];
28913 p[0] = sorg(*testsh);
28914 p[1] = sdest(*testsh);
28915 for (j = 0; j < 2; j++) {
28916 idx = pointmark(p[j]);
28917 if (idx >= 0) {
28918 setpointmark(p[j], -idx - 1);
28919 verlist->append(&(p[j]));
28920 }
28921 }
28922 }
28923
28924 j = 0; // Use j to count the number of inside balls.
28925 for (i = 0; i < verlist->len(); i++) {
28926 ploop = * (point *)(* verlist)[i];
28927 // Uninfect q.
28928 idx = pointmark(ploop);
28929 setpointmark(ploop, -(idx + 1));
28930 // Check if p is inside the protect ball of q.
28931 if (ploop[pointmtrindex] > 0.0) {
28932 lfs = b->alpha2 * ploop[pointmtrindex];
28933 L = distance(ploop, facpt);
28934 if (L < lfs) j++; // p is inside ball.
28935 }
28936 }
28937 verlist->clear();
28938
28939 if (j == 0) return true; // case (3).
28940
28941 rejsubpts++;
28942 return false;
28943}
28944
28946// //
28947// acceptvolpt() Check if a volume point can be inserted or not. //
28948// //
28949// 'ceillist' is B(p). 'verlist' (V) is empty on input, it returns the set //
28950// of vertices of B(p). //
28951// //
28952// p can be split if |p - v| > \alpha_2 H(v), for all v \in V. //
28953// //
28955
28956bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist)
28957{
28958 triface* testtet;
28959 point p[3], ploop;
28960 REAL L, lfs;
28961 int idx, i, j;
28962
28963 // Collect the vertices of CBC(p), save them in V.
28964 for (i = 0; i < ceillist->len(); i++) {
28965 testtet = (triface *)(* ceillist)[i];
28966 p[0] = org(*testtet);
28967 p[1] = dest(*testtet);
28968 p[2] = apex(*testtet);
28969 for (j = 0; j < 3; j++) {
28970 idx = pointmark(p[j]);
28971 if (idx >= 0) {
28972 setpointmark(p[j], -idx - 1);
28973 verlist->append(&(p[j]));
28974 }
28975 }
28976 }
28977
28978 j = 0; // Use j to counte the number of inside balls.
28979 for (i = 0; i < verlist->len(); i++) {
28980 ploop = * (point *)(* verlist)[i];
28981 // Uninfect q.
28982 idx = pointmark(ploop);
28983 setpointmark(ploop, -(idx + 1));
28984 // Check if p is inside the protect ball of q.
28985 if (ploop[pointmtrindex] > 0.0) {
28986 lfs = b->alpha2 * ploop[pointmtrindex];
28987 L = distance(ploop, volpt);
28988 if (L < lfs) j++; // p is inside the protect ball.
28989 }
28990 }
28991 verlist->clear();
28992
28993 if (j == 0) return true; // case (2).
28994
28995 rejtetpts++;
28996 return false;
28997}
28998
29000// //
29001// getsplitpoint() Get the inserting point in a segment. //
29002// //
29004
29005void tetgenmesh::getsplitpoint(point e1, point e2, point refpt, point newpt)
29006{
29007 point ei, ej;
29008 REAL split, L, d1, d2, ps, rs;
29009 bool acutea, acuteb;
29010 int i;
29011
29012 if (refpt != (point) NULL) {
29013 // Use the CDT rules to split the segment.
29014 acutea = (pointtype(e1) == ACUTEVERTEX);
29015 acuteb = (pointtype(e2) == ACUTEVERTEX);
29016 if (acutea ^ acuteb) {
29017 // Only one endpoint is acute. Use rule-2 or rule-3.
29018 ei = acutea ? e1 : e2;
29019 ej = acutea ? e2 : e1;
29020 L = distance(ei, ej);
29021 // Apply rule-2.
29022 d1 = distance(ei, refpt);
29023 split = d1 / L;
29024 for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]);
29025 // Check if rule-3 is needed.
29026 d2 = distance(refpt, newpt);
29027 if (d2 > (L - d1)) {
29028 // Apply rule-3.
29029 if ((d1 - d2) > (0.5 * d1)) {
29030 split = (d1 - d2) / L;
29031 } else {
29032 split = 0.5 * d1 / L;
29033 }
29034 for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]);
29035 if (b->verbose > 1) {
29036 printf(" Found by rule-3:");
29037 }
29038 r3count++;
29039 } else {
29040 if (b->verbose > 1) {
29041 printf(" Found by rule-2:");
29042 }
29043 r2count++;
29044 }
29045 if (b->verbose > 1) {
29046 printf(" center %d, split = %.12g.\n", pointmark(ei), split);
29047 }
29048 // Add a random perturbation on newpt.
29049 d1 = distance(ei, newpt);
29050 d2 = distance(newpt, refpt);
29051 ps = randgenerator(d2 * b->epsilon2 * 1e+2);
29052 rs = ps / d1;
29053 // Perturb newpt away from ei.
29054 for (i = 0; i < 3; i++) newpt[i] = ei[i] + (1.0+rs) * (newpt[i] - ei[i]);
29055 } else {
29056 // Both endpoints are acute or not. Split it at the middle.
29057 for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
29058 // Add a random perturbation on newpt.
29059 d1 = 0.5 * distance(e1, e2);
29060 ps = randgenerator(d1 * b->epsilon2 * 1e+2);
29061 rs = ps / d1;
29062 for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]);
29063 }
29064 } else {
29065 // Split the segment at its midpoint.
29066 for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
29067 // Add a random perturbation on newpt.
29068 d1 = 0.5 * distance(e1, e2);
29069 ps = randgenerator(d1 * b->epsilon2 * 1e+2);
29070 rs = ps / d1;
29071 for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]);
29072 }
29073}
29074
29076// //
29077// shepardinterpolation() Interpolate the local size of a newpoint. //
29078// //
29079// The classical Shepard interoplation (inversed weighted distance) is used. //
29080// (With the choice p = 2). //
29081// //
29082// 'verlist' contains a list vertices neighboring to 'newpt'. //
29083// //
29085
29086void tetgenmesh::shepardinterpolate(point newpt, list *verlist)
29087{
29088 point neipt;
29089 REAL *weights, sumweight;
29090 REAL vec[3];
29091 int i, j;
29092
29093 weights = new REAL[verlist->len()];
29094 sumweight = 0.0;
29095
29096 // Calculate the weight of each point.
29097 for (i = 0; i < verlist->len(); i++) {
29098 neipt = * (point *)(* verlist)[i];
29099 for (j = 0; j < 3; j++) vec[j] = neipt[j] - newpt[j];
29100 weights[i] = 1.0 / dot(vec, vec);
29101 sumweight += weights[i];
29102 }
29103 // Interpolate.
29104 newpt[pointmtrindex] = 0.0;
29105 for (i = 0; i < verlist->len(); i++) {
29106 neipt = * (point *)(* verlist)[i];
29107 newpt[pointmtrindex] += (weights[i] * neipt[pointmtrindex]) / sumweight;
29108 }
29109
29110 delete [] weights;
29111}
29112
29114// //
29115// setnewpointsize() Set the size for a new point. //
29116// //
29117// The size of the new point p is interpolated either from a background mesh //
29118// (b->bgmesh) or from the two input endpoints. //
29119// //
29121
29122void tetgenmesh::setnewpointsize(point newpt, point e1, point e2)
29123{
29124 if (b->metric) {
29125 // Interpolate the point size in a background mesh.
29126 triface bgmtet;
29127 // Get a tet in background mesh for locating p.
29128 decode(point2bgmtet(e1), bgmtet);
29129 p1interpolatebgm(newpt, &bgmtet, NULL);
29130 } else {
29131 if (e2 != (point) NULL) {
29132 // Interpolate the size between the two endpoints.
29133 REAL split, l, d;
29134 l = distance(e1, e2);
29135 d = distance(e1, newpt);
29136 split = d / l;
29137#ifdef SELF_CHECK
29138 // Check if e1 and e2 are endpoints of a sharp segment.
29139 assert(e1[pointmtrindex] > 0.0);
29140 assert(e2[pointmtrindex] > 0.0);
29141#endif
29142 newpt[pointmtrindex] = (1.0 - split) * e1[pointmtrindex]
29143 + split * e2[pointmtrindex];
29144 }
29145 }
29146}
29147
29149// //
29150// splitencseg() Split an enc-seg and recover the Delaunayness by flips. //
29151// //
29153
29154void tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist,
29155 list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet,
29156 bool optflag)
29157{
29158 list *mytetlist;
29159 queue *myflipque;
29160 triface starttet;
29161 face startsh, spinsh, checksh;
29162 int i;
29163
29164 mytetlist = NULL;
29165 myflipque = NULL;
29166
29167 if (optflag) {
29168 mytetlist = new list(sizeof(triface), NULL, 1024);
29169 myflipque = new queue(sizeof(badface));
29170 tetlist = mytetlist;
29171 flipque = myflipque;
29172 }
29173
29174 // Use the base orientation (important in this routine).
29175 splitseg->shver = 0;
29176 // Insert p, this should always success.
29177 sstpivot(splitseg, &starttet);
29178 splittetedge(newpt, &starttet, flipque);
29179 // Remove locally non-Delaunay faces by flipping.
29180 flip(flipque, NULL); // lawson(NULL, flipque);
29181
29182 if (!optflag) {
29183 // Check the two new subsegs to see if they're encroached (not by p).
29184 for (i = 0; i < 2; i++) {
29185 if (!shell2badface(*splitseg)) {
29186 checkseg4encroach(splitseg, NULL, NULL, true);
29187 }
29188 if (i == 1) break; // Two new segs have been checked.
29189 senextself(*splitseg);
29190 spivotself(*splitseg);
29191#ifdef SELF_CHECK
29192 assert(splitseg->sh != (shellface *) NULL);
29193#endif
29194 splitseg->shver = 0;
29195 }
29196 // Check the new subfaces to see if they're encroached (not by p).
29197 if (chkencsub) {
29198 spivot(*splitseg, startsh);
29199 spinsh = startsh;
29200 do {
29201 sublist->append(&spinsh);
29202 formstarpolygon(newpt, sublist, verlist);
29203 for (i = 0; i < sublist->len(); i++) {
29204 checksh = * (face *)(* sublist)[i];
29205 if (!shell2badface(checksh)) {
29206 checksub4encroach(&checksh, NULL, true);
29207 }
29208 }
29209 sublist->clear();
29210 if (verlist) verlist->clear();
29211 spivotself(spinsh);
29212 } while (spinsh.sh != startsh.sh);
29213 }
29214 } // if (!optflag)
29215
29216 // Collect the new tets connecting at p.
29217 sstpivot(splitseg, &starttet);
29218 tetlist->append(&starttet);
29219 formstarpolyhedron(newpt, tetlist, verlist, true);
29220
29221 if (!optflag) {
29222 // Check if p encroaches adjacent segments.
29223 tallencsegs(newpt, 1, &tetlist);
29224 if (chkencsub) {
29225 // Check if p encroaches adjacent subfaces.
29226 tallencsubs(newpt, 1, &tetlist);
29227 }
29228 if (chkbadtet) {
29229 // Check if there are new bad quality tets at p.
29230 for (i = 0; i < tetlist->len(); i++) {
29231 starttet = * (triface *)(* tetlist)[i];
29232 checktet4badqual(&starttet, true);
29233 }
29234 }
29235 tetlist->clear();
29236 } else {
29237 // Check if new tets are non-optimal.
29238 for (i = 0; i < tetlist->len(); i++) {
29239 starttet = * (triface *)(* tetlist)[i];
29240 checktet4opt(&starttet, true);
29241 }
29242 delete mytetlist;
29243 delete myflipque;
29244 }
29245}
29246
29248// //
29249// tallencsegs() Check for encroached segments and save them in list. //
29250// //
29251// If 'testpt' (p) != NULL, only check if segments are encroached by p, else,//
29252// check all the nearby mesh vertices. //
29253// //
29254// If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the //
29255// segments which are on B_i(p)s, else, check the entire list of segments //
29256// (in the pool 'this->subsegs'). //
29257// //
29259
29260bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists)
29261{
29262 list *ceillist;
29263 triface ceiltet;
29264 face checkseg;
29265 long oldencnum;
29266 int i, j, k;
29267
29268 // Remember the current number of encroached segments.
29269 oldencnum = badsubsegs->items;
29270
29271 if (ceillists != (list **) NULL) {
29272 for (k = 0; k < n; k++) {
29273 ceillist = ceillists[k];
29274 // Check the segments on B_i(p).
29275 for (i = 0; i < ceillist->len(); i++) {
29276 ceiltet = * (triface *)(* ceillist)[i];
29277 ceiltet.ver = 0;
29278 for (j = 0; j < 3; j++) {
29279 tsspivot(&ceiltet, &checkseg);
29280 if (checkseg.sh != dummysh) {
29281 // Found a segment. Test it if it isn't in enc-list.
29282 if (!shell2badface(checkseg)) {
29283 checkseg4encroach(&checkseg, testpt, NULL, true);
29284 }
29285 }
29286 enextself(ceiltet);
29287 }
29288 }
29289 }
29290 } else {
29291 // Check the entire list of segments.
29292 subsegs->traversalinit();
29293 checkseg.sh = shellfacetraverse(subsegs);
29294 while (checkseg.sh != (shellface *) NULL) {
29295 // Test it if it isn't in enc-list.
29296 if (!shell2badface(checkseg)) {
29297 checkseg4encroach(&checkseg, testpt, NULL, true);
29298 }
29299 checkseg.sh = shellfacetraverse(subsegs);
29300 }
29301 }
29302
29303 return (badsubsegs->items > oldencnum);
29304}
29305
29307// //
29308// tallencsubs() Find all encroached subfaces and save them in list. //
29309// //
29310// If 'testpt' (p) != NULL, only check if subfaces are encroached by p, else,//
29311// check the adjacent vertices of subfaces. //
29312// //
29313// If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the //
29314// subfaces which are on B_i(p)s, else, check the entire list of subfaces //
29315// (in the pool 'this->subfaces'). //
29316// //
29318
29319bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists)
29320{
29321 list *ceillist;
29322 triface ceiltet;
29323 face checksh;
29324 long oldencnum;
29325 int i, k;
29326
29327 // Remember the current number of encroached segments.
29328 oldencnum = badsubfaces->items;
29329
29330 if (ceillists != (list **) NULL) {
29331 for (k = 0; k < n; k++) {
29332 ceillist = ceillists[k];
29333 // Check the subfaces on B_i(p).
29334 for (i = 0; i < ceillist->len(); i++) {
29335 ceiltet = * (triface *)(* ceillist)[i];
29336 tspivot(ceiltet, checksh);
29337 if (checksh.sh != dummysh) {
29338 // Found a subface. Test it if it isn't in enc-list.
29339 if (!shell2badface(checksh)) {
29340 checksub4encroach(&checksh, testpt, true);
29341 }
29342 }
29343 }
29344 }
29345 } else {
29346 // Check the entire list of subfaces.
29347 subfaces->traversalinit();
29348 checksh.sh = shellfacetraverse(subfaces);
29349 while (checksh.sh != (shellface *) NULL) {
29350 // Test it if it isn't in enc-list.
29351 if (!shell2badface(checksh)) {
29352 checksub4encroach(&checksh, testpt, true);
29353 }
29354 checksh.sh = shellfacetraverse(subfaces);
29355 }
29356 }
29357
29358 return (badsubfaces->items > oldencnum);
29359}
29360
29362// //
29363// tallbadtetrahedrons() Queue all the bad-quality tetrahedra in the mesh.//
29364// //
29366
29367void tetgenmesh::tallbadtetrahedrons()
29368{
29369 triface tetloop;
29370
29371 tetrahedrons->traversalinit();
29372 tetloop.tet = tetrahedrontraverse();
29373 while (tetloop.tet != (tetrahedron *) NULL) {
29374 checktet4badqual(&tetloop, true);
29375 tetloop.tet = tetrahedrontraverse();
29376 }
29377}
29378
29380// //
29381// repairencsegs() Repair (split) all the encroached segments. //
29382// //
29383// Each encroached segment is repaired by splitting it - inserting a vertex //
29384// at or near its midpoint. Newly inserted vertices may encroach upon other //
29385// subsegments, these are also repaired. //
29386// //
29387// 'chkencsub' and 'chkbadtet' are two flags that specify whether one should //
29388// take note of new encroaced subfaces and bad quality tets that result from //
29389// inserting vertices to repair encroached subsegments. //
29390// //
29392
29393void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
29394{
29395 list **tetlists, **ceillists;
29396 list **sublists, **subceillists;
29397 list *tetlist, *sublist;
29398 queue *flipque;
29399 badface *encloop;
29400 face splitseg, symsplitseg;
29401 point newpt, sympt, refpt;
29402 point e1, e2;
29403 enum locateresult symloc;
29404 int nmax, n, i, j;
29405
29406 ceillists = NULL;
29407 flipque = NULL;
29408 subceillists = NULL;
29409 sublist = NULL;
29410 sublists = NULL;
29411 tetlist = NULL;
29412 tetlists = NULL;
29413
29414 n = 0;
29415 nmax = 128;
29416 if (!b->fliprepair) {
29417 tetlists = new list*[nmax];
29418 ceillists = new list*[nmax];
29419 sublists = new list*[nmax];
29420 subceillists = new list*[nmax];
29421 } else {
29422 tetlist = new list(sizeof(triface), NULL, 1024);
29423 sublist = new list(sizeof(face), NULL, 256);
29424 flipque = new queue(sizeof(badface));
29425 }
29426
29427 // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
29428 // if an unlimited number of Steiner points is allowed.
29429 while ((badsubsegs->items > 0) && (steinerleft != 0)) {
29430 badsubsegs->traversalinit();
29431 encloop = badfacetraverse(badsubsegs);
29432 while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
29433 // Get an encroached subsegment s.
29434 splitseg = encloop->ss;
29435 // Clear the in-queue flag in s.
29436 setshell2badface(splitseg, NULL);
29437 if ((sorg(splitseg) == encloop->forg) &&
29438 (sdest(splitseg) == encloop->fdest)) {
29439 if (b->verbose > 1) {
29440 printf(" Get an enc-seg (%d, %d)\n", pointmark(encloop->forg),
29441 pointmark(encloop->fdest));
29442 }
29443 refpt = (point) NULL;
29444 if (b->conformdel) {
29445 // Look for a reference point.
29446 checkseg4encroach(&splitseg, NULL, &refpt, false);
29447 }
29448 // Create the new point p (at the middle of s).
29449 makepoint(&newpt);
29450 getsplitpoint(encloop->forg, encloop->fdest, refpt, newpt);
29451 setpointtype(newpt, FREESEGVERTEX);
29452 setpoint2sh(newpt, sencode(splitseg));
29453 // Decide whether p can be inserted or not.
29454 if (acceptsegpt(newpt, refpt, &splitseg)) {
29455 // Is there periodic boundary condition?
29456 if (checkpbcs) {
29457 // Insert points on other segments of incident pbcgroups.
29458 i = shellmark(splitseg) - 1;
29459 for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
29460 makepoint(&sympt);
29461 symloc = getsegpbcsympoint(newpt, &splitseg, sympt, &symsplitseg,
29462 segpglist[j]);
29463 if (symloc == ONEDGE) {
29464 if (symsplitseg.sh != splitseg.sh) {
29465 // Insert sympt.
29466 setpointtype(sympt, FREESEGVERTEX);
29467 setpoint2sh(sympt, sencode(symsplitseg));
29468 // Save the endpoints of the seg for size interpolation.
29469 e1 = sorg(symsplitseg);
29470 if (shelltype(symsplitseg) == SHARP) {
29471 e2 = sdest(symsplitseg);
29472 } else {
29473 e2 = (point) NULL; // No need to do size interpolation.
29474 }
29475 if (!b->fliprepair) {
29476 // Form BC(symp), B(symp), CBC(symp)s, C(symp)s.
29477 formbowatcavity(sympt, &symsplitseg, NULL, &n, &nmax,
29478 sublists, subceillists, tetlists, ceillists);
29479 // Validate BC(symp), B(symp), CBC(symp)s, C(symp)s.
29480 if (trimbowatcavity(sympt, &symsplitseg, n, sublists,
29481 subceillists, tetlists, ceillists, -1.0)) {
29482 bowatinsertsite(sympt, &symsplitseg, n, sublists,
29483 subceillists, tetlists, ceillists, NULL, flipque,
29484 true, chkencsub, chkbadtet);
29485 setnewpointsize(sympt, e1, e2);
29486 if (steinerleft > 0) steinerleft--;
29487 } else {
29488 // p did not insert for invalid BC(symp).
29489 pointdealloc(sympt);
29490 }
29491 // Free the memory allocated in formbowatcavity().
29492 releasebowatcavity(&symsplitseg, n, sublists, subceillists,
29493 tetlists, ceillists);
29494 } else {
29495 splitencseg(sympt, &symsplitseg, tetlist, sublist, NULL,
29496 flipque, chkencsub, chkbadtet, false);
29497 setnewpointsize(sympt, e1, e2);
29498 if (steinerleft > 0) steinerleft--;
29499 }
29500 } else {
29501 // The sympt are on the same segment. It is possible when
29502 // splitseg is the symmetric rotating axes.
29503 pointdealloc(sympt);
29504 }
29505 } else if (symloc == ONVERTEX) {
29506 // The sympt already exists. It is possible when two pbc
29507 // groups are exactly the same. Omit this point.
29508 pointdealloc(sympt);
29509 } else {
29510 // Do not isnert symp for unknown cases: ONFACE, OUTSIDE.
29511 // assert(0);
29512 pointdealloc(sympt);
29513 }
29514 } // for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++)
29515 } // if (checkpbcs)
29516 // Save the endpoints of the seg for size interpolation.
29517 e1 = sorg(splitseg);
29518 if (shelltype(splitseg) == SHARP) {
29519 e2 = sdest(splitseg);
29520 } else {
29521 e2 = (point) NULL; // No need to do size interoplation.
29522 }
29523 if (!b->fliprepair) {
29524 // Form BC(p), B(p), CBC(p)s, and C(p)s.
29525 formbowatcavity(newpt, &splitseg, NULL, &n, &nmax, sublists,
29526 subceillists, tetlists, ceillists);
29527 // Validate/update BC(p), B(p), CBC(p)s, and C(p)s.
29528 if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists,
29529 tetlists, ceillists, -1.0)) {
29530 bowatinsertsite(newpt, &splitseg, n, sublists, subceillists,
29531 tetlists, ceillists, NULL, flipque, true,
29532 chkencsub, chkbadtet);
29533 setnewpointsize(newpt, e1, e2);
29534 if (steinerleft > 0) steinerleft--;
29535 } else {
29536 // p did not insert for invalid B(p).
29537 pointdealloc(newpt);
29538 }
29539 // Free the memory allocated in formbowatcavity().
29540 releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists,
29541 ceillists);
29542 } else {
29543 splitencseg(newpt, &splitseg, tetlist, sublist, NULL, flipque,
29544 chkencsub, chkbadtet, false);
29545 setnewpointsize(newpt, e1, e2);
29546 if (steinerleft > 0) steinerleft--;
29547 }
29548 } else {
29549 // p did not accept for insertion.
29550 pointdealloc(newpt);
29551 } // if (checkseg4splitting(newpt, &splitseg))
29552 } // if ((encloop->forg == pa) && (encloop->fdest == pb))
29553 badfacedealloc(badsubsegs, encloop); // Remove this entry from list.
29554 encloop = badfacetraverse(badsubsegs); // Get the next enc-segment.
29555 } // while ((encloop != (badface *) NULL) && (steinerleft != 0))
29556 } // while ((badsubsegs->items > 0) && (steinerleft != 0))
29557
29558 if (!b->fliprepair) {
29559 delete [] tetlists;
29560 delete [] ceillists;
29561 delete [] sublists;
29562 delete [] subceillists;
29563 } else {
29564 delete tetlist;
29565 delete sublist;
29566 delete flipque;
29567 }
29568}
29569
29571// //
29572// repairencsubs() Repair (split) all the encroached subfaces. //
29573// //
29574// Each encroached subface is repaired by splitting it - inserting a vertex //
29575// at or near its circumcenter. Newly inserted vertices may encroach upon //
29576// other subfaces, these are also repaired. //
29577// //
29578// 'chkbadtet' is a flag that specifies whether one should take note of new //
29579// bad quality tets that result from inserted vertices. //
29580// //
29582
29583void tetgenmesh::repairencsubs(bool chkbadtet)
29584{
29585 list *tetlists[2], *ceillists[2];
29586 list *sublist, *subceillist;
29587 list *verlist;
29588 badface *encloop;
29589 face splitsub, symsplitsub;
29590 point newpt, sympt, e1;
29591 enum locateresult loc, symloc;
29592 bool reject;
29593 long oldptnum;
29594 int quenumber, n, i;
29595
29596 quenumber = 0;
29597 n = 0;
29598 sublist = (list *) NULL;
29599 subceillist = (list *) NULL;
29600 verlist = new list(sizeof(point *), NULL, 256);
29601
29602 // Loop until the pool 'badsubfaces' is empty. Note that steinerleft == -1
29603 // if an unlimited number of Steiner points is allowed.
29604 while ((badsubfaces->items > 0) && (steinerleft != 0)) {
29605 // Get an encroached subface f.
29606 encloop = dequeueencsub(&quenumber);
29607 splitsub = encloop->ss;
29608 // Clear the in-queue flag of f.
29609 setshell2badface(splitsub, NULL);
29610 // f may not be the same one when it was determined to be encroached.
29611 if (!isdead(&splitsub)
29612 && (sorg(splitsub) == encloop->forg)
29613 && (sdest(splitsub) == encloop->fdest)
29614 && (sapex(splitsub) == encloop->fapex)) {
29615 if (b->verbose > 1) {
29616 printf(" Dequeuing ensub (%d, %d, %d) [%d].\n",
29617 pointmark(encloop->forg), pointmark(encloop->fdest),
29618 pointmark(encloop->fapex), quenumber);
29619 }
29620 // Create a new point p at the circumcenter of f.
29621 makepoint(&newpt);
29622 for (i = 0; i < 3; i++) newpt[i] = encloop->cent[i];
29623 setpointtype(newpt, FREESUBVERTEX);
29624 setpoint2sh(newpt, sencode(splitsub));
29625 // Set the abovepoint of f for point location.
29626 abovepoint = facetabovepointarray[shellmark(splitsub)];
29627 if (abovepoint == (point) NULL) {
29628 getfacetabovepoint(&splitsub);
29629 }
29630 // Locate p, start from f, stop at segment (1), use a tolerance to
29631 // detect ONVERTEX or OUTSIDE case. Update f on return.
29632 loc = locatesub(newpt, &splitsub, 1, b->epsilon * 1e+2);
29633 if ((loc != ONVERTEX) && (loc != OUTSIDE)) {
29634 // Form BC(p), B(p), CBC(p) and C(p).
29635 formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
29636 &subceillist, tetlists, ceillists);
29637 // Check for encroached subsegments (on B(p)).
29638 reject = tallencsegs(newpt, 2, ceillists);
29639 // Execute point accept rule if p does not encroach upon any segment.
29640 if (!reject) {
29641 reject = !acceptfacpt(newpt, subceillist, verlist);
29642 }
29643 if (!reject) {
29644 // Validate/update cavity.
29645 reject = !trimbowatcavity(newpt, NULL, n, &sublist, &subceillist,
29646 tetlists, ceillists, -1.0);
29647 }
29648 if (!reject) {
29649 // CBC(p) should include s, so that s can be removed after CBC(p)
29650 // is remeshed. However, if there are locally non-Delaunay faces
29651 // and encroached subsegments, s may not be collected in CBC(p).
29652 // p should not be inserted in such case.
29653 reject = !sinfected(encloop->ss);
29654 }
29655 if (!reject) {
29656 if (checkpbcs) {
29657 if (shellpbcgroup(splitsub) >= 0) {
29658 // Check for splitting of the symmetric subface of f.
29659 makepoint(&sympt);
29660 symloc = getsubpbcsympoint(newpt,&splitsub,sympt,&symsplitsub);
29661 if (symloc != ONVERTEX) {
29662 // Release CBC(p) and BC(p) and free the memory..
29663 releasebowatcavity(NULL, 2, &sublist, &subceillist, tetlists,
29664 ceillists);
29665 // Form CBC(symp), C(symp), BC(sympt) and B(sympt).
29666 formbowatcavity(sympt, NULL, &symsplitsub, &n, NULL, &sublist,
29667 &subceillist, tetlists, ceillists);
29668 reject = tallencsegs(sympt, 2, ceillists);
29669 if (!reject) {
29670 reject = !acceptfacpt(sympt, subceillist, verlist);
29671 }
29672 if (!reject) {
29673 reject = !trimbowatcavity(sympt,NULL,n,&sublist,&subceillist,
29674 tetlists, ceillists, -1.0);
29675 }
29676 if (!reject) {
29677 // Insert sympt.
29678 setpoint2pbcpt(newpt, sympt);
29679 setpoint2pbcpt(sympt, newpt);
29680 setpointtype(sympt, FREESUBVERTEX);
29681 setpoint2sh(sympt, sencode(symsplitsub));
29682 // Save a point for size interpolation.
29683 e1 = sorg(symsplitsub);
29684 bowatinsertsite(sympt, NULL, n, &sublist, &subceillist,
29685 tetlists,ceillists,NULL,NULL,false,true,chkbadtet);
29686 setnewpointsize(sympt, e1, NULL);
29687 if (steinerleft > 0) steinerleft--;
29688 // Release CBC(symp) and BC(symp) and free the memory..
29689 releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists,
29690 ceillists);
29691 } else {
29692 // symp is rejected for one of the following reasons:
29693 // (1) BC(symp) is not valid; or
29694 // (2) symp encroaches upon some subsegments (queued); or
29695 // (3) symp is rejected by point accepting rule.
29696 pointdealloc(sympt);
29697 // Cavity will be released by the following code.
29698 }
29699 } else {
29700 // Do not insert sympt for invalid PBC data.
29701 pointdealloc(sympt);
29702 // p is rejected due to symp.
29703 reject = true;
29704 }
29705 }
29706 } // if (checkpbcs)
29707 }
29708 if (!reject) {
29709 // Insert p.
29710 if (checkpbcs) {
29711 if (shellpbcgroup(splitsub) >= 0) {
29712 // Form CBC(p), C(p), BC(p) and B(p).
29713 formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
29714 &subceillist, tetlists, ceillists);
29715 trimbowatcavity(newpt, NULL, n, &sublist, &subceillist, tetlists,
29716 ceillists, -1.0);
29717 }
29718 }
29719 // Save a point for size interpolation.
29720 e1 = sorg(splitsub);
29721 bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists,
29722 ceillists, NULL, NULL, true, true, chkbadtet);
29723 setnewpointsize(newpt, e1, NULL);
29724 if (steinerleft > 0) steinerleft--;
29725 } else {
29726 // p is rejected for the one of the following reasons:
29727 // (1) BC(p) is not valid.
29728 // (2) s does not in CBC(p).
29729 // (3) p encroaches upon some segments (queued); or
29730 // (4) p is rejected by point accepting rule, or
29731 // (5) due to the rejection of symp (the PBC).
29732 pointdealloc(newpt);
29733 } // if (!reject)
29734 // Release the cavity and free the memory.
29735 releasebowatcavity(NULL,n,&sublist,&subceillist,tetlists,ceillists);
29736 if (reject) {
29737 // Are there queued encroached subsegments.
29738 if (badsubsegs->items > 0) {
29739 // Repair enc-subsegments.
29740 oldptnum = points->items;
29741 repairencsegs(true, chkbadtet);
29742 if (points->items > oldptnum) {
29743 // Some enc-subsegments got split. Try to repair f later.
29744 splitsub = encloop->ss;
29745 if (!isdead(&splitsub)) {
29746 if (!shell2badface(splitsub)) {
29747 checksub4encroach(&splitsub, NULL, true);
29748 }
29749 }
29750 }
29751 }
29752 }
29753 } else {
29754 // Don't insert p for one of the following reasons:
29755 // (1) Locate on an existing vertex; or
29756 // (2) locate outside the domain.
29757 // Case (1) should not be possible. If such vertex v exists, it is
29758 // the circumcenter of f, ie., f is non-Delaunay. Either f was got
29759 // split before by v, but survived after v was inserted, or the
29760 // same for a f' which is nearly co-circular with f. Whatsoever,
29761 // there are encroached segs by v, but the routine tallencsegs()
29762 // did not find them out.
29763 if (loc == ONVERTEX) {
29764 printf("Internal error in repairencsubs():\n");
29765 printf(" During repairing encroached subface (%d, %d, %d)\n",
29766 pointmark(encloop->forg), pointmark(encloop->fdest),
29767 pointmark(encloop->fapex));
29768 printf(" New point %d is coincident with an existing vertex %d\n",
29769 pointmark(newpt), pointmark(sorg(splitsub)));
29770 internalerror();
29771 }
29772 // Case (2) can happen when thers is a segment s which is close to f
29773 // and is non-conforming Delaunay. The circumcenter of f encroaches
29774 // upon s, but the circumcenter of s is rejected for insertion.
29775 pointdealloc(newpt);
29776 } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
29777 } else {
29778 if (!isdead(&splitsub)) {
29779 // The subface has been changed, re-check it.
29780 checksub4encroach(&splitsub, NULL, true);
29781 }
29782 } // if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) &&
29783 // Remove this entry from list.
29784 badfacedealloc(badsubfaces, encloop);
29785 } // while ((badsubfaces->items > 0) && (steinerleft != 0))
29786
29787 delete verlist;
29788}
29789
29791// //
29792// repairbadtets() Repair all bad-quality tetrahedra. //
29793// //
29794// All bad-quality tets are stored in pool 'badtetrahedrons'. Each bad tet //
29795// is repaired by inserting a point at or near its circumcenter. However, if //
29796// this point encroaches any subsegment or subface, it is not inserted. Ins- //
29797// tead the encroached segment and subface are split. Newly inserted points //
29798// may create other bad-quality tets, these are also repaired. //
29799// //
29801
29802void tetgenmesh::repairbadtets()
29803{
29804 list *tetlist, *ceillist;
29805 list *verlist;
29806 badface *badtet;
29807 triface starttet;
29808 point newpt, e1;
29809 enum locateresult loc;
29810 bool reject;
29811 long oldptnum;
29812 int i;
29813
29814 tetlist = new list(sizeof(triface), NULL, 1024);
29815 ceillist = new list(sizeof(triface), NULL, 1024);
29816 verlist = new list(sizeof(point *), NULL, 256);
29817
29818 // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1
29819 // if an unlimited number of Steiner points is allowed.
29820 while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
29821 // Get a bad-quality tet t.
29822 badtet = topbadtetra();
29823 // Make sure that the tet is still the same one when it was tested.
29824 // Subsequent transformations may have made it a different tet.
29825 if ((badtet != (badface *) NULL) && !isdead(&badtet->tt)
29826 && org(badtet->tt) == badtet->forg
29827 && dest(badtet->tt) == badtet->fdest
29828 && apex(badtet->tt) == badtet->fapex
29829 && oppo(badtet->tt) == badtet->foppo) {
29830 if (b->verbose > 1) {
29831 printf(" Dequeuing btet (%d, %d, %d, %d).\n",
29832 pointmark(badtet->forg), pointmark(badtet->fdest),
29833 pointmark(badtet->fapex), pointmark(badtet->foppo));
29834 }
29835 // Create the new point p (at the circumcenter of t).
29836 makepoint(&newpt);
29837 for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i];
29838 setpointtype(newpt, FREEVOLVERTEX);
29839 // Locate p.
29840 starttet = badtet->tt;
29841 loc = preciselocate(newpt, &starttet, tetrahedrons->items);
29842 if ((loc != ONVERTEX) && (loc != OUTSIDE)) {
29843 // For BC(p) and B(p).
29844 infect(starttet);
29845 tetlist->append(&starttet);
29846 formbowatcavityquad(newpt, tetlist, ceillist);
29847 // Check for encroached subsegments.
29848 reject = tallencsegs(newpt, 1, &ceillist);
29849 if (!reject) {
29850 // Check for encroached subfaces.
29851 reject = tallencsubs(newpt, 1, &ceillist);
29852 }
29853 // Execute point accepting rule if p does not encroach upon any
29854 // subsegment and subface.
29855 if (!reject) {
29856 reject = !acceptvolpt(newpt, ceillist, verlist);
29857 }
29858 if (!reject) {
29859 reject = !trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist,
29860 &ceillist, -1.0);
29861 }
29862 if (!reject) {
29863 // BC(p) should include t, so that t can be removed after BC(p) is
29864 // remeshed. However, if there are locally non-Delaunay faces
29865 // and encroached subsegments/subfaces, t may not be collected
29866 // in BC(p). p should not be inserted in such case.
29867 reject = !infected(badtet->tt);
29868 if (reject) outbowatcircumcount++;
29869 }
29870 if (!reject) {
29871 // Save a point for size interpolation.
29872 e1 = org(starttet);
29873 // Insert p.
29874 bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist,
29875 NULL, NULL, false, false, true);
29876 setnewpointsize(newpt, e1, NULL);
29877 if (steinerleft > 0) steinerleft--;
29878 } else {
29879 // p is rejected for one of the following reasons:
29880 // (1) BC(p) is not valid.
29881 // (2) t does not in BC(p).
29882 // (3) p encroaches upon some segments;
29883 // (4) p encroaches upon some subfaces;
29884 // (5) p is rejected by the point accepting rule.
29885 pointdealloc(newpt);
29886 // Uninfect tets of BC(p).
29887 for (i = 0; i < tetlist->len(); i++) {
29888 starttet = * (triface *)(* tetlist)[i];
29889 uninfect(starttet);
29890 }
29891 }
29892 tetlist->clear();
29893 ceillist->clear();
29894 // Split encroached subsegments/subfaces if there are.
29895 if (reject) {
29896 oldptnum = points->items;
29897 if (badsubsegs->items > 0) {
29898 repairencsegs(true, true);
29899 }
29900 if (badsubfaces->items > 0) {
29901 repairencsubs(true);
29902 }
29903 if (points->items > oldptnum) {
29904 // Some encroaching subsegments/subfaces got split. Re-queue the
29905 // tet if it is still alive.
29906 starttet = badtet->tt;
29907 if (!isdead(&starttet)) {
29908 checktet4badqual(&starttet, true);
29909 }
29910 }
29911 }
29912 } else {
29913 // Do not insert p. The reason may be one of:
29914 // (1) p is coincident (ONVERTEX) with an existing vertex; or
29915 // (2) p is outside (OUTSIDE) the mesh.
29916 // Case (1) should not be possible. If such vertex v exists, it is
29917 // the circumcenter of t, ie., t is non-Delaunay. Either t was got
29918 // split before by v, but survived after v was inserted, or the
29919 // same for a t' which is nearly co-spherical with t. Whatsoever,
29920 // there are encroached segments or subfaces by v but the routines
29921 // tallencsegs() or tallencsubs() did not find them out.
29922 if (loc == ONVERTEX) {
29923 printf("Internal error in repairbadtets():\n");
29924 printf(" During repairing bad tet (%d, %d, %d, %d)\n",
29925 pointmark(badtet->forg), pointmark(badtet->fdest),
29926 pointmark(badtet->fapex), pointmark(badtet->foppo));
29927 printf(" New point %d is coincident with an existing vertex %d\n",
29928 pointmark(newpt), pointmark(org(starttet)));
29929 internalerror();
29930 }
29931 // Case (2) can happen when there is a segment s (or subface f) which
29932 // is close to f and is non-conforming Delaunay. The circumcenter
29933 // of t encroaches upon s (or f), but the circumcenter of s (or f)
29934 // is rejected for insertion.
29935 pointdealloc(newpt);
29936 } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
29937 } // if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg &&
29938 // Remove the tet from the queue.
29939 dequeuebadtet();
29940 } // while ((badtetrahedrons->items > 0) && (steinerleft != 0))
29941
29942 delete tetlist;
29943 delete ceillist;
29944 delete verlist;
29945}
29946
29948// //
29949// enforcequality() Refine the mesh. //
29950// //
29952
29953void tetgenmesh::enforcequality()
29954{
29955 long total, vertcount;
29956 int i;
29957
29958 if (!b->quiet) {
29959 printf("Adding Steiner points to enforce quality.\n");
29960 }
29961
29962 total = vertcount = 0l;
29963 if (b->conformdel) {
29964 r2count = r3count = 0l;
29965 }
29966
29967 // If both '-D' and '-r' options are used.
29968 if (b->conformdel && b->refine) {
29969 markacutevertices(65.0);
29970 }
29971 // If '-m' is not used.
29972 if (!b->metric) {
29973 // Find and mark all sharp segments.
29974 marksharpsegments(65.0);
29975 // Decide the sizes for feature points.
29976 decidefeaturepointsizes();
29977 }
29978
29979 // Initialize the pool of encroached subsegments.
29980 badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
29981 // Looking for encroached subsegments.
29982 tallencsegs(NULL, 0, NULL);
29983 if (b->verbose && badsubsegs->items > 0) {
29984 printf(" Splitting encroached subsegments.\n");
29985 }
29986 vertcount = points->items;
29987 // Fix encroached segments without noting any enc subfaces.
29988 repairencsegs(false, false);
29989 if (b->verbose > 0) {
29990 printf(" %ld split points.\n", points->items - vertcount);
29991 }
29992 total += points->items - vertcount;
29993
29994 // Initialize the pool of encroached subfaces.
29995 badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
29996 // Initialize the priority queues of badfaces.
29997 for (i = 0; i < 3; i++) subquefront[i] = (badface *) NULL;
29998 for (i = 0; i < 3; i++) subquetail[i] = &subquefront[i];
29999 // Looking for encroached subfaces.
30000 tallencsubs(NULL, 0, NULL);
30001 if (b->verbose && badsubfaces->items > 0) {
30002 printf(" Splitting encroached subfaces.\n");
30003 }
30004 vertcount = points->items;
30005 // Fix encroached subfaces without noting bad tetrahedra.
30006 repairencsubs(false);
30007 if (b->verbose > 0) {
30008 printf(" %ld split points.\n", points->items - vertcount);
30009 }
30010 total += points->items - vertcount;
30011 // At this point, the mesh should be conforming Delaunay if no input
30012 // angle is smaller than 90 degree.
30013
30014 // Next, fix bad quality tetrahedra.
30015 if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) {
30016 // Initialize the pool of bad tets
30017 badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
30018 // Initialize the priority queues of bad tets.
30019 for (i = 0; i < 64; i++) tetquefront[i] = (badface *) NULL;
30020 firstnonemptyq = -1;
30021 recentq = -1;
30022 // Looking for bad quality tets.
30023 cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
30024 cosmindihed = cos(b->mindihedral * PI / 180.0);
30025 tallbadtetrahedrons();
30026 if (b->verbose && badtetrahedrons->items > 0) {
30027 printf(" Splitting bad tetrahedra.\n");
30028 }
30029 vertcount = points->items;
30030 repairbadtets();
30031 if (b->verbose > 0) {
30032 printf(" %ld refinement points.\n", points->items - vertcount);
30033 }
30034 total += points->items - vertcount;
30035 delete badtetrahedrons;
30036 }
30037
30038 if (b->verbose > 0) {
30039 printf(" Totally added %ld points.\n", total);
30040 }
30041
30042 delete badsubfaces;
30043 delete badsubsegs;
30044}
30045
30046//
30047// End of Delaunay refinement routines
30048//
30049
30050//
30051// Begin of mesh optimization routines
30052//
30053
30054void tetgenmesh::dumpbadtets()
30055{
30056 FILE *fout;
30057 badface *remtet;
30058
30059 // Write out a file of remaining bad tets.
30060 printf(" Writing bad tets to file bad-dump.lua.\n");
30061 fout = fopen("bad-dump.lua", "w");
30062 fprintf(fout, "-- %ld remaining bad tets (> %g degree).\n",
30063 badtetrahedrons->items, b->maxdihedral);
30064 badtetrahedrons->traversalinit();
30065 remtet = badfacetraverse(badtetrahedrons);
30066 while (remtet != (badface *) NULL) {
30067 if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
30068 dest(remtet->tt) == remtet->fdest &&
30069 apex(remtet->tt) == remtet->fapex &&
30070 oppo(remtet->tt) == remtet->foppo) {
30071 fprintf(fout, "p:draw_tet(%d, %d, %d, %d) -- %g\n",
30072 pointmark(remtet->forg), pointmark(remtet->fdest),
30073 pointmark(remtet->fapex), pointmark(remtet->foppo),
30074 acos(remtet->key) * 180.0 / PI);
30075 }
30076 remtet = badfacetraverse(badtetrahedrons);
30077 }
30078 fclose(fout);
30079}
30080
30082// //
30083// checktet4ill() Check a tet to see if it is illegal. //
30084// //
30085// A tet is "illegal" if it spans on one input facet. Save the tet in queue //
30086// if it is illegal and the flag 'enqflag' is set. //
30087// //
30088// Note: Such case can happen when the input facet has non-coplanar vertices //
30089// and the Delaunay tetrahedralization of the vertices may creat such tets. //
30090// //
30092
30093bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag)
30094{
30095 badface *newbadtet;
30096 triface checktet;
30097 face checksh1, checksh2;
30098 face checkseg;
30099 bool illflag;
30100 int i;
30101
30102 illflag = false;
30103 for (testtet->loc = 0; testtet->loc < 4; testtet->loc++) {
30104 tspivot(*testtet, checksh1);
30105 if (checksh1.sh != dummysh) {
30106 testtet->ver = 0;
30107 findedge(&checksh1, org(*testtet), dest(*testtet));
30108 for (i = 0; i < 3; i++) {
30109 fnext(*testtet, checktet);
30110 tspivot(checktet, checksh2);
30111 if (checksh2.sh != dummysh) {
30112 // Two subfaces share this edge.
30113 sspivot(checksh1, checkseg);
30114 if (checkseg.sh == dummysh) {
30115 // The four corners of the tet are on one facet. Illegal! Try to
30116 // flip the opposite edge of the current one.
30117 enextfnextself(*testtet);
30118 enextself(*testtet);
30119 illflag = true;
30120 break;
30121 }
30122 }
30123 enextself(*testtet);
30124 senextself(checksh1);
30125 }
30126 }
30127 if (illflag) break;
30128 }
30129
30130 if (illflag && enqflag) {
30131 // Allocate space for the bad tetrahedron.
30132 newbadtet = (badface *) badtetrahedrons->alloc();
30133 newbadtet->tt = *testtet;
30134 newbadtet->key = -1.0; // = 180 degree.
30135 for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
30136 newbadtet->forg = org(*testtet);
30137 newbadtet->fdest = dest(*testtet);
30138 newbadtet->fapex = apex(*testtet);
30139 newbadtet->foppo = oppo(*testtet);
30140 newbadtet->nextitem = (badface *) NULL;
30141 if (b->verbose > 2) {
30142 printf(" Queueing illtet: (%d, %d, %d, %d).\n",
30143 pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
30144 pointmark(newbadtet->fapex), pointmark(newbadtet->foppo));
30145 }
30146 }
30147
30148 return illflag;
30149}
30150
30152// //
30153// checktet4opt() Check a tet to see if it needs to be optimized. //
30154// //
30155// A tet t needs to be optimized if it fails to certain quality measures. //
30156// The only quality measure currently used is the maximal dihedral angle at //
30157// edges. The desired maximal dihedral angle is b->maxdihed (set by the '-s' //
30158// option. //
30159// //
30160// A tet may have one, two, or three big dihedral angles. Examples: Let the //
30161// tet t = abcd, and its four corners are nearly co-planar. Then t has one //
30162// big dihedral angle if d is very close to the edge ab; t has three big //
30163// dihedral angles if d's projection on the face abc is also inside abc, i.e.//
30164// the shape of t likes a hat; finally, t has two big dihedral angles if d's //
30165// projection onto abc is outside abc. //
30166// //
30168
30169bool tetgenmesh::checktet4opt(triface* testtet, bool enqflag)
30170{
30171 badface *newbadtet;
30172 point pa, pb, pc, pd;
30173 REAL N[4][3], len;
30174 REAL cosd;
30175 bool enq;
30176 int i, j;
30177
30178 cosd = 0.0;
30179 enq = false;
30180 pa = (point) testtet->tet[4];
30181 pb = (point) testtet->tet[5];
30182 pc = (point) testtet->tet[6];
30183 pd = (point) testtet->tet[7];
30184 // Compute the 4 face normals: N[0] cbd, N[1] acd, N[2] bad, N[3] abc.
30185 tetallnormal(pa, pb, pc, pd, N, NULL);
30186 // Normalize the normals.
30187 for (i = 0; i < 4; i++) {
30188 len = sqrt(dot(N[i], N[i]));
30189 if (len != 0.0) {
30190 for (j = 0; j < 3; j++) N[i][j] /= len;
30191 }
30192 }
30193 // Find all large dihedral angles.
30194 for (i = 0; i < 6; i++) {
30195 // Locate the edge i and calculate the dihedral angle at the edge.
30196 testtet->loc = 0;
30197 testtet->ver = 0;
30198 switch (i) {
30199 case 0: // edge ab
30200 cosd = -dot(N[2], N[3]);
30201 break;
30202 case 1: // edge cd
30203 enextfnextself(*testtet);
30204 enextself(*testtet);
30205 cosd = -dot(N[0], N[1]);
30206 break;
30207 case 2: // edge bd
30208 enextfnextself(*testtet);
30209 enext2self(*testtet);
30210 cosd = -dot(N[0], N[2]);
30211 break;
30212 case 3: // edge bc
30213 enextself(*testtet);
30214 cosd = -dot(N[0], N[3]);
30215 break;
30216 case 4: // edge ad
30217 enext2fnextself(*testtet);
30218 enextself(*testtet);
30219 cosd = -dot(N[1], N[2]);
30220 break;
30221 case 5: // edge ac
30222 enext2self(*testtet);
30223 cosd = -dot(N[1], N[3]);
30224 break;
30225 }
30226 if (cosd < cosmaxdihed) {
30227 // A bigger dihedral angle.
30228 if (enqflag) {
30229 // Allocate space for the bad tetrahedron.
30230 newbadtet = (badface *) badtetrahedrons->alloc();
30231 newbadtet->tt = *testtet;
30232 newbadtet->key = cosd;
30233 for (j = 0; j < 3; j++) newbadtet->cent[j] = 0.0;
30234 newbadtet->forg = org(*testtet);
30235 newbadtet->fdest = dest(*testtet);
30236 newbadtet->fapex = apex(*testtet);
30237 newbadtet->foppo = oppo(*testtet);
30238 newbadtet->nextitem = (badface *) NULL;
30239 if (b->verbose > 2) {
30240 printf(" Queueing tet: (%d, %d, %d, %d), dihed %g (degree).\n",
30241 pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
30242 pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
30243 acos(cosd) * 180.0 / PI);
30244 }
30245 }
30246 enq = true;
30247 }
30248 }
30249
30250 return enq;
30251}
30252
30254// //
30255// removeedge() Remove an edge //
30256// //
30257// 'remedge' is a tet (abcd) having the edge ab wanted to be removed. Local //
30258// reconnecting operations are used to remove edge ab. The following opera- //
30259// tion will be tryed. //
30260// //
30261// If ab is on the hull, and abc and abd are both hull faces. Then ab can be //
30262// removed by stripping abcd from the mesh. However, if ab is a segemnt, do //
30263// the operation only if 'b->optlevel' > 1 and 'b->nobisect == 0'. //
30264// //
30265// If ab is an internal edge, there are n tets contains it. Then ab can be //
30266// removed if there exists another m tets which can replace the n tets with- //
30267// out changing the boundary of the n tets. //
30268// //
30269// If 'optflag' is set. The value 'remedge->key' means cos(theta), where //
30270// 'theta' is the maximal dishedral angle at ab. In this case, even if the //
30271// n-to-m flip exists, it will not be performed if the maximum dihedral of //
30272// the new tets is larger than 'theta'. //
30273// //
30275
30276bool tetgenmesh::removeedge(badface* remedge, bool optflag)
30277{
30278 triface abcd, badc; // Tet configuration at edge ab.
30279 triface baccasing, abdcasing;
30280 triface abtetlist[11]; // Old configuration at ab, save maximum 10 tets.
30281 triface bftetlist[11]; // Old configuration at bf, save maximum 10 tets.
30282 triface newtetlist[33]; // New configuration after removing ab.
30283 face checksh;
30284 enum fliptype fty;
30285 REAL key;
30286 bool remflag, subflag;
30287 int n, n1, m, i, j;
30288
30289 // First try to strip abcd from the mesh. This needs to check either ab
30290 // or cd is on the hull. Try to strip it whichever is true.
30291 abcd = remedge->tt;
30292 adjustedgering(abcd, CCW);
30293 i = 0;
30294 do {
30295 sym(abcd, baccasing);
30296 // Is the tet on the hull?
30297 if (baccasing.tet == dummytet) {
30298 fnext(abcd, badc);
30299 sym(badc, abdcasing);
30300 if (abdcasing.tet == dummytet) {
30301 // Strip the tet from the mesh -> ab is removed as well.
30302 if (removetetbypeeloff(&abcd)) {
30303 if (b->verbose > 1) {
30304 printf(" Stripped tet from the mesh.\n");
30305 }
30306 optcount[0]++;
30307 return true;
30308 }
30309 }
30310 }
30311 // Check if the oppsite edge cd is on the hull.
30312 enext2fnextself(abcd);
30313 enext2self(abcd);
30314 esymself(abcd); // --> cdab
30315 i++;
30316 } while (i < 2);
30317
30318 // Get the tets configuration at ab. Collect maximum 10 tets.
30319 subflag = false;
30320 abcd = remedge->tt;
30321 adjustedgering(abcd, CW);
30322 n = 0;
30323 abtetlist[n] = abcd;
30324 do {
30325 // Is the list full?
30326 if (n == 10) break;
30327 // Stop if a subface appears.
30328 tspivot(abtetlist[n], checksh);
30329 if (checksh.sh != dummysh) {
30330 // ab is either a segment or a facet edge. The latter case is not
30331 // handled yet! An edge flip is needed.
30332 subflag = true; break; // return false;
30333 }
30334 // Get the next tet at ab.
30335 fnext(abtetlist[n], abtetlist[n + 1]);
30336 n++;
30337 } while (apex(abtetlist[n]) != apex(abcd));
30338
30339 remflag = false;
30340 key = remedge->key;
30341
30342 if (subflag && optflag) {
30343 abcd = remedge->tt;
30344 adjustedgering(abcd, CCW);
30345 // Try to flip face cda or cdb to improve quality.
30346 for (j = 0; j < 2; j++) {
30347 if (j == 0) {
30348 enext2fnext(abcd, abtetlist[0]); // Goto cda.
30349 } else {
30350 enextfnext(abcd, abtetlist[0]); // Goto cdb.
30351 }
30352 fty = categorizeface(abtetlist[0]);
30353 if (fty == T23) {
30354 // A 2-to-3 flip is possible.
30355 sym(abtetlist[0], abtetlist[1]);
30356 assert(abtetlist[1].tet != dummytet);
30357 n = 2;
30358 m = 3;
30359 remflag = removefacebyflip23(&key, abtetlist, newtetlist, NULL);
30360 } else if (fty == T22) {
30361 // A 2-to-2 or 4-to-4 flip is possible.
30362 n = 2;
30363 newtetlist[0] = abtetlist[0];
30364 adjustedgering(newtetlist[0], CW);
30365 fnext(newtetlist[0], newtetlist[1]);
30366 assert(newtetlist[1].tet != dummytet);
30367 // May it is 4-to-4 flip.
30368 if (fnext(newtetlist[1], newtetlist[2])) {
30369 fnext(newtetlist[2], newtetlist[3]);
30370 assert(newtetlist[3].tet != dummytet);
30371 n = 4;
30372 }
30373 m = n;
30374 remflag = removeedgebyflip22(&key, n, newtetlist, NULL);
30375 }
30376 // Has quality been improved?
30377 if (remflag) {
30378 if (b->verbose > 1) {
30379 printf(" Done flip %d-to-%d. Qual: %g -> %g.\n", n, m,
30380 acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0);
30381 }
30382 // Delete the old tets. Note, flip22() does not create new tets.
30383 if (m == 3) {
30384 for (i = 0; i < n; i++) {
30385 tetrahedrondealloc(abtetlist[i].tet);
30386 }
30387 }
30388 for (i = 0; i < m; i++) {
30389 checktet4opt(&(newtetlist[i]), true);
30390 }
30391 optcount[1]++;
30392 return true;
30393 }
30394 } // if (j = 0; j < 2; j++)
30395 // Faces are not flipable. Return.
30396 return false;
30397 }
30398
30399 // 2 <= n <= 10.
30400 if (n == 3) {
30401 // There are three tets at ab. Try to do a flip32 at ab.
30402 remflag = removeedgebyflip32(&key, abtetlist, newtetlist, NULL);
30403 } else if ((n == 4) || (n == 5) || (n == 6)) {
30404 // Four tets case. Try to do edge transformation.
30405 remflag = removeedgebytranNM(&key,n,abtetlist,newtetlist,NULL,NULL,NULL);
30406 } else {
30407 if (b->verbose > 1) {
30408 printf(" !! Unhandled case: n = %d.\n", n);
30409 }
30410 }
30411 if (remflag) {
30412 optcount[n]++;
30413 // Delete the old tets.
30414 for (i = 0; i < n; i++) {
30415 tetrahedrondealloc(abtetlist[i].tet);
30416 }
30417 m = (n - 2) * 2; // The numebr of new tets.
30418 if (b->verbose > 1) {
30419 printf(" Done flip %d-to-%d. ", n, m);
30420 if (optflag) {
30421 printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0,
30422 acos(key) / PI * 180.0);
30423 }
30424 printf("\n");
30425 }
30426 }
30427
30428 if (!remflag && (key == remedge->key) && (n < 7)) {
30429 // Try to do a combination of flips.
30430 n1 = 0;
30431 remflag = removeedgebycombNM(&key, n, abtetlist, &n1, bftetlist,
30432 newtetlist, NULL);
30433 if (remflag) {
30434 optcount[9]++;
30435 // Delete the old tets.
30436 for (i = 0; i < n; i++) {
30437 tetrahedrondealloc(abtetlist[i].tet);
30438 }
30439 for (i = 0; i < n1; i++) {
30440 if (!isdead(&(bftetlist[i]))) {
30441 tetrahedrondealloc(bftetlist[i].tet);
30442 }
30443 }
30444 m = ((n1 - 2) * 2 - 1) + (n - 3) * 2; // The number of new tets.
30445 if (b->verbose > 1) {
30446 printf(" Done flip %d-to-%d (n-1=%d, n1=%d). ", n+n1-2, m, n-1,n1);
30447 if (optflag) {
30448 printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0,
30449 acos(key) / PI * 180.0);
30450 }
30451 printf("\n");
30452 }
30453 }
30454 }
30455
30456 if (remflag) {
30457 // edge is removed. Test new tets for further optimization.
30458 for (i = 0; i < m; i++) {
30459 if (optflag) {
30460 checktet4opt(&(newtetlist[i]), true);
30461 } else {
30462 checktet4ill(&(newtetlist[i]), true);
30463 }
30464 }
30465 }
30466
30467 return remflag;
30468}
30469
30471// //
30472// smoothsliver() Remove a sliver by smoothing a vertex of it. //
30473// //
30474// The 'slivtet' represents a sliver abcd, and ab is the current edge which //
30475// has a large dihedral angle (close to 180 degree). //
30476// //
30478
30479bool tetgenmesh::smoothsliver(badface* remedge, list *starlist)
30480{
30481 triface checktet;
30482 point smthpt;
30483 bool smthed;
30484 int idx, i, j;
30485
30486 // Find a Steiner volume point and smooth it.
30487 smthed = false;
30488 for (i = 0; i < 4 && !smthed; i++) {
30489 smthpt = (point) remedge->tt.tet[4 + i];
30490 // Is it a volume point?
30491 if (pointtype(smthpt) == FREEVOLVERTEX) {
30492 // Is it a Steiner point?
30493 idx = pointmark(smthpt) - in->firstnumber;
30494 if (!(idx < in->numberofpoints)) {
30495 // Smooth a Steiner volume point.
30496 starlist->append(&(remedge->tt.tet));
30497 formstarpolyhedron(smthpt, starlist, NULL, false);
30498 smthed = smoothpoint(smthpt,NULL,NULL,starlist,false,&remedge->key);
30499 // If it is smoothed. Queue new bad tets.
30500 if (smthed) {
30501 for (j = 0; j < starlist->len(); j++) {
30502 checktet = * (triface *)(* starlist)[j];
30503 checktet4opt(&checktet, true);
30504 }
30505 }
30506 starlist->clear();
30507 }
30508 }
30509 }
30510
30511 /* Omit to smooth segment points. This may cause infinite loop.
30512 if (smthed) {
30513 return true;
30514 }
30515 face abseg, nextseg, prevseg;
30516 point pt[2];
30517 // Check if ab is a segment.
30518 tsspivot(slivtet, &abseg);
30519 if (abseg.sh == dummysh) {
30520 // ab is not a segment. Check if a or b is a Steiner segment point.
30521 for (i = 0; i < 2 && !smthed; i++) {
30522 smthpt = (i == 0 ? org(*slivtet) : dest(*slivtet));
30523 if (pointtype(smthpt) == FREESEGVERTEX) {
30524 // Is it a Steiner point?
30525 idx = pointmark(smthpt) - in->firstnumber;
30526 if (!(idx < in->numberofpoints)) {
30527 // Smooth a Steiner segment point. Get the segment.
30528 sdecode(point2sh(smthpt), nextseg);
30529 locateseg(smthpt, &nextseg);
30530 assert(sorg(nextseg) == smthpt);
30531 pt[0] = sdest(nextseg);
30532 senext2(nextseg, prevseg);
30533 spivotself(prevseg);
30534 prevseg.shver = 0;
30535 if (sorg(prevseg) == smthpt) sesymself(prevseg);
30536 assert(sdest(prevseg) == smthpt);
30537 pt[1] = sorg(prevseg);
30538 starlist->append(slivtet);
30539 formstarpolyhedron(smthpt, starlist, NULL, true);
30540 smthed = smoothpoint(smthpt, pt[0], pt[1], starlist, false);
30541 // If it is smoothed. Check if the tet is still a sliver.
30542 if (smthed) checktet4opt(slivtet, true);
30543 starlist->clear();
30544 }
30545 }
30546 }
30547 }
30548 */
30549
30550 return smthed;
30551}
30552
30554// //
30555// splitsliver() Remove a sliver by inserting a point. //
30556// //
30557// The 'remedge->tt' represents a sliver abcd, ab is the current edge which //
30558// has a large dihedral angle (close to 180 degree). //
30559// //
30561
30562bool tetgenmesh::splitsliver(badface *remedge, list *tetlist, list *ceillist)
30563{
30564 triface starttet;
30565 face checkseg;
30566 point newpt, pt[4];
30567 bool remflag;
30568 int i;
30569
30570 starttet = remedge->tt;
30571
30572 // Check if cd is a segment.
30573 adjustedgering(starttet, CCW);
30574 enextfnextself(starttet);
30575 enextself(starttet);
30576 tsspivot(&starttet, &checkseg);
30577 if (b->nobisect == 0) {
30578 if (checkseg.sh != dummysh) {
30579 // cd is a segment. The seg will be split. BUT do not flip! Due to the
30580 // exact predicates, lot of slivers ay be rsulted and hard to remove.
30581 checkseg.shver = 0;
30582 pt[0] = sorg(checkseg);
30583 pt[1] = sdest(checkseg);
30584 makepoint(&newpt);
30585 getsplitpoint(pt[0], pt[1], NULL, newpt);
30586 setpointtype(newpt, FREESEGVERTEX);
30587 setpoint2sh(newpt, sencode(checkseg));
30588 // Insert p, this should always success.
30589 sstpivot(&checkseg, &starttet);
30590 splittetedge(newpt, &starttet, NULL);
30591 // Collect the new tets connecting at p.
30592 sstpivot(&checkseg, &starttet);
30593 ceillist->append(&starttet);
30594 formstarpolyhedron(newpt, ceillist, NULL, true);
30595 setnewpointsize(newpt, pt[0], NULL);
30596 if (steinerleft > 0) steinerleft--;
30597 // Smooth p.
30598 smoothpoint(newpt, pt[0], pt[1], ceillist, false, NULL);
30599 // Queue new slivers.
30600 for (i = 0; i < ceillist->len(); i++) {
30601 starttet = * (triface *)(* ceillist)[i];
30602 checktet4opt(&starttet, true);
30603 }
30604 ceillist->clear();
30605 return true;
30606 }
30607 }
30608
30609 // Get the four corners.
30610 for (i = 0; i < 4; i++) {
30611 pt[i] = (point) starttet.tet[4 + i];
30612 }
30613 // Create the new point p (at the circumcenter of t).
30614 makepoint(&newpt);
30615 for (i = 0; i < 3; i++) {
30616 newpt[i] = 0.25 * (pt[0][i] + pt[1][i] + pt[2][i] + pt[3][i]);
30617 }
30618 setpointtype(newpt, FREEVOLVERTEX);
30619
30620 // Form the Bowyer-Watson cavity of p.
30621 remflag = false;
30622 infect(starttet);
30623 tetlist->append(&starttet);
30624 formbowatcavityquad(newpt, tetlist, ceillist);
30625 if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, -1.0)) {
30626 // Smooth p.
30627 if (smoothpoint( newpt, NULL, NULL, ceillist, false, &remedge->key)) {
30628 // Insert p.
30629 bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, NULL,
30630 NULL, false, false, false);
30631 setnewpointsize(newpt, pt[0], NULL);
30632 if (steinerleft > 0) steinerleft--;
30633 // Queue new slivers.
30634 for (i = 0; i < ceillist->len(); i++) {
30635 starttet = * (triface *)(* ceillist)[i];
30636 checktet4opt(&starttet, true);
30637 }
30638 remflag = true;
30639 } // if (smoothpoint)
30640 } // if (trimbowatcavity)
30641
30642 if (!remflag) {
30643 // p is rejected for BC(p) is not valid.
30644 pointdealloc(newpt);
30645 // Uninfect tets of BC(p).
30646 for (i = 0; i < tetlist->len(); i++) {
30647 starttet = * (triface *)(* tetlist)[i];
30648 uninfect(starttet);
30649 }
30650 }
30651 tetlist->clear();
30652 ceillist->clear();
30653
30654 return remflag;
30655}
30656
30658// //
30659// tallslivers() Queue all the slivers in the mesh. //
30660// //
30662
30663void tetgenmesh::tallslivers(bool optflag)
30664{
30665 triface tetloop;
30666
30667 tetrahedrons->traversalinit();
30668 tetloop.tet = tetrahedrontraverse();
30669 while (tetloop.tet != (tetrahedron *) NULL) {
30670 if (optflag) {
30671 checktet4opt(&tetloop, true);
30672 } else {
30673 checktet4ill(&tetloop, true);
30674 }
30675 tetloop.tet = tetrahedrontraverse();
30676 }
30677}
30678
30680// //
30681// optimizemesh() Improve mesh quality by mesh optimizations. //
30682// //
30683// Available mesh optimizing operations are: (1) multiple edge flips (3-to-2,//
30684// 4-to-4, 5-to-6, etc), (2) free vertex deletion, (3) new vertex insertion. //
30685// (1) is mandatory, while (2) and (3) are optionally. //
30686// //
30687// The variable 'b->optlevel' (set after '-s') determines the use of these //
30688// operations. If it is: 0, do no optimization; 1, only do (1) operation; 2, //
30689// do (1) and (2) operations; 3, do all operations. Deault, b->optlvel = 2. //
30690// //
30692
30693void tetgenmesh::optimizemesh(bool optflag)
30694{
30695 list *splittetlist, *tetlist, *ceillist;
30696 badface *remtet, *lastentry;
30697 //REAL maxdihed, objdihed, curdihed; // maxdihead commented out to get gcc 4.6 working
30698 REAL objdihed, curdihed;
30699 long oldnum;
30700 int iter, i;
30701
30702 objdihed = 0.0;
30703
30704 if (!b->quiet) {
30705 if (optflag) {
30706 printf("Optimizing mesh.\n");
30707 } else {
30708 printf("Repairing mesh.\n");
30709 }
30710 }
30711
30712#ifdef SELF_CHECK
30713 if (optflag && (b->verbose)) {
30714 printf(" level = %d.\n", b->optlevel);
30715 }
30716#endif
30717
30718 // Initialize the pool of bad tets.
30719 badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
30720 if (optflag) {
30721 cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
30722 cosmindihed = cos(b->mindihedral * PI / 180.0);
30723 // The radian of the maximum dihedral angle.
30724 //maxdihed = b->maxdihedral / 180.0 * PI; // maxdihead commented out to get gcc 4.6 working
30725 // A sliver has an angle large than 'objdihed' will be split.
30726 objdihed = b->maxdihedral + 5.0;
30727 if (objdihed < 170.0) objdihed = 170.0;
30728 objdihed = objdihed / 180.0 * PI;
30729 }
30730 // Looking for non-optimal tets.
30731 tallslivers(optflag);
30732
30733 optcount[0] = 0l; // tet strip count.
30734 optcount[1] = 0l; // face (2-3) and edge (2-2) flip count.
30735 optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips.
30736 optcount[9] = 0l; // combined flip count.
30737
30738 // Perform edge flip to improve quality.
30739 lastentry = (badface *) NULL;
30740 // Loop until pool 'badtetrahedrons' is empty.
30741 while (badtetrahedrons->items > 0) {
30742 badtetrahedrons->traversalinit();
30743 remtet = badfacetraverse(badtetrahedrons);
30744 while (remtet != (badface *) NULL) {
30745 // Make sure that the tet is still the same one when it was tested.
30746 // Subsequent transformations may have made it a different tet.
30747 if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
30748 dest(remtet->tt) == remtet->fdest &&
30749 apex(remtet->tt) == remtet->fapex &&
30750 oppo(remtet->tt) == remtet->foppo) {
30751 if (b->verbose > 1) {
30752 printf(" Repair tet (%d, %d, %d, %d) %g (degree).\n",
30753 pointmark(remtet->forg), pointmark(remtet->fdest),
30754 pointmark(remtet->fapex), pointmark(remtet->foppo),
30755 acos(remtet->key) / PI * 180.0);
30756 }
30757 if (!removeedge(remtet, optflag)) {
30758 // An unremoveable tet. Check if it forms a loop.
30759 if (lastentry != (badface *) NULL) {
30760 if (remtet == lastentry) break;
30761 } else {
30762 // Remember this tet as a breakpoint.
30763 lastentry = remtet;
30764 }
30765 } else {
30766 // Clear the breakpoint.
30767 lastentry = (badface *) NULL;
30768 // Remove the entry from the queue.
30769 badfacedealloc(badtetrahedrons, remtet);
30770 }
30771 } else {
30772 // Remove the entry from the queue.
30773 badfacedealloc(badtetrahedrons, remtet);
30774 }
30775 remtet = badfacetraverse(badtetrahedrons);
30776 }
30777 // Stop if the above loop was out by force.
30778 if (remtet != (badface *) NULL) break;
30779 }
30780
30781 if (b->verbose) {
30782 if (optcount[0] > 0l) {
30783 printf(" %ld tets are peeled off.\n", optcount[0]);
30784 }
30785 if (optcount[1] > 0l) {
30786 printf(" %ld faces are flipped.\n", optcount[1]);
30787 }
30788 if (optcount[3] + optcount[4] + optcount[5] + optcount[6] +
30789 optcount[9] > 0l) {
30790 printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] +
30791 optcount[5] + optcount[6] + optcount[9]);
30792 }
30793 // if (badtetrahedrons->items > 0l) {
30794 // printf(" %ld edges remain.\n", badtetrahedrons->items);
30795 // }
30796 }
30797
30798 if ((badtetrahedrons->items > 0l) && optflag && (b->optlevel > 2)) {
30799 splittetlist = new list(sizeof(badface), NULL, 256);
30800 tetlist = new list(sizeof(triface), NULL, 256);
30801 ceillist = new list(sizeof(triface), NULL, 256);
30802 oldnum = points->items;
30803 smoothsegverts = smoothvolverts = 0;
30804 optcount[1] = 0l;
30805 optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips.
30806 optcount[9] = 0l; // combined flip count.
30807 iter = 0;
30808
30809 do {
30810 // Form a list of slivers to be split and clean the pool.
30811 badtetrahedrons->traversalinit();
30812 remtet = badfacetraverse(badtetrahedrons);
30813 while (remtet != (badface *) NULL) {
30814 splittetlist->append(remtet);
30815 // Remove the entry from the queue.
30816 badfacedealloc(badtetrahedrons, remtet);
30817 remtet = badfacetraverse(badtetrahedrons);
30818 }
30819 for (i = 0; i < splittetlist->len(); i++) {
30820 remtet = (badface *)(* splittetlist)[i];
30821 // Make sure that the tet is still the same one when it was tested.
30822 // Subsequent transformations may have made it a different tet.
30823 if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
30824 dest(remtet->tt) == remtet->fdest &&
30825 apex(remtet->tt) == remtet->fapex &&
30826 oppo(remtet->tt) == remtet->foppo) {
30827 // The sliver may get smoothed due to a neighboring tet.
30828 curdihed = facedihedral(remtet->forg, remtet->fdest, remtet->fapex,
30829 remtet->foppo);
30830 // The dihedral angle of a tet must less than PI, correct it.
30831 if (curdihed > PI) curdihed = 2 * PI - curdihed;
30832 // Is it a large angle?
30833 if (curdihed > objdihed) {
30834 remtet->key = cos(curdihed);
30835 if (b->verbose > 1) {
30836 printf(" Get sliver (%d, %d, %d, %d) %g (degree).\n",
30837 pointmark(remtet->forg), pointmark(remtet->fdest),
30838 pointmark(remtet->fapex), pointmark(remtet->foppo),
30839 acos(remtet->key) / PI * 180.0);
30840 }
30841 if (!removeedge(remtet, optflag)) {
30842 if (!smoothsliver(remtet, tetlist)) {
30843 splitsliver(remtet, tetlist, ceillist);
30844 }
30845 }
30846 }
30847 }
30848 }
30849 iter++;
30850 } while ((badtetrahedrons->items > 0l) && (iter < b->optpasses));
30851
30852 if (b->verbose) {
30853 printf(" %d passes.\n", iter);
30854 if ((points->items - oldnum) > 0l) {
30855 printf(" %ld points are inserted (%d on segment).\n",
30856 points->items - oldnum, smoothsegverts);
30857 }
30858 if (optcount[1] > 0l) {
30859 printf(" %ld faces are flipped.\n", optcount[1]);
30860 }
30861 if (optcount[3] + optcount[4] + optcount[5] + optcount[6] +
30862 optcount[9] > 0l) {
30863 printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] +
30864 optcount[5] + optcount[6] + optcount[9]);
30865 }
30866 // if (badtetrahedrons->items > 0l) {
30867 // printf(" %ld edges remain.\n", badtetrahedrons->items);
30868 // }
30869 }
30870 delete tetlist;
30871 delete ceillist;
30872 delete splittetlist;
30873 }
30874
30875 delete badtetrahedrons;
30876 badtetrahedrons = (memorypool *) NULL;
30877}
30878
30879//
30880// End of mesh optimization routines
30881//
30882
30883//
30884// Begin of I/O rouitnes
30885//
30886
30888// //
30889// transfernodes() Transfer nodes from 'io->pointlist' to 'this->points'. //
30890// //
30891// Initializing 'this->points'. Transferring all points from 'in->pointlist'//
30892// into it. All points are indexed (start from in->firstnumber). Each point //
30893// is initialized be UNUSEDVERTEX. The bounding box (xmin, xmax, ymin, ymax,//
30894// zmin, zmax) and the diameter (longest) of the point set are calculated. //
30895// //
30897
30898void tetgenmesh::transfernodes()
30899{
30900 point pointloop;
30901 REAL x, y, z;
30902 int coordindex;
30903 int attribindex;
30904 int mtrindex;
30905 int i, j;
30906
30907 // Read the points.
30908 coordindex = 0;
30909 attribindex = 0;
30910 mtrindex = 0;
30911 for (i = 0; i < in->numberofpoints; i++) {
30912 makepoint(&pointloop);
30913 // Read the point coordinates.
30914 x = pointloop[0] = in->pointlist[coordindex++];
30915 y = pointloop[1] = in->pointlist[coordindex++];
30916 z = pointloop[2] = in->pointlist[coordindex++];
30917 // Read the point attributes.
30918 for (j = 0; j < in->numberofpointattributes; j++) {
30919 pointloop[3 + j] = in->pointattributelist[attribindex++];
30920 }
30921 // Read the point metric tensor.
30922 for (j = 0; j < in->numberofpointmtrs; j++) {
30923 pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
30924 }
30925 // Determine the smallest and largests x, y and z coordinates.
30926 if (i == 0) {
30927 xmin = xmax = x;
30928 ymin = ymax = y;
30929 zmin = zmax = z;
30930 } else {
30931 xmin = (x < xmin) ? x : xmin;
30932 xmax = (x > xmax) ? x : xmax;
30933 ymin = (y < ymin) ? y : ymin;
30934 ymax = (y > ymax) ? y : ymax;
30935 zmin = (z < zmin) ? z : zmin;
30936 zmax = (z > zmax) ? z : zmax;
30937 }
30938 }
30939 // 'longest' is the largest possible edge length formed by input vertices.
30940 x = xmax - xmin;
30941 y = ymax - ymin;
30942 z = zmax - zmin;
30943 longest = sqrt(x * x + y * y + z * z);
30944 if (longest == 0.0) {
30945 printf("Error: The point set is trivial.\n");
30946 terminatetetgen(1);
30947 }
30948 // Two identical points are distinguished by 'lengthlimit'.
30949 lengthlimit = longest * b->epsilon * 1e+2;
30950}
30951
30953// //
30954// jettisonnodes() Jettison unused or duplicated vertices. //
30955// //
30956// Unused points are those input points which are outside the mesh domain or //
30957// have no connection (isolated) to the mesh. Duplicated points exist for //
30958// example if the input PLC is read from a .stl mesh file (marked during the //
30959// Delaunay tetrahedralization step. This routine remove these points from //
30960// points list. All existing points are reindexed. //
30961// //
30963
30964void tetgenmesh::jettisonnodes()
30965{
30966 point pointloop;
30967 bool jetflag;
30968 int oldidx, newidx;
30969 int remcount;
30970
30971 if (!b->quiet) {
30972 printf("Jettisoning redundants points.\n");
30973 }
30974
30975 points->traversalinit();
30976 pointloop = pointtraverse();
30977 oldidx = newidx = 0; // in->firstnumber;
30978 remcount = 0;
30979 while (pointloop != (point) NULL) {
30980 jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
30981 (pointtype(pointloop) == UNUSEDVERTEX);
30982 if (jetflag) {
30983 // It is a duplicated point, delete it.
30984 pointdealloc(pointloop);
30985 remcount++;
30986 } else {
30987 // Re-index it.
30988 setpointmark(pointloop, newidx + in->firstnumber);
30989 if (in->pointmarkerlist != (int *) NULL) {
30990 if (oldidx < in->numberofpoints) {
30991 // Re-index the point marker as well.
30992 in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
30993 }
30994 }
30995 newidx++;
30996 }
30997 oldidx++;
30998 if (oldidx == in->numberofpoints) {
30999 // Update the numbe of input points (Because some were removed).
31000 in->numberofpoints -= remcount;
31001 // Remember this number for output original input nodes.
31002 jettisoninverts = remcount;
31003 }
31004 pointloop = pointtraverse();
31005 }
31006 if (b->verbose) {
31007 printf(" %d duplicated vertices have been removed.\n", dupverts);
31008 printf(" %d unused vertices have been removed.\n", unuverts);
31009 }
31010 dupverts = 0;
31011 unuverts = 0;
31012
31013 // The following line ensures that dead items in the pool of nodes cannot
31014 // be allocated for the new created nodes. This ensures that the input
31015 // nodes will occur earlier in the output files, and have lower indices.
31016 points->deaditemstack = (void *) NULL;
31017}
31018
31020// //
31021// highorder() Create extra nodes for quadratic subparametric elements. //
31022// //
31023// 'highordertable' is an array (size = numberoftetrahedra * 6) for storing //
31024// high-order nodes of each tetrahedron. This routine is used only when -o2 //
31025// switch is used. //
31026// //
31028
31029void tetgenmesh::highorder()
31030{
31031 triface tetloop, worktet;
31032 triface spintet, adjtet;
31033 point torg, tdest, tapex;
31034 point *extralist, *adjextralist;
31035 point newpoint;
31036 int hitbdry, ptmark;
31037 int i, j;
31038
31039 if (!b->quiet) {
31040 printf("Adding vertices for second-order tetrahedra.\n");
31041 }
31042
31043 // Initialize the 'highordertable'.
31044 highordertable = new point[tetrahedrons->items * 6];
31045 if (highordertable == (point *) NULL) {
31046 printf("Error: Out of memory.\n");
31047 terminatetetgen(1);
31048 }
31049
31050 // The following line ensures that dead items in the pool of nodes cannot
31051 // be allocated for the extra nodes associated with high order elements.
31052 // This ensures that the primary nodes (at the corners of elements) will
31053 // occur earlier in the output files, and have lower indices, than the
31054 // extra nodes.
31055 points->deaditemstack = (void *) NULL;
31056
31057 // Assign an entry for each tetrahedron to find its extra nodes. At the
31058 // mean while, initialize all extra nodes be NULL.
31059 i = 0;
31060 tetrahedrons->traversalinit();
31061 tetloop.tet = tetrahedrontraverse();
31062 while (tetloop.tet != (tetrahedron *) NULL) {
31063 tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
31064 for (j = 0; j < 6; j++) {
31065 highordertable[i + j] = (point) NULL;
31066 }
31067 i += 6;
31068 tetloop.tet = tetrahedrontraverse();
31069 }
31070
31071 // To create a unique node on each edge. Loop over all tetrahedra, and
31072 // look at the six edges of each tetrahedron. If the extra node in
31073 // the tetrahedron corresponding to this edge is NULL, create a node
31074 // for this edge, at the same time, set the new node into the extra
31075 // node lists of all other tetrahedra sharing this edge.
31076 tetrahedrons->traversalinit();
31077 tetloop.tet = tetrahedrontraverse();
31078 while (tetloop.tet != (tetrahedron *) NULL) {
31079 // Get the list of extra nodes.
31080 extralist = (point *) tetloop.tet[highorderindex];
31081 worktet.tet = tetloop.tet;
31082 for (i = 0; i < 6; i++) {
31083 if (extralist[i] == (point) NULL) {
31084 // Operate on this edge.
31085 worktet.loc = edge2locver[i][0];
31086 worktet.ver = edge2locver[i][1];
31087 // Create a new node on this edge.
31088 torg = org(worktet);
31089 tdest = dest(worktet);
31090 // Create a new node in the middle of the edge.
31091 newpoint = (point) points->alloc();
31092 // Interpolate its attributes.
31093 for (j = 0; j < 3 + in->numberofpointattributes; j++) {
31094 newpoint[j] = 0.5 * (torg[j] + tdest[j]);
31095 }
31096 ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
31097 setpointmark(newpoint, ptmark);
31098 // Add this node to its extra node list.
31099 extralist[i] = newpoint;
31100 // Set 'newpoint' into extra node lists of other tetrahedra
31101 // sharing this edge.
31102 tapex = apex(worktet);
31103 spintet = worktet;
31104 hitbdry = 0;
31105 while (hitbdry < 2) {
31106 if (fnextself(spintet)) {
31107 // Get the extra node list of 'spintet'.
31108 adjextralist = (point *) spintet.tet[highorderindex];
31109 // Find the index of its extra node list.
31110 j = locver2edge[spintet.loc][spintet.ver];
31111 // Only set 'newpoint' into 'adjextralist' if it is a NULL.
31112 // Because two faces can belong to the same tetrahedron.
31113 if (adjextralist[j] == (point) NULL) {
31114 adjextralist[j] = newpoint;
31115 }
31116 if (apex(spintet) == tapex) {
31117 break;
31118 }
31119 } else {
31120 hitbdry++;
31121 if (hitbdry < 2) {
31122 esym(worktet, spintet);
31123 }
31124 }
31125 }
31126 }
31127 }
31128 tetloop.tet = tetrahedrontraverse();
31129 }
31130}
31131
31133// //
31134// outnodes() Output the points to a .node file or a tetgenio structure. //
31135// //
31136// Note: each point has already been numbered on input (the first index is //
31137// 'in->firstnumber'). //
31138// //
31140
31141void tetgenmesh::outnodes(tetgenio* out)
31142{
31143 FILE *outfile;
31144 char outnodefilename[FILENAMESIZE];
31145 shellface subptr;
31146 triface adjtet;
31147 face subloop;
31148 point pointloop;
31149 point *extralist, ep[3];
31150 int nextras, bmark, shmark, marker;
31151 int coordindex, attribindex;
31152 int pointnumber, firstindex;
31153 int index, i;
31154
31155 if (out == (tetgenio *) NULL) {
31156 strcpy(outnodefilename, b->outfilename);
31157 strcat(outnodefilename, ".node");
31158 }
31159
31160 if (!b->quiet) {
31161 if (out == (tetgenio *) NULL) {
31162 printf("Writing %s.\n", outnodefilename);
31163 } else {
31164 printf("Writing nodes.\n");
31165 }
31166 }
31167
31168 nextras = in->numberofpointattributes;
31169 bmark = !b->nobound && in->pointmarkerlist;
31170
31171 // Avoid compile warnings.
31172 outfile = (FILE *) NULL;
31173 marker = coordindex = 0;
31174
31175 if (out == (tetgenio *) NULL) {
31176 outfile = fopen(outnodefilename, "w");
31177 if (outfile == (FILE *) NULL) {
31178 printf("File I/O Error: Cannot create file %s.\n", outnodefilename);
31179 terminatetetgen(1);
31180 }
31181 // Number of points, number of dimensions, number of point attributes,
31182 // and number of boundary markers (zero or one).
31183 fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark);
31184 } else {
31185 // Allocate space for 'pointlist';
31186 out->pointlist = new REAL[points->items * 3];
31187 if (out->pointlist == (REAL *) NULL) {
31188 printf("Error: Out of memory.\n");
31189 terminatetetgen(1);
31190 }
31191 // Allocate space for 'pointattributelist' if necessary;
31192 if (nextras > 0) {
31193 out->pointattributelist = new REAL[points->items * nextras];
31194 if (out->pointattributelist == (REAL *) NULL) {
31195 printf("Error: Out of memory.\n");
31196 terminatetetgen(1);
31197 }
31198 }
31199 // Allocate space for 'pointmarkerlist' if necessary;
31200 if (bmark) {
31201 out->pointmarkerlist = new int[points->items];
31202 if (out->pointmarkerlist == (int *) NULL) {
31203 printf("Error: Out of memory.\n");
31204 terminatetetgen(1);
31205 }
31206 }
31207 out->numberofpoints = points->items;
31208 out->numberofpointattributes = nextras;
31209 coordindex = 0;
31210 attribindex = 0;
31211 }
31212
31213 if (bmark && (b->plc || b->refine)) {
31214 // Initialize the point2tet field of each point.
31215 points->traversalinit();
31216 pointloop = pointtraverse();
31217 while (pointloop != (point) NULL) {
31218 setpoint2tet(pointloop, (tetrahedron) NULL);
31219 pointloop = pointtraverse();
31220 }
31221 // Make a map point-to-subface. Hence a boundary point will get the
31222 // facet marker from that facet where it lies on.
31223 subfaces->traversalinit();
31224 subloop.sh = shellfacetraverse(subfaces);
31225 while (subloop.sh != (shellface *) NULL) {
31226 subloop.shver = 0;
31227 // Check all three points of the subface.
31228 for (i = 0; i < 3; i++) {
31229 pointloop = (point) subloop.sh[3 + i];
31230 setpoint2tet(pointloop, (tetrahedron) sencode(subloop));
31231 }
31232 if (b->order == 2) {
31233 // '-o2' switch. Set markers for quadratic nodes of this subface.
31234 stpivot(subloop, adjtet);
31235 if (adjtet.tet == dummytet) {
31236 sesymself(subloop);
31237 stpivot(subloop, adjtet);
31238 }
31239 assert(adjtet.tet != dummytet);
31240 extralist = (point *) adjtet.tet[highorderindex];
31241 switch (adjtet.loc) {
31242 case 0:
31243 ep[0] = extralist[0];
31244 ep[1] = extralist[1];
31245 ep[2] = extralist[2];
31246 break;
31247 case 1:
31248 ep[0] = extralist[0];
31249 ep[1] = extralist[4];
31250 ep[2] = extralist[3];
31251 break;
31252 case 2:
31253 ep[0] = extralist[1];
31254 ep[1] = extralist[5];
31255 ep[2] = extralist[4];
31256 break;
31257 case 3:
31258 ep[0] = extralist[2];
31259 ep[1] = extralist[3];
31260 ep[2] = extralist[5];
31261 break;
31262 default: break;
31263 }
31264 for (i = 0; i < 3; i++) {
31265 setpoint2tet(ep[i], (tetrahedron) sencode(subloop));
31266 }
31267 }
31268 subloop.sh = shellfacetraverse(subfaces);
31269 }
31270 }
31271
31272 // Determine the first index (0 or 1).
31273 firstindex = b->zeroindex ? 0 : in->firstnumber;
31274
31275 points->traversalinit();
31276 pointloop = pointtraverse();
31277 pointnumber = firstindex; // in->firstnumber;
31278 index = 0;
31279 while (pointloop != (point) NULL) {
31280 if (bmark) {
31281 // Default the vertex has a zero marker.
31282 marker = 0;
31283 // Is it an input vertex?
31284 if (index < in->numberofpoints) {
31285 // Input point's marker is directly copied to output.
31286 marker = in->pointmarkerlist[index];
31287 }
31288 // Is it a boundary vertex has marker zero?
31289 if ((marker == 0) && (b->plc || b->refine)) {
31290 subptr = (shellface) point2tet(pointloop);
31291 if (subptr != (shellface) NULL) {
31292 // Default a boundary vertex has marker 1.
31293 marker = 1;
31294 if (in->facetmarkerlist != (int *) NULL) {
31295 // The vertex gets the marker from the facet it lies on.
31296 sdecode(subptr, subloop);
31297 shmark = shellmark(subloop);
31298 marker = in->facetmarkerlist[shmark - 1];
31299 }
31300 }
31301 }
31302 }
31303 if (out == (tetgenio *) NULL) {
31304 // Point number, x, y and z coordinates.
31305 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
31306 pointloop[0], pointloop[1], pointloop[2]);
31307 for (i = 0; i < nextras; i++) {
31308 // Write an attribute.
31309 fprintf(outfile, " %.17g", pointloop[3 + i]);
31310 }
31311 if (bmark) {
31312 // Write the boundary marker.
31313 fprintf(outfile, " %d", marker);
31314 }
31315 fprintf(outfile, "\n");
31316 } else {
31317 // X, y, and z coordinates.
31318 out->pointlist[coordindex++] = pointloop[0];
31319 out->pointlist[coordindex++] = pointloop[1];
31320 out->pointlist[coordindex++] = pointloop[2];
31321 // Point attributes.
31322 for (i = 0; i < nextras; i++) {
31323 // Output an attribute.
31324 out->pointattributelist[attribindex++] = pointloop[3 + i];
31325 }
31326 if (bmark) {
31327 // Output the boundary marker.
31328 out->pointmarkerlist[index] = marker;
31329 }
31330 }
31331 pointloop = pointtraverse();
31332 pointnumber++;
31333 index++;
31334 }
31335
31336 if (out == (tetgenio *) NULL) {
31337 fprintf(outfile, "# Generated by %s\n", b->commandline);
31338 fclose(outfile);
31339 }
31340}
31341
31343// //
31344// outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. //
31345// //
31347
31348void tetgenmesh::outmetrics(tetgenio* out)
31349{
31350 FILE *outfile;
31351 char outmtrfilename[FILENAMESIZE];
31352 list *tetlist, *ptlist;
31353 triface tetloop;
31354 point ptloop, neipt;
31355 REAL lave, len; // lmin, lmax,
31356 int mtrindex;
31357 int i;
31358
31359 lave = 0.0;
31360
31361 if (out == (tetgenio *) NULL) {
31362 strcpy(outmtrfilename, b->outfilename);
31363 strcat(outmtrfilename, ".mtr");
31364 }
31365
31366 if (!b->quiet) {
31367 if (out == (tetgenio *) NULL) {
31368 printf("Writing %s.\n", outmtrfilename);
31369 } else {
31370 printf("Writing metrics.\n");
31371 }
31372 }
31373
31374 // Avoid compile warnings.
31375 outfile = (FILE *) NULL;
31376 mtrindex = 0;
31377
31378 if (out == (tetgenio *) NULL) {
31379 outfile = fopen(outmtrfilename, "w");
31380 if (outfile == (FILE *) NULL) {
31381 printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
31382 terminatetetgen(1);
31383 }
31384 // Number of points, number of point metrices,
31385 // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3);
31386 fprintf(outfile, "%ld %d\n", points->items, 1);
31387 } else {
31388 // Allocate space for 'pointmtrlist' if necessary;
31389 // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
31390 out->pointmtrlist = new REAL[points->items];
31391 if (out->pointmtrlist == (REAL *) NULL) {
31392 printf("Error: Out of memory.\n");
31393 terminatetetgen(1);
31394 }
31395 out->numberofpointmtrs = 1; // (sizeoftensor + 3);
31396 mtrindex = 0;
31397 }
31398
31399 // Initialize the point2tet field of each point.
31400 points->traversalinit();
31401 ptloop = pointtraverse();
31402 while (ptloop != (point) NULL) {
31403 setpoint2tet(ptloop, (tetrahedron) NULL);
31404 ptloop = pointtraverse();
31405 }
31406 // Create the point-to-tet map.
31407 tetrahedrons->traversalinit();
31408 tetloop.tet = tetrahedrontraverse();
31409 while (tetloop.tet != (tetrahedron *) NULL) {
31410 for (i = 0; i < 4; i++) {
31411 ptloop = (point) tetloop.tet[4 + i];
31412 setpoint2tet(ptloop, encode(tetloop));
31413 }
31414 tetloop.tet = tetrahedrontraverse();
31415 }
31416
31417 tetlist = new list(sizeof(triface), NULL, 256);
31418 ptlist = new list(sizeof(point *), NULL, 256);
31419
31420 points->traversalinit();
31421 ptloop = pointtraverse();
31422 while (ptloop != (point) NULL) {
31423 decode(point2tet(ptloop), tetloop);
31424 if (!isdead(&tetloop)) {
31425 // Form the star of p.
31426 tetlist->append(&tetloop);
31427 formstarpolyhedron(ptloop, tetlist, ptlist, true);
31428 // lmin = longest;
31429 // lmax = 0.0;
31430 lave = 0.0;
31431 for (i = 0; i < ptlist->len(); i++) {
31432 neipt = * (point *)(* ptlist)[i];
31433 len = distance(ptloop, neipt);
31434 // lmin = lmin < len ? lmin : len;
31435 // lmax = lmax > len ? lmax : len;
31436 lave += len;
31437 }
31438 lave /= ptlist->len();
31439 }
31440 if (out == (tetgenio *) NULL) {
31441 // for (i = 0; i < sizeoftensor; i++) {
31442 // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
31443 // }
31444 if (ptlist->len() > 0) {
31445 // fprintf(outfile, "%-16.8e %-16.8e %-16.8e", lmin, lmax, lave);
31446 fprintf(outfile, "%-16.8e ", lave);
31447 } else {
31448 fprintf(outfile, "0.0 "); // fprintf(outfile, "0.0 0.0 0.0");
31449 }
31450 fprintf(outfile, "\n");
31451 } else {
31452 // for (i = 0; i < sizeoftensor; i++) {
31453 // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
31454 // }
31455 if (ptlist->len() > 0) {
31456 // out->pointmtrlist[mtrindex++] = lmin;
31457 // out->pointmtrlist[mtrindex++] = lmax;
31458 out->pointmtrlist[mtrindex++] = lave;
31459 } else {
31460 // out->pointmtrlist[mtrindex++] = 0.0;
31461 // out->pointmtrlist[mtrindex++] = 0.0;
31462 out->pointmtrlist[mtrindex++] = 0.0;
31463 }
31464 }
31465 tetlist->clear();
31466 ptlist->clear();
31467 ptloop = pointtraverse();
31468 }
31469
31470 delete tetlist;
31471 delete ptlist;
31472
31473 if (out == (tetgenio *) NULL) {
31474 fprintf(outfile, "# Generated by %s\n", b->commandline);
31475 fclose(outfile);
31476 }
31477}
31478
31480// //
31481// outelements() Output the tetrahedra to an .ele file or a tetgenio //
31482// structure. //
31483// //
31485
31486void tetgenmesh::outelements(tetgenio* out)
31487{
31488 FILE *outfile;
31489 char outelefilename[FILENAMESIZE];
31490 tetrahedron* tptr;
31491 int *tlist;
31492 REAL *talist;
31493 int firstindex, shift;
31494 int pointindex;
31495 int attribindex;
31496 point p1, p2, p3, p4;
31497 point *extralist;
31498 int elementnumber;
31499 int eextras;
31500 int i;
31501
31502 if (out == (tetgenio *) NULL) {
31503 strcpy(outelefilename, b->outfilename);
31504 strcat(outelefilename, ".ele");
31505 }
31506
31507 if (!b->quiet) {
31508 if (out == (tetgenio *) NULL) {
31509 printf("Writing %s.\n", outelefilename);
31510 } else {
31511 printf("Writing elements.\n");
31512 }
31513 }
31514
31515 // Avoid compile warnings.
31516 outfile = (FILE *) NULL;
31517 tlist = (int *) NULL;
31518 talist = (double *) NULL;
31519 pointindex = attribindex = 0;
31520
31521 eextras = in->numberoftetrahedronattributes;
31522 if (out == (tetgenio *) NULL) {
31523 outfile = fopen(outelefilename, "w");
31524 if (outfile == (FILE *) NULL) {
31525 printf("File I/O Error: Cannot create file %s.\n", outelefilename);
31526 terminatetetgen(1);
31527 }
31528 // Number of tetras, points per tetra, attributes per tetra.
31529 fprintf(outfile, "%ld %d %d\n", tetrahedrons->items,
31530 b->order == 1 ? 4 : 10, eextras);
31531 } else {
31532 // Allocate memory for output tetrahedra.
31533 out->tetrahedronlist = new int[tetrahedrons->items *
31534 (b->order == 1 ? 4 : 10)];
31535 if (out->tetrahedronlist == (int *) NULL) {
31536 printf("Error: Out of memory.\n");
31537 terminatetetgen(1);
31538 }
31539 // Allocate memory for output tetrahedron attributes if necessary.
31540 if (eextras > 0) {
31541 out->tetrahedronattributelist = new REAL[tetrahedrons->items * eextras];
31542 if (out->tetrahedronattributelist == (REAL *) NULL) {
31543 printf("Error: Out of memory.\n");
31544 terminatetetgen(1);
31545 }
31546 }
31547 out->numberoftetrahedra = tetrahedrons->items;
31548 out->numberofcorners = b->order == 1 ? 4 : 10;
31549 out->numberoftetrahedronattributes = eextras;
31550 tlist = out->tetrahedronlist;
31551 talist = out->tetrahedronattributelist;
31552 pointindex = 0;
31553 attribindex = 0;
31554 }
31555
31556 // Determine the first index (0 or 1).
31557 firstindex = b->zeroindex ? 0 : in->firstnumber;
31558 shift = 0; // Default no shiftment.
31559 if ((in->firstnumber == 1) && (firstindex == 0)) {
31560 shift = 1; // Shift the output indices by 1.
31561 }
31562
31563 tetrahedrons->traversalinit();
31564 tptr = tetrahedrontraverse();
31565 elementnumber = firstindex; // in->firstnumber;
31566 while (tptr != (tetrahedron *) NULL) {
31567 p1 = (point) tptr[4];
31568 p2 = (point) tptr[5];
31569 p3 = (point) tptr[6];
31570 p4 = (point) tptr[7];
31571 if (out == (tetgenio *) NULL) {
31572 // Tetrahedron number, indices for four points.
31573 fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
31574 pointmark(p1) - shift, pointmark(p2) - shift,
31575 pointmark(p3) - shift, pointmark(p4) - shift);
31576 if (b->order == 2) {
31577 extralist = (point *) tptr[highorderindex];
31578 // Tetrahedron number, indices for four points plus six extra points.
31579 fprintf(outfile, " %5d %5d %5d %5d %5d %5d",
31580 pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
31581 pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
31582 pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
31583 }
31584 for (i = 0; i < eextras; i++) {
31585 fprintf(outfile, " %.17g", elemattribute(tptr, i));
31586 }
31587 fprintf(outfile, "\n");
31588 } else {
31589 tlist[pointindex++] = pointmark(p1) - shift;
31590 tlist[pointindex++] = pointmark(p2) - shift;
31591 tlist[pointindex++] = pointmark(p3) - shift;
31592 tlist[pointindex++] = pointmark(p4) - shift;
31593 if (b->order == 2) {
31594 extralist = (point *) tptr[highorderindex];
31595 tlist[pointindex++] = pointmark(extralist[0]) - shift;
31596 tlist[pointindex++] = pointmark(extralist[1]) - shift;
31597 tlist[pointindex++] = pointmark(extralist[2]) - shift;
31598 tlist[pointindex++] = pointmark(extralist[3]) - shift;
31599 tlist[pointindex++] = pointmark(extralist[4]) - shift;
31600 tlist[pointindex++] = pointmark(extralist[5]) - shift;
31601 }
31602 for (i = 0; i < eextras; i++) {
31603 talist[attribindex++] = elemattribute(tptr, i);
31604 }
31605 }
31606 if (b->neighout) {
31607 // Remember the index of this element.
31608 * (int *) (tptr + elemmarkerindex) = elementnumber;
31609 }
31610 tptr = tetrahedrontraverse();
31611 elementnumber++;
31612 }
31613 if (b->neighout) {
31614 // Set the outside element marker.
31615 * (int *) (dummytet + elemmarkerindex) = -1;
31616 }
31617
31618 if (out == (tetgenio *) NULL) {
31619 fprintf(outfile, "# Generated by %s\n", b->commandline);
31620 fclose(outfile);
31621 }
31622}
31623
31625// //
31626// outfaces() Output all faces to a .face file or a tetgenio structure. //
31627// //
31628// This routines outputs all triangular faces (including outer boundary //
31629// faces and inner faces) of this mesh. //
31630// //
31632
31633void tetgenmesh::outfaces(tetgenio* out)
31634{
31635 FILE *outfile;
31636 char facefilename[FILENAMESIZE];
31637 int *elist;
31638 int *emlist;
31639 int neigh1, neigh2;
31640 int index;
31641 triface tface, tsymface;
31642 face checkmark;
31643 point torg, tdest, tapex;
31644 long faces;
31645 int bmark, faceid, marker;
31646 int firstindex, shift;
31647 int facenumber;
31648
31649 neigh1 = 0;
31650 neigh2 = 0;
31651
31652 if (out == (tetgenio *) NULL) {
31653 strcpy(facefilename, b->outfilename);
31654 strcat(facefilename, ".face");
31655 }
31656
31657 if (!b->quiet) {
31658 if (out == (tetgenio *) NULL) {
31659 printf("Writing %s.\n", facefilename);
31660 } else {
31661 printf("Writing faces.\n");
31662 }
31663 }
31664
31665 // Avoid compile warnings.
31666 outfile = (FILE *) NULL;
31667 elist = (int *) NULL;
31668 emlist = (int *) NULL;
31669 index = marker = 0;
31670
31671 faces = (4l * tetrahedrons->items + hullsize) / 2l;
31672 bmark = !b->nobound && in->facetmarkerlist;
31673
31674 if (out == (tetgenio *) NULL) {
31675 outfile = fopen(facefilename, "w");
31676 if (outfile == (FILE *) NULL) {
31677 printf("File I/O Error: Cannot create file %s.\n", facefilename);
31678 terminatetetgen(1);
31679 }
31680 fprintf(outfile, "%ld %d\n", faces, bmark);
31681 } else {
31682 // Allocate memory for 'trifacelist'.
31683 out->trifacelist = new int[faces * 3];
31684 if (out->trifacelist == (int *) NULL) {
31685 printf("Error: Out of memory.\n");
31686 terminatetetgen(1);
31687 }
31688 // Allocate memory for 'trifacemarkerlist' if necessary.
31689 if (bmark) {
31690 out->trifacemarkerlist = new int[faces];
31691 if (out->trifacemarkerlist == (int *) NULL) {
31692 printf("Error: Out of memory.\n");
31693 terminatetetgen(1);
31694 }
31695 }
31696 if (b->neighout > 1) {
31697 // '-nn' switch.
31698 out->adjtetlist = new int[subfaces->items * 2];
31699 if (out->adjtetlist == (int *) NULL) {
31700 printf("Error: Out of memory.\n");
31701 terminatetetgen(1);
31702 }
31703 }
31704 out->numberoftrifaces = faces;
31705 elist = out->trifacelist;
31706 emlist = out->trifacemarkerlist;
31707 index = 0;
31708 }
31709
31710 // Determine the first index (0 or 1).
31711 firstindex = b->zeroindex ? 0 : in->firstnumber;
31712 shift = 0; // Default no shiftment.
31713 if ((in->firstnumber == 1) && (firstindex == 0)) {
31714 shift = 1; // Shift the output indices by 1.
31715 }
31716
31717 tetrahedrons->traversalinit();
31718 tface.tet = tetrahedrontraverse();
31719 facenumber = firstindex; // in->firstnumber;
31720 // To loop over the set of faces, loop over all tetrahedra, and look at
31721 // the four faces of each one. If there isn't another tetrahedron
31722 // adjacent to this face, operate on the face. If there is another
31723 // adjacent tetrahedron, operate on the face only if the current
31724 // tetrahedron has a smaller pointer than its neighbor. This way, each
31725 // face is considered only once.
31726 while (tface.tet != (tetrahedron *) NULL) {
31727 for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
31728 sym(tface, tsymface);
31729 if ((tsymface.tet == dummytet) || (tface.tet < tsymface.tet)) {
31730 torg = org(tface);
31731 tdest = dest(tface);
31732 tapex = apex(tface);
31733 if (bmark) {
31734 // Get the boundary marker of this face. If it is an inner face,
31735 // it has no boundary marker, set it be zero.
31736 if (b->useshelles) {
31737 // Shell face is used.
31738 tspivot(tface, checkmark);
31739 if (checkmark.sh == dummysh) {
31740 marker = 0; // It is an inner face.
31741 } else {
31742 faceid = shellmark(checkmark) - 1;
31743 marker = in->facetmarkerlist[faceid];
31744 }
31745 } else {
31746 // Shell face is not used, only distinguish outer and inner face.
31747 marker = tsymface.tet != dummytet ? 1 : 0;
31748 }
31749 }
31750 if (b->neighout > 1) {
31751 // '-nn' switch. Output adjacent tets indices.
31752 neigh1 = * (int *)(tface.tet + elemmarkerindex);
31753 if (tsymface.tet != dummytet) {
31754 neigh2 = * (int *)(tsymface.tet + elemmarkerindex);
31755 } else {
31756 neigh2 = -1;
31757 }
31758 }
31759 if (out == (tetgenio *) NULL) {
31760 // Face number, indices of three vertices.
31761 fprintf(outfile, "%5d %4d %4d %4d", facenumber,
31762 pointmark(torg) - shift, pointmark(tdest) - shift,
31763 pointmark(tapex) - shift);
31764 if (bmark) {
31765 // Output a boundary marker.
31766 fprintf(outfile, " %d", marker);
31767 }
31768 if (b->neighout > 1) {
31769 fprintf(outfile, " %5d %5d", neigh1, neigh2);
31770 }
31771 fprintf(outfile, "\n");
31772 } else {
31773 // Output indices of three vertices.
31774 elist[index++] = pointmark(torg) - shift;
31775 elist[index++] = pointmark(tdest) - shift;
31776 elist[index++] = pointmark(tapex) - shift;
31777 if (bmark) {
31778 emlist[facenumber - in->firstnumber] = marker;
31779 }
31780 if (b->neighout > 1) {
31781 out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1;
31782 out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
31783 }
31784 }
31785 facenumber++;
31786 }
31787 }
31788 tface.tet = tetrahedrontraverse();
31789 }
31790
31791 if (out == (tetgenio *) NULL) {
31792 fprintf(outfile, "# Generated by %s\n", b->commandline);
31793 fclose(outfile);
31794 }
31795}
31796
31798// //
31799// outhullfaces() Output outer boundary faces to a .face file or a //
31800// tetgenio structure. //
31801// //
31802// The normal of each face is arranged to point inside of the domain (use //
31803// right-hand rule). This routines will outputs convex hull faces if the //
31804// mesh is a Delaunay tetrahedralization. //
31805// //
31807
31808void tetgenmesh::outhullfaces(tetgenio* out)
31809{
31810 FILE *outfile;
31811 char facefilename[FILENAMESIZE];
31812 int *elist;
31813 int index;
31814 triface tface, tsymface;
31815 face checkmark;
31816 point torg, tdest, tapex;
31817 int firstindex, shift;
31818 int facenumber;
31819
31820 if (out == (tetgenio *) NULL) {
31821 strcpy(facefilename, b->outfilename);
31822 strcat(facefilename, ".face");
31823 }
31824
31825 if (!b->quiet) {
31826 if (out == (tetgenio *) NULL) {
31827 printf("Writing %s.\n", facefilename);
31828 } else {
31829 printf("Writing faces.\n");
31830 }
31831 }
31832
31833 // Avoid compile warnings.
31834 outfile = (FILE *) NULL;
31835 elist = (int *) NULL;
31836 index = 0;
31837
31838 if (out == (tetgenio *) NULL) {
31839 outfile = fopen(facefilename, "w");
31840 if (outfile == (FILE *) NULL) {
31841 printf("File I/O Error: Cannot create file %s.\n", facefilename);
31842 terminatetetgen(1);
31843 }
31844 fprintf(outfile, "%ld 0\n", hullsize);
31845 } else {
31846 // Allocate memory for 'trifacelist'.
31847 out->trifacelist = new int[hullsize * 3];
31848 if (out->trifacelist == (int *) NULL) {
31849 printf("Error: Out of memory.\n");
31850 terminatetetgen(1);
31851 }
31852 out->numberoftrifaces = hullsize;
31853 elist = out->trifacelist;
31854 index = 0;
31855 }
31856
31857 // Determine the first index (0 or 1).
31858 firstindex = b->zeroindex ? 0 : in->firstnumber;
31859 shift = 0; // Default no shiftment.
31860 if ((in->firstnumber == 1) && (firstindex == 0)) {
31861 shift = 1; // Shift the output indices by 1.
31862 }
31863
31864 tetrahedrons->traversalinit();
31865 tface.tet = tetrahedrontraverse();
31866 facenumber = firstindex; // in->firstnumber;
31867 // To loop over the set of hull faces, loop over all tetrahedra, and look
31868 // at the four faces of each one. If there isn't another tetrahedron
31869 // adjacent to this face, operate on the face.
31870 while (tface.tet != (tetrahedron *) NULL) {
31871 for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
31872 sym(tface, tsymface);
31873 if (tsymface.tet == dummytet) {
31874 torg = org(tface);
31875 tdest = dest(tface);
31876 tapex = apex(tface);
31877 if (out == (tetgenio *) NULL) {
31878 // Face number, indices of three vertices.
31879 fprintf(outfile, "%5d %4d %4d %4d", facenumber,
31880 pointmark(torg) - shift, pointmark(tdest) - shift,
31881 pointmark(tapex) - shift);
31882 fprintf(outfile, "\n");
31883 } else {
31884 // Output indices of three vertices.
31885 elist[index++] = pointmark(torg) - shift;
31886 elist[index++] = pointmark(tdest) - shift;
31887 elist[index++] = pointmark(tapex) - shift;
31888 }
31889 facenumber++;
31890 }
31891 }
31892 tface.tet = tetrahedrontraverse();
31893 }
31894
31895 if (out == (tetgenio *) NULL) {
31896 fprintf(outfile, "# Generated by %s\n", b->commandline);
31897 fclose(outfile);
31898 }
31899}
31900
31902// //
31903// outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or //
31904// a tetgenio structure. //
31905// //
31906// The boundary faces are exist in 'subfaces'. For listing triangle vertices //
31907// in the same sense for all triangles in the mesh, the direction determined //
31908// by right-hand rule is pointer to the inside of the volume. //
31909// //
31911
31912void tetgenmesh::outsubfaces(tetgenio* out)
31913{
31914 FILE *outfile;
31915 char facefilename[FILENAMESIZE];
31916 int *elist;
31917 int *emlist;
31918 int index, index1, index2;
31919 triface abuttingtet;
31920 face faceloop;
31921 point torg, tdest, tapex;
31922 int bmark, faceid, marker;
31923 int firstindex, shift;
31924 int neigh1, neigh2;
31925 int facenumber;
31926
31927 if (out == (tetgenio *) NULL) {
31928 strcpy(facefilename, b->outfilename);
31929 strcat(facefilename, ".face");
31930 }
31931
31932 if (!b->quiet) {
31933 if (out == (tetgenio *) NULL) {
31934 printf("Writing %s.\n", facefilename);
31935 } else {
31936 printf("Writing faces.\n");
31937 }
31938 }
31939
31940 // Avoid compile warnings.
31941 outfile = (FILE *) NULL;
31942 elist = (int *) NULL;
31943 emlist = (int *) NULL;
31944 index = index1 = index2 = 0;
31945 faceid = marker = 0;
31946 neigh1 = neigh2 = 0;
31947
31948 bmark = !b->nobound && in->facetmarkerlist;
31949
31950 if (out == (tetgenio *) NULL) {
31951 outfile = fopen(facefilename, "w");
31952 if (outfile == (FILE *) NULL) {
31953 printf("File I/O Error: Cannot create file %s.\n", facefilename);
31954 terminatetetgen(1);
31955 }
31956 // Number of subfaces.
31957 fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
31958 } else {
31959 // Allocate memory for 'trifacelist'.
31960 out->trifacelist = new int[subfaces->items * 3];
31961 if (out->trifacelist == (int *) NULL) {
31962 printf("Error: Out of memory.\n");
31963 terminatetetgen(1);
31964 }
31965 if (bmark) {
31966 // Allocate memory for 'trifacemarkerlist'.
31967 out->trifacemarkerlist = new int[subfaces->items];
31968 if (out->trifacemarkerlist == (int *) NULL) {
31969 printf("Error: Out of memory.\n");
31970 terminatetetgen(1);
31971 }
31972 }
31973 if (b->neighout > 1) {
31974 // '-nn' switch.
31975 out->adjtetlist = new int[subfaces->items * 2];
31976 if (out->adjtetlist == (int *) NULL) {
31977 printf("Error: Out of memory.\n");
31978 terminatetetgen(1);
31979 }
31980 }
31981 out->numberoftrifaces = subfaces->items;
31982 elist = out->trifacelist;
31983 emlist = out->trifacemarkerlist;
31984 }
31985
31986 // Determine the first index (0 or 1).
31987 firstindex = b->zeroindex ? 0 : in->firstnumber;
31988 shift = 0; // Default no shiftment.
31989 if ((in->firstnumber == 1) && (firstindex == 0)) {
31990 shift = 1; // Shift the output indices by 1.
31991 }
31992
31993 subfaces->traversalinit();
31994 faceloop.sh = shellfacetraverse(subfaces);
31995 facenumber = firstindex; // in->firstnumber;
31996 while (faceloop.sh != (shellface *) NULL) {
31997 stpivot(faceloop, abuttingtet);
31998 if (abuttingtet.tet == dummytet) {
31999 sesymself(faceloop);
32000 stpivot(faceloop, abuttingtet);
32001 }
32002 if (abuttingtet.tet != dummytet) {
32003 // If there is a tetrahedron containing this subface, orient it so
32004 // that the normal of this face points to inside of the volume by
32005 // right-hand rule.
32006 adjustedgering(abuttingtet, CCW);
32007 torg = org(abuttingtet);
32008 tdest = dest(abuttingtet);
32009 tapex = apex(abuttingtet);
32010 } else {
32011 // This may happen when only a surface mesh be generated.
32012 torg = sorg(faceloop);
32013 tdest = sdest(faceloop);
32014 tapex = sapex(faceloop);
32015 }
32016 if (bmark) {
32017 faceid = shellmark(faceloop) - 1;
32018 marker = in->facetmarkerlist[faceid];
32019 }
32020 if (b->neighout > 1) {
32021 // '-nn' switch. Output adjacent tets indices.
32022 neigh1 = -1;
32023 stpivot(faceloop, abuttingtet);
32024 if (abuttingtet.tet != dummytet) {
32025 neigh1 = * (int *)(abuttingtet.tet + elemmarkerindex);
32026 }
32027 neigh2 = -1;
32028 sesymself(faceloop);
32029 stpivot(faceloop, abuttingtet);
32030 if (abuttingtet.tet != dummytet) {
32031 neigh2 = * (int *)(abuttingtet.tet + elemmarkerindex);
32032 }
32033 }
32034 if (out == (tetgenio *) NULL) {
32035 fprintf(outfile, "%5d %4d %4d %4d", facenumber,
32036 pointmark(torg) - shift, pointmark(tdest) - shift,
32037 pointmark(tapex) - shift);
32038 if (bmark) {
32039 fprintf(outfile, " %d", marker);
32040 }
32041 if (b->neighout > 1) {
32042 fprintf(outfile, " %5d %5d", neigh1, neigh2);
32043 }
32044 fprintf(outfile, "\n");
32045 } else {
32046 // Output three vertices of this face;
32047 elist[index++] = pointmark(torg) - shift;
32048 elist[index++] = pointmark(tdest) - shift;
32049 elist[index++] = pointmark(tapex) - shift;
32050 if (bmark) {
32051 emlist[index1++] = marker;
32052 }
32053 if (b->neighout > 1) {
32054 out->adjtetlist[index2++] = neigh1;
32055 out->adjtetlist[index2++] = neigh2;
32056 }
32057 }
32058 facenumber++;
32059 faceloop.sh = shellfacetraverse(subfaces);
32060 }
32061
32062 if (out == (tetgenio *) NULL) {
32063 fprintf(outfile, "# Generated by %s\n", b->commandline);
32064 fclose(outfile);
32065 }
32066}
32067
32069// //
32070// outedges() Output all edges to a .edge file or a structure. //
32071// //
32073
32074void tetgenmesh::outedges(tetgenio* out)
32075{
32076 FILE *outfile;
32077 char edgefilename[FILENAMESIZE];
32078 int *elist, *emlist;
32079 int index, index1;
32080 triface tetloop, worktet, spintet;
32081 face checksh;
32082 point torg, tdest;
32083 long faces, edges;
32084 int firstindex, shift;
32085 int edgenumber, faceid, marker;
32086 int hitbdry, i;
32087
32088 if (out == (tetgenio *) NULL) {
32089 strcpy(edgefilename, b->outfilename);
32090 strcat(edgefilename, ".edge");
32091 }
32092
32093 if (!b->quiet) {
32094 if (out == (tetgenio *) NULL) {
32095 printf("Writing %s.\n", edgefilename);
32096 } else {
32097 printf("Writing edges.\n");
32098 }
32099 }
32100
32101 // Avoid compile warnings.
32102 outfile = (FILE *) NULL;
32103 elist = (int *) NULL;
32104 emlist = (int *) NULL;
32105 index = index1 = 0;
32106 faceid = marker = 0;
32107
32108 // Using the Euler formula (V-E+F-T=1) to get the total number of edges.
32109 faces = (4l * tetrahedrons->items + hullsize) / 2l;
32110 edges = points->items + faces - tetrahedrons->items - 1l;
32111
32112 if (out == (tetgenio *) NULL) {
32113 outfile = fopen(edgefilename, "w");
32114 if (outfile == (FILE *) NULL) {
32115 printf("File I/O Error: Cannot create file %s.\n", edgefilename);
32116 terminatetetgen(1);
32117 }
32118 // Write the number of edges, boundary markers (0 or 1).
32119 fprintf(outfile, "%ld %d\n", edges, !b->nobound);
32120 } else {
32121 // Allocate memory for 'edgelist'.
32122 out->edgelist = new int[edges * 2];
32123 if (out->edgelist == (int *) NULL) {
32124 printf("Error: Out of memory.\n");
32125 terminatetetgen(1);
32126 }
32127 if (!b->nobound) {
32128 out->edgemarkerlist = new int[edges];
32129 }
32130 out->numberofedges = edges;
32131 elist = out->edgelist;
32132 emlist = out->edgemarkerlist;
32133 }
32134
32135 // Determine the first index (0 or 1).
32136 firstindex = b->zeroindex ? 0 : in->firstnumber;
32137 shift = 0; // Default no shiftment.
32138 if ((in->firstnumber == 1) && (firstindex == 0)) {
32139 shift = 1; // Shift (reduce) the output indices by 1.
32140 }
32141
32142 tetrahedrons->traversalinit();
32143 tetloop.tet = tetrahedrontraverse();
32144 edgenumber = firstindex; // in->firstnumber;
32145 while (tetloop.tet != (tetrahedron *) NULL) {
32146 // Count the number of Voronoi faces. Look at the six edges of each
32147 // tetrahedron. Count the edge only if the tetrahedron's pointer is
32148 // smaller than those of all other tetrahedra that share the edge.
32149 worktet.tet = tetloop.tet;
32150 for (i = 0; i < 6; i++) {
32151 worktet.loc = edge2locver[i][0];
32152 worktet.ver = edge2locver[i][1];
32153 adjustedgering(worktet, CW);
32154 spintet = worktet;
32155 hitbdry = 0;
32156 while (hitbdry < 2) {
32157 if (fnextself(spintet)) {
32158 if (apex(spintet) == apex(worktet)) break;
32159 if (spintet.tet < worktet.tet) break;
32160 } else {
32161 hitbdry++;
32162 if (hitbdry < 2) {
32163 esym(worktet, spintet);
32164 fnextself(spintet); // In the same tet.
32165 }
32166 }
32167 }
32168 // Count this edge if no adjacent tets are smaller than this tet.
32169 if (spintet.tet >= worktet.tet) {
32170 torg = org(worktet);
32171 tdest = dest(worktet);
32172 if (out == (tetgenio *) NULL) {
32173 fprintf(outfile, "%5d %4d %4d", edgenumber,
32174 pointmark(torg) - shift, pointmark(tdest) - shift);
32175 } else {
32176 // Output three vertices of this face;
32177 elist[index++] = pointmark(torg) - shift;
32178 elist[index++] = pointmark(tdest) - shift;
32179 }
32180 if (!b->nobound) {
32181 if (hitbdry > 0) {
32182 // It is a boundary edge. Get the boundary marker of the facet
32183 // containing this edge. Note there may have more than one
32184 // facet, choose one arbitrarily.
32185 if ((b->plc || b->refine) && in->facetmarkerlist) {
32186 tspivot(spintet, checksh);
32187 faceid = shellmark(checksh) - 1;
32188 marker = in->facetmarkerlist[faceid];
32189 } else {
32190 marker = 1; // Indicate it's a boundary edge.
32191 }
32192 } else {
32193 marker = 0;
32194 }
32195 if (out == (tetgenio *) NULL) {
32196 fprintf(outfile, " %d", marker);
32197 } else {
32198 emlist[index1++] = marker;
32199 }
32200 }
32201 if (out == (tetgenio *) NULL) {
32202 fprintf(outfile, "\n");
32203 }
32204 edgenumber++;
32205 }
32206 }
32207 tetloop.tet = tetrahedrontraverse();
32208 }
32209
32210 if (out == (tetgenio *) NULL) {
32211 fprintf(outfile, "# Generated by %s\n", b->commandline);
32212 fclose(outfile);
32213 }
32214}
32215
32217// //
32218// outsubsegments() Output segments to a .edge file or a structure. //
32219// //
32221
32222void tetgenmesh::outsubsegments(tetgenio* out)
32223{
32224 FILE *outfile;
32225 char edgefilename[FILENAMESIZE];
32226 int *elist;
32227 int index;
32228 face edgeloop;
32229 point torg, tdest;
32230 int firstindex, shift;
32231 int edgenumber;
32232
32233 if (out == (tetgenio *) NULL) {
32234 strcpy(edgefilename, b->outfilename);
32235 strcat(edgefilename, ".edge");
32236 }
32237
32238 if (!b->quiet) {
32239 if (out == (tetgenio *) NULL) {
32240 printf("Writing %s.\n", edgefilename);
32241 } else {
32242 printf("Writing edges.\n");
32243 }
32244 }
32245
32246 // Avoid compile warnings.
32247 outfile = (FILE *) NULL;
32248 elist = (int *) NULL;
32249 index = 0;
32250
32251 if (out == (tetgenio *) NULL) {
32252 outfile = fopen(edgefilename, "w");
32253 if (outfile == (FILE *) NULL) {
32254 printf("File I/O Error: Cannot create file %s.\n", edgefilename);
32255 terminatetetgen(1);
32256 }
32257 // Number of subsegments.
32258 fprintf(outfile, "%ld\n", subsegs->items);
32259 } else {
32260 // Allocate memory for 'edgelist'.
32261 out->edgelist = new int[subsegs->items * 2];
32262 if (out->edgelist == (int *) NULL) {
32263 printf("Error: Out of memory.\n");
32264 terminatetetgen(1);
32265 }
32266 out->numberofedges = subsegs->items;
32267 elist = out->edgelist;
32268 }
32269
32270 // Determine the first index (0 or 1).
32271 firstindex = b->zeroindex ? 0 : in->firstnumber;
32272 shift = 0; // Default no shiftment.
32273 if ((in->firstnumber == 1) && (firstindex == 0)) {
32274 shift = 1; // Shift the output indices by 1.
32275 }
32276
32277 subsegs->traversalinit();
32278 edgeloop.sh = shellfacetraverse(subsegs);
32279 edgenumber = firstindex; // in->firstnumber;
32280 while (edgeloop.sh != (shellface *) NULL) {
32281 torg = sorg(edgeloop);
32282 tdest = sdest(edgeloop);
32283 if (out == (tetgenio *) NULL) {
32284 fprintf(outfile, "%5d %4d %4d\n", edgenumber,
32285 pointmark(torg) - shift, pointmark(tdest) - shift);
32286 } else {
32287 // Output three vertices of this face;
32288 elist[index++] = pointmark(torg) - shift;
32289 elist[index++] = pointmark(tdest) - shift;
32290 }
32291 edgenumber++;
32292 edgeloop.sh = shellfacetraverse(subsegs);
32293 }
32294
32295 if (out == (tetgenio *) NULL) {
32296 fprintf(outfile, "# Generated by %s\n", b->commandline);
32297 fclose(outfile);
32298 }
32299}
32300
32302// //
32303// outneighbors() Output tet neighbors to a .neigh file or a structure. //
32304// //
32306
32307void tetgenmesh::outneighbors(tetgenio* out)
32308{
32309 FILE *outfile;
32310 char neighborfilename[FILENAMESIZE];
32311 int *nlist;
32312 int index;
32313 triface tetloop, tetsym;
32314 int neighbor1, neighbor2, neighbor3, neighbor4;
32315 int firstindex;
32316 int elementnumber;
32317
32318 if (out == (tetgenio *) NULL) {
32319 strcpy(neighborfilename, b->outfilename);
32320 strcat(neighborfilename, ".neigh");
32321 }
32322
32323 if (!b->quiet) {
32324 if (out == (tetgenio *) NULL) {
32325 printf("Writing %s.\n", neighborfilename);
32326 } else {
32327 printf("Writing neighbors.\n");
32328 }
32329 }
32330
32331 // Avoid compile warnings.
32332 outfile = (FILE *) NULL;
32333 nlist = (int *) NULL;
32334 index = 0;
32335
32336 if (out == (tetgenio *) NULL) {
32337 outfile = fopen(neighborfilename, "w");
32338 if (outfile == (FILE *) NULL) {
32339 printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
32340 terminatetetgen(1);
32341 }
32342 // Number of tetrahedra, four faces per tetrahedron.
32343 fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4);
32344 } else {
32345 // Allocate memory for 'neighborlist'.
32346 out->neighborlist = new int[tetrahedrons->items * 4];
32347 if (out->neighborlist == (int *) NULL) {
32348 printf("Error: Out of memory.\n");
32349 terminatetetgen(1);
32350 }
32351 nlist = out->neighborlist;
32352 }
32353
32354 // Determine the first index (0 or 1).
32355 firstindex = b->zeroindex ? 0 : in->firstnumber;
32356
32357 tetrahedrons->traversalinit();
32358 tetloop.tet = tetrahedrontraverse();
32359 elementnumber = firstindex; // in->firstnumber;
32360 while (tetloop.tet != (tetrahedron *) NULL) {
32361 tetloop.loc = 2;
32362 sym(tetloop, tetsym);
32363 neighbor1 = * (int *) (tetsym.tet + elemmarkerindex);
32364 tetloop.loc = 3;
32365 sym(tetloop, tetsym);
32366 neighbor2 = * (int *) (tetsym.tet + elemmarkerindex);
32367 tetloop.loc = 1;
32368 sym(tetloop, tetsym);
32369 neighbor3 = * (int *) (tetsym.tet + elemmarkerindex);
32370 tetloop.loc = 0;
32371 sym(tetloop, tetsym);
32372 neighbor4 = * (int *) (tetsym.tet + elemmarkerindex);
32373 if (out == (tetgenio *) NULL) {
32374 // Tetrahedra number, neighboring tetrahedron numbers.
32375 fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
32376 neighbor1, neighbor2, neighbor3, neighbor4);
32377 } else {
32378 nlist[index++] = neighbor1;
32379 nlist[index++] = neighbor2;
32380 nlist[index++] = neighbor3;
32381 nlist[index++] = neighbor4;
32382 }
32383 tetloop.tet = tetrahedrontraverse();
32384 elementnumber++;
32385 }
32386
32387 if (out == (tetgenio *) NULL) {
32388 fprintf(outfile, "# Generated by %s\n", b->commandline);
32389 fclose(outfile);
32390 }
32391}
32392
32394// //
32395// outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
32396// and .v.cell. //
32397// //
32398// The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
32399// The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
32400// Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
32401// unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
32402// A Voronoi face is the convex hull of all Voronoi vertices around a common //
32403// Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a //
32404// ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
32405// onoi vertices around a common Delaunay vertex. It is a polytope for any //
32406// internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
32407// vertex belonging to the convex hull. //
32408// //
32410
32411void tetgenmesh::outvoronoi(tetgenio* out)
32412{
32413 FILE *outfile;
32414 char outfilename[FILENAMESIZE];
32415 tetgenio::voroedge *vedge;
32416 tetgenio::vorofacet *vfacet;
32417 list *tetlist, *ptlist;
32418 triface tetloop, worktet, spintet;
32419 point pt[4], ptloop, neipt;
32420 REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
32421 long faces, edges;
32422 int *tetfaceindexarray, *tetedgeindexarray;
32423 int arraysize, *vertarray;
32424 int vpointcount, vedgecount, vfacecount, tcount;
32425 int index, shift;
32426 int end1, end2;
32427 int hitbdry, i, j, k;
32428
32429 vedge = NULL;
32430 vertarray = NULL;
32431 vfacet = NULL;
32432 k = 0;
32433
32434 // Output Voronoi vertices to .v.node file.
32435 if (out == (tetgenio *) NULL) {
32436 strcpy(outfilename, b->outfilename);
32437 strcat(outfilename, ".v.node");
32438 }
32439
32440 if (!b->quiet) {
32441 if (out == (tetgenio *) NULL) {
32442 printf("Writing %s.\n", outfilename);
32443 } else {
32444 printf("Writing Voronoi vertices.\n");
32445 }
32446 }
32447
32448 // Determine the first index (0 or 1).
32449 shift = (b->zeroindex ? 0 : in->firstnumber);
32450 // The number of Delaunay faces (= the number of Voronoi edges).
32451 faces = (4l * tetrahedrons->items + hullsize) / 2l;
32452 // The number of Delaunay edges (= the number of Voronoi faces).
32453 edges = points->items + faces - tetrahedrons->items - 1;
32454 outfile = (FILE *) NULL; // Avoid compile warnings.
32455
32456 if (out == (tetgenio *) NULL) {
32457 outfile = fopen(outfilename, "w");
32458 if (outfile == (FILE *) NULL) {
32459 printf("File I/O Error: Cannot create file %s.\n", outfilename);
32460 terminatetetgen(1);
32461 }
32462 // Number of voronoi points, 3 dim, no attributes, no marker.
32463 fprintf(outfile, "%ld 3 0 0\n", tetrahedrons->items);
32464 } else {
32465 // Allocate space for 'vpointlist'.
32466 out->numberofvpoints = (int) tetrahedrons->items;
32467 out->vpointlist = new REAL[out->numberofvpoints * 3];
32468 if (out->vpointlist == (REAL *) NULL) {
32469 printf("Error: Out of memory.\n");
32470 terminatetetgen(1);
32471 }
32472 }
32473
32474 // Loop the tetrahedronlist once, do the following:
32475 // (1) Output Voronoi vertices (the circumcenter of the tetrahedron).
32476 // (2) Make a map from points-to-tetrahedra (for Voronoi cells).
32477 tetrahedrons->traversalinit();
32478 tetloop.tet = tetrahedrontraverse();
32479 vpointcount = 0;
32480 index = 0;
32481 while (tetloop.tet != (tetrahedron *) NULL) {
32482 // Calculate the circumcenter.
32483 for (i = 0; i < 4; i++) {
32484 pt[i] = (point) tetloop.tet[4 + i];
32485 setpoint2tet(pt[i], encode(tetloop));
32486 }
32487 circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
32488 if (out == (tetgenio *) NULL) {
32489 fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
32490 ccent[0], ccent[1], ccent[2]);
32491 } else {
32492 out->vpointlist[index++] = ccent[0];
32493 out->vpointlist[index++] = ccent[1];
32494 out->vpointlist[index++] = ccent[2];
32495 }
32496 // Remember the index of this element.
32497 * (int *) (tetloop.tet + elemmarkerindex) = vpointcount;
32498 vpointcount++;
32499 tetloop.tet = tetrahedrontraverse();
32500 }
32501 // Set the outside element marker.
32502 * (int *) (dummytet + elemmarkerindex) = -1;
32503
32504 if (out == (tetgenio *) NULL) {
32505 fprintf(outfile, "# Generated by %s\n", b->commandline);
32506 fclose(outfile);
32507 }
32508
32509 // Output Voronoi edges to .v.edge file.
32510 if (out == (tetgenio *) NULL) {
32511 strcpy(outfilename, b->outfilename);
32512 strcat(outfilename, ".v.edge");
32513 }
32514
32515 if (!b->quiet) {
32516 if (out == (tetgenio *) NULL) {
32517 printf("Writing %s.\n", outfilename);
32518 } else {
32519 printf("Writing Voronoi edges.\n");
32520 }
32521 }
32522
32523 if (out == (tetgenio *) NULL) {
32524 outfile = fopen(outfilename, "w");
32525 if (outfile == (FILE *) NULL) {
32526 printf("File I/O Error: Cannot create file %s.\n", outfilename);
32527 terminatetetgen(1);
32528 }
32529 // Number of Voronoi edges, no marker.
32530 fprintf(outfile, "%ld 0\n", faces);
32531 } else {
32532 // Allocate space for 'vpointlist'.
32533 out->numberofedges = (int) faces;
32534 out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
32535 }
32536
32537 // Loop the tetrahedronlist once, output the Voronoi edges. The index of
32538 // each Voronoi edge corresponding to the index of the Delaunay face.
32539 // The four faces' indices of each tetrahedron are saved in the list
32540 // 'tetfaceindexarray', in the entry of i, where i (0-based) is the
32541 // index of this tetrahedron (= vpointcount).
32542 tetfaceindexarray = new int[tetrahedrons->items * 4];
32543 tetrahedrons->traversalinit();
32544 tetloop.tet = tetrahedrontraverse();
32545 vedgecount = 0;
32546 index = 0;
32547 while (tetloop.tet != (tetrahedron *) NULL) {
32548 // Count the number of Voronoi edges. Look at the four faces of each
32549 // tetrahedron. Count the face if the tetrahedron's pointer is
32550 // smaller than its neighbor's or the neighbor is outside.
32551 end1 = * (int *) (tetloop.tet + elemmarkerindex);
32552 for (i = 0; i < 4; i++) {
32553 decode(tetloop.tet[i], worktet);
32554 if ((worktet.tet == dummytet) || (tetloop.tet < worktet.tet)) {
32555 if (out == (tetgenio *) NULL) {
32556 fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
32557 } else {
32558 vedge = &(out->vedgelist[index++]);
32559 vedge->v1 = end1 + shift;
32560 }
32561 end2 = * (int *) (worktet.tet + elemmarkerindex);
32562 // Note that end2 may be -1 (worktet.tet is outside).
32563 if (end2 == -1) {
32564 // Calculate the out normal of this hull face.
32565 worktet.tet = tetloop.tet;
32566 worktet.loc = i;
32567 worktet.ver = 1; // The CW edge ring.
32568 pt[0] = org(worktet);
32569 pt[1] = dest(worktet);
32570 pt[2] = apex(worktet);
32571 for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
32572 for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
32573 cross(vec1, vec2, infvec);
32574 // Normalize it.
32575 L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
32576 + infvec[2] * infvec[2]);
32577 if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
32578 if (out == (tetgenio *) NULL) {
32579 fprintf(outfile, " -1");
32580 fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
32581 } else {
32582 vedge->v2 = -1;
32583 vedge->vnormal[0] = infvec[0];
32584 vedge->vnormal[1] = infvec[1];
32585 vedge->vnormal[2] = infvec[2];
32586 }
32587 } else {
32588 if (out == (tetgenio *) NULL) {
32589 fprintf(outfile, " %4d\n", end2 + shift);
32590 } else {
32591 vedge->v2 = end2 + shift;
32592 vedge->vnormal[0] = 0.0;
32593 vedge->vnormal[1] = 0.0;
32594 vedge->vnormal[2] = 0.0;
32595 }
32596 }
32597 // Save the face index in this tet and its neighbor if exists.
32598 tetfaceindexarray[end1 * 4 + i] = vedgecount;
32599 if (end2 != -1) {
32600 tetfaceindexarray[end2 * 4 + worktet.loc] = vedgecount;
32601 }
32602 vedgecount++;
32603 }
32604 }
32605 tetloop.tet = tetrahedrontraverse();
32606 }
32607
32608 if (out == (tetgenio *) NULL) {
32609 fprintf(outfile, "# Generated by %s\n", b->commandline);
32610 fclose(outfile);
32611 }
32612
32613 // Output Voronoi faces to .v.face file.
32614 if (out == (tetgenio *) NULL) {
32615 strcpy(outfilename, b->outfilename);
32616 strcat(outfilename, ".v.face");
32617 }
32618
32619 if (!b->quiet) {
32620 if (out == (tetgenio *) NULL) {
32621 printf("Writing %s.\n", outfilename);
32622 } else {
32623 printf("Writing Voronoi faces.\n");
32624 }
32625 }
32626
32627 if (out == (tetgenio *) NULL) {
32628 outfile = fopen(outfilename, "w");
32629 if (outfile == (FILE *) NULL) {
32630 printf("File I/O Error: Cannot create file %s.\n", outfilename);
32631 terminatetetgen(1);
32632 }
32633 // Number of Voronoi faces.
32634 fprintf(outfile, "%ld 0\n", edges);
32635 } else {
32636 out->numberofvfacets = edges;
32637 out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
32638 if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
32639 printf("Error: Out of memory.\n");
32640 terminatetetgen(1);
32641 }
32642 }
32643
32644 // Loop the tetrahedronlist once, Output Voronoi facets. The index of each
32645 // Voronoi facet corresponding to the index of the Delaunay edge. The
32646 // six edges' indices of each tetrahedron are saved in the list 'tetedge-
32647 // indexarray', in the entry of i, where i (0-based) is the index of
32648 // this tetrahedron (= vpointcount).
32649 tetedgeindexarray = new int[tetrahedrons->items * 6];
32650 tetrahedrons->traversalinit();
32651 tetloop.tet = tetrahedrontraverse();
32652 vfacecount = 0;
32653 while (tetloop.tet != (tetrahedron *) NULL) {
32654 // Count the number of Voronoi faces. Look at the six edges of each
32655 // tetrahedron. Count the edge only if the tetrahedron's pointer is
32656 // smaller than those of all other tetrahedra that share the edge.
32657 worktet = tetloop;
32658 for (i = 0; i < 6; i++) {
32659 worktet.loc = edge2locver[i][0];
32660 worktet.ver = edge2locver[i][1];
32661 // Now count the number of tets surrounding this edge.
32662 tcount = 1;
32663 adjustedgering(worktet, CW);
32664 spintet = worktet;
32665 hitbdry = 0;
32666 while (hitbdry < 2) {
32667 if (fnextself(spintet)) {
32668 if (apex(spintet) == apex(worktet)) break;
32669 if (spintet.tet < worktet.tet) break;
32670 tcount++;
32671 } else {
32672 hitbdry++;
32673 if (hitbdry < 2) {
32674 esym(worktet, spintet);
32675 fnextself(spintet); // In the same tet.
32676 }
32677 }
32678 }
32679 // Count this edge if no adjacent tets are smaller than this tet.
32680 if (spintet.tet >= worktet.tet) {
32681 // Get the two endpoints of this edge.
32682 pt[0] = org(worktet);
32683 pt[1] = dest(worktet);
32684 end1 = pointmark(pt[0]) - in->firstnumber;
32685 end2 = pointmark(pt[1]) - in->firstnumber;
32686 if (out == (tetgenio *) NULL) {
32687 fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
32688 end1 + shift, end2 + shift, tcount + (hitbdry > 0));
32689 } else {
32690 vfacet = &(out->vfacetlist[vfacecount]);
32691 vfacet->c1 = end1 + shift;
32692 vfacet->c2 = end2 + shift;
32693 vfacet->elist = new int[tcount + (hitbdry > 0) + 1];
32694 vfacet->elist[0] = tcount + (hitbdry > 0);
32695 index = 1;
32696 }
32697 // If hitbdry > 0, then spintet is a hull face.
32698 if (hitbdry > 0) {
32699 // The edge list starts with a ray.
32700 vpointcount = * (int *) (spintet.tet + elemmarkerindex);
32701 vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc];
32702 if (out == (tetgenio *) NULL) {
32703 fprintf(outfile, " %d", vedgecount + shift);
32704 } else {
32705 vfacet->elist[index++] = vedgecount + shift;
32706 }
32707 // Save this facet number in tet.
32708 tetedgeindexarray[vpointcount * 6 +
32709 locver2edge[spintet.loc][spintet.ver]] = vfacecount;
32710 esymself(spintet);
32711 fnextself(spintet); // In the same tet.
32712 }
32713 // Output internal Voronoi edges.
32714 for (j = 0; j < tcount; j++) {
32715 vpointcount = * (int *) (spintet.tet + elemmarkerindex);
32716 vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc];
32717 if (out == (tetgenio *) NULL) {
32718 fprintf(outfile, " %d", vedgecount + shift);
32719 } else {
32720 vfacet->elist[index++] = vedgecount + shift;
32721 }
32722 // Save this facet number in tet.
32723 tetedgeindexarray[vpointcount * 6 +
32724 locver2edge[spintet.loc][spintet.ver]] = vfacecount;
32725 fnextself(spintet);
32726 }
32727 if (out == (tetgenio *) NULL) {
32728 fprintf(outfile, "\n");
32729 }
32730 vfacecount++;
32731 }
32732 } // if (i = 0; i < 6; i++)
32733 tetloop.tet = tetrahedrontraverse();
32734 }
32735
32736 if (out == (tetgenio *) NULL) {
32737 fprintf(outfile, "# Generated by %s\n", b->commandline);
32738 fclose(outfile);
32739 }
32740
32741 // Output Voronoi cells to .v.cell file.
32742 if (out == (tetgenio *) NULL) {
32743 strcpy(outfilename, b->outfilename);
32744 strcat(outfilename, ".v.cell");
32745 }
32746
32747 if (!b->quiet) {
32748 if (out == (tetgenio *) NULL) {
32749 printf("Writing %s.\n", outfilename);
32750 } else {
32751 printf("Writing Voronoi cells.\n");
32752 }
32753 }
32754
32755 if (out == (tetgenio *) NULL) {
32756 outfile = fopen(outfilename, "w");
32757 if (outfile == (FILE *) NULL) {
32758 printf("File I/O Error: Cannot create file %s.\n", outfilename);
32759 terminatetetgen(1);
32760 }
32761 // Number of Voronoi cells.
32762 fprintf(outfile, "%ld\n", points->items);
32763 } else {
32764 out->numberofvcells = points->items;
32765 out->vcelllist = new int*[out->numberofvcells];
32766 if (out->vcelllist == (int **) NULL) {
32767 printf("Error: Out of memory.\n");
32768 terminatetetgen(1);
32769 }
32770 }
32771
32772 // Loop through point list, for each point, output a Voronoi cell.
32773 tetlist = new list(sizeof(triface), NULL, 256);
32774 ptlist = new list(sizeof(point *), NULL, 256);
32775 points->traversalinit();
32776 ptloop = pointtraverse();
32777 vpointcount = 0;
32778 while (ptloop != (point) NULL) {
32779 decode(point2tet(ptloop), tetloop);
32780 // assert(!isdead(&tetloop));
32781 if (!isdead(&tetloop)) {
32782 // Form the star of p.
32783 tetlist->append(&tetloop);
32784 formstarpolyhedron(ptloop, tetlist, ptlist, true);
32785 tcount = ptlist->len();
32786 if (out == (tetgenio *) NULL) {
32787 fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
32788 } else {
32789 arraysize = tcount;
32790 vertarray = out->vcelllist[vpointcount];
32791 vertarray = new int[arraysize + 1];
32792 vertarray[0] = arraysize;
32793 index = 1;
32794 }
32795 // List Voronoi facets bounding this cell.
32796 for (i = 0; i < ptlist->len(); i++) {
32797 neipt = * (point *)(* ptlist)[i];
32798 // Find a tet in tetlist having edge (ptloop, neipt) -- Very Slow.
32799 for (j = 0; j < tetlist->len(); j++) {
32800 tetloop = * (triface *)(* tetlist)[j];
32801 for (k = 0; k < 6; k++) {
32802 tetloop.loc = edge2locver[k][0];
32803 tetloop.ver = edge2locver[k][1];
32804 if (org(tetloop) == ptloop) {
32805 if (dest(tetloop) == neipt) break;
32806 } else if (org(tetloop) == neipt) {
32807 if (dest(tetloop) == ptloop) break;
32808 }
32809 }
32810 if (k < 6) break; // Found this edge.
32811 }
32812 assert(j < tetlist->len());
32813 // k is the right edge number.
32814 end1 = * (int *) (tetloop.tet + elemmarkerindex);
32815 vfacecount = tetedgeindexarray[end1 * 6 + k];
32816 if (out == (tetgenio *) NULL) {
32817 fprintf(outfile, " %d", vfacecount + shift);
32818 } else {
32819 vertarray[index++] = vfacecount + shift;
32820 }
32821 } // for (i = 0; i < ptlist->len(); i++) {
32822 if (out == (tetgenio *) NULL) {
32823 fprintf(outfile, "\n");
32824 }
32825 vpointcount++;
32826 }
32827 tetlist->clear();
32828 ptlist->clear();
32829 ptloop = pointtraverse();
32830 }
32831 delete tetlist;
32832 delete ptlist;
32833 delete [] tetfaceindexarray;
32834 delete [] tetedgeindexarray;
32835
32836 if (out == (tetgenio *) NULL) {
32837 fprintf(outfile, "# Generated by %s\n", b->commandline);
32838 fclose(outfile);
32839 }
32840}
32841
32843// //
32844// outpbcnodes() Output pbc node pairs to a .pbc file or a structure. //
32845// //
32847
32848void tetgenmesh::outpbcnodes(tetgenio* out)
32849{
32850 FILE *outfile;
32851 char pbcfilename[FILENAMESIZE];
32852 list *ptpairlist;
32853 tetgenio::pbcgroup *pgi, *pgo;
32854 pbcdata *pd;
32855 face faceloop;
32856 face checkseg, symseg;
32857 point *ptpair, pa, pb;
32858 enum locateresult loc;
32859 REAL sympt[3], d1, d2;
32860 int *worklist;
32861 int firstindex, shift;
32862 int index, idx;
32863 int i, j, k, l;
32864
32865 if (out == (tetgenio *) NULL) {
32866 strcpy(pbcfilename, b->outfilename);
32867 strcat(pbcfilename, ".pbc");
32868 }
32869
32870 if (!b->quiet) {
32871 if (out == (tetgenio *) NULL) {
32872 printf("Writing %s.\n", pbcfilename);
32873 } else {
32874 printf("Writing pbc nodes.\n");
32875 }
32876 }
32877
32878 // Avoid compilation warnings.
32879 outfile = (FILE *) NULL;
32880 pgo = (tetgenio::pbcgroup *) NULL;
32881 index = 0;
32882
32883 if (out == (tetgenio *) NULL) {
32884 outfile = fopen(pbcfilename, "w");
32885 if (outfile == (FILE *) NULL) {
32886 printf("File I/O Error: Cannot create file %s.\n", pbcfilename);
32887 terminatetetgen(1);
32888 }
32889 // Number of pbc groups.
32890 fprintf(outfile, "# number of PBCs.\n");
32891 fprintf(outfile, "%d\n\n", in->numberofpbcgroups);
32892 } else {
32893 out->numberofpbcgroups = in->numberofpbcgroups;
32894 // Allocate memory for 'out->pbcgrouplist'.
32895 out->pbcgrouplist = new tetgenio::pbcgroup[in->numberofpbcgroups];
32896 // (Next line was a bug, reported by Murry Nigel).
32897 if (out->pbcgrouplist == (tetgenio::pbcgroup *) NULL) {
32898 printf("Error: Out of memory.\n");
32899 terminatetetgen(1);
32900 }
32901 }
32902
32903 ptpairlist = new list(2 * sizeof(point *), NULL, 256);
32904 worklist = new int[points->items + 1];
32905 for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
32906
32907 // Determine the first index (0 or 1).
32908 firstindex = b->zeroindex ? 0 : in->firstnumber;
32909 shift = 0; // Default no shiftment.
32910 if ((in->firstnumber == 1) && (firstindex == 0)) {
32911 shift = 1; // Shift the output indices by 1.
32912 }
32913
32914 for (i = 0; i < in->numberofpbcgroups; i++) {
32915 // Group i.
32916 pgi = &(in->pbcgrouplist[i]);
32917 if (out == (tetgenio *) NULL) {
32918 fprintf(outfile, "# PBC %d\n", in->firstnumber + i);
32919 // Output facet markers.
32920 fprintf(outfile, "%d %d\n", pgi->fmark1, pgi->fmark2);
32921 // Output transformation matrix.
32922 fprintf(outfile, "[\n");
32923 for (j = 0; j < 4; j++) {
32924 fprintf(outfile, " %.12g %.12g %.12g %.12g\n", pgi->transmat[j][0],
32925 pgi->transmat[j][1], pgi->transmat[j][2], pgi->transmat[j][3]);
32926 }
32927 fprintf(outfile, "]\n");
32928 } else {
32929 pgo = &(out->pbcgrouplist[i]);
32930 // Copy data from pgi to pgo.
32931 pgo->fmark1 = pgi->fmark1;
32932 pgo->fmark2 = pgi->fmark2;
32933 for (j = 0; j < 4; j++) {
32934 for (k = 0; k < 4; k++) pgo->transmat[j][k] = pgi->transmat[j][k];
32935 }
32936 }
32937
32938 // Find the point pairs of group i.
32939 subfaces->traversalinit();
32940 faceloop.sh = shellfacetraverse(subfaces);
32941 while (faceloop.sh != (shellface *) NULL) {
32942 if (shellpbcgroup(faceloop) == i) {
32943 // It is in group i. Operate on it if it has pgi->fmark1.
32944 idx = shellmark(faceloop) - 1;
32945 if (in->facetmarkerlist[idx] == pgi->fmark1) {
32946 // Loop three edges of the subface.
32947 for (j = 0; j < 3; j++) {
32948 sspivot(faceloop, checkseg);
32949 // Loop two vertices of the edge.
32950 for (k = 0; k < 2; k++) {
32951 if (k == 0) pa = sorg(faceloop);
32952 else pa = sdest(faceloop);
32953 if (worklist[pointmark(pa)] == 0) {
32954 pb = (point) NULL;
32955 if (checkseg.sh != dummysh) {
32956 // pa is on a segment. Find pb.
32957 // Find the incident pbcgroup of checkseg.
32958 idx = shellmark(checkseg) - 1;
32959 for (l = idx2segpglist[idx]; l < idx2segpglist[idx + 1];
32960 l++) {
32961 pd = (pbcdata *)(* segpbcgrouptable)[segpglist[l]];
32962 if (((pd->fmark[0] == pgi->fmark1) &&
32963 (pd->fmark[1] == pgi->fmark2)) ||
32964 ((pd->fmark[0] == pgi->fmark2) &&
32965 (pd->fmark[1] == pgi->fmark1))) break;
32966 }
32967#ifdef SELF_CHECK
32968 assert(l < idx2segpglist[idx + 1]);
32969#endif
32970 loc = getsegpbcsympoint(pa, &checkseg, sympt, &symseg,
32971 segpglist[l]);
32972 if (loc != ONVERTEX) {
32973 // Not found a match point! It may be caused by the
32974 // pair of input vertices don't have enough digits.
32975 // Choose a near vertex.
32976 d1 = distance(sympt, sorg(symseg));
32977 d2 = distance(sympt, sdest(symseg));
32978 if (d1 > d2) sesymself(symseg);
32979 }
32980 pb = sorg(symseg);
32981 } else {
32982 // Operate on pa if it is inside the facet.
32983 if (pointtype(pa) == FREESUBVERTEX) {
32984 pb = point2pbcpt(pa);
32985 }
32986 }
32987 if (pb != (point) NULL) {
32988 // Add the pair (pa, pb) into list.
32989 ptpair = (point *) ptpairlist->append(NULL);
32990 ptpair[0] = pa;
32991 ptpair[1] = pb;
32992 // Mark pa (avoid to operate on it later).
32993 worklist[pointmark(pa)] = 1;
32994 }
32995 }
32996 }
32997 // Get the next edge.
32998 senextself(faceloop);
32999 }
33000 }
33001 }
33002 faceloop.sh = shellfacetraverse(subfaces);
33003 }
33004
33005 // Output the list of pbc points.
33006 if (out == (tetgenio *) NULL) {
33007 fprintf(outfile, "%d\n", ptpairlist->len());
33008 } else {
33009 pgo->numberofpointpairs = ptpairlist->len();
33010 pgo->pointpairlist = new int[pgo->numberofpointpairs * 2];
33011 index = 0;
33012 }
33013 for (j = 0; j < ptpairlist->len(); j++) {
33014 ptpair = (point *)(* ptpairlist)[j];
33015 pa = ptpair[0];
33016 pb = ptpair[1];
33017 if (out == (tetgenio *) NULL) {
33018 fprintf(outfile, " %4d %4d\n", pointmark(pa) - shift,
33019 pointmark(pb) - shift);
33020 } else {
33021 pgo->pointpairlist[index++] = pointmark(pa) - shift;
33022 pgo->pointpairlist[index++] = pointmark(pb) - shift;
33023 }
33024 // Unmark pa.
33025 worklist[pointmark(pa)] = 0;
33026 }
33027 if (out == (tetgenio *) NULL) {
33028 fprintf(outfile, "\n");
33029 }
33030 ptpairlist->clear();
33031 }
33032
33033 delete [] worklist;
33034 delete ptpairlist;
33035
33036 if (out == (tetgenio *) NULL) {
33037 fprintf(outfile, "# Generated by %s\n", b->commandline);
33038 fclose(outfile);
33039 }
33040}
33041
33043// //
33044// outsmesh() Write surface mesh to a .smesh file, which can be read and //
33045// tetrahedralized by TetGen. //
33046// //
33047// You can specify a filename (without suffix) in 'smfilename'. If you don't //
33048// supply a filename (let smfilename be NULL), the default name stored in //
33049// 'tetgenbehavior' will be used. //
33050// //
33052
33053void tetgenmesh::outsmesh(char* smfilename)
33054{
33055 FILE *outfile;
33056 char nodfilename[FILENAMESIZE];
33057 char smefilename[FILENAMESIZE];
33058 face faceloop;
33059 point p1, p2, p3;
33060 int firstindex, shift;
33061 int bmark;
33062 int faceid, marker;
33063 int i;
33064
33065 if (smfilename != (char *) NULL && smfilename[0] != '\0') {
33066 strcpy(smefilename, smfilename);
33067 } else if (b->outfilename[0] != '\0') {
33068 strcpy(smefilename, b->outfilename);
33069 } else {
33070 strcpy(smefilename, "unnamed");
33071 }
33072 strcpy(nodfilename, smefilename);
33073 strcat(smefilename, ".smesh");
33074 strcat(nodfilename, ".node");
33075
33076 if (!b->quiet) {
33077 printf("Writing %s.\n", smefilename);
33078 }
33079 outfile = fopen(smefilename, "w");
33080 if (outfile == (FILE *) NULL) {
33081 printf("File I/O Error: Cannot create file %s.\n", smefilename);
33082 return;
33083 }
33084
33085 // Determine the first index (0 or 1).
33086 firstindex = b->zeroindex ? 0 : in->firstnumber;
33087 shift = 0; // Default no shiftment.
33088 if ((in->firstnumber == 1) && (firstindex == 0)) {
33089 shift = 1; // Shift the output indices by 1.
33090 }
33091
33092 fprintf(outfile, "# %s. TetGen's input file.\n", smefilename);
33093 fprintf(outfile, "\n# part 1: node list.\n");
33094 fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename);
33095
33096 marker = 0; // avoid compile warning.
33097 bmark = !b->nobound && in->facetmarkerlist;
33098
33099 fprintf(outfile, "\n# part 2: facet list.\n");
33100 // Number of facets, boundary marker.
33101 fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
33102
33103 subfaces->traversalinit();
33104 faceloop.sh = shellfacetraverse(subfaces);
33105 while (faceloop.sh != (shellface *) NULL) {
33106 p1 = sorg(faceloop);
33107 p2 = sdest(faceloop);
33108 p3 = sapex(faceloop);
33109 if (bmark) {
33110 faceid = shellmark(faceloop) - 1;
33111 if (faceid >= 0) {
33112 marker = in->facetmarkerlist[faceid];
33113 } else {
33114 marker = 0; // This subface must be added manually later.
33115 }
33116 }
33117 fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift,
33118 pointmark(p2) - shift, pointmark(p3) - shift);
33119 if (bmark) {
33120 fprintf(outfile, " %d", marker);
33121 }
33122 fprintf(outfile, "\n");
33123 faceloop.sh = shellfacetraverse(subfaces);
33124 }
33125
33126 // Copy input holelist.
33127 fprintf(outfile, "\n# part 3: hole list.\n");
33128 fprintf(outfile, "%d\n", in->numberofholes);
33129 for (i = 0; i < in->numberofholes; i++) {
33130 fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber,
33131 in->holelist[i * 3], in->holelist[i * 3 + 1],
33132 in->holelist[i * 3 + 2]);
33133 }
33134
33135 // Copy input regionlist.
33136 fprintf(outfile, "\n# part 4: region list.\n");
33137 fprintf(outfile, "%d\n", in->numberofregions);
33138 for (i = 0; i < in->numberofregions; i++) {
33139 fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber,
33140 in->regionlist[i * 5], in->regionlist[i * 5 + 1],
33141 in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
33142 in->regionlist[i * 5 + 4]);
33143 }
33144
33145 fprintf(outfile, "# Generated by %s\n", b->commandline);
33146 fclose(outfile);
33147}
33148
33150// //
33151// outmesh2medit() Write mesh to a .mesh file, which can be read and //
33152// rendered by Medit (a free mesh viewer from INRIA). //
33153// //
33154// You can specify a filename (without suffix) in 'mfilename'. If you don't //
33155// supply a filename (let mfilename be NULL), the default name stored in //
33156// 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
33157// //
33159
33160void tetgenmesh::outmesh2medit(char* mfilename)
33161{
33162 FILE *outfile;
33163 char mefilename[FILENAMESIZE];
33164 tetrahedron* tetptr;
33165 triface tface, tsymface;
33166 face segloop, checkmark;
33167 point ptloop, p1, p2, p3, p4;
33168 long faces;
33169 int pointnumber;
33170 int i;
33171
33172 if (mfilename != (char *) NULL && mfilename[0] != '\0') {
33173 strcpy(mefilename, mfilename);
33174 } else if (b->outfilename[0] != '\0') {
33175 strcpy(mefilename, b->outfilename);
33176 } else {
33177 strcpy(mefilename, "unnamed");
33178 }
33179 strcat(mefilename, ".mesh");
33180
33181 if (!b->quiet) {
33182 printf("Writing %s.\n", mefilename);
33183 }
33184 outfile = fopen(mefilename, "w");
33185 if (outfile == (FILE *) NULL) {
33186 printf("File I/O Error: Cannot create file %s.\n", mefilename);
33187 return;
33188 }
33189
33190 fprintf(outfile, "MeshVersionFormatted 1\n");
33191 fprintf(outfile, "\n");
33192 fprintf(outfile, "Dimension\n");
33193 fprintf(outfile, "3\n");
33194 fprintf(outfile, "\n");
33195
33196 fprintf(outfile, "\n# Set of mesh vertices\n");
33197 fprintf(outfile, "Vertices\n");
33198 fprintf(outfile, "%ld\n", points->items);
33199
33200 points->traversalinit();
33201 ptloop = pointtraverse();
33202 pointnumber = 1; // Medit need start number form 1.
33203 while (ptloop != (point) NULL) {
33204 // Point coordinates.
33205 fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
33206 if (in->numberofpointattributes > 0) {
33207 // Write an attribute, ignore others if more than one.
33208 fprintf(outfile, " %.17g\n", ptloop[3]);
33209 } else {
33210 fprintf(outfile, " 0\n");
33211 }
33212 setpointmark(ptloop, pointnumber);
33213 ptloop = pointtraverse();
33214 pointnumber++;
33215 }
33216
33217 // Compute the number of edges.
33218 faces = (4l * tetrahedrons->items + hullsize) / 2l;
33219
33220 fprintf(outfile, "\n# Set of Triangles\n");
33221 fprintf(outfile, "Triangles\n");
33222 fprintf(outfile, "%ld\n", faces);
33223
33224 tetrahedrons->traversalinit();
33225 tface.tet = tetrahedrontraverse();
33226 // To loop over the set of faces, loop over all tetrahedra, and look at
33227 // the four faces of each tetrahedron. If there isn't another tetrahedron
33228 // adjacent to the face, operate on the face. If there is another adj-
33229 // acent tetrahedron, operate on the face only if the current tetrahedron
33230 // has a smaller pointer than its neighbor. This way, each face is
33231 // considered only once.
33232 while (tface.tet != (tetrahedron *) NULL) {
33233 for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
33234 sym(tface, tsymface);
33235 if (tface.tet < tsymface.tet || tsymface.tet == dummytet) {
33236 p1 = org (tface);
33237 p2 = dest(tface);
33238 p3 = apex(tface);
33239 fprintf(outfile, "%5d %5d %5d",
33240 pointmark(p1), pointmark(p2), pointmark(p3));
33241 fprintf(outfile, " 0\n");
33242 }
33243 }
33244 tface.tet = tetrahedrontraverse();
33245 }
33246
33247 fprintf(outfile, "\n# Set of Tetrahedra\n");
33248 fprintf(outfile, "Tetrahedra\n");
33249 fprintf(outfile, "%ld\n", tetrahedrons->items);
33250
33251 tetrahedrons->traversalinit();
33252 tetptr = tetrahedrontraverse();
33253 while (tetptr != (tetrahedron *) NULL) {
33254 p1 = (point) tetptr[4];
33255 p2 = (point) tetptr[5];
33256 p3 = (point) tetptr[6];
33257 p4 = (point) tetptr[7];
33258 fprintf(outfile, "%5d %5d %5d %5d",
33259 pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
33260 if (in->numberoftetrahedronattributes > 0) {
33261 fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
33262 } else {
33263 fprintf(outfile, " 0");
33264 }
33265 fprintf(outfile, "\n");
33266 tetptr = tetrahedrontraverse();
33267 }
33268
33269 fprintf(outfile, "\nCorners\n");
33270 fprintf(outfile, "%d\n", in->numberofpoints);
33271
33272 for (i = 0; i < in->numberofpoints; i++) {
33273 fprintf(outfile, "%4d\n", i + 1);
33274 }
33275
33276 if (b->useshelles) {
33277 fprintf(outfile, "\nEdges\n");
33278 fprintf(outfile, "%ld\n", subsegs->items);
33279
33280 subsegs->traversalinit();
33281 segloop.sh = shellfacetraverse(subsegs);
33282 while (segloop.sh != (shellface *) NULL) {
33283 p1 = sorg(segloop);
33284 p2 = sdest(segloop);
33285 fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2));
33286 fprintf(outfile, " 0\n");
33287 segloop.sh = shellfacetraverse(subsegs);
33288 }
33289 }
33290
33291 fprintf(outfile, "\nEnd\n");
33292 fclose(outfile);
33293}
33294
33296// //
33297// outmesh2gid() Write mesh to a .ele.msh file and a .face.msh file, //
33298// which can be imported and rendered by Gid. //
33299// //
33300// You can specify a filename (without suffix) in 'gfilename'. If you don't //
33301// supply a filename (let gfilename be NULL), the default name stored in //
33302// 'tetgenbehavior' will be used. The suffixes (.ele.msh and .face.msh) will //
33303// be automatically added. //
33304// //
33306
33307void tetgenmesh::outmesh2gid(char* gfilename)
33308{
33309 FILE *outfile;
33310 char gidfilename[FILENAMESIZE];
33311 tetrahedron* tetptr;
33312 triface tface, tsymface;
33313 face sface;
33314 point ptloop, p1, p2, p3, p4;
33315 int pointnumber;
33316 int elementnumber;
33317
33318 if (gfilename != (char *) NULL && gfilename[0] != '\0') {
33319 strcpy(gidfilename, gfilename);
33320 } else if (b->outfilename[0] != '\0') {
33321 strcpy(gidfilename, b->outfilename);
33322 } else {
33323 strcpy(gidfilename, "unnamed");
33324 }
33325 strcat(gidfilename, ".ele.msh");
33326
33327 if (!b->quiet) {
33328 printf("Writing %s.\n", gidfilename);
33329 }
33330 outfile = fopen(gidfilename, "w");
33331 if (outfile == (FILE *) NULL) {
33332 printf("File I/O Error: Cannot create file %s.\n", gidfilename);
33333 return;
33334 }
33335
33336 fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n");
33337 fprintf(outfile, "coordinates\n");
33338
33339 points->traversalinit();
33340 ptloop = pointtraverse();
33341 pointnumber = 1; // Gid need start number form 1.
33342 while (ptloop != (point) NULL) {
33343 // Point coordinates.
33344 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
33345 ptloop[0], ptloop[1], ptloop[2]);
33346 if (in->numberofpointattributes > 0) {
33347 // Write an attribute, ignore others if more than one.
33348 fprintf(outfile, " %.17g", ptloop[3]);
33349 }
33350 fprintf(outfile, "\n");
33351 setpointmark(ptloop, pointnumber);
33352 ptloop = pointtraverse();
33353 pointnumber++;
33354 }
33355
33356 fprintf(outfile, "end coordinates\n");
33357 fprintf(outfile, "elements\n");
33358
33359 tetrahedrons->traversalinit();
33360 tetptr = tetrahedrontraverse();
33361 elementnumber = 1;
33362 while (tetptr != (tetrahedron *) NULL) {
33363 p1 = (point) tetptr[4];
33364 p2 = (point) tetptr[5];
33365 p3 = (point) tetptr[6];
33366 p4 = (point) tetptr[7];
33367 fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
33368 pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
33369 if (in->numberoftetrahedronattributes > 0) {
33370 fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
33371 }
33372 fprintf(outfile, "\n");
33373 tetptr = tetrahedrontraverse();
33374 elementnumber++;
33375 }
33376
33377 fprintf(outfile, "end elements\n");
33378 fclose(outfile);
33379
33380 if (gfilename != (char *) NULL && gfilename[0] != '\0') {
33381 strcpy(gidfilename, gfilename);
33382 } else if (b->outfilename[0] != '\0') {
33383 strcpy(gidfilename, b->outfilename);
33384 } else {
33385 strcpy(gidfilename, "unnamed");
33386 }
33387 strcat(gidfilename, ".face.msh");
33388
33389 if (!b->quiet) {
33390 printf("Writing %s.\n", gidfilename);
33391 }
33392 outfile = fopen(gidfilename, "w");
33393 if (outfile == (FILE *) NULL) {
33394 printf("File I/O Error: Cannot create file %s.\n", gidfilename);
33395 return;
33396 }
33397
33398 fprintf(outfile, "mesh dimension = 3 elemtype triangle nnode = 3\n");
33399 fprintf(outfile, "coordinates\n");
33400
33401 points->traversalinit();
33402 ptloop = pointtraverse();
33403 pointnumber = 1; // Gid need start number form 1.
33404 while (ptloop != (point) NULL) {
33405 // Point coordinates.
33406 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
33407 ptloop[0], ptloop[1], ptloop[2]);
33408 if (in->numberofpointattributes > 0) {
33409 // Write an attribute, ignore others if more than one.
33410 fprintf(outfile, " %.17g", ptloop[3]);
33411 }
33412 fprintf(outfile, "\n");
33413 setpointmark(ptloop, pointnumber);
33414 ptloop = pointtraverse();
33415 pointnumber++;
33416 }
33417
33418 fprintf(outfile, "end coordinates\n");
33419 fprintf(outfile, "elements\n");
33420
33421 tetrahedrons->traversalinit();
33422 tface.tet = tetrahedrontraverse();
33423 elementnumber = 1;
33424 while (tface.tet != (tetrahedron *) NULL) {
33425 for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
33426 sym(tface, tsymface);
33427 if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
33428 p1 = org(tface);
33429 p2 = dest(tface);
33430 p3 = apex(tface);
33431 if (tsymface.tet == dummytet) {
33432 // It's a hull face, output it.
33433 fprintf(outfile, "%5d %d %d %d\n", elementnumber,
33434 pointmark(p1), pointmark(p2), pointmark(p3));
33435 elementnumber++;
33436 } else if (b->useshelles) {
33437 // Only output it if it's a subface.
33438 tspivot(tface, sface);
33439 if (sface.sh != dummysh) {
33440 fprintf(outfile, "%5d %d %d %d\n", elementnumber,
33441 pointmark(p1), pointmark(p2), pointmark(p3));
33442 elementnumber++;
33443 }
33444 }
33445 }
33446 }
33447 tface.tet = tetrahedrontraverse();
33448 }
33449
33450 fprintf(outfile, "end elements\n");
33451 fclose(outfile);
33452}
33453
33455// //
33456// outmesh2off() Write the mesh to an .off file. //
33457// //
33458// .off, the Object File Format, is one of the popular file formats from the //
33459// Geometry Center's Geomview package (http://www.geomview.org). //
33460// //
33462
33463void tetgenmesh::outmesh2off(char* ofilename)
33464{
33465 FILE *outfile;
33466 char offfilename[FILENAMESIZE];
33467 triface tface, tsymface;
33468 point ptloop, p1, p2, p3;
33469 long faces;
33470 int shift;
33471
33472 if (ofilename != (char *) NULL && ofilename[0] != '\0') {
33473 strcpy(offfilename, ofilename);
33474 } else if (b->outfilename[0] != '\0') {
33475 strcpy(offfilename, b->outfilename);
33476 } else {
33477 strcpy(offfilename, "unnamed");
33478 }
33479 strcat(offfilename, ".off");
33480
33481 if (!b->quiet) {
33482 printf("Writing %s.\n", offfilename);
33483 }
33484 outfile = fopen(offfilename, "w");
33485 if (outfile == (FILE *) NULL) {
33486 printf("File I/O Error: Cannot create file %s.\n", offfilename);
33487 return;
33488 }
33489
33490 // Calculate the number of triangular faces in the tetrahedral mesh.
33491 faces = (4l * tetrahedrons->items + hullsize) / 2l;
33492
33493 // Number of points, faces, and edges(not used, here show hullsize).
33494 fprintf(outfile, "OFF\n%ld %ld %ld\n", points->items, faces, hullsize);
33495
33496 // Write the points.
33497 points->traversalinit();
33498 ptloop = pointtraverse();
33499 while (ptloop != (point) NULL) {
33500 fprintf(outfile, " %.17g %.17g %.17g\n",ptloop[0], ptloop[1], ptloop[2]);
33501 ptloop = pointtraverse();
33502 }
33503
33504 // OFF always use zero as the first index.
33505 shift = in->firstnumber == 1 ? 1 : 0;
33506
33507 tetrahedrons->traversalinit();
33508 tface.tet = tetrahedrontraverse();
33509 // To loop over the set of faces, loop over all tetrahedra, and look at
33510 // the four faces of each tetrahedron. If there isn't another tetrahedron
33511 // adjacent to the face, operate on the face. If there is another adj-
33512 // acent tetrahedron, operate on the face only if the current tetrahedron
33513 // has a smaller pointer than its neighbor. This way, each face is
33514 // considered only once.
33515 while (tface.tet != (tetrahedron *) NULL) {
33516 for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
33517 sym(tface, tsymface);
33518 if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
33519 p1 = org(tface);
33520 p2 = dest(tface);
33521 p3 = apex(tface);
33522 // Face number, indices of three vertexs.
33523 fprintf(outfile, "3 %4d %4d %4d\n", pointmark(p1) - shift,
33524 pointmark(p2) - shift, pointmark(p3) - shift);
33525 }
33526 }
33527 tface.tet = tetrahedrontraverse();
33528 }
33529
33530 fprintf(outfile, "# Generated by %s\n", b->commandline);
33531 fclose(outfile);
33532}
33533
33534//
33535// End of I/O rouitnes
33536//
33537
33538//
33539// Begin of user interaction routines
33540//
33541
33543// //
33544// internalerror() Ask the user to send me the defective product. Exit. //
33545// //
33547
33548void tetgenmesh::internalerror()
33549{
33550 printf(" Please report this bug to sihang@mail.berlios.de. Include the\n");
33551 printf(" message above, your input data set, and the exact command\n");
33552 printf(" line you used to run this program, thank you.\n");
33553 terminatetetgen(2);
33554}
33555
33557// //
33558// checkmesh() Test the mesh for topological consistency. //
33559// //
33561
33562void tetgenmesh::checkmesh()
33563{
33564 triface tetraloop;
33565 triface oppotet, oppooppotet;
33566 point tetorg, tetdest, tetapex, tetoppo;
33567 REAL oritest;
33568 int horrors;
33569
33570 if (!b->quiet) {
33571 printf(" Checking consistency of mesh...\n");
33572 }
33573
33574 horrors = 0;
33575 // Run through the list of tetrahedra, checking each one.
33576 tetrahedrons->traversalinit();
33577 tetraloop.tet = tetrahedrontraverse();
33578 while (tetraloop.tet != (tetrahedron *) NULL) {
33579 // Check all four faces of the tetrahedron.
33580 for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
33581 tetorg = org(tetraloop);
33582 tetdest = dest(tetraloop);
33583 tetapex = apex(tetraloop);
33584 tetoppo = oppo(tetraloop);
33585 if (tetraloop.loc == 0) { // Only test for inversion once.
33586 oritest = orient3d(tetorg, tetdest, tetapex, tetoppo);
33587 if (oritest >= 0.0) {
33588 printf(" !! !! %s ", oritest > 0.0 ? "Inverted" : "Degenerated");
33589 printtet(&tetraloop);
33590 printf(" orient3d = %.17g.\n", oritest);
33591 horrors++;
33592 }
33593 }
33594 // Find the neighboring tetrahedron on this face.
33595 sym(tetraloop, oppotet);
33596 if (oppotet.tet != dummytet) {
33597 // Check that the tetrahedron's neighbor knows it's a neighbor.
33598 sym(oppotet, oppooppotet);
33599 if ((tetraloop.tet != oppooppotet.tet)
33600 || (tetraloop.loc != oppooppotet.loc)) {
33601 printf(" !! !! Asymmetric tetra-tetra bond:\n");
33602 if (tetraloop.tet == oppooppotet.tet) {
33603 printf(" (Right tetrahedron, wrong orientation)\n");
33604 }
33605 printf(" First ");
33606 printtet(&tetraloop);
33607 printf(" Second (nonreciprocating) ");
33608 printtet(&oppotet);
33609 horrors++;
33610 }
33611 }
33612 }
33613 tetraloop.tet = tetrahedrontraverse();
33614 }
33615 if (horrors == 0) {
33616 if (!b->quiet) {
33617 printf(" In my studied opinion, the mesh appears to be consistent.\n");
33618 }
33619 } else if (horrors == 1) {
33620 printf(" !! !! !! !! Precisely one festering wound discovered.\n");
33621 } else {
33622 printf(" !! !! !! !! %d abominations witnessed.\n", horrors);
33623 }
33624}
33625
33627// //
33628// checkshells() Test the boundary mesh for topological consistency. //
33629// //
33631
33632void tetgenmesh::checkshells()
33633{
33634 triface oppotet, oppooppotet, testtet;
33635 face shloop, segloop, spin;
33636 face testsh, testseg, testshsh;
33637 point shorg, shdest, segorg, segdest;
33638 REAL checksign;
33639 bool same;
33640 int horrors;
33641 int i;
33642
33643 if (!b->quiet) {
33644 printf(" Checking consistency of the mesh boundary...\n");
33645 }
33646 horrors = 0;
33647
33648 // Run through the list of subfaces, checking each one.
33649 subfaces->traversalinit();
33650 shloop.sh = shellfacetraverse(subfaces);
33651 while (shloop.sh != (shellface *) NULL) {
33652 // Check two connected tetrahedra if they exist.
33653 shloop.shver = 0;
33654 stpivot(shloop, oppotet);
33655 if (oppotet.tet != dummytet) {
33656 tspivot(oppotet, testsh);
33657 if (testsh.sh != shloop.sh) {
33658 printf(" !! !! Wrong tetra-subface connection.\n");
33659 printf(" Tetra: ");
33660 printtet(&oppotet);
33661 printf(" Subface: ");
33662 printsh(&shloop);
33663 horrors++;
33664 }
33665 if (oppo(oppotet) != (point) NULL) {
33666 adjustedgering(oppotet, CCW);
33667 checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop),
33668 oppo(oppotet));
33669 if (checksign >= 0.0) {
33670 printf(" !! !! Wrong subface orientation.\n");
33671 printf(" Subface: ");
33672 printsh(&shloop);
33673 horrors++;
33674 }
33675 }
33676 }
33677 sesymself(shloop);
33678 stpivot(shloop, oppooppotet);
33679 if (oppooppotet.tet != dummytet) {
33680 tspivot(oppooppotet, testsh);
33681 if (testsh.sh != shloop.sh) {
33682 printf(" !! !! Wrong tetra-subface connection.\n");
33683 printf(" Tetra: ");
33684 printtet(&oppooppotet);
33685 printf(" Subface: ");
33686 printsh(&shloop);
33687 horrors++;
33688 }
33689 if (oppotet.tet != dummytet) {
33690 sym(oppotet, testtet);
33691 if (testtet.tet != oppooppotet.tet) {
33692 printf(" !! !! Wrong tetra-subface-tetra connection.\n");
33693 printf(" Tetra 1: ");
33694 printtet(&oppotet);
33695 printf(" Subface: ");
33696 printsh(&shloop);
33697 printf(" Tetra 2: ");
33698 printtet(&oppooppotet);
33699 horrors++;
33700 }
33701 }
33702 if (oppo(oppooppotet) != (point) NULL) {
33703 adjustedgering(oppooppotet, CCW);
33704 checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop),
33705 oppo(oppooppotet));
33706 if (checksign >= 0.0) {
33707 printf(" !! !! Wrong subface orientation.\n");
33708 printf(" Subface: ");
33709 printsh(&shloop);
33710 horrors++;
33711 }
33712 }
33713 }
33714 // Check connection between subfaces.
33715 shloop.shver = 0;
33716 for (i = 0; i < 3; i++) {
33717 shorg = sorg(shloop);
33718 shdest = sdest(shloop);
33719 sspivot(shloop, testseg);
33720 if (testseg.sh != dummysh) {
33721 segorg = sorg(testseg);
33722 segdest = sdest(testseg);
33723 same = ((shorg == segorg) && (shdest == segdest))
33724 || ((shorg == segdest) && (shdest == segorg));
33725 if (!same) {
33726 printf(" !! !! Wrong subface-subsegment connection.\n");
33727 printf(" Subface: ");
33728 printsh(&shloop);
33729 printf(" Subsegment: ");
33730 printsh(&testseg);
33731 horrors++;
33732 }
33733 }
33734 spivot(shloop, testsh);
33735 if (testsh.sh != dummysh) {
33736 segorg = sorg(testsh);
33737 segdest = sdest(testsh);
33738 same = ((shorg == segorg) && (shdest == segdest))
33739 || ((shorg == segdest) && (shdest == segorg));
33740 if (!same) {
33741 printf(" !! !! Wrong subface-subface connection.\n");
33742 printf(" Subface 1: ");
33743 printsh(&shloop);
33744 printf(" Subface 2: ");
33745 printsh(&testsh);
33746 horrors++;
33747 }
33748 spivot(testsh, testshsh);
33749 shorg = sorg(testshsh);
33750 shdest = sdest(testshsh);
33751 same = ((shorg == segorg) && (shdest == segdest))
33752 || ((shorg == segdest) && (shdest == segorg));
33753 if (!same) {
33754 printf(" !! !! Wrong subface-subface connection.\n");
33755 printf(" Subface 1: ");
33756 printsh(&testsh);
33757 printf(" Subface 2: ");
33758 printsh(&testshsh);
33759 horrors++;
33760 }
33761 if (testseg.sh == dummysh) {
33762 if (testshsh.sh != shloop.sh) {
33763 printf(" !! !! Wrong subface-subface connection.\n");
33764 printf(" Subface 1: ");
33765 printsh(&shloop);
33766 printf(" Subface 2: ");
33767 printsh(&testsh);
33768 horrors++;
33769 }
33770 }
33771 }
33772 senextself(shloop);
33773 }
33774 shloop.sh = shellfacetraverse(subfaces);
33775 }
33776
33777 // Run through the list of subsegs, checking each one.
33778 subsegs->traversalinit();
33779 segloop.sh = shellfacetraverse(subsegs);
33780 while (segloop.sh != (shellface *) NULL) {
33781 segorg = sorg(segloop);
33782 segdest = sdest(segloop);
33783 spivot(segloop, testsh);
33784 if (testsh.sh == dummysh) {
33785 printf(" !! !! Wrong subsegment-subface connection.\n");
33786 printf(" Subsegment: ");
33787 printsh(&segloop);
33788 horrors++;
33789 segloop.sh = shellfacetraverse(subsegs);
33790 continue;
33791 }
33792 shorg = sorg(testsh);
33793 shdest = sdest(testsh);
33794 same = ((shorg == segorg) && (shdest == segdest))
33795 || ((shorg == segdest) && (shdest == segorg));
33796 if (!same) {
33797 printf(" !! !! Wrong subsegment-subface connection.\n");
33798 printf(" Subsegment : ");
33799 printsh(&segloop);
33800 printf(" Subface : ");
33801 printsh(&testsh);
33802 horrors++;
33803 segloop.sh = shellfacetraverse(subsegs);
33804 continue;
33805 }
33806 // Check the connection of face loop around this subsegment.
33807 spin = testsh;
33808 i = 0;
33809 do {
33810 spivotself(spin);
33811 shorg = sorg(spin);
33812 shdest = sdest(spin);
33813 same = ((shorg == segorg) && (shdest == segdest))
33814 || ((shorg == segdest) && (shdest == segorg));
33815 if (!same) {
33816 printf(" !! !! Wrong subsegment-subface connection.\n");
33817 printf(" Subsegment : ");
33818 printsh(&segloop);
33819 printf(" Subface : ");
33820 printsh(&testsh);
33821 horrors++;
33822 break;
33823 }
33824 i++;
33825 } while (spin.sh != testsh.sh && i < 1000);
33826 if (i >= 1000) {
33827 printf(" !! !! Wrong subsegment-subface connection.\n");
33828 printf(" Subsegment : ");
33829 printsh(&segloop);
33830 horrors++;
33831 }
33832 segloop.sh = shellfacetraverse(subsegs);
33833 }
33834 if (horrors == 0) {
33835 if (!b->quiet) {
33836 printf(" Mesh boundaries connected correctly.\n");
33837 }
33838 } else {
33839 printf(" !! !! !! !! %d boundary connection viewed with horror.\n",
33840 horrors);
33841 return;
33842 }
33843}
33844
33846// //
33847// checkdelaunay() Ensure that the mesh is constrained Delaunay. //
33848// //
33849// If 'flipqueue' is not NULL, non-locally Delaunay faces are saved in it. //
33850// //
33852
33853void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue)
33854{
33855 triface tetraloop;
33856 triface oppotet;
33857 face opposhelle;
33858 point tetorg, tetdest, tetapex, tetoppo;
33859 point oppooppo;
33860 enum fliptype fc;
33861 REAL sign;
33862 int shouldbedelaunay;
33863 int horrors;
33864
33865 if (!b->quiet) {
33866 printf(" Checking Delaunay property of the mesh...\n");
33867 }
33868 horrors = 0;
33869 // Run through the list of triangles, checking each one.
33870 tetrahedrons->traversalinit();
33871 tetraloop.tet = tetrahedrontraverse();
33872 while (tetraloop.tet != (tetrahedron *) NULL) {
33873 // Check all four faces of the tetrahedron.
33874 for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
33875 tetorg = org(tetraloop);
33876 tetdest = dest(tetraloop);
33877 tetapex = apex(tetraloop);
33878 tetoppo = oppo(tetraloop);
33879 sym(tetraloop, oppotet);
33880 oppooppo = oppo(oppotet);
33881 // Only do testif there is an adjoining tetrahedron whose pointer is
33882 // larger (to ensure that each pair isn't tested twice).
33883 shouldbedelaunay = (oppotet.tet != dummytet)
33884 && (tetoppo != (point) NULL)
33885 && (oppooppo != (point) NULL)
33886 && (tetraloop.tet < oppotet.tet);
33887 if (checksubfaces && shouldbedelaunay) {
33888 // If a shell face separates the tetrahedra, then the face is
33889 // constrained, so no local Delaunay test should be done.
33890 tspivot(tetraloop, opposhelle);
33891 if (opposhelle.sh != dummysh){
33892 shouldbedelaunay = 0;
33893 }
33894 }
33895 if (shouldbedelaunay) {
33896 sign = insphere(tetdest, tetorg, tetapex, tetoppo, oppooppo);
33897 if ((sign > 0.0) && (eps > 0.0)) {
33898 if (iscospheric(tetdest, tetorg, tetapex, tetoppo, oppooppo, sign,
33899 eps)) sign = 0.0;
33900 }
33901 if (sign > 0.0) {
33902 if (flipqueue) {
33903 enqueueflipface(tetraloop, flipqueue);
33904 } else {
33905 printf(" !! Non-locally Delaunay face (%d, %d, %d) ",
33906 pointmark(tetorg), pointmark(tetdest), pointmark(tetapex));
33907 fc = categorizeface(tetraloop);
33908 switch (fc) {
33909 case T23: printf("\"T23\""); break;
33910 case T32: printf("\"T32\""); break;
33911 case T22: printf("\"T22\""); break;
33912 case T44: printf("\"T44\""); break;
33913 case N32: printf("\"N32\""); break;
33914 case N40: printf("\"N40\""); break;
33915 case FORBIDDENFACE:printf("\"FORBIDDENFACE\""); break;
33916 case FORBIDDENEDGE:printf("\"FORBIDDENEDGE\""); break;
33917 }
33918 printf("\n");
33919 }
33920 horrors++;
33921 }
33922 }
33923 }
33924 tetraloop.tet = tetrahedrontraverse();
33925 }
33926 if (flipqueue == (queue *) NULL) {
33927 if (horrors == 0) {
33928 if (!b->quiet) {
33929 printf(" The mesh is %s.\n",
33930 checksubfaces ? "constrained Delaunay" : "Delaunay");
33931 }
33932 } else {
33933 printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors);
33934 }
33935 }
33936}
33937
33939// //
33940// checkconforming() Ensure that the mesh is conforming Delaunay. //
33941// //
33943
33944void tetgenmesh::checkconforming()
33945{
33946 face segloop, shloop;
33947 int encsubsegs, encsubfaces;
33948
33949 if (!b->quiet) {
33950 printf(" Checking conforming Delaunay property of mesh...\n");
33951 }
33952 encsubsegs = encsubfaces = 0;
33953 // Run through the list of subsegments, check each one.
33954 subsegs->traversalinit();
33955 segloop.sh = shellfacetraverse(subsegs);
33956 while (segloop.sh != (shellface *) NULL) {
33957 if (checkseg4encroach(&segloop, NULL, NULL, false)) {
33958 printf(" !! !! Non-conforming subsegment: (%d, %d)\n",
33959 pointmark(sorg(segloop)), pointmark(sdest(segloop)));
33960 encsubsegs++;
33961 }
33962 segloop.sh = shellfacetraverse(subsegs);
33963 }
33964 // Run through the list of subfaces, check each one.
33965 subfaces->traversalinit();
33966 shloop.sh = shellfacetraverse(subfaces);
33967 while (shloop.sh != (shellface *) NULL) {
33968 if (checksub4encroach(&shloop, NULL, false)) {
33969 printf(" !! !! Non-conforming subface: (%d, %d, %d)\n",
33970 pointmark(sorg(shloop)), pointmark(sdest(shloop)),
33971 pointmark(sapex(shloop)));
33972 encsubfaces++;
33973 }
33974 shloop.sh = shellfacetraverse(subfaces);
33975 }
33976 if (encsubsegs == 0 && encsubfaces == 0) {
33977 if (!b->quiet) {
33978 printf(" The mesh is conforming Delaunay.\n");
33979 }
33980 } else {
33981 if (encsubsegs > 0) {
33982 printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs);
33983 }
33984 if (encsubfaces > 0) {
33985 printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces);
33986 }
33987 }
33988}
33989
33991// //
33992// algorithmicstatistics() Print statistics about the mesh algorithms. //
33993// //
33995
33996#ifdef SELF_CHECK
33997
33998void tetgenmesh::algorithmicstatistics()
33999{
34000 /*
34001 printf("Algorithmic statistics:\n\n");
34002 printf(" Point location millisecond: %g\n", (REAL) tloctime * 1e+3);
34003 printf(" Flip millisecond: %g\n", (REAL) tfliptime * 1e+3);
34004 if (b->plc || b->refine) {
34005 printf(" Number of facet above points calculations: %ld\n", abovecount);
34006 }
34007 if (b->plc) {
34008 printf(" Segment split rules: R1 %ld, R2 %ld, R3 %ld\n", r1count, r2count,
34009 r3count);
34010 }
34011 if (b->quality) {
34012 printf(" Bowyer-Watson insertions: seg %ld, sub %ld, vol %ld.\n",
34013 bowatsegcount, bowatsubcount, bowatvolcount);
34014 printf(" Bowyer-Watson corrections: seg %ld, sub %ld, vol %ld\n",
34015 updsegcount, updsubcount, updvolcount);
34016 printf(" Bowyer-Watson failures: seg %ld, sub %ld, vol %ld\n",
34017 failsegcount, failsubcount, failvolcount);
34018 printf(" Number of repair flips: %ld.\n", repairflipcount);
34019 printf(" Number of circumcenters outside Bowat-cav.: %ld.\n",
34020 outbowatcircumcount);
34021 if (b->conformdel) {
34022 printf(" Segment split rules: R2 %ld, R3 %ld\n", r2count, r3count);
34023 printf(" Number of CDT enforcement points: %ld.\n", cdtenforcesegpts);
34024 }
34025 printf(" Number of Rejections: seg %ld, sub %ld, tet %ld.\n", rejsegpts,
34026 rejsubpts, rejtetpts);
34027 if (b->optlevel) {
34028 printf(
34029 " Optimization flips: f32 %ld, f44 %ld, f56 %ld, f68 %ld, fnm %ld.\n",
34030 optcount[3], optcount[4], optcount[5], optcount[6], optcount[9]);
34031 printf(" Optimization segment deletions: %ld.\n", optcount[1]);
34032 }
34033 }
34034 printf("\n");
34035 */
34036}
34037
34038#endif // #ifdef SELF_CHECK
34039
34041// //
34042// qualitystatistics() Print statistics about the quality of the mesh. //
34043// //
34045
34046void tetgenmesh::qualitystatistics()
34047{
34048 triface tetloop, neightet;
34049 point p[4];
34050 char sbuf[128];
34051 REAL radiusratiotable[12];
34052 REAL aspectratiotable[12];
34053 REAL A[4][4], rhs[4], D;
34054 REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
34055 REAL edgelength[6], alldihed[6], faceangle[3];
34056 REAL shortest, longest;
34057 REAL smallestvolume, biggestvolume;
34058 REAL smallestdiangle, biggestdiangle;
34059 REAL smallestfaangle, biggestfaangle;
34060 REAL tetvol, minaltitude;
34061 REAL cirradius, minheightinv; // insradius;
34062 REAL shortlen, longlen;
34063 REAL tetaspect, tetradius;
34064 REAL smalldiangle, bigdiangle;
34065 REAL smallfaangle, bigfaangle;
34066 int radiustable[12];
34067 int aspecttable[16];
34068 int dihedangletable[18];
34069 int faceangletable[18];
34070 int indx[4];
34071 int radiusindex;
34072 int aspectindex;
34073 int tendegree;
34074 int i, j;
34075
34076 smallfaangle = 0.0;
34077 bigfaangle = 0.0;
34078
34079 printf("Mesh quality statistics:\n\n");
34080
34081 // Avoid compile warnings.
34082 shortlen = longlen = 0.0;
34083 smalldiangle = bigdiangle = 0.0;
34084
34085 radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0;
34086 radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2;
34087 radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6;
34088 radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0;
34089 radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0;
34090 radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0;
34091
34092 aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0;
34093 aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0;
34094 aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0;
34095 aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0;
34096 aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0;
34097 aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0;
34098
34099 for (i = 0; i < 12; i++) radiustable[i] = 0;
34100 for (i = 0; i < 12; i++) aspecttable[i] = 0;
34101 for (i = 0; i < 18; i++) dihedangletable[i] = 0;
34102 for (i = 0; i < 18; i++) faceangletable[i] = 0;
34103
34104 minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
34105 minaltitude = minaltitude * minaltitude;
34106 shortest = minaltitude;
34107 longest = 0.0;
34108 smallestvolume = minaltitude;
34109 biggestvolume = 0.0;
34110 smallestdiangle = smallestfaangle = 180.0;
34111 biggestdiangle = biggestfaangle = 0.0;
34112
34113 // Loop all elements, calculate quality parameters for each element.
34114 tetrahedrons->traversalinit();
34115 tetloop.tet = tetrahedrontraverse();
34116 while (tetloop.tet != (tetrahedron *) NULL) {
34117
34118 // Get four vertices: p0, p1, p2, p3.
34119 for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
34120 // Set the edge vectors: V[0], ..., V[5]
34121 for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
34122 for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
34123 for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
34124 for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
34125 for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
34126 for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
34127 // Set the matrix A = [V[0], V[1], V[2]]^T.
34128 for (j = 0; j < 3; j++) {
34129 for (i = 0; i < 3; i++) A[j][i] = V[j][i];
34130 }
34131 // Decompose A just once.
34132 lu_decmp(A, 3, indx, &D, 0);
34133 // Get the tet volume.
34134 tetvol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
34135 // Get the three faces normals.
34136 for (j = 0; j < 3; j++) {
34137 for (i = 0; i < 3; i++) rhs[i] = 0.0;
34138 rhs[j] = 1.0; // Positive means the inside direction
34139 lu_solve(A, 3, indx, rhs, 0);
34140 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
34141 }
34142 // Get the fourth face normal by summing up the first three.
34143 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
34144 // Get the radius of the circumsphere.
34145 for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
34146 lu_solve(A, 3, indx, rhs, 0);
34147 cirradius = sqrt(dot(rhs, rhs));
34148 // Normalize the face normals.
34149 for (i = 0; i < 4; i++) {
34150 // H[i] is the inverse of height of its corresponding face.
34151 H[i] = sqrt(dot(N[i], N[i]));
34152 for (j = 0; j < 3; j++) N[i][j] /= H[i];
34153 }
34154 // Get the radius of the inscribed sphere.
34155 // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
34156 // Get the biggest H[i] (corresponding to the smallest height).
34157 minheightinv = H[0];
34158 for (i = 1; i < 3; i++) {
34159 if (H[i] > minheightinv) minheightinv = H[i];
34160 }
34161 // Get the squares of the edge lengthes.
34162 for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
34163 // Get the dihedrals (in degree) at each edges.
34164 j = 0;
34165 for (i = 1; i < 4; i++) {
34166 alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
34167 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
34168 else if (alldihed[j] > 1.0) alldihed[j] = 1;
34169 alldihed[j] = acos(alldihed[j]) / PI * 180.0;
34170 j++;
34171 }
34172 for (i = 2; i < 4; i++) {
34173 alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
34174 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
34175 else if (alldihed[j] > 1.0) alldihed[j] = 1;
34176 alldihed[j] = acos(alldihed[j]) / PI * 180.0;
34177 j++;
34178 }
34179 alldihed[j] = -dot(N[2], N[3]); // Edge ab.
34180 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
34181 else if (alldihed[j] > 1.0) alldihed[j] = 1;
34182 alldihed[j] = acos(alldihed[j]) / PI * 180.0;
34183
34184 // Calculate the longest and shortest edge length.
34185 for (i = 0; i < 6; i++) {
34186 if (i == 0) {
34187 shortlen = longlen = edgelength[i];
34188 } else {
34189 shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
34190 longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
34191 }
34192 if (edgelength[i] > longest) {
34193 longest = edgelength[i];
34194 }
34195 if (edgelength[i] < shortest) {
34196 shortest = edgelength[i];
34197 }
34198 }
34199
34200 // Calculate the largest and smallest volume.
34201 if (tetvol < smallestvolume) {
34202 smallestvolume = tetvol;
34203 }
34204 if (tetvol > biggestvolume) {
34205 biggestvolume = tetvol;
34206 }
34207
34208 // Calculate the largest and smallest dihedral angles.
34209 for (i = 0; i < 6; i++) {
34210 if (i == 0) {
34211 smalldiangle = bigdiangle = alldihed[i];
34212 } else {
34213 smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
34214 bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
34215 }
34216 if (alldihed[i] < smallestdiangle) {
34217 smallestdiangle = alldihed[i];
34218 }
34219 if (alldihed[i] > biggestdiangle) {
34220 biggestdiangle = alldihed[i];
34221 }
34222 }
34223 // Accumulate the corresponding number in the dihedral angle histogram.
34224 if (smalldiangle < 5.0) {
34225 tendegree = 0;
34226 } else if (smalldiangle >= 5.0 && smalldiangle < 10.0) {
34227 tendegree = 1;
34228 } else if (smalldiangle >= 80.0 && smalldiangle < 110.0) {
34229 tendegree = 9; // Angles between 80 to 110 degree are in one entry.
34230 } else {
34231 tendegree = (int) (smalldiangle / 10.);
34232 if (smalldiangle < 80.0) {
34233 tendegree++; // In the left column.
34234 } else {
34235 tendegree--; // In the right column.
34236 }
34237 }
34238 dihedangletable[tendegree]++;
34239 if (bigdiangle >= 80.0 && bigdiangle < 110.0) {
34240 tendegree = 9; // Angles between 80 to 110 degree are in one entry.
34241 } else if (bigdiangle >= 170.0 && bigdiangle < 175.0) {
34242 tendegree = 16;
34243 } else if (bigdiangle >= 175.0) {
34244 tendegree = 17;
34245 } else {
34246 tendegree = (int) (bigdiangle / 10.);
34247 if (bigdiangle < 80.0) {
34248 tendegree++; // In the left column.
34249 } else {
34250 tendegree--; // In the right column.
34251 }
34252 }
34253 dihedangletable[tendegree]++;
34254
34255 // Calulate the largest and smallest face angles.
34256 tetloop.ver = 0;
34257 for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
34258 sym(tetloop, neightet);
34259 // Only do the calulation once for a face.
34260 if ((neightet.tet == dummytet) || (tetloop.tet < neightet.tet)) {
34261 p[0] = org(tetloop);
34262 p[1] = dest(tetloop);
34263 p[2] = apex(tetloop);
34264 faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
34265 faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
34266 faceangle[2] = PI - (faceangle[0] + faceangle[1]);
34267 // Translate angles into degrees.
34268 for (i = 0; i < 3; i++) {
34269 faceangle[i] = (faceangle[i] * 180.0) / PI;
34270 }
34271 // Calculate the largest and smallest face angles.
34272 for (i = 0; i < 3; i++) {
34273 if (i == 0) {
34274 smallfaangle = bigfaangle = faceangle[i];
34275 } else {
34276 smallfaangle = faceangle[i] < smallfaangle ?
34277 faceangle[i] : smallfaangle;
34278 bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
34279 }
34280 if (faceangle[i] < smallestfaangle) {
34281 smallestfaangle = faceangle[i];
34282 }
34283 if (faceangle[i] > biggestfaangle) {
34284 biggestfaangle = faceangle[i];
34285 }
34286 }
34287 tendegree = (int) (smallfaangle / 10.);
34288 faceangletable[tendegree]++;
34289 tendegree = (int) (bigfaangle / 10.);
34290 faceangletable[tendegree]++;
34291 }
34292 }
34293
34294 // Calculate aspect ratio and radius-edge ratio for this element.
34295 tetradius = cirradius / sqrt(shortlen);
34296 // tetaspect = sqrt(longlen) / (2.0 * insradius);
34297 tetaspect = sqrt(longlen) * minheightinv;
34298 aspectindex = 0;
34299 while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
34300 aspectindex++;
34301 }
34302 aspecttable[aspectindex]++;
34303 radiusindex = 0;
34304 while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
34305 radiusindex++;
34306 }
34307 radiustable[radiusindex]++;
34308
34309 tetloop.tet = tetrahedrontraverse();
34310 }
34311
34312 shortest = sqrt(shortest);
34313 longest = sqrt(longest);
34314 minaltitude = sqrt(minaltitude);
34315
34316 printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n",
34317 smallestvolume, biggestvolume);
34318 printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
34319 shortest, longest);
34320 sprintf(sbuf, "%.17g", biggestfaangle);
34321 if (strlen(sbuf) > 8) {
34322 sbuf[8] = '\0';
34323 }
34324 printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
34325 smallestfaangle, sbuf);
34326 sprintf(sbuf, "%.17g", biggestdiangle);
34327 if (strlen(sbuf) > 8) {
34328 sbuf[8] = '\0';
34329 }
34330 printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
34331 smallestdiangle, sbuf);
34332
34333 /*
34334 printf(" Radius-edge ratio histogram:\n");
34335 printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34336 radiusratiotable[0], radiustable[0], radiusratiotable[5],
34337 radiusratiotable[6], radiustable[6]);
34338 for (i = 1; i < 5; i++) {
34339 printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34340 radiusratiotable[i - 1], radiusratiotable[i], radiustable[i],
34341 radiusratiotable[i + 5], radiusratiotable[i + 6],
34342 radiustable[i + 6]);
34343 }
34344 printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n",
34345 radiusratiotable[4], radiusratiotable[5], radiustable[5],
34346 radiusratiotable[10], radiustable[11]);
34347 printf(" (A tetrahedron's radius-edge ratio is its radius of ");
34348 printf("circumsphere divided\n");
34349 printf(" by its shortest edge length)\n\n");
34350 */
34351
34352 printf(" Aspect ratio histogram:\n");
34353 printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34354 aspectratiotable[0], aspecttable[0], aspectratiotable[5],
34355 aspectratiotable[6], aspecttable[6]);
34356 for (i = 1; i < 5; i++) {
34357 printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34358 aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
34359 aspectratiotable[i + 5], aspectratiotable[i + 6],
34360 aspecttable[i + 6]);
34361 }
34362 printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n",
34363 aspectratiotable[4], aspectratiotable[5], aspecttable[5],
34364 aspectratiotable[10], aspecttable[11]);
34365 printf(" (A tetrahedron's aspect ratio is its longest edge length");
34366 printf(" divided by its\n");
34367 printf(" smallest side height)\n\n");
34368
34369 printf(" Face angle histogram:\n");
34370 for (i = 0; i < 9; i++) {
34371 printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n",
34372 i * 10, i * 10 + 10, faceangletable[i],
34373 i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
34374 }
34375 if (minfaceang != PI) {
34376 printf(" Minimum input face angle is %g (degree).\n",
34377 minfaceang / PI * 180.0);
34378 }
34379 printf("\n");
34380
34381 printf(" Dihedral angle histogram:\n");
34382 // Print the three two rows:
34383 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34384 0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
34385 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34386 5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
34387 // Print the third to seventh rows.
34388 for (i = 2; i < 7; i++) {
34389 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34390 (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
34391 (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
34392 }
34393 // Print the last two rows.
34394 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34395 60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
34396 printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34397 70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
34398 if (minfacetdihed != PI) {
34399 printf(" Minimum input facet dihedral angle is %g (degree).\n",
34400 minfacetdihed / PI * 180.0);
34401 }
34402 printf("\n");
34403}
34404
34406// //
34407// statistics() Print all sorts of cool facts. //
34408// //
34410
34411void tetgenmesh::statistics()
34412{
34413 printf("\nStatistics:\n\n");
34414 printf(" Input points: %d\n", in->numberofpoints + jettisoninverts);
34415 if (b->refine) {
34416 printf(" Input tetrahedra: %d\n", in->numberoftetrahedra);
34417 }
34418 if (b->plc) {
34419 printf(" Input facets: %d\n", in->numberoffacets);
34420 printf(" Input segments: %ld\n", insegments);
34421 printf(" Input holes: %d\n", in->numberofholes);
34422 printf(" Input regions: %d\n", in->numberofregions);
34423 }
34424
34425 printf("\n Mesh points: %ld\n", points->items);
34426 printf(" Mesh tetrahedra: %ld\n", tetrahedrons->items);
34427 if (b->plc || b->refine) {
34428 printf(" Mesh triangles: %ld\n", (4l*tetrahedrons->items+hullsize)/2l);
34429 }
34430 if (b->plc || b->refine) {
34431 printf(" Mesh subfaces: %ld\n", subfaces->items);
34432 printf(" Mesh subsegments: %ld\n\n", subsegs->items);
34433 } else {
34434 printf(" Convex hull triangles: %ld\n\n", hullsize);
34435 }
34436 if (b->verbose > 0) {
34437 qualitystatistics();
34438 unsigned long totalmeshbytes;
34439 printf("Memory allocation statistics:\n\n");
34440 printf(" Maximum number of vertices: %ld\n", points->maxitems);
34441 totalmeshbytes = points->maxitems * points->itembytes;
34442 printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
34443 totalmeshbytes += tetrahedrons->maxitems * tetrahedrons->itembytes;
34444 if (subfaces != (memorypool *) NULL) {
34445 printf(" Maximum number of subfaces: %ld\n", subfaces->maxitems);
34446 totalmeshbytes += subfaces->maxitems * subfaces->itembytes;
34447 }
34448 if (subsegs != (memorypool *) NULL) {
34449 printf(" Maximum number of segments: %ld\n", subsegs->maxitems);
34450 totalmeshbytes += subsegs->maxitems * subsegs->itembytes;
34451 }
34452 printf(" Approximate heap memory used by the mesh (K bytes): %g\n\n",
34453 (double) totalmeshbytes / 1024.0);
34454#ifdef SELF_CHECK
34455 algorithmicstatistics();
34456#endif
34457 }
34458}
34459
34460//
34461// End of user interaction routines
34462//
34463
34464//
34465// Begin of constructor and destructor of tetgenmesh
34466//
34467
34469// //
34470// ~tetgenmesh() Deallocte memory occupied by a tetgenmesh object. //
34471// //
34473
34474tetgenmesh::~tetgenmesh()
34475{
34476 bgm = (tetgenmesh *) NULL;
34477 in = (tetgenio *) NULL;
34478 b = (tetgenbehavior *) NULL;
34479
34480 if (tetrahedrons != (memorypool *) NULL) {
34481 delete tetrahedrons;
34482 }
34483 if (subfaces != (memorypool *) NULL) {
34484 delete subfaces;
34485 }
34486 if (subsegs != (memorypool *) NULL) {
34487 delete subsegs;
34488 }
34489 if (points != (memorypool *) NULL) {
34490 delete points;
34491 }
34492 if (dummytetbase != (tetrahedron *) NULL) {
34493 delete [] dummytetbase;
34494 }
34495 if (dummyshbase != (shellface *) NULL) {
34496 delete [] dummyshbase;
34497 }
34498 if (facetabovepointarray != (point *) NULL) {
34499 delete [] facetabovepointarray;
34500 }
34501 if (highordertable != (point *) NULL) {
34502 delete [] highordertable;
34503 }
34504 if (subpbcgrouptable != (pbcdata *) NULL) {
34505 delete [] subpbcgrouptable;
34506 }
34507 if (segpbcgrouptable != (list *) NULL) {
34508 delete segpbcgrouptable;
34509 delete [] idx2segpglist;
34510 delete [] segpglist;
34511 }
34512}
34513
34515// //
34516// tetgenmesh() Initialize a tetgenmesh object. //
34517// //
34519
34520tetgenmesh::tetgenmesh()
34521{
34522 bgm = (tetgenmesh *) NULL;
34523 in = (tetgenio *) NULL;
34524 b = (tetgenbehavior *) NULL;
34525
34526 tetrahedrons = (memorypool *) NULL;
34527 subfaces = (memorypool *) NULL;
34528 subsegs = (memorypool *) NULL;
34529 points = (memorypool *) NULL;
34530 badsubsegs = (memorypool *) NULL;
34531 badsubfaces = (memorypool *) NULL;
34532 badtetrahedrons = (memorypool *) NULL;
34533 flipstackers = (memorypool *) NULL;
34534
34535 dummytet = (tetrahedron *) NULL;
34536 dummytetbase = (tetrahedron *) NULL;
34537 dummysh = (shellface *) NULL;
34538 dummyshbase = (shellface *) NULL;
34539
34540 facetabovepointarray = (point *) NULL;
34541 abovepoint = (point) NULL;
34542 highordertable = (point *) NULL;
34543 subpbcgrouptable = (pbcdata *) NULL;
34544 segpbcgrouptable = (list *) NULL;
34545 idx2segpglist = (int *) NULL;
34546 segpglist = (int *) NULL;
34547
34548 xmax = xmin = ymax = ymin = zmax = zmin = 0.0;
34549 longest = 0.0;
34550 hullsize = 0l;
34551 insegments = 0l;
34552 pointmtrindex = 0;
34553 pointmarkindex = 0;
34554 point2simindex = 0;
34555 point2pbcptindex = 0;
34556 highorderindex = 0;
34557 elemattribindex = 0;
34558 volumeboundindex = 0;
34559 shmarkindex = 0;
34560 areaboundindex = 0;
34561 checksubfaces = 0;
34562 checksubsegs = 0;
34563 checkpbcs = 0;
34564 varconstraint = 0;
34565 nonconvex = 0;
34566 dupverts = 0;
34567 unuverts = 0;
34568 relverts = 0;
34569 suprelverts = 0;
34570 collapverts = 0;
34571 unsupverts = 0;
34572 jettisoninverts = 0;
34573 symbolic = 1;
34574 samples = 0l;
34575 randomseed = 1l;
34576 macheps = 0.0;
34577 minfaceang = minfacetdihed = PI;
34578 maxcavfaces = maxcavverts = 0;
34579 expcavcount = 0;
34580 abovecount = 0l;
34581 bowatvolcount = bowatsubcount = bowatsegcount = 0l;
34582 updvolcount = updsubcount = updsegcount = 0l;
34583 repairflipcount = 0l;
34584 outbowatcircumcount = 0l;
34585 failvolcount = failsubcount = failsegcount = 0l;
34586 r1count = r2count = r3count = 0l;
34587 cdtenforcesegpts = 0l;
34588 rejsegpts = rejsubpts = rejtetpts = 0l;
34589 flip23s = flip32s = flip22s = flip44s = 0l;
34590 tloctime = tfliptime = 0.0;
34591}
34592
34593//
34594// End of constructor and destructor of tetgenmesh
34595//
34596
34597//
34598// End of class 'tetgenmesh' implementation.
34599//
34600
34602// //
34603// tetrahedralize() The interface for users using TetGen library to //
34604// generate tetrahedral meshes with all features. //
34605// //
34606// The sequence is roughly as follows. Many of these steps can be skipped, //
34607// depending on the command line switches. //
34608// //
34609// - Initialize constants and parse the command line. //
34610// - Read the vertices from a file and either //
34611// - tetrahedralize them (no -r), or //
34612// - read an old mesh from files and reconstruct it (-r). //
34613// - Insert the PLC segments and facets (-p). //
34614// - Read the holes (-p), regional attributes (-pA), and regional volume //
34615// constraints (-pa). Carve the holes and concavities, and spread the //
34616// regional attributes and volume constraints. //
34617// - Enforce the constraints on minimum quality bound (-q) and maximum //
34618// volume (-a). Also enforce the conforming Delaunay property (-q and -a). //
34619// - Promote the mesh's linear tetrahedra to higher order elements (-o). //
34620// - Write the output files and print the statistics. //
34621// - Check the consistency and Delaunay property of the mesh (-C). //
34622// //
34624
34625void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
34626 tetgenio *addin, tetgenio *bgmin)
34627{
34628 tetgenmesh m;
34629 // Variables for timing the performance of TetGen (defined in time.h).
34630 clock_t tv[14];
34631
34632 tv[0] = clock();
34633
34634 m.b = b;
34635 m.in = in;
34636 m.macheps = exactinit();
34637 m.steinerleft = b->steiner;
34638 if (b->metric) {
34639 m.bgm = new tetgenmesh();
34640 m.bgm->b = b;
34641 m.bgm->in = bgmin;
34642 m.bgm->macheps = exactinit();
34643 }
34644 m.initializepools();
34645 m.transfernodes();
34646
34647 tv[1] = clock();
34648
34649 if (b->refine) {
34650 m.reconstructmesh();
34651 } else {
34652 m.delaunizevertices();
34653 }
34654
34655 tv[2] = clock();
34656
34657 if (!b->quiet) {
34658 if (b->refine) {
34659 printf("Mesh reconstruction seconds:");
34660 } else {
34661 printf("Delaunay seconds:");
34662 }
34663 printf(" %g\n", (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
34664 }
34665
34666 if (b->metric) {
34667 if (bgmin != (tetgenio *) NULL) {
34668 m.bgm->initializepools();
34669 m.bgm->transfernodes();
34670 m.bgm->reconstructmesh();
34671 } else {
34672 m.bgm->in = in;
34673 m.bgm->initializepools();
34674 m.duplicatebgmesh();
34675 }
34676 }
34677
34678 tv[3] = clock();
34679
34680 if (!b->quiet) {
34681 if (b->metric) {
34682 printf("Background mesh reconstruct seconds: %g\n",
34683 (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC);
34684 }
34685 }
34686
34687 if (b->useshelles && !b->refine) {
34688 m.meshsurface();
34689 if (b->diagnose != 1) {
34690 m.markacutevertices(89.0);
34691 m.incrperturbvertices(b->epsilon);
34692 m.delaunizesegments();
34693 if (m.checkpbcs) {
34694 long oldnum;
34695 do {
34696 oldnum = m.points->items;
34697 m.incrperturbvertices(b->epsilon);
34698 if (m.points->items > oldnum) {
34699 oldnum = m.points->items;
34700 m.delaunizesegments();
34701 }
34702 } while (oldnum < m.points->items);
34703 }
34704 m.constrainedfacets();
34705 } else {
34706 m.detectinterfaces();
34707 }
34708 }
34709
34710 tv[4] = clock();
34711
34712 if (!b->quiet) {
34713 if (b->useshelles && !b->refine) {
34714 if (b->diagnose != 1) {
34715 printf("Segment and facet ");
34716 } else {
34717 printf("Intersection ");
34718 }
34719 printf("seconds: %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
34720 }
34721 }
34722
34723 if (b->plc && !(b->diagnose == 1)) {
34724 m.carveholes();
34725 }
34726
34727 tv[5] = clock();
34728
34729 if (!b->quiet) {
34730 if (b->plc && !(b->diagnose == 1)) {
34731 printf("Hole seconds: %g\n", (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC);
34732 }
34733 }
34734
34735 if ((b->plc || b->refine) && !(b->diagnose == 1)) {
34736 m.optimizemesh(false);
34737 }
34738
34739 tv[6] = clock();
34740
34741 if (!b->quiet) {
34742 if ((b->plc || b->refine) && !(b->diagnose == 1)) {
34743 printf("Repair seconds: %g\n", (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
34744 }
34745 }
34746
34747 if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
34748 m.removesteiners(false);
34749 }
34750
34751 tv[7] = clock();
34752
34753 if (!b->quiet) {
34754 if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
34755 printf("Steiner removal seconds: %g\n",
34756 (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC);
34757 }
34758 }
34759
34760 if (b->insertaddpoints && (addin != (tetgenio *) NULL)) {
34761 if (addin->numberofpoints > 0) {
34762 m.insertconstrainedpoints(addin);
34763 }
34764 }
34765
34766 tv[8] = clock();
34767
34768 if (!b->quiet) {
34769 if ((b->plc || b->refine) && (b->insertaddpoints)) {
34770 printf("Constrained points seconds: %g\n",
34771 (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC);
34772 }
34773 }
34774
34775 if (b->metric) {
34776 m.interpolatesizemap();
34777 }
34778
34779 tv[9] = clock();
34780
34781 if (!b->quiet) {
34782 if (b->metric) {
34783 printf("Size interpolating seconds: %g\n",
34784 (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC);
34785 }
34786 }
34787
34788 if (b->coarse) {
34789 m.removesteiners(true);
34790 }
34791
34792 tv[10] = clock();
34793
34794 if (!b->quiet) {
34795 if (b->coarse) {
34796 printf("Mesh coarsening seconds: %g\n",
34797 (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC);
34798 }
34799 }
34800
34801 if (b->quality) {
34802 m.enforcequality();
34803 }
34804
34805 tv[11] = clock();
34806
34807 if (!b->quiet) {
34808 if (b->quality) {
34809 printf("Quality seconds: %g\n",
34810 (tv[11] - tv[10]) / (REAL) CLOCKS_PER_SEC);
34811 }
34812 }
34813
34814 if (b->quality && (b->optlevel > 0)) {
34815 m.optimizemesh(true);
34816 }
34817
34818 tv[12] = clock();
34819
34820 if (!b->quiet) {
34821 if (b->quality && (b->optlevel > 0)) {
34822 printf("Optimize seconds: %g\n",
34823 (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC);
34824 }
34825 }
34826
34827 if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
34828 || (b->refine && (in->numberofcorners == 10)))) {
34829 m.jettisonnodes();
34830 }
34831
34832 if (b->order > 1) {
34833 m.highorder();
34834 }
34835
34836 if (!b->quiet) {
34837 printf("\n");
34838 }
34839
34840 if (out != (tetgenio *) NULL) {
34841 out->firstnumber = in->firstnumber;
34842 out->mesh_dim = in->mesh_dim;
34843 }
34844
34845 if (b->nonodewritten || b->noiterationnum) {
34846 if (!b->quiet) {
34847 printf("NOT writing a .node file.\n");
34848 }
34849 } else {
34850 if (b->diagnose == 1) {
34851 if (m.subfaces->items > 0l) {
34852 m.outnodes(out); // Only output when self-intersecting faces exist.
34853 }
34854 } else {
34855 m.outnodes(out);
34856 if (b->quality || b->metric) {
34857 // m.outmetrics(out);
34858 }
34859 }
34860 }
34861
34862 if (b->noelewritten) {
34863 if (!b->quiet) {
34864 printf("NOT writing an .ele file.\n");
34865 }
34866 } else {
34867 if (!(b->diagnose == 1)) {
34868 if (m.tetrahedrons->items > 0l) {
34869 m.outelements(out);
34870 }
34871 }
34872 }
34873
34874 if (b->nofacewritten) {
34875 if (!b->quiet) {
34876 printf("NOT writing an .face file.\n");
34877 }
34878 } else {
34879 if (b->facesout) {
34880 if (m.tetrahedrons->items > 0l) {
34881 m.outfaces(out); // Output all faces.
34882 }
34883 } else {
34884 if (b->diagnose == 1) {
34885 if (m.subfaces->items > 0l) {
34886 m.outsubfaces(out); // Only output self-intersecting faces.
34887 }
34888 } else if (b->plc || b->refine) {
34889 if (m.subfaces->items > 0l) {
34890 m.outsubfaces(out); // Output boundary faces.
34891 }
34892 } else {
34893 if (m.tetrahedrons->items > 0l) {
34894 m.outhullfaces(out); // Output convex hull faces.
34895 }
34896 }
34897 }
34898 }
34899
34900 if (m.checkpbcs) {
34901 m.outpbcnodes(out);
34902 }
34903
34904 if (b->edgesout) {
34905 if (b->edgesout > 1) {
34906 m.outedges(out); // -ee, output all mesh edges.
34907 } else {
34908 m.outsubsegments(out); // -e, only output subsegments.
34909 }
34910 }
34911
34912 if (!out && b->plc &&
34913 ((b->object == tetgenbehavior::OFF) ||
34914 (b->object == tetgenbehavior::PLY) ||
34915 (b->object == tetgenbehavior::STL))) {
34916 m.outsmesh(b->outfilename);
34917 }
34918
34919 if (!out && b->meditview) {
34920 m.outmesh2medit(b->outfilename);
34921 }
34922
34923 if (!out && b->gidview) {
34924 m.outmesh2gid(b->outfilename);
34925 }
34926
34927 if (!out && b->geomview) {
34928 m.outmesh2off(b->outfilename);
34929 }
34930
34931 if (b->neighout) {
34932 m.outneighbors(out);
34933 }
34934
34935 if (b->voroout) {
34936 m.outvoronoi(out);
34937 }
34938
34939 tv[13] = clock();
34940
34941 if (!b->quiet) {
34942 printf("\nOutput seconds: %g\n",
34943 (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC);
34944 printf("Total running seconds: %g\n",
34945 (tv[13] - tv[0]) / (REAL) CLOCKS_PER_SEC);
34946 }
34947
34948 if (b->docheck) {
34949 m.checkmesh();
34950 if (m.checksubfaces) {
34951 m.checkshells();
34952 }
34953 if (b->docheck > 1) {
34954 m.checkdelaunay(0.0, NULL);
34955 if (b->docheck > 2) {
34956 if (b->quality || b->refine) {
34957 m.checkconforming();
34958 }
34959 }
34960 }
34961 }
34962
34963 if (!b->quiet) {
34964 m.statistics();
34965 }
34966
34967 if (b->metric) {
34968 delete m.bgm;
34969 }
34970}
34971
34972#ifndef TETLIBRARY
34973
34975// //
34976// main() The entrance for running TetGen from command line. //
34977// //
34979
34980int main(int argc, char *argv[])
34981
34982#else // with TETLIBRARY
34983
34985// //
34986// tetrahedralize() The entrance for calling TetGen from another program. //
34987// //
34989
34990void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
34991 tetgenio *addin, tetgenio *bgmin)
34992
34993#endif // not TETLIBRARY
34994
34995{
34996 tetgenbehavior b;
34997
34998#ifndef TETLIBRARY
34999
35000 tetgenio in, addin, bgmin;
35001
35002 if (!b.parse_commandline(argc, argv)) {
35003 terminatetetgen(1);
35004 }
35005 if (b.refine) {
35006 if (!in.load_tetmesh(b.infilename)) {
35007 terminatetetgen(1);
35008 }
35009 } else {
35010 if (!in.load_plc(b.infilename, (int) b.object)) {
35011 terminatetetgen(1);
35012 }
35013 }
35014 if (b.insertaddpoints) {
35015 if (!addin.load_node(b.addinfilename)) {
35016 addin.numberofpoints = 0l;
35017 }
35018 }
35019 if (b.metric) {
35020 if (!bgmin.load_tetmesh(b.bgmeshfilename)) {
35021 bgmin.numberoftetrahedra = 0l;
35022 }
35023 }
35024
35025 if (bgmin.numberoftetrahedra > 0l) {
35026 tetrahedralize(&b, &in, NULL, &addin, &bgmin);
35027 } else {
35028 tetrahedralize(&b, &in, NULL, &addin, NULL);
35029 }
35030
35031 return 0;
35032
35033#else // with TETLIBRARY
35034
35035 if (!b.parse_commandline(switches)) {
35036 terminatetetgen(1);
35037 }
35038 tetrahedralize(&b, in, out, addin, bgmin);
35039
35040#endif // not TETLIBRARY
35041}
35042
35043} //Added namespace to avoid clash with triangle
35044
35045#ifndef TETLIBRARY
35046// Shim for entry point to main inside the namespace. This is just in case we want to compile up a binary from this
35047// source code.
35048int main(int argc, char *argv[])
35049{
35050 tetgen::main(argc, argv);
35051}
35052#endif // not TETLIBRARY
#define UNUSED_OPT(var)