1///////////////////////////////////////////////////////////////////////////////
2// //
3// TetGen //
4// //
5// A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator //
6// //
7// Version 1.5 //
8// November 4, 2013 //
9// //
10// TetGen is freely available through the website: http://www.tetgen.org. //
11// It may be copied, modified, and redistributed for non-commercial use. //
12// Please consult the file LICENSE for the detailed copyright notices. //
13// //
14///////////////////////////////////////////////////////////////////////////////
15
16#include "TetGen/tetgen.h"
17#include <inttypes.h>
18
19//// io_cxx ///////////////////////////////////////////////////////////////////
20//// ////
21//// ////
22
23///////////////////////////////////////////////////////////////////////////////
24// //
25// load_node_call() Read a list of points from a file. //
26// //
27// 'infile' is the file handle contains the node list. It may point to a //
28// .node, or .poly or .smesh file. 'markers' indicates each node contains an //
29// additional marker (integer) or not. 'uvflag' indicates each node contains //
30// u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
31// of the file being read, it is only used in error messages. //
32// //
33// The 'firstnumber' (0 or 1) is automatically determined by the number of //
34// the first index of the first point. //
35// //
36///////////////////////////////////////////////////////////////////////////////
37
38#ifdef _MSC_VER
39# pragma warning(push)
40# pragma warning(disable: 4996)
41#endif
42
43bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
44 char* infilename)
45{
46 char inputline[INPUTLINESIZE];
47 char *stringptr;
48 REAL x, y, z, attrib;
49 int firstnode, currentmarker;
50 int index, attribindex;
51 int i, j;
52
53 // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
54 pointlist = new REAL[numberofpoints * 3];
55 if (pointlist == (REAL *) NULL) {
56 terminatetetgen(NULL, 1);
57 }
58 if (numberofpointattributes > 0) {
59 pointattributelist = new REAL[numberofpoints * numberofpointattributes];
60 if (pointattributelist == (REAL *) NULL) {
61 terminatetetgen(NULL, 1);
62 }
63 }
64 if (markers) {
65 pointmarkerlist = new int[numberofpoints];
66 if (pointmarkerlist == (int *) NULL) {
67 terminatetetgen(NULL, 1);
68 }
69 }
70 if (uvflag) {
71 pointparamlist = new pointparam[numberofpoints];
72 if (pointparamlist == NULL) {
73 terminatetetgen(NULL, 1);
74 }
75 }
76
77 // Read the point section.
78 index = 0;
79 attribindex = 0;
80 for (i = 0; i < numberofpoints; i++) {
81 stringptr = readnumberline(inputline, infile, infilename);
82 if (useindex) {
83 if (i == 0) {
84 firstnode = (int) strtol (stringptr, &stringptr, 0);
85 if ((firstnode == 0) || (firstnode == 1)) {
86 firstnumber = firstnode;
87 }
88 }
89 stringptr = findnextnumber(stringptr);
90 } // if (useindex)
91 if (*stringptr == '\0') {
92 printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
93 break;
94 }
95 x = (REAL) strtod(stringptr, &stringptr);
96 stringptr = findnextnumber(stringptr);
97 if (*stringptr == '\0') {
98 printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
99 break;
100 }
101 y = (REAL) strtod(stringptr, &stringptr);
102 if (mesh_dim == 3) {
103 stringptr = findnextnumber(stringptr);
104 if (*stringptr == '\0') {
105 printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
106 break;
107 }
108 z = (REAL) strtod(stringptr, &stringptr);
109 } else {
110 z = 0.0; // mesh_dim == 2;
111 }
112 pointlist[index++] = x;
113 pointlist[index++] = y;
114 pointlist[index++] = z;
115 // Read the point attributes.
116 for (j = 0; j < numberofpointattributes; j++) {
117 stringptr = findnextnumber(stringptr);
118 if (*stringptr == '\0') {
119 attrib = 0.0;
120 } else {
121 attrib = (REAL) strtod(stringptr, &stringptr);
122 }
123 pointattributelist[attribindex++] = attrib;
124 }
125 if (markers) {
126 // Read a point marker.
127 stringptr = findnextnumber(stringptr);
128 if (*stringptr == '\0') {
129 currentmarker = 0;
130 } else {
131 currentmarker = (int) strtol (stringptr, &stringptr, 0);
132 }
133 pointmarkerlist[i] = currentmarker;
134 }
135 if (uvflag) {
136 // Read point paramteters.
137 stringptr = findnextnumber(stringptr);
138 if (*stringptr == '\0') {
139 printf("Error: Point %d has no uv[0].\n", firstnumber + i);
140 break;
141 }
142 pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
143 stringptr = findnextnumber(stringptr);
144 if (*stringptr == '\0') {
145 printf("Error: Point %d has no uv[1].\n", firstnumber + i);
146 break;
147 }
148 pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
149 stringptr = findnextnumber(stringptr);
150 if (*stringptr == '\0') {
151 printf("Error: Point %d has no tag.\n", firstnumber + i);
152 break;
153 }
154 pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
155 stringptr = findnextnumber(stringptr);
156 if (*stringptr == '\0') {
157 printf("Error: Point %d has no type.\n", firstnumber + i);
158 break;
159 }
160 pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
161 if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
162 printf("Error: Point %d has an invalid type.\n", firstnumber + i);
163 break;
164 }
165 }
166 }
167 if (i < numberofpoints) {
168 // Failed to read points due to some error.
169 delete [] pointlist;
170 pointlist = (REAL *) NULL;
171 if (markers) {
172 delete [] pointmarkerlist;
173 pointmarkerlist = (int *) NULL;
174 }
175 if (numberofpointattributes > 0) {
176 delete [] pointattributelist;
177 pointattributelist = (REAL *) NULL;
178 }
179 if (uvflag) {
180 delete [] pointparamlist;
181 pointparamlist = NULL;
182 }
183 numberofpoints = 0;
184 return false;
185 }
186 return true;
187}
188
189///////////////////////////////////////////////////////////////////////////////
190// //
191// load_node() Load a list of points from a .node file. //
192// //
193///////////////////////////////////////////////////////////////////////////////
194
195bool tetgenio::load_node(char* filebasename)
196{
197 FILE *infile;
198 char innodefilename[FILENAMESIZE];
199 char inputline[INPUTLINESIZE];
200 char *stringptr;
201 bool okflag;
202 int markers;
203 int uvflag; // for psc input.
204
205 // Assembling the actual file names we want to open.
206 strcpy(innodefilename, filebasename);
207 strcat(innodefilename, ".node");
208
209 // Try to open a .node file.
210 infile = fopen(innodefilename, "r");
211 if (infile == (FILE *) NULL) {
212 printf(" Cannot access file %s.\n", innodefilename);
213 return false;
214 }
215 printf("Opening %s.\n", innodefilename);
216
217 // Set initial flags.
218 mesh_dim = 3;
219 numberofpointattributes = 0; // no point attribute.
220 markers = 0; // no boundary marker.
221 uvflag = 0; // no uv parameters (required by a PSC).
222
223 // Read the first line of the file.
224 stringptr = readnumberline(inputline, infile, innodefilename);
225 // Does this file contain an index column?
226 stringptr = strstr(inputline, "rbox");
227 if (stringptr == NULL) {
228 // Read number of points, number of dimensions, number of point
229 // attributes, and number of boundary markers.
230 stringptr = inputline;
231 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
232 stringptr = findnextnumber(stringptr);
233 if (*stringptr != '\0') {
234 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
235 }
236 stringptr = findnextnumber(stringptr);
237 if (*stringptr != '\0') {
238 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
239 }
240 stringptr = findnextnumber(stringptr);
241 if (*stringptr != '\0') {
242 markers = (int) strtol (stringptr, &stringptr, 0);
243 }
244 stringptr = findnextnumber(stringptr);
245 if (*stringptr != '\0') {
246 uvflag = (int) strtol (stringptr, &stringptr, 0);
247 }
248 } else {
249 // It is a rbox (qhull) input file.
250 stringptr = inputline;
251 // Get the dimension.
252 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
253 // Get the number of points.
254 stringptr = readnumberline(inputline, infile, innodefilename);
255 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
256 // There is no index column.
257 useindex = 0;
258 }
259
260 // Load the list of nodes.
261 okflag = load_node_call(infile, markers, uvflag, innodefilename);
262
263 fclose(infile);
264 return okflag;
265}
266
267///////////////////////////////////////////////////////////////////////////////
268// //
269// load_edge() Load a list of edges from a .edge file. //
270// //
271///////////////////////////////////////////////////////////////////////////////
272
273bool tetgenio::load_edge(char* filebasename)
274{
275 FILE *infile;
276 char inedgefilename[FILENAMESIZE];
277 char inputline[INPUTLINESIZE];
278 char *stringptr;
279 int markers, corner;
280 int index;
281 int i, j;
282
283 strcpy(inedgefilename, filebasename);
284 strcat(inedgefilename, ".edge");
285
286 infile = fopen(inedgefilename, "r");
287 if (infile != (FILE *) NULL) {
288 printf("Opening %s.\n", inedgefilename);
289 } else {
290 //printf(" Cannot access file %s.\n", inedgefilename);
291 return false;
292 }
293
294 // Read number of boundary edges.
295 stringptr = readnumberline(inputline, infile, inedgefilename);
296 numberofedges = (int) strtol (stringptr, &stringptr, 0);
297 if (numberofedges > 0) {
298 edgelist = new int[numberofedges * 2];
299 if (edgelist == (int *) NULL) {
300 terminatetetgen(NULL, 1);
301 }
302 stringptr = findnextnumber(stringptr);
303 if (*stringptr == '\0') {
304 markers = 0; // Default value.
305 } else {
306 markers = (int) strtol (stringptr, &stringptr, 0);
307 }
308 if (markers > 0) {
309 edgemarkerlist = new int[numberofedges];
310 }
311 }
312
313 // Read the list of edges.
314 index = 0;
315 for (i = 0; i < numberofedges; i++) {
316 // Read edge index and the edge's two endpoints.
317 stringptr = readnumberline(inputline, infile, inedgefilename);
318 for (j = 0; j < 2; j++) {
319 stringptr = findnextnumber(stringptr);
320 if (*stringptr == '\0') {
321 printf("Error: Edge %d is missing vertex %d in %s.\n",
322 i + firstnumber, j + 1, inedgefilename);
323 terminatetetgen(NULL, 1);
324 }
325 corner = (int) strtol(stringptr, &stringptr, 0);
326 if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
327 printf("Error: Edge %d has an invalid vertex index.\n",
328 i + firstnumber);
329 terminatetetgen(NULL, 1);
330 }
331 edgelist[index++] = corner;
332 }
333 if (numberofcorners == 10) {
334 // Skip an extra vertex (generated by a previous -o2 option).
335 stringptr = findnextnumber(stringptr);
336 }
337 // Read the edge marker if it has.
338 if (markers) {
339 stringptr = findnextnumber(stringptr);
340 edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
341 }
342 }
343
344 fclose(infile);
345 return true;
346}
347
348///////////////////////////////////////////////////////////////////////////////
349// //
350// load_face() Load a list of faces (triangles) from a .face file. //
351// //
352///////////////////////////////////////////////////////////////////////////////
353
354bool tetgenio::load_face(char* filebasename)
355{
356 FILE *infile;
357 char infilename[FILENAMESIZE];
358 char inputline[INPUTLINESIZE];
359 char *stringptr;
360 REAL attrib;
361 int markers, corner;
362 int index;
363 int i, j;
364
365 strcpy(infilename, filebasename);
366 strcat(infilename, ".face");
367
368 infile = fopen(infilename, "r");
369 if (infile != (FILE *) NULL) {
370 printf("Opening %s.\n", infilename);
371 } else {
372 return false;
373 }
374
375 // Read number of faces, boundary markers.
376 stringptr = readnumberline(inputline, infile, infilename);
377 numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
378 stringptr = findnextnumber(stringptr);
379 if (mesh_dim == 2) {
380 // Skip a number.
381 stringptr = findnextnumber(stringptr);
382 }
383 if (*stringptr == '\0') {
384 markers = 0; // Default there is no marker per face.
385 } else {
386 markers = (int) strtol (stringptr, &stringptr, 0);
387 }
388 if (numberoftrifaces > 0) {
389 trifacelist = new int[numberoftrifaces * 3];
390 if (trifacelist == (int *) NULL) {
391 terminatetetgen(NULL, 1);
392 }
393 if (markers) {
394 trifacemarkerlist = new int[numberoftrifaces];
395 if (trifacemarkerlist == (int *) NULL) {
396 terminatetetgen(NULL, 1);
397 }
398 }
399 }
400
401 // Read the list of faces.
402 index = 0;
403 for (i = 0; i < numberoftrifaces; i++) {
404 // Read face index and the face's three corners.
405 stringptr = readnumberline(inputline, infile, infilename);
406 for (j = 0; j < 3; j++) {
407 stringptr = findnextnumber(stringptr);
408 if (*stringptr == '\0') {
409 printf("Error: Face %d is missing vertex %d in %s.\n",
410 i + firstnumber, j + 1, infilename);
411 terminatetetgen(NULL, 1);
412 }
413 corner = (int) strtol(stringptr, &stringptr, 0);
414 if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
415 printf("Error: Face %d has an invalid vertex index.\n",
416 i + firstnumber);
417 terminatetetgen(NULL, 1);
418 }
419 trifacelist[index++] = corner;
420 }
421 if (numberofcorners == 10) {
422 // Skip 3 extra vertices (generated by a previous -o2 option).
423 for (j = 0; j < 3; j++) {
424 stringptr = findnextnumber(stringptr);
425 }
426 }
427 // Read the boundary marker if it exists.
428 if (markers) {
429 stringptr = findnextnumber(stringptr);
430 if (*stringptr == '\0') {
431 attrib = 0.0;
432 } else {
433 attrib = (REAL) strtod(stringptr, &stringptr);
434 }
435 trifacemarkerlist[i] = (int) attrib;
436 }
437 }
438
439 fclose(infile);
440
441 return true;
442}
443
444///////////////////////////////////////////////////////////////////////////////
445// //
446// load_tet() Load a list of tetrahedra from a .ele file. //
447// //
448///////////////////////////////////////////////////////////////////////////////
449
450bool tetgenio::load_tet(char* filebasename)
451{
452 FILE *infile;
453 char infilename[FILENAMESIZE];
454 char inputline[INPUTLINESIZE];
455 char *stringptr;
456 REAL attrib;
457 int corner;
458 int index, attribindex;
459 int i, j;
460
461 strcpy(infilename, filebasename);
462 strcat(infilename, ".ele");
463
464 infile = fopen(infilename, "r");
465 if (infile != (FILE *) NULL) {
466 printf("Opening %s.\n", infilename);
467 } else {
468 return false;
469 }
470
471 // Read number of elements, number of corners (4 or 10), number of
472 // element attributes.
473 stringptr = readnumberline(inputline, infile, infilename);
474 numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
475 if (numberoftetrahedra <= 0) {
476 printf("Error: Invalid number of tetrahedra.\n");
477 fclose(infile);
478 return false;
479 }
480 stringptr = findnextnumber(stringptr);
481 if (*stringptr == '\0') {
482 numberofcorners = 4; // Default read 4 nodes per element.
483 } else {
484 numberofcorners = (int) strtol(stringptr, &stringptr, 0);
485 }
486 stringptr = findnextnumber(stringptr);
487 if (*stringptr == '\0') {
488 numberoftetrahedronattributes = 0; // Default no attribute.
489 } else {
490 numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
491 }
492 if (numberofcorners != 4 && numberofcorners != 10) {
493 printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
494 numberofcorners);
495 fclose(infile);
496 return false;
497 }
498
499 // Allocate memory for tetrahedra.
500 tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
501 if (tetrahedronlist == (int *) NULL) {
502 terminatetetgen(NULL, 1);
503 }
504 // Allocate memory for output tetrahedron attributes if necessary.
505 if (numberoftetrahedronattributes > 0) {
506 tetrahedronattributelist = new REAL[numberoftetrahedra *
507 numberoftetrahedronattributes];
508 if (tetrahedronattributelist == (REAL *) NULL) {
509 terminatetetgen(NULL, 1);
510 }
511 }
512
513 // Read the list of tetrahedra.
514 index = 0;
515 attribindex = 0;
516 for (i = 0; i < numberoftetrahedra; i++) {
517 // Read tetrahedron index and the tetrahedron's corners.
518 stringptr = readnumberline(inputline, infile, infilename);
519 for (j = 0; j < numberofcorners; j++) {
520 stringptr = findnextnumber(stringptr);
521 if (*stringptr == '\0') {
522 printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
523 i + firstnumber, j + 1, infilename);
524 terminatetetgen(NULL, 1);
525 }
526 corner = (int) strtol(stringptr, &stringptr, 0);
527 if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
528 printf("Error: Tetrahedron %d has an invalid vertex index.\n",
529 i + firstnumber);
530 terminatetetgen(NULL, 1);
531 }
532 tetrahedronlist[index++] = corner;
533 }
534 // Read the tetrahedron's attributes.
535 for (j = 0; j < numberoftetrahedronattributes; j++) {
536 stringptr = findnextnumber(stringptr);
537 if (*stringptr == '\0') {
538 attrib = 0.0;
539 } else {
540 attrib = (REAL) strtod(stringptr, &stringptr);
541 }
542 tetrahedronattributelist[attribindex++] = attrib;
543 }
544 }
545
546 fclose(infile);
547
548 return true;
549}
550
551///////////////////////////////////////////////////////////////////////////////
552// //
553// load_vol() Load a list of volume constraints from a .vol file. //
554// //
555///////////////////////////////////////////////////////////////////////////////
556
557bool tetgenio::load_vol(char* filebasename)
558{
559 FILE *infile;
560 char inelefilename[FILENAMESIZE];
561 char infilename[FILENAMESIZE];
562 char inputline[INPUTLINESIZE];
563 char *stringptr;
564 REAL volume;
565 int volelements;
566 int i;
567
568 strcpy(infilename, filebasename);
569 strcat(infilename, ".vol");
570
571 infile = fopen(infilename, "r");
572 if (infile != (FILE *) NULL) {
573 printf("Opening %s.\n", infilename);
574 } else {
575 return false;
576 }
577
578 // Read number of tetrahedra.
579 stringptr = readnumberline(inputline, infile, infilename);
580 volelements = (int) strtol (stringptr, &stringptr, 0);
581 if (volelements != numberoftetrahedra) {
582 strcpy(inelefilename, filebasename);
583 strcat(infilename, ".ele");
584 printf("Warning: %s and %s disagree on number of tetrahedra.\n",
585 inelefilename, infilename);
586 fclose(infile);
587 return false;
588 }
589
590 tetrahedronvolumelist = new REAL[volelements];
591 if (tetrahedronvolumelist == (REAL *) NULL) {
592 terminatetetgen(NULL, 1);
593 }
594
595 // Read the list of volume constraints.
596 for (i = 0; i < volelements; i++) {
597 stringptr = readnumberline(inputline, infile, infilename);
598 stringptr = findnextnumber(stringptr);
599 if (*stringptr == '\0') {
600 volume = -1.0; // No constraint on this tetrahedron.
601 } else {
602 volume = (REAL) strtod(stringptr, &stringptr);
603 }
604 tetrahedronvolumelist[i] = volume;
605 }
606
607 fclose(infile);
608
609 return true;
610}
611
612///////////////////////////////////////////////////////////////////////////////
613// //
614// load_var() Load constraints applied on facets, segments, and nodes //
615// from a .var file. //
616// //
617///////////////////////////////////////////////////////////////////////////////
618
619bool tetgenio::load_var(char* filebasename)
620{
621 FILE *infile;
622 char varfilename[FILENAMESIZE];
623 char inputline[INPUTLINESIZE];
624 char *stringptr;
625 int index;
626 int i;
627
628 // Variant constraints are saved in file "filename.var".
629 strcpy(varfilename, filebasename);
630 strcat(varfilename, ".var");
631 infile = fopen(varfilename, "r");
632 if (infile != (FILE *) NULL) {
633 printf("Opening %s.\n", varfilename);
634 } else {
635 return false;
636 }
637
638 // Read the facet constraint section.
639 stringptr = readnumberline(inputline, infile, varfilename);
640 if (*stringptr != '\0') {
641 numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
642 } else {
643 numberoffacetconstraints = 0;
644 }
645 if (numberoffacetconstraints > 0) {
646 // Initialize 'facetconstraintlist'.
647 facetconstraintlist = new REAL[numberoffacetconstraints * 2];
648 index = 0;
649 for (i = 0; i < numberoffacetconstraints; i++) {
650 stringptr = readnumberline(inputline, infile, varfilename);
651 stringptr = findnextnumber(stringptr);
652 if (*stringptr == '\0') {
653 printf("Error: facet constraint %d has no facet marker.\n",
654 firstnumber + i);
655 break;
656 } else {
657 facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
658 }
659 stringptr = findnextnumber(stringptr);
660 if (*stringptr == '\0') {
661 printf("Error: facet constraint %d has no maximum area bound.\n",
662 firstnumber + i);
663 break;
664 } else {
665 facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
666 }
667 }
668 if (i < numberoffacetconstraints) {
669 // This must be caused by an error.
670 fclose(infile);
671 return false;
672 }
673 }
674
675 // Read the segment constraint section.
676 stringptr = readnumberline(inputline, infile, varfilename);
677 if (*stringptr != '\0') {
678 numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
679 } else {
680 numberofsegmentconstraints = 0;
681 }
682 if (numberofsegmentconstraints > 0) {
683 // Initialize 'segmentconstraintlist'.
684 segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
685 index = 0;
686 for (i = 0; i < numberofsegmentconstraints; i++) {
687 stringptr = readnumberline(inputline, infile, varfilename);
688 stringptr = findnextnumber(stringptr);
689 if (*stringptr == '\0') {
690 printf("Error: segment constraint %d has no frist endpoint.\n",
691 firstnumber + i);
692 break;
693 } else {
694 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
695 }
696 stringptr = findnextnumber(stringptr);
697 if (*stringptr == '\0') {
698 printf("Error: segment constraint %d has no second endpoint.\n",
699 firstnumber + i);
700 break;
701 } else {
702 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
703 }
704 stringptr = findnextnumber(stringptr);
705 if (*stringptr == '\0') {
706 printf("Error: segment constraint %d has no maximum length bound.\n",
707 firstnumber + i);
708 break;
709 } else {
710 segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
711 }
712 }
713 if (i < numberofsegmentconstraints) {
714 // This must be caused by an error.
715 fclose(infile);
716 return false;
717 }
718 }
719
720 fclose(infile);
721 return true;
722}
723
724///////////////////////////////////////////////////////////////////////////////
725// //
726// load_mtr() Load a size specification map from a .mtr file. //
727// //
728///////////////////////////////////////////////////////////////////////////////
729
730bool tetgenio::load_mtr(char* filebasename)
731{
732 FILE *infile;
733 char mtrfilename[FILENAMESIZE];
734 char inputline[INPUTLINESIZE];
735 char *stringptr;
736 REAL mtr;
737 int ptnum;
738 int mtrindex;
739 int i, j;
740
741 strcpy(mtrfilename, filebasename);
742 strcat(mtrfilename, ".mtr");
743 infile = fopen(mtrfilename, "r");
744 if (infile != (FILE *) NULL) {
745 printf("Opening %s.\n", mtrfilename);
746 } else {
747 return false;
748 }
749
750 // Read the number of points.
751 stringptr = readnumberline(inputline, infile, mtrfilename);
752 ptnum = (int) strtol (stringptr, &stringptr, 0);
753 if (ptnum != numberofpoints) {
754 printf(" !! Point numbers are not equal. Ignored.\n");
755 fclose(infile);
756 return false;
757 }
758 // Read the number of columns (1, 3, or 6).
759 stringptr = findnextnumber(stringptr); // Skip number of points.
760 if (*stringptr != '\0') {
761 numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
762 }
763 if (numberofpointmtrs == 0) {
764 // Column number doesn't match. Set a default number (1).
765 numberofpointmtrs = 1;
766 }
767
768 // Allocate space for pointmtrlist.
769 pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
770 if (pointmtrlist == (REAL *) NULL) {
771 terminatetetgen(NULL, 1);
772 }
773 mtrindex = 0;
774 for (i = 0; i < numberofpoints; i++) {
775 // Read metrics.
776 stringptr = readnumberline(inputline, infile, mtrfilename);
777 for (j = 0; j < numberofpointmtrs; j++) {
778 if (*stringptr == '\0') {
779 printf("Error: Metric %d is missing value #%d in %s.\n",
780 i + firstnumber, j + 1, mtrfilename);
781 terminatetetgen(NULL, 1);
782 }
783 mtr = (REAL) strtod(stringptr, &stringptr);
784 pointmtrlist[mtrindex++] = mtr;
785 stringptr = findnextnumber(stringptr);
786 }
787 }
788
789 fclose(infile);
790 return true;
791}
792
793///////////////////////////////////////////////////////////////////////////////
794// //
795// load_poly() Load a PL complex from a .poly or a .smesh file. //
796// //
797///////////////////////////////////////////////////////////////////////////////
798
799bool tetgenio::load_poly(char* filebasename)
800{
801 FILE *infile;
802 char inpolyfilename[FILENAMESIZE];
803 char insmeshfilename[FILENAMESIZE];
804 char inputline[INPUTLINESIZE];
805 char *stringptr, *infilename;
806 int smesh, markers, uvflag, currentmarker;
807 int index;
808 int i, j, k;
809
810 // Assembling the actual file names we want to open.
811 strcpy(inpolyfilename, filebasename);
812 strcpy(insmeshfilename, filebasename);
813 strcat(inpolyfilename, ".poly");
814 strcat(insmeshfilename, ".smesh");
815
816 // First assume it is a .poly file.
817 smesh = 0;
818 // Try to open a .poly file.
819 infile = fopen(inpolyfilename, "r");
820 if (infile == (FILE *) NULL) {
821 // .poly doesn't exist! Try to open a .smesh file.
822 infile = fopen(insmeshfilename, "r");
823 if (infile == (FILE *) NULL) {
824 printf(" Cannot access file %s and %s.\n",
825 inpolyfilename, insmeshfilename);
826 return false;
827 } else {
828 printf("Opening %s.\n", insmeshfilename);
829 infilename = insmeshfilename;
830 }
831 smesh = 1;
832 } else {
833 printf("Opening %s.\n", inpolyfilename);
834 infilename = inpolyfilename;
835 }
836
837 // Initialize the default values.
838 mesh_dim = 3; // Three-dimensional coordinates.
839 numberofpointattributes = 0; // no point attribute.
840 markers = 0; // no boundary marker.
841 uvflag = 0; // no uv parameters (required by a PSC).
842
843 // Read number of points, number of dimensions, number of point
844 // attributes, and number of boundary markers.
845 stringptr = readnumberline(inputline, infile, infilename);
846 numberofpoints = (int) strtol (stringptr, &stringptr, 0);
847 stringptr = findnextnumber(stringptr);
848 if (*stringptr != '\0') {
849 mesh_dim = (int) strtol (stringptr, &stringptr, 0);
850 }
851 stringptr = findnextnumber(stringptr);
852 if (*stringptr != '\0') {
853 numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
854 }
855 stringptr = findnextnumber(stringptr);
856 if (*stringptr != '\0') {
857 markers = (int) strtol (stringptr, &stringptr, 0);
858 }
859 if (*stringptr != '\0') {
860 uvflag = (int) strtol (stringptr, &stringptr, 0);
861 }
862
863 if (numberofpoints > 0) {
864 // Load the list of nodes.
865 if (!load_node_call(infile, markers, uvflag, infilename)) {
866 fclose(infile);
867 return false;
868 }
869 } else {
870 // If the .poly or .smesh file claims there are zero points, that
871 // means the points should be read from a separate .node file.
872 if (!load_node(filebasename)) {
873 fclose(infile);
874 return false;
875 }
876 }
877
878 if ((mesh_dim != 3) && (mesh_dim != 2)) {
879 printf("Input error: TetGen only works for 2D & 3D point sets.\n");
880 fclose(infile);
881 return false;
882 }
883 if (numberofpoints < (mesh_dim + 1)) {
884 printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
885 fclose(infile);
886 return false;
887 }
888
889 facet *f;
890 polygon *p;
891
892 if (mesh_dim == 3) {
893
894 // Read number of facets and number of boundary markers.
895 stringptr = readnumberline(inputline, infile, infilename);
896 if (stringptr == NULL) {
897 // No facet list, return.
898 fclose(infile);
899 return true;
900 }
901 numberoffacets = (int) strtol (stringptr, &stringptr, 0);
902 if (numberoffacets <= 0) {
903 // No facet list, return.
904 fclose(infile);
905 return true;
906 }
907 stringptr = findnextnumber(stringptr);
908 if (*stringptr == '\0') {
909 markers = 0; // no boundary marker.
910 } else {
911 markers = (int) strtol (stringptr, &stringptr, 0);
912 }
913
914 // Initialize the 'facetlist', 'facetmarkerlist'.
915 facetlist = new facet[numberoffacets];
916 if (markers == 1) {
917 facetmarkerlist = new int[numberoffacets];
918 }
919
920 // Read data into 'facetlist', 'facetmarkerlist'.
921 if (smesh == 0) {
922 // Facets are in .poly file format.
923 for (i = 1; i <= numberoffacets; i++) {
924 f = &(facetlist[i - 1]);
925 init(f);
926 f->numberofholes = 0;
927 currentmarker = 0;
928 // Read number of polygons, number of holes, and a boundary marker.
929 stringptr = readnumberline(inputline, infile, infilename);
930 f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
931 stringptr = findnextnumber(stringptr);
932 if (*stringptr != '\0') {
933 f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
934 if (markers == 1) {
935 stringptr = findnextnumber(stringptr);
936 if (*stringptr != '\0') {
937 currentmarker = (int) strtol(stringptr, &stringptr, 0);
938 }
939 }
940 }
941 // Initialize facetmarker if it needs.
942 if (markers == 1) {
943 facetmarkerlist[i - 1] = currentmarker;
944 }
945 // Each facet should has at least one polygon.
946 if (f->numberofpolygons <= 0) {
947 printf("Error: Wrong number of polygon in %d facet.\n", i);
948 break;
949 }
950 // Initialize the 'f->polygonlist'.
951 f->polygonlist = new polygon[f->numberofpolygons];
952 // Go through all polygons, read in their vertices.
953 for (j = 1; j <= f->numberofpolygons; j++) {
954 p = &(f->polygonlist[j - 1]);
955 init(p);
956 // Read number of vertices of this polygon.
957 stringptr = readnumberline(inputline, infile, infilename);
958 p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
959 if (p->numberofvertices < 1) {
960 printf("Error: Wrong polygon %d in facet %d\n", j, i);
961 break;
962 }
963 // Initialize 'p->vertexlist'.
964 p->vertexlist = new int[p->numberofvertices];
965 // Read all vertices of this polygon.
966 for (k = 1; k <= p->numberofvertices; k++) {
967 stringptr = findnextnumber(stringptr);
968 if (*stringptr == '\0') {
969 // Try to load another non-empty line and continue to read the
970 // rest of vertices.
971 stringptr = readnumberline(inputline, infile, infilename);
972 if (*stringptr == '\0') {
973 printf("Error: Missing %d endpoints of polygon %d in facet %d",
974 p->numberofvertices - k, j, i);
975 break;
976 }
977 }
978 p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
979 }
980 }
981 if (j <= f->numberofpolygons) {
982 // This must be caused by an error. However, there're j - 1
983 // polygons have been read. Reset the 'f->numberofpolygon'.
984 if (j == 1) {
985 // This is the first polygon.
986 delete [] f->polygonlist;
987 }
988 f->numberofpolygons = j - 1;
989 // No hole will be read even it exists.
990 f->numberofholes = 0;
991 break;
992 }
993 // If this facet has hole pints defined, read them.
994 if (f->numberofholes > 0) {
995 // Initialize 'f->holelist'.
996 f->holelist = new REAL[f->numberofholes * 3];
997 // Read the holes' coordinates.
998 index = 0;
999 for (j = 1; j <= f->numberofholes; j++) {
1000 stringptr = readnumberline(inputline, infile, infilename);
1001 for (k = 1; k <= 3; k++) {
1002 stringptr = findnextnumber(stringptr);
1003 if (*stringptr == '\0') {
1004 printf("Error: Hole %d in facet %d has no coordinates", j, i);
1005 break;
1006 }
1007 f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1008 }
1009 if (k <= 3) {
1010 // This must be caused by an error.
1011 break;
1012 }
1013 }
1014 if (j <= f->numberofholes) {
1015 // This must be caused by an error.
1016 break;
1017 }
1018 }
1019 }
1020 if (i <= numberoffacets) {
1021 // This must be caused by an error.
1022 numberoffacets = i - 1;
1023 fclose(infile);
1024 return false;
1025 }
1026 } else { // poly == 0
1027 // Read the facets from a .smesh file.
1028 for (i = 1; i <= numberoffacets; i++) {
1029 f = &(facetlist[i - 1]);
1030 init(f);
1031 // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1032 // contains exactly one polygon, no hole.
1033 f->numberofpolygons = 1;
1034 f->polygonlist = new polygon[f->numberofpolygons];
1035 p = &(f->polygonlist[0]);
1036 init(p);
1037 // Read number of vertices of this polygon.
1038 stringptr = readnumberline(inputline, infile, insmeshfilename);
1039 p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1040 if (p->numberofvertices < 1) {
1041 printf("Error: Wrong number of vertex in facet %d\n", i);
1042 break;
1043 }
1044 // Initialize 'p->vertexlist'.
1045 p->vertexlist = new int[p->numberofvertices];
1046 for (k = 1; k <= p->numberofvertices; k++) {
1047 stringptr = findnextnumber(stringptr);
1048 if (*stringptr == '\0') {
1049 // Try to load another non-empty line and continue to read the
1050 // rest of vertices.
1051 stringptr = readnumberline(inputline, infile, infilename);
1052 if (*stringptr == '\0') {
1053 printf("Error: Missing %d endpoints in facet %d",
1054 p->numberofvertices - k, i);
1055 break;
1056 }
1057 }
1058 p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1059 }
1060 if (k <= p->numberofvertices) {
1061 // This must be caused by an error.
1062 break;
1063 }
1064 // Read facet's boundary marker at last.
1065 if (markers == 1) {
1066 stringptr = findnextnumber(stringptr);
1067 if (*stringptr == '\0') {
1068 currentmarker = 0;
1069 } else {
1070 currentmarker = (int) strtol(stringptr, &stringptr, 0);
1071 }
1072 facetmarkerlist[i - 1] = currentmarker;
1073 }
1074 }
1075 if (i <= numberoffacets) {
1076 // This must be caused by an error.
1077 numberoffacets = i - 1;
1078 fclose(infile);
1079 return false;
1080 }
1081 }
1082
1083 // Read the hole section.
1084 stringptr = readnumberline(inputline, infile, infilename);
1085 if (stringptr == NULL) {
1086 // No hole list, return.
1087 fclose(infile);
1088 return true;
1089 }
1090 if (*stringptr != '\0') {
1091 numberofholes = (int) strtol (stringptr, &stringptr, 0);
1092 } else {
1093 numberofholes = 0;
1094 }
1095 if (numberofholes > 0) {
1096 // Initialize 'holelist'.
1097 holelist = new REAL[numberofholes * 3];
1098 for (i = 0; i < 3 * numberofholes; i += 3) {
1099 stringptr = readnumberline(inputline, infile, infilename);
1100 stringptr = findnextnumber(stringptr);
1101 if (*stringptr == '\0') {
1102 printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
1103 break;
1104 } else {
1105 holelist[i] = (REAL) strtod(stringptr, &stringptr);
1106 }
1107 stringptr = findnextnumber(stringptr);
1108 if (*stringptr == '\0') {
1109 printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
1110 break;
1111 } else {
1112 holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1113 }
1114 stringptr = findnextnumber(stringptr);
1115 if (*stringptr == '\0') {
1116 printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
1117 break;
1118 } else {
1119 holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1120 }
1121 }
1122 if (i < 3 * numberofholes) {
1123 // This must be caused by an error.
1124 fclose(infile);
1125 return false;
1126 }
1127 }
1128
1129 // Read the region section. The 'region' section is optional, if we
1130 // don't reach the end-of-file, try read it in.
1131 stringptr = readnumberline(inputline, infile, NULL);
1132 if (stringptr != (char *) NULL && *stringptr != '\0') {
1133 numberofregions = (int) strtol (stringptr, &stringptr, 0);
1134 } else {
1135 numberofregions = 0;
1136 }
1137 if (numberofregions > 0) {
1138 // Initialize 'regionlist'.
1139 regionlist = new REAL[numberofregions * 5];
1140 index = 0;
1141 for (i = 0; i < numberofregions; i++) {
1142 stringptr = readnumberline(inputline, infile, infilename);
1143 stringptr = findnextnumber(stringptr);
1144 if (*stringptr == '\0') {
1145 printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
1146 break;
1147 } else {
1148 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1149 }
1150 stringptr = findnextnumber(stringptr);
1151 if (*stringptr == '\0') {
1152 printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
1153 break;
1154 } else {
1155 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1156 }
1157 stringptr = findnextnumber(stringptr);
1158 if (*stringptr == '\0') {
1159 printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
1160 break;
1161 } else {
1162 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1163 }
1164 stringptr = findnextnumber(stringptr);
1165 if (*stringptr == '\0') {
1166 printf("Error: Region %d has no region attrib.\n", firstnumber + i);
1167 break;
1168 } else {
1169 regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1170 }
1171 stringptr = findnextnumber(stringptr);
1172 if (*stringptr == '\0') {
1173 regionlist[index] = regionlist[index - 1];
1174 } else {
1175 regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1176 }
1177 index++;
1178 }
1179 if (i < numberofregions) {
1180 // This must be caused by an error.
1181 fclose(infile);
1182 return false;
1183 }
1184 }
1185
1186 } else {
1187
1188 // Read a PSLG from Triangle's poly file.
1189 assert(mesh_dim == 2);
1190 // A PSLG is a facet of a PLC.
1191 numberoffacets = 1;
1192 // Initialize the 'facetlist'.
1193 facetlist = new facet[numberoffacets];
1194 facetmarkerlist = (int *) NULL; // No facet markers.
1195 f = &(facetlist[0]);
1196 init(f);
1197 // Read number of segments.
1198 stringptr = readnumberline(inputline, infile, infilename);
1199 // Segments are degenerate polygons.
1200 f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
1201 if (f->numberofpolygons > 0) {
1202 f->polygonlist = new polygon[f->numberofpolygons];
1203 }
1204 // Go through all segments, read in their vertices.
1205 for (j = 0; j < f->numberofpolygons; j++) {
1206 p = &(f->polygonlist[j]);
1207 init(p);
1208 // Read in a segment.
1209 stringptr = readnumberline(inputline, infile, infilename);
1210 stringptr = findnextnumber(stringptr); // Skip its index.
1211 p->numberofvertices = 2; // A segment always has two vertices.
1212 p->vertexlist = new int[p->numberofvertices];
1213 p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
1214 stringptr = findnextnumber(stringptr);
1215 p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
1216 }
1217 // Read number of holes.
1218 stringptr = readnumberline(inputline, infile, infilename);
1219 f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
1220 if (f->numberofholes > 0) {
1221 // Initialize 'f->holelist'.
1222 f->holelist = new REAL[f->numberofholes * 3];
1223 // Read the holes' coordinates.
1224 for (j = 0; j < f->numberofholes; j++) {
1225 // Read a 2D hole point.
1226 stringptr = readnumberline(inputline, infile, infilename);
1227 stringptr = findnextnumber(stringptr); // Skip its index.
1228 f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
1229 stringptr = findnextnumber(stringptr);
1230 f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
1231 f->holelist[j * 3 + 2] = 0.0; // The z-coord.
1232 }
1233 }
1234 // The regions are skipped.
1235
1236 }
1237
1238 // End of reading poly/smesh file.
1239 fclose(infile);
1240 return true;
1241}
1242
1243///////////////////////////////////////////////////////////////////////////////
1244// //
1245// load_off() Load a polyhedron from a .off file. //
1246// //
1247// The .off format is one of file formats of the Geomview, an interactive //
1248// program for viewing and manipulating geometric objects. More information //
1249// is available form: http://www.geomview.org. //
1250// //
1251///////////////////////////////////////////////////////////////////////////////
1252
1253bool tetgenio::load_off(char* filebasename)
1254{
1255 FILE *fp;
1256 tetgenio::facet *f;
1257 tetgenio::polygon *p;
1258 char infilename[FILENAMESIZE];
1259 char buffer[INPUTLINESIZE];
1260 char *bufferp;
1261 double *coord;
1262 int nverts = 0, iverts = 0;
1263 int nfaces = 0, ifaces = 0;
1264 int nedges = 0;
1265 int line_count = 0, i;
1266
1267 // Default, the off file's index is from '0'. We check it by remembering the
1268 // smallest index we found in the file. It should be either 0 or 1.
1269 int smallestidx = 0;
1270
1271 strncpy(infilename, filebasename, 1024 - 1);
1272 infilename[FILENAMESIZE - 1] = '\0';
1273 if (infilename[0] == '\0') {
1274 printf("Error: No filename.\n");
1275 return false;
1276 }
1277 if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1278 strcat(infilename, ".off");
1279 }
1280
1281 if (!(fp = fopen(infilename, "r"))) {
1282 printf(" Unable to open file %s\n", infilename);
1283 return false;
1284 }
1285 printf("Opening %s.\n", infilename);
1286
1287 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1288 // Check section
1289 if (nverts == 0) {
1290 // Read header
1291 bufferp = strstr(bufferp, "OFF");
1292 if (bufferp != NULL) {
1293 // Read mesh counts
1294 bufferp = findnextnumber(bufferp); // Skip field "OFF".
1295 if (*bufferp == '\0') {
1296 // Read a non-empty line.
1297 bufferp = readline(buffer, fp, &line_count);
1298 }
1299 if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1300 || (nverts == 0)) {
1301 printf("Syntax error reading header on line %d in file %s\n",
1302 line_count, infilename);
1303 fclose(fp);
1304 return false;
1305 }
1306 // Allocate memory for 'tetgenio'
1307 if (nverts > 0) {
1308 numberofpoints = nverts;
1309 pointlist = new REAL[nverts * 3];
1310 smallestidx = nverts + 1; // A bigger enough number.
1311 }
1312 if (nfaces > 0) {
1313 numberoffacets = nfaces;
1314 facetlist = new tetgenio::facet[nfaces];
1315 }
1316 }
1317 } else if (iverts < nverts) {
1318 // Read vertex coordinates
1319 coord = &pointlist[iverts * 3];
1320 for (i = 0; i < 3; i++) {
1321 if (*bufferp == '\0') {
1322 printf("Syntax error reading vertex coords on line %d in file %s\n",
1323 line_count, infilename);
1324 fclose(fp);
1325 return false;
1326 }
1327 coord[i] = (REAL) strtod(bufferp, &bufferp);
1328 bufferp = findnextnumber(bufferp);
1329 }
1330 iverts++;
1331 } else if (ifaces < nfaces) {
1332 // Get next face
1333 f = &facetlist[ifaces];
1334 init(f);
1335 // In .off format, each facet has one polygon, no hole.
1336 f->numberofpolygons = 1;
1337 f->polygonlist = new tetgenio::polygon[1];
1338 p = &f->polygonlist[0];
1339 init(p);
1340 // Read the number of vertices, it should be greater than 0.
1341 p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1342 if (p->numberofvertices == 0) {
1343 printf("Syntax error reading polygon on line %d in file %s\n",
1344 line_count, infilename);
1345 fclose(fp);
1346 return false;
1347 }
1348 // Allocate memory for face vertices
1349 p->vertexlist = new int[p->numberofvertices];
1350 for (i = 0; i < p->numberofvertices; i++) {
1351 bufferp = findnextnumber(bufferp);
1352 if (*bufferp == '\0') {
1353 printf("Syntax error reading polygon on line %d in file %s\n",
1354 line_count, infilename);
1355 fclose(fp);
1356 return false;
1357 }
1358 p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1359 // Detect the smallest index.
1360 if (p->vertexlist[i] < smallestidx) {
1361 smallestidx = p->vertexlist[i];
1362 }
1363 }
1364 ifaces++;
1365 } else {
1366 // Should never get here
1367 printf("Found extra text starting at line %d in file %s\n", line_count,
1368 infilename);
1369 break;
1370 }
1371 }
1372
1373 // Close file
1374 fclose(fp);
1375
1376 // Decide the firstnumber of the index.
1377 if (smallestidx == 0) {
1378 firstnumber = 0;
1379 } else if (smallestidx == 1) {
1380 firstnumber = 1;
1381 } else {
1382 printf("A wrong smallest index (%d) was detected in file %s\n",
1383 smallestidx, infilename);
1384 return false;
1385 }
1386
1387 if (iverts != nverts) {
1388 printf("Expected %d vertices, but read only %d vertices in file %s\n",
1389 nverts, iverts, infilename);
1390 return false;
1391 }
1392 if (ifaces != nfaces) {
1393 printf("Expected %d faces, but read only %d faces in file %s\n",
1394 nfaces, ifaces, infilename);
1395 return false;
1396 }
1397
1398 return true;
1399}
1400
1401///////////////////////////////////////////////////////////////////////////////
1402// //
1403// load_ply() Load a polyhedron from a .ply file. //
1404// //
1405// This is a simplified version of reading .ply files, which only reads the //
1406// set of vertices and the set of faces. Other informations (such as color, //
1407// material, texture, etc) in .ply file are ignored. Complete routines for //
1408// reading and writing ,ply files are available from: http://www.cc.gatech. //
1409// edu/projects/large_models/ply.html. Except the header section, ply file //
1410// format has exactly the same format for listing vertices and polygons as //
1411// off file format. //
1412// //
1413///////////////////////////////////////////////////////////////////////////////
1414
1415bool tetgenio::load_ply(char* filebasename)
1416{
1417 FILE *fp;
1418 tetgenio::facet *f;
1419 tetgenio::polygon *p;
1420 char infilename[FILENAMESIZE];
1421 char buffer[INPUTLINESIZE];
1422 char *bufferp, *str;
1423 double *coord;
1424 int endheader = 0, format = 0;
1425 int nverts = 0, iverts = 0;
1426 int nfaces = 0, ifaces = 0;
1427 int line_count = 0, i;
1428
1429 // Default, the ply file's index is from '0'. We check it by remembering the
1430 // smallest index we found in the file. It should be either 0 or 1.
1431 int smallestidx = 0;
1432
1433 strncpy(infilename, filebasename, FILENAMESIZE - 1);
1434 infilename[FILENAMESIZE - 1] = '\0';
1435 if (infilename[0] == '\0') {
1436 printf("Error: No filename.\n");
1437 return false;
1438 }
1439 if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1440 strcat(infilename, ".ply");
1441 }
1442
1443 if (!(fp = fopen(infilename, "r"))) {
1444 printf("Error: Unable to open file %s\n", infilename);
1445 return false;
1446 }
1447 printf("Opening %s.\n", infilename);
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 smallestidx = nverts + 1; // A big enough index.
1492 }
1493 }
1494 }
1495 if (nfaces == 0) {
1496 // Find if it is the keyword "face".
1497 str = strstr(bufferp, "face");
1498 if (!str) str = strstr(bufferp, "Face");
1499 if (str) {
1500 bufferp = findnextnumber(str);
1501 if (*bufferp == '\0') {
1502 printf("Syntax error reading face number on line");
1503 printf(" %d in file %s\n", line_count, infilename);
1504 fclose(fp);
1505 return false;
1506 }
1507 nfaces = (int) strtol(bufferp, &bufferp, 0);
1508 // Allocate memory for 'tetgenio'
1509 if (nfaces > 0) {
1510 numberoffacets = nfaces;
1511 facetlist = new tetgenio::facet[nfaces];
1512 }
1513 }
1514 }
1515 } // It is not the string "element".
1516 }
1517 if (format == 0) {
1518 // Find the keyword "format".
1519 str = strstr(bufferp, "format");
1520 if (!str) str = strstr(bufferp, "Format");
1521 if (str) {
1522 format = 1;
1523 bufferp = findnextfield(str);
1524 // Find if it is the string "ascii".
1525 str = strstr(bufferp, "ascii");
1526 if (!str) str = strstr(bufferp, "ASCII");
1527 if (!str) {
1528 printf("This routine only reads ascii format of ply files.\n");
1529 printf("Hint: You can convert the binary to ascii format by\n");
1530 printf(" using the provided ply tools:\n");
1531 printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
1532 fclose(fp);
1533 return false;
1534 }
1535 }
1536 }
1537 } else if (iverts < nverts) {
1538 // Read vertex coordinates
1539 coord = &pointlist[iverts * 3];
1540 for (i = 0; i < 3; i++) {
1541 if (*bufferp == '\0') {
1542 printf("Syntax error reading vertex coords on line %d in file %s\n",
1543 line_count, infilename);
1544 fclose(fp);
1545 return false;
1546 }
1547 coord[i] = (REAL) strtod(bufferp, &bufferp);
1548 bufferp = findnextnumber(bufferp);
1549 }
1550 iverts++;
1551 } else if (ifaces < nfaces) {
1552 // Get next face
1553 f = &facetlist[ifaces];
1554 init(f);
1555 // In .off format, each facet has one polygon, no hole.
1556 f->numberofpolygons = 1;
1557 f->polygonlist = new tetgenio::polygon[1];
1558 p = &f->polygonlist[0];
1559 init(p);
1560 // Read the number of vertices, it should be greater than 0.
1561 p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1562 if (p->numberofvertices == 0) {
1563 printf("Syntax error reading polygon on line %d in file %s\n",
1564 line_count, infilename);
1565 fclose(fp);
1566 return false;
1567 }
1568 // Allocate memory for face vertices
1569 p->vertexlist = new int[p->numberofvertices];
1570 for (i = 0; i < p->numberofvertices; i++) {
1571 bufferp = findnextnumber(bufferp);
1572 if (*bufferp == '\0') {
1573 printf("Syntax error reading polygon on line %d in file %s\n",
1574 line_count, infilename);
1575 fclose(fp);
1576 return false;
1577 }
1578 p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1579 if (p->vertexlist[i] < smallestidx) {
1580 smallestidx = p->vertexlist[i];
1581 }
1582 }
1583 ifaces++;
1584 } else {
1585 // Should never get here
1586 printf("Found extra text starting at line %d in file %s\n", line_count,
1587 infilename);
1588 break;
1589 }
1590 }
1591
1592 // Close file
1593 fclose(fp);
1594
1595 // Decide the firstnumber of the index.
1596 if (smallestidx == 0) {
1597 firstnumber = 0;
1598 } else if (smallestidx == 1) {
1599 firstnumber = 1;
1600 } else {
1601 printf("A wrong smallest index (%d) was detected in file %s\n",
1602 smallestidx, infilename);
1603 return false;
1604 }
1605
1606 if (iverts != nverts) {
1607 printf("Expected %d vertices, but read only %d vertices in file %s\n",
1608 nverts, iverts, infilename);
1609 return false;
1610 }
1611 if (ifaces != nfaces) {
1612 printf("Expected %d faces, but read only %d faces in file %s\n",
1613 nfaces, ifaces, infilename);
1614 return false;
1615 }
1616
1617 return true;
1618}
1619
1620///////////////////////////////////////////////////////////////////////////////
1621// //
1622// load_stl() Load a surface mesh from a .stl file. //
1623// //
1624// The .stl or stereolithography format is an ASCII or binary file used in //
1625// manufacturing. It is a list of the triangular surfaces that describe a //
1626// computer generated solid model. This is the standard input for most rapid //
1627// prototyping machines. //
1628// //
1629// Comment: A .stl file many contain many duplicated points. They will be //
1630// unified during the Delaunay tetrahedralization process. //
1631// //
1632///////////////////////////////////////////////////////////////////////////////
1633
1634bool tetgenio::load_stl(char* filebasename)
1635{
1636 FILE *fp;
1637 tetgenmesh::arraypool *plist;
1638 tetgenio::facet *f;
1639 tetgenio::polygon *p;
1640 char infilename[FILENAMESIZE];
1641 char buffer[INPUTLINESIZE];
1642 char *bufferp, *str;
1643 double *coord;
1644 int solid = 0;
1645 int nverts = 0, iverts = 0;
1646 int nfaces = 0;
1647 int line_count = 0, i;
1648
1649 strncpy(infilename, filebasename, FILENAMESIZE - 1);
1650 infilename[FILENAMESIZE - 1] = '\0';
1651 if (infilename[0] == '\0') {
1652 printf("Error: No filename.\n");
1653 return false;
1654 }
1655 if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1656 strcat(infilename, ".stl");
1657 }
1658
1659 if (!(fp = fopen(infilename, "r"))) {
1660 printf("Error: Unable to open file %s\n", infilename);
1661 return false;
1662 }
1663 printf("Opening %s.\n", infilename);
1664
1665 // STL file has no number of points available. Use a list to read points.
1666 plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10);
1667
1668 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1669 // The ASCII .stl file must start with the lower case keyword solid and
1670 // end with endsolid.
1671 if (solid == 0) {
1672 // Read header
1673 bufferp = strstr(bufferp, "solid");
1674 if (bufferp != NULL) {
1675 solid = 1;
1676 }
1677 } else {
1678 // We're inside the block of the solid.
1679 str = bufferp;
1680 // Is this the end of the solid.
1681 bufferp = strstr(bufferp, "endsolid");
1682 if (bufferp != NULL) {
1683 solid = 0;
1684 } else {
1685 // Read the XYZ coordinates if it is a vertex.
1686 bufferp = str;
1687 bufferp = strstr(bufferp, "vertex");
1688 if (bufferp != NULL) {
1689 plist->newindex((void **) &coord);
1690 for (i = 0; i < 3; i++) {
1691 bufferp = findnextnumber(bufferp);
1692 if (*bufferp == '\0') {
1693 printf("Syntax error reading vertex coords on line %d\n",
1694 line_count);
1695 delete plist;
1696 fclose(fp);
1697 return false;
1698 }
1699 coord[i] = (REAL) strtod(bufferp, &bufferp);
1700 }
1701 }
1702 }
1703 }
1704 }
1705 fclose(fp);
1706
1707 nverts = (int) plist->objects;
1708 // nverts should be an integer times 3 (every 3 vertices denote a face).
1709 if (nverts == 0 || (nverts % 3 != 0)) {
1710 printf("Error: Wrong number of vertices in file %s.\n", infilename);
1711 delete plist;
1712 return false;
1713 }
1714 numberofpoints = nverts;
1715 pointlist = new REAL[nverts * 3];
1716 for (i = 0; i < nverts; i++) {
1717 coord = (double *) fastlookup(plist, i);
1718 iverts = i * 3;
1719 pointlist[iverts] = (REAL) coord[0];
1720 pointlist[iverts + 1] = (REAL) coord[1];
1721 pointlist[iverts + 2] = (REAL) coord[2];
1722 }
1723
1724 nfaces = (int) (nverts / 3);
1725 numberoffacets = nfaces;
1726 facetlist = new tetgenio::facet[nfaces];
1727
1728 // Default use '1' as the array starting index.
1729 firstnumber = 1;
1730 iverts = firstnumber;
1731 for (i = 0; i < nfaces; i++) {
1732 f = &facetlist[i];
1733 init(f);
1734 // In .stl format, each facet has one polygon, no hole.
1735 f->numberofpolygons = 1;
1736 f->polygonlist = new tetgenio::polygon[1];
1737 p = &f->polygonlist[0];
1738 init(p);
1739 // Each polygon has three vertices.
1740 p->numberofvertices = 3;
1741 p->vertexlist = new int[p->numberofvertices];
1742 p->vertexlist[0] = iverts;
1743 p->vertexlist[1] = iverts + 1;
1744 p->vertexlist[2] = iverts + 2;
1745 iverts += 3;
1746 }
1747
1748 delete plist;
1749 return true;
1750}
1751
1752///////////////////////////////////////////////////////////////////////////////
1753// //
1754// load_medit() Load a surface mesh from a .mesh file. //
1755// //
1756// The .mesh format is the file format of Medit, a user-friendly interactive //
1757// mesh viewer program. //
1758// //
1759///////////////////////////////////////////////////////////////////////////////
1760
1761bool tetgenio::load_medit(char* filebasename, int istetmesh)
1762{
1763 FILE *fp;
1764 tetgenio::facet *tmpflist, *f;
1765 tetgenio::polygon *p;
1766 char infilename[FILENAMESIZE];
1767 char buffer[INPUTLINESIZE];
1768 char *bufferp, *str;
1769 double *coord;
1770 int *tmpfmlist;
1771 int dimension = 0;
1772 int nverts = 0;
1773 int nfaces = 0;
1774 int ntets = 0;
1775 int line_count = 0;
1776 int corners = 0; // 3 (triangle) or 4 (quad).
1777 int *plist;
1778 int i, j;
1779
1780 int smallestidx = 0;
1781
1782 strncpy(infilename, filebasename, FILENAMESIZE - 1);
1783 infilename[FILENAMESIZE - 1] = '\0';
1784 if (infilename[0] == '\0') {
1785 printf("Error: No filename.\n");
1786 return false;
1787 }
1788 if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1789 strcat(infilename, ".mesh");
1790 }
1791
1792 if (!(fp = fopen(infilename, "r"))) {
1793 printf("Error: Unable to open file %s\n", infilename);
1794 return false;
1795 }
1796 printf("Opening %s.\n", infilename);
1797
1798 while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1799 if (*bufferp == '#') continue; // A comment line is skipped.
1800 if (dimension == 0) {
1801 // Find if it is the keyword "Dimension".
1802 str = strstr(bufferp, "Dimension");
1803 if (!str) str = strstr(bufferp, "dimension");
1804 if (!str) str = strstr(bufferp, "DIMENSION");
1805 if (str) {
1806 // Read the dimensions
1807 bufferp = findnextnumber(str); // Skip field "Dimension".
1808 if (*bufferp == '\0') {
1809 // Read a non-empty line.
1810 bufferp = readline(buffer, fp, &line_count);
1811 }
1812 dimension = (int) strtol(bufferp, &bufferp, 0);
1813 if (dimension != 2 && dimension != 3) {
1814 printf("Unknown dimension in file on line %d in file %s\n",
1815 line_count, infilename);
1816 fclose(fp);
1817 return false;
1818 }
1819 mesh_dim = dimension;
1820 }
1821 }
1822 if (nverts == 0) {
1823 // Find if it is the keyword "Vertices".
1824 str = strstr(bufferp, "Vertices");
1825 if (!str) str = strstr(bufferp, "vertices");
1826 if (!str) str = strstr(bufferp, "VERTICES");
1827 if (str) {
1828 // Read the number of vertices.
1829 bufferp = findnextnumber(str); // Skip field "Vertices".
1830 if (*bufferp == '\0') {
1831 // Read a non-empty line.
1832 bufferp = readline(buffer, fp, &line_count);
1833 }
1834 nverts = (int) strtol(bufferp, &bufferp, 0);
1835 // Initialize the smallest index.
1836 smallestidx = nverts + 1;
1837 // Allocate memory for 'tetgenio'
1838 if (nverts > 0) {
1839 numberofpoints = nverts;
1840 pointlist = new REAL[nverts * 3];
1841 }
1842 // Read the follwoing node list.
1843 for (i = 0; i < nverts; i++) {
1844 bufferp = readline(buffer, fp, &line_count);
1845 if (bufferp == NULL) {
1846 printf("Unexpected end of file on line %d in file %s\n",
1847 line_count, infilename);
1848 fclose(fp);
1849 return false;
1850 }
1851 // Read vertex coordinates
1852 coord = &pointlist[i * 3];
1853 for (j = 0; j < 3; j++) {
1854 if (*bufferp == '\0') {
1855 printf("Syntax error reading vertex coords on line");
1856 printf(" %d in file %s\n", line_count, infilename);
1857 fclose(fp);
1858 return false;
1859 }
1860 if ((j < 2) || (dimension == 3)) {
1861 coord[j] = (REAL) strtod(bufferp, &bufferp);
1862 } else {
1863 assert((j == 2) && (dimension == 2));
1864 coord[j] = 0.0;
1865 }
1866 bufferp = findnextnumber(bufferp);
1867 }
1868 }
1869 continue;
1870 }
1871 }
1872 if (ntets == 0) {
1873 // Find if it is the keyword "Tetrahedra"
1874 corners = 0;
1875 str = strstr(bufferp, "Tetrahedra");
1876 if (!str) str = strstr(bufferp, "tetrahedra");
1877 if (!str) str = strstr(bufferp, "TETRAHEDRA");
1878 if (str) {
1879 corners = 4;
1880 }
1881 if (corners == 4) {
1882 // Read the number of tetrahedra
1883 bufferp = findnextnumber(str); // Skip field "Tetrahedra".
1884 if (*bufferp == '\0') {
1885 // Read a non-empty line.
1886 bufferp = readline(buffer, fp, &line_count);
1887 }
1888 ntets = strtol(bufferp, &bufferp, 0);
1889 if (ntets > 0) {
1890 // It is a tetrahedral mesh.
1891 numberoftetrahedra = ntets;
1892 numberofcorners = 4;
1893 numberoftetrahedronattributes = 1;
1894 tetrahedronlist = new int[ntets * 4];
1895 tetrahedronattributelist = new REAL[ntets];
1896 }
1897 } // if (corners == 4)
1898 // Read the list of tetrahedra.
1899 for (i = 0; i < numberoftetrahedra; i++) {
1900 plist = &(tetrahedronlist[i * 4]);
1901 bufferp = readline(buffer, fp, &line_count);
1902 if (bufferp == NULL) {
1903 printf("Unexpected end of file on line %d in file %s\n",
1904 line_count, infilename);
1905 fclose(fp);
1906 return false;
1907 }
1908 // Read the vertices of the tet.
1909 for (j = 0; j < corners; j++) {
1910 if (*bufferp == '\0') {
1911 printf("Syntax error reading face on line %d in file %s\n",
1912 line_count, infilename);
1913 fclose(fp);
1914 return false;
1915 }
1916 plist[j] = (int) strtol(bufferp, &bufferp, 0);
1917 // Remember the smallest index.
1918 if (plist[j] < smallestidx) smallestidx = plist[j];
1919 bufferp = findnextnumber(bufferp);
1920 }
1921 // Read the attribute of the tet if it exists.
1922 tetrahedronattributelist[i] = 0;
1923 if (*bufferp != '\0') {
1924 tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
1925 }
1926 } // i
1927 } // Tetrahedra
1928 if (nfaces == 0) {
1929 // Find if it is the keyword "Triangles" or "Quadrilaterals".
1930 corners = 0;
1931 str = strstr(bufferp, "Triangles");
1932 if (!str) str = strstr(bufferp, "triangles");
1933 if (!str) str = strstr(bufferp, "TRIANGLES");
1934 if (str) {
1935 corners = 3;
1936 } else {
1937 str = strstr(bufferp, "Quadrilaterals");
1938 if (!str) str = strstr(bufferp, "quadrilaterals");
1939 if (!str) str = strstr(bufferp, "QUADRILATERALS");
1940 if (str) {
1941 corners = 4;
1942 }
1943 }
1944 if (corners == 3 || corners == 4) {
1945 // Read the number of triangles (or quadrilaterals).
1946 bufferp = findnextnumber(str); // Skip field "Triangles".
1947 if (*bufferp == '\0') {
1948 // Read a non-empty line.
1949 bufferp = readline(buffer, fp, &line_count);
1950 }
1951 nfaces = strtol(bufferp, &bufferp, 0);
1952 // Allocate memory for 'tetgenio'
1953 if (nfaces > 0) {
1954 if (!istetmesh) {
1955 // It is a PLC surface mesh.
1956 if (numberoffacets > 0) {
1957 // facetlist has already been allocated. Enlarge arrays.
1958 // This happens when the surface mesh contains mixed cells.
1959 tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1960 tmpfmlist = new int[numberoffacets + nfaces];
1961 // Copy the data of old arrays into new arrays.
1962 for (i = 0; i < numberoffacets; i++) {
1963 f = &(tmpflist[i]);
1964 tetgenio::init(f);
1965 *f = facetlist[i];
1966 tmpfmlist[i] = facetmarkerlist[i];
1967 }
1968 // Release old arrays.
1969 delete [] facetlist;
1970 delete [] facetmarkerlist;
1971 // Remember the new arrays.
1972 facetlist = tmpflist;
1973 facetmarkerlist = tmpfmlist;
1974 } else {
1975 // This is the first time to allocate facetlist.
1976 facetlist = new tetgenio::facet[nfaces];
1977 facetmarkerlist = new int[nfaces];
1978 }
1979 } else {
1980 if (corners == 3) {
1981 // It is a surface mesh of a tetrahedral mesh.
1982 numberoftrifaces = nfaces;
1983 trifacelist = new int[nfaces * 3];
1984 trifacemarkerlist = new int[nfaces];
1985 }
1986 }
1987 } // if (nfaces > 0)
1988 // Read the following list of faces.
1989 if (!istetmesh) {
1990 for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
1991 bufferp = readline(buffer, fp, &line_count);
1992 if (bufferp == NULL) {
1993 printf("Unexpected end of file on line %d in file %s\n",
1994 line_count, infilename);
1995 fclose(fp);
1996 return false;
1997 }
1998 f = &facetlist[i];
1999 tetgenio::init(f);
2000 // In .mesh format, each facet has one polygon, no hole.
2001 f->numberofpolygons = 1;
2002 f->polygonlist = new tetgenio::polygon[1];
2003 p = &f->polygonlist[0];
2004 tetgenio::init(p);
2005 p->numberofvertices = corners;
2006 // Allocate memory for face vertices
2007 p->vertexlist = new int[p->numberofvertices];
2008 // Read the vertices of the face.
2009 for (j = 0; j < corners; j++) {
2010 if (*bufferp == '\0') {
2011 printf("Syntax error reading face on line %d in file %s\n",
2012 line_count, infilename);
2013 fclose(fp);
2014 return false;
2015 }
2016 p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
2017 // Remember the smallest index.
2018 if (p->vertexlist[j] < smallestidx) {
2019 smallestidx = p->vertexlist[j];
2020 }
2021 bufferp = findnextnumber(bufferp);
2022 }
2023 // Read the marker of the face if it exists.
2024 facetmarkerlist[i] = 0;
2025 if (*bufferp != '\0') {
2026 facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2027 }
2028 }
2029 // Have read in a list of triangles/quads.
2030 numberoffacets += nfaces;
2031 nfaces = 0;
2032 } else {
2033 // It is a surface mesh of a tetrahedral mesh.
2034 if (corners == 3) {
2035 for (i = 0; i < numberoftrifaces; i++) {
2036 plist = &(trifacelist[i * 3]);
2037 bufferp = readline(buffer, fp, &line_count);
2038 if (bufferp == NULL) {
2039 printf("Unexpected end of file on line %d in file %s\n",
2040 line_count, infilename);
2041 fclose(fp);
2042 return false;
2043 }
2044 // Read the vertices of the face.
2045 for (j = 0; j < corners; j++) {
2046 if (*bufferp == '\0') {
2047 printf("Syntax error reading face on line %d in file %s\n",
2048 line_count, infilename);
2049 fclose(fp);
2050 return false;
2051 }
2052 plist[j] = (int) strtol(bufferp, &bufferp, 0);
2053 // Remember the smallest index.
2054 if (plist[j] < smallestidx) {
2055 smallestidx = plist[j];
2056 }
2057 bufferp = findnextnumber(bufferp);
2058 }
2059 // Read the marker of the face if it exists.
2060 trifacemarkerlist[i] = 0;
2061 if (*bufferp != '\0') {
2062 trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2063 }
2064 } // i
2065 } // if (corners == 3)
2066 } // if (b->refine)
2067 } // if (corners == 3 || corners == 4)
2068 }
2069 }
2070
2071 // Close file
2072 fclose(fp);
2073
2074 // Decide the firstnumber of the index.
2075 if (smallestidx == 0) {
2076 firstnumber = 0;
2077 } else if (smallestidx == 1) {
2078 firstnumber = 1;
2079 } else {
2080 printf("A wrong smallest index (%d) was detected in file %s\n",
2081 smallestidx, infilename);
2082 return false;
2083 }
2084
2085 return true;
2086}
2087
2088///////////////////////////////////////////////////////////////////////////////
2089// //
2090// load_vtk() Load VTK surface mesh from file (.vtk ascii or binary). //
2091// //
2092// This function is contributed by: Bryn Lloyd, Computer Vision Laboratory, //
2093// ETH, Zuerich. May 7, 2007. //
2094// //
2095///////////////////////////////////////////////////////////////////////////////
2096
2097// Two inline functions used in read/write VTK files.
2098
2099void swapBytes(unsigned char* var, int size)
2100{
2101 int i = 0;
2102 int j = size - 1;
2103 char c;
2104
2105 while (i < j) {
2106 c = var[i]; var[i] = var[j]; var[j] = c;
2107 i++, j--;
2108 }
2109}
2110
2111bool testIsBigEndian()
2112{
2113 short word = 0x4321;
2114 if((*(char *)& word) != 0x21)
2115 return true;
2116 else
2117 return false;
2118}
2119
2120
2121bool tetgenio::load_vtk(char* filebasename)
2122{
2123 FILE *fp;
2124 tetgenio::facet *f;
2125 tetgenio::polygon *p;
2126 char infilename[FILENAMESIZE];
2127 char line[INPUTLINESIZE];
2128 char mode[128], id[256], fmt[64];
2129 char *bufferp;
2130 double *coord;
2131 float _x, _y, _z;
2132 int nverts = 0;
2133 int nfaces = 0;
2134 int line_count = 0;
2135 int dummy;
2136 int id1, id2, id3;
2137 int nn = -1;
2138 int nn_old = -1;
2139 int i, j;
2140 bool ImALittleEndian = !testIsBigEndian();
2141
2142 int smallestidx = 0;
2143
2144 strncpy(infilename, filebasename, FILENAMESIZE - 1);
2145 infilename[FILENAMESIZE - 1] = '\0';
2146 if (infilename[0] == '\0') {
2147 printf("Error: No filename.\n");
2148 return false;
2149 }
2150 if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
2151 strcat(infilename, ".vtk");
2152 }
2153 if (!(fp = fopen(infilename, "r"))) {
2154 printf("Error: Unable to open file %s\n", infilename);
2155 return false;
2156 }
2157 printf("Opening %s.\n", infilename);
2158
2159 // Default uses the index starts from '0'.
2160 firstnumber = 0;
2161 strcpy(mode, "BINARY");
2162
2163 while((bufferp = readline(line, fp, &line_count)) != NULL) {
2164 if(strlen(line) == 0) continue;
2165 //swallow lines beginning with a comment sign or white space
2166 if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 ||
2167 line[0] == 32) continue;
2168
2169 sscanf(line, "%s", id);
2170 if(!strcmp(id, "ASCII")) {
2171 strcpy(mode, "ASCII");
2172 }
2173
2174 if(!strcmp(id, "POINTS")) {
2175 sscanf(line, "%s %d %s", id, &nverts, fmt);
2176 if (nverts > 0) {
2177 numberofpoints = nverts;
2178 pointlist = new REAL[nverts * 3];
2179 smallestidx = nverts + 1;
2180 }
2181
2182 if(!strcmp(mode, "BINARY")) {
2183 for(i = 0; i < nverts; i++) {
2184 coord = &pointlist[i * 3];
2185 if(!strcmp(fmt, "double")) {
2186 if(fread((char*)(&(coord[0])), sizeof(double), 1, fp)){};
2187 if(fread((char*)(&(coord[1])), sizeof(double), 1, fp)){};
2188 if(fread((char*)(&(coord[2])), sizeof(double), 1, fp)){};
2189 if(ImALittleEndian){
2190 swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
2191 swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
2192 swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
2193 }
2194 } else if(!strcmp(fmt, "float")) {
2195 if(fread((char*)(&_x), sizeof(float), 1, fp)){};
2196 if(fread((char*)(&_y), sizeof(float), 1, fp)){};
2197 if(fread((char*)(&_z), sizeof(float), 1, fp)){};
2198 if(ImALittleEndian){
2199 swapBytes((unsigned char *) &_x, sizeof(_x));
2200 swapBytes((unsigned char *) &_y, sizeof(_y));
2201 swapBytes((unsigned char *) &_z, sizeof(_z));
2202 }
2203 coord[0] = double(_x);
2204 coord[1] = double(_y);
2205 coord[2] = double(_z);
2206 } else {
2207 printf("Error: Only float or double formats are supported!\n");
2208 return false;
2209 }
2210 }
2211 } else if(!strcmp(mode, "ASCII")) {
2212 for(i = 0; i < nverts; i++){
2213 bufferp = readline(line, fp, &line_count);
2214 if (bufferp == NULL) {
2215 printf("Unexpected end of file on line %d in file %s\n",
2216 line_count, infilename);
2217 fclose(fp);
2218 return false;
2219 }
2220 // Read vertex coordinates
2221 coord = &pointlist[i * 3];
2222 for (j = 0; j < 3; j++) {
2223 if (*bufferp == '\0') {
2224 printf("Syntax error reading vertex coords on line");
2225 printf(" %d in file %s\n", line_count, infilename);
2226 fclose(fp);
2227 return false;
2228 }
2229 coord[j] = (REAL) strtod(bufferp, &bufferp);
2230 bufferp = findnextnumber(bufferp);
2231 }
2232 }
2233 }
2234 continue;
2235 }
2236
2237 if(!strcmp(id, "POLYGONS")) {
2238 sscanf(line, "%s %d %d", id, &nfaces, &dummy);
2239 if (nfaces > 0) {
2240 numberoffacets = nfaces;
2241 facetlist = new tetgenio::facet[nfaces];
2242 }
2243
2244 if(!strcmp(mode, "BINARY")) {
2245 for(i = 0; i < nfaces; i++){
2246 if(fread((char*)(&nn), sizeof(int), 1, fp)){};
2247 if(ImALittleEndian){
2248 swapBytes((unsigned char *) &nn, sizeof(nn));
2249 }
2250 if (i == 0)
2251 nn_old = nn;
2252 if (nn != nn_old) {
2253 printf("Error: No mixed cells are allowed.\n");
2254 return false;
2255 }
2256
2257 if(nn == 3){
2258 if(fread((char*)(&id1), sizeof(int), 1, fp)){};
2259 if(fread((char*)(&id2), sizeof(int), 1, fp)){};
2260 if(fread((char*)(&id3), sizeof(int), 1, fp)){};
2261 if(ImALittleEndian){
2262 swapBytes((unsigned char *) &id1, sizeof(id1));
2263 swapBytes((unsigned char *) &id2, sizeof(id2));
2264 swapBytes((unsigned char *) &id3, sizeof(id3));
2265 }
2266 f = &facetlist[i];
2267 init(f);
2268 // In .off format, each facet has one polygon, no hole.
2269 f->numberofpolygons = 1;
2270 f->polygonlist = new tetgenio::polygon[1];
2271 p = &f->polygonlist[0];
2272 init(p);
2273 // Set number of vertices
2274 p->numberofvertices = 3;
2275 // Allocate memory for face vertices
2276 p->vertexlist = new int[p->numberofvertices];
2277 p->vertexlist[0] = id1;
2278 p->vertexlist[1] = id2;
2279 p->vertexlist[2] = id3;
2280 // Detect the smallest index.
2281 for (j = 0; j < 3; j++) {
2282 if (p->vertexlist[j] < smallestidx) {
2283 smallestidx = p->vertexlist[j];
2284 }
2285 }
2286 } else {
2287 printf("Error: Only triangles are supported\n");
2288 return false;
2289 }
2290 }
2291 } else if(!strcmp(mode, "ASCII")) {
2292 for(i = 0; i < nfaces; i++) {
2293 bufferp = readline(line, fp, &line_count);
2294 nn = (int) strtol(bufferp, &bufferp, 0);
2295 if (i == 0)
2296 nn_old = nn;
2297 if (nn != nn_old) {
2298 printf("Error: No mixed cells are allowed.\n");
2299 return false;
2300 }
2301
2302 if (nn == 3) {
2303 bufferp = findnextnumber(bufferp); // Skip the first field.
2304 id1 = (int) strtol(bufferp, &bufferp, 0);
2305 bufferp = findnextnumber(bufferp);
2306 id2 = (int) strtol(bufferp, &bufferp, 0);
2307 bufferp = findnextnumber(bufferp);
2308 id3 = (int) strtol(bufferp, &bufferp, 0);
2309 f = &facetlist[i];
2310 init(f);
2311 // In .off format, each facet has one polygon, no hole.
2312 f->numberofpolygons = 1;
2313 f->polygonlist = new tetgenio::polygon[1];
2314 p = &f->polygonlist[0];
2315 init(p);
2316 // Set number of vertices
2317 p->numberofvertices = 3;
2318 // Allocate memory for face vertices
2319 p->vertexlist = new int[p->numberofvertices];
2320 p->vertexlist[0] = id1;
2321 p->vertexlist[1] = id2;
2322 p->vertexlist[2] = id3;
2323 // Detect the smallest index.
2324 for (j = 0; j < 3; j++) {
2325 if (p->vertexlist[j] < smallestidx) {
2326 smallestidx = p->vertexlist[j];
2327 }
2328 }
2329 } else {
2330 printf("Error: Only triangles are supported.\n");
2331 return false;
2332 }
2333 }
2334 }
2335
2336 fclose(fp);
2337
2338 // Decide the firstnumber of the index.
2339 if (smallestidx == 0) {
2340 firstnumber = 0;
2341 } else if (smallestidx == 1) {
2342 firstnumber = 1;
2343 } else {
2344 printf("A wrong smallest index (%d) was detected in file %s\n",
2345 smallestidx, infilename);
2346 return false;
2347 }
2348
2349 return true;
2350 }
2351
2352 if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
2353 printf("Warning: load_vtk(): cannot read formats LINES, CELLS.\n");
2354 }
2355 } // while ()
2356
2357 return true;
2358}
2359
2360///////////////////////////////////////////////////////////////////////////////
2361// //
2362// load_plc() Load a piecewise linear complex from file(s). //
2363// //
2364///////////////////////////////////////////////////////////////////////////////
2365
2366bool tetgenio::load_plc(char* filebasename, int object)
2367{
2368 bool success;
2369
2370 if (object == (int) tetgenbehavior::NODES) {
2371 success = load_node(filebasename);
2372 } else if (object == (int) tetgenbehavior::POLY) {
2373 success = load_poly(filebasename);
2374 } else if (object == (int) tetgenbehavior::OFF) {
2375 success = load_off(filebasename);
2376 } else if (object == (int) tetgenbehavior::PLY) {
2377 success = load_ply(filebasename);
2378 } else if (object == (int) tetgenbehavior::STL) {
2379 success = load_stl(filebasename);
2380 } else if (object == (int) tetgenbehavior::MEDIT) {
2381 success = load_medit(filebasename, 0);
2382 } else if (object == (int) tetgenbehavior::VTK) {
2383 success = load_vtk(filebasename);
2384 } else {
2385 success = load_poly(filebasename);
2386 }
2387
2388 if (success) {
2389 // Try to load the following files (.edge, .var, .mtr).
2390 load_edge(filebasename);
2391 load_var(filebasename);
2392 load_mtr(filebasename);
2393 }
2394
2395 return success;
2396}
2397
2398///////////////////////////////////////////////////////////////////////////////
2399// //
2400// load_mesh() Load a tetrahedral mesh from file(s). //
2401// //
2402///////////////////////////////////////////////////////////////////////////////
2403
2404bool tetgenio::load_tetmesh(char* filebasename, int object)
2405{
2406 bool success;
2407
2408 if (object == (int) tetgenbehavior::MEDIT) {
2409 success = load_medit(filebasename, 1);
2410 } else {
2411 success = load_node(filebasename);
2412 if (success) {
2413 success = load_tet(filebasename);
2414 }
2415 if (success) {
2416 // Try to load the following files (.face, .edge, .vol).
2417 load_face(filebasename);
2418 load_edge(filebasename);
2419 load_vol(filebasename);
2420 }
2421 }
2422
2423 if (success) {
2424 // Try to load the following files (.var, .mtr).
2425 load_var(filebasename);
2426 load_mtr(filebasename);
2427 }
2428
2429 return success;
2430}
2431
2432///////////////////////////////////////////////////////////////////////////////
2433// //
2434// save_nodes() Save points to a .node file. //
2435// //
2436///////////////////////////////////////////////////////////////////////////////
2437
2438void tetgenio::save_nodes(char* filebasename)
2439{
2440 FILE *fout;
2441 char outnodefilename[FILENAMESIZE];
2442 char outmtrfilename[FILENAMESIZE];
2443 int i, j;
2444
2445 sprintf(outnodefilename, "%s.node", filebasename);
2446 printf("Saving nodes to %s\n", outnodefilename);
2447 fout = fopen(outnodefilename, "w");
2448 fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
2449 numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
2450 for (i = 0; i < numberofpoints; i++) {
2451 if (mesh_dim == 2) {
2452 fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 3],
2453 pointlist[i * 3 + 1]);
2454 } else {
2455 fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
2456 pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2457 }
2458 for (j = 0; j < numberofpointattributes; j++) {
2459 fprintf(fout, " %.16g",
2460 pointattributelist[i * numberofpointattributes + j]);
2461 }
2462 if (pointmarkerlist != NULL) {
2463 fprintf(fout, " %d", pointmarkerlist[i]);
2464 }
2465 fprintf(fout, "\n");
2466 }
2467 fclose(fout);
2468
2469 // If the point metrics exist, output them to a .mtr file.
2470 if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
2471 sprintf(outmtrfilename, "%s.mtr", filebasename);
2472 printf("Saving metrics to %s\n", outmtrfilename);
2473 fout = fopen(outmtrfilename, "w");
2474 fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
2475 for (i = 0; i < numberofpoints; i++) {
2476 for (j = 0; j < numberofpointmtrs; j++) {
2477 fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2478 }
2479 fprintf(fout, "\n");
2480 }
2481 fclose(fout);
2482 }
2483}
2484
2485///////////////////////////////////////////////////////////////////////////////
2486// //
2487// save_elements() Save elements to a .ele file. //
2488// //
2489///////////////////////////////////////////////////////////////////////////////
2490
2491void tetgenio::save_elements(char* filebasename)
2492{
2493 FILE *fout;
2494 char outelefilename[FILENAMESIZE];
2495 int i, j;
2496
2497 sprintf(outelefilename, "%s.ele", filebasename);
2498 printf("Saving elements to %s\n", outelefilename);
2499 fout = fopen(outelefilename, "w");
2500 if (mesh_dim == 3) {
2501 fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
2502 numberoftetrahedronattributes);
2503 for (i = 0; i < numberoftetrahedra; i++) {
2504 fprintf(fout, "%d", i + firstnumber);
2505 for (j = 0; j < numberofcorners; j++) {
2506 fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
2507 }
2508 for (j = 0; j < numberoftetrahedronattributes; j++) {
2509 fprintf(fout, " %g",
2510 tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2511 }
2512 fprintf(fout, "\n");
2513 }
2514 } else {
2515 // Save a two-dimensional mesh.
2516 fprintf(fout, "%d %d %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
2517 for (i = 0; i < numberoftrifaces; i++) {
2518 fprintf(fout, "%d", i + firstnumber);
2519 for (j = 0; j < 3; j++) {
2520 fprintf(fout, " %5d", trifacelist[i * 3 + j]);
2521 }
2522 if (trifacemarkerlist != NULL) {
2523 fprintf(fout, " %d", trifacemarkerlist[i]);
2524 }
2525 fprintf(fout, "\n");
2526 }
2527 }
2528
2529 fclose(fout);
2530}
2531
2532///////////////////////////////////////////////////////////////////////////////
2533// //
2534// save_faces() Save faces to a .face file. //
2535// //
2536///////////////////////////////////////////////////////////////////////////////
2537
2538void tetgenio::save_faces(char* filebasename)
2539{
2540 FILE *fout;
2541 char outfacefilename[FILENAMESIZE];
2542 int i;
2543
2544 sprintf(outfacefilename, "%s.face", filebasename);
2545 printf("Saving faces to %s\n", outfacefilename);
2546 fout = fopen(outfacefilename, "w");
2547 fprintf(fout, "%d %d\n", numberoftrifaces,
2548 trifacemarkerlist != NULL ? 1 : 0);
2549 for (i = 0; i < numberoftrifaces; i++) {
2550 fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
2551 trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2552 if (trifacemarkerlist != NULL) {
2553 fprintf(fout, " %d", trifacemarkerlist[i]);
2554 }
2555 fprintf(fout, "\n");
2556 }
2557
2558 fclose(fout);
2559}
2560
2561///////////////////////////////////////////////////////////////////////////////
2562// //
2563// save_edges() Save egdes to a .edge file. //
2564// //
2565///////////////////////////////////////////////////////////////////////////////
2566
2567void tetgenio::save_edges(char* filebasename)
2568{
2569 FILE *fout;
2570 char outedgefilename[FILENAMESIZE];
2571 int i;
2572
2573 sprintf(outedgefilename, "%s.edge", filebasename);
2574 printf("Saving edges to %s\n", outedgefilename);
2575 fout = fopen(outedgefilename, "w");
2576 fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2577 for (i = 0; i < numberofedges; i++) {
2578 fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2579 edgelist[i * 2 + 1]);
2580 if (edgemarkerlist != NULL) {
2581 fprintf(fout, " %d", edgemarkerlist[i]);
2582 }
2583 fprintf(fout, "\n");
2584 }
2585
2586 fclose(fout);
2587}
2588
2589///////////////////////////////////////////////////////////////////////////////
2590// //
2591// save_neighbors() Save egdes to a .neigh file. //
2592// //
2593///////////////////////////////////////////////////////////////////////////////
2594
2595void tetgenio::save_neighbors(char* filebasename)
2596{
2597 FILE *fout;
2598 char outneighborfilename[FILENAMESIZE];
2599 int i;
2600
2601 sprintf(outneighborfilename, "%s.neigh", filebasename);
2602 printf("Saving neighbors to %s\n", outneighborfilename);
2603 fout = fopen(outneighborfilename, "w");
2604 fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
2605 for (i = 0; i < numberoftetrahedra; i++) {
2606 if (mesh_dim == 2) {
2607 fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
2608 neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2609 } else {
2610 fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
2611 neighborlist[i * 4], neighborlist[i * 4 + 1],
2612 neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2613 }
2614 fprintf(fout, "\n");
2615 }
2616
2617 fclose(fout);
2618}
2619
2620///////////////////////////////////////////////////////////////////////////////
2621// //
2622// save_poly() Save segments or facets to a .poly file. //
2623// //
2624// It only save the facets, holes and regions. No .node file is saved. //
2625// //
2626///////////////////////////////////////////////////////////////////////////////
2627
2628void tetgenio::save_poly(char* filebasename)
2629{
2630 FILE *fout;
2631 facet *f;
2632 polygon *p;
2633 char outpolyfilename[FILENAMESIZE];
2634 int i, j, k;
2635
2636 sprintf(outpolyfilename, "%s.poly", filebasename);
2637 printf("Saving poly to %s\n", outpolyfilename);
2638 fout = fopen(outpolyfilename, "w");
2639
2640 // The zero indicates that the vertices are in a separate .node file.
2641 // Followed by number of dimensions, number of vertex attributes,
2642 // and number of boundary markers (zero or one).
2643 fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2644 pointmarkerlist != NULL ? 1 : 0);
2645
2646 // Save segments or facets.
2647 if (mesh_dim == 2) {
2648 // Number of segments, number of boundary markers (zero or one).
2649 fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2650 for (i = 0; i < numberofedges; i++) {
2651 fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2652 edgelist[i * 2 + 1]);
2653 if (edgemarkerlist != NULL) {
2654 fprintf(fout, " %d", edgemarkerlist[i]);
2655 }
2656 fprintf(fout, "\n");
2657 }
2658 } else {
2659 // Number of facets, number of boundary markers (zero or one).
2660 fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
2661 for (i = 0; i < numberoffacets; i++) {
2662 f = &(facetlist[i]);
2663 fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
2664 facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
2665 // Output polygons of this facet.
2666 for (j = 0; j < f->numberofpolygons; j++) {
2667 p = &(f->polygonlist[j]);
2668 fprintf(fout, "%d ", p->numberofvertices);
2669 for (k = 0; k < p->numberofvertices; k++) {
2670 if (((k + 1) % 10) == 0) {
2671 fprintf(fout, "\n ");
2672 }
2673 fprintf(fout, " %d", p->vertexlist[k]);
2674 }
2675 fprintf(fout, "\n");
2676 }
2677 // Output holes of this facet.
2678 for (j = 0; j < f->numberofholes; j++) {
2679 fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
2680 f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2681 }
2682 }
2683 }
2684
2685 // Save holes.
2686 fprintf(fout, "%d\n", numberofholes);
2687 for (i = 0; i < numberofholes; i++) {
2688 // Output x, y coordinates.
2689 fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
2690 holelist[i * mesh_dim + 1]);
2691 if (mesh_dim == 3) {
2692 // Output z coordinate.
2693 fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
2694 }
2695 fprintf(fout, "\n");
2696 }
2697
2698 // Save regions.
2699 fprintf(fout, "%d\n", numberofregions);
2700 for (i = 0; i < numberofregions; i++) {
2701 if (mesh_dim == 2) {
2702 // Output the index, x, y coordinates, attribute (region number)
2703 // and maximum area constraint (maybe -1).
2704 fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
2705 regionlist[i * 4], regionlist[i * 4 + 1],
2706 regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2707 } else {
2708 // Output the index, x, y, z coordinates, attribute (region number)
2709 // and maximum volume constraint (maybe -1).
2710 fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
2711 regionlist[i * 5], regionlist[i * 5 + 1],
2712 regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2713 regionlist[i * 5 + 4]);
2714 }
2715 }
2716
2717 fclose(fout);
2718}
2719
2720///////////////////////////////////////////////////////////////////////////////
2721// //
2722// save_faces2smesh() Save triangular faces to a .smesh file. //
2723// //
2724// It only save the facets. No holes and regions. No .node file. //
2725// //
2726///////////////////////////////////////////////////////////////////////////////
2727
2728void tetgenio::save_faces2smesh(char* filebasename)
2729{
2730 FILE *fout;
2731 char outsmeshfilename[FILENAMESIZE];
2732 int i, j;
2733
2734 sprintf(outsmeshfilename, "%s.smesh", filebasename);
2735 printf("Saving faces to %s\n", outsmeshfilename);
2736 fout = fopen(outsmeshfilename, "w");
2737
2738 // The zero indicates that the vertices are in a separate .node file.
2739 // Followed by number of dimensions, number of vertex attributes,
2740 // and number of boundary markers (zero or one).
2741 fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2742 pointmarkerlist != NULL ? 1 : 0);
2743
2744 // Number of facets, number of boundary markers (zero or one).
2745 fprintf(fout, "%d %d\n", numberoftrifaces,
2746 trifacemarkerlist != NULL ? 1 : 0);
2747
2748 // Output triangular facets.
2749 for (i = 0; i < numberoftrifaces; i++) {
2750 j = i * 3;
2751 fprintf(fout, "3 %d %d %d", trifacelist[j], trifacelist[j + 1],
2752 trifacelist[j + 2]);
2753 if (trifacemarkerlist != NULL) {
2754 fprintf(fout, " %d", trifacemarkerlist[i]);
2755 }
2756 fprintf(fout, "\n");
2757 }
2758
2759 // No holes and regions.
2760 fprintf(fout, "0\n");
2761 fprintf(fout, "0\n");
2762
2763 fclose(fout);
2764}
2765
2766///////////////////////////////////////////////////////////////////////////////
2767// //
2768// readline() Read a nonempty line from a file. //
2769// //
2770// A line is considered "nonempty" if it contains something more than white //
2771// spaces. If a line is considered empty, it will be dropped and the next //
2772// line will be read, this process ends until reaching the end-of-file or a //
2773// non-empty line. Return NULL if it is the end-of-file, otherwise, return //
2774// a pointer to the first non-whitespace character of the line. //
2775// //
2776///////////////////////////////////////////////////////////////////////////////
2777
2778char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2779{
2780 char *result;
2781
2782 // Search for a non-empty line.
2783 do {
2784 result = fgets(string, INPUTLINESIZE - 1, infile);
2785 if (linenumber) (*linenumber)++;
2786 if (result == (char *) NULL) {
2787 return (char *) NULL;
2788 }
2789 // Skip white spaces.
2790 while ((*result == ' ') || (*result == '\t')) result++;
2791 // If it's end of line, read another line and try again.
2792 } while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
2793 return result;
2794}
2795
2796///////////////////////////////////////////////////////////////////////////////
2797// //
2798// findnextfield() Find the next field of a string. //
2799// //
2800// Jumps past the current field by searching for whitespace or a comma, then //
2801// jumps past the whitespace or the comma to find the next field. //
2802// //
2803///////////////////////////////////////////////////////////////////////////////
2804
2805char* tetgenio::findnextfield(char *string)
2806{
2807 char *result;
2808
2809 result = string;
2810 // Skip the current field. Stop upon reaching whitespace or a comma.
2811 while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
2812 (*result != ',') && (*result != ';')) {
2813 result++;
2814 }
2815 // Now skip the whitespace or the comma, stop at anything else that looks
2816 // like a character, or the end of a line.
2817 while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2818 (*result == ';')) {
2819 result++;
2820 }
2821 return result;
2822}
2823
2824///////////////////////////////////////////////////////////////////////////////
2825// //
2826// readnumberline() Read a nonempty number line from a file. //
2827// //
2828// A line is considered "nonempty" if it contains something that looks like //
2829// a number. Comments (prefaced by `#') are ignored. //
2830// //
2831///////////////////////////////////////////////////////////////////////////////
2832
2833char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2834{
2835 char *result;
2836
2837 // Search for something that looks like a number.
2838 do {
2839 result = fgets(string, INPUTLINESIZE, infile);
2840 if (result == (char *) NULL) {
2841 return result;
2842 }
2843 // Skip anything that doesn't look like a number, a comment,
2844 // or the end of a line.
2845 while ((*result != '\0') && (*result != '#')
2846 && (*result != '.') && (*result != '+') && (*result != '-')
2847 && ((*result < '0') || (*result > '9'))) {
2848 result++;
2849 }
2850 // If it's a comment or end of line, read another line and try again.
2851 } while ((*result == '#') || (*result == '\0'));
2852 return result;
2853}
2854
2855///////////////////////////////////////////////////////////////////////////////
2856// //
2857// findnextnumber() Find the next field of a number string. //
2858// //
2859// Jumps past the current field by searching for whitespace or a comma, then //
2860// jumps past the whitespace or the comma to find the next field that looks //
2861// like a number. //
2862// //
2863///////////////////////////////////////////////////////////////////////////////
2864
2865char* tetgenio::findnextnumber(char *string)
2866{
2867 char *result;
2868
2869 result = string;
2870 // Skip the current field. Stop upon reaching whitespace or a comma.
2871 while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2872 (*result != '\t') && (*result != ',')) {
2873 result++;
2874 }
2875 // Now skip the whitespace and anything else that doesn't look like a
2876 // number, a comment, or the end of a line.
2877 while ((*result != '\0') && (*result != '#')
2878 && (*result != '.') && (*result != '+') && (*result != '-')
2879 && ((*result < '0') || (*result > '9'))) {
2880 result++;
2881 }
2882 // Check for a comment (prefixed with `#').
2883 if (*result == '#') {
2884 *result = '\0';
2885 }
2886 return result;
2887}
2888
2889//// ////
2890//// ////
2891//// io_cxx ///////////////////////////////////////////////////////////////////
2892
2893//// behavior_cxx /////////////////////////////////////////////////////////////
2894//// ////
2895//// ////
2896
2897///////////////////////////////////////////////////////////////////////////////
2898// //
2899// syntax() Print list of command line switches. //
2900// //
2901///////////////////////////////////////////////////////////////////////////////
2902
2903void tetgenbehavior::syntax()
2904{
2905 printf(" tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
2906 printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
2907 printf(" -Y Preserves the input surface mesh (does not modify it).\n");
2908 printf(" -r Reconstructs a previously generated mesh.\n");
2909 printf(" -q Refines mesh (to improve mesh quality).\n");
2910 printf(" -R Mesh coarsening (to reduce the mesh elements).\n");
2911 printf(" -A Assigns attributes to tetrahedra in different regions.\n");
2912 printf(" -a Applies a maximum tetrahedron volume constraint.\n");
2913 printf(" -m Applies a mesh sizing function.\n");
2914 printf(" -i Inserts a list of additional points.\n");
2915 printf(" -O Specifies the level of mesh optimization.\n");
2916 printf(" -S Specifies maximum number of added points.\n");
2917 printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
2918 printf(" -X Suppresses use of exact arithmetic.\n");
2919 printf(" -M No merge of coplanar facets or very close vertices.\n");
2920 printf(" -w Generates weighted Delaunay (regular) triangulation.\n");
2921 printf(" -c Retains the convex hull of the PLC.\n");
2922 printf(" -d Detects self-intersections of facets of the PLC.\n");
2923 printf(" -z Numbers all output items starting from zero.\n");
2924 printf(" -f Outputs all faces to .face file.\n");
2925 printf(" -e Outputs all edges to .edge file.\n");
2926 printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
2927 printf(" -v Outputs Voronoi diagram to files.\n");
2928 printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
2929 printf(" -k Outputs mesh to .vtk file for viewing by Paraview.\n");
2930 printf(" -J No jettison of unused vertices from output .node file.\n");
2931 printf(" -B Suppresses output of boundary information.\n");
2932 printf(" -N Suppresses output of .node file.\n");
2933 printf(" -E Suppresses output of .ele file.\n");
2934 printf(" -F Suppresses output of .face and .edge file.\n");
2935 printf(" -I Suppresses mesh iteration numbers.\n");
2936 printf(" -C Checks the consistency of the final mesh.\n");
2937 printf(" -Q Quiet: No terminal output except errors.\n");
2938 printf(" -V Verbose: Detailed information, more terminal output.\n");
2939 printf(" -h Help: A brief instruction for using TetGen.\n");
2940}
2941
2942///////////////////////////////////////////////////////////////////////////////
2943// //
2944// usage() Print a brief instruction for using TetGen. //
2945// //
2946///////////////////////////////////////////////////////////////////////////////
2947
2948void tetgenbehavior::usage()
2949{
2950 printf("TetGen\n");
2951 printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
2952 printf("Triangulator\n");
2953 printf("Version 1.5\n");
2954 printf("November 4, 2013\n");
2955 printf("\n");
2956 printf("What Can TetGen Do?\n");
2957 printf("\n");
2958 printf(" TetGen generates Delaunay tetrahedralizations, constrained\n");
2959 printf(" Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
2960 printf("\n");
2961 printf("Command Line Syntax:\n");
2962 printf("\n");
2963 printf(" Below is the basic command line syntax of TetGen with a list of ");
2964 printf("short\n");
2965 printf(" descriptions. Underscores indicate that numbers may optionally\n");
2966 printf(" follow certain switches. Do not leave any space between a ");
2967 printf("switch\n");
2968 printf(" and its numeric parameter. \'input_file\' contains input data\n");
2969 printf(" depending on the switches you supplied which may be a ");
2970 printf(" piecewise\n");
2971 printf(" linear complex or a list of nodes. File formats and detailed\n");
2972 printf(" description of command line switches are found in user's ");
2973 printf("manual.\n");
2974 printf("\n");
2975 syntax();
2976 printf("\n");
2977 printf("Examples of How to Use TetGen:\n");
2978 printf("\n");
2979 printf(" \'tetgen object\' reads vertices from object.node, and writes ");
2980 printf("their\n Delaunay tetrahedralization to object.1.node, ");
2981 printf("object.1.ele\n (tetrahedra), and object.1.face");
2982 printf(" (convex hull faces).\n");
2983 printf("\n");
2984 printf(" \'tetgen -p object\' reads a PLC from object.poly or object.");
2985 printf("smesh (and\n possibly object.node) and writes its constrained ");
2986 printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele, ");
2987 printf("object.1.face,\n");
2988 printf(" (boundary faces) and object.1.edge (boundary edges).\n");
2989 printf("\n");
2990 printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
2991 printf(" object.smesh (and possibly object.node), generates a mesh ");
2992 printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and ");
2993 printf("have volume\n of 0.1 or less, and writes the mesh to ");
2994 printf("object.1.node, object.1.ele,\n object.1.face, and object.1.edge\n");
2995 printf("\n");
2996 printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
2997 terminatetetgen(NULL, 0);
2998}
2999
3000///////////////////////////////////////////////////////////////////////////////
3001// //
3002// parse_commandline() Read the command line, identify switches, and set //
3003// up options and file names. //
3004// //
3005// 'argc' and 'argv' are the same parameters passed to the function main() //
3006// of a C/C++ program. They together represent the command line user invoked //
3007// from an environment in which TetGen is running. //
3008// //
3009///////////////////////////////////////////////////////////////////////////////
3010
3011bool tetgenbehavior::parse_commandline(int argc, char **argv)
3012{
3013 int startindex;
3014 int increment;
3015 int meshnumber;
3016 int i, j, k;
3017 char workstring[1024];
3018
3019 // First determine the input style of the switches.
3020 if (argc == 0) {
3021 startindex = 0; // Switches are given without a dash.
3022 argc = 1; // For running the following for-loop once.
3023 commandline[0] = '\0';
3024 } else {
3025 startindex = 1;
3026 strcpy(commandline, argv[0]);
3027 strcat(commandline, " ");
3028 }
3029
3030 for (i = startindex; i < argc; i++) {
3031 // Remember the command line for output.
3032 strcat(commandline, argv[i]);
3033 strcat(commandline, " ");
3034 if (startindex == 1) {
3035 // Is this string a filename?
3036 if (argv[i][0] != '-') {
3037 strncpy(infilename, argv[i], 1024 - 1);
3038 infilename[1024 - 1] = '\0';
3039 continue;
3040 }
3041 }
3042 // Parse the individual switch from the string.
3043 for (j = startindex; argv[i][j] != '\0'; j++) {
3044 if (argv[i][j] == 'p') {
3045 plc = 1;
3046 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3047 (argv[i][j + 1] == '.')) {
3048 k = 0;
3049 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3050 (argv[i][j + 1] == '.')) {
3051 j++;
3052 workstring[k] = argv[i][j];
3053 k++;
3054 }
3055 workstring[k] = '\0';
3056 facet_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3057 }
3058 } else if (argv[i][j] == 's') {
3059 psc = 1;
3060 } else if (argv[i][j] == 'Y') {
3061 nobisect = 1;
3062 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3063 nobisect_param = (argv[i][j + 1] - '0');
3064 j++;
3065 }
3066 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3067 j++;
3068 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3069 addsteiner_algo = (argv[i][j + 1] - '0');
3070 j++;
3071 }
3072 }
3073 } else if (argv[i][j] == 'r') {
3074 refine = 1;
3075 } else if (argv[i][j] == 'q') {
3076 quality = 1;
3077 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3078 (argv[i][j + 1] == '.')) {
3079 k = 0;
3080 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3081 (argv[i][j + 1] == '.')) {
3082 j++;
3083 workstring[k] = argv[i][j];
3084 k++;
3085 }
3086 workstring[k] = '\0';
3087 minratio = (REAL) strtod(workstring, (char **) NULL);
3088 }
3089 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3090 j++;
3091 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3092 (argv[i][j + 1] == '.')) {
3093 k = 0;
3094 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3095 (argv[i][j + 1] == '.')) {
3096 j++;
3097 workstring[k] = argv[i][j];
3098 k++;
3099 }
3100 workstring[k] = '\0';
3101 mindihedral = (REAL) strtod(workstring, (char **) NULL);
3102 }
3103 }
3104 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3105 j++;
3106 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3107 (argv[i][j + 1] == '.')) {
3108 k = 0;
3109 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3110 (argv[i][j + 1] == '.')) {
3111 j++;
3112 workstring[k] = argv[i][j];
3113 k++;
3114 }
3115 workstring[k] = '\0';
3116 optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
3117 }
3118 }
3119 } else if (argv[i][j] == 'R') {
3120 coarsen = 1;
3121 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3122 coarsen_param = (argv[i][j + 1] - '0');
3123 j++;
3124 }
3125 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3126 j++;
3127 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3128 (argv[i][j + 1] == '.')) {
3129 k = 0;
3130 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3131 (argv[i][j + 1] == '.')) {
3132 j++;
3133 workstring[k] = argv[i][j];
3134 k++;
3135 }
3136 workstring[k] = '\0';
3137 coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
3138 }
3139 }
3140 } else if (argv[i][j] == 'w') {
3141 weighted = 1;
3142 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3143 weighted_param = (argv[i][j + 1] - '0');
3144 j++;
3145 }
3146 } else if (argv[i][j] == 'b') {
3147 // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
3148 brio_hilbert = 1;
3149 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3150 (argv[i][j + 1] == '.')) {
3151 k = 0;
3152 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3153 (argv[i][j + 1] == '.')) {
3154 j++;
3155 workstring[k] = argv[i][j];
3156 k++;
3157 }
3158 workstring[k] = '\0';
3159 brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
3160 }
3161 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3162 j++;
3163 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3164 (argv[i][j + 1] == '.')) {
3165 k = 0;
3166 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3167 (argv[i][j + 1] == '.')) {
3168 j++;
3169 workstring[k] = argv[i][j];
3170 k++;
3171 }
3172 workstring[k] = '\0';
3173 brio_ratio = (REAL) strtod(workstring, (char **) NULL);
3174 }
3175 }
3176 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3177 j++;
3178 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3179 (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3180 k = 0;
3181 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3182 (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3183 j++;
3184 workstring[k] = argv[i][j];
3185 k++;
3186 }
3187 workstring[k] = '\0';
3188 hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
3189 }
3190 }
3191 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3192 j++;
3193 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3194 (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3195 k = 0;
3196 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3197 (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3198 j++;
3199 workstring[k] = argv[i][j];
3200 k++;
3201 }
3202 workstring[k] = '\0';
3203 hilbert_order = (int)(REAL) strtod(workstring, (char **) NULL);
3204 }
3205 }
3206 if (brio_threshold == 0) { // -b0
3207 brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3208 }
3209 if (brio_ratio >= 1.0) { // -b/1
3210 no_sort = 1;
3211 brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3212 }
3213 } else if (argv[i][j] == 'l') {
3214 incrflip = 1;
3215 } else if (argv[i][j] == 'L') {
3216 flipinsert = 1;
3217 } else if (argv[i][j] == 'm') {
3218 metric = 1;
3219 } else if (argv[i][j] == 'a') {
3220 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3221 (argv[i][j + 1] == '.')) {
3222 fixedvolume = 1;
3223 k = 0;
3224 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3225 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3226 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3227 j++;
3228 workstring[k] = argv[i][j];
3229 k++;
3230 }
3231 workstring[k] = '\0';
3232 maxvolume = (REAL) strtod(workstring, (char **) NULL);
3233 } else {
3234 varvolume = 1;
3235 }
3236 } else if (argv[i][j] == 'A') {
3237 regionattrib = 1;
3238 } else if (argv[i][j] == 'D') {
3239 conforming = 1;
3240 if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
3241 reflevel = (argv[i][j + 1] - '1') + 1;
3242 j++;
3243 }
3244 } else if (argv[i][j] == 'i') {
3245 insertaddpoints = 1;
3246 } else if (argv[i][j] == 'd') {
3247 diagnose = 1;
3248 } else if (argv[i][j] == 'c') {
3249 convex = 1;
3250 } else if (argv[i][j] == 'M') {
3251 nomergefacet = 1;
3252 nomergevertex = 1;
3253 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3254 nomergefacet = (argv[i][j + 1] - '0');
3255 j++;
3256 }
3257 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3258 j++;
3259 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3260 nomergevertex = (argv[i][j + 1] - '0');
3261 j++;
3262 }
3263 }
3264 } else if (argv[i][j] == 'X') {
3265 if (argv[i][j + 1] == '1') {
3266 nostaticfilter = 1;
3267 j++;
3268 } else {
3269 noexact = 1;
3270 }
3271 } else if (argv[i][j] == 'z') {
3272 zeroindex = 1;
3273 } else if (argv[i][j] == 'f') {
3274 facesout++;
3275 } else if (argv[i][j] == 'e') {
3276 edgesout++;
3277 } else if (argv[i][j] == 'n') {
3278 neighout++;
3279 } else if (argv[i][j] == 'v') {
3280 voroout = 1;
3281 } else if (argv[i][j] == 'g') {
3282 meditview = 1;
3283 } else if (argv[i][j] == 'k') {
3284 vtkview = 1;
3285 } else if (argv[i][j] == 'J') {
3286 nojettison = 1;
3287 } else if (argv[i][j] == 'B') {
3288 nobound = 1;
3289 } else if (argv[i][j] == 'N') {
3290 nonodewritten = 1;
3291 } else if (argv[i][j] == 'E') {
3292 noelewritten = 1;
3293 } else if (argv[i][j] == 'F') {
3294 nofacewritten = 1;
3295 } else if (argv[i][j] == 'I') {
3296 noiterationnum = 1;
3297 } else if (argv[i][j] == 'S') {
3298 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3299 (argv[i][j + 1] == '.')) {
3300 k = 0;
3301 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3302 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3303 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3304 j++;
3305 workstring[k] = argv[i][j];
3306 k++;
3307 }
3308 workstring[k] = '\0';
3309 steinerleft = (int) strtol(workstring, (char **) NULL, 0);
3310 }
3311 } else if (argv[i][j] == 'o') {
3312 if (argv[i][j + 1] == '2') {
3313 order = 2;
3314 j++;
3315 }
3316 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3317 j++;
3318 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3319 (argv[i][j + 1] == '.')) {
3320 k = 0;
3321 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3322 (argv[i][j + 1] == '.')) {
3323 j++;
3324 workstring[k] = argv[i][j];
3325 k++;
3326 }
3327 workstring[k] = '\0';
3328 optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
3329 }
3330 }
3331 } else if (argv[i][j] == 'O') {
3332 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3333 optlevel = (argv[i][j + 1] - '0');
3334 j++;
3335 }
3336 if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3337 j++;
3338 if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
3339 optscheme = (argv[i][j + 1] - '0');
3340 j++;
3341 }
3342 }
3343 } else if (argv[i][j] == 'T') {
3344 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3345 (argv[i][j + 1] == '.')) {
3346 k = 0;
3347 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3348 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3349 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3350 j++;
3351 workstring[k] = argv[i][j];
3352 k++;
3353 }
3354 workstring[k] = '\0';
3355 epsilon = (REAL) strtod(workstring, (char **) NULL);
3356 }
3357 } else if (argv[i][j] == 'R') {
3358 reversetetori = 1;
3359 } else if (argv[i][j] == 'C') {
3360 docheck++;
3361 } else if (argv[i][j] == 'Q') {
3362 quiet = 1;
3363 } else if (argv[i][j] == 'V') {
3364 verbose++;
3365 } else if (argv[i][j] == 'x') {
3366 if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3367 (argv[i][j + 1] == '.')) {
3368 k = 0;
3369 while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3370 (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3371 (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3372 j++;
3373 workstring[k] = argv[i][j];
3374 k++;
3375 }
3376 workstring[k] = '\0';
3377 tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
3378 if (tetrahedraperblock > 8188) {
3379 vertexperblock = tetrahedraperblock / 2;
3380 shellfaceperblock = vertexperblock / 2;
3381 } else {
3382 tetrahedraperblock = 8188;
3383 }
3384 }
3385 } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
3386 (argv[i][j] == '?')) {
3387 usage();
3388 } else {
3389 printf("Warning: Unknown switch -%c.\n", argv[i][j]);
3390 }
3391 }
3392 }
3393
3394 if (startindex == 0) {
3395 // Set a temporary filename for debugging output.
3396 strcpy(infilename, "tetgen-tmpfile");
3397 } else {
3398 if (infilename[0] == '\0') {
3399 // No input file name. Print the syntax and exit.
3400 syntax();
3401 terminatetetgen(NULL, 0);
3402 }
3403 // Recognize the object from file extension if it is available.
3404 if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3405 infilename[strlen(infilename) - 5] = '\0';
3406 object = NODES;
3407 } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3408 infilename[strlen(infilename) - 5] = '\0';
3409 object = POLY;
3410 plc = 1;
3411 } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3412 infilename[strlen(infilename) - 6] = '\0';
3413 object = POLY;
3414 plc = 1;
3415 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3416 infilename[strlen(infilename) - 4] = '\0';
3417 object = OFF;
3418 plc = 1;
3419 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3420 infilename[strlen(infilename) - 4] = '\0';
3421 object = PLY;
3422 plc = 1;
3423 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3424 infilename[strlen(infilename) - 4] = '\0';
3425 object = STL;
3426 plc = 1;
3427 } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3428 infilename[strlen(infilename) - 5] = '\0';
3429 object = MEDIT;
3430 if (!refine) plc = 1;
3431 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
3432 infilename[strlen(infilename) - 4] = '\0';
3433 object = VTK;
3434 plc = 1;
3435 } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3436 infilename[strlen(infilename) - 4] = '\0';
3437 object = MESH;
3438 refine = 1;
3439 }
3440 }
3441
3442 if (nobisect && (!plc && !refine)) { // -Y
3443 plc = 1; // Default -p option.
3444 }
3445 if (quality && (!plc && !refine)) { // -q
3446 plc = 1; // Default -p option.
3447 }
3448 if (diagnose && !plc) { // -d
3449 plc = 1;
3450 }
3451 if (refine && !quality) { // -r only
3452 // Reconstruct a mesh, no mesh optimization.
3453 optlevel = 0;
3454 }
3455 if (insertaddpoints && (optlevel == 0)) { // with -i option
3456 optlevel = 2;
3457 }
3458 if (coarsen && (optlevel == 0)) { // with -R option
3459 optlevel = 2;
3460 }
3461
3462 // Detect improper combinations of switches.
3463 if ((refine || plc) && weighted) {
3464 printf("Error: Switches -w cannot use together with -p or -r.\n");
3465 return false;
3466 }
3467
3468 if (convex) { // -c
3469 if (plc && !regionattrib) {
3470 // -A (region attribute) is needed for marking exterior tets (-1).
3471 regionattrib = 1;
3472 }
3473 }
3474
3475 // Note: -A must not used together with -r option.
3476 // Be careful not to add an extra attribute to each element unless the
3477 // input supports it (PLC in, but not refining a preexisting mesh).
3478 if (refine || !plc) {
3479 regionattrib = 0;
3480 }
3481 // Be careful not to allocate space for element area constraints that
3482 // will never be assigned any value (other than the default -1.0).
3483 if (!refine && !plc) {
3484 varvolume = 0;
3485 }
3486 // If '-a' or '-aa' is in use, enable '-q' option too.
3487 if (fixedvolume || varvolume) {
3488 if (quality == 0) {
3489 quality = 1;
3490 if (!plc && !refine) {
3491 plc = 1; // enable -p.
3492 }
3493 }
3494 }
3495 // No user-specified dihedral angle bound. Use default ones.
3496 if (!quality) {
3497 if (optmaxdihedral < 179.0) {
3498 if (nobisect) { // with -Y option
3499 optmaxdihedral = 179.0;
3500 } else { // -p only
3501 optmaxdihedral = 179.999;
3502 }
3503 }
3504 if (optminsmtdihed < 179.999) {
3505 optminsmtdihed = 179.999;
3506 }
3507 if (optminslidihed < 179.999) {
3508 optminslidihed = 179.999;
3509 }
3510 }
3511
3512 increment = 0;
3513 strcpy(workstring, infilename);
3514 j = 1;
3515 while (workstring[j] != '\0') {
3516 if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
3517 increment = j + 1;
3518 }
3519 j++;
3520 }
3521 meshnumber = 0;
3522 if (increment > 0) {
3523 j = increment;
3524 do {
3525 if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
3526 meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
3527 } else {
3528 increment = 0;
3529 }
3530 j++;
3531 } while (workstring[j] != '\0');
3532 }
3533 if (noiterationnum) {
3534 strcpy(outfilename, infilename);
3535 } else if (increment == 0) {
3536 strcpy(outfilename, infilename);
3537 strcat(outfilename, ".1");
3538 } else {
3539 workstring[increment] = '%';
3540 workstring[increment + 1] = 'd';
3541 workstring[increment + 2] = '\0';
3542 sprintf(outfilename, workstring, meshnumber + 1);
3543 }
3544 // Additional input file name has the end ".a".
3545 strcpy(addinfilename, infilename);
3546 strcat(addinfilename, ".a");
3547 // Background filename has the form "*.b.ele", "*.b.node", ...
3548 strcpy(bgmeshfilename, infilename);
3549 strcat(bgmeshfilename, ".b");
3550
3551 return true;
3552}
3553
3554//// ////
3555//// ////
3556//// behavior_cxx /////////////////////////////////////////////////////////////
3557
3558//// mempool_cxx //////////////////////////////////////////////////////////////
3559//// ////
3560//// ////
3561
3562// Initialize fast lookup tables for mesh maniplulation primitives.
3563
3564int tetgenmesh::bondtbl[12][12] = {{0,},};
3565int tetgenmesh::enexttbl[12] = {0,};
3566int tetgenmesh::eprevtbl[12] = {0,};
3567int tetgenmesh::enextesymtbl[12] = {0,};
3568int tetgenmesh::eprevesymtbl[12] = {0,};
3569int tetgenmesh::eorgoppotbl[12] = {0,};
3570int tetgenmesh::edestoppotbl[12] = {0,};
3571int tetgenmesh::fsymtbl[12][12] = {{0,},};
3572int tetgenmesh::facepivot1[12] = {0,};
3573int tetgenmesh::facepivot2[12][12] = {{0,},};
3574int tetgenmesh::tsbondtbl[12][6] = {{0,},};
3575int tetgenmesh::stbondtbl[12][6] = {{0,},};
3576int tetgenmesh::tspivottbl[12][6] = {{0,},};
3577int tetgenmesh::stpivottbl[12][6] = {{0,},};
3578
3579// Table 'esymtbl' takes an directed edge (version) as input, returns the
3580// inversed edge (version) of it.
3581
3582int tetgenmesh::esymtbl[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
3583
3584// The following four tables give the 12 permutations of the set {0,1,2,3}.
3585// An offset 4 is added to each element for a direct access of the points
3586// in the tetrahedron data structure.
3587
3588int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
3589int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
3590int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
3591int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
3592
3593// The twelve versions correspond to six undirected edges. The following two
3594// tables map a version to an undirected edge and vice versa.
3595
3596int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
3597int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
3598
3599// Edge versions whose apex or opposite may be dummypoint.
3600
3601int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
3602
3603
3604// Table 'snextpivot' takes an edge version as input, returns the next edge
3605// version in the same edge ring.
3606
3607int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
3608
3609// The following three tables give the 6 permutations of the set {0,1,2}.
3610// An offset 3 is added to each element for a direct access of the points
3611// in the triangle data structure.
3612
3613int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
3614int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
3615int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
3616
3617///////////////////////////////////////////////////////////////////////////////
3618// //
3619// inittable() Initialize the look-up tables. //
3620// //
3621///////////////////////////////////////////////////////////////////////////////
3622
3623void tetgenmesh::inittables()
3624{
3625 int i, j;
3626
3627
3628 // i = t1.ver; j = t2.ver;
3629 for (i = 0; i < 12; i++) {
3630 for (j = 0; j < 12; j++) {
3631 bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
3632 }
3633 }
3634
3635
3636 // i = t1.ver; j = t2.ver
3637 for (i = 0; i < 12; i++) {
3638 for (j = 0; j < 12; j++) {
3639 fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
3640 }
3641 }
3642
3643
3644 for (i = 0; i < 12; i++) {
3645 facepivot1[i] = (esymtbl[i] & 3);
3646 }
3647
3648 for (i = 0; i < 12; i++) {
3649 for (j = 0; j < 12; j++) {
3650 facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
3651 }
3652 }
3653
3654 for (i = 0; i < 12; i++) {
3655 enexttbl[i] = (i + 4) % 12;
3656 eprevtbl[i] = (i + 8) % 12;
3657 }
3658
3659 for (i = 0; i < 12; i++) {
3660 enextesymtbl[i] = esymtbl[enexttbl[i]];
3661 eprevesymtbl[i] = esymtbl[eprevtbl[i]];
3662 }
3663
3664 for (i = 0; i < 12; i++) {
3665 eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]];
3666 edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]];
3667 }
3668
3669 int soffset, toffset;
3670
3671 // i = t.ver, j = s.shver
3672 for (i = 0; i < 12; i++) {
3673 for (j = 0; j < 6; j++) {
3674 if ((j & 1) == 0) {
3675 soffset = (6 - ((i & 12) >> 1)) % 6;
3676 toffset = (12 - ((j & 6) << 1)) % 12;
3677 } else {
3678 soffset = (i & 12) >> 1;
3679 toffset = (j & 6) << 1;
3680 }
3681 tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3682 stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3683 }
3684 }
3685
3686
3687 // i = t.ver, j = s.shver
3688 for (i = 0; i < 12; i++) {
3689 for (j = 0; j < 6; j++) {
3690 if ((j & 1) == 0) {
3691 soffset = (i & 12) >> 1;
3692 toffset = (j & 6) << 1;
3693 } else {
3694 soffset = (6 - ((i & 12) >> 1)) % 6;
3695 toffset = (12 - ((j & 6) << 1)) % 12;
3696 }
3697 tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3698 stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3699 }
3700 }
3701}
3702
3703///////////////////////////////////////////////////////////////////////////////
3704// //
3705// restart() Deallocate all objects in this pool. //
3706// //
3707// The pool returns to a fresh state, like after it was initialized, except //
3708// that no memory is freed to the operating system. Rather, the previously //
3709// allocated blocks are ready to be used. //
3710// //
3711///////////////////////////////////////////////////////////////////////////////
3712
3713void tetgenmesh::arraypool::restart()
3714{
3715 objects = 0l;
3716}
3717
3718///////////////////////////////////////////////////////////////////////////////
3719// //
3720// poolinit() Initialize an arraypool for allocation of objects. //
3721// //
3722// Before the pool may be used, it must be initialized by this procedure. //
3723// After initialization, memory can be allocated and freed in this pool. //
3724// //
3725///////////////////////////////////////////////////////////////////////////////
3726
3727void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
3728{
3729 // Each object must be at least one byte long.
3730 objectbytes = sizeofobject > 1 ? sizeofobject : 1;
3731
3732 log2objectsperblock = log2objperblk;
3733 // Compute the number of objects in each block.
3734 objectsperblock = ((int) 1) << log2objectsperblock;
3735 objectsperblockmark = objectsperblock - 1;
3736
3737 // No memory has been allocated.
3738 totalmemory = 0l;
3739 // The top array has not been allocated yet.
3740 toparray = (char **) NULL;
3741 toparraylen = 0;
3742
3743 // Ready all indices to be allocated.
3744 restart();
3745}
3746
3747///////////////////////////////////////////////////////////////////////////////
3748// //
3749// arraypool() The constructor and destructor. //
3750// //
3751///////////////////////////////////////////////////////////////////////////////
3752
3753tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
3754{
3755 poolinit(sizeofobject, log2objperblk);
3756}
3757
3758tetgenmesh::arraypool::~arraypool()
3759{
3760 int i;
3761
3762 // Has anything been allocated at all?
3763 if (toparray != (char **) NULL) {
3764 // Walk through the top array.
3765 for (i = 0; i < toparraylen; i++) {
3766 // Check every pointer; NULLs may be scattered randomly.
3767 if (toparray[i] != (char *) NULL) {
3768 // Free an allocated block.
3769 free((void *) toparray[i]);
3770 }
3771 }
3772 // Free the top array.
3773 free((void *) toparray);
3774 }
3775
3776 // The top array is no longer allocated.
3777 toparray = (char **) NULL;
3778 toparraylen = 0;
3779 objects = 0;
3780 totalmemory = 0;
3781}
3782
3783///////////////////////////////////////////////////////////////////////////////
3784// //
3785// getblock() Return (and perhaps create) the block containing the object //
3786// with a given index. //
3787// //
3788// This function takes care of allocating or resizing the top array if nece- //
3789// ssary, and of allocating the block if it hasn't yet been allocated. //
3790// //
3791// Return a pointer to the beginning of the block (NOT the object). //
3792// //
3793///////////////////////////////////////////////////////////////////////////////
3794
3795char* tetgenmesh::arraypool::getblock(int objectindex)
3796{
3797 char **newarray;
3798 char *block;
3799 int newsize;
3800 int topindex;
3801 int i;
3802
3803 // Compute the index in the top array (upper bits).
3804 topindex = objectindex >> log2objectsperblock;
3805 // Does the top array need to be allocated or resized?
3806 if (toparray == (char **) NULL) {
3807 // Allocate the top array big enough to hold 'topindex', and NULL out
3808 // its contents.
3809 newsize = topindex + 128;
3810 toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3811 toparraylen = newsize;
3812 for (i = 0; i < newsize; i++) {
3813 toparray[i] = (char *) NULL;
3814 }
3815 // Account for the memory.
3816 totalmemory = newsize * (uintptr_t) sizeof(char *);
3817 } else if (topindex >= toparraylen) {
3818 // Resize the top array, making sure it holds 'topindex'.
3819 newsize = 3 * toparraylen;
3820 if (topindex >= newsize) {
3821 newsize = topindex + 128;
3822 }
3823 // Allocate the new array, copy the contents, NULL out the rest, and
3824 // free the old array.
3825 newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3826 for (i = 0; i < toparraylen; i++) {
3827 newarray[i] = toparray[i];
3828 }
3829 for (i = toparraylen; i < newsize; i++) {
3830 newarray[i] = (char *) NULL;
3831 }
3832 free(toparray);
3833 // Account for the memory.
3834 totalmemory += (newsize - toparraylen) * sizeof(char *);
3835 toparray = newarray;
3836 toparraylen = newsize;
3837 }
3838
3839 // Find the block, or learn that it hasn't been allocated yet.
3840 block = toparray[topindex];
3841 if (block == (char *) NULL) {
3842 // Allocate a block at this index.
3843 block = (char *) malloc((size_t) (objectsperblock * objectbytes));
3844 toparray[topindex] = block;
3845 // Account for the memory.
3846 totalmemory += objectsperblock * objectbytes;
3847 }
3848
3849 // Return a pointer to the block.
3850 return block;
3851}
3852
3853///////////////////////////////////////////////////////////////////////////////
3854// //
3855// lookup() Return the pointer to the object with a given index, or NULL //
3856// if the object's block doesn't exist yet. //
3857// //
3858///////////////////////////////////////////////////////////////////////////////
3859
3860void* tetgenmesh::arraypool::lookup(int objectindex)
3861{
3862 char *block;
3863 int topindex;
3864
3865 // Has the top array been allocated yet?
3866 if (toparray == (char **) NULL) {
3867 return (void *) NULL;
3868 }
3869
3870 // Compute the index in the top array (upper bits).
3871 topindex = objectindex >> log2objectsperblock;
3872 // Does the top index fit in the top array?
3873 if (topindex >= toparraylen) {
3874 return (void *) NULL;
3875 }
3876
3877 // Find the block, or learn that it hasn't been allocated yet.
3878 block = toparray[topindex];
3879 if (block == (char *) NULL) {
3880 return (void *) NULL;
3881 }
3882
3883 // Compute a pointer to the object with the given index. Note that
3884 // 'objectsperblock' is a power of two, so the & operation is a bit mask
3885 // that preserves the lower bits.
3886 return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
3887}
3888
3889///////////////////////////////////////////////////////////////////////////////
3890// //
3891// newindex() Allocate space for a fresh object from the pool. //
3892// //
3893// 'newptr' returns a pointer to the new object (it must not be a NULL). //
3894// //
3895///////////////////////////////////////////////////////////////////////////////
3896
3897int tetgenmesh::arraypool::newindex(void **newptr)
3898{
3899 // Allocate an object at index 'firstvirgin'.
3900 int newindex = objects;
3901 *newptr = (void *) (getblock(objects) +
3902 (objects & (objectsperblock - 1)) * objectbytes);
3903 objects++;
3904
3905 return newindex;
3906}
3907
3908
3909///////////////////////////////////////////////////////////////////////////////
3910// //
3911// memorypool() The constructors of memorypool. //
3912// //
3913///////////////////////////////////////////////////////////////////////////////
3914
3915tetgenmesh::memorypool::memorypool()
3916{
3917 firstblock = nowblock = (void **) NULL;
3918 nextitem = (void *) NULL;
3919 deaditemstack = (void *) NULL;
3920 pathblock = (void **) NULL;
3921 pathitem = (void *) NULL;
3922 alignbytes = 0;
3923 itembytes = itemwords = 0;
3924 itemsperblock = 0;
3925 items = maxitems = 0l;
3926 unallocateditems = 0;
3927 pathitemsleft = 0;
3928}
3929
3930tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize,
3931 int alignment)
3932{
3933 poolinit(bytecount, itemcount, wsize, alignment);
3934}
3935
3936///////////////////////////////////////////////////////////////////////////////
3937// //
3938// ~memorypool() Free to the operating system all memory taken by a pool. //
3939// //
3940///////////////////////////////////////////////////////////////////////////////
3941
3942tetgenmesh::memorypool::~memorypool()
3943{
3944 while (firstblock != (void **) NULL) {
3945 nowblock = (void **) *(firstblock);
3946 free(firstblock);
3947 firstblock = nowblock;
3948 }
3949}
3950
3951///////////////////////////////////////////////////////////////////////////////
3952// //
3953// poolinit() Initialize a pool of memory for allocation of items. //
3954// //
3955// A `pool' is created whose records have size at least `bytecount'. Items //
3956// will be allocated in `itemcount'-item blocks. Each item is assumed to be //
3957// a collection of words, and either pointers or floating-point values are //
3958// assumed to be the "primary" word type. (The "primary" word type is used //
3959// to determine alignment of items.) If `alignment' isn't zero, all items //
3960// will be `alignment'-byte aligned in memory. `alignment' must be either a //
3961// multiple or a factor of the primary word size; powers of two are safe. //
3962// `alignment' is normally used to create a few unused bits at the bottom of //
3963// each item's pointer, in which information may be stored. //
3964// //
3965///////////////////////////////////////////////////////////////////////////////
3966
3967void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
3968 int alignment)
3969{
3970 // Find the proper alignment, which must be at least as large as:
3971 // - The parameter `alignment'.
3972 // - The primary word type, to avoid unaligned accesses.
3973 // - sizeof(void *), so the stack of dead items can be maintained
3974 // without unaligned accesses.
3975 if (alignment > wordsize) {
3976 alignbytes = alignment;
3977 } else {
3978 alignbytes = wordsize;
3979 }
3980 if ((int) sizeof(void *) > alignbytes) {
3981 alignbytes = (int) sizeof(void *);
3982 }
3983 itemwords = ((bytecount + alignbytes - 1) / alignbytes)
3984 * (alignbytes / wordsize);
3985 itembytes = itemwords * wordsize;
3986 itemsperblock = itemcount;
3987
3988 // Allocate a block of items. Space for `itemsperblock' items and one
3989 // pointer (to point to the next block) are allocated, as well as space
3990 // to ensure alignment of the items.
3991 firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
3992 + alignbytes);
3993 if (firstblock == (void **) NULL) {
3994 terminatetetgen(NULL, 1);
3995 }
3996 // Set the next block pointer to NULL.
3997 *(firstblock) = (void *) NULL;
3998 restart();
3999}
4000
4001///////////////////////////////////////////////////////////////////////////////
4002// //
4003// restart() Deallocate all items in this pool. //
4004// //
4005// The pool is returned to its starting state, except that no memory is //
4006// freed to the operating system. Rather, the previously allocated blocks //
4007// are ready to be reused. //
4008// //
4009///////////////////////////////////////////////////////////////////////////////
4010
4011void tetgenmesh::memorypool::restart()
4012{
4013 uintptr_t alignptr;
4014
4015 items = 0;
4016 maxitems = 0;
4017
4018 // Set the currently active block.
4019 nowblock = firstblock;
4020 // Find the first item in the pool. Increment by the size of (void *).
4021 alignptr = (uintptr_t) (nowblock + 1);
4022 // Align the item on an `alignbytes'-byte boundary.
4023 nextitem = (void *)
4024 (alignptr + (uintptr_t) alignbytes -
4025 (alignptr % (uintptr_t) alignbytes));
4026 // There are lots of unallocated items left in this block.
4027 unallocateditems = itemsperblock;
4028 // The stack of deallocated items is empty.
4029 deaditemstack = (void *) NULL;
4030}
4031
4032///////////////////////////////////////////////////////////////////////////////
4033// //
4034// alloc() Allocate space for an item. //
4035// //
4036///////////////////////////////////////////////////////////////////////////////
4037
4038void* tetgenmesh::memorypool::alloc()
4039{
4040 void *newitem;
4041 void **newblock;
4042 uintptr_t alignptr;
4043
4044 // First check the linked list of dead items. If the list is not
4045 // empty, allocate an item from the list rather than a fresh one.
4046 if (deaditemstack != (void *) NULL) {
4047 newitem = deaditemstack; // Take first item in list.
4048 deaditemstack = * (void **) deaditemstack;
4049 } else {
4050 // Check if there are any free items left in the current block.
4051 if (unallocateditems == 0) {
4052 // Check if another block must be allocated.
4053 if (*nowblock == (void *) NULL) {
4054 // Allocate a new block of items, pointed to by the previous block.
4055 newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4056 + alignbytes);
4057 if (newblock == (void **) NULL) {
4058 terminatetetgen(NULL, 1);
4059 }
4060 *nowblock = (void *) newblock;
4061 // The next block pointer is NULL.
4062 *newblock = (void *) NULL;
4063 }
4064 // Move to the new block.
4065 nowblock = (void **) *nowblock;
4066 // Find the first item in the block.
4067 // Increment by the size of (void *).
4068 alignptr = (uintptr_t) (nowblock + 1);
4069 // Align the item on an `alignbytes'-byte boundary.
4070 nextitem = (void *)
4071 (alignptr + (uintptr_t) alignbytes -
4072 (alignptr % (uintptr_t) alignbytes));
4073 // There are lots of unallocated items left in this block.
4074 unallocateditems = itemsperblock;
4075 }
4076 // Allocate a new item.
4077 newitem = nextitem;
4078 // Advance `nextitem' pointer to next free item in block.
4079 nextitem = (void *) ((uintptr_t) nextitem + itembytes);
4080 unallocateditems--;
4081 maxitems++;
4082 }
4083 items++;
4084 return newitem;
4085}
4086
4087///////////////////////////////////////////////////////////////////////////////
4088// //
4089// dealloc() Deallocate space for an item. //
4090// //
4091// The deallocated space is stored in a queue for later reuse. //
4092// //
4093///////////////////////////////////////////////////////////////////////////////
4094
4095void tetgenmesh::memorypool::dealloc(void *dyingitem)
4096{
4097 // Push freshly killed item onto stack.
4098 *((void **) dyingitem) = deaditemstack;
4099 deaditemstack = dyingitem;
4100 items--;
4101}
4102
4103///////////////////////////////////////////////////////////////////////////////
4104// //
4105// traversalinit() Prepare to traverse the entire list of items. //
4106// //
4107// This routine is used in conjunction with traverse(). //
4108// //
4109///////////////////////////////////////////////////////////////////////////////
4110
4111void tetgenmesh::memorypool::traversalinit()
4112{
4113 uintptr_t alignptr;
4114
4115 // Begin the traversal in the first block.
4116 pathblock = firstblock;
4117 // Find the first item in the block. Increment by the size of (void *).
4118 alignptr = (uintptr_t) (pathblock + 1);
4119 // Align with item on an `alignbytes'-byte boundary.
4120 pathitem = (void *)
4121 (alignptr + (uintptr_t) alignbytes -
4122 (alignptr % (uintptr_t) alignbytes));
4123 // Set the number of items left in the current block.
4124 pathitemsleft = itemsperblock;
4125}
4126
4127///////////////////////////////////////////////////////////////////////////////
4128// //
4129// traverse() Find the next item in the list. //
4130// //
4131// This routine is used in conjunction with traversalinit(). Be forewarned //
4132// that this routine successively returns all items in the list, including //
4133// deallocated ones on the deaditemqueue. It's up to you to figure out which //
4134// ones are actually dead. It can usually be done more space-efficiently by //
4135// a routine that knows something about the structure of the item. //
4136// //
4137///////////////////////////////////////////////////////////////////////////////
4138
4139void* tetgenmesh::memorypool::traverse()
4140{
4141 void *newitem;
4142 uintptr_t alignptr;
4143
4144 // Stop upon exhausting the list of items.
4145 if (pathitem == nextitem) {
4146 return (void *) NULL;
4147 }
4148 // Check whether any untraversed items remain in the current block.
4149 if (pathitemsleft == 0) {
4150 // Find the next block.
4151 pathblock = (void **) *pathblock;
4152 // Find the first item in the block. Increment by the size of (void *).
4153 alignptr = (uintptr_t) (pathblock + 1);
4154 // Align with item on an `alignbytes'-byte boundary.
4155 pathitem = (void *)
4156 (alignptr + (uintptr_t) alignbytes -
4157 (alignptr % (uintptr_t) alignbytes));
4158 // Set the number of items left in the current block.
4159 pathitemsleft = itemsperblock;
4160 }
4161 newitem = pathitem;
4162 // Find the next item in the block.
4163 pathitem = (void *) ((uintptr_t) pathitem + itembytes);
4164 pathitemsleft--;
4165 return newitem;
4166}
4167
4168///////////////////////////////////////////////////////////////////////////////
4169// //
4170// makeindex2pointmap() Create a map from index to vertices. //
4171// //
4172// 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
4173// to each vertex is set into the array. The pointer to the first vertex is //
4174// saved in 'idx2verlist[in->firstnumber]'. //
4175// //
4176///////////////////////////////////////////////////////////////////////////////
4177
4178void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
4179{
4180 point pointloop;
4181 int idx;
4182
4183 if (b->verbose > 1) {
4184 printf(" Constructing mapping from indices to points.\n");
4185 }
4186
4187 idx2verlist = new point[points->items + 1];
4188
4189 points->traversalinit();
4190 pointloop = pointtraverse();
4191 idx = in->firstnumber;
4192 while (pointloop != (point) NULL) {
4193 idx2verlist[idx++] = pointloop;
4194 pointloop = pointtraverse();
4195 }
4196}
4197
4198///////////////////////////////////////////////////////////////////////////////
4199// //
4200// makesubfacemap() Create a map from vertex to subfaces incident at it. //
4201// //
4202// The map is returned in two arrays 'idx2faclist' and 'facperverlist'. All //
4203// subfaces incident at i-th vertex (i is counted from 0) are found in the //
4204// array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1]. //
4205// Each entry in facperverlist[j] is a subface whose origin is the vertex. //
4206// //
4207// NOTE: These two arrays will be created inside this routine, don't forget //
4208// to free them after using. //
4209// //
4210///////////////////////////////////////////////////////////////////////////////
4211
4212void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
4213 face*& facperverlist)
4214{
4215 face shloop;
4216 int i, j, k;
4217
4218 if (b->verbose > 1) {
4219 printf(" Making a map from points to subfaces.\n");
4220 }
4221
4222 // Initialize 'idx2faclist'.
4223 idx2faclist = new int[points->items + 1];
4224 for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
4225
4226 // Loop all subfaces, counter the number of subfaces incident at a vertex.
4227 pool->traversalinit();
4228 shloop.sh = shellfacetraverse(pool);
4229 while (shloop.sh != (shellface *) NULL) {
4230 // Increment the number of incident subfaces for each vertex.
4231 j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4232 idx2faclist[j]++;
4233 j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4234 idx2faclist[j]++;
4235 // Skip the third corner if it is a segment.
4236 if (shloop.sh[5] != NULL) {
4237 j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4238 idx2faclist[j]++;
4239 }
4240 shloop.sh = shellfacetraverse(pool);
4241 }
4242
4243 // Calculate the total length of array 'facperverlist'.
4244 j = idx2faclist[0];
4245 idx2faclist[0] = 0; // Array starts from 0 element.
4246 for (i = 0; i < points->items; i++) {
4247 k = idx2faclist[i + 1];
4248 idx2faclist[i + 1] = idx2faclist[i] + j;
4249 j = k;
4250 }
4251
4252 // The total length is in the last unit of idx2faclist.
4253 facperverlist = new face[idx2faclist[i]];
4254
4255 // Loop all subfaces again, remember the subfaces at each vertex.
4256 pool->traversalinit();
4257 shloop.sh = shellfacetraverse(pool);
4258 while (shloop.sh != (shellface *) NULL) {
4259 j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4260 shloop.shver = 0; // save the origin.
4261 facperverlist[idx2faclist[j]] = shloop;
4262 idx2faclist[j]++;
4263 // Is it a subface or a subsegment?
4264 if (shloop.sh[5] != NULL) {
4265 j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4266 shloop.shver = 2; // save the origin.
4267 facperverlist[idx2faclist[j]] = shloop;
4268 idx2faclist[j]++;
4269 j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4270 shloop.shver = 4; // save the origin.
4271 facperverlist[idx2faclist[j]] = shloop;
4272 idx2faclist[j]++;
4273 } else {
4274 j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4275 shloop.shver = 1; // save the origin.
4276 facperverlist[idx2faclist[j]] = shloop;
4277 idx2faclist[j]++;
4278 }
4279 shloop.sh = shellfacetraverse(pool);
4280 }
4281
4282 // Contents in 'idx2faclist' are shifted, now shift them back.
4283 for (i = points->items - 1; i >= 0; i--) {
4284 idx2faclist[i + 1] = idx2faclist[i];
4285 }
4286 idx2faclist[0] = 0;
4287}
4288
4289///////////////////////////////////////////////////////////////////////////////
4290// //
4291// tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
4292// //
4293///////////////////////////////////////////////////////////////////////////////
4294
4295void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
4296{
4297 // Set tetrahedron's vertices to NULL. This makes it possible to detect
4298 // dead tetrahedra when traversing the list of all tetrahedra.
4299 dyingtetrahedron[4] = (tetrahedron) NULL;
4300
4301 // Dealloc the space to subfaces/subsegments.
4302 if (dyingtetrahedron[8] != NULL) {
4303 tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
4304 }
4305 if (dyingtetrahedron[9] != NULL) {
4306 tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
4307 }
4308
4309 tetrahedrons->dealloc((void *) dyingtetrahedron);
4310}
4311
4312///////////////////////////////////////////////////////////////////////////////
4313// //
4314// tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
4315// //
4316///////////////////////////////////////////////////////////////////////////////
4317
4318tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
4319{
4320 tetrahedron *newtetrahedron;
4321
4322 do {
4323 newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4324 if (newtetrahedron == (tetrahedron *) NULL) {
4325 return (tetrahedron *) NULL;
4326 }
4327 } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
4328 ((point) newtetrahedron[7] == dummypoint));
4329 return newtetrahedron;
4330}
4331
4332tetgenmesh::tetrahedron* tetgenmesh::alltetrahedrontraverse()
4333{
4334 tetrahedron *newtetrahedron;
4335
4336 do {
4337 newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4338 if (newtetrahedron == (tetrahedron *) NULL) {
4339 return (tetrahedron *) NULL;
4340 }
4341 } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
4342 return newtetrahedron;
4343}
4344
4345///////////////////////////////////////////////////////////////////////////////
4346// //
4347// shellfacedealloc() Deallocate space for a shellface, marking it dead. //
4348// Used both for dealloc a subface and subsegment. //
4349// //
4350///////////////////////////////////////////////////////////////////////////////
4351
4352void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
4353{
4354 // Set shellface's vertices to NULL. This makes it possible to detect dead
4355 // shellfaces when traversing the list of all shellfaces.
4356 dyingsh[3] = (shellface) NULL;
4357 pool->dealloc((void *) dyingsh);
4358}
4359
4360///////////////////////////////////////////////////////////////////////////////
4361// //
4362// shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
4363// for both subfaces and subsegments pool traverse. //
4364// //
4365///////////////////////////////////////////////////////////////////////////////
4366
4367tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
4368{
4369 shellface *newshellface;
4370
4371 do {
4372 newshellface = (shellface *) pool->traverse();
4373 if (newshellface == (shellface *) NULL) {
4374 return (shellface *) NULL;
4375 }
4376 } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
4377 return newshellface;
4378}
4379
4380
4381///////////////////////////////////////////////////////////////////////////////
4382// //
4383// pointdealloc() Deallocate space for a point, marking it dead. //
4384// //
4385///////////////////////////////////////////////////////////////////////////////
4386
4387void tetgenmesh::pointdealloc(point dyingpoint)
4388{
4389 // Mark the point as dead. This makes it possible to detect dead points
4390 // when traversing the list of all points.
4391 setpointtype(dyingpoint, DEADVERTEX);
4392 points->dealloc((void *) dyingpoint);
4393}
4394
4395///////////////////////////////////////////////////////////////////////////////
4396// //
4397// pointtraverse() Traverse the points, skipping dead ones. //
4398// //
4399///////////////////////////////////////////////////////////////////////////////
4400
4401tetgenmesh::point tetgenmesh::pointtraverse()
4402{
4403 point newpoint;
4404
4405 do {
4406 newpoint = (point) points->traverse();
4407 if (newpoint == (point) NULL) {
4408 return (point) NULL;
4409 }
4410 } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
4411 return newpoint;
4412}
4413
4414///////////////////////////////////////////////////////////////////////////////
4415// //
4416// maketetrahedron() Create a new tetrahedron. //
4417// //
4418///////////////////////////////////////////////////////////////////////////////
4419
4420void tetgenmesh::maketetrahedron(triface *newtet)
4421{
4422 newtet->tet = (tetrahedron *) tetrahedrons->alloc();
4423
4424 // Initialize the four adjoining tetrahedra to be "outer space".
4425 newtet->tet[0] = NULL;
4426 newtet->tet[1] = NULL;
4427 newtet->tet[2] = NULL;
4428 newtet->tet[3] = NULL;
4429 // Four NULL vertices.
4430 newtet->tet[4] = NULL;
4431 newtet->tet[5] = NULL;
4432 newtet->tet[6] = NULL;
4433 newtet->tet[7] = NULL;
4434 // No attached segments and subfaces yet.
4435 newtet->tet[8] = NULL;
4436 newtet->tet[9] = NULL;
4437 // Initialize the marker (clear all flags).
4438 setelemmarker(newtet->tet, 0);
4439 for (int i = 0; i < numelemattrib; i++) {
4440 setelemattribute(newtet->tet, i, 0.0);
4441 }
4442 if (b->varvolume) {
4443 setvolumebound(newtet->tet, -1.0);
4444 }
4445
4446 // Initialize the version to be Zero.
4447 newtet->ver = 11;
4448}
4449
4450///////////////////////////////////////////////////////////////////////////////
4451// //
4452// makeshellface() Create a new shellface with version zero. Used for //
4453// both subfaces and subsegments. //
4454// //
4455///////////////////////////////////////////////////////////////////////////////
4456
4457void tetgenmesh::makeshellface(memorypool *pool, face *newface)
4458{
4459 newface->sh = (shellface *) pool->alloc();
4460
4461 // No adjointing subfaces.
4462 newface->sh[0] = NULL;
4463 newface->sh[1] = NULL;
4464 newface->sh[2] = NULL;
4465 // Three NULL vertices.
4466 newface->sh[3] = NULL;
4467 newface->sh[4] = NULL;
4468 newface->sh[5] = NULL;
4469 // No adjoining subsegments.
4470 newface->sh[6] = NULL;
4471 newface->sh[7] = NULL;
4472 newface->sh[8] = NULL;
4473 // No adjoining tetrahedra.
4474 newface->sh[9] = NULL;
4475 newface->sh[10] = NULL;
4476 if (checkconstraints) {
4477 // Initialize the maximum area bound.
4478 setareabound(*newface, 0.0);
4479 }
4480 // Clear the infection and marktest bits.
4481 ((int *) (newface->sh))[shmarkindex + 1] = 0;
4482 if (useinsertradius) {
4483 setfacetindex(*newface, 0);
4484 }
4485 // Set the boundary marker to zero.
4486 setshellmark(*newface, 0);
4487
4488 newface->shver = 0;
4489}
4490
4491///////////////////////////////////////////////////////////////////////////////
4492// //
4493// makepoint() Create a new point. //
4494// //
4495///////////////////////////////////////////////////////////////////////////////
4496
4497void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
4498{
4499 int i;
4500
4501 *pnewpoint = (point) points->alloc();
4502
4503 // Initialize the point attributes.
4504 for (i = 0; i < numpointattrib; i++) {
4505 (*pnewpoint)[3 + i] = 0.0;
4506 }
4507 // Initialize the metric tensor.
4508 for (i = 0; i < sizeoftensor; i++) {
4509 (*pnewpoint)[pointmtrindex + i] = 0.0;
4510 }
4511 setpoint2tet(*pnewpoint, NULL);
4512 setpoint2ppt(*pnewpoint, NULL);
4513 if (b->plc || b->refine) {
4514 // Initialize the point-to-simplex field.
4515 setpoint2sh(*pnewpoint, NULL);
4516 if (b->metric && (bgm != NULL)) {
4517 setpoint2bgmtet(*pnewpoint, NULL);
4518 }
4519 }
4520 // Initialize the point marker (starting from in->firstnumber).
4521 setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
4522 // Clear all flags.
4523 ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
4524 // Initialize (set) the point type.
4525 setpointtype(*pnewpoint, vtype);
4526}
4527
4528///////////////////////////////////////////////////////////////////////////////
4529// //
4530// initializepools() Calculate the sizes of the point, tetrahedron, and //
4531// subface. Initialize their memory pools. //
4532// //
4533// This routine also computes the indices 'pointmarkindex', 'point2simindex',//
4534// 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'. They are //
4535// used to find values within each point and tetrahedron, respectively. //
4536// //
4537///////////////////////////////////////////////////////////////////////////////
4538
4539void tetgenmesh::initializepools()
4540{
4541 int pointsize = 0, elesize = 0, shsize = 0;
4542 int i;
4543
4544 if (b->verbose) {
4545 printf(" Initializing memorypools.\n");
4546 printf(" tetrahedron per block: %d.\n", b->tetrahedraperblock);
4547 }
4548
4549 inittables();
4550
4551 // There are three input point lists available, which are in, addin,
4552 // and bgm->in. These point lists may have different number of
4553 // attributes. Decide the maximum number.
4554 numpointattrib = in->numberofpointattributes;
4555 if (bgm != NULL) {
4556 if (bgm->in->numberofpointattributes > numpointattrib) {
4557 numpointattrib = bgm->in->numberofpointattributes;
4558 }
4559 }
4560 if (addin != NULL) {
4561 if (addin->numberofpointattributes > numpointattrib) {
4562 numpointattrib = addin->numberofpointattributes;
4563 }
4564 }
4565 if (b->weighted || b->flipinsert) { // -w or -L.
4566 // The internal number of point attribute needs to be at least 1
4567 // (for storing point weights).
4568 if (numpointattrib == 0) {
4569 numpointattrib = 1;
4570 }
4571 }
4572
4573 // Default varconstraint = 0;
4574 if (in->segmentconstraintlist || in->facetconstraintlist) {
4575 checkconstraints = 1;
4576 }
4577 if (b->plc || b->refine) {
4578 // Save the insertion radius for Steiner points if boundaries
4579 // are allowed be split.
4580 if (!b->nobisect || checkconstraints) {
4581 useinsertradius = 1;
4582 }
4583 }
4584
4585 // The index within each point at which its metric tensor is found.
4586 // Each vertex has three coordinates.
4587 if (b->psc) {
4588 // '-s' option (PSC), the u,v coordinates are provided.
4589 pointmtrindex = 5 + numpointattrib;
4590 // The index within each point at which its u, v coordinates are found.
4591 // Comment: They are saved after the list of point attributes.
4592 pointparamindex = pointmtrindex - 2;
4593 } else {
4594 pointmtrindex = 3 + numpointattrib;
4595 }
4596 // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
4597 if (b->metric) {
4598 // Decide the size (1, 3, or 6) of the metric tensor.
4599 if (bgm != (tetgenmesh *) NULL) {
4600 // A background mesh is allocated. It may not exist though.
4601 sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
4602 bgm->in->numberofpointmtrs : in->numberofpointmtrs;
4603 } else {
4604 // No given background mesh - Itself is a background mesh.
4605 sizeoftensor = in->numberofpointmtrs;
4606 }
4607 // Make sure sizeoftensor is at least 1.
4608 sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
4609 } else {
4610 // For '-q' option. Make sure to have space for saving a scalar value.
4611 sizeoftensor = b->quality ? 1 : 0;
4612 }
4613 if (useinsertradius) {
4614 // Increase a space (REAL) for saving point insertion radius, it is
4615 // saved directly after the metric.
4616 sizeoftensor++;
4617 }
4618 // The index within each point at which an element pointer is found, where
4619 // the index is measured in pointers. Ensure the index is aligned to a
4620 // sizeof(tetrahedron)-byte address.
4621 point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
4622 + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
4623 if (b->plc || b->refine || b->voroout) {
4624 // Increase the point size by three pointers, which are:
4625 // - a pointer to a tet, read by point2tet();
4626 // - a pointer to a parent point, read by point2ppt()).
4627 // - a pointer to a subface or segment, read by point2sh();
4628 if (b->metric && (bgm != (tetgenmesh *) NULL)) {
4629 // Increase one pointer into the background mesh, point2bgmtet().
4630 pointsize = (point2simindex + 4) * sizeof(tetrahedron);
4631 } else {
4632 pointsize = (point2simindex + 3) * sizeof(tetrahedron);
4633 }
4634 } else {
4635 // Increase the point size by two pointer, which are:
4636 // - a pointer to a tet, read by point2tet();
4637 // - a pointer to a parent point, read by point2ppt()). -- Used by btree.
4638 pointsize = (point2simindex + 2) * sizeof(tetrahedron);
4639 }
4640 // The index within each point at which the boundary marker is found,
4641 // Ensure the point marker is aligned to a sizeof(int)-byte address.
4642 pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
4643 // Now point size is the ints (indicated by pointmarkindex) plus:
4644 // - an integer for boundary marker;
4645 // - an integer for vertex type;
4646 // - an integer for geometry tag (optional, -s option).
4647 pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
4648
4649 // Initialize the pool of vertices.
4650 points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
4651
4652 if (b->verbose) {
4653 printf(" Size of a point: %d bytes.\n", points->itembytes);
4654 }
4655
4656 // Initialize the infinite vertex.
4657 dummypoint = (point) new char[pointsize];
4658 // Initialize all fields of this point.
4659 dummypoint[0] = 0.0;
4660 dummypoint[1] = 0.0;
4661 dummypoint[2] = 0.0;
4662 for (i = 0; i < numpointattrib; i++) {
4663 dummypoint[3 + i] = 0.0;
4664 }
4665 // Initialize the metric tensor.
4666 for (i = 0; i < sizeoftensor; i++) {
4667 dummypoint[pointmtrindex + i] = 0.0;
4668 }
4669 setpoint2tet(dummypoint, NULL);
4670 setpoint2ppt(dummypoint, NULL);
4671 if (b->plc || b->psc || b->refine) {
4672 // Initialize the point-to-simplex field.
4673 setpoint2sh(dummypoint, NULL);
4674 if (b->metric && (bgm != NULL)) {
4675 setpoint2bgmtet(dummypoint, NULL);
4676 }
4677 }
4678 // Initialize the point marker (starting from in->firstnumber).
4679 setpointmark(dummypoint, -1); // The unique marker for dummypoint.
4680 // Clear all flags.
4681 ((int *) (dummypoint))[pointmarkindex + 1] = 0;
4682 // Initialize (set) the point type.
4683 setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
4684
4685 // The number of bytes occupied by a tetrahedron is varying by the user-
4686 // specified options. The contents of the first 12 pointers are listed
4687 // in the following table:
4688 // [0] |__ neighbor at f0 __|
4689 // [1] |__ neighbor at f1 __|
4690 // [2] |__ neighbor at f2 __|
4691 // [3] |__ neighbor at f3 __|
4692 // [4] |_____ vertex p0 ____|
4693 // [5] |_____ vertex p1 ____|
4694 // [6] |_____ vertex p2 ____|
4695 // [7] |_____ vertex p3 ____|
4696 // [8] |__ segments array __| (used by -p)
4697 // [9] |__ subfaces array __| (used by -p)
4698 // [10] |_____ reserved _____|
4699 // [11] |___ elem marker ____| (used as an integer)
4700
4701 elesize = 12 * sizeof(tetrahedron);
4702
4703 // The index to find the element markers. An integer containing varies
4704 // flags and element counter.
4705 assert(sizeof(int) <= sizeof(tetrahedron));
4706 assert((sizeof(tetrahedron) % sizeof(int)) == 0);
4707 elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
4708
4709 // The actual number of element attributes. Note that if the
4710 // `b->regionattrib' flag is set, an additional attribute will be added.
4711 numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
4712
4713 // The index within each element at which its attributes are found, where
4714 // the index is measured in REALs.
4715 elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
4716 // The index within each element at which the maximum volume bound is
4717 // found, where the index is measured in REALs.
4718 volumeboundindex = elemattribindex + numelemattrib;
4719 // If element attributes or an constraint are needed, increase the number
4720 // of bytes occupied by an element.
4721 if (b->varvolume) {
4722 elesize = (volumeboundindex + 1) * sizeof(REAL);
4723 } else if (numelemattrib > 0) {
4724 elesize = volumeboundindex * sizeof(REAL);
4725 }
4726
4727
4728 // Having determined the memory size of an element, initialize the pool.
4729 tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
4730 16);
4731
4732 if (b->verbose) {
4733 printf(" Size of a tetrahedron: %d (%d) bytes.\n", elesize,
4734 tetrahedrons->itembytes);
4735 }
4736
4737 if (b->plc || b->refine) { // if (b->useshelles) {
4738 // The number of bytes occupied by a subface. The list of pointers
4739 // stored in a subface are: three to other subfaces, three to corners,
4740 // three to subsegments, two to tetrahedra.
4741 shsize = 11 * sizeof(shellface);
4742 // The index within each subface at which the maximum area bound is
4743 // found, where the index is measured in REALs.
4744 areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
4745 // If -q switch is in use, increase the number of bytes occupied by
4746 // a subface for saving maximum area bound.
4747 if (checkconstraints) {
4748 shsize = (areaboundindex + 1) * sizeof(REAL);
4749 } else {
4750 shsize = areaboundindex * sizeof(REAL);
4751 }
4752 // The index within subface at which the facet marker is found. Ensure
4753 // the marker is aligned to a sizeof(int)-byte address.
4754 shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
4755 // Increase the number of bytes by two or three integers, one for facet
4756 // marker, one for shellface type, and optionally one for pbc group.
4757 shsize = (shmarkindex + 2) * sizeof(shellface);
4758 if (useinsertradius) {
4759 // Increase the number of byte by one integer for storing facet index.
4760 // set/read by setfacetindex() and getfacetindex.
4761 shsize = (shmarkindex + 3) * sizeof(shellface);
4762 }
4763
4764 // Initialize the pool of subfaces. Each subface record is eight-byte
4765 // aligned so it has room to store an edge version (from 0 to 5) in
4766 // the least three bits.
4767 subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4768
4769 if (b->verbose) {
4770 printf(" Size of a shellface: %d (%d) bytes.\n", shsize,
4771 subfaces->itembytes);
4772 }
4773
4774 // Initialize the pool of subsegments. The subsegment's record is same
4775 // with subface.
4776 subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4777
4778 // Initialize the pool for tet-subseg connections.
4779 tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock,
4780 sizeof(void *), 0);
4781 // Initialize the pool for tet-subface connections.
4782 tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock,
4783 sizeof(void *), 0);
4784
4785 // Initialize arraypools for segment & facet recovery.
4786 subsegstack = new arraypool(sizeof(face), 10);
4787 subfacstack = new arraypool(sizeof(face), 10);
4788 subvertstack = new arraypool(sizeof(point), 8);
4789
4790 // Initialize arraypools for surface point insertion/deletion.
4791 caveshlist = new arraypool(sizeof(face), 8);
4792 caveshbdlist = new arraypool(sizeof(face), 8);
4793 cavesegshlist = new arraypool(sizeof(face), 4);
4794
4795 cavetetshlist = new arraypool(sizeof(face), 8);
4796 cavetetseglist = new arraypool(sizeof(face), 8);
4797 caveencshlist = new arraypool(sizeof(face), 8);
4798 caveencseglist = new arraypool(sizeof(face), 8);
4799 }
4800
4801 // Initialize the pools for flips.
4802 flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
4803 unflipqueue = new arraypool(sizeof(badface), 10);
4804
4805 // Initialize the arraypools for point insertion.
4806 cavetetlist = new arraypool(sizeof(triface), 10);
4807 cavebdrylist = new arraypool(sizeof(triface), 10);
4808 caveoldtetlist = new arraypool(sizeof(triface), 10);
4809 cavetetvertlist = new arraypool(sizeof(point), 10);
4810}
4811
4812//// ////
4813//// ////
4814//// mempool_cxx //////////////////////////////////////////////////////////////
4815
4816//// geom_cxx /////////////////////////////////////////////////////////////////
4817//// ////
4818//// ////
4819
4820// PI is the ratio of a circle's circumference to its diameter.
4821REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
4822
4823///////////////////////////////////////////////////////////////////////////////
4824// //
4825// insphere_s() Insphere test with symbolic perturbation. //
4826// //
4827// Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
4828// outside the circumscribed sphere of the four points. //
4829// //
4830// Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4831// pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4832// points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4833// //
4834// Return a positive value (> 0) if pe lies inside, a negative value (< 0) //
4835// if pe lies outside the sphere, the returned value will not be zero. //
4836// //
4837///////////////////////////////////////////////////////////////////////////////
4838
4839REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
4840{
4841 REAL sign;
4842
4843 sign = insphere(pa, pb, pc, pd, pe);
4844 if (sign != 0.0) {
4845 return sign;
4846 }
4847
4848 // Symbolic perturbation.
4849 point pt[5], swappt;
4850 REAL oriA, oriB;
4851 int swaps, count;
4852 int n, i;
4853
4854 pt[0] = pa;
4855 pt[1] = pb;
4856 pt[2] = pc;
4857 pt[3] = pd;
4858 pt[4] = pe;
4859
4860 // Sort the five points such that their indices are in the increasing
4861 // order. An optimized bubble sort algorithm is used, i.e., it has
4862 // the worst case O(n^2) runtime, but it is usually much faster.
4863 swaps = 0; // Record the total number of swaps.
4864 n = 5;
4865 do {
4866 count = 0;
4867 n = n - 1;
4868 for (i = 0; i < n; i++) {
4869 if (pointmark(pt[i]) > pointmark(pt[i+1])) {
4870 swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
4871 count++;
4872 }
4873 }
4874 swaps += count;
4875 } while (count > 0); // Continue if some points are swapped.
4876
4877 oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
4878 if (oriA != 0.0) {
4879 // Flip the sign if there are odd number of swaps.
4880 if ((swaps % 2) != 0) oriA = -oriA;
4881 return oriA;
4882 }
4883
4884 oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
4885 assert(oriB != 0.0); // SELF_CHECK
4886 // Flip the sign if there are odd number of swaps.
4887 if ((swaps % 2) != 0) oriB = -oriB;
4888 return oriB;
4889}
4890
4891///////////////////////////////////////////////////////////////////////////////
4892// //
4893// orient4d_s() 4d orientation test with symbolic perturbation. //
4894// //
4895// Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
4896// point pe' in R^4 lies below or above the hyperplane passing through the //
4897// four points pa', pb', pc', and pd'. //
4898// //
4899// Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4900// pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4901// the points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4902// //
4903// Return a positive value (> 0) if pe' lies below, a negative value (< 0) //
4904// if pe' lies above the hyperplane, the returned value should not be zero. //
4905// //
4906///////////////////////////////////////////////////////////////////////////////
4907
4908REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
4909 REAL aheight, REAL bheight, REAL cheight,
4910 REAL dheight, REAL eheight)
4911{
4912 REAL sign;
4913
4914 sign = orient4d(pa, pb, pc, pd, pe,
4915 aheight, bheight, cheight, dheight, eheight);
4916 if (sign != 0.0) {
4917 return sign;
4918 }
4919
4920 // Symbolic perturbation.
4921 point pt[5], swappt;
4922 REAL oriA, oriB;
4923 int swaps, count;
4924 int n, i;
4925
4926 pt[0] = pa;
4927 pt[1] = pb;
4928 pt[2] = pc;
4929 pt[3] = pd;
4930 pt[4] = pe;
4931
4932 // Sort the five points such that their indices are in the increasing
4933 // order. An optimized bubble sort algorithm is used, i.e., it has
4934 // the worst case O(n^2) runtime, but it is usually much faster.
4935 swaps = 0; // Record the total number of swaps.
4936 n = 5;
4937 do {
4938 count = 0;
4939 n = n - 1;
4940 for (i = 0; i < n; i++) {
4941 if (pointmark(pt[i]) > pointmark(pt[i+1])) {
4942 swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
4943 count++;
4944 }
4945 }
4946 swaps += count;
4947 } while (count > 0); // Continue if some points are swapped.
4948
4949 oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
4950 if (oriA != 0.0) {
4951 // Flip the sign if there are odd number of swaps.
4952 if ((swaps % 2) != 0) oriA = -oriA;
4953 return oriA;
4954 }
4955
4956 oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
4957 assert(oriB != 0.0); // SELF_CHECK
4958 // Flip the sign if there are odd number of swaps.
4959 if ((swaps % 2) != 0) oriB = -oriB;
4960 return oriB;
4961}
4962
4963///////////////////////////////////////////////////////////////////////////////
4964// //
4965// tri_edge_test() Triangle-edge intersection test. //
4966// //
4967// This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
4968// Q) in 3D, and tests if they intersect each other. //
4969// //
4970// If the point 'R' is not NULL, it lies strictly above the plane defined by //
4971// A, B, C. It is used in test when T and E are coplanar. //
4972// //
4973// If T and E intersect each other, they may intersect in different ways. If //
4974// 'level' > 0, their intersection type will be reported 'types' and 'pos'. //
4975// //
4976// The return value indicates one of the following cases: //
4977// - 0, T and E are disjoint. //
4978// - 1, T and E intersect each other. //
4979// - 2, T and E are not coplanar. They intersect at a single point. //
4980// - 4, T and E are coplanar. They intersect at a single point or a line //
4981// segment (if types[1] != DISJOINT). //
4982// //
4983///////////////////////////////////////////////////////////////////////////////
4984
4985#define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
4986
4987#define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
4988
4989int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q,
4990 point R, int level, int *types, int *pos)
4991{
4992 point U[3], V[3]; // The permuted vectors of points.
4993 int pu[3], pv[3]; // The original positions of points.
4994 REAL abovept[3];
4995 REAL sA, sB, sC;
4996 REAL s1, s2, s3, s4;
4997 int z1;
4998
4999 if (R == NULL) {
5000 // Calculate a lift point.
5001 if (1) {
5002 REAL n[3], len;
5003 // Calculate a lift point, saved in dummypoint.
5004 facenormal(A, B, C, n, 1, NULL);
5005 len = sqrt(dot(n, n));
5006 if (len != 0) {
5007 n[0] /= len;
5008 n[1] /= len;
5009 n[2] /= len;
5010 len = distance(A, B);
5011 len += distance(B, C);
5012 len += distance(C, A);
5013 len /= 3.0;
5014 R = abovept; //dummypoint;
5015 R[0] = A[0] + len * n[0];
5016 R[1] = A[1] + len * n[1];
5017 R[2] = A[2] + len * n[2];
5018 } else {
5019 // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
5020 // to a line. We need a line-line intersection test.
5021 //assert(0);
5022 // !!! A non-save return value.!!!
5023 return 0; // DISJOINT
5024 }
5025 }
5026 }
5027
5028 // Test A's, B's, and C's orientations wrt plane PQR.
5029 sA = orient3d(P, Q, R, A);
5030 sB = orient3d(P, Q, R, B);
5031 sC = orient3d(P, Q, R, C);
5032
5033
5034 if (sA < 0) {
5035 if (sB < 0) {
5036 if (sC < 0) { // (---).
5037 return 0;
5038 } else {
5039 if (sC > 0) { // (--+).
5040 // All points are in the right positions.
5041 SETVECTOR3(U, A, B, C); // I3
5042 SETVECTOR3(V, P, Q, R); // I2
5043 SETVECTOR3(pu, 0, 1, 2);
5044 SETVECTOR3(pv, 0, 1, 2);
5045 z1 = 0;
5046 } else { // (--0).
5047 SETVECTOR3(U, A, B, C); // I3
5048 SETVECTOR3(V, P, Q, R); // I2
5049 SETVECTOR3(pu, 0, 1, 2);
5050 SETVECTOR3(pv, 0, 1, 2);
5051 z1 = 1;
5052 }
5053 }
5054 } else {
5055 if (sB > 0) {
5056 if (sC < 0) { // (-+-).
5057 SETVECTOR3(U, C, A, B); // PT = ST
5058 SETVECTOR3(V, P, Q, R); // I2
5059 SETVECTOR3(pu, 2, 0, 1);
5060 SETVECTOR3(pv, 0, 1, 2);
5061 z1 = 0;
5062 } else {
5063 if (sC > 0) { // (-++).
5064 SETVECTOR3(U, B, C, A); // PT = ST x ST
5065 SETVECTOR3(V, Q, P, R); // PL = SL
5066 SETVECTOR3(pu, 1, 2, 0);
5067 SETVECTOR3(pv, 1, 0, 2);
5068 z1 = 0;
5069 } else { // (-+0).
5070 SETVECTOR3(U, C, A, B); // PT = ST
5071 SETVECTOR3(V, P, Q, R); // I2
5072 SETVECTOR3(pu, 2, 0, 1);
5073 SETVECTOR3(pv, 0, 1, 2);
5074 z1 = 2;
5075 }
5076 }
5077 } else {
5078 if (sC < 0) { // (-0-).
5079 SETVECTOR3(U, C, A, B); // PT = ST
5080 SETVECTOR3(V, P, Q, R); // I2
5081 SETVECTOR3(pu, 2, 0, 1);
5082 SETVECTOR3(pv, 0, 1, 2);
5083 z1 = 1;
5084 } else {
5085 if (sC > 0) { // (-0+).
5086 SETVECTOR3(U, B, C, A); // PT = ST x ST
5087 SETVECTOR3(V, Q, P, R); // PL = SL
5088 SETVECTOR3(pu, 1, 2, 0);
5089 SETVECTOR3(pv, 1, 0, 2);
5090 z1 = 2;
5091 } else { // (-00).
5092 SETVECTOR3(U, B, C, A); // PT = ST x ST
5093 SETVECTOR3(V, Q, P, R); // PL = SL
5094 SETVECTOR3(pu, 1, 2, 0);
5095 SETVECTOR3(pv, 1, 0, 2);
5096 z1 = 3;
5097 }
5098 }
5099 }
5100 }
5101 } else {
5102 if (sA > 0) {
5103 if (sB < 0) {
5104 if (sC < 0) { // (+--).
5105 SETVECTOR3(U, B, C, A); // PT = ST x ST
5106 SETVECTOR3(V, P, Q, R); // I2
5107 SETVECTOR3(pu, 1, 2, 0);
5108 SETVECTOR3(pv, 0, 1, 2);
5109 z1 = 0;
5110 } else {
5111 if (sC > 0) { // (+-+).
5112 SETVECTOR3(U, C, A, B); // PT = ST
5113 SETVECTOR3(V, Q, P, R); // PL = SL
5114 SETVECTOR3(pu, 2, 0, 1);
5115 SETVECTOR3(pv, 1, 0, 2);
5116 z1 = 0;
5117 } else { // (+-0).
5118 SETVECTOR3(U, C, A, B); // PT = ST
5119 SETVECTOR3(V, Q, P, R); // PL = SL
5120 SETVECTOR3(pu, 2, 0, 1);
5121 SETVECTOR3(pv, 1, 0, 2);
5122 z1 = 2;
5123 }
5124 }
5125 } else {
5126 if (sB > 0) {
5127 if (sC < 0) { // (++-).
5128 SETVECTOR3(U, A, B, C); // I3
5129 SETVECTOR3(V, Q, P, R); // PL = SL
5130 SETVECTOR3(pu, 0, 1, 2);
5131 SETVECTOR3(pv, 1, 0, 2);
5132 z1 = 0;
5133 } else {
5134 if (sC > 0) { // (+++).
5135 return 0;
5136 } else { // (++0).
5137 SETVECTOR3(U, A, B, C); // I3
5138 SETVECTOR3(V, Q, P, R); // PL = SL
5139 SETVECTOR3(pu, 0, 1, 2);
5140 SETVECTOR3(pv, 1, 0, 2);
5141 z1 = 1;
5142 }
5143 }
5144 } else { // (+0#)
5145 if (sC < 0) { // (+0-).
5146 SETVECTOR3(U, B, C, A); // PT = ST x ST
5147 SETVECTOR3(V, P, Q, R); // I2
5148 SETVECTOR3(pu, 1, 2, 0);
5149 SETVECTOR3(pv, 0, 1, 2);
5150 z1 = 2;
5151 } else {
5152 if (sC > 0) { // (+0+).
5153 SETVECTOR3(U, C, A, B); // PT = ST
5154 SETVECTOR3(V, Q, P, R); // PL = SL
5155 SETVECTOR3(pu, 2, 0, 1);
5156 SETVECTOR3(pv, 1, 0, 2);
5157 z1 = 1;
5158 } else { // (+00).
5159 SETVECTOR3(U, B, C, A); // PT = ST x ST
5160 SETVECTOR3(V, P, Q, R); // I2
5161 SETVECTOR3(pu, 1, 2, 0);
5162 SETVECTOR3(pv, 0, 1, 2);
5163 z1 = 3;
5164 }
5165 }
5166 }
5167 }
5168 } else {
5169 if (sB < 0) {
5170 if (sC < 0) { // (0--).
5171 SETVECTOR3(U, B, C, A); // PT = ST x ST
5172 SETVECTOR3(V, P, Q, R); // I2
5173 SETVECTOR3(pu, 1, 2, 0);
5174 SETVECTOR3(pv, 0, 1, 2);
5175 z1 = 1;
5176 } else {
5177 if (sC > 0) { // (0-+).
5178 SETVECTOR3(U, A, B, C); // I3
5179 SETVECTOR3(V, P, Q, R); // I2
5180 SETVECTOR3(pu, 0, 1, 2);
5181 SETVECTOR3(pv, 0, 1, 2);
5182 z1 = 2;
5183 } else { // (0-0).
5184 SETVECTOR3(U, C, A, B); // PT = ST
5185 SETVECTOR3(V, Q, P, R); // PL = SL
5186 SETVECTOR3(pu, 2, 0, 1);
5187 SETVECTOR3(pv, 1, 0, 2);
5188 z1 = 3;
5189 }
5190 }
5191 } else {
5192 if (sB > 0) {
5193 if (sC < 0) { // (0+-).
5194 SETVECTOR3(U, A, B, C); // I3
5195 SETVECTOR3(V, Q, P, R); // PL = SL
5196 SETVECTOR3(pu, 0, 1, 2);
5197 SETVECTOR3(pv, 1, 0, 2);
5198 z1 = 2;
5199 } else {
5200 if (sC > 0) { // (0++).
5201 SETVECTOR3(U, B, C, A); // PT = ST x ST
5202 SETVECTOR3(V, Q, P, R); // PL = SL
5203 SETVECTOR3(pu, 1, 2, 0);
5204 SETVECTOR3(pv, 1, 0, 2);
5205 z1 = 1;
5206 } else { // (0+0).
5207 SETVECTOR3(U, C, A, B); // PT = ST
5208 SETVECTOR3(V, P, Q, R); // I2
5209 SETVECTOR3(pu, 2, 0, 1);
5210 SETVECTOR3(pv, 0, 1, 2);
5211 z1 = 3;
5212 }
5213 }
5214 } else { // (00#)
5215 if (sC < 0) { // (00-).
5216 SETVECTOR3(U, A, B, C); // I3
5217 SETVECTOR3(V, Q, P, R); // PL = SL
5218 SETVECTOR3(pu, 0, 1, 2);
5219 SETVECTOR3(pv, 1, 0, 2);
5220 z1 = 3;
5221 } else {
5222 if (sC > 0) { // (00+).
5223 SETVECTOR3(U, A, B, C); // I3
5224 SETVECTOR3(V, P, Q, R); // I2
5225 SETVECTOR3(pu, 0, 1, 2);
5226 SETVECTOR3(pv, 0, 1, 2);
5227 z1 = 3;
5228 } else { // (000)
5229 // Not possible unless ABC is degenerate.
5230 // Avoiding compiler warnings.
5231 SETVECTOR3(U, A, B, C); // I3
5232 SETVECTOR3(V, P, Q, R); // I2
5233 SETVECTOR3(pu, 0, 1, 2);
5234 SETVECTOR3(pv, 0, 1, 2);
5235 z1 = 4;
5236 }
5237 }
5238 }
5239 }
5240 }
5241 }
5242
5243 s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q
5244 s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P
5245
5246 if (s1 > 0) {
5247 return 0;
5248 }
5249 if (s2 < 0) {
5250 return 0;
5251 }
5252
5253 if (level == 0) {
5254 return 1; // They are intersected.
5255 }
5256
5257 assert(z1 != 4); // SELF_CHECK
5258
5259 if (z1 == 1) {
5260 if (s1 == 0) { // (0###)
5261 // C = Q.
5262 types[0] = (int) SHAREVERT;
5263 pos[0] = pu[2]; // C
5264 pos[1] = pv[1]; // Q
5265 types[1] = (int) DISJOINT;
5266 } else {
5267 if (s2 == 0) { // (#0##)
5268 // C = P.
5269 types[0] = (int) SHAREVERT;
5270 pos[0] = pu[2]; // C
5271 pos[1] = pv[0]; // P
5272 types[1] = (int) DISJOINT;
5273 } else { // (-+##)
5274 // C in [P, Q].
5275 types[0] = (int) ACROSSVERT;
5276 pos[0] = pu[2]; // C
5277 pos[1] = pv[0]; // [P, Q]
5278 types[1] = (int) DISJOINT;
5279 }
5280 }
5281 return 4;
5282 }
5283
5284 s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P
5285 s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q
5286
5287 if (z1 == 0) { // (tritri-03)
5288 if (s1 < 0) {
5289 if (s3 > 0) {
5290 assert(s2 > 0); // SELF_CHECK
5291 if (s4 > 0) {
5292 // [P, Q] overlaps [k, l] (-+++).
5293 types[0] = (int) ACROSSEDGE;
5294 pos[0] = pu[2]; // [C, A]
5295 pos[1] = pv[0]; // [P, Q]
5296 types[1] = (int) TOUCHFACE;
5297 pos[2] = 3; // [A, B, C]
5298 pos[3] = pv[1]; // Q
5299 } else {
5300 if (s4 == 0) {
5301 // Q = l, [P, Q] contains [k, l] (-++0).
5302 types[0] = (int) ACROSSEDGE;
5303 pos[0] = pu[2]; // [C, A]
5304 pos[1] = pv[0]; // [P, Q]
5305 types[1] = (int) TOUCHEDGE;
5306 pos[2] = pu[1]; // [B, C]
5307 pos[3] = pv[1]; // Q
5308 } else { // s4 < 0
5309 // [P, Q] contains [k, l] (-++-).
5310 types[0] = (int) ACROSSEDGE;
5311 pos[0] = pu[2]; // [C, A]
5312 pos[1] = pv[0]; // [P, Q]
5313 types[1] = (int) ACROSSEDGE;
5314 pos[2] = pu[1]; // [B, C]
5315 pos[3] = pv[0]; // [P, Q]
5316 }
5317 }
5318 } else {
5319 if (s3 == 0) {
5320 assert(s2 > 0); // SELF_CHECK
5321 if (s4 > 0) {
5322 // P = k, [P, Q] in [k, l] (-+0+).
5323 types[0] = (int) TOUCHEDGE;
5324 pos[0] = pu[2]; // [C, A]
5325 pos[1] = pv[0]; // P
5326 types[1] = (int) TOUCHFACE;
5327 pos[2] = 3; // [A, B, C]
5328 pos[3] = pv[1]; // Q
5329 } else {
5330 if (s4 == 0) {
5331 // [P, Q] = [k, l] (-+00).
5332 types[0] = (int) TOUCHEDGE;
5333 pos[0] = pu[2]; // [C, A]
5334 pos[1] = pv[0]; // P
5335 types[1] = (int) TOUCHEDGE;
5336 pos[2] = pu[1]; // [B, C]
5337 pos[3] = pv[1]; // Q
5338 } else {
5339 // P = k, [P, Q] contains [k, l] (-+0-).
5340 types[0] = (int) TOUCHEDGE;
5341 pos[0] = pu[2]; // [C, A]
5342 pos[1] = pv[0]; // P
5343 types[1] = (int) ACROSSEDGE;
5344 pos[2] = pu[1]; // [B, C]
5345 pos[3] = pv[0]; // [P, Q]
5346 }
5347 }
5348 } else { // s3 < 0
5349 if (s2 > 0) {
5350 if (s4 > 0) {
5351 // [P, Q] in [k, l] (-+-+).
5352 types[0] = (int) TOUCHFACE;
5353 pos[0] = 3; // [A, B, C]
5354 pos[1] = pv[0]; // P
5355 types[1] = (int) TOUCHFACE;
5356 pos[2] = 3; // [A, B, C]
5357 pos[3] = pv[1]; // Q
5358 } else {
5359 if (s4 == 0) {
5360 // Q = l, [P, Q] in [k, l] (-+-0).
5361 types[0] = (int) TOUCHFACE;
5362 pos[0] = 3; // [A, B, C]
5363 pos[1] = pv[0]; // P
5364 types[1] = (int) TOUCHEDGE;
5365 pos[2] = pu[1]; // [B, C]
5366 pos[3] = pv[1]; // Q
5367 } else { // s4 < 0
5368 // [P, Q] overlaps [k, l] (-+--).
5369 types[0] = (int) TOUCHFACE;
5370 pos[0] = 3; // [A, B, C]
5371 pos[1] = pv[0]; // P
5372 types[1] = (int) ACROSSEDGE;
5373 pos[2] = pu[1]; // [B, C]
5374 pos[3] = pv[0]; // [P, Q]
5375 }
5376 }
5377 } else { // s2 == 0
5378 // P = l (#0##).
5379 types[0] = (int) TOUCHEDGE;
5380 pos[0] = pu[1]; // [B, C]
5381 pos[1] = pv[0]; // P
5382 types[1] = (int) DISJOINT;
5383 }
5384 }
5385 }
5386 } else { // s1 == 0
5387 // Q = k (0####)
5388 types[0] = (int) TOUCHEDGE;
5389 pos[0] = pu[2]; // [C, A]
5390 pos[1] = pv[1]; // Q
5391 types[1] = (int) DISJOINT;
5392 }
5393 } else if (z1 == 2) { // (tritri-23)
5394 if (s1 < 0) {
5395 if (s3 > 0) {
5396 assert(s2 > 0); // SELF_CHECK
5397 if (s4 > 0) {
5398 // [P, Q] overlaps [A, l] (-+++).
5399 types[0] = (int) ACROSSVERT;
5400 pos[0] = pu[0]; // A
5401 pos[1] = pv[0]; // [P, Q]
5402 types[1] = (int) TOUCHFACE;
5403 pos[2] = 3; // [A, B, C]
5404 pos[3] = pv[1]; // Q
5405 } else {
5406 if (s4 == 0) {
5407 // Q = l, [P, Q] contains [A, l] (-++0).
5408 types[0] = (int) ACROSSVERT;
5409 pos[0] = pu[0]; // A
5410 pos[1] = pv[0]; // [P, Q]
5411 types[1] = (int) TOUCHEDGE;
5412 pos[2] = pu[1]; // [B, C]
5413 pos[3] = pv[1]; // Q
5414 } else { // s4 < 0
5415 // [P, Q] contains [A, l] (-++-).
5416 types[0] = (int) ACROSSVERT;
5417 pos[0] = pu[0]; // A
5418 pos[1] = pv[0]; // [P, Q]
5419 types[1] = (int) ACROSSEDGE;
5420 pos[2] = pu[1]; // [B, C]
5421 pos[3] = pv[0]; // [P, Q]
5422 }
5423 }
5424 } else {
5425 if (s3 == 0) {
5426 assert(s2 > 0); // SELF_CHECK
5427 if (s4 > 0) {
5428 // P = A, [P, Q] in [A, l] (-+0+).
5429 types[0] = (int) SHAREVERT;
5430 pos[0] = pu[0]; // A
5431 pos[1] = pv[0]; // P
5432 types[1] = (int) TOUCHFACE;
5433 pos[2] = 3; // [A, B, C]
5434 pos[3] = pv[1]; // Q
5435 } else {
5436 if (s4 == 0) {
5437 // [P, Q] = [A, l] (-+00).
5438 types[0] = (int) SHAREVERT;
5439 pos[0] = pu[0]; // A
5440 pos[1] = pv[0]; // P
5441 types[1] = (int) TOUCHEDGE;
5442 pos[2] = pu[1]; // [B, C]
5443 pos[3] = pv[1]; // Q
5444 } else { // s4 < 0
5445 // Q = l, [P, Q] in [A, l] (-+0-).
5446 types[0] = (int) SHAREVERT;
5447 pos[0] = pu[0]; // A
5448 pos[1] = pv[0]; // P
5449 types[1] = (int) ACROSSEDGE;
5450 pos[2] = pu[1]; // [B, C]
5451 pos[3] = pv[0]; // [P, Q]
5452 }
5453 }
5454 } else { // s3 < 0
5455 if (s2 > 0) {
5456 if (s4 > 0) {
5457 // [P, Q] in [A, l] (-+-+).
5458 types[0] = (int) TOUCHFACE;
5459 pos[0] = 3; // [A, B, C]
5460 pos[1] = pv[0]; // P
5461 types[0] = (int) TOUCHFACE;
5462 pos[0] = 3; // [A, B, C]
5463 pos[1] = pv[1]; // Q
5464 } else {
5465 if (s4 == 0) {
5466 // Q = l, [P, Q] in [A, l] (-+-0).
5467 types[0] = (int) TOUCHFACE;
5468 pos[0] = 3; // [A, B, C]
5469 pos[1] = pv[0]; // P
5470 types[0] = (int) TOUCHEDGE;
5471 pos[0] = pu[1]; // [B, C]
5472 pos[1] = pv[1]; // Q
5473 } else { // s4 < 0
5474 // [P, Q] overlaps [A, l] (-+--).
5475 types[0] = (int) TOUCHFACE;
5476 pos[0] = 3; // [A, B, C]
5477 pos[1] = pv[0]; // P
5478 types[0] = (int) ACROSSEDGE;
5479 pos[0] = pu[1]; // [B, C]
5480 pos[1] = pv[0]; // [P, Q]
5481 }
5482 }
5483 } else { // s2 == 0
5484 // P = l (#0##).
5485 types[0] = (int) TOUCHEDGE;
5486 pos[0] = pu[1]; // [B, C]
5487 pos[1] = pv[0]; // P
5488 types[1] = (int) DISJOINT;
5489 }
5490 }
5491 }
5492 } else { // s1 == 0
5493 // Q = A (0###).
5494 types[0] = (int) SHAREVERT;
5495 pos[0] = pu[0]; // A
5496 pos[1] = pv[1]; // Q
5497 types[1] = (int) DISJOINT;
5498 }
5499 } else if (z1 == 3) { // (tritri-33)
5500 if (s1 < 0) {
5501 if (s3 > 0) {
5502 assert(s2 > 0); // SELF_CHECK
5503 if (s4 > 0) {
5504 // [P, Q] overlaps [A, B] (-+++).
5505 types[0] = (int) ACROSSVERT;
5506 pos[0] = pu[0]; // A
5507 pos[1] = pv[0]; // [P, Q]
5508 types[1] = (int) TOUCHEDGE;
5509 pos[2] = pu[0]; // [A, B]
5510 pos[3] = pv[1]; // Q
5511 } else {
5512 if (s4 == 0) {
5513 // Q = B, [P, Q] contains [A, B] (-++0).
5514 types[0] = (int) ACROSSVERT;
5515 pos[0] = pu[0]; // A
5516 pos[1] = pv[0]; // [P, Q]
5517 types[1] = (int) SHAREVERT;
5518 pos[2] = pu[1]; // B
5519 pos[3] = pv[1]; // Q
5520 } else { // s4 < 0
5521 // [P, Q] contains [A, B] (-++-).
5522 types[0] = (int) ACROSSVERT;
5523 pos[0] = pu[0]; // A
5524 pos[1] = pv[0]; // [P, Q]
5525 types[1] = (int) ACROSSVERT;
5526 pos[2] = pu[1]; // B
5527 pos[3] = pv[0]; // [P, Q]
5528 }
5529 }
5530 } else {
5531 if (s3 == 0) {
5532 assert(s2 > 0); // SELF_CHECK
5533 if (s4 > 0) {
5534 // P = A, [P, Q] in [A, B] (-+0+).
5535 types[0] = (int) SHAREVERT;
5536 pos[0] = pu[0]; // A
5537 pos[1] = pv[0]; // P
5538 types[1] = (int) TOUCHEDGE;
5539 pos[2] = pu[0]; // [A, B]
5540 pos[3] = pv[1]; // Q
5541 } else {
5542 if (s4 == 0) {
5543 // [P, Q] = [A, B] (-+00).
5544 types[0] = (int) SHAREEDGE;
5545 pos[0] = pu[0]; // [A, B]
5546 pos[1] = pv[0]; // [P, Q]
5547 types[1] = (int) DISJOINT;
5548 } else { // s4 < 0
5549 // P= A, [P, Q] in [A, B] (-+0-).
5550 types[0] = (int) SHAREVERT;
5551 pos[0] = pu[0]; // A
5552 pos[1] = pv[0]; // P
5553 types[1] = (int) ACROSSVERT;
5554 pos[2] = pu[1]; // B
5555 pos[3] = pv[0]; // [P, Q]
5556 }
5557 }
5558 } else { // s3 < 0
5559 if (s2 > 0) {
5560 if (s4 > 0) {
5561 // [P, Q] in [A, B] (-+-+).
5562 types[0] = (int) TOUCHEDGE;
5563 pos[0] = pu[0]; // [A, B]
5564 pos[1] = pv[0]; // P
5565 types[1] = (int) TOUCHEDGE;
5566 pos[2] = pu[0]; // [A, B]
5567 pos[3] = pv[1]; // Q
5568 } else {
5569 if (s4 == 0) {
5570 // Q = B, [P, Q] in [A, B] (-+-0).
5571 types[0] = (int) TOUCHEDGE;
5572 pos[0] = pu[0]; // [A, B]
5573 pos[1] = pv[0]; // P
5574 types[1] = (int) SHAREVERT;
5575 pos[2] = pu[1]; // B
5576 pos[3] = pv[1]; // Q
5577 } else { // s4 < 0
5578 // [P, Q] overlaps [A, B] (-+--).
5579 types[0] = (int) TOUCHEDGE;
5580 pos[0] = pu[0]; // [A, B]
5581 pos[1] = pv[0]; // P
5582 types[1] = (int) ACROSSVERT;
5583 pos[2] = pu[1]; // B
5584 pos[3] = pv[0]; // [P, Q]
5585 }
5586 }
5587 } else { // s2 == 0
5588 // P = B (#0##).
5589 types[0] = (int) SHAREVERT;
5590 pos[0] = pu[1]; // B
5591 pos[1] = pv[0]; // P
5592 types[1] = (int) DISJOINT;
5593 }
5594 }
5595 }
5596 } else { // s1 == 0
5597 // Q = A (0###).
5598 types[0] = (int) SHAREVERT;
5599 pos[0] = pu[0]; // A
5600 pos[1] = pv[1]; // Q
5601 types[1] = (int) DISJOINT;
5602 }
5603 }
5604
5605 return 4;
5606}
5607
5608int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
5609 REAL sP,REAL sQ,int level,int *types,int *pos)
5610{
5611 point U[3], V[3]; //, Ptmp;
5612 int pu[3], pv[3]; //, itmp;
5613 REAL s1, s2, s3;
5614 int z1;
5615
5616
5617 if (sP < 0) {
5618 if (sQ < 0) { // (--) disjoint
5619 return 0;
5620 } else {
5621 if (sQ > 0) { // (-+)
5622 SETVECTOR3(U, A, B, C);
5623 SETVECTOR3(V, P, Q, R);
5624 SETVECTOR3(pu, 0, 1, 2);
5625 SETVECTOR3(pv, 0, 1, 2);
5626 z1 = 0;
5627 } else { // (-0)
5628 SETVECTOR3(U, A, B, C);
5629 SETVECTOR3(V, P, Q, R);
5630 SETVECTOR3(pu, 0, 1, 2);
5631 SETVECTOR3(pv, 0, 1, 2);
5632 z1 = 1;
5633 }
5634 }
5635 } else {
5636 if (sP > 0) { // (+-)
5637 if (sQ < 0) {
5638 SETVECTOR3(U, A, B, C);
5639 SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5640 SETVECTOR3(pu, 0, 1, 2);
5641 SETVECTOR3(pv, 1, 0, 2);
5642 z1 = 0;
5643 } else {
5644 if (sQ > 0) { // (++) disjoint
5645 return 0;
5646 } else { // (+0)
5647 SETVECTOR3(U, B, A, C); // A and B are flipped.
5648 SETVECTOR3(V, P, Q, R);
5649 SETVECTOR3(pu, 1, 0, 2);
5650 SETVECTOR3(pv, 0, 1, 2);
5651 z1 = 1;
5652 }
5653 }
5654 } else { // sP == 0
5655 if (sQ < 0) { // (0-)
5656 SETVECTOR3(U, A, B, C);
5657 SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5658 SETVECTOR3(pu, 0, 1, 2);
5659 SETVECTOR3(pv, 1, 0, 2);
5660 z1 = 1;
5661 } else {
5662 if (sQ > 0) { // (0+)
5663 SETVECTOR3(U, B, A, C); // A and B are flipped.
5664 SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5665 SETVECTOR3(pu, 1, 0, 2);
5666 SETVECTOR3(pv, 1, 0, 2);
5667 z1 = 1;
5668 } else { // (00)
5669 // A, B, C, P, and Q are coplanar.
5670 z1 = 2;
5671 }
5672 }
5673 }
5674 }
5675
5676 if (z1 == 2) {
5677 // The triangle and the edge are coplanar.
5678 return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
5679 }
5680
5681 s1 = orient3d(U[0], U[1], V[0], V[1]);
5682 if (s1 < 0) {
5683 return 0;
5684 }
5685
5686 s2 = orient3d(U[1], U[2], V[0], V[1]);
5687 if (s2 < 0) {
5688 return 0;
5689 }
5690
5691 s3 = orient3d(U[2], U[0], V[0], V[1]);
5692 if (s3 < 0) {
5693 return 0;
5694 }
5695
5696 if (level == 0) {
5697 return 1; // The are intersected.
5698 }
5699
5700 types[1] = (int) DISJOINT; // No second intersection point.
5701
5702 if (z1 == 0) {
5703 if (s1 > 0) {
5704 if (s2 > 0) {
5705 if (s3 > 0) { // (+++)
5706 // [P, Q] passes interior of [A, B, C].
5707 types[0] = (int) ACROSSFACE;
5708 pos[0] = 3; // interior of [A, B, C]
5709 pos[1] = 0; // [P, Q]
5710 } else { // s3 == 0 (++0)
5711 // [P, Q] intersects [C, A].
5712 types[0] = (int) ACROSSEDGE;
5713 pos[0] = pu[2]; // [C, A]
5714 pos[1] = 0; // [P, Q]
5715 }
5716 } else { // s2 == 0
5717 if (s3 > 0) { // (+0+)
5718 // [P, Q] intersects [B, C].
5719 types[0] = (int) ACROSSEDGE;
5720 pos[0] = pu[1]; // [B, C]
5721 pos[1] = 0; // [P, Q]
5722 } else { // s3 == 0 (+00)
5723 // [P, Q] passes C.
5724 types[0] = (int) ACROSSVERT;
5725 pos[0] = pu[2]; // C
5726 pos[1] = 0; // [P, Q]
5727 }
5728 }
5729 } else { // s1 == 0
5730 if (s2 > 0) {
5731 if (s3 > 0) { // (0++)
5732 // [P, Q] intersects [A, B].
5733 types[0] = (int) ACROSSEDGE;
5734 pos[0] = pu[0]; // [A, B]
5735 pos[1] = 0; // [P, Q]
5736 } else { // s3 == 0 (0+0)
5737 // [P, Q] passes A.
5738 types[0] = (int) ACROSSVERT;
5739 pos[0] = pu[0]; // A
5740 pos[1] = 0; // [P, Q]
5741 }
5742 } else { // s2 == 0
5743 if (s3 > 0) { // (00+)
5744 // [P, Q] passes B.
5745 types[0] = (int) ACROSSVERT;
5746 pos[0] = pu[1]; // B
5747 pos[1] = 0; // [P, Q]
5748 } else { // s3 == 0 (000)
5749 // Impossible.
5750 assert(0);
5751 }
5752 }
5753 }
5754 } else { // z1 == 1
5755 if (s1 > 0) {
5756 if (s2 > 0) {
5757 if (s3 > 0) { // (+++)
5758 // Q lies in [A, B, C].
5759 types[0] = (int) TOUCHFACE;
5760 pos[0] = 0; // [A, B, C]
5761 pos[1] = pv[1]; // Q
5762 } else { // s3 == 0 (++0)
5763 // Q lies on [C, A].
5764 types[0] = (int) TOUCHEDGE;
5765 pos[0] = pu[2]; // [C, A]
5766 pos[1] = pv[1]; // Q
5767 }
5768 } else { // s2 == 0
5769 if (s3 > 0) { // (+0+)
5770 // Q lies on [B, C].
5771 types[0] = (int) TOUCHEDGE;
5772 pos[0] = pu[1]; // [B, C]
5773 pos[1] = pv[1]; // Q
5774 } else { // s3 == 0 (+00)
5775 // Q = C.
5776 types[0] = (int) SHAREVERT;
5777 pos[0] = pu[2]; // C
5778 pos[1] = pv[1]; // Q
5779 }
5780 }
5781 } else { // s1 == 0
5782 if (s2 > 0) {
5783 if (s3 > 0) { // (0++)
5784 // Q lies on [A, B].
5785 types[0] = (int) TOUCHEDGE;
5786 pos[0] = pu[0]; // [A, B]
5787 pos[1] = pv[1]; // Q
5788 } else { // s3 == 0 (0+0)
5789 // Q = A.
5790 types[0] = (int) SHAREVERT;
5791 pos[0] = pu[0]; // A
5792 pos[1] = pv[1]; // Q
5793 }
5794 } else { // s2 == 0
5795 if (s3 > 0) { // (00+)
5796 // Q = B.
5797 types[0] = (int) SHAREVERT;
5798 pos[0] = pu[1]; // B
5799 pos[1] = pv[1]; // Q
5800 } else { // s3 == 0 (000)
5801 // Impossible.
5802 assert(0);
5803 }
5804 }
5805 }
5806 }
5807
5808 // T and E intersect in a single point.
5809 return 2;
5810}
5811
5812int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q,
5813 point R, int level, int *types, int *pos)
5814{
5815 REAL sP, sQ;
5816
5817 // Test the locations of P and Q with respect to ABC.
5818 sP = orient3d(A, B, C, P);
5819 sQ = orient3d(A, B, C, Q);
5820
5821 return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
5822}
5823
5824///////////////////////////////////////////////////////////////////////////////
5825// //
5826// tri_tri_inter() Test whether two triangle (abc) and (opq) are //
5827// intersecting or not. //
5828// //
5829// Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
5830// the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT. //
5831// //
5832///////////////////////////////////////////////////////////////////////////////
5833
5834int tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P,
5835 REAL* Q, REAL s_p, REAL s_q)
5836{
5837 int types[2], pos[4];
5838 int ni; // =0, 2, 4
5839
5840 ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
5841
5842 if (ni > 0) {
5843 if (ni == 2) {
5844 // Get the intersection type.
5845 if (types[0] == (int) SHAREVERT) {
5846 return (int) SHAREVERT;
5847 } else {
5848 return (int) INTERSECT;
5849 }
5850 } else if (ni == 4) {
5851 // There may be two intersections.
5852 if (types[0] == (int) SHAREVERT) {
5853 if (types[1] == (int) DISJOINT) {
5854 return (int) SHAREVERT;
5855 } else {
5856 assert(types[1] != (int) SHAREVERT);
5857 return (int) INTERSECT;
5858 }
5859 } else {
5860 if (types[0] == (int) SHAREEDGE) {
5861 return (int) SHAREEDGE;
5862 } else {
5863 return (int) INTERSECT;
5864 }
5865 }
5866 } else {
5867 assert(0);
5868 }
5869 }
5870
5871 return (int) DISJOINT;
5872}
5873
5874int tetgenmesh::tri_tri_inter(REAL* A,REAL* B,REAL* C,REAL* O,REAL* P,REAL* Q)
5875{
5876 REAL s_o, s_p, s_q;
5877 REAL s_a, s_b, s_c;
5878
5879 s_o = orient3d(A, B, C, O);
5880 s_p = orient3d(A, B, C, P);
5881 s_q = orient3d(A, B, C, Q);
5882 if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
5883 // o, p, q are all in the same halfspace of ABC.
5884 return 0; // DISJOINT;
5885 }
5886
5887 s_a = orient3d(O, P, Q, A);
5888 s_b = orient3d(O, P, Q, B);
5889 s_c = orient3d(O, P, Q, C);
5890 if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
5891 // a, b, c are all in the same halfspace of OPQ.
5892 return 0; // DISJOINT;
5893 }
5894
5895 int abcop, abcpq, abcqo;
5896 int shareedge = 0;
5897
5898 abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
5899 if (abcop == (int) INTERSECT) {
5900 return (int) INTERSECT;
5901 } else if (abcop == (int) SHAREEDGE) {
5902 shareedge++;
5903 }
5904 abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
5905 if (abcpq == (int) INTERSECT) {
5906 return (int) INTERSECT;
5907 } else if (abcpq == (int) SHAREEDGE) {
5908 shareedge++;
5909 }
5910 abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
5911 if (abcqo == (int) INTERSECT) {
5912 return (int) INTERSECT;
5913 } else if (abcqo == (int) SHAREEDGE) {
5914 shareedge++;
5915 }
5916 if (shareedge == 3) {
5917 // opq are coincident with abc.
5918 return (int) SHAREFACE;
5919 }
5920
5921 // It is only possible either no share edge or one.
5922 assert(shareedge == 0 || shareedge == 1);
5923
5924 // Continue to detect whether opq and abc are intersecting or not.
5925 int opqab, opqbc, opqca;
5926
5927 opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
5928 if (opqab == (int) INTERSECT) {
5929 return (int) INTERSECT;
5930 }
5931 opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
5932 if (opqbc == (int) INTERSECT) {
5933 return (int) INTERSECT;
5934 }
5935 opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
5936 if (opqca == (int) INTERSECT) {
5937 return (int) INTERSECT;
5938 }
5939
5940 // At this point, two triangles are not intersecting and not coincident.
5941 // They may be share an edge, or share a vertex, or disjoint.
5942 if (abcop == (int) SHAREEDGE) {
5943 assert((abcpq == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
5944 // op is coincident with an edge of abc.
5945 return (int) SHAREEDGE;
5946 }
5947 if (abcpq == (int) SHAREEDGE) {
5948 assert((abcop == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
5949 // pq is coincident with an edge of abc.
5950 return (int) SHAREEDGE;
5951 }
5952 if (abcqo == (int) SHAREEDGE) {
5953 assert((abcop == (int) SHAREVERT) && (abcpq == (int) SHAREVERT));
5954 // qo is coincident with an edge of abc.
5955 return (int) SHAREEDGE;
5956 }
5957
5958 // They may share a vertex or disjoint.
5959 if (abcop == (int) SHAREVERT) {
5960 // o or p is coincident with a vertex of abc.
5961 if (abcpq == (int) SHAREVERT) {
5962 // p is the coincident vertex.
5963 assert(abcqo != (int) SHAREVERT);
5964 } else {
5965 // o is the coincident vertex.
5966 assert(abcqo == (int) SHAREVERT);
5967 }
5968 return (int) SHAREVERT;
5969 }
5970 if (abcpq == (int) SHAREVERT) {
5971 // q is the coincident vertex.
5972 assert(abcqo == (int) SHAREVERT);
5973 return (int) SHAREVERT;
5974 }
5975
5976 // They are disjoint.
5977 return (int) DISJOINT;
5978}
5979
5980///////////////////////////////////////////////////////////////////////////////
5981// //
5982// lu_decmp() Compute the LU decomposition of a matrix. //
5983// //
5984// Compute the LU decomposition of a (non-singular) square matrix A using //
5985// partial pivoting and implicit row exchanges. The result is: //
5986// A = P * L * U, //
5987// where P is a permutation matrix, L is unit lower triangular, and U is //
5988// upper triangular. The factored form of A is used in combination with //
5989// 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
5990// //
5991// The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
5992// On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
5993// tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
5994// permutation effected by the partial pivoting, effectively, 'ps' array //
5995// tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
5996// depending on whether the number of row interchanges was even or odd, //
5997// respectively. //
5998// //
5999// Return true if the LU decomposition is successfully computed, otherwise, //
6000// return false in case that A is a singular matrix. //
6001// //
6002///////////////////////////////////////////////////////////////////////////////
6003
6004bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6005{
6006 REAL scales[4];
6007 REAL pivot, biggest, mult, tempf;
6008 int pivotindex = 0;
6009 int i, j, k;
6010
6011 *d = 1.0; // No row interchanges yet.
6012
6013 for (i = N; i < n + N; i++) { // For each row.
6014 // Find the largest element in each row for row equilibration
6015 biggest = 0.0;
6016 for (j = N; j < n + N; j++)
6017 if (biggest < (tempf = fabs(lu[i][j])))
6018 biggest = tempf;
6019 if (biggest != 0.0)
6020 scales[i] = 1.0 / biggest;
6021 else {
6022 scales[i] = 0.0;
6023 return false; // Zero row: singular matrix.
6024 }
6025 ps[i] = i; // Initialize pivot sequence.
6026 }
6027
6028 for (k = N; k < n + N - 1; k++) { // For each column.
6029 // Find the largest element in each column to pivot around.
6030 biggest = 0.0;
6031 for (i = k; i < n + N; i++) {
6032 if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6033 biggest = tempf;
6034 pivotindex = i;
6035 }
6036 }
6037 if (biggest == 0.0) {
6038 return false; // Zero column: singular matrix.
6039 }
6040 if (pivotindex != k) { // Update pivot sequence.
6041 j = ps[k];
6042 ps[k] = ps[pivotindex];
6043 ps[pivotindex] = j;
6044 *d = -(*d); // ...and change the parity of d.
6045 }
6046
6047 // Pivot, eliminating an extra variable each time
6048 pivot = lu[ps[k]][k];
6049 for (i = k + 1; i < n + N; i++) {
6050 lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6051 if (mult != 0.0) {
6052 for (j = k + 1; j < n + N; j++)
6053 lu[ps[i]][j] -= mult * lu[ps[k]][j];
6054 }
6055 }
6056 }
6057
6058 // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6059 return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6060}
6061
6062///////////////////////////////////////////////////////////////////////////////
6063// //
6064// lu_solve() Solves the linear equation: Ax = b, after the matrix A //
6065// has been decomposed into the lower and upper triangular //
6066// matrices L and U, where A = LU. //
6067// //
6068// 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
6069// its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
6070// is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
6071// is input as the right-hand side vector, and returns with the solution //
6072// vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
6073// left in place for successive calls with different right-hand sides 'b'. //
6074// //
6075///////////////////////////////////////////////////////////////////////////////
6076
6077void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6078{
6079 int i, j;
6080 REAL X[4], dot;
6081
6082 for (i = N; i < n + N; i++) X[i] = 0.0;
6083
6084 // Vector reduction using U triangular matrix.
6085 for (i = N; i < n + N; i++) {
6086 dot = 0.0;
6087 for (j = N; j < i + N; j++)
6088 dot += lu[ps[i]][j] * X[j];
6089 X[i] = b[ps[i]] - dot;
6090 }
6091
6092 // Back substitution, in L triangular matrix.
6093 for (i = n + N - 1; i >= N; i--) {
6094 dot = 0.0;
6095 for (j = i + 1; j < n + N; j++)
6096 dot += lu[ps[i]][j] * X[j];
6097 X[i] = (X[i] - dot) / lu[ps[i]][i];
6098 }
6099
6100 for (i = N; i < n + N; i++) b[i] = X[i];
6101}
6102
6103///////////////////////////////////////////////////////////////////////////////
6104// //
6105// incircle3d() 3D in-circle test. //
6106// //
6107// Return a negative value if pd is inside the circumcircle of the triangle //
6108// pa, pb, and pc. //
6109// //
6110// IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input //
6111// triangles are [a,b,c] and [b,a,d]. //
6112// //
6113///////////////////////////////////////////////////////////////////////////////
6114
6115REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
6116{
6117 REAL area2[2], n1[3], n2[3], c[3];
6118 REAL sign, r, d;
6119
6120 // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
6121 facenormal(pa, pb, pc, n1, 1, NULL);
6122 area2[0] = dot(n1, n1);
6123 facenormal(pb, pa, pd, n2, 1, NULL);
6124 area2[1] = dot(n2, n2);
6125
6126 if (area2[0] > area2[1]) {
6127 // Choose [a, b, c] as the base triangle.
6128 circumsphere(pa, pb, pc, NULL, c, &r);
6129 d = distance(c, pd);
6130 } else {
6131 // Choose [b, a, d] as the base triangle.
6132 if (area2[1] > 0) {
6133 circumsphere(pb, pa, pd, NULL, c, &r);
6134 d = distance(c, pc);
6135 } else {
6136 // The four points are collinear. This case only happens on the boundary.
6137 return 0; // Return "not inside".
6138 }
6139 }
6140
6141 sign = d - r;
6142 if (fabs(sign) / r < b->epsilon) {
6143 sign = 0;
6144 }
6145
6146 return sign;
6147}
6148
6149///////////////////////////////////////////////////////////////////////////////
6150// //
6151// facenormal() Calculate the normal of the face. //
6152// //
6153// The normal of the face abc can be calculated by the cross product of 2 of //
6154// its 3 edge vectors. A better choice of two edge vectors will reduce the //
6155// numerical error during the calculation. Burdakov proved that the optimal //
6156// basis problem is equivalent to the minimum spanning tree problem with the //
6157// edge length be the functional, see Burdakov, "A greedy algorithm for the //
6158// optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
6159// short edges in abc are chosen for the calculation. //
6160// //
6161// If 'lav' is not NULL and if 'pivot' is set, the average edge length of //
6162// the edges of the face [a,b,c] is returned. //
6163// //
6164///////////////////////////////////////////////////////////////////////////////
6165
6166void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
6167 REAL* lav)
6168{
6169 REAL v1[3], v2[3], v3[3], *pv1, *pv2;
6170 REAL L1, L2, L3;
6171
6172 v1[0] = pb[0] - pa[0]; // edge vector v1: a->b
6173 v1[1] = pb[1] - pa[1];
6174 v1[2] = pb[2] - pa[2];
6175 v2[0] = pa[0] - pc[0]; // edge vector v2: c->a
6176 v2[1] = pa[1] - pc[1];
6177 v2[2] = pa[2] - pc[2];
6178
6179 // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
6180 if (pivot > 0) {
6181 // Choose edge vectors by Burdakov's algorithm.
6182 v3[0] = pc[0] - pb[0]; // edge vector v3: b->c
6183 v3[1] = pc[1] - pb[1];
6184 v3[2] = pc[2] - pb[2];
6185 L1 = dot(v1, v1);
6186 L2 = dot(v2, v2);
6187 L3 = dot(v3, v3);
6188 // Sort the three edge lengths.
6189 if (L1 < L2) {
6190 if (L2 < L3) {
6191 pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6192 } else {
6193 pv1 = v3; pv2 = v1; // n = v3 x (-v1).
6194 }
6195 } else {
6196 if (L1 < L3) {
6197 pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6198 } else {
6199 pv1 = v2; pv2 = v3; // n = v2 x (-v3).
6200 }
6201 }
6202 if (lav) {
6203 // return the average edge length.
6204 *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
6205 }
6206 } else {
6207 pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6208 }
6209
6210 // Calculate the face normal.
6211 cross(pv1, pv2, n);
6212 // Inverse the direction;
6213 n[0] = -n[0];
6214 n[1] = -n[1];
6215 n[2] = -n[2];
6216}
6217
6218///////////////////////////////////////////////////////////////////////////////
6219// //
6220// shortdistance() Returns the shortest distance from point p to a line //
6221// defined by two points e1 and e2. //
6222// //
6223// First compute the projection length l_p of the vector v1 = p - e1 along //
6224// the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
6225// shortest distance. //
6226// //
6227// This routine allows that p is collinear with the line. In this case, the //
6228// return value is zero. The two points e1 and e2 should not be identical. //
6229// //
6230///////////////////////////////////////////////////////////////////////////////
6231
6232REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
6233{
6234 REAL v1[3], v2[3];
6235 REAL len, l_p;
6236
6237 v1[0] = e2[0] - e1[0];
6238 v1[1] = e2[1] - e1[1];
6239 v1[2] = e2[2] - e1[2];
6240 v2[0] = p[0] - e1[0];
6241 v2[1] = p[1] - e1[1];
6242 v2[2] = p[2] - e1[2];
6243
6244 len = sqrt(dot(v1, v1));
6245 assert(len != 0.0);
6246
6247 v1[0] /= len;
6248 v1[1] /= len;
6249 v1[2] /= len;
6250 l_p = dot(v1, v2);
6251
6252 return sqrt(dot(v2, v2) - l_p * l_p);
6253}
6254
6255///////////////////////////////////////////////////////////////////////////////
6256// //
6257// triarea() Return the area of a triangle. //
6258// //
6259///////////////////////////////////////////////////////////////////////////////
6260
6261REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
6262{
6263 REAL A[4][4];
6264
6265 // Compute the coefficient matrix A (3x3).
6266 A[0][0] = pb[0] - pa[0];
6267 A[0][1] = pb[1] - pa[1];
6268 A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
6269 A[1][0] = pc[0] - pa[0];
6270 A[1][1] = pc[1] - pa[1];
6271 A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
6272
6273 cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
6274
6275 return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
6276}
6277
6278REAL tetgenmesh::orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
6279{
6280 REAL adx, bdx, cdx;
6281 REAL ady, bdy, cdy;
6282 REAL adz, bdz, cdz;
6283
6284 adx = pa[0] - pd[0];
6285 bdx = pb[0] - pd[0];
6286 cdx = pc[0] - pd[0];
6287 ady = pa[1] - pd[1];
6288 bdy = pb[1] - pd[1];
6289 cdy = pc[1] - pd[1];
6290 adz = pa[2] - pd[2];
6291 bdz = pb[2] - pd[2];
6292 cdz = pc[2] - pd[2];
6293
6294 return adx * (bdy * cdz - bdz * cdy)
6295 + bdx * (cdy * adz - cdz * ady)
6296 + cdx * (ady * bdz - adz * bdy);
6297}
6298
6299///////////////////////////////////////////////////////////////////////////////
6300// //
6301// interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
6302// o->p1 and o->p2. //
6303// //
6304// 'n' is the normal of the plane containing face (o, p1, p2). The interior //
6305// angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
6306// the position of p1 and p2 will get the complement angle of the other one. //
6307// i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
6308// 'n' be NULL if you only want the interior angle between 0 - PI. //
6309// //
6310///////////////////////////////////////////////////////////////////////////////
6311
6312REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
6313{
6314 REAL v1[3], v2[3], np[3];
6315 REAL theta, costheta, lenlen;
6316 REAL ori, len1, len2;
6317
6318 // Get the interior angle (0 - PI) between o->p1, and o->p2.
6319 v1[0] = p1[0] - o[0];
6320 v1[1] = p1[1] - o[1];
6321 v1[2] = p1[2] - o[2];
6322 v2[0] = p2[0] - o[0];
6323 v2[1] = p2[1] - o[1];
6324 v2[2] = p2[2] - o[2];
6325 len1 = sqrt(dot(v1, v1));
6326 len2 = sqrt(dot(v2, v2));
6327 lenlen = len1 * len2;
6328 assert(lenlen != 0.0);
6329
6330 costheta = dot(v1, v2) / lenlen;
6331 if (costheta > 1.0) {
6332 costheta = 1.0; // Roundoff.
6333 } else if (costheta < -1.0) {
6334 costheta = -1.0; // Roundoff.
6335 }
6336 theta = acos(costheta);
6337 if (n != NULL) {
6338 // Get a point above the face (o, p1, p2);
6339 np[0] = o[0] + n[0];
6340 np[1] = o[1] + n[1];
6341 np[2] = o[2] + n[2];
6342 // Adjust theta (0 - 2 * PI).
6343 ori = orient3d(p1, o, np, p2);
6344 if (ori > 0.0) {
6345 theta = 2 * PI - theta;
6346 }
6347 }
6348
6349 return theta;
6350}
6351
6352///////////////////////////////////////////////////////////////////////////////
6353// //
6354// projpt2edge() Return the projection point from a point to an edge. //
6355// //
6356///////////////////////////////////////////////////////////////////////////////
6357
6358void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
6359{
6360 REAL v1[3], v2[3];
6361 REAL len, l_p;
6362
6363 v1[0] = e2[0] - e1[0];
6364 v1[1] = e2[1] - e1[1];
6365 v1[2] = e2[2] - e1[2];
6366 v2[0] = p[0] - e1[0];
6367 v2[1] = p[1] - e1[1];
6368 v2[2] = p[2] - e1[2];
6369
6370 len = sqrt(dot(v1, v1));
6371 assert(len != 0.0);
6372 v1[0] /= len;
6373 v1[1] /= len;
6374 v1[2] /= len;
6375 l_p = dot(v1, v2);
6376
6377 prj[0] = e1[0] + l_p * v1[0];
6378 prj[1] = e1[1] + l_p * v1[1];
6379 prj[2] = e1[2] + l_p * v1[2];
6380}
6381
6382///////////////////////////////////////////////////////////////////////////////
6383// //
6384// projpt2face() Return the projection point from a point to a face. //
6385// //
6386///////////////////////////////////////////////////////////////////////////////
6387
6388void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
6389{
6390 REAL fnormal[3], v1[3];
6391 REAL len, dist;
6392
6393 // Get the unit face normal.
6394 facenormal(f1, f2, f3, fnormal, 1, NULL);
6395 len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] +
6396 fnormal[2]*fnormal[2]);
6397 fnormal[0] /= len;
6398 fnormal[1] /= len;
6399 fnormal[2] /= len;
6400 // Get the vector v1 = |p - f1|.
6401 v1[0] = p[0] - f1[0];
6402 v1[1] = p[1] - f1[1];
6403 v1[2] = p[2] - f1[2];
6404 // Get the project distance.
6405 dist = dot(fnormal, v1);
6406
6407 // Get the project point.
6408 prj[0] = p[0] - dist * fnormal[0];
6409 prj[1] = p[1] - dist * fnormal[1];
6410 prj[2] = p[2] - dist * fnormal[2];
6411}
6412
6413///////////////////////////////////////////////////////////////////////////////
6414// //
6415// facedihedral() Return the dihedral angle (in radian) between two //
6416// adjoining faces. //
6417// //
6418// 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are //
6419// apexes of these two faces. Return the angle (between 0 to 2*pi) between //
6420// the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). //
6421// //
6422///////////////////////////////////////////////////////////////////////////////
6423
6424REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
6425{
6426 REAL n1[3], n2[3];
6427 REAL n1len, n2len;
6428 REAL costheta, ori;
6429 REAL theta;
6430
6431 facenormal(pa, pb, pc1, n1, 1, NULL);
6432 facenormal(pa, pb, pc2, n2, 1, NULL);
6433 n1len = sqrt(dot(n1, n1));
6434 n2len = sqrt(dot(n2, n2));
6435 costheta = dot(n1, n2) / (n1len * n2len);
6436 // Be careful rounding error!
6437 if (costheta > 1.0) {
6438 costheta = 1.0;
6439 } else if (costheta < -1.0) {
6440 costheta = -1.0;
6441 }
6442 theta = acos(costheta);
6443 ori = orient3d(pa, pb, pc1, pc2);
6444 if (ori > 0.0) {
6445 theta = 2 * PI - theta;
6446 }
6447
6448 return theta;
6449}
6450
6451///////////////////////////////////////////////////////////////////////////////
6452// //
6453// tetalldihedral() Get all (six) dihedral angles of a tet. //
6454// //
6455// If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles, //
6456// the edge indices are given in the global array 'edge2ver'. If 'cosmaxd' //
6457// (or 'cosmind') is not NULL, it returns the cosine of the maximal (or //
6458// minimal) dihedral angle. //
6459// //
6460///////////////////////////////////////////////////////////////////////////////
6461
6462bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
6463 REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
6464{
6465 REAL N[4][3], vol, cosd, len;
6466 int f1 = 0, f2 = 0, i, j;
6467
6468 vol = 0; // Check if the tet is valid or not.
6469
6470 // Get four normals of faces of the tet.
6471 tetallnormal(pa, pb, pc, pd, N, &vol);
6472
6473 if (vol > 0) {
6474 // Normalize the normals.
6475 for (i = 0; i < 4; i++) {
6476 len = sqrt(dot(N[i], N[i]));
6477 if (len != 0.0) {
6478 for (j = 0; j < 3; j++) N[i][j] /= len;
6479 } else {
6480 // There are degeneracies, such as duplicated vertices.
6481 vol = 0; //assert(0);
6482 }
6483 }
6484 }
6485
6486 if (vol <= 0) { // if (vol == 0.0) {
6487 // A degenerated tet or an inverted tet.
6488 facenormal(pc, pb, pd, N[0], 1, NULL);
6489 facenormal(pa, pc, pd, N[1], 1, NULL);
6490 facenormal(pb, pa, pd, N[2], 1, NULL);
6491 facenormal(pa, pb, pc, N[3], 1, NULL);
6492 // Normalize the normals.
6493 for (i = 0; i < 4; i++) {
6494 len = sqrt(dot(N[i], N[i]));
6495 if (len != 0.0) {
6496 for (j = 0; j < 3; j++) N[i][j] /= len;
6497 } else {
6498 // There are degeneracies, such as duplicated vertices.
6499 break; // Not a valid normal.
6500 }
6501 }
6502 if (i < 4) {
6503 // Do not calculate dihedral angles.
6504 // Set all angles be 0 degree. There will be no quality optimization for
6505 // this tet! Use volume optimization to correct it.
6506 if (cosdd != NULL) {
6507 for (i = 0; i < 6; i++) {
6508 cosdd[i] = -1.0; // 180 degree.
6509 }
6510 }
6511 // This tet has zero volume.
6512 if (cosmaxd != NULL) {
6513 *cosmaxd = -1.0; // 180 degree.
6514 }
6515 if (cosmind != NULL) {
6516 *cosmind = -1.0; // 180 degree.
6517 }
6518 return false;
6519 }
6520 }
6521
6522 // Calculate the cosine of the dihedral angles of the edges.
6523 for (i = 0; i < 6; i++) {
6524 switch (i) {
6525 case 0: f1 = 0; f2 = 1; break; // [c,d].
6526 case 1: f1 = 1; f2 = 2; break; // [a,d].
6527 case 2: f1 = 2; f2 = 3; break; // [a,b].
6528 case 3: f1 = 0; f2 = 3; break; // [b,c].
6529 case 4: f1 = 2; f2 = 0; break; // [b,d].
6530 case 5: f1 = 1; f2 = 3; break; // [a,c].
6531 }
6532 cosd = -dot(N[f1], N[f2]);
6533 if (cosd < -1.0) cosd = -1.0; // Rounding.
6534 if (cosd > 1.0) cosd = 1.0; // Rounding.
6535 if (cosdd) cosdd[i] = cosd;
6536 if (cosmaxd || cosmind) {
6537 if (i == 0) {
6538 if (cosmaxd) *cosmaxd = cosd;
6539 if (cosmind) *cosmind = cosd;
6540 } else {
6541 if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
6542 if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
6543 }
6544 }
6545 }
6546
6547 return true;
6548}
6549
6550///////////////////////////////////////////////////////////////////////////////
6551// //
6552// tetallnormal() Get the in-normals of the four faces of a given tet. //
6553// //
6554// Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
6555// N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices //
6556// of the mesh data structure). These normals are unnormalized. //
6557// //
6558///////////////////////////////////////////////////////////////////////////////
6559
6560void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
6561 REAL N[4][3], REAL* volume)
6562{
6563 REAL A[4][4], rhs[4], D;
6564 int indx[4];
6565 int i, j;
6566
6567 // get the entries of A[3][3].
6568 for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
6569 for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
6570 for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
6571
6572 // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
6573 if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
6574 if (volume != NULL) {
6575 // Get the volume of the tet.
6576 *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
6577 }
6578 for (j = 0; j < 3; j++) {
6579 for (i = 0; i < 3; i++) rhs[i] = 0.0;
6580 rhs[j] = 1.0; // Positive means the inside direction
6581 lu_solve(A, 3, indx, rhs, 0);
6582 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6583 }
6584 // Get the fourth normal by summing up the first three.
6585 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6586 } else {
6587 // The tet is degenerated.
6588 if (volume != NULL) {
6589 *volume = 0;
6590 }
6591 }
6592}
6593
6594///////////////////////////////////////////////////////////////////////////////
6595// //
6596// tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
6597// //
6598// The aspect ratio of a tet is R/h, where R is the circumradius and h is //
6599// the shortest height of the tet. //
6600// //
6601///////////////////////////////////////////////////////////////////////////////
6602
6603REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
6604{
6605 REAL vda[3], vdb[3], vdc[3];
6606 REAL N[4][3], A[4][4], rhs[4], D;
6607 REAL H[4], volume, radius2, minheightinv;
6608 int indx[4];
6609 int i, j;
6610
6611 // Set the matrix A = [vda, vdb, vdc]^T.
6612 for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
6613 for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
6614 for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
6615 // Lu-decompose the matrix A.
6616 lu_decmp(A, 3, indx, &D, 0);
6617 // Get the volume of abcd.
6618 volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
6619 // Check if it is zero.
6620 if (volume == 0.0) return 1.0e+200; // A degenerate tet.
6621 // if (volume < 0.0) volume = -volume;
6622 // Check the radiu-edge ratio of the tet.
6623 rhs[0] = 0.5 * dot(vda, vda);
6624 rhs[1] = 0.5 * dot(vdb, vdb);
6625 rhs[2] = 0.5 * dot(vdc, vdc);
6626 lu_solve(A, 3, indx, rhs, 0);
6627 // Get the circumcenter.
6628 // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
6629 // Get the square of the circumradius.
6630 radius2 = dot(rhs, rhs);
6631
6632 // Compute the 4 face normals (N[0], ..., N[3]).
6633 for (j = 0; j < 3; j++) {
6634 for (i = 0; i < 3; i++) rhs[i] = 0.0;
6635 rhs[j] = 1.0; // Positive means the inside direction
6636 lu_solve(A, 3, indx, rhs, 0);
6637 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6638 }
6639 // Get the fourth normal by summing up the first three.
6640 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6641 // Normalized the normals.
6642 for (i = 0; i < 4; i++) {
6643 // H[i] is the inverse of the height of its corresponding face.
6644 H[i] = sqrt(dot(N[i], N[i]));
6645 // if (H[i] > 0.0) {
6646 // for (j = 0; j < 3; j++) N[i][j] /= H[i];
6647 // }
6648 }
6649 // Get the radius of the inscribed sphere.
6650 // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
6651 // Get the biggest H[i] (corresponding to the smallest height).
6652 minheightinv = H[0];
6653 for (i = 1; i < 3; i++) {
6654 if (H[i] > minheightinv) minheightinv = H[i];
6655 }
6656
6657 return sqrt(radius2) * minheightinv;
6658}
6659
6660///////////////////////////////////////////////////////////////////////////////
6661// //
6662// circumsphere() Calculate the smallest circumsphere (center and radius) //
6663// of the given three or four points. //
6664// //
6665// The circumsphere of four points (a tetrahedron) is unique if they are not //
6666// degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
6667// the diametral sphere of the triangle if they are not degenerate. //
6668// //
6669// Return TRUE if the input points are not degenerate and the circumcenter //
6670// and circumradius are returned in 'cent' and 'radius' respectively if they //
6671// are not NULLs. Otherwise, return FALSE, the four points are co-planar. //
6672// //
6673///////////////////////////////////////////////////////////////////////////////
6674
6675bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6676 REAL* cent, REAL* radius)
6677{
6678 REAL A[4][4], rhs[4], D;
6679 int indx[4];
6680
6681 // Compute the coefficient matrix A (3x3).
6682 A[0][0] = pb[0] - pa[0];
6683 A[0][1] = pb[1] - pa[1];
6684 A[0][2] = pb[2] - pa[2];
6685 A[1][0] = pc[0] - pa[0];
6686 A[1][1] = pc[1] - pa[1];
6687 A[1][2] = pc[2] - pa[2];
6688 if (pd != NULL) {
6689 A[2][0] = pd[0] - pa[0];
6690 A[2][1] = pd[1] - pa[1];
6691 A[2][2] = pd[2] - pa[2];
6692 } else {
6693 cross(A[0], A[1], A[2]);
6694 }
6695
6696 // Compute the right hand side vector b (3x1).
6697 rhs[0] = 0.5 * dot(A[0], A[0]);
6698 rhs[1] = 0.5 * dot(A[1], A[1]);
6699 if (pd != NULL) {
6700 rhs[2] = 0.5 * dot(A[2], A[2]);
6701 } else {
6702 rhs[2] = 0.0;
6703 }
6704
6705 // Solve the 3 by 3 equations use LU decomposition with partial pivoting
6706 // and backward and forward substitute..
6707 if (!lu_decmp(A, 3, indx, &D, 0)) {
6708 if (radius != (REAL *) NULL) *radius = 0.0;
6709 return false;
6710 }
6711 lu_solve(A, 3, indx, rhs, 0);
6712 if (cent != (REAL *) NULL) {
6713 cent[0] = pa[0] + rhs[0];
6714 cent[1] = pa[1] + rhs[1];
6715 cent[2] = pa[2] + rhs[2];
6716 }
6717 if (radius != (REAL *) NULL) {
6718 *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
6719 }
6720 return true;
6721}
6722
6723///////////////////////////////////////////////////////////////////////////////
6724// //
6725// orthosphere() Calulcate the orthosphere of four weighted points. //
6726// //
6727// A weighted point (p, P^2) can be interpreted as a sphere centered at the //
6728// point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 + //
6729// p[1]^2 + p[2]^2 - P^2. //
6730// //
6731///////////////////////////////////////////////////////////////////////////////
6732
6733bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6734 REAL aheight, REAL bheight, REAL cheight,
6735 REAL dheight, REAL* orthocent, REAL* radius)
6736{
6737 REAL A[4][4], rhs[4], D;
6738 int indx[4];
6739
6740 // Set the coefficient matrix A (4 x 4).
6741 A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
6742 A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
6743 A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
6744 A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
6745
6746 // Set the right hand side vector (4 x 1).
6747 rhs[0] = 0.5 * aheight;
6748 rhs[1] = 0.5 * bheight;
6749 rhs[2] = 0.5 * cheight;
6750 rhs[3] = 0.5 * dheight;
6751
6752 // Solve the 4 by 4 equations use LU decomposition with partial pivoting
6753 // and backward and forward substitute..
6754 if (!lu_decmp(A, 4, indx, &D, 0)) {
6755 if (radius != (REAL *) NULL) *radius = 0.0;
6756 return false;
6757 }
6758 lu_solve(A, 4, indx, rhs, 0);
6759
6760 if (orthocent != (REAL *) NULL) {
6761 orthocent[0] = rhs[1];
6762 orthocent[1] = rhs[2];
6763 orthocent[2] = rhs[3];
6764 }
6765 if (radius != (REAL *) NULL) {
6766 // rhs[0] = - rheight / 2;
6767 // rheight = - 2 * rhs[0];
6768 // = r[0]^2 + r[1]^2 + r[2]^2 - radius^2
6769 // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
6770 // = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
6771 *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
6772 + 2.0 * rhs[0]);
6773 }
6774 return true;
6775}
6776
6777///////////////////////////////////////////////////////////////////////////////
6778// //
6779// planelineint() Calculate the intersection of a line and a plane. //
6780// //
6781// The equation of a plane (points P are on the plane with normal N and P3 //
6782// on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
6783// line (points P on the line passing through P1 and P2) can be written as: //
6784// P = P1 + u (P2 - P1). The intersection of these two occurs when: //
6785// N dot (P1 + u (P2 - P1)) = N dot P3. //
6786// Solving for u gives: //
6787// N dot (P3 - P1) //
6788// u = ------------------. //
6789// N dot (P2 - P1) //
6790// If the denominator is 0 then N (the normal to the plane) is perpendicular //
6791// to the line. Thus the line is either parallel to the plane and there are //
6792// no solutions or the line is on the plane in which case there are an infi- //
6793// nite number of solutions. //
6794// //
6795// The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
6796// line. If u is non-zero, The intersection point (if exists) returns in ip. //
6797// //
6798///////////////////////////////////////////////////////////////////////////////
6799
6800void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
6801 REAL* ip, REAL* u)
6802{
6803 REAL n[3], det, det1;
6804
6805 // Calculate N.
6806 facenormal(pa, pb, pc, n, 1, NULL);
6807 // Calculate N dot (e2 - e1).
6808 det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
6809 + n[2] * (e2[2] - e1[2]);
6810 if (det != 0.0) {
6811 // Calculate N dot (pa - e1)
6812 det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
6813 + n[2] * (pa[2] - e1[2]);
6814 *u = det1 / det;
6815 ip[0] = e1[0] + *u * (e2[0] - e1[0]);
6816 ip[1] = e1[1] + *u * (e2[1] - e1[1]);
6817 ip[2] = e1[2] + *u * (e2[2] - e1[2]);
6818 } else {
6819 *u = 0.0;
6820 }
6821}
6822
6823///////////////////////////////////////////////////////////////////////////////
6824// //
6825// linelineint() Calculate the intersection(s) of two line segments. //
6826// //
6827// Calculate the line segment [P, Q] that is the shortest route between two //
6828// lines from A to B and C to D. Calculate also the values of tp and tq //
6829// where: P = A + tp (B - A), and Q = C + tq (D - C). //
6830// //
6831// Return 1 if the line segment exists. Otherwise, return 0. //
6832// //
6833///////////////////////////////////////////////////////////////////////////////
6834
6835int tetgenmesh::linelineint(REAL* A, REAL* B, REAL* C, REAL* D, REAL* P,
6836 REAL* Q, REAL* tp, REAL* tq)
6837{
6838 REAL vab[3], vcd[3], vca[3];
6839 REAL vab_vab, vcd_vcd, vab_vcd;
6840 REAL vca_vab, vca_vcd;
6841 REAL det, eps;
6842 int i;
6843
6844 for (i = 0; i < 3; i++) {
6845 vab[i] = B[i] - A[i];
6846 vcd[i] = D[i] - C[i];
6847 vca[i] = A[i] - C[i];
6848 }
6849
6850 vab_vab = dot(vab, vab);
6851 vcd_vcd = dot(vcd, vcd);
6852 vab_vcd = dot(vab, vcd);
6853
6854 det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
6855 // Round the result.
6856 eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
6857 if (eps < b->epsilon) {
6858 return 0;
6859 }
6860
6861 vca_vab = dot(vca, vab);
6862 vca_vcd = dot(vca, vcd);
6863
6864 *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
6865 *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
6866
6867 for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
6868 for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
6869
6870 return 1;
6871}
6872
6873///////////////////////////////////////////////////////////////////////////////
6874// //
6875// tetprismvol() Calculate the volume of a tetrahedral prism in 4D. //
6876// //
6877// A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
6878// tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular //
6879// prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
6880// vertices. (Wikipedia). //
6881// //
6882// Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
6883// the lower tetrahedral facet of the prism. The top tetrahedral facet is //
6884// formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by //
6885// lifting each vertex of the lower facet into R^4 by a weight (height). A //
6886// canonical choice of the weights is the square of Euclidean norm of of the //
6887// points (vectors). //
6888// //
6889// //
6890// The return value is (4!) 24 times of the volume of the tetrahedral prism. //
6891// //
6892///////////////////////////////////////////////////////////////////////////////
6893
6894REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
6895{
6896 REAL *p4, *p5, *p6, *p7;
6897 REAL w4, w5, w6, w7;
6898 REAL vol[4];
6899
6900 p4 = p0;
6901 p5 = p1;
6902 p6 = p2;
6903 p7 = p3;
6904
6905 // TO DO: these weights can be pre-calculated!
6906 w4 = dot(p0, p0);
6907 w5 = dot(p1, p1);
6908 w6 = dot(p2, p2);
6909 w7 = dot(p3, p3);
6910
6911 // Calculate the volume of the tet-prism.
6912 vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
6913 vol[1] = orient4d(p3, p6, p2, p0, p1, 0, w6, 0, 0, 0);
6914 vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6, 0, 0, 0);
6915 vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0, 0);
6916
6917 return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
6918}
6919
6920///////////////////////////////////////////////////////////////////////////////
6921// //
6922// calculateabovepoint() Calculate a point above a facet in 'dummypoint'. //
6923// //
6924///////////////////////////////////////////////////////////////////////////////
6925
6926bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
6927 point *ppb, point *ppc)
6928{
6929 point *ppt, pa, pb, pc;
6930 REAL v1[3], v2[3], n[3];
6931 REAL lab, len, A, area;
6932 REAL x, y, z;
6933 int i;
6934
6935 ppt = (point *) fastlookup(facpoints, 0);
6936 pa = *ppt; // a is the first point.
6937 pb = pc = NULL; // Avoid compiler warnings.
6938
6939 // Get a point b s.t. the length of [a, b] is maximal.
6940 lab = 0;
6941 for (i = 1; i < facpoints->objects; i++) {
6942 ppt = (point *) fastlookup(facpoints, i);
6943 x = (*ppt)[0] - pa[0];
6944 y = (*ppt)[1] - pa[1];
6945 z = (*ppt)[2] - pa[2];
6946 len = x * x + y * y + z * z;
6947 if (len > lab) {
6948 lab = len;
6949 pb = *ppt;
6950 }
6951 }
6952 lab = sqrt(lab);
6953 if (lab == 0) {
6954 if (!b->quiet) {
6955 printf("Warning: All points of a facet are coincident with %d.\n",
6956 pointmark(pa));
6957 }
6958 return false;
6959 }
6960
6961 // Get a point c s.t. the area of [a, b, c] is maximal.
6962 v1[0] = pb[0] - pa[0];
6963 v1[1] = pb[1] - pa[1];
6964 v1[2] = pb[2] - pa[2];
6965 A = 0;
6966 for (i = 1; i < facpoints->objects; i++) {
6967 ppt = (point *) fastlookup(facpoints, i);
6968 v2[0] = (*ppt)[0] - pa[0];
6969 v2[1] = (*ppt)[1] - pa[1];
6970 v2[2] = (*ppt)[2] - pa[2];
6971 cross(v1, v2, n);
6972 area = dot(n, n);
6973 if (area > A) {
6974 A = area;
6975 pc = *ppt;
6976 }
6977 }
6978 if (A == 0) {
6979 // All points are collinear. No above point.
6980 if (!b->quiet) {
6981 printf("Warning: All points of a facet are collinaer with [%d, %d].\n",
6982 pointmark(pa), pointmark(pb));
6983 }
6984 return false;
6985 }
6986
6987 // Calculate an above point of this facet.
6988 facenormal(pa, pb, pc, n, 1, NULL);
6989 len = sqrt(dot(n, n));
6990 n[0] /= len;
6991 n[1] /= len;
6992 n[2] /= len;
6993 lab /= 2.0; // Half the maximal length.
6994 dummypoint[0] = pa[0] + lab * n[0];
6995 dummypoint[1] = pa[1] + lab * n[1];
6996 dummypoint[2] = pa[2] + lab * n[2];
6997
6998 if (ppa != NULL) {
6999 // Return the three points.
7000 *ppa = pa;
7001 *ppb = pb;
7002 *ppc = pc;
7003 }
7004
7005 return true;
7006}
7007
7008///////////////////////////////////////////////////////////////////////////////
7009// //
7010// Calculate an above point. It lies above the plane containing the subface //
7011// [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
7012// is the normal of the plane. //
7013// //
7014///////////////////////////////////////////////////////////////////////////////
7015
7016void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
7017{
7018 REAL n1[3], n2[3], *norm;
7019 REAL len, len1, len2;
7020
7021 // Select a base.
7022 facenormal(pa, pb, pc, n1, 1, NULL);
7023 len1 = sqrt(dot(n1, n1));
7024 facenormal(pa, pb, pd, n2, 1, NULL);
7025 len2 = sqrt(dot(n2, n2));
7026 if (len1 > len2) {
7027 norm = n1;
7028 len = len1;
7029 } else {
7030 norm = n2;
7031 len = len2;
7032 }
7033 assert(len > 0);
7034 norm[0] /= len;
7035 norm[1] /= len;
7036 norm[2] /= len;
7037 len = distance(pa, pb);
7038 dummypoint[0] = pa[0] + len * norm[0];
7039 dummypoint[1] = pa[1] + len * norm[1];
7040 dummypoint[2] = pa[2] + len * norm[2];
7041}
7042
7043//// ////
7044//// ////
7045//// geom_cxx /////////////////////////////////////////////////////////////////
7046
7047//// flip_cxx /////////////////////////////////////////////////////////////////
7048//// ////
7049//// ////
7050
7051///////////////////////////////////////////////////////////////////////////////
7052// //
7053// flip23() Perform a 2-to-3 flip (face-to-edge flip). //
7054// //
7055// 'fliptets' is an array of three tets (handles), where the [0] and [1] are //
7056// [a,b,c,d] and [b,a,c,e]. The three new tets: [e,d,a,b], [e,d,b,c], and //
7057// [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'. As a result, //
7058// The face [a,b,c] is removed, and the edge [d,e] is created. //
7059// //
7060// If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
7061// the five vertices may be 'dummypoint'. There are two canonical cases: //
7062// (1) d is 'dummypoint', then all three new tets are hull tets. If e is //
7063// 'dummypoint', we reconfigure e to d, i.e., turn it up-side down. //
7064// (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are //
7065// hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
7066// rotate the three input tets counterclockwisely (right-hand rule) //
7067// until a or b is in c's position. //
7068// //
7069// If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
7070// In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
7071// after the insertion of a new point. It is assumed that 'd' is the new //
7072// point. IN this case, only link faces of 'd' are queued. //
7073// //
7074///////////////////////////////////////////////////////////////////////////////
7075
7076void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
7077{
7078 triface topcastets[3], botcastets[3];
7079 triface newface, casface;
7080 point pa, pb, pc, pd, pe;
7081 REAL attrib, volume;
7082 int dummyflag = 0; // range = {-1, 0, 1, 2}.
7083 int i;
7084
7085 if (hullflag > 0) {
7086 // Check if e is dummypoint.
7087 if (oppo(fliptets[1]) == dummypoint) {
7088 // Swap the two old tets.
7089 newface = fliptets[0];
7090 fliptets[0] = fliptets[1];
7091 fliptets[1] = newface;
7092 dummyflag = -1; // d is dummypoint.
7093 } else {
7094 // Check if either a or b is dummypoint.
7095 if (org(fliptets[0]) == dummypoint) {
7096 dummyflag = 1; // a is dummypoint.
7097 enextself(fliptets[0]);
7098 eprevself(fliptets[1]);
7099 } else if (dest(fliptets[0]) == dummypoint) {
7100 dummyflag = 2; // b is dummypoint.
7101 eprevself(fliptets[0]);
7102 enextself(fliptets[1]);
7103 } else {
7104 dummyflag = 0; // either c or d may be dummypoint.
7105 }
7106 }
7107 }
7108
7109 pa = org(fliptets[0]);
7110 pb = dest(fliptets[0]);
7111 pc = apex(fliptets[0]);
7112 pd = oppo(fliptets[0]);
7113 pe = oppo(fliptets[1]);
7114
7115 flip23count++;
7116
7117 // Get the outer boundary faces.
7118 for (i = 0; i < 3; i++) {
7119 fnext(fliptets[0], topcastets[i]);
7120 enextself(fliptets[0]);
7121 }
7122 for (i = 0; i < 3; i++) {
7123 fnext(fliptets[1], botcastets[i]);
7124 eprevself(fliptets[1]);
7125 }
7126
7127 // Re-use fliptets[0] and fliptets[1].
7128 fliptets[0].ver = 11;
7129 fliptets[1].ver = 11;
7130 setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7131 setelemmarker(fliptets[1].tet, 0);
7132 // NOTE: the element attributes and volume constraint remain unchanged.
7133 if (checksubsegflag) {
7134 // Dealloc the space to subsegments.
7135 if (fliptets[0].tet[8] != NULL) {
7136 tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7137 fliptets[0].tet[8] = NULL;
7138 }
7139 if (fliptets[1].tet[8] != NULL) {
7140 tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7141 fliptets[1].tet[8] = NULL;
7142 }
7143 }
7144 if (checksubfaceflag) {
7145 // Dealloc the space to subfaces.
7146 if (fliptets[0].tet[9] != NULL) {
7147 tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7148 fliptets[0].tet[9] = NULL;
7149 }
7150 if (fliptets[1].tet[9] != NULL) {
7151 tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7152 fliptets[1].tet[9] = NULL;
7153 }
7154 }
7155 // Create a new tet.
7156 maketetrahedron(&(fliptets[2]));
7157 // The new tet have the same attributes from the old tet.
7158 for (i = 0; i < numelemattrib; i++) {
7159 attrib = elemattribute(fliptets[0].tet, i);
7160 setelemattribute(fliptets[2].tet, i, attrib);
7161 }
7162 if (b->varvolume) {
7163 volume = volumebound(fliptets[0].tet);
7164 setvolumebound(fliptets[2].tet, volume);
7165 }
7166
7167 if (hullflag > 0) {
7168 // Check if d is dummytet.
7169 if (pd != dummypoint) {
7170 setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7171 setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7172 // Check if c is dummypoint.
7173 if (pc != dummypoint) {
7174 setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7175 } else {
7176 setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
7177 esymself(fliptets[2]); // [e,d,c,a] *
7178 }
7179 // The hullsize does not change.
7180 } else {
7181 // d is dummypoint.
7182 setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
7183 setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
7184 setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
7185 // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
7186 for (i = 0; i < 3; i++) {
7187 eprevesymself(fliptets[i]);
7188 enextself(fliptets[i]);
7189 }
7190 // We deleted one hull tet, and created three hull tets.
7191 hullsize += 2;
7192 }
7193 } else {
7194 setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7195 setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7196 setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7197 }
7198
7199 if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7200 REAL volneg[2], volpos[3], vol_diff;
7201 if (pd != dummypoint) {
7202 if (pc != dummypoint) {
7203 volpos[0] = tetprismvol(pe, pd, pa, pb);
7204 volpos[1] = tetprismvol(pe, pd, pb, pc);
7205 volpos[2] = tetprismvol(pe, pd, pc, pa);
7206 volneg[0] = tetprismvol(pa, pb, pc, pd);
7207 volneg[1] = tetprismvol(pb, pa, pc, pe);
7208 } else { // pc == dummypoint
7209 volpos[0] = tetprismvol(pe, pd, pa, pb);
7210 volpos[1] = 0.;
7211 volpos[2] = 0.;
7212 volneg[0] = 0.;
7213 volneg[1] = 0.;
7214 }
7215 } else { // pd == dummypoint.
7216 volpos[0] = 0.;
7217 volpos[1] = 0.;
7218 volpos[2] = 0.;
7219 volneg[0] = 0.;
7220 volneg[1] = tetprismvol(pb, pa, pc, pe);
7221 }
7222 vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
7223 fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7224 }
7225
7226 // Bond three new tets together.
7227 for (i = 0; i < 3; i++) {
7228 esym(fliptets[i], newface);
7229 bond(newface, fliptets[(i + 1) % 3]);
7230 }
7231 // Bond to top outer boundary faces (at [a,b,c,d]).
7232 for (i = 0; i < 3; i++) {
7233 eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
7234 bond(newface, topcastets[i]);
7235 }
7236 // Bond bottom outer boundary faces (at [b,a,c,e]).
7237 for (i = 0; i < 3; i++) {
7238 edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
7239 bond(newface, botcastets[i]);
7240 }
7241
7242 if (checksubsegflag) {
7243 // Bond subsegments if there are.
7244 // Each new tet has 5 edges to be checked (except the edge [e,d]).
7245 face checkseg;
7246 // The middle three: [a,b], [b,c], [c,a].
7247 for (i = 0; i < 3; i++) {
7248 if (issubseg(topcastets[i])) {
7249 tsspivot1(topcastets[i], checkseg);
7250 eorgoppo(fliptets[i], newface);
7251 tssbond1(newface, checkseg);
7252 sstbond1(checkseg, newface);
7253 if (fc->chkencflag & 1) {
7254 enqueuesubface(badsubsegs, &checkseg);
7255 }
7256 }
7257 }
7258 // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
7259 for (i = 0; i < 3; i++) {
7260 eprev(topcastets[i], casface);
7261 if (issubseg(casface)) {
7262 tsspivot1(casface, checkseg);
7263 enext(fliptets[i], newface);
7264 tssbond1(newface, checkseg);
7265 sstbond1(checkseg, newface);
7266 esym(fliptets[(i + 2) % 3], newface);
7267 eprevself(newface);
7268 tssbond1(newface, checkseg);
7269 sstbond1(checkseg, newface);
7270 if (fc->chkencflag & 1) {
7271 enqueuesubface(badsubsegs, &checkseg);
7272 }
7273 }
7274 }
7275 // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
7276 for (i = 0; i < 3; i++) {
7277 enext(botcastets[i], casface);
7278 if (issubseg(casface)) {
7279 tsspivot1(casface, checkseg);
7280 eprev(fliptets[i], newface);
7281 tssbond1(newface, checkseg);
7282 sstbond1(checkseg, newface);
7283 esym(fliptets[(i + 2) % 3], newface);
7284 enextself(newface);
7285 tssbond1(newface, checkseg);
7286 sstbond1(checkseg, newface);
7287 if (fc->chkencflag & 1) {
7288 enqueuesubface(badsubsegs, &checkseg);
7289 }
7290 }
7291 }
7292 } // if (checksubsegflag)
7293
7294 if (checksubfaceflag) {
7295 // Bond 6 subfaces if there are.
7296 face checksh;
7297 for (i = 0; i < 3; i++) {
7298 if (issubface(topcastets[i])) {
7299 tspivot(topcastets[i], checksh);
7300 eorgoppo(fliptets[i], newface);
7301 sesymself(checksh);
7302 tsbond(newface, checksh);
7303 if (fc->chkencflag & 2) {
7304 enqueuesubface(badsubfacs, &checksh);
7305 }
7306 }
7307 }
7308 for (i = 0; i < 3; i++) {
7309 if (issubface(botcastets[i])) {
7310 tspivot(botcastets[i], checksh);
7311 edestoppo(fliptets[i], newface);
7312 sesymself(checksh);
7313 tsbond(newface, checksh);
7314 if (fc->chkencflag & 2) {
7315 enqueuesubface(badsubfacs, &checksh);
7316 }
7317 }
7318 }
7319 } // if (checksubfaceflag)
7320
7321 if (fc->chkencflag & 4) {
7322 // Put three new tets into check list.
7323 for (i = 0; i < 3; i++) {
7324 enqueuetetrahedron(&(fliptets[i]));
7325 }
7326 }
7327
7328 // Update the point-to-tet map.
7329 setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
7330 setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
7331 setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
7332 setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
7333 setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
7334
7335 if (hullflag > 0) {
7336 if (dummyflag != 0) {
7337 // Restore the original position of the points (for flipnm()).
7338 if (dummyflag == -1) {
7339 // Reverse the edge.
7340 for (i = 0; i < 3; i++) {
7341 esymself(fliptets[i]);
7342 }
7343 // Swap the last two new tets.
7344 newface = fliptets[1];
7345 fliptets[1] = fliptets[2];
7346 fliptets[2] = newface;
7347 } else {
7348 // either a or b were swapped.
7349 if (dummyflag == 1) {
7350 // a is dummypoint.
7351 newface = fliptets[0];
7352 fliptets[0] = fliptets[2];
7353 fliptets[2] = fliptets[1];
7354 fliptets[1] = newface;
7355 } else { // dummyflag == 2
7356 // b is dummypoint.
7357 newface = fliptets[0];
7358 fliptets[0] = fliptets[1];
7359 fliptets[1] = fliptets[2];
7360 fliptets[2] = newface;
7361 }
7362 }
7363 }
7364 }
7365
7366 if (fc->enqflag > 0) {
7367 // Queue faces which may be locally non-Delaunay.
7368 for (i = 0; i < 3; i++) {
7369 eprevesym(fliptets[i], newface);
7370 flippush(flipstack, &newface);
7371 }
7372 if (fc->enqflag > 1) {
7373 for (i = 0; i < 3; i++) {
7374 enextesym(fliptets[i], newface);
7375 flippush(flipstack, &newface);
7376 }
7377 }
7378 }
7379
7380 recenttet = fliptets[0];
7381}
7382
7383///////////////////////////////////////////////////////////////////////////////
7384// //
7385// flip32() Perform a 3-to-2 flip (edge-to-face flip). //
7386// //
7387// 'fliptets' is an array of three tets (handles), which are [e,d,a,b], //
7388// [e,d,b,c], and [e,d,c,a]. The two new tets: [a,b,c,d] and [b,a,c,e] are //
7389// returned in [0] and [1] of 'fliptets'. As a result, the edge [e,d] is //
7390// replaced by the face [a,b,c]. //
7391// //
7392// If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
7393// the five vertices may be 'dummypoint'. There are two canonical cases: //
7394// (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
7395// we reconfigure e to d, i.e., turnover it. //
7396// (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets. //
7397// If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
7398// three old tets counterclockwisely (right-hand rule) until a or b //
7399// is in c's position. //
7400// //
7401// If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
7402// In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
7403// after the insertion of a new point. It is assumed that 'a' is the new //
7404// point. In this case, only link faces of 'a' are queued. //
7405// //
7406// If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a //
7407// segment. There may be two (interior) subfaces sharing at [e,d], which are //
7408// [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c), //
7409// or (c,a) In such case, a 2-to-2 flip is performed on these two subfaces //
7410// and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted //
7411// back into the tetrahedralization. //
7412// //
7413///////////////////////////////////////////////////////////////////////////////
7414
7415void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
7416{
7417 triface topcastets[3], botcastets[3];
7418 triface newface, casface;
7419 face flipshs[3];
7420 face checkseg;
7421 point pa, pb, pc, pd, pe;
7422 REAL attrib, volume;
7423 int dummyflag = 0; // Rangle = {-1, 0, 1, 2}
7424 int spivot = -1, scount = 0; // for flip22()
7425 int t1ver;
7426 int i, j;
7427
7428 if (hullflag > 0) {
7429 // Check if e is 'dummypoint'.
7430 if (org(fliptets[0]) == dummypoint) {
7431 // Reverse the edge.
7432 for (i = 0; i < 3; i++) {
7433 esymself(fliptets[i]);
7434 }
7435 // Swap the last two tets.
7436 newface = fliptets[1];
7437 fliptets[1] = fliptets[2];
7438 fliptets[2] = newface;
7439 dummyflag = -1; // e is dummypoint.
7440 } else {
7441 // Check if a or b is the 'dummypoint'.
7442 if (apex(fliptets[0]) == dummypoint) {
7443 dummyflag = 1; // a is dummypoint.
7444 newface = fliptets[0];
7445 fliptets[0] = fliptets[1];
7446 fliptets[1] = fliptets[2];
7447 fliptets[2] = newface;
7448 } else if (apex(fliptets[1]) == dummypoint) {
7449 dummyflag = 2; // b is dummypoint.
7450 newface = fliptets[0];
7451 fliptets[0] = fliptets[2];
7452 fliptets[2] = fliptets[1];
7453 fliptets[1] = newface;
7454 } else {
7455 dummyflag = 0; // either c or d may be dummypoint.
7456 }
7457 }
7458 }
7459
7460 pa = apex(fliptets[0]);
7461 pb = apex(fliptets[1]);
7462 pc = apex(fliptets[2]);
7463 pd = dest(fliptets[0]);
7464 pe = org(fliptets[0]);
7465
7466 flip32count++;
7467
7468 // Get the outer boundary faces.
7469 for (i = 0; i < 3; i++) {
7470 eorgoppo(fliptets[i], casface);
7471 fsym(casface, topcastets[i]);
7472 }
7473 for (i = 0; i < 3; i++) {
7474 edestoppo(fliptets[i], casface);
7475 fsym(casface, botcastets[i]);
7476 }
7477
7478 if (checksubfaceflag) {
7479 // Check if there are interior subfaces at the edge [e,d].
7480 for (i = 0; i < 3; i++) {
7481 tspivot(fliptets[i], flipshs[i]);
7482 if (flipshs[i].sh != NULL) {
7483 // Found an interior subface.
7484 stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
7485 scount++;
7486 } else {
7487 spivot = i;
7488 }
7489 }
7490 }
7491
7492 // Re-use fliptets[0] and fliptets[1].
7493 fliptets[0].ver = 11;
7494 fliptets[1].ver = 11;
7495 setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7496 setelemmarker(fliptets[1].tet, 0);
7497 if (checksubsegflag) {
7498 // Dealloc the space to subsegments.
7499 if (fliptets[0].tet[8] != NULL) {
7500 tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7501 fliptets[0].tet[8] = NULL;
7502 }
7503 if (fliptets[1].tet[8] != NULL) {
7504 tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7505 fliptets[1].tet[8] = NULL;
7506 }
7507 }
7508 if (checksubfaceflag) {
7509 // Dealloc the space to subfaces.
7510 if (fliptets[0].tet[9] != NULL) {
7511 tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7512 fliptets[0].tet[9] = NULL;
7513 }
7514 if (fliptets[1].tet[9] != NULL) {
7515 tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7516 fliptets[1].tet[9] = NULL;
7517 }
7518 }
7519 if (checksubfaceflag) {
7520 if (scount > 0) {
7521 // The element attributes and volume constraint must be set correctly.
7522 // There are two subfaces involved in this flip. The three tets are
7523 // separated into two different regions, one may be exterior. The
7524 // first region has two tets, and the second region has only one.
7525 // The two created tets must be in the same region as the first region.
7526 // The element attributes and volume constraint must be set correctly.
7527 //assert(spivot != -1);
7528 // The tet fliptets[spivot] is in the first region.
7529 for (j = 0; j < 2; j++) {
7530 for (i = 0; i < numelemattrib; i++) {
7531 attrib = elemattribute(fliptets[spivot].tet, i);
7532 setelemattribute(fliptets[j].tet, i, attrib);
7533 }
7534 if (b->varvolume) {
7535 volume = volumebound(fliptets[spivot].tet);
7536 setvolumebound(fliptets[j].tet, volume);
7537 }
7538 }
7539 }
7540 }
7541 // Delete an old tet.
7542 tetrahedrondealloc(fliptets[2].tet);
7543
7544 if (hullflag > 0) {
7545 // Check if c is dummypointc.
7546 if (pc != dummypoint) {
7547 // Check if d is dummypoint.
7548 if (pd != dummypoint) {
7549 // No hull tet is involved.
7550 } else {
7551 // We deleted three hull tets, and created one hull tet.
7552 hullsize -= 2;
7553 }
7554 setvertices(fliptets[0], pa, pb, pc, pd);
7555 setvertices(fliptets[1], pb, pa, pc, pe);
7556 } else {
7557 // c is dummypoint. The two new tets are hull tets.
7558 setvertices(fliptets[0], pb, pa, pd, pc);
7559 setvertices(fliptets[1], pa, pb, pe, pc);
7560 // Adjust badc -> abcd.
7561 esymself(fliptets[0]);
7562 // Adjust abec -> bace.
7563 esymself(fliptets[1]);
7564 // The hullsize does not change.
7565 }
7566 } else {
7567 setvertices(fliptets[0], pa, pb, pc, pd);
7568 setvertices(fliptets[1], pb, pa, pc, pe);
7569 }
7570
7571 if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7572 REAL volneg[3], volpos[2], vol_diff;
7573 if (pc != dummypoint) {
7574 if (pd != dummypoint) {
7575 volneg[0] = tetprismvol(pe, pd, pa, pb);
7576 volneg[1] = tetprismvol(pe, pd, pb, pc);
7577 volneg[2] = tetprismvol(pe, pd, pc, pa);
7578 volpos[0] = tetprismvol(pa, pb, pc, pd);
7579 volpos[1] = tetprismvol(pb, pa, pc, pe);
7580 } else { // pd == dummypoint
7581 volneg[0] = 0.;
7582 volneg[1] = 0.;
7583 volneg[2] = 0.;
7584 volpos[0] = 0.;
7585 volpos[1] = tetprismvol(pb, pa, pc, pe);
7586 }
7587 } else { // pc == dummypoint.
7588 volneg[0] = tetprismvol(pe, pd, pa, pb);
7589 volneg[1] = 0.;
7590 volneg[2] = 0.;
7591 volpos[0] = 0.;
7592 volpos[1] = 0.;
7593 }
7594 vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
7595 fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7596 }
7597
7598 // Bond abcd <==> bace.
7599 bond(fliptets[0], fliptets[1]);
7600 // Bond new faces to top outer boundary faces (at abcd).
7601 for (i = 0; i < 3; i++) {
7602 esym(fliptets[0], newface);
7603 bond(newface, topcastets[i]);
7604 enextself(fliptets[0]);
7605 }
7606 // Bond new faces to bottom outer boundary faces (at bace).
7607 for (i = 0; i < 3; i++) {
7608 esym(fliptets[1], newface);
7609 bond(newface, botcastets[i]);
7610 eprevself(fliptets[1]);
7611 }
7612
7613 if (checksubsegflag) {
7614 // Bond 9 segments to new (flipped) tets.
7615 for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.
7616 if (issubseg(topcastets[i])) {
7617 tsspivot1(topcastets[i], checkseg);
7618 tssbond1(fliptets[0], checkseg);
7619 sstbond1(checkseg, fliptets[0]);
7620 tssbond1(fliptets[1], checkseg);
7621 sstbond1(checkseg, fliptets[1]);
7622 if (fc->chkencflag & 1) {
7623 enqueuesubface(badsubsegs, &checkseg);
7624 }
7625 }
7626 enextself(fliptets[0]);
7627 eprevself(fliptets[1]);
7628 }
7629 // The three top edges.
7630 for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
7631 esym(fliptets[0], newface);
7632 eprevself(newface);
7633 enext(topcastets[i], casface);
7634 if (issubseg(casface)) {
7635 tsspivot1(casface, checkseg);
7636 tssbond1(newface, checkseg);
7637 sstbond1(checkseg, newface);
7638 if (fc->chkencflag & 1) {
7639 enqueuesubface(badsubsegs, &checkseg);
7640 }
7641 }
7642 enextself(fliptets[0]);
7643 }
7644 // The three bot edges.
7645 for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
7646 esym(fliptets[1], newface);
7647 enextself(newface);
7648 eprev(botcastets[i], casface);
7649 if (issubseg(casface)) {
7650 tsspivot1(casface, checkseg);
7651 tssbond1(newface, checkseg);
7652 sstbond1(checkseg, newface);
7653 if (fc->chkencflag & 1) {
7654 enqueuesubface(badsubsegs, &checkseg);
7655 }
7656 }
7657 eprevself(fliptets[1]);
7658 }
7659 } // if (checksubsegflag)
7660
7661 if (checksubfaceflag) {
7662 face checksh;
7663 // Bond the top three casing subfaces.
7664 for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
7665 if (issubface(topcastets[i])) {
7666 tspivot(topcastets[i], checksh);
7667 esym(fliptets[0], newface);
7668 sesymself(checksh);
7669 tsbond(newface, checksh);
7670 if (fc->chkencflag & 2) {
7671 enqueuesubface(badsubfacs, &checksh);
7672 }
7673 }
7674 enextself(fliptets[0]);
7675 }
7676 // Bond the bottom three casing subfaces.
7677 for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
7678 if (issubface(botcastets[i])) {
7679 tspivot(botcastets[i], checksh);
7680 esym(fliptets[1], newface);
7681 sesymself(checksh);
7682 tsbond(newface, checksh);
7683 if (fc->chkencflag & 2) {
7684 enqueuesubface(badsubfacs, &checksh);
7685 }
7686 }
7687 eprevself(fliptets[1]);
7688 }
7689
7690 if (scount > 0) {
7691 face flipfaces[2];
7692 // Perform a 2-to-2 flip in subfaces.
7693 flipfaces[0] = flipshs[(spivot + 1) % 3];
7694 flipfaces[1] = flipshs[(spivot + 2) % 3];
7695 sesymself(flipfaces[1]);
7696 flip22(flipfaces, 0, fc->chkencflag);
7697 // Connect the flipped subfaces to flipped tets.
7698 // First go to the corresponding flipping edge.
7699 // Re-use top- and botcastets[0].
7700 topcastets[0] = fliptets[0];
7701 botcastets[0] = fliptets[1];
7702 for (i = 0; i < ((spivot + 1) % 3); i++) {
7703 enextself(topcastets[0]);
7704 eprevself(botcastets[0]);
7705 }
7706 // Connect the top subface to the top tets.
7707 esymself(topcastets[0]);
7708 sesymself(flipfaces[0]);
7709 // Check if there already exists a subface.
7710 tspivot(topcastets[0], checksh);
7711 if (checksh.sh == NULL) {
7712 tsbond(topcastets[0], flipfaces[0]);
7713 fsymself(topcastets[0]);
7714 sesymself(flipfaces[0]);
7715 tsbond(topcastets[0], flipfaces[0]);
7716 } else {
7717 // An invalid 2-to-2 flip. Report a bug.
7718 terminatetetgen(this, 2);
7719 }
7720 // Connect the bot subface to the bottom tets.
7721 esymself(botcastets[0]);
7722 sesymself(flipfaces[1]);
7723 // Check if there already exists a subface.
7724 tspivot(botcastets[0], checksh);
7725 if (checksh.sh == NULL) {
7726 tsbond(botcastets[0], flipfaces[1]);
7727 fsymself(botcastets[0]);
7728 sesymself(flipfaces[1]);
7729 tsbond(botcastets[0], flipfaces[1]);
7730 } else {
7731 // An invalid 2-to-2 flip. Report a bug.
7732 terminatetetgen(this, 2);
7733 }
7734 } // if (scount > 0)
7735 } // if (checksubfaceflag)
7736
7737 if (fc->chkencflag & 4) {
7738 // Put two new tets into check list.
7739 for (i = 0; i < 2; i++) {
7740 enqueuetetrahedron(&(fliptets[i]));
7741 }
7742 }
7743
7744 setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
7745 setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
7746 setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
7747 setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
7748 setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
7749
7750 if (hullflag > 0) {
7751 if (dummyflag != 0) {
7752 // Restore the original position of the points (for flipnm()).
7753 if (dummyflag == -1) {
7754 // e were dummypoint. Swap the two new tets.
7755 newface = fliptets[0];
7756 fliptets[0] = fliptets[1];
7757 fliptets[1] = newface;
7758 } else {
7759 // a or b was dummypoint.
7760 if (dummyflag == 1) {
7761 eprevself(fliptets[0]);
7762 enextself(fliptets[1]);
7763 } else { // dummyflag == 2
7764 enextself(fliptets[0]);
7765 eprevself(fliptets[1]);
7766 }
7767 }
7768 }
7769 }
7770
7771 if (fc->enqflag > 0) {
7772 // Queue faces which may be locally non-Delaunay.
7773 // pa = org(fliptets[0]); // 'a' may be a new vertex.
7774 enextesym(fliptets[0], newface);
7775 flippush(flipstack, &newface);
7776 eprevesym(fliptets[1], newface);
7777 flippush(flipstack, &newface);
7778 if (fc->enqflag > 1) {
7779 //pb = dest(fliptets[0]);
7780 eprevesym(fliptets[0], newface);
7781 flippush(flipstack, &newface);
7782 enextesym(fliptets[1], newface);
7783 flippush(flipstack, &newface);
7784 //pc = apex(fliptets[0]);
7785 esym(fliptets[0], newface);
7786 flippush(flipstack, &newface);
7787 esym(fliptets[1], newface);
7788 flippush(flipstack, &newface);
7789 }
7790 }
7791
7792 recenttet = fliptets[0];
7793}
7794
7795///////////////////////////////////////////////////////////////////////////////
7796// //
7797// flip41() Perform a 4-to-1 flip (Remove a vertex). //
7798// //
7799// 'fliptets' is an array of four tetrahedra in the star of the removing //
7800// vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
7801// four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
7802// p]. On return, 'fliptets[0]' is the new tet [a,b,c,d]. //
7803// //
7804// If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
7805// The 'hullsize' may be changed. Note that p may be dummypoint. In this //
7806// case, four hull tets are replaced by one real tet. //
7807// //
7808// If 'checksubface' flag is set (>0), it is possible that there are three //
7809// interior subfaces connecting at p. If so, a 3-to-1 flip is performed to //
7810// to remove p from the surface triangulation. //
7811// //
7812// If it is called by the routine incrementalflip(), we assume that d is the //
7813// newly inserted vertex. //
7814// //
7815///////////////////////////////////////////////////////////////////////////////
7816
7817void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
7818{
7819 triface topcastets[3], botcastet;
7820 triface newface, neightet;
7821 face flipshs[4];
7822 point pa, pb, pc, pd, pp;
7823 int dummyflag = 0; // in {0, 1, 2, 3, 4}
7824 int spivot = -1, scount = 0;
7825 int t1ver;
7826 int i;
7827
7828 pa = org(fliptets[3]);
7829 pb = dest(fliptets[3]);
7830 pc = apex(fliptets[3]);
7831 pd = dest(fliptets[0]);
7832 pp = org(fliptets[0]); // The removing vertex.
7833
7834 flip41count++;
7835
7836 // Get the outer boundary faces.
7837 for (i = 0; i < 3; i++) {
7838 enext(fliptets[i], topcastets[i]);
7839 fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
7840 enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
7841 }
7842 fsym(fliptets[3], botcastet); // [b,a,c,#]
7843
7844 if (checksubfaceflag) {
7845 // Check if there are three subfaces at 'p'.
7846 // Re-use 'newface'.
7847 for (i = 0; i < 3; i++) {
7848 fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
7849 tspivot(newface, flipshs[i]);
7850 if (flipshs[i].sh != NULL) {
7851 spivot = i; // Remember this subface.
7852 scount++;
7853 }
7854 enextself(fliptets[3]);
7855 }
7856 if (scount > 0) {
7857 // There are three subfaces connecting at p.
7858 if (scount < 3) {
7859 // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
7860 assert(scount == 1); // spivot >= 0
7861 // Go to the tet containing the three subfaces.
7862 fsym(topcastets[spivot], neightet);
7863 // Get the three subfaces connecting at p.
7864 for (i = 0; i < 3; i++) {
7865 esym(neightet, newface);
7866 tspivot(newface, flipshs[i]);
7867 assert(flipshs[i].sh != NULL);
7868 eprevself(neightet);
7869 }
7870 } else {
7871 spivot = 3; // The new subface is [a,b,c].
7872 }
7873 }
7874 } // if (checksubfaceflag)
7875
7876
7877 // Re-use fliptets[0] for [a,b,c,d].
7878 fliptets[0].ver = 11;
7879 setelemmarker(fliptets[0].tet, 0); // Clean all flags.
7880 // NOTE: the element attributes and volume constraint remain unchanged.
7881 if (checksubsegflag) {
7882 // Dealloc the space to subsegments.
7883 if (fliptets[0].tet[8] != NULL) {
7884 tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7885 fliptets[0].tet[8] = NULL;
7886 }
7887 }
7888 if (checksubfaceflag) {
7889 // Dealloc the space to subfaces.
7890 if (fliptets[0].tet[9] != NULL) {
7891 tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7892 fliptets[0].tet[9] = NULL;
7893 }
7894 }
7895 // Delete the other three tets.
7896 for (i = 1; i < 4; i++) {
7897 tetrahedrondealloc(fliptets[i].tet);
7898 }
7899
7900 if (pp != dummypoint) {
7901 // Mark the point pp as unused.
7902 setpointtype(pp, UNUSEDVERTEX);
7903 unuverts++;
7904 }
7905
7906 // Create the new tet [a,b,c,d].
7907 if (hullflag > 0) {
7908 // One of the five vertices may be 'dummypoint'.
7909 if (pa == dummypoint) {
7910 // pa is dummypoint.
7911 setvertices(fliptets[0], pc, pb, pd, pa);
7912 esymself(fliptets[0]); // [b,c,a,d]
7913 eprevself(fliptets[0]); // [a,b,c,d]
7914 dummyflag = 1;
7915 } else if (pb == dummypoint) {
7916 setvertices(fliptets[0], pa, pc, pd, pb);
7917 esymself(fliptets[0]); // [c,a,b,d]
7918 enextself(fliptets[0]); // [a,b,c,d]
7919 dummyflag = 2;
7920 } else if (pc == dummypoint) {
7921 setvertices(fliptets[0], pb, pa, pd, pc);
7922 esymself(fliptets[0]); // [a,b,c,d]
7923 dummyflag = 3;
7924 } else if (pd == dummypoint) {
7925 setvertices(fliptets[0], pa, pb, pc, pd);
7926 dummyflag = 4;
7927 } else {
7928 setvertices(fliptets[0], pa, pb, pc, pd);
7929 if (pp == dummypoint) {
7930 dummyflag = -1;
7931 } else {
7932 dummyflag = 0;
7933 }
7934 }
7935 if (dummyflag > 0) {
7936 // We deleted 3 hull tets, and create 1 hull tet.
7937 hullsize -= 2;
7938 } else if (dummyflag < 0) {
7939 // We deleted 4 hull tets.
7940 hullsize -= 4;
7941 // meshedges does not change.
7942 }
7943 } else {
7944 setvertices(fliptets[0], pa, pb, pc, pd);
7945 }
7946
7947 if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7948 REAL volneg[4], volpos[1], vol_diff;
7949 if (dummyflag > 0) {
7950 if (pa == dummypoint) {
7951 volneg[0] = 0.;
7952 volneg[1] = tetprismvol(pp, pd, pb, pc);
7953 volneg[2] = 0.;
7954 volneg[3] = 0.;
7955 } else if (pb == dummypoint) {
7956 volneg[0] = 0.;
7957 volneg[1] = 0.;
7958 volneg[2] = tetprismvol(pp, pd, pc, pa);
7959 volneg[3] = 0.;
7960 } else if (pc == dummypoint) {
7961 volneg[0] = tetprismvol(pp, pd, pa, pb);
7962 volneg[1] = 0.;
7963 volneg[2] = 0.;
7964 volneg[3] = 0.;
7965 } else { // pd == dummypoint
7966 volneg[0] = 0.;
7967 volneg[1] = 0.;
7968 volneg[2] = 0.;
7969 volneg[3] = tetprismvol(pa, pb, pc, pp);
7970 }
7971 volpos[0] = 0.;
7972 } else if (dummyflag < 0) {
7973 volneg[0] = 0.;
7974 volneg[1] = 0.;
7975 volneg[2] = 0.;
7976 volneg[3] = 0.;
7977 volpos[0] = tetprismvol(pa, pb, pc, pd);
7978 } else {
7979 volneg[0] = tetprismvol(pp, pd, pa, pb);
7980 volneg[1] = tetprismvol(pp, pd, pb, pc);
7981 volneg[2] = tetprismvol(pp, pd, pc, pa);
7982 volneg[3] = tetprismvol(pa, pb, pc, pp);
7983 volpos[0] = tetprismvol(pa, pb, pc, pd);
7984 }
7985 vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
7986 fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7987 }
7988
7989 // Bond the new tet to adjacent tets.
7990 for (i = 0; i < 3; i++) {
7991 esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
7992 bond(newface, topcastets[i]);
7993 enextself(fliptets[0]);
7994 }
7995 bond(fliptets[0], botcastet);
7996
7997 if (checksubsegflag) {
7998 face checkseg;
7999 // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
8000 for (i = 0; i < 3; i++) {
8001 eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
8002 if (issubseg(newface)) {
8003 tsspivot1(newface, checkseg);
8004 esym(fliptets[0], newface);
8005 enextself(newface); // At edges [a,d], [b,d], [c,d].
8006 tssbond1(newface, checkseg);
8007 sstbond1(checkseg, newface);
8008 if (fc->chkencflag & 1) {
8009 enqueuesubface(badsubsegs, &checkseg);
8010 }
8011 }
8012 enextself(fliptets[0]);
8013 }
8014 for (i = 0; i < 3; i++) {
8015 if (issubseg(topcastets[i])) {
8016 tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
8017 tssbond1(fliptets[0], checkseg);
8018 sstbond1(checkseg, fliptets[0]);
8019 if (fc->chkencflag & 1) {
8020 enqueuesubface(badsubsegs, &checkseg);
8021 }
8022 }
8023 enextself(fliptets[0]);
8024 }
8025 }
8026
8027 if (checksubfaceflag) {
8028 face checksh;
8029 // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
8030 for (i = 0; i < 3; i++) {
8031 if (issubface(topcastets[i])) {
8032 tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
8033 esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
8034 sesymself(checksh);
8035 tsbond(newface, checksh);
8036 if (fc->chkencflag & 2) {
8037 enqueuesubface(badsubfacs, &checksh);
8038 }
8039 }
8040 enextself(fliptets[0]);
8041 }
8042 if (issubface(botcastet)) {
8043 tspivot(botcastet, checksh); // At face [b,a,c]
8044 sesymself(checksh);
8045 tsbond(fliptets[0], checksh);
8046 if (fc->chkencflag & 2) {
8047 enqueuesubface(badsubfacs, &checksh);
8048 }
8049 }
8050
8051 if (spivot >= 0) {
8052 // Perform a 3-to-1 flip in surface triangulation.
8053 // Depending on the value of 'spivot', the three subfaces are:
8054 // - 0: [a,b,p], [b,d,p], [d,a,p]
8055 // - 1: [b,c,p], [c,d,p], [d,b,p]
8056 // - 2: [c,a,p], [a,d,p], [d,c,p]
8057 // - 3: [a,b,p], [b,c,p], [c,a,p]
8058 // Adjust the three subfaces such that their origins are p, i.e.,
8059 // - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
8060 for (i = 0; i < 3; i++) {
8061 senext2self(flipshs[i]);
8062 }
8063 flip31(flipshs, 0);
8064 // Delete the three old subfaces.
8065 for (i = 0; i < 3; i++) {
8066 shellfacedealloc(subfaces, flipshs[i].sh);
8067 }
8068 if (spivot < 3) {
8069 // // Bond the new subface to the new tet [a,b,c,d].
8070 tsbond(topcastets[spivot], flipshs[3]);
8071 fsym(topcastets[spivot], newface);
8072 sesym(flipshs[3], checksh);
8073 tsbond(newface, checksh);
8074 } else {
8075 // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
8076 tsbond(fliptets[0], flipshs[3]);
8077 fsym(fliptets[0], newface);
8078 sesym(flipshs[3], checksh);
8079 tsbond(newface, checksh);
8080 }
8081 } // if (spivot > 0)
8082 } // if (checksubfaceflag)
8083
8084 if (fc->chkencflag & 4) {
8085 enqueuetetrahedron(&(fliptets[0]));
8086 }
8087
8088 // Update the point-to-tet map.
8089 setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8090 setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8091 setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8092 setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8093
8094 if (fc->enqflag > 0) {
8095 // Queue faces which may be locally non-Delaunay.
8096 flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
8097 if (fc->enqflag > 1) {
8098 for (i = 0; i < 3; i++) {
8099 esym(fliptets[0], newface);
8100 flippush(flipstack, &newface);
8101 enextself(fliptets[0]);
8102 }
8103 }
8104 }
8105
8106 recenttet = fliptets[0];
8107}
8108
8109///////////////////////////////////////////////////////////////////////////////
8110// //
8111// flipnm() Flip an edge through a sequence of elementary flips. //
8112// //
8113// 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
8114// ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
8115// use the right-hand rule. //
8116// //
8117// 'level' (>= 0) indicates the current link level. If 'level > 0', we are //
8118// flipping a link edge of an edge [a',b'], and 'abedgepivot' indicates //
8119// which link edge, i.e., [c',b'] or [a',c'], is [a,b] These two parameters //
8120// allow us to determine the new tets after a 3-to-2 flip, i.e., tets that //
8121// do not inside the reduced star of edge [a',b']. //
8122// //
8123// If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8124// in flipnm([a,b]) so that the mesh is returned to its original state //
8125// before doing the flipnm([a,b]) operation. //
8126// //
8127// The return value is an integer nn, where nn <= n. If nn is 2, then the //
8128// edge is flipped. The first and the second tets in 'abtets' are new tets. //
8129// Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets //
8130// in the current star of [a,b]. //
8131// //
8132// ASSUMPTIONS: //
8133// - Neither a nor b is 'dummypoint'. //
8134// - [a,b] must not be a segment. //
8135// //
8136///////////////////////////////////////////////////////////////////////////////
8137
8138int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
8139 flipconstraints* fc)
8140{
8141 triface fliptets[3], spintet, flipedge;
8142 triface *tmpabtets, *parytet;
8143 point pa, pb, pc, pd, pe, pf;
8144 REAL ori;
8145 int hullflag, hulledgeflag;
8146 int reducflag, rejflag;
8147 int reflexlinkedgecount;
8148 int edgepivot;
8149 int n1, nn;
8150 int t1ver;
8151 int i, j;
8152
8153 pa = org(abtets[0]);
8154 pb = dest(abtets[0]);
8155
8156 if (n > 3) {
8157 // Try to reduce the size of the Star(ab) by flipping a face in it.
8158 reflexlinkedgecount = 0;
8159
8160 for (i = 0; i < n; i++) {
8161 // Let the face of 'abtets[i]' be [a,b,c].
8162 if (checksubfaceflag) {
8163 if (issubface(abtets[i])) {
8164 continue; // Skip a subface.
8165 }
8166 }
8167 // Do not flip this face if it is involved in two Stars.
8168 if ((elemcounter(abtets[i]) > 1) ||
8169 (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8170 continue;
8171 }
8172
8173 pc = apex(abtets[i]);
8174 pd = apex(abtets[(i + 1) % n]);
8175 pe = apex(abtets[(i - 1 + n) % n]);
8176 if ((pd == dummypoint) || (pe == dummypoint)) {
8177 continue; // [a,b,c] is a hull face.
8178 }
8179
8180
8181 // Decide whether [a,b,c] is flippable or not.
8182 reducflag = 0;
8183
8184 hullflag = (pc == dummypoint); // pc may be dummypoint.
8185 hulledgeflag = 0;
8186 if (hullflag == 0) {
8187 ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
8188 if (ori > 0) {
8189 ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
8190 if (ori > 0) {
8191 // Test if [a,b] is locally convex OR flat.
8192 ori = orient3d(pa, pb, pd, pe);
8193 if (ori > 0) {
8194 // Found a 2-to-3 flip: [a,b,c] => [e,d]
8195 reducflag = 1;
8196 } else if (ori == 0) {
8197 // [a,b] is flat.
8198 if (n == 4) {
8199 // The "flat" tet can be removed immediately by a 3-to-2 flip.
8200 reducflag = 1;
8201 // Check if [e,d] is a hull edge.
8202 pf = apex(abtets[(i + 2) % n]);
8203 hulledgeflag = (pf == dummypoint);
8204 }
8205 }
8206 }
8207 }
8208 if (!reducflag) {
8209 reflexlinkedgecount++;
8210 }
8211 } else {
8212 // 'c' is dummypoint.
8213 if (n == 4) {
8214 // Let the vertex opposite to 'c' is 'f'.
8215 // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
8216 // are valid tets.
8217 // Note: When the mesh is not convex, it is possible that [a,b] is
8218 // locally non-convex (at hull faces [a,b,e] and [b,a,d]).
8219 // In this case, an edge flip [a,b] to [e,d] is still possible.
8220 pf = apex(abtets[(i + 2) % n]);
8221 assert(pf != dummypoint);
8222 ori = orient3d(pd, pe, pf, pa);
8223 if (ori < 0) {
8224 ori = orient3d(pe, pd, pf, pb);
8225 if (ori < 0) {
8226 // Found a 4-to-4 flip: [a,b] => [e,d]
8227 reducflag = 1;
8228 ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
8229 hulledgeflag = 1; // [e,d] is a hull edge.
8230 }
8231 }
8232 }
8233 } // if (hullflag)
8234
8235 if (reducflag) {
8236 if (nonconvex && hulledgeflag) {
8237 // We will create a hull edge [e,d]. Make sure it does not exist.
8238 if (getedge(pe, pd, &spintet)) {
8239 // The 2-to-3 flip is not a topological valid flip.
8240 reducflag = 0;
8241 }
8242 }
8243 }
8244
8245 if (reducflag) {
8246 // [a,b,c] could be removed by a 2-to-3 flip.
8247 rejflag = 0;
8248 if (fc->checkflipeligibility) {
8249 // Check if the flip can be performed.
8250 rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
8251 abedgepivot, fc);
8252 }
8253 if (!rejflag) {
8254 // Do flip: [a,b,c] => [e,d].
8255 fliptets[0] = abtets[i];
8256 fsym(fliptets[0], fliptets[1]); // abtets[i-1].
8257 flip23(fliptets, hullflag, fc);
8258
8259 // Shrink the array 'abtets', maintain the original order.
8260 // Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
8261 // are flipped, i.e., they do not in Star(ab) anymore.
8262 // 'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
8263 // 'abtets[i-1]' (adjust it to be [a,b,e,d]), see below:
8264 //
8265 // before after
8266 // [0] |___________| [0] |___________|
8267 // ... |___________| ... |___________|
8268 // [i-1] |_[a,b,e,c]_| [i-1] |_[a,b,e,d]_|
8269 // [i] |_[a,b,c,d]_| --> [i] |_[a,b,d,#]_|
8270 // [i+1] |_[a,b,d,#]_| [i+1] |_[a,b,#,*]_|
8271 // ... |___________| ... |___________|
8272 // [n-2] |___________| [n-2] |___________|
8273 // [n-1] |___________| [n-1] |_[i]_2-t-3_|
8274 //
8275 edestoppoself(fliptets[0]); // [a,b,e,d]
8276 // Increase the counter of this new tet (it is in Star(ab)).
8277 increaseelemcounter(fliptets[0]);
8278 abtets[(i - 1 + n) % n] = fliptets[0];
8279 for (j = i; j < n - 1; j++) {
8280 abtets[j] = abtets[j + 1]; // Upshift
8281 }
8282 // The last entry 'abtets[n-1]' is empty. It is used in two ways:
8283 // (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
8284 // (ii) it remembers the position [i] where this flip took place.
8285 // These informations let us to either undo this flip or recover
8286 // the original edge link (for collecting new created tets).
8287 //abtets[n - 1] = fliptets[1]; // [e,d,b,c] is remembered.
8288 abtets[n - 1].tet = (tetrahedron *) pc;
8289 abtets[n - 1].ver = 0; // Clear it.
8290 // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
8291 // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
8292 abtets[n - 1].ver |= (1 << 4);
8293 // The poisition [i] of this flip is saved above the 7th bit.
8294 abtets[n - 1].ver |= (i << 6);
8295
8296 if (fc->collectnewtets) {
8297 // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
8298 // Re-use the global array 'cavetetlist'.
8299 for (j = 1; j < 3; j++) {
8300 cavetetlist->newindex((void **) &parytet);
8301 *parytet = fliptets[j]; // fliptets[1], fliptets[2].
8302 }
8303 }
8304
8305 // Star(ab) is reduced. Try to flip the edge [a,b].
8306 nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
8307
8308 if (nn == 2) {
8309 // The edge has been flipped.
8310 return nn;
8311 } else { // if (nn > 2)
8312 // The edge is not flipped.
8313 if (fc->unflip || (ori == 0)) {
8314 // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to
8315 // transform [e,d] => [a,b,c].
8316 // 'ori == 0' means that the previous flip created a degenerated
8317 // tet. It must be removed.
8318 // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to
8319 // find another two tets [e,d,b,c] and [e,d,c,a].
8320 fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
8321 edestoppoself(fliptets[0]); // [e,d,a,b]
8322 fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
8323 fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
8324 assert(apex(fliptets[0]) == oppo(fliptets[2])); // SELF_CHECK
8325 // Restore the two original tets in Star(ab).
8326 flip32(fliptets, hullflag, fc);
8327 // Marktest the two restored tets in Star(ab).
8328 for (j = 0; j < 2; j++) {
8329 increaseelemcounter(fliptets[j]);
8330 }
8331 // Expand the array 'abtets', maintain the original order.
8332 for (j = n - 2; j>= i; j--) {
8333 abtets[j + 1] = abtets[j]; // Downshift
8334 }
8335 // Insert the two new tets 'fliptets[0]' [a,b,c,d] and
8336 // 'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries,
8337 // respectively.
8338 esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
8339 abtets[i] = fliptets[0]; // [a,b,c,d]
8340 nn++;
8341 if (fc->collectnewtets) {
8342 // Pop two (flipped) tets from the stack.
8343 cavetetlist->objects -= 2;
8344 }
8345 } // if (unflip || (ori == 0))
8346 } // if (nn > 2)
8347
8348 if (!fc->unflip) {
8349 // The flips are not reversed. The current Star(ab) can not be
8350 // further reduced. Return its current size (# of tets).
8351 return nn;
8352 }
8353 // unflip is set.
8354 // Continue the search for flips.
8355 }
8356 } // if (reducflag)
8357 } // i
8358
8359 // The Star(ab) is not reduced.
8360 if (reflexlinkedgecount > 0) {
8361 // There are reflex edges in the Link(ab).
8362 if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) ||
8363 ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
8364 // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
8365 for (i = 0; i < n; i++) {
8366 // Do not flip this face [a,b,c] if there are two Stars involved.
8367 if ((elemcounter(abtets[i]) > 1) ||
8368 (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8369 continue;
8370 }
8371 pc = apex(abtets[i]);
8372 if (pc == dummypoint) {
8373 continue; // [a,b] is a hull edge.
8374 }
8375 pd = apex(abtets[(i + 1) % n]);
8376 pe = apex(abtets[(i - 1 + n) % n]);
8377 if ((pd == dummypoint) || (pe == dummypoint)) {
8378 continue; // [a,b,c] is a hull face.
8379 }
8380
8381
8382 edgepivot = 0; // No edge is selected yet.
8383
8384 // Test if [b,c] is locally convex or flat.
8385 ori = orient3d(pb, pc, pd, pe);
8386 if (ori <= 0) {
8387 // Select the edge [c,b].
8388 enext(abtets[i], flipedge); // [b,c,a,d]
8389 edgepivot = 1;
8390 }
8391 if (!edgepivot) {
8392 // Test if [c,a] is locally convex or flat.
8393 ori = orient3d(pc, pa, pd, pe);
8394 if (ori <= 0) {
8395 // Select the edge [a,c].
8396 eprev(abtets[i], flipedge); // [c,a,b,d].
8397 edgepivot = 2;
8398 }
8399 }
8400
8401 if (!edgepivot) continue;
8402
8403 // An edge is selected.
8404 if (checksubsegflag) {
8405 // Do not flip it if it is a segment.
8406 if (issubseg(flipedge)) {
8407 if (fc->collectencsegflag) {
8408 face checkseg, *paryseg;
8409 tsspivot1(flipedge, checkseg);
8410 if (!sinfected(checkseg)) {
8411 // Queue this segment in list.
8412 sinfect(checkseg);
8413 caveencseglist->newindex((void **) &paryseg);
8414 *paryseg = checkseg;
8415 }
8416 }
8417 continue;
8418 }
8419 }
8420
8421 // Try to flip the selected edge ([c,b] or [a,c]).
8422 esymself(flipedge);
8423 // Count the number of tets at the edge.
8424 n1 = 0;
8425 j = 0; // Sum of the star counters.
8426 spintet = flipedge;
8427 while (1) {
8428 n1++;
8429 j += (elemcounter(spintet));
8430 fnextself(spintet);
8431 if (spintet.tet == flipedge.tet) break;
8432 }
8433 assert(n1 >= 3);
8434 if (j > 2) {
8435 // The Star(flipedge) overlaps other Stars.
8436 continue; // Do not flip this edge.
8437 }
8438 // Only two tets can be marktested.
8439 assert(j == 2);
8440
8441 if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
8442 // The star size exceeds the given limit.
8443 continue; // Do not flip it.
8444 }
8445
8446 // Allocate spaces for Star(flipedge).
8447 tmpabtets = new triface[n1];
8448 // Form the Star(flipedge).
8449 j = 0;
8450 spintet = flipedge;
8451 while (1) {
8452 tmpabtets[j] = spintet;
8453 // Increase the star counter of this tet.
8454 increaseelemcounter(tmpabtets[j]);
8455 j++;
8456 fnextself(spintet);
8457 if (spintet.tet == flipedge.tet) break;
8458 }
8459
8460 // Try to flip the selected edge away.
8461 nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
8462
8463 if (nn == 2) {
8464 // The edge is flipped. Star(ab) is reduced.
8465 // Shrink the array 'abtets', maintain the original order.
8466 if (edgepivot == 1) {
8467 // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
8468 spintet = tmpabtets[0]; // [d,a,e,b]
8469 enextself(spintet);
8470 esymself(spintet);
8471 enextself(spintet); // [a,b,e,d]
8472 } else {
8473 // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
8474 spintet = tmpabtets[1]; // [b,d,e,a]
8475 eprevself(spintet);
8476 esymself(spintet);
8477 eprevself(spintet); // [a,b,e,d]
8478 } // edgepivot == 2
8479 assert(elemcounter(spintet) == 0); // It's a new tet.
8480 increaseelemcounter(spintet); // It is in Star(ab).
8481 // Put the new tet at [i-1]-th entry.
8482 abtets[(i - 1 + n) % n] = spintet;
8483 for (j = i; j < n - 1; j++) {
8484 abtets[j] = abtets[j + 1]; // Upshift
8485 }
8486 // Remember the flips in the last entry of the array 'abtets'.
8487 // They can be used to recover the flipped edge.
8488 abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
8489 abtets[n - 1].ver = 0; // Clear it.
8490 // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
8491 abtets[n - 1].ver |= edgepivot;
8492 // Use the 6th bit to signal this n1-to-m1 flip.
8493 abtets[n - 1].ver |= (1 << 5);
8494 // The poisition [i] of this flip is saved from 7th to 19th bit.
8495 abtets[n - 1].ver |= (i << 6);
8496 // The size of the star 'n1' is saved from 20th bit.
8497 abtets[n - 1].ver |= (n1 << 19);
8498
8499 // Remember the flipped link vertex 'c'. It can be used to recover
8500 // the original edge link of [a,b], and to collect new tets.
8501 tmpabtets[0].tet = (tetrahedron *) pc;
8502 tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
8503
8504 // Continue to flip the edge [a,b].
8505 nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
8506
8507 if (nn == 2) {
8508 // The edge has been flipped.
8509 return nn;
8510 } else { // if (nn > 2) {
8511 // The edge is not flipped.
8512 if (fc->unflip) {
8513 // Recover the flipped edge ([c,b] or [a,c]).
8514 assert(nn == (n - 1));
8515 // The sequence of flips are saved in 'tmpabtets'.
8516 // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
8517 // the flipping of edge [c,b] or [a,c].It must still exist in
8518 // Star(ab). It is the start tet to recover the flipped edge.
8519 if (edgepivot == 1) {
8520 // The flip edge is [c,b].
8521 tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
8522 eprevself(tmpabtets[0]);
8523 esymself(tmpabtets[0]);
8524 eprevself(tmpabtets[0]); // [d,a,e,b]
8525 fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
8526 } else {
8527 // The flip edge is [a,c].
8528 tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
8529 enextself(tmpabtets[1]);
8530 esymself(tmpabtets[1]);
8531 enextself(tmpabtets[1]); // [b,d,e,a]
8532 fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
8533 } // if (edgepivot == 2)
8534
8535 // Recover the flipped edge ([c,b] or [a,c]).
8536 flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8537
8538 // Insert the two recovered tets into Star(ab).
8539 for (j = n - 2; j >= i; j--) {
8540 abtets[j + 1] = abtets[j]; // Downshift
8541 }
8542 if (edgepivot == 1) {
8543 // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
8544 // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
8545 // tmpabtets[2] is [c,b,e,d]
8546 fliptets[0] = tmpabtets[1];
8547 enextself(fliptets[0]);
8548 esymself(fliptets[0]); // [a,b,e,c]
8549 fliptets[1] = tmpabtets[0];
8550 esymself(fliptets[1]);
8551 eprevself(fliptets[1]); // [a,b,c,d]
8552 } else {
8553 // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
8554 // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
8555 // tmpabtets[2] is [a,c,e,d]
8556 fliptets[0] = tmpabtets[1];
8557 eprevself(fliptets[0]);
8558 esymself(fliptets[0]); // [a,b,e,c]
8559 fliptets[1] = tmpabtets[0];
8560 esymself(fliptets[1]);
8561 enextself(fliptets[1]); // [a,b,c,d]
8562 } // edgepivot == 2
8563 for (j = 0; j < 2; j++) {
8564 increaseelemcounter(fliptets[j]);
8565 }
8566 // Insert the two recovered tets into Star(ab).
8567 abtets[(i - 1 + n) % n] = fliptets[0];
8568 abtets[i] = fliptets[1];
8569 nn++;
8570 // Release the allocated spaces.
8571 delete [] tmpabtets;
8572 } // if (unflip)
8573 } // if (nn > 2)
8574
8575 if (!fc->unflip) {
8576 // The flips are not reversed. The current Star(ab) can not be
8577 // further reduced. Return its size (# of tets).
8578 return nn;
8579 }
8580 // unflip is set.
8581 // Continue the search for flips.
8582 } else {
8583 // The selected edge is not flipped.
8584 if (fc->unflip) {
8585 // The memory should already be freed.
8586 assert(nn == n1);
8587 } else {
8588 // Release the memory used in this attempted flip.
8589 flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
8590 }
8591 // Decrease the star counters of tets in Star(flipedge).
8592 for (j = 0; j < nn; j++) {
8593 assert(elemcounter(tmpabtets[j]) > 0); // SELF_CHECK
8594 decreaseelemcounter(tmpabtets[j]);
8595 }
8596 // Release the allocated spaces.
8597 delete [] tmpabtets;
8598 }
8599 } // i
8600 } // if (level...)
8601 } // if (reflexlinkedgecount > 0)
8602 } else {
8603 // Check if a 3-to-2 flip is possible.
8604 // Let the three apexes be c, d,and e. Hull tets may be involved. If so,
8605 // we rearrange them such that the vertex e is dummypoint.
8606 hullflag = 0;
8607
8608 if (apex(abtets[0]) == dummypoint) {
8609 pc = apex(abtets[1]);
8610 pd = apex(abtets[2]);
8611 pe = apex(abtets[0]);
8612 hullflag = 1;
8613 } else if (apex(abtets[1]) == dummypoint) {
8614 pc = apex(abtets[2]);
8615 pd = apex(abtets[0]);
8616 pe = apex(abtets[1]);
8617 hullflag = 2;
8618 } else {
8619 pc = apex(abtets[0]);
8620 pd = apex(abtets[1]);
8621 pe = apex(abtets[2]);
8622 hullflag = (pe == dummypoint) ? 3 : 0;
8623 }
8624
8625 reducflag = 0;
8626 rejflag = 0;
8627
8628
8629 if (hullflag == 0) {
8630 // Make sure that no inverted tet will be created, i.e. the new tets
8631 // [d,c,e,a] and [c,d,e,b] must be valid tets.
8632 ori = orient3d(pd, pc, pe, pa);
8633 if (ori < 0) {
8634 ori = orient3d(pc, pd, pe, pb);
8635 if (ori < 0) {
8636 reducflag = 1;
8637 }
8638 }
8639 } else {
8640 // [a,b] is a hull edge.
8641 // Note: This can happen when it is in the middle of a 4-to-4 flip.
8642 // Note: [a,b] may even be a non-convex hull edge.
8643 if (!nonconvex) {
8644 // The mesh is convex, only do flip if it is a coplanar hull edge.
8645 ori = orient3d(pa, pb, pc, pd);
8646 if (ori == 0) {
8647 reducflag = 1;
8648 }
8649 } else { // nonconvex
8650 reducflag = 1;
8651 }
8652 if (reducflag == 1) {
8653 // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
8654 // Make sure that no inverted tet will be created.
8655 point searchpt = NULL, chkpt;
8656 REAL bigvol = 0.0, ori1, ori2;
8657 // Search an interior vertex which is an apex of edge [c,d].
8658 // In principle, it can be arbitrary interior vertex. To avoid
8659 // numerical issue, we choose the vertex which belongs to a tet
8660 // 't' at edge [c,d] and 't' has the biggest volume.
8661 fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
8662 eorgoppoself(fliptets[0]); // [d,c,b,a]
8663 spintet = fliptets[0];
8664 while (1) {
8665 fnextself(spintet);
8666 chkpt = oppo(spintet);
8667 if (chkpt == pb) break;
8668 if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
8669 ori = -orient3d(pd, pc, apex(spintet), chkpt);
8670 assert(ori > 0);
8671 if (ori > bigvol) {
8672 bigvol = ori;
8673 searchpt = chkpt;
8674 }
8675 }
8676 }
8677 if (searchpt != NULL) {
8678 // Now valid the configuration.
8679 ori1 = orient3d(pd, pc, searchpt, pa);
8680 ori2 = orient3d(pd, pc, searchpt, pb);
8681 if (ori1 * ori2 >= 0.0) {
8682 reducflag = 0; // Not valid.
8683 } else {
8684 ori1 = orient3d(pa, pb, searchpt, pc);
8685 ori2 = orient3d(pa, pb, searchpt, pd);
8686 if (ori1 * ori2 >= 0.0) {
8687 reducflag = 0; // Not valid.
8688 }
8689 }
8690 } else {
8691 // No valid searchpt is found.
8692 reducflag = 0; // Do not flip it.
8693 }
8694 } // if (reducflag == 1)
8695 } // if (hullflag == 1)
8696
8697 if (reducflag) {
8698 // A 3-to-2 flip is possible.
8699 if (checksubfaceflag) {
8700 // This edge (must not be a segment) can be flipped ONLY IF it belongs
8701 // to either 0 or 2 subfaces. In the latter case, a 2-to-2 flip in
8702 // the surface mesh will be automatically performed within the
8703 // 3-to-2 flip.
8704 nn = 0;
8705 edgepivot = -1; // Re-use it.
8706 for (j = 0; j < 3; j++) {
8707 if (issubface(abtets[j])) {
8708 nn++; // Found a subface.
8709 } else {
8710 edgepivot = j;
8711 }
8712 }
8713 assert(nn < 3);
8714 if (nn == 1) {
8715 // Found only 1 subface containing this edge. This can happen in
8716 // the boundary recovery phase. The neighbor subface is not yet
8717 // recovered. This edge should not be flipped at this moment.
8718 rejflag = 1;
8719 } else if (nn == 2) {
8720 // Found two subfaces. A 2-to-2 flip is possible. Validate it.
8721 // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
8722 eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
8723 if (issubface(spintet)) {
8724 rejflag = 1; // Conflict to a 2-to-2 flip.
8725 } else {
8726 esymself(spintet);
8727 if (issubface(spintet)) {
8728 rejflag = 1; // Conflict to a 2-to-2 flip.
8729 }
8730 }
8731 }
8732 }
8733 if (!rejflag && fc->checkflipeligibility) {
8734 // Here we must exchange 'a' and 'b'. Since in the check... function,
8735 // we assume the following point sequence, 'a,b,c,d,e', where
8736 // the face [a,b,c] will be flipped and the edge [e,d] will be
8737 // created. The two new tets are [a,b,c,d] and [b,a,c,e].
8738 rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level,
8739 abedgepivot, fc);
8740 }
8741 if (!rejflag) {
8742 // Do flip: [a,b] => [c,d,e]
8743 flip32(abtets, hullflag, fc);
8744 if (fc->remove_ndelaunay_edge) {
8745 if (level == 0) {
8746 // It is the desired removing edge. Check if we have improved
8747 // the objective function.
8748 if ((fc->tetprism_vol_sum >= 0.0) ||
8749 (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
8750 // No improvement! flip back: [c,d,e] => [a,b].
8751 flip23(abtets, hullflag, fc);
8752 // Increase the element counter -- They are in cavity.
8753 for (j = 0; j < 3; j++) {
8754 increaseelemcounter(abtets[j]);
8755 }
8756 return 3;
8757 }
8758 } // if (level == 0)
8759 }
8760 if (fc->collectnewtets) {
8761 // Collect new tets.
8762 if (level == 0) {
8763 // Push the two new tets into stack.
8764 for (j = 0; j < 2; j++) {
8765 cavetetlist->newindex((void **) &parytet);
8766 *parytet = abtets[j];
8767 }
8768 } else {
8769 // Only one of the new tets is collected. The other one is inside
8770 // the reduced edge star. 'abedgepivot' is either '1' or '2'.
8771 cavetetlist->newindex((void **) &parytet);
8772 if (abedgepivot == 1) { // [c,b]
8773 *parytet = abtets[1];
8774 } else {
8775 assert(abedgepivot == 2); // [a,c]
8776 *parytet = abtets[0];
8777 }
8778 }
8779 } // if (fc->collectnewtets)
8780 return 2;
8781 }
8782 } // if (reducflag)
8783 } // if (n == 3)
8784
8785 // The current (reduced) Star size.
8786 return n;
8787}
8788
8789///////////////////////////////////////////////////////////////////////////////
8790// //
8791// flipnm_post() Post process a n-to-m flip. //
8792// //
8793// IMPORTANT: This routine only works when there is no other flip operation //
8794// is done after flipnm([a,b]) which attempts to remove an edge [a,b]. //
8795// //
8796// 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
8797// [a,b] before flipnm([a,b]). 'nn' (< n) is the value returned by flipnm. //
8798// If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
8799// are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
8800// b] and its initial Star([a,b]). If 'nn >= 3' edge [a,b] still exists in //
8801// current mesh and 'nn' is the current number of tets in Star([a,b]). //
8802// //
8803// Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a //
8804// flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet //
8805// 'abtets[t-1]', where '0 <= t <= i'. These information can be used to //
8806// undo the flips performed in flipnm([a,b]) or to collect new tets created //
8807// by the flipnm([a,b]) operation. //
8808// //
8809// Default, this routine only walks through the flips and frees the spaces //
8810// allocated during the flipnm([a,b]) operation. //
8811// //
8812// If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8813// in flipnm([a,b]) so that the mesh is returned to its original state //
8814// before doing the flipnm([a,b]) operation. //
8815// //
8816// //
8817///////////////////////////////////////////////////////////////////////////////
8818
8819int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
8820 flipconstraints* fc)
8821{
8822 triface fliptets[3], flipface;
8823 triface *tmpabtets;
8824 int fliptype;
8825 int edgepivot;
8826 int t, n1;
8827 int i, j;
8828
8829
8830 if (nn == 2) {
8831 // The edge [a,b] has been flipped.
8832 // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
8833 // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
8834 if (fc->unflip) {
8835 // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
8836 flip23(abtets, 1, fc);
8837 if (fc->collectnewtets) {
8838 // Pop up new (flipped) tets from the stack.
8839 if (abedgepivot == 0) {
8840 // Two new tets were collected.
8841 cavetetlist->objects -= 2;
8842 } else {
8843 // Only one of the two new tets was collected.
8844 cavetetlist->objects -= 1;
8845 }
8846 }
8847 }
8848 // The initial size of Star(ab) is 3.
8849 nn++;
8850 }
8851
8852 // Walk through the performed flips.
8853 for (i = nn; i < n; i++) {
8854 // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
8855 // At the end of this step, the size of the Star([a,b]) is 'i+1'.
8856 // The sizes of the Link([a,b]) are the same.
8857 fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
8858 if (fliptype == 1) {
8859 // It was a 2-to-3 flip: [a,b,c]->[e,d].
8860 t = (abtets[i].ver >> 6);
8861 assert(t <= i);
8862 if (fc->unflip) {
8863 if (b->verbose > 2) {
8864 printf(" Recover a 2-to-3 flip at f[%d].\n", t);
8865 }
8866 // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
8867 // it is created by a 2-to-3 flip [a,b,c] => [e,d].
8868 fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
8869 eprevself(fliptets[0]);
8870 esymself(fliptets[0]);
8871 enextself(fliptets[0]); // [e,d,a,b]
8872 fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
8873 fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
8874 // Do a 3-to-2 flip: [e,d] => [a,b,c].
8875 // NOTE: hull tets may be invloved.
8876 flip32(fliptets, 1, fc);
8877 // Expand the array 'abtets', maintain the original order.
8878 // The new array length is (i+1).
8879 for (j = i - 1; j >= t; j--) {
8880 abtets[j + 1] = abtets[j]; // Downshift
8881 }
8882 // The tet abtets[(t-1)%i] is deleted. Insert the two new tets
8883 // 'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
8884 // the (t-1)-th and t-th entries, respectively.
8885 esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
8886 abtets[t] = fliptets[0]; // [a,b,c,d]
8887 if (fc->collectnewtets) {
8888 // Pop up two (flipped) tets from the stack.
8889 cavetetlist->objects -= 2;
8890 }
8891 }
8892 } else if (fliptype == 2) {
8893 tmpabtets = (triface *) (abtets[i].tet);
8894 n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
8895 edgepivot = (abtets[i].ver & 3);
8896 t = ((abtets[i].ver >> 6) & 8191);
8897 assert(t <= i);
8898 if (fc->unflip) {
8899 if (b->verbose > 2) {
8900 printf(" Recover a %d-to-m flip at e[%d] of f[%d].\n", n1,
8901 edgepivot, t);
8902 }
8903 // Recover the flipped edge ([c,b] or [a,c]).
8904 // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
8905 // the flipping of edge [c,b] or [a,c]. It must still exist in
8906 // Star(ab). Use it to recover the flipped edge.
8907 if (edgepivot == 1) {
8908 // The flip edge is [c,b].
8909 tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
8910 eprevself(tmpabtets[0]);
8911 esymself(tmpabtets[0]);
8912 eprevself(tmpabtets[0]); // [d,a,e,b]
8913 fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
8914 } else {
8915 // The flip edge is [a,c].
8916 tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
8917 enextself(tmpabtets[1]);
8918 esymself(tmpabtets[1]);
8919 enextself(tmpabtets[1]); // [b,d,e,a]
8920 fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
8921 } // if (edgepivot == 2)
8922
8923 // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
8924 flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8925
8926 // Insert the two recovered tets into the original Star(ab).
8927 for (j = i - 1; j >= t; j--) {
8928 abtets[j + 1] = abtets[j]; // Downshift
8929 }
8930 if (edgepivot == 1) {
8931 // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
8932 // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
8933 // tmpabtets[2] is [c,b,e,d]
8934 fliptets[0] = tmpabtets[1];
8935 enextself(fliptets[0]);
8936 esymself(fliptets[0]); // [a,b,e,c]
8937 fliptets[1] = tmpabtets[0];
8938 esymself(fliptets[1]);
8939 eprevself(fliptets[1]); // [a,b,c,d]
8940 } else {
8941 // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
8942 // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
8943 // tmpabtets[2] is [a,c,e,d]
8944 fliptets[0] = tmpabtets[1];
8945 eprevself(fliptets[0]);
8946 esymself(fliptets[0]); // [a,b,e,c]
8947 fliptets[1] = tmpabtets[0];
8948 esymself(fliptets[1]);
8949 enextself(fliptets[1]); // [a,b,c,d]
8950 } // edgepivot == 2
8951 // Insert the two recovered tets into Star(ab).
8952 abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
8953 abtets[t] = fliptets[1];
8954 }
8955 else {
8956 // Only free the spaces.
8957 flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8958 } // if (!unflip)
8959 if (b->verbose > 2) {
8960 printf(" Release %d spaces at f[%d].\n", n1, i);
8961 }
8962 delete [] tmpabtets;
8963 }
8964 } // i
8965
8966 return 1;
8967}
8968
8969///////////////////////////////////////////////////////////////////////////////
8970// //
8971// insertpoint() Insert a point into current tetrahedralization. //
8972// //
8973// The Bowyer-Watson (B-W) algorithm is used to add a new point p into the //
8974// tetrahedralization T. It first finds a "cavity", denoted as C, in T, C //
8975// consists of tetrahedra in T that "conflict" with p. If T is a Delaunay //
8976// tetrahedralization, then all boundary faces (triangles) of C are visible //
8977// by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
8978// tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
8979// C and p. If T is not a DT, then C may be not star-shaped. It must be //
8980// modified so that it becomes star-shaped. //
8981// //
8982///////////////////////////////////////////////////////////////////////////////
8983
8984int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
8985 face *splitseg, insertvertexflags *ivf)
8986{
8987 arraypool *swaplist;
8988 triface *cavetet, spintet, neightet, neineitet, *parytet;
8989 triface oldtet, newtet, newneitet;
8990 face checksh, neighsh, *parysh;
8991 face checkseg, *paryseg;
8992 point *pts, pa, pb, pc, *parypt;
8993 enum locateresult loc = OUTSIDE;
8994 REAL sign, ori;
8995 REAL attrib, volume;
8996 bool enqflag;
8997 int t1ver;
8998 int i, j, k, s;
8999
9000 if (b->verbose > 2) {
9001 printf(" Insert point %d\n", pointmark(insertpt));
9002 }
9003
9004 // Locate the point.
9005 if (searchtet->tet != NULL) {
9006 loc = (enum locateresult) ivf->iloc;
9007 }
9008
9009 if (loc == OUTSIDE) {
9010 if (searchtet->tet == NULL) {
9011 if (!b->weighted) {
9012 randomsample(insertpt, searchtet);
9013 } else {
9014 // Weighted DT. There may exist dangling vertex.
9015 *searchtet = recenttet;
9016 }
9017 }
9018 // Locate the point.
9019 loc = locate(insertpt, searchtet);
9020 }
9021
9022 ivf->iloc = (int) loc; // The return value.
9023
9024 if (b->weighted) {
9025 if (loc != OUTSIDE) {
9026 // Check if this vertex is regular.
9027 pts = (point *) searchtet->tet;
9028 assert(pts[7] != dummypoint);
9029 sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9030 pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9031 insertpt[3]);
9032 if (sign > 0) {
9033 // This new vertex does not lie below the lower hull. Skip it.
9034 setpointtype(insertpt, NREGULARVERTEX);
9035 nonregularcount++;
9036 ivf->iloc = (int) NONREGULAR;
9037 return 0;
9038 }
9039 }
9040 }
9041
9042 // Create the initial cavity C(p) which contains all tetrahedra that
9043 // intersect p. It may include 1, 2, or n tetrahedra.
9044 // If p lies on a segment or subface, also create the initial sub-cavity
9045 // sC(p) which contains all subfaces (and segment) which intersect p.
9046
9047 if (loc == OUTSIDE) {
9048 flip14count++;
9049 // The current hull will be enlarged.
9050 // Add four adjacent boundary tets into list.
9051 for (i = 0; i < 4; i++) {
9052 decode(searchtet->tet[i], neightet);
9053 neightet.ver = epivot[neightet.ver];
9054 cavebdrylist->newindex((void **) &parytet);
9055 *parytet = neightet;
9056 }
9057 infect(*searchtet);
9058 caveoldtetlist->newindex((void **) &parytet);
9059 *parytet = *searchtet;
9060 } else if (loc == INTETRAHEDRON) {
9061 flip14count++;
9062 // Add four adjacent boundary tets into list.
9063 for (i = 0; i < 4; i++) {
9064 decode(searchtet->tet[i], neightet);
9065 neightet.ver = epivot[neightet.ver];
9066 cavebdrylist->newindex((void **) &parytet);
9067 *parytet = neightet;
9068 }
9069 infect(*searchtet);
9070 caveoldtetlist->newindex((void **) &parytet);
9071 *parytet = *searchtet;
9072 } else if (loc == ONFACE) {
9073 flip26count++;
9074 // Add six adjacent boundary tets into list.
9075 j = (searchtet->ver & 3); // The current face number.
9076 for (i = 1; i < 4; i++) {
9077 decode(searchtet->tet[(j + i) % 4], neightet);
9078 neightet.ver = epivot[neightet.ver];
9079 cavebdrylist->newindex((void **) &parytet);
9080 *parytet = neightet;
9081 }
9082 decode(searchtet->tet[j], spintet);
9083 j = (spintet.ver & 3); // The current face number.
9084 for (i = 1; i < 4; i++) {
9085 decode(spintet.tet[(j + i) % 4], neightet);
9086 neightet.ver = epivot[neightet.ver];
9087 cavebdrylist->newindex((void **) &parytet);
9088 *parytet = neightet;
9089 }
9090 infect(spintet);
9091 caveoldtetlist->newindex((void **) &parytet);
9092 *parytet = spintet;
9093 infect(*searchtet);
9094 caveoldtetlist->newindex((void **) &parytet);
9095 *parytet = *searchtet;
9096
9097 if (ivf->splitbdflag) {
9098 if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9099 // Create the initial sub-cavity sC(p).
9100 smarktest(*splitsh);
9101 caveshlist->newindex((void **) &parysh);
9102 *parysh = *splitsh;
9103 }
9104 } // if (splitbdflag)
9105 } else if (loc == ONEDGE) {
9106 flipn2ncount++;
9107 // Add all adjacent boundary tets into list.
9108 spintet = *searchtet;
9109 while (1) {
9110 eorgoppo(spintet, neightet);
9111 decode(neightet.tet[neightet.ver & 3], neightet);
9112 neightet.ver = epivot[neightet.ver];
9113 cavebdrylist->newindex((void **) &parytet);
9114 *parytet = neightet;
9115 edestoppo(spintet, neightet);
9116 decode(neightet.tet[neightet.ver & 3], neightet);
9117 neightet.ver = epivot[neightet.ver];
9118 cavebdrylist->newindex((void **) &parytet);
9119 *parytet = neightet;
9120 infect(spintet);
9121 caveoldtetlist->newindex((void **) &parytet);
9122 *parytet = spintet;
9123 fnextself(spintet);
9124 if (spintet.tet == searchtet->tet) break;
9125 } // while (1)
9126
9127 if (ivf->splitbdflag) {
9128 // Create the initial sub-cavity sC(p).
9129 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9130 smarktest(*splitseg);
9131 splitseg->shver = 0;
9132 spivot(*splitseg, *splitsh);
9133 }
9134 if (splitsh != NULL) {
9135 if (splitsh->sh != NULL) {
9136 // Collect all subfaces share at this edge.
9137 pa = sorg(*splitsh);
9138 neighsh = *splitsh;
9139 while (1) {
9140 // Adjust the origin of its edge to be 'pa'.
9141 if (sorg(neighsh) != pa) {
9142 sesymself(neighsh);
9143 }
9144 // Add this face into list (in B-W cavity).
9145 smarktest(neighsh);
9146 caveshlist->newindex((void **) &parysh);
9147 *parysh = neighsh;
9148 // Add this face into face-at-splitedge list.
9149 cavesegshlist->newindex((void **) &parysh);
9150 *parysh = neighsh;
9151 // Go to the next face at the edge.
9152 spivotself(neighsh);
9153 // Stop if all faces at the edge have been visited.
9154 if (neighsh.sh == splitsh->sh) break;
9155 if (neighsh.sh == NULL) break;
9156 } // while (1)
9157 } // if (not a dangling segment)
9158 }
9159 } // if (splitbdflag)
9160 } else if (loc == INSTAR) {
9161 // We assume that all tets in the star are given in 'caveoldtetlist',
9162 // and they are all infected.
9163 assert(caveoldtetlist->objects > 0);
9164 // Collect the boundary faces of the star.
9165 for (i = 0; i < caveoldtetlist->objects; i++) {
9166 cavetet = (triface *) fastlookup(caveoldtetlist, i);
9167 // Check its 4 neighbor tets.
9168 for (j = 0; j < 4; j++) {
9169 decode(cavetet->tet[j], neightet);
9170 if (!infected(neightet)) {
9171 // It's a boundary face.
9172 neightet.ver = epivot[neightet.ver];
9173 cavebdrylist->newindex((void **) &parytet);
9174 *parytet = neightet;
9175 }
9176 }
9177 }
9178 } else if (loc == ONVERTEX) {
9179 // The point already exist. Do nothing and return.
9180 return 0;
9181 }
9182
9183
9184 if (ivf->assignmeshsize) {
9185 // Assign mesh size for the new point.
9186 if (bgm != NULL) {
9187 // Interpolate the mesh size from the background mesh.
9188 bgm->decode(point2bgmtet(org(*searchtet)), neightet);
9189 int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
9190 if (bgmloc != (int) OUTSIDE) {
9191 insertpt[pointmtrindex] =
9192 bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
9193 setpoint2bgmtet(insertpt, bgm->encode(neightet));
9194 }
9195 } else {
9196 insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
9197 }
9198 } // if (assignmeshsize)
9199
9200 if (ivf->bowywat) {
9201 // Update the cavity C(p) using the Bowyer-Watson algorithm.
9202 swaplist = cavetetlist;
9203 cavetetlist = cavebdrylist;
9204 cavebdrylist = swaplist;
9205 for (i = 0; i < cavetetlist->objects; i++) {
9206 // 'cavetet' is an adjacent tet at outside of the cavity.
9207 cavetet = (triface *) fastlookup(cavetetlist, i);
9208 // The tet may be tested and included in the (enlarged) cavity.
9209 if (!infected(*cavetet)) {
9210 // Check for two possible cases for this tet:
9211 // (1) It is a cavity tet, or
9212 // (2) it is a cavity boundary face.
9213 enqflag = false;
9214 if (!marktested(*cavetet)) {
9215 // Do Delaunay (in-sphere) test.
9216 pts = (point *) cavetet->tet;
9217 if (pts[7] != dummypoint) {
9218 // A volume tet. Operate on it.
9219 if (b->weighted) {
9220 sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9221 pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9222 insertpt[3]);
9223 } else {
9224 sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
9225 }
9226 enqflag = (sign < 0.0);
9227 } else {
9228 if (!nonconvex) {
9229 // Test if this hull face is visible by the new point.
9230 ori = orient3d(pts[4], pts[5], pts[6], insertpt);
9231 if (ori < 0) {
9232 // A visible hull face.
9233 //if (!nonconvex) {
9234 // Include it in the cavity. The convex hull will be enlarged.
9235 enqflag = true; // (ori < 0.0);
9236 //}
9237 } else if (ori == 0.0) {
9238 // A coplanar hull face. We need to test if this hull face is
9239 // Delaunay or not. We test if the adjacent tet (not faked)
9240 // of this hull face is Delaunay or not.
9241 decode(cavetet->tet[3], neineitet);
9242 if (!infected(neineitet)) {
9243 if (!marktested(neineitet)) {
9244 // Do Delaunay test on this tet.
9245 pts = (point *) neineitet.tet;
9246 assert(pts[7] != dummypoint);
9247 if (b->weighted) {
9248 sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9249 pts[4][3], pts[5][3], pts[6][3],
9250 pts[7][3], insertpt[3]);
9251 } else {
9252 sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9253 }
9254 enqflag = (sign < 0.0);
9255 }
9256 } else {
9257 // The adjacent tet is non-Delaunay. The hull face is non-
9258 // Delaunay as well. Include it in the cavity.
9259 enqflag = true;
9260 } // if (!infected(neineitet))
9261 } // if (ori == 0.0)
9262 } else {
9263 // A hull face (must be a subface).
9264 // We FIRST include it in the initial cavity if the adjacent tet
9265 // (not faked) of this hull face is not Delaunay wrt p.
9266 // Whether it belongs to the final cavity will be determined
9267 // during the validation process. 'validflag'.
9268 decode(cavetet->tet[3], neineitet);
9269 if (!infected(neineitet)) {
9270 if (!marktested(neineitet)) {
9271 // Do Delaunay test on this tet.
9272 pts = (point *) neineitet.tet;
9273 assert(pts[7] != dummypoint);
9274 if (b->weighted) {
9275 sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9276 pts[4][3], pts[5][3], pts[6][3],
9277 pts[7][3], insertpt[3]);
9278 } else {
9279 sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9280 }
9281 enqflag = (sign < 0.0);
9282 }
9283 } else {
9284 // The adjacent tet is non-Delaunay. The hull face is non-
9285 // Delaunay as well. Include it in the cavity.
9286 enqflag = true;
9287 } // if (infected(neineitet))
9288 } // if (nonconvex)
9289 } // if (pts[7] != dummypoint)
9290 marktest(*cavetet); // Only test it once.
9291 } // if (!marktested(*cavetet))
9292
9293 if (enqflag) {
9294 // Found a tet in the cavity. Put other three faces in check list.
9295 k = (cavetet->ver & 3); // The current face number
9296 for (j = 1; j < 4; j++) {
9297 decode(cavetet->tet[(j + k) % 4], neightet);
9298 cavetetlist->newindex((void **) &parytet);
9299 *parytet = neightet;
9300 }
9301 infect(*cavetet);
9302 caveoldtetlist->newindex((void **) &parytet);
9303 *parytet = *cavetet;
9304 } else {
9305 // Found a boundary face of the cavity.
9306 cavetet->ver = epivot[cavetet->ver];
9307 cavebdrylist->newindex((void **) &parytet);
9308 *parytet = *cavetet;
9309 }
9310 } // if (!infected(*cavetet))
9311 } // i
9312
9313 cavetetlist->restart(); // Clear the working list.
9314 } // if (ivf->bowywat)
9315
9316 if (checksubsegflag) {
9317 // Collect all segments of C(p).
9318 shellface *ssptr;
9319 for (i = 0; i < caveoldtetlist->objects; i++) {
9320 cavetet = (triface *) fastlookup(caveoldtetlist, i);
9321 if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
9322 for (j = 0; j < 6; j++) {
9323 if (ssptr[j]) {
9324 sdecode(ssptr[j], checkseg);
9325 if (!sinfected(checkseg)) {
9326 sinfect(checkseg);
9327 cavetetseglist->newindex((void **) &paryseg);
9328 *paryseg = checkseg;
9329 }
9330 }
9331 } // j
9332 }
9333 } // i
9334 // Uninfect collected segments.
9335 for (i = 0; i < cavetetseglist->objects; i++) {
9336 paryseg = (face *) fastlookup(cavetetseglist, i);
9337 suninfect(*paryseg);
9338 }
9339
9340 if (ivf->rejflag & 1) {
9341 // Reject this point if it encroaches upon any segment.
9342 face *paryseg1;
9343 for (i = 0; i < cavetetseglist->objects; i++) {
9344 paryseg1 = (face *) fastlookup(cavetetseglist, i);
9345 if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4],
9346 insertpt)) {
9347 encseglist->newindex((void **) &paryseg);
9348 *paryseg = *paryseg1;
9349 }
9350 } // i
9351 if (encseglist->objects > 0) {
9352 insertpoint_abort(splitseg, ivf);
9353 ivf->iloc = (int) ENCSEGMENT;
9354 return 0;
9355 }
9356 }
9357 } // if (checksubsegflag)
9358
9359 if (checksubfaceflag) {
9360 // Collect all subfaces of C(p).
9361 shellface *sptr;
9362 for (i = 0; i < caveoldtetlist->objects; i++) {
9363 cavetet = (triface *) fastlookup(caveoldtetlist, i);
9364 if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
9365 for (j = 0; j < 4; j++) {
9366 if (sptr[j]) {
9367 sdecode(sptr[j], checksh);
9368 if (!sinfected(checksh)) {
9369 sinfect(checksh);
9370 cavetetshlist->newindex((void **) &parysh);
9371 *parysh = checksh;
9372 }
9373 }
9374 } // j
9375 }
9376 } // i
9377 // Uninfect collected subfaces.
9378 for (i = 0; i < cavetetshlist->objects; i++) {
9379 parysh = (face *) fastlookup(cavetetshlist, i);
9380 suninfect(*parysh);
9381 }
9382
9383 if (ivf->rejflag & 2) {
9384 REAL rd, cent[3];
9385 badface *bface;
9386 // Reject this point if it encroaches upon any subface.
9387 for (i = 0; i < cavetetshlist->objects; i++) {
9388 parysh = (face *) fastlookup(cavetetshlist, i);
9389 if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4],
9390 (point) parysh->sh[5], insertpt, cent, &rd)) {
9391 encshlist->newindex((void **) &bface);
9392 bface->ss = *parysh;
9393 bface->forg = (point) parysh->sh[3]; // Not a dad one.
9394 for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
9395 bface->key = rd;
9396 }
9397 }
9398 if (encshlist->objects > 0) {
9399 insertpoint_abort(splitseg, ivf);
9400 ivf->iloc = (int) ENCSUBFACE;
9401 return 0;
9402 }
9403 }
9404 } // if (checksubfaceflag)
9405
9406 if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
9407 // The vertex lies outside of the domain. And it does not encroach
9408 // upon any boundary segment or subface. Do not insert it.
9409 insertpoint_abort(splitseg, ivf);
9410 return 0;
9411 }
9412
9413 if (ivf->splitbdflag) {
9414 // The new point locates in surface mesh. Update the sC(p).
9415 // We have already 'smarktested' the subfaces which directly intersect
9416 // with p in 'caveshlist'. From them, we 'smarktest' their neighboring
9417 // subfaces which are included in C(p). Do not across a segment.
9418 for (i = 0; i < caveshlist->objects; i++) {
9419 parysh = (face *) fastlookup(caveshlist, i);
9420 assert(smarktested(*parysh));
9421 checksh = *parysh;
9422 for (j = 0; j < 3; j++) {
9423 if (!isshsubseg(checksh)) {
9424 spivot(checksh, neighsh);
9425 assert(neighsh.sh != NULL);
9426 if (!smarktested(neighsh)) {
9427 stpivot(neighsh, neightet);
9428 if (infected(neightet)) {
9429 fsymself(neightet);
9430 if (infected(neightet)) {
9431 // This subface is inside C(p).
9432 // Check if its diametrical circumsphere encloses 'p'.
9433 // The purpose of this check is to avoid forming invalid
9434 // subcavity in surface mesh.
9435 sign = incircle3d(sorg(neighsh), sdest(neighsh),
9436 sapex(neighsh), insertpt);
9437 if (sign < 0) {
9438 smarktest(neighsh);
9439 caveshlist->newindex((void **) &parysh);
9440 *parysh = neighsh;
9441 }
9442 }
9443 }
9444 }
9445 }
9446 senextself(checksh);
9447 } // j
9448 } // i
9449 } // if (ivf->splitbdflag)
9450
9451 if (ivf->validflag) {
9452 // Validate C(p) and update it if it is not star-shaped.
9453 int cutcount = 0;
9454
9455 if (ivf->respectbdflag) {
9456 // The initial cavity may include subfaces which are not on the facets
9457 // being splitting. Find them and make them as boundary of C(p).
9458 // Comment: We have already 'smarktested' the subfaces in sC(p). They
9459 // are completely inside C(p).
9460 for (i = 0; i < cavetetshlist->objects; i++) {
9461 parysh = (face *) fastlookup(cavetetshlist, i);
9462 stpivot(*parysh, neightet);
9463 if (infected(neightet)) {
9464 fsymself(neightet);
9465 if (infected(neightet)) {
9466 // Found a subface inside C(p).
9467 if (!smarktested(*parysh)) {
9468 // It is possible that this face is a boundary subface.
9469 // Check if it is a hull face.
9470 //assert(apex(neightet) != dummypoint);
9471 if (oppo(neightet) != dummypoint) {
9472 fsymself(neightet);
9473 }
9474 if (oppo(neightet) != dummypoint) {
9475 ori = orient3d(org(neightet), dest(neightet), apex(neightet),
9476 insertpt);
9477 if (ori < 0) {
9478 // A visible face, get its neighbor face.
9479 fsymself(neightet);
9480 ori = -ori; // It must be invisible by p.
9481 }
9482 } else {
9483 // A hull tet. It needs to be cut.
9484 ori = 1;
9485 }
9486 // Cut this tet if it is either invisible by or coplanar with p.
9487 if (ori >= 0) {
9488 uninfect(neightet);
9489 unmarktest(neightet);
9490 cutcount++;
9491 neightet.ver = epivot[neightet.ver];
9492 cavebdrylist->newindex((void **) &parytet);
9493 *parytet = neightet;
9494 // Add three new faces to find new boundaries.
9495 for (j = 0; j < 3; j++) {
9496 esym(neightet, neineitet);
9497 neineitet.ver = epivot[neineitet.ver];
9498 cavebdrylist->newindex((void **) &parytet);
9499 *parytet = neineitet;
9500 enextself(neightet);
9501 }
9502 } // if (ori >= 0)
9503 }
9504 }
9505 }
9506 } // i
9507
9508 // The initial cavity may include segments in its interior. We need to
9509 // Update the cavity so that these segments are on the boundary of
9510 // the cavity.
9511 for (i = 0; i < cavetetseglist->objects; i++) {
9512 paryseg = (face *) fastlookup(cavetetseglist, i);
9513 // Check this segment if it is not a splitting segment.
9514 if (!smarktested(*paryseg)) {
9515 sstpivot1(*paryseg, neightet);
9516 spintet = neightet;
9517 while (1) {
9518 if (!infected(spintet)) break;
9519 fnextself(spintet);
9520 if (spintet.tet == neightet.tet) break;
9521 }
9522 if (infected(spintet)) {
9523 // Find an adjacent tet at this segment such that both faces
9524 // at this segment are not visible by p.
9525 pa = org(neightet);
9526 pb = dest(neightet);
9527 spintet = neightet;
9528 j = 0;
9529 while (1) {
9530 // Check if this face is visible by p.
9531 pc = apex(spintet);
9532 if (pc != dummypoint) {
9533 ori = orient3d(pa, pb, pc, insertpt);
9534 if (ori >= 0) {
9535 // Not visible. Check another face in this tet.
9536 esym(spintet, neineitet);
9537 pc = apex(neineitet);
9538 if (pc != dummypoint) {
9539 ori = orient3d(pb, pa, pc, insertpt);
9540 if (ori >= 0) {
9541 // Not visible. Found this face.
9542 j = 1; // Flag that it is found.
9543 break;
9544 }
9545 }
9546 }
9547 }
9548 fnextself(spintet);
9549 if (spintet.tet == neightet.tet) break;
9550 }
9551 if (j == 0) {
9552 // Not found such a face.
9553 assert(0); // debug this case.
9554 }
9555 neightet = spintet;
9556 if (b->verbose > 3) {
9557 printf(" Cut tet (%d, %d, %d, %d)\n",
9558 pointmark(org(neightet)), pointmark(dest(neightet)),
9559 pointmark(apex(neightet)), pointmark(oppo(neightet)));
9560 }
9561 uninfect(neightet);
9562 unmarktest(neightet);
9563 cutcount++;
9564 neightet.ver = epivot[neightet.ver];
9565 cavebdrylist->newindex((void **) &parytet);
9566 *parytet = neightet;
9567 // Add three new faces to find new boundaries.
9568 for (j = 0; j < 3; j++) {
9569 esym(neightet, neineitet);
9570 neineitet.ver = epivot[neineitet.ver];
9571 cavebdrylist->newindex((void **) &parytet);
9572 *parytet = neineitet;
9573 enextself(neightet);
9574 }
9575 }
9576 }
9577 } // i
9578 } // if (ivf->respectbdflag)
9579
9580 // Update the cavity by removing invisible faces until it is star-shaped.
9581 for (i = 0; i < cavebdrylist->objects; i++) {
9582 cavetet = (triface *) fastlookup(cavebdrylist, i);
9583 // 'cavetet' is an exterior tet adjacent to the cavity.
9584 // Check if its neighbor is inside C(p).
9585 fsym(*cavetet, neightet);
9586 if (infected(neightet)) {
9587 if (apex(*cavetet) != dummypoint) {
9588 // It is a cavity boundary face. Check its visibility.
9589 if (oppo(neightet) != dummypoint) {
9590 ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
9591 insertpt);
9592 enqflag = (ori > 0);
9593 // Comment: if ori == 0 (coplanar case), we also cut the tet.
9594 } else {
9595 // It is a hull face. And its adjacent tet (at inside of the
9596 // domain) has been cut from the cavity. Cut it as well.
9597 //assert(nonconvex);
9598 enqflag = false;
9599 }
9600 } else {
9601 enqflag = true; // A hull edge.
9602 }
9603 if (enqflag) {
9604 // This face is valid, save it.
9605 cavetetlist->newindex((void **) &parytet);
9606 *parytet = *cavetet;
9607 } else {
9608 uninfect(neightet);
9609 unmarktest(neightet);
9610 cutcount++;
9611 // Add three new faces to find new boundaries.
9612 for (j = 0; j < 3; j++) {
9613 esym(neightet, neineitet);
9614 neineitet.ver = epivot[neineitet.ver];
9615 cavebdrylist->newindex((void **) &parytet);
9616 *parytet = neineitet;
9617 enextself(neightet);
9618 }
9619 // 'cavetet' is not on the cavity boundary anymore.
9620 unmarktest(*cavetet);
9621 }
9622 } else {
9623 // 'cavetet' is not on the cavity boundary anymore.
9624 unmarktest(*cavetet);
9625 }
9626 } // i
9627
9628 if (cutcount > 0) {
9629 // The cavity has been updated.
9630 // Update the cavity boundary faces.
9631 cavebdrylist->restart();
9632 for (i = 0; i < cavetetlist->objects; i++) {
9633 cavetet = (triface *) fastlookup(cavetetlist, i);
9634 // 'cavetet' was an exterior tet adjacent to the cavity.
9635 fsym(*cavetet, neightet);
9636 if (infected(neightet)) {
9637 // It is a cavity boundary face.
9638 cavebdrylist->newindex((void **) &parytet);
9639 *parytet = *cavetet;
9640 } else {
9641 // Not a cavity boundary face.
9642 unmarktest(*cavetet);
9643 }
9644 }
9645
9646 // Update the list of old tets.
9647 cavetetlist->restart();
9648 for (i = 0; i < caveoldtetlist->objects; i++) {
9649 cavetet = (triface *) fastlookup(caveoldtetlist, i);
9650 if (infected(*cavetet)) {
9651 cavetetlist->newindex((void **) &parytet);
9652 *parytet = *cavetet;
9653 }
9654 }
9655 // Swap 'cavetetlist' and 'caveoldtetlist'.
9656 swaplist = caveoldtetlist;
9657 caveoldtetlist = cavetetlist;
9658 cavetetlist = swaplist;
9659
9660 // The cavity should contain at least one tet.
9661 if (caveoldtetlist->objects == 0l) {
9662 insertpoint_abort(splitseg, ivf);
9663 ivf->iloc = (int) BADELEMENT;
9664 return 0;
9665 }
9666
9667 if (ivf->splitbdflag) {
9668 int cutshcount = 0;
9669 // Update the sub-cavity sC(p).
9670 for (i = 0; i < caveshlist->objects; i++) {
9671 parysh = (face *) fastlookup(caveshlist, i);
9672 if (smarktested(*parysh)) {
9673 enqflag = false;
9674 stpivot(*parysh, neightet);
9675 if (infected(neightet)) {
9676 fsymself(neightet);
9677 if (infected(neightet)) {
9678 enqflag = true;
9679 }
9680 }
9681 if (!enqflag) {
9682 sunmarktest(*parysh);
9683 // Use the last entry of this array to fill this entry.
9684 j = caveshlist->objects - 1;
9685 checksh = * (face *) fastlookup(caveshlist, j);
9686 *parysh = checksh;
9687 cutshcount++;
9688 caveshlist->objects--; // The list is shrinked.
9689 i--;
9690 }
9691 }
9692 }
9693
9694 if (cutshcount > 0) {
9695 i = 0; // Count the number of invalid subfaces/segments.
9696 // Valid the updated sub-cavity sC(p).
9697 if (loc == ONFACE) {
9698 if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9699 // The to-be split subface should be in sC(p).
9700 if (!smarktested(*splitsh)) i++;
9701 }
9702 } else if (loc == ONEDGE) {
9703 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9704 // The to-be split segment should be in sC(p).
9705 if (!smarktested(*splitseg)) i++;
9706 }
9707 if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9708 // All subfaces at this edge should be in sC(p).
9709 pa = sorg(*splitsh);
9710 neighsh = *splitsh;
9711 while (1) {
9712 // Adjust the origin of its edge to be 'pa'.
9713 if (sorg(neighsh) != pa) {
9714 sesymself(neighsh);
9715 }
9716 // Add this face into list (in B-W cavity).
9717 if (!smarktested(neighsh)) i++;
9718 // Go to the next face at the edge.
9719 spivotself(neighsh);
9720 // Stop if all faces at the edge have been visited.
9721 if (neighsh.sh == splitsh->sh) break;
9722 if (neighsh.sh == NULL) break;
9723 } // while (1)
9724 }
9725 }
9726
9727 if (i > 0) {
9728 // The updated sC(p) is invalid. Do not insert this vertex.
9729 insertpoint_abort(splitseg, ivf);
9730 ivf->iloc = (int) BADELEMENT;
9731 return 0;
9732 }
9733 } // if (cutshcount > 0)
9734 } // if (ivf->splitbdflag)
9735 } // if (cutcount > 0)
9736
9737 } // if (ivf->validflag)
9738
9739 if (ivf->refineflag) {
9740 // The new point is inserted by Delaunay refinement, i.e., it is the
9741 // circumcenter of a tetrahedron, or a subface, or a segment.
9742 // Do not insert this point if the tetrahedron, or subface, or segment
9743 // is not inside the final cavity.
9744 if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
9745 ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
9746 insertpoint_abort(splitseg, ivf);
9747 ivf->iloc = (int) BADELEMENT;
9748 return 0;
9749 }
9750 } // if (ivf->refineflag)
9751
9752 if (b->plc && (loc != INSTAR)) {
9753 // Reject the new point if it lies too close to an existing point (b->plc),
9754 // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
9755 // Collect the list of vertices of the initial cavity.
9756 if (loc == OUTSIDE) {
9757 pts = (point *) &(searchtet->tet[4]);
9758 for (i = 0; i < 3; i++) {
9759 cavetetvertlist->newindex((void **) &parypt);
9760 *parypt = pts[i];
9761 }
9762 } else if (loc == INTETRAHEDRON) {
9763 pts = (point *) &(searchtet->tet[4]);
9764 for (i = 0; i < 4; i++) {
9765 cavetetvertlist->newindex((void **) &parypt);
9766 *parypt = pts[i];
9767 }
9768 } else if (loc == ONFACE) {
9769 pts = (point *) &(searchtet->tet[4]);
9770 for (i = 0; i < 3; i++) {
9771 cavetetvertlist->newindex((void **) &parypt);
9772 *parypt = pts[i];
9773 }
9774 if (pts[3] != dummypoint) {
9775 cavetetvertlist->newindex((void **) &parypt);
9776 *parypt = pts[3];
9777 }
9778 fsym(*searchtet, spintet);
9779 if (oppo(spintet) != dummypoint) {
9780 cavetetvertlist->newindex((void **) &parypt);
9781 *parypt = oppo(spintet);
9782 }
9783 } else if (loc == ONEDGE) {
9784 spintet = *searchtet;
9785 cavetetvertlist->newindex((void **) &parypt);
9786 *parypt = org(spintet);
9787 cavetetvertlist->newindex((void **) &parypt);
9788 *parypt = dest(spintet);
9789 while (1) {
9790 if (apex(spintet) != dummypoint) {
9791 cavetetvertlist->newindex((void **) &parypt);
9792 *parypt = apex(spintet);
9793 }
9794 fnextself(spintet);
9795 if (spintet.tet == searchtet->tet) break;
9796 }
9797 }
9798
9799 int rejptflag = (ivf->rejflag & 4);
9800 REAL rd;
9801 pts = NULL;
9802
9803 for (i = 0; i < cavetetvertlist->objects; i++) {
9804 parypt = (point *) fastlookup(cavetetvertlist, i);
9805 rd = distance(*parypt, insertpt);
9806 // Is the point very close to an existing point?
9807 if (rd < b->minedgelength) {
9808 pts = parypt;
9809 loc = NEARVERTEX;
9810 break;
9811 }
9812 if (rejptflag) {
9813 // Is the point encroaches upon an existing point?
9814 if (rd < (0.5 * (*parypt)[pointmtrindex])) {
9815 pts = parypt;
9816 loc = ENCVERTEX;
9817 break;
9818 }
9819 }
9820 }
9821 cavetetvertlist->restart(); // Clear the work list.
9822
9823 if (pts != NULL) {
9824 // The point is either too close to an existing vertex (NEARVERTEX)
9825 // or encroaches upon (inside the protecting ball) of that vertex.
9826 if (loc == NEARVERTEX) {
9827 if (b->nomergevertex) { // -M0/1 option.
9828 // In this case, we still insert this vertex. Although it is very
9829 // close to an existing vertex. Give a warning, anyway.
9830 if (!b->quiet) {
9831 printf("Warning: Two points, %d and %d, are very close.\n",
9832 pointmark(insertpt), pointmark(*pts));
9833 printf(" Creating a very short edge (len = %g) (< %g).\n",
9834 rd, b->minedgelength);
9835 printf(" You may try a smaller tolerance (-T) (current is %g)\n",
9836 b->epsilon);
9837 printf(" to avoid this warning.\n");
9838 }
9839 } else {
9840 insertpt[3] = rd; // Only for reporting.
9841 setpoint2ppt(insertpt, *pts);
9842 insertpoint_abort(splitseg, ivf);
9843 ivf->iloc = (int) loc;
9844 return 0;
9845 }
9846 } else { // loc == ENCVERTEX
9847 // The point lies inside the protection ball.
9848 setpoint2ppt(insertpt, *pts);
9849 insertpoint_abort(splitseg, ivf);
9850 ivf->iloc = (int) loc;
9851 return 0;
9852 }
9853 }
9854 } // if (b->plc && (loc != INSTAR))
9855
9856 if (b->weighted || ivf->cdtflag || ivf->smlenflag
9857 ) {
9858 // There may be other vertices inside C(p). We need to find them.
9859 // Collect all vertices of C(p).
9860 for (i = 0; i < caveoldtetlist->objects; i++) {
9861 cavetet = (triface *) fastlookup(caveoldtetlist, i);
9862 //assert(infected(*cavetet));
9863 pts = (point *) &(cavetet->tet[4]);
9864 for (j = 0; j < 4; j++) {
9865 if (pts[j] != dummypoint) {
9866 if (!pinfected(pts[j])) {
9867 pinfect(pts[j]);
9868 cavetetvertlist->newindex((void **) &parypt);
9869 *parypt = pts[j];
9870 }
9871 }
9872 } // j
9873 } // i
9874 // Uninfect all collected (cavity) vertices.
9875 for (i = 0; i < cavetetvertlist->objects; i++) {
9876 parypt = (point *) fastlookup(cavetetvertlist, i);
9877 puninfect(*parypt);
9878 }
9879 if (ivf->smlenflag) {
9880 REAL len;
9881 // Get the length of the shortest edge connecting to 'newpt'.
9882 parypt = (point *) fastlookup(cavetetvertlist, 0);
9883 ivf->smlen = distance(*parypt, insertpt);
9884 ivf->parentpt = *parypt;
9885 for (i = 1; i < cavetetvertlist->objects; i++) {
9886 parypt = (point *) fastlookup(cavetetvertlist, i);
9887 len = distance(*parypt, insertpt);
9888 if (len < ivf->smlen) {
9889 ivf->smlen = len;
9890 ivf->parentpt = *parypt;
9891 }
9892 }
9893 }
9894 }
9895
9896
9897 if (ivf->cdtflag) {
9898 // Unmark tets.
9899 for (i = 0; i < caveoldtetlist->objects; i++) {
9900 cavetet = (triface *) fastlookup(caveoldtetlist, i);
9901 unmarktest(*cavetet);
9902 }
9903 for (i = 0; i < cavebdrylist->objects; i++) {
9904 cavetet = (triface *) fastlookup(cavebdrylist, i);
9905 unmarktest(*cavetet);
9906 }
9907 // Clean up arrays which are not needed.
9908 cavetetlist->restart();
9909 if (checksubsegflag) {
9910 cavetetseglist->restart();
9911 }
9912 if (checksubfaceflag) {
9913 cavetetshlist->restart();
9914 }
9915 return 1;
9916 }
9917
9918 // Before re-mesh C(p). Process the segments and subfaces which are on the
9919 // boundary of C(p). Make sure that each such segment or subface is
9920 // connecting to a tet outside C(p). So we can re-connect them to the
9921 // new tets inside the C(p) later.
9922
9923 if (checksubsegflag) {
9924 for (i = 0; i < cavetetseglist->objects; i++) {
9925 paryseg = (face *) fastlookup(cavetetseglist, i);
9926 // Operate on it if it is not the splitting segment, i.e., in sC(p).
9927 if (!smarktested(*paryseg)) {
9928 // Check if the segment is inside the cavity.
9929 // 'j' counts the num of adjacent tets of this seg.
9930 // 'k' counts the num of adjacent tets which are 'sinfected'.
9931 j = k = 0;
9932 sstpivot1(*paryseg, neightet);
9933 spintet = neightet;
9934 while (1) {
9935 j++;
9936 if (!infected(spintet)) {
9937 neineitet = spintet; // An outer tet. Remember it.
9938 } else {
9939 k++; // An in tet.
9940 }
9941 fnextself(spintet);
9942 if (spintet.tet == neightet.tet) break;
9943 }
9944 // assert(j > 0);
9945 if (k == 0) {
9946 // The segment is not connect to C(p) anymore. Remove it by
9947 // Replacing it by the last entry of this list.
9948 s = cavetetseglist->objects - 1;
9949 checkseg = * (face *) fastlookup(cavetetseglist, s);
9950 *paryseg = checkseg;
9951 cavetetseglist->objects--;
9952 i--;
9953 } else if (k < j) {
9954 // The segment is on the boundary of C(p).
9955 sstbond1(*paryseg, neineitet);
9956 } else { // k == j
9957 // The segment is inside C(p).
9958 if (!ivf->splitbdflag) {
9959 checkseg = *paryseg;
9960 sinfect(checkseg); // Flag it as an interior segment.
9961 caveencseglist->newindex((void **) &paryseg);
9962 *paryseg = checkseg;
9963 } else {
9964 assert(0); // Not possible.
9965 }
9966 }
9967 } else {
9968 // assert(smarktested(*paryseg));
9969 // Flag it as an interior segment. Do not queue it, since it will
9970 // be deleted after the segment splitting.
9971 sinfect(*paryseg);
9972 }
9973 } // i
9974 } // if (checksubsegflag)
9975
9976 if (checksubfaceflag) {
9977 for (i = 0; i < cavetetshlist->objects; i++) {
9978 parysh = (face *) fastlookup(cavetetshlist, i);
9979 // Operate on it if it is not inside the sub-cavity sC(p).
9980 if (!smarktested(*parysh)) {
9981 // Check if this subface is inside the cavity.
9982 k = 0;
9983 for (j = 0; j < 2; j++) {
9984 stpivot(*parysh, neightet);
9985 if (!infected(neightet)) {
9986 checksh = *parysh; // Remember this side.
9987 } else {
9988 k++;
9989 }
9990 sesymself(*parysh);
9991 }
9992 if (k == 0) {
9993 // The subface is not connected to C(p). Remove it.
9994 s = cavetetshlist->objects - 1;
9995 checksh = * (face *) fastlookup(cavetetshlist, s);
9996 *parysh = checksh;
9997 cavetetshlist->objects--;
9998 i--;
9999 } else if (k == 1) {
10000 // This side is the outer boundary of C(p).
10001 *parysh = checksh;
10002 } else { // k == 2
10003 if (!ivf->splitbdflag) {
10004 checksh = *parysh;
10005 sinfect(checksh); // Flag it.
10006 caveencshlist->newindex((void **) &parysh);
10007 *parysh = checksh;
10008 } else {
10009 assert(0); // Not possible.
10010 }
10011 }
10012 } else {
10013 // assert(smarktested(*parysh));
10014 // Flag it as an interior subface. Do not queue it. It will be
10015 // deleted after the facet point insertion.
10016 sinfect(*parysh);
10017 }
10018 } // i
10019 } // if (checksubfaceflag)
10020
10021 // Create new tetrahedra to fill the cavity.
10022
10023 for (i = 0; i < cavebdrylist->objects; i++) {
10024 cavetet = (triface *) fastlookup(cavebdrylist, i);
10025 neightet = *cavetet;
10026 unmarktest(neightet); // Unmark it.
10027 // Get the oldtet (inside the cavity).
10028 fsym(neightet, oldtet);
10029 if (apex(neightet) != dummypoint) {
10030 // Create a new tet in the cavity.
10031 maketetrahedron(&newtet);
10032 setorg(newtet, dest(neightet));
10033 setdest(newtet, org(neightet));
10034 setapex(newtet, apex(neightet));
10035 setoppo(newtet, insertpt);
10036 } else {
10037 // Create a new hull tet.
10038 hullsize++;
10039 maketetrahedron(&newtet);
10040 setorg(newtet, org(neightet));
10041 setdest(newtet, dest(neightet));
10042 setapex(newtet, insertpt);
10043 setoppo(newtet, dummypoint); // It must opposite to face 3.
10044 // Adjust back to the cavity bounday face.
10045 esymself(newtet);
10046 }
10047 // The new tet inherits attribtes from the old tet.
10048 for (j = 0; j < numelemattrib; j++) {
10049 attrib = elemattribute(oldtet.tet, j);
10050 setelemattribute(newtet.tet, j, attrib);
10051 }
10052 if (b->varvolume) {
10053 volume = volumebound(oldtet.tet);
10054 setvolumebound(newtet.tet, volume);
10055 }
10056 // Connect newtet <==> neightet, this also disconnect the old bond.
10057 bond(newtet, neightet);
10058 // oldtet still connects to neightet.
10059 *cavetet = oldtet; // *cavetet = newtet;
10060 } // i
10061
10062 // Set a handle for speeding point location.
10063 recenttet = newtet;
10064 //setpoint2tet(insertpt, encode(newtet));
10065 setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
10066
10067 // Re-use this list to save new interior cavity faces.
10068 cavetetlist->restart();
10069
10070 // Connect adjacent new tetrahedra together.
10071 for (i = 0; i < cavebdrylist->objects; i++) {
10072 cavetet = (triface *) fastlookup(cavebdrylist, i);
10073 // cavtet is an oldtet, get the newtet at this face.
10074 oldtet = *cavetet;
10075 fsym(oldtet, neightet);
10076 fsym(neightet, newtet);
10077 // Comment: oldtet and newtet must be at the same directed edge.
10078 // Connect the three other faces of this newtet.
10079 for (j = 0; j < 3; j++) {
10080 esym(newtet, neightet); // Go to the face.
10081 if (neightet.tet[neightet.ver & 3] == NULL) {
10082 // Find the adjacent face of this newtet.
10083 spintet = oldtet;
10084 while (1) {
10085 fnextself(spintet);
10086 if (!infected(spintet)) break;
10087 }
10088 fsym(spintet, newneitet);
10089 esymself(newneitet);
10090 assert(newneitet.tet[newneitet.ver & 3] == NULL);
10091 bond(neightet, newneitet);
10092 if (ivf->lawson > 1) {
10093 cavetetlist->newindex((void **) &parytet);
10094 *parytet = neightet;
10095 }
10096 }
10097 //setpoint2tet(org(newtet), encode(newtet));
10098 setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
10099 enextself(newtet);
10100 enextself(oldtet);
10101 }
10102 *cavetet = newtet; // Save the new tet.
10103 } // i
10104
10105 if (checksubfaceflag) {
10106 // Connect subfaces on the boundary of the cavity to the new tets.
10107 for (i = 0; i < cavetetshlist->objects; i++) {
10108 parysh = (face *) fastlookup(cavetetshlist, i);
10109 // Connect it if it is not a missing subface.
10110 if (!sinfected(*parysh)) {
10111 stpivot(*parysh, neightet);
10112 fsym(neightet, spintet);
10113 sesymself(*parysh);
10114 tsbond(spintet, *parysh);
10115 }
10116 }
10117 }
10118
10119 if (checksubsegflag) {
10120 // Connect segments on the boundary of the cavity to the new tets.
10121 for (i = 0; i < cavetetseglist->objects; i++) {
10122 paryseg = (face *) fastlookup(cavetetseglist, i);
10123 // Connect it if it is not a missing segment.
10124 if (!sinfected(*paryseg)) {
10125 sstpivot1(*paryseg, neightet);
10126 spintet = neightet;
10127 while (1) {
10128 tssbond1(spintet, *paryseg);
10129 fnextself(spintet);
10130 if (spintet.tet == neightet.tet) break;
10131 }
10132 }
10133 }
10134 }
10135
10136 if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10137 ((splitseg != NULL) && (splitseg->sh != NULL))) {
10138 // Split a subface or a segment.
10139 sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
10140 }
10141
10142 if (checksubfaceflag) {
10143 if (ivf->splitbdflag) {
10144 // Recover new subfaces in C(p).
10145 for (i = 0; i < caveshbdlist->objects; i++) {
10146 // Get an old subface at edge [a, b].
10147 parysh = (face *) fastlookup(caveshbdlist, i);
10148 spivot(*parysh, checksh); // The new subface [a, b, p].
10149 // Do not recover a deleted new face (degenerated).
10150 if (checksh.sh[3] != NULL) {
10151 // Note that the old subface still connects to adjacent old tets
10152 // of C(p), which still connect to the tets outside C(p).
10153 stpivot(*parysh, neightet);
10154 assert(infected(neightet));
10155 // Find the adjacent tet containing the edge [a,b] outside C(p).
10156 spintet = neightet;
10157 while (1) {
10158 fnextself(spintet);
10159 if (!infected(spintet)) break;
10160 assert(spintet.tet != neightet.tet);
10161 }
10162 // The adjacent tet connects to a new tet in C(p).
10163 fsym(spintet, neightet);
10164 assert(!infected(neightet));
10165 // Find the tet containing the face [a, b, p].
10166 spintet = neightet;
10167 while (1) {
10168 fnextself(spintet);
10169 if (apex(spintet) == insertpt) break;
10170 assert(spintet.tet != neightet.tet);
10171 }
10172 // Adjust the edge direction in spintet and checksh.
10173 if (sorg(checksh) != org(spintet)) {
10174 sesymself(checksh);
10175 assert(sorg(checksh) == org(spintet));
10176 }
10177 assert(sdest(checksh) == dest(spintet));
10178 // Connect the subface to two adjacent tets.
10179 tsbond(spintet, checksh);
10180 fsymself(spintet);
10181 sesymself(checksh);
10182 tsbond(spintet, checksh);
10183 } // if (checksh.sh[3] != NULL)
10184 }
10185 // There should be no missing interior subfaces in C(p).
10186 assert(caveencshlist->objects == 0l);
10187 } else {
10188 // The Boundary recovery phase.
10189 // Put all new subfaces into stack for recovery.
10190 for (i = 0; i < caveshbdlist->objects; i++) {
10191 // Get an old subface at edge [a, b].
10192 parysh = (face *) fastlookup(caveshbdlist, i);
10193 spivot(*parysh, checksh); // The new subface [a, b, p].
10194 // Do not recover a deleted new face (degenerated).
10195 if (checksh.sh[3] != NULL) {
10196 subfacstack->newindex((void **) &parysh);
10197 *parysh = checksh;
10198 }
10199 }
10200 // Put all interior subfaces into stack for recovery.
10201 for (i = 0; i < caveencshlist->objects; i++) {
10202 parysh = (face *) fastlookup(caveencshlist, i);
10203 assert(sinfected(*parysh));
10204 // Some subfaces inside C(p) might be split in sinsertvertex().
10205 // Only queue those faces which are not split.
10206 if (!smarktested(*parysh)) {
10207 checksh = *parysh;
10208 suninfect(checksh);
10209 stdissolve(checksh); // Detach connections to old tets.
10210 subfacstack->newindex((void **) &parysh);
10211 *parysh = checksh;
10212 }
10213 }
10214 }
10215 } // if (checksubfaceflag)
10216
10217 if (checksubsegflag) {
10218 if (ivf->splitbdflag) {
10219 if (splitseg != NULL) {
10220 // Recover the two new subsegments in C(p).
10221 for (i = 0; i < cavesegshlist->objects; i++) {
10222 paryseg = (face *) fastlookup(cavesegshlist, i);
10223 // Insert this subsegment into C(p).
10224 checkseg = *paryseg;
10225 // Get the adjacent new subface.
10226 checkseg.shver = 0;
10227 spivot(checkseg, checksh);
10228 if (checksh.sh != NULL) {
10229 // Get the adjacent new tetrahedron.
10230 stpivot(checksh, neightet);
10231 } else {
10232 // It's a dangling segment.
10233 point2tetorg(sorg(checkseg), neightet);
10234 finddirection(&neightet, sdest(checkseg));
10235 assert(dest(neightet) == sdest(checkseg));
10236 }
10237 assert(!infected(neightet));
10238 sstbond1(checkseg, neightet);
10239 spintet = neightet;
10240 while (1) {
10241 tssbond1(spintet, checkseg);
10242 fnextself(spintet);
10243 if (spintet.tet == neightet.tet) break;
10244 }
10245 }
10246 } // if (splitseg != NULL)
10247 // There should be no interior segment in C(p).
10248 assert(caveencseglist->objects == 0l);
10249 } else {
10250 // The Boundary Recovery Phase.
10251 // Queue missing segments in C(p) for recovery.
10252 if (splitseg != NULL) {
10253 // Queue two new subsegments in C(p) for recovery.
10254 for (i = 0; i < cavesegshlist->objects; i++) {
10255 paryseg = (face *) fastlookup(cavesegshlist, i);
10256 checkseg = *paryseg;
10257 //sstdissolve1(checkseg); // It has not been connected yet.
10258 s = randomnation(subsegstack->objects + 1);
10259 subsegstack->newindex((void **) &paryseg);
10260 *paryseg = * (face *) fastlookup(subsegstack, s);
10261 paryseg = (face *) fastlookup(subsegstack, s);
10262 *paryseg = checkseg;
10263 }
10264 } // if (splitseg != NULL)
10265 for (i = 0; i < caveencseglist->objects; i++) {
10266 paryseg = (face *) fastlookup(caveencseglist, i);
10267 assert(sinfected(*paryseg));
10268 if (!smarktested(*paryseg)) { // It may be split.
10269 checkseg = *paryseg;
10270 suninfect(checkseg);
10271 sstdissolve1(checkseg); // Detach connections to old tets.
10272 s = randomnation(subsegstack->objects + 1);
10273 subsegstack->newindex((void **) &paryseg);
10274 *paryseg = * (face *) fastlookup(subsegstack, s);
10275 paryseg = (face *) fastlookup(subsegstack, s);
10276 *paryseg = checkseg;
10277 }
10278 }
10279 }
10280 } // if (checksubsegflag)
10281
10282 if (b->weighted
10283 ) {
10284 // Some vertices may be completed inside the cavity. They must be
10285 // detected and added to recovering list.
10286 // Since every "live" vertex must contain a pointer to a non-dead
10287 // tetrahedron, we can check for each vertex this pointer.
10288 for (i = 0; i < cavetetvertlist->objects; i++) {
10289 pts = (point *) fastlookup(cavetetvertlist, i);
10290 decode(point2tet(*pts), *searchtet);
10291 assert(searchtet->tet != NULL); // No tet has been deleted yet.
10292 if (infected(*searchtet)) {
10293 if (b->weighted) {
10294 if (b->verbose > 1) {
10295 printf(" Point #%d is non-regular after the insertion of #%d.\n",
10296 pointmark(*pts), pointmark(insertpt));
10297 }
10298 setpointtype(*pts, NREGULARVERTEX);
10299 nonregularcount++;
10300 }
10301 }
10302 }
10303 }
10304
10305 if (ivf->chkencflag & 1) {
10306 // Queue all segment outside C(p).
10307 for (i = 0; i < cavetetseglist->objects; i++) {
10308 paryseg = (face *) fastlookup(cavetetseglist, i);
10309 // Skip if it is the split segment.
10310 if (!sinfected(*paryseg)) {
10311 enqueuesubface(badsubsegs, paryseg);
10312 }
10313 }
10314 if (splitseg != NULL) {
10315 // Queue the two new subsegments inside C(p).
10316 for (i = 0; i < cavesegshlist->objects; i++) {
10317 paryseg = (face *) fastlookup(cavesegshlist, i);
10318 enqueuesubface(badsubsegs, paryseg);
10319 }
10320 }
10321 } // if (chkencflag & 1)
10322
10323 if (ivf->chkencflag & 2) {
10324 // Queue all subfaces outside C(p).
10325 for (i = 0; i < cavetetshlist->objects; i++) {
10326 parysh = (face *) fastlookup(cavetetshlist, i);
10327 // Skip if it is a split subface.
10328 if (!sinfected(*parysh)) {
10329 enqueuesubface(badsubfacs, parysh);
10330 }
10331 }
10332 // Queue all new subfaces inside C(p).
10333 for (i = 0; i < caveshbdlist->objects; i++) {
10334 // Get an old subface at edge [a, b].
10335 parysh = (face *) fastlookup(caveshbdlist, i);
10336 spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
10337 // Do not recover a deleted new face (degenerated).
10338 if (checksh.sh[3] != NULL) {
10339 enqueuesubface(badsubfacs, &checksh);
10340 }
10341 }
10342 } // if (chkencflag & 2)
10343
10344 if (ivf->chkencflag & 4) {
10345 // Queue all new tetrahedra in C(p).
10346 for (i = 0; i < cavebdrylist->objects; i++) {
10347 cavetet = (triface *) fastlookup(cavebdrylist, i);
10348 enqueuetetrahedron(cavetet);
10349 }
10350 }
10351
10352 // C(p) is re-meshed successfully.
10353
10354 // Delete the old tets in C(p).
10355 for (i = 0; i < caveoldtetlist->objects; i++) {
10356 searchtet = (triface *) fastlookup(caveoldtetlist, i);
10357 if (ishulltet(*searchtet)) {
10358 hullsize--;
10359 }
10360 tetrahedrondealloc(searchtet->tet);
10361 }
10362
10363 if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10364 ((splitseg != NULL) && (splitseg->sh != NULL))) {
10365 // Delete the old subfaces in sC(p).
10366 for (i = 0; i < caveshlist->objects; i++) {
10367 parysh = (face *) fastlookup(caveshlist, i);
10368 if (checksubfaceflag) {//if (bowywat == 2) {
10369 // It is possible that this subface still connects to adjacent
10370 // tets which are not in C(p). If so, clear connections in the
10371 // adjacent tets at this subface.
10372 stpivot(*parysh, neightet);
10373 if (neightet.tet != NULL) {
10374 if (neightet.tet[4] != NULL) {
10375 // Found an adjacent tet. It must be not in C(p).
10376 assert(!infected(neightet));
10377 tsdissolve(neightet);
10378 fsymself(neightet);
10379 assert(!infected(neightet));
10380 tsdissolve(neightet);
10381 }
10382 }
10383 }
10384 shellfacedealloc(subfaces, parysh->sh);
10385 }
10386 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10387 // Delete the old segment in sC(p).
10388 shellfacedealloc(subsegs, splitseg->sh);
10389 }
10390 }
10391
10392 if (ivf->lawson) {
10393 for (i = 0; i < cavebdrylist->objects; i++) {
10394 searchtet = (triface *) fastlookup(cavebdrylist, i);
10395 flippush(flipstack, searchtet);
10396 }
10397 if (ivf->lawson > 1) {
10398 for (i = 0; i < cavetetlist->objects; i++) {
10399 searchtet = (triface *) fastlookup(cavetetlist, i);
10400 flippush(flipstack, searchtet);
10401 }
10402 }
10403 }
10404
10405
10406 // Clean the working lists.
10407
10408 caveoldtetlist->restart();
10409 cavebdrylist->restart();
10410 cavetetlist->restart();
10411
10412 if (checksubsegflag) {
10413 cavetetseglist->restart();
10414 caveencseglist->restart();
10415 }
10416
10417 if (checksubfaceflag) {
10418 cavetetshlist->restart();
10419 caveencshlist->restart();
10420 }
10421
10422 if (b->weighted || ivf->validflag) {
10423 cavetetvertlist->restart();
10424 }
10425
10426 if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10427 ((splitseg != NULL) && (splitseg->sh != NULL))) {
10428 caveshlist->restart();
10429 caveshbdlist->restart();
10430 cavesegshlist->restart();
10431 }
10432
10433 return 1; // Point is inserted.
10434}
10435
10436///////////////////////////////////////////////////////////////////////////////
10437// //
10438// insertpoint_abort() Abort the insertion of a new vertex. //
10439// //
10440// The cavity will be restored. All working lists are cleared. //
10441// //
10442///////////////////////////////////////////////////////////////////////////////
10443
10444void tetgenmesh::insertpoint_abort(face *splitseg, insertvertexflags *ivf)
10445{
10446 triface *cavetet;
10447 face *parysh;
10448 int i;
10449
10450 for (i = 0; i < caveoldtetlist->objects; i++) {
10451 cavetet = (triface *) fastlookup(caveoldtetlist, i);
10452 uninfect(*cavetet);
10453 unmarktest(*cavetet);
10454 }
10455 for (i = 0; i < cavebdrylist->objects; i++) {
10456 cavetet = (triface *) fastlookup(cavebdrylist, i);
10457 unmarktest(*cavetet);
10458 }
10459 cavetetlist->restart();
10460 cavebdrylist->restart();
10461 caveoldtetlist->restart();
10462 cavetetseglist->restart();
10463 cavetetshlist->restart();
10464 if (ivf->splitbdflag) {
10465 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10466 sunmarktest(*splitseg);
10467 }
10468 for (i = 0; i < caveshlist->objects; i++) {
10469 parysh = (face *) fastlookup(caveshlist, i);
10470 assert(smarktested(*parysh));
10471 sunmarktest(*parysh);
10472 }
10473 caveshlist->restart();
10474 cavesegshlist->restart();
10475 }
10476}
10477
10478//// ////
10479//// ////
10480//// flip_cxx /////////////////////////////////////////////////////////////////
10481
10482//// delaunay_cxx /////////////////////////////////////////////////////////////
10483//// ////
10484//// ////
10485
10486///////////////////////////////////////////////////////////////////////////////
10487// //
10488// transfernodes() Read the vertices from the input (tetgenio). //
10489// //
10490// Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
10491// All points are indexed (the first point index is 'in->firstnumber'). Each //
10492// point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
10493// ...) and the diameter (longest) of the point set are calculated. //
10494// //
10495///////////////////////////////////////////////////////////////////////////////
10496
10497void tetgenmesh::transfernodes()
10498{
10499 point pointloop;
10500 REAL x, y, z, w;
10501 int coordindex;
10502 int attribindex;
10503 int mtrindex;
10504 int i, j;
10505
10506 if (b->psc) {
10507 assert(in->pointparamlist != NULL);
10508 }
10509
10510 // Read the points.
10511 coordindex = 0;
10512 attribindex = 0;
10513 mtrindex = 0;
10514 for (i = 0; i < in->numberofpoints; i++) {
10515 makepoint(&pointloop, UNUSEDVERTEX);
10516 // Read the point coordinates.
10517 x = pointloop[0] = in->pointlist[coordindex++];
10518 y = pointloop[1] = in->pointlist[coordindex++];
10519 z = pointloop[2] = in->pointlist[coordindex++];
10520 // Read the point attributes. (Including point weights.)
10521 for (j = 0; j < in->numberofpointattributes; j++) {
10522 pointloop[3 + j] = in->pointattributelist[attribindex++];
10523 }
10524 // Read the point metric tensor.
10525 for (j = 0; j < in->numberofpointmtrs; j++) {
10526 pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
10527 }
10528 if (b->weighted) { // -w option
10529 if (in->numberofpointattributes > 0) {
10530 // The first point attribute is its weight.
10531 //w = in->pointattributelist[in->numberofpointattributes * i];
10532 w = pointloop[3];
10533 } else {
10534 // No given weight available. Default choose the maximum
10535 // absolute value among its coordinates.
10536 w = fabs(x);
10537 if (w < fabs(y)) w = fabs(y);
10538 if (w < fabs(z)) w = fabs(z);
10539 }
10540 if (b->weighted_param == 0) {
10541 pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
10542 } else { // -w1 option
10543 pointloop[3] = w; // Regular tetrahedralization.
10544 }
10545 }
10546 // Determine the smallest and largest x, y and z coordinates.
10547 if (i == 0) {
10548 xmin = xmax = x;
10549 ymin = ymax = y;
10550 zmin = zmax = z;
10551 } else {
10552 xmin = (x < xmin) ? x : xmin;
10553 xmax = (x > xmax) ? x : xmax;
10554 ymin = (y < ymin) ? y : ymin;
10555 ymax = (y > ymax) ? y : ymax;
10556 zmin = (z < zmin) ? z : zmin;
10557 zmax = (z > zmax) ? z : zmax;
10558 }
10559 if (b->psc) {
10560 // Read the geometry parameters.
10561 setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
10562 setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
10563 setpointgeomtag(pointloop, in->pointparamlist[i].tag);
10564 if (in->pointparamlist[i].type == 0) {
10565 setpointtype(pointloop, RIDGEVERTEX);
10566 } else if (in->pointparamlist[i].type == 1) {
10567 setpointtype(pointloop, FREESEGVERTEX);
10568 } else if (in->pointparamlist[i].type == 2) {
10569 setpointtype(pointloop, FREEFACETVERTEX);
10570 } else if (in->pointparamlist[i].type == 3) {
10571 setpointtype(pointloop, FREEVOLVERTEX);
10572 }
10573 }
10574 }
10575
10576 // 'longest' is the largest possible edge length formed by input vertices.
10577 x = xmax - xmin;
10578 y = ymax - ymin;
10579 z = zmax - zmin;
10580 longest = sqrt(x * x + y * y + z * z);
10581 if (longest == 0.0) {
10582 printf("Error: The point set is trivial.\n");
10583 terminatetetgen(this, 3);
10584 }
10585
10586 // Two identical points are distinguished by 'lengthlimit'.
10587 if (b->minedgelength == 0.0) {
10588 b->minedgelength = longest * b->epsilon;
10589 }
10590}
10591
10592///////////////////////////////////////////////////////////////////////////////
10593// //
10594// hilbert_init() Initialize the Gray code permutation table. //
10595// //
10596// The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray //
10597// code sequences traveled by the 1st order Hilbert curve in 3 dimensions. //
10598// The first column is the Gray code of the entry point of the curve, and //
10599// the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
10600// the exit point of curve lies. //
10601// //
10602// The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
10603// indices from 0 to 7, modulo by '3'. The code for generating this table is //
10604// from: http://graphics.stanford.edu/~seander/bithacks.html. //
10605// //
10606///////////////////////////////////////////////////////////////////////////////
10607
10608void tetgenmesh::hilbert_init(int n)
10609{
10610 int gc[8], N, mask, travel_bit;
10611 int e, d, f, k, g;
10612 int v, c;
10613 int i;
10614
10615 N = (n == 2) ? 4 : 8;
10616 mask = (n == 2) ? 3 : 7;
10617
10618 // Generate the Gray code sequence.
10619 for (i = 0; i < N; i++) {
10620 gc[i] = i ^ (i >> 1);
10621 }
10622
10623 for (e = 0; e < N; e++) {
10624 for (d = 0; d < n; d++) {
10625 // Calculate the end point (f).
10626 f = e ^ (1 << d); // Toggle the d-th bit of 'e'.
10627 // travel_bit = 2**p, the bit we want to travel.
10628 travel_bit = e ^ f;
10629 for (i = 0; i < N; i++) {
10630 // // Rotate gc[i] left by (p + 1) % n bits.
10631 k = gc[i] * (travel_bit * 2);
10632 g = ((k | (k / N)) & mask);
10633 // Calculate the permuted Gray code by xor with the start point (e).
10634 transgc[e][d][i] = (g ^ e);
10635 }
10636 assert(transgc[e][d][0] == e);
10637 assert(transgc[e][d][N - 1] == f);
10638 } // d
10639 } // e
10640
10641 // Count the consecutive '1' bits (trailing) on the right.
10642 tsb1mod3[0] = 0;
10643 for (i = 1; i < N; i++) {
10644 v = ~i; // Count the 0s.
10645 v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
10646 for (c = 0; v; c++) {
10647 v >>= 1;
10648 }
10649 tsb1mod3[i] = c % n;
10650 }
10651}
10652
10653///////////////////////////////////////////////////////////////////////////////
10654// //
10655// hilbert_sort3() Sort points using the 3d Hilbert curve. //
10656// //
10657///////////////////////////////////////////////////////////////////////////////
10658
10659int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
10660 REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
10661 REAL bzmin, REAL bzmax)
10662{
10663 point swapvert;
10664 int axis, d;
10665 REAL split;
10666 int i, j;
10667
10668
10669 // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
10670 // correspoding to x-, or y- or z-axis.
10671 axis = (gc0 ^ gc1) >> 1;
10672
10673 // Calulate the split position along the axis.
10674 if (axis == 0) {
10675 split = 0.5 * (bxmin + bxmax);
10676 } else if (axis == 1) {
10677 split = 0.5 * (bymin + bymax);
10678 } else { // == 2
10679 split = 0.5 * (bzmin + bzmax);
10680 }
10681
10682 // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
10683 // of the axis is to the positive of the axis, otherwise, it is -1.
10684 d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
10685
10686
10687 // Partition the vertices into left- and right-arrays such that left points
10688 // have Hilbert indices lower than the right points.
10689 i = 0;
10690 j = arraysize - 1;
10691
10692 // Partition the vertices into left- and right-arrays.
10693 if (d > 0) {
10694 do {
10695 for (; i < arraysize; i++) {
10696 if (vertexarray[i][axis] >= split) break;
10697 }
10698 for (; j >= 0; j--) {
10699 if (vertexarray[j][axis] < split) break;
10700 }
10701 // Is the partition finished?
10702 if (i == (j + 1)) break;
10703 // Swap i-th and j-th vertices.
10704 swapvert = vertexarray[i];
10705 vertexarray[i] = vertexarray[j];
10706 vertexarray[j] = swapvert;
10707 // Continue patitioning the array;
10708 } while (true);
10709 } else {
10710 do {
10711 for (; i < arraysize; i++) {
10712 if (vertexarray[i][axis] <= split) break;
10713 }
10714 for (; j >= 0; j--) {
10715 if (vertexarray[j][axis] > split) break;
10716 }
10717 // Is the partition finished?
10718 if (i == (j + 1)) break;
10719 // Swap i-th and j-th vertices.
10720 swapvert = vertexarray[i];
10721 vertexarray[i] = vertexarray[j];
10722 vertexarray[j] = swapvert;
10723 // Continue patitioning the array;
10724 } while (true);
10725 }
10726
10727 return i;
10728}
10729
10730void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
10731 REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
10732 REAL bzmin, REAL bzmax, int depth)
10733{
10734 REAL x1, x2, y1, y2, z1, z2;
10735 int p[9], w, e_w, d_w, k, ei, di;
10736 int n = 3, mask = 7;
10737
10738 p[0] = 0;
10739 p[8] = arraysize;
10740
10741 // Sort the points according to the 1st order Hilbert curve in 3d.
10742 p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4],
10743 bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10744 p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2],
10745 bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10746 p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1],
10747 bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10748 p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2],
10749 transgc[e][d][2], transgc[e][d][3],
10750 bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
10751 p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4],
10752 transgc[e][d][5], transgc[e][d][6],
10753 bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
10754 p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4],
10755 transgc[e][d][4], transgc[e][d][5],
10756 bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
10757 p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6],
10758 transgc[e][d][6], transgc[e][d][7],
10759 bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
10760
10761 if (b->hilbert_order > 0) {
10762 // A maximum order is prescribed.
10763 if ((depth + 1) == b->hilbert_order) {
10764 // The maximum prescribed order is reached.
10765 return;
10766 }
10767 }
10768
10769 // Recursively sort the points in sub-boxes.
10770 for (w = 0; w < 8; w++) {
10771 // w is the local Hilbert index (NOT Gray code).
10772 // Sort into the sub-box either there are more than 2 points in it, or
10773 // the prescribed order of the curve is not reached yet.
10774 //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
10775 if ((p[w+1] - p[w]) > b->hilbert_limit) {
10776 // Calculcate the start point (ei) of the curve in this sub-box.
10777 // update e = e ^ (e(w) left_rotate (d+1)).
10778 if (w == 0) {
10779 e_w = 0;
10780 } else {
10781 // calculate e(w) = gc(2 * floor((w - 1) / 2)).
10782 k = 2 * ((w - 1) / 2);
10783 e_w = k ^ (k >> 1); // = gc(k).
10784 }
10785 k = e_w;
10786 e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
10787 ei = e ^ e_w;
10788 // Calulcate the direction (di) of the curve in this sub-box.
10789 // update d = (d + d(w) + 1) % n
10790 if (w == 0) {
10791 d_w = 0;
10792 } else {
10793 d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
10794 }
10795 di = (d + d_w + 1) % n;
10796 // Calculate the bounding box of the sub-box.
10797 if (transgc[e][d][w] & 1) { // x-axis
10798 x1 = 0.5 * (bxmin + bxmax);
10799 x2 = bxmax;
10800 } else {
10801 x1 = bxmin;
10802 x2 = 0.5 * (bxmin + bxmax);
10803 }
10804 if (transgc[e][d][w] & 2) { // y-axis
10805 y1 = 0.5 * (bymin + bymax);
10806 y2 = bymax;
10807 } else {
10808 y1 = bymin;
10809 y2 = 0.5 * (bymin + bymax);
10810 }
10811 if (transgc[e][d][w] & 4) { // z-axis
10812 z1 = 0.5 * (bzmin + bzmax);
10813 z2 = bzmax;
10814 } else {
10815 z1 = bzmin;
10816 z2 = 0.5 * (bzmin + bzmax);
10817 }
10818 hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di,
10819 x1, x2, y1, y2, z1, z2, depth+1);
10820 } // if (p[w+1] - p[w] > 1)
10821 } // w
10822}
10823
10824///////////////////////////////////////////////////////////////////////////////
10825// //
10826// brio_multiscale_sort() Sort the points using BRIO and Hilbert curve. //
10827// //
10828///////////////////////////////////////////////////////////////////////////////
10829
10830void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize,
10831 int threshold, REAL ratio, int *depth)
10832{
10833 int middle;
10834
10835 middle = 0;
10836 if (arraysize >= threshold) {
10837 (*depth)++;
10838 middle = (int)(arraysize * ratio);
10839 brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
10840 }
10841 // Sort the right-array (rnd-th round) using the Hilbert curve.
10842 hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
10843 xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
10844}
10845
10846///////////////////////////////////////////////////////////////////////////////
10847// //
10848// randomnation() Generate a random number between 0 and 'choices' - 1. //
10849// //
10850///////////////////////////////////////////////////////////////////////////////
10851
10852unsigned long tetgenmesh::randomnation(unsigned int choices)
10853{
10854 unsigned long newrandom;
10855
10856 if (choices >= 714025l) {
10857 newrandom = (randomseed * 1366l + 150889l) % 714025l;
10858 randomseed = (newrandom * 1366l + 150889l) % 714025l;
10859 newrandom = newrandom * (choices / 714025l) + randomseed;
10860 if (newrandom >= choices) {
10861 return newrandom - choices;
10862 } else {
10863 return newrandom;
10864 }
10865 } else {
10866 randomseed = (randomseed * 1366l + 150889l) % 714025l;
10867 return randomseed % choices;
10868 }
10869}
10870
10871///////////////////////////////////////////////////////////////////////////////
10872// //
10873// randomsample() Randomly sample the tetrahedra for point loation. //
10874// //
10875// Searching begins from one of handles: the input 'searchtet', a recently //
10876// encountered tetrahedron 'recenttet', or from one chosen from a random //
10877// sample. The choice is made by determining which one's origin is closest //
10878// to the point we are searching for. //
10879// //
10880///////////////////////////////////////////////////////////////////////////////
10881
10882void tetgenmesh::randomsample(point searchpt,triface *searchtet)
10883{
10884 tetrahedron *firsttet, *tetptr;
10885 point torg;
10886 void **sampleblock;
10887 uintptr_t alignptr;
10888 long sampleblocks, samplesperblock, samplenum;
10889 long tetblocks, i, j;
10890 REAL searchdist, dist;
10891
10892 if (b->verbose > 2) {
10893 printf(" Random sampling tetrahedra for searching point %d.\n",
10894 pointmark(searchpt));
10895 }
10896
10897 if (!nonconvex) {
10898 if (searchtet->tet == NULL) {
10899 // A null tet. Choose the recenttet as the starting tet.
10900 *searchtet = recenttet;
10901 // Recenttet should not be dead.
10902 assert(recenttet.tet[4] != NULL);
10903 }
10904
10905 // 'searchtet' should be a valid tetrahedron. Choose the base face
10906 // whose vertices must not be 'dummypoint'.
10907 searchtet->ver = 3;
10908 // Record the distance from its origin to the searching point.
10909 torg = org(*searchtet);
10910 searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
10911 (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
10912 (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
10913
10914 // If a recently encountered tetrahedron has been recorded and has not
10915 // been deallocated, test it as a good starting point.
10916 if (recenttet.tet != searchtet->tet) {
10917 recenttet.ver = 3;
10918 torg = org(recenttet);
10919 dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
10920 (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
10921 (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
10922 if (dist < searchdist) {
10923 *searchtet = recenttet;
10924 searchdist = dist;
10925 }
10926 }
10927 } else {
10928 // The mesh is non-convex. Do not use 'recenttet'.
10929 assert(samples >= 1l); // Make sure at least 1 sample.
10930 searchdist = longest;
10931 }
10932
10933 // Select "good" candidate using k random samples, taking the closest one.
10934 // The number of random samples taken is proportional to the fourth root
10935 // of the number of tetrahedra in the mesh.
10936 while (samples * samples * samples * samples < tetrahedrons->items) {
10937 samples++;
10938 }
10939 // Find how much blocks in current tet pool.
10940 tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1)
10941 / b->tetrahedraperblock;
10942 // Find the average samples per block. Each block at least have 1 sample.
10943 samplesperblock = 1 + (samples / tetblocks);
10944 sampleblocks = samples / samplesperblock;
10945 sampleblock = tetrahedrons->firstblock;
10946 for (i = 0; i < sampleblocks; i++) {
10947 alignptr = (uintptr_t) (sampleblock + 1);
10948 firsttet = (tetrahedron *)
10949 (alignptr + (uintptr_t) tetrahedrons->alignbytes
10950 - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
10951 for (j = 0; j < samplesperblock; j++) {
10952 if (i == tetblocks - 1) {
10953 // This is the last block.
10954 samplenum = randomnation((int)
10955 (tetrahedrons->maxitems - (i * b->tetrahedraperblock)));
10956 } else {
10957 samplenum = randomnation(b->tetrahedraperblock);
10958 }
10959 tetptr = (tetrahedron *)
10960 (firsttet + (samplenum * tetrahedrons->itemwords));
10961 torg = (point) tetptr[4];
10962 if (torg != (point) NULL) {
10963 dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
10964 (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
10965 (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
10966 if (dist < searchdist) {
10967 searchtet->tet = tetptr;
10968 searchtet->ver = 11; // torg = org(t);
10969 searchdist = dist;
10970 }
10971 } else {
10972 // A dead tet. Re-sample it.
10973 if (i != tetblocks - 1) j--;
10974 }
10975 }
10976 sampleblock = (void **) *sampleblock;
10977 }
10978}
10979
10980///////////////////////////////////////////////////////////////////////////////
10981// //
10982// locate() Find a tetrahedron containing a given point. //
10983// //
10984// Begins its search from 'searchtet', assume there is a line segment L from //
10985// a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
10986// towards 'searchpt' by traversing all faces intersected by L. //
10987// //
10988// On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
10989// returned value indicates one of the following cases: //
10990// - ONVERTEX, the search point lies on the origin of 'searchtet'. //
10991// - ONEDGE, the search point lies on an edge of 'searchtet'. //
10992// - ONFACE, the search point lies on a face of 'searchtet'. //
10993// - INTET, the search point lies in the interior of 'searchtet'. //
10994// - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a //
10995// hull face which is visible by the search point. //
10996// //
10997// WARNING: This routine is designed for convex triangulations, and will not //
10998// generally work after the holes and concavities have been carved. //
10999// //
11000///////////////////////////////////////////////////////////////////////////////
11001
11002enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt,
11003 triface* searchtet)
11004{
11005 point torg, tdest, tapex, toppo;
11006 enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
11007 REAL ori, oriorg, oridest, oriapex;
11008 enum locateresult loc = OUTSIDE;
11009 int t1ver;
11010 int s;
11011
11012 if (searchtet->tet == NULL) {
11013 // A null tet. Choose the recenttet as the starting tet.
11014 searchtet->tet = recenttet.tet;
11015 }
11016
11017 // Check if we are in the outside of the convex hull.
11018 if (ishulltet(*searchtet)) {
11019 // Get its adjacent tet (inside the hull).
11020 searchtet->ver = 3;
11021 fsymself(*searchtet);
11022 }
11023
11024 // Let searchtet be the face such that 'searchpt' lies above to it.
11025 for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
11026 torg = org(*searchtet);
11027 tdest = dest(*searchtet);
11028 tapex = apex(*searchtet);
11029 ori = orient3d(torg, tdest, tapex, searchpt);
11030 if (ori < 0.0) break;
11031 }
11032 assert(searchtet->ver != 4);
11033
11034 // Walk through tetrahedra to locate the point.
11035 while (true) {
11036
11037 toppo = oppo(*searchtet);
11038
11039 // Check if the vertex is we seek.
11040 if (toppo == searchpt) {
11041 // Adjust the origin of searchtet to be searchpt.
11042 esymself(*searchtet);
11043 eprevself(*searchtet);
11044 loc = ONVERTEX; // return ONVERTEX;
11045 break;
11046 }
11047
11048 // We enter from one of serarchtet's faces, which face do we exit?
11049 oriorg = orient3d(tdest, tapex, toppo, searchpt);
11050 oridest = orient3d(tapex, torg, toppo, searchpt);
11051 oriapex = orient3d(torg, tdest, toppo, searchpt);
11052
11053 // Now decide which face to move. It is possible there are more than one
11054 // faces are viable moves. If so, randomly choose one.
11055 if (oriorg < 0) {
11056 if (oridest < 0) {
11057 if (oriapex < 0) {
11058 // All three faces are possible.
11059 s = randomnation(3); // 's' is in {0,1,2}.
11060 if (s == 0) {
11061 nextmove = ORGMOVE;
11062 } else if (s == 1) {
11063 nextmove = DESTMOVE;
11064 } else {
11065 nextmove = APEXMOVE;
11066 }
11067 } else {
11068 // Two faces, opposite to origin and destination, are viable.
11069 //s = randomnation(2); // 's' is in {0,1}.
11070 if (randomnation(2)) {
11071 nextmove = ORGMOVE;
11072 } else {
11073 nextmove = DESTMOVE;
11074 }
11075 }
11076 } else {
11077 if (oriapex < 0) {
11078 // Two faces, opposite to origin and apex, are viable.
11079 //s = randomnation(2); // 's' is in {0,1}.
11080 if (randomnation(2)) {
11081 nextmove = ORGMOVE;
11082 } else {
11083 nextmove = APEXMOVE;
11084 }
11085 } else {
11086 // Only the face opposite to origin is viable.
11087 nextmove = ORGMOVE;
11088 }
11089 }
11090 } else {
11091 if (oridest < 0) {
11092 if (oriapex < 0) {
11093 // Two faces, opposite to destination and apex, are viable.
11094 //s = randomnation(2); // 's' is in {0,1}.
11095 if (randomnation(2)) {
11096 nextmove = DESTMOVE;
11097 } else {
11098 nextmove = APEXMOVE;
11099 }
11100 } else {
11101 // Only the face opposite to destination is viable.
11102 nextmove = DESTMOVE;
11103 }
11104 } else {
11105 if (oriapex < 0) {
11106 // Only the face opposite to apex is viable.
11107 nextmove = APEXMOVE;
11108 } else {
11109 // The point we seek must be on the boundary of or inside this
11110 // tetrahedron. Check for boundary cases.
11111 if (oriorg == 0) {
11112 // Go to the face opposite to origin.
11113 enextesymself(*searchtet);
11114 if (oridest == 0) {
11115 eprevself(*searchtet); // edge oppo->apex
11116 if (oriapex == 0) {
11117 // oppo is duplicated with p.
11118 loc = ONVERTEX; // return ONVERTEX;
11119 break;
11120 }
11121 loc = ONEDGE; // return ONEDGE;
11122 break;
11123 }
11124 if (oriapex == 0) {
11125 enextself(*searchtet); // edge dest->oppo
11126 loc = ONEDGE; // return ONEDGE;
11127 break;
11128 }
11129 loc = ONFACE; // return ONFACE;
11130 break;
11131 }
11132 if (oridest == 0) {
11133 // Go to the face opposite to destination.
11134 eprevesymself(*searchtet);
11135 if (oriapex == 0) {
11136 eprevself(*searchtet); // edge oppo->org
11137 loc = ONEDGE; // return ONEDGE;
11138 break;
11139 }
11140 loc = ONFACE; // return ONFACE;
11141 break;
11142 }
11143 if (oriapex == 0) {
11144 // Go to the face opposite to apex
11145 esymself(*searchtet);
11146 loc = ONFACE; // return ONFACE;
11147 break;
11148 }
11149 loc = INTETRAHEDRON; // return INTETRAHEDRON;
11150 break;
11151 }
11152 }
11153 }
11154
11155 // Move to the selected face.
11156 if (nextmove == ORGMOVE) {
11157 enextesymself(*searchtet);
11158 } else if (nextmove == DESTMOVE) {
11159 eprevesymself(*searchtet);
11160 } else {
11161 esymself(*searchtet);
11162 }
11163 // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
11164 fsymself(*searchtet);
11165 if (oppo(*searchtet) == dummypoint) {
11166 loc = OUTSIDE; // return OUTSIDE;
11167 break;
11168 }
11169
11170 // Retreat the three vertices of the base face.
11171 torg = org(*searchtet);
11172 tdest = dest(*searchtet);
11173 tapex = apex(*searchtet);
11174
11175 } // while (true)
11176
11177 return loc;
11178}
11179
11180///////////////////////////////////////////////////////////////////////////////
11181// //
11182// flippush() Push a face (possibly will be flipped) into flipstack. //
11183// //
11184// The face is marked. The flag is used to check the validity of the face on //
11185// its popup. Some other flips may change it already. //
11186// //
11187///////////////////////////////////////////////////////////////////////////////
11188
11189void tetgenmesh::flippush(badface*& fstack, triface* flipface)
11190{
11191 if (!facemarked(*flipface)) {
11192 badface *newflipface = (badface *) flippool->alloc();
11193 newflipface->tt = *flipface;
11194 markface(newflipface->tt);
11195 // Push this face into stack.
11196 newflipface->nextitem = fstack;
11197 fstack = newflipface;
11198 }
11199}
11200
11201///////////////////////////////////////////////////////////////////////////////
11202// //
11203// incrementalflip() Incrementally flipping to construct DT. //
11204// //
11205// Faces need to be checked for flipping are already queued in 'flipstack'. //
11206// Return the total number of performed flips. //
11207// //
11208// Comment: This routine should be only used in the incremental Delaunay //
11209// construction. In other cases, lawsonflip3d() should be used. //
11210// //
11211// If the new point lies outside of the convex hull ('hullflag' is set). The //
11212// incremental flip algorithm still works as usual. However, we must ensure //
11213// that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
11214// edge or face. Otherwise, the underlying space of the triangulation becomes//
11215// non-manifold and it is not possible to flip further. //
11216// Thanks to Joerg Rambau and Frank Lutz for helping in this issue. //
11217// //
11218///////////////////////////////////////////////////////////////////////////////
11219
11220int tetgenmesh::incrementalflip(point newpt, int hullflag, flipconstraints *fc)
11221{
11222 badface *popface;
11223 triface fliptets[5], *parytet;
11224 point *pts, *parypt, pe;
11225 REAL sign, ori;
11226 int flipcount = 0;
11227 int t1ver;
11228 int i;
11229
11230 if (b->verbose > 2) {
11231 printf(" Lawson flip (%ld faces).\n", flippool->items);
11232 }
11233
11234 if (hullflag) {
11235 // 'newpt' lies in the outside of the convex hull.
11236 // Mark all hull vertices which are connecting to it.
11237 popface = flipstack;
11238 while (popface != NULL) {
11239 pts = (point *) popface->tt.tet;
11240 for (i = 4; i < 8; i++) {
11241 if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
11242 if (!pinfected(pts[i])) {
11243 pinfect(pts[i]);
11244 cavetetvertlist->newindex((void **) &parypt);
11245 *parypt = pts[i];
11246 }
11247 }
11248 }
11249 popface = popface->nextitem;
11250 }
11251 }
11252
11253 // Loop until the queue is empty.
11254 while (flipstack != NULL) {
11255
11256 // Pop a face from the stack.
11257 popface = flipstack;
11258 fliptets[0] = popface->tt;
11259 flipstack = flipstack->nextitem; // The next top item in stack.
11260 flippool->dealloc((void *) popface);
11261
11262 // Skip it if it is a dead tet (destroyed by previous flips).
11263 if (isdeadtet(fliptets[0])) continue;
11264 // Skip it if it is not the same tet as we saved.
11265 if (!facemarked(fliptets[0])) continue;
11266
11267 unmarkface(fliptets[0]);
11268
11269 if ((point) fliptets[0].tet[7] == dummypoint) {
11270 // It must be a hull edge.
11271 fliptets[0].ver = epivot[fliptets[0].ver];
11272 // A hull edge. The current convex hull may be enlarged.
11273 fsym(fliptets[0], fliptets[1]);
11274 pts = (point *) fliptets[1].tet;
11275 ori = orient3d(pts[4], pts[5], pts[6], newpt);
11276 if (ori < 0) {
11277 // Visible. The convex hull will be enlarged.
11278 // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
11279 // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
11280 enext(fliptets[1], fliptets[2]);
11281 eprev(fliptets[1], fliptets[3]);
11282 fnextself(fliptets[2]); // [a,c,e,*]
11283 fnextself(fliptets[3]); // [c,b,e,*]
11284 if (oppo(fliptets[2]) == newpt) {
11285 if (oppo(fliptets[3]) == newpt) {
11286 // Both tets exist! A 4-to-1 flip is found.
11287 terminatetetgen(this, 2); // Report a bug.
11288 } else {
11289 esym(fliptets[2], fliptets[0]);
11290 fnext(fliptets[0], fliptets[1]);
11291 fnext(fliptets[1], fliptets[2]);
11292 // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
11293 // This corresponds to my standard labels, where edge [e,d] is
11294 // repalced by face [a,b,c], and a is the new vertex.
11295 // [0] [c,a,d,e] (d = newpt)
11296 // [1] [c,a,e,b] (c = dummypoint)
11297 // [2] [c,a,b,d]
11298 flip32(fliptets, 1, fc);
11299 }
11300 } else {
11301 if (oppo(fliptets[3]) == newpt) {
11302 fnext(fliptets[3], fliptets[0]);
11303 fnext(fliptets[0], fliptets[1]);
11304 fnext(fliptets[1], fliptets[2]);
11305 // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
11306 // [0] [c,b,d,a] (d = newpt)
11307 // [1] [c,b,a,e] (c = dummypoint)
11308 // [2] [c,b,e,d]
11309 flip32(fliptets, 1, fc);
11310 } else {
11311 if (hullflag) {
11312 // Reject this flip if pe is already marked.
11313 pe = oppo(fliptets[1]);
11314 if (!pinfected(pe)) {
11315 pinfect(pe);
11316 cavetetvertlist->newindex((void **) &parypt);
11317 *parypt = pe;
11318 // Perform a 2-to-3 flip.
11319 flip23(fliptets, 1, fc);
11320 } else {
11321 // Reject this flip.
11322 flipcount--;
11323 }
11324 } else {
11325 // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
11326 // [0] [a,b,c,d], d = newpt.
11327 // [1] [b,a,c,e], c = dummypoint.
11328 flip23(fliptets, 1, fc);
11329 }
11330 }
11331 }
11332 flipcount++;
11333 }
11334 continue;
11335 } // if (dummypoint)
11336
11337 fsym(fliptets[0], fliptets[1]);
11338 if ((point) fliptets[1].tet[7] == dummypoint) {
11339 // A hull face is locally Delaunay.
11340 continue;
11341 }
11342 // Check if the adjacent tet has already been tested.
11343 if (marktested(fliptets[1])) {
11344 // It has been tested and it is Delaunay.
11345 continue;
11346 }
11347
11348 // Test whether the face is locally Delaunay or not.
11349 pts = (point *) fliptets[1].tet;
11350 if (b->weighted) {
11351 sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
11352 pts[4][3], pts[5][3], pts[6][3], pts[7][3],
11353 newpt[3]);
11354 } else {
11355 sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
11356 }
11357
11358
11359 if (sign < 0) {
11360 point pd = newpt;
11361 point pe = oppo(fliptets[1]);
11362 // Check the convexity of its three edges. Stop checking either a
11363 // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
11364 // encountered, and 'fliptet' represents that edge.
11365 for (i = 0; i < 3; i++) {
11366 ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
11367 if (ori <= 0) break;
11368 enextself(fliptets[0]);
11369 }
11370 if (ori > 0) {
11371 // A 2-to-3 flip is found.
11372 // [0] [a,b,c,d],
11373 // [1] [b,a,c,e]. no dummypoint.
11374 flip23(fliptets, 0, fc);
11375 flipcount++;
11376 } else { // ori <= 0
11377 // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
11378 // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
11379 // Check if there are three or four tets sharing at this edge.
11380 esymself(fliptets[0]); // [b,a,d,c]
11381 for (i = 0; i < 3; i++) {
11382 fnext(fliptets[i], fliptets[i+1]);
11383 }
11384 if (fliptets[3].tet == fliptets[0].tet) {
11385 // A 3-to-2 flip is found. (No hull tet.)
11386 flip32(fliptets, 0, fc);
11387 flipcount++;
11388 } else {
11389 // There are more than 3 tets at this edge.
11390 fnext(fliptets[3], fliptets[4]);
11391 if (fliptets[4].tet == fliptets[0].tet) {
11392 if (ori == 0) {
11393 // A 4-to-4 flip is found. (Two hull tets may be involved.)
11394 // Current tets in 'fliptets':
11395 // [0] [b,a,d,c] (d may be newpt)
11396 // [1] [b,a,c,e]
11397 // [2] [b,a,e,f] (f may be dummypoint)
11398 // [3] [b,a,f,d]
11399 esymself(fliptets[0]); // [a,b,c,d]
11400 // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
11401 // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
11402 // It will be removed by the followed 3-to-2 flip.
11403 flip23(fliptets, 0, fc); // No hull tet.
11404 fnext(fliptets[3], fliptets[1]);
11405 fnext(fliptets[1], fliptets[2]);
11406 // Current tets in 'fliptets':
11407 // [0] [...]
11408 // [1] [b,a,d,e] (degenerated, d may be new point).
11409 // [2] [b,a,e,f] (f may be dummypoint)
11410 // [3] [b,a,f,d]
11411 // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
11412 // Hull tets may be involved (f may be dummypoint).
11413 flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
11414 flipcount++;
11415 }
11416 }
11417 }
11418 } // ori
11419 } else {
11420 // The adjacent tet is Delaunay. Mark it to avoid testing it again.
11421 marktest(fliptets[1]);
11422 // Save it for unmarking it later.
11423 cavebdrylist->newindex((void **) &parytet);
11424 *parytet = fliptets[1];
11425 }
11426
11427 } // while (flipstack)
11428
11429 // Unmark saved tetrahedra.
11430 for (i = 0; i < cavebdrylist->objects; i++) {
11431 parytet = (triface *) fastlookup(cavebdrylist, i);
11432 unmarktest(*parytet);
11433 }
11434 cavebdrylist->restart();
11435
11436 if (hullflag) {
11437 // Unmark infected vertices.
11438 for (i = 0; i < cavetetvertlist->objects; i++) {
11439 parypt = (point *) fastlookup(cavetetvertlist, i);
11440 puninfect(*parypt);
11441 }
11442 cavetetvertlist->restart();
11443 }
11444
11445
11446 return flipcount;
11447}
11448
11449///////////////////////////////////////////////////////////////////////////////
11450// //
11451// initialdelaunay() Create an initial Delaunay tetrahedralization. //
11452// //
11453// The tetrahedralization contains only one tetrahedron abcd, and four hull //
11454// tetrahedra. The points pa, pb, pc, and pd must be linearly independent. //
11455// //
11456///////////////////////////////////////////////////////////////////////////////
11457
11458void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
11459{
11460 triface firsttet, tetopa, tetopb, tetopc, tetopd;
11461 triface worktet, worktet1;
11462
11463 if (b->verbose > 2) {
11464 printf(" Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
11465 pointmark(pb), pointmark(pc), pointmark(pd));
11466 }
11467
11468 // Create the first tetrahedron.
11469 maketetrahedron(&firsttet);
11470 setvertices(firsttet, pa, pb, pc, pd);
11471 // Create four hull tetrahedra.
11472 maketetrahedron(&tetopa);
11473 setvertices(tetopa, pb, pc, pd, dummypoint);
11474 maketetrahedron(&tetopb);
11475 setvertices(tetopb, pc, pa, pd, dummypoint);
11476 maketetrahedron(&tetopc);
11477 setvertices(tetopc, pa, pb, pd, dummypoint);
11478 maketetrahedron(&tetopd);
11479 setvertices(tetopd, pb, pa, pc, dummypoint);
11480 hullsize += 4;
11481
11482 // Connect hull tetrahedra to firsttet (at four faces of firsttet).
11483 bond(firsttet, tetopd);
11484 esym(firsttet, worktet);
11485 bond(worktet, tetopc); // ab
11486 enextesym(firsttet, worktet);
11487 bond(worktet, tetopa); // bc
11488 eprevesym(firsttet, worktet);
11489 bond(worktet, tetopb); // ca
11490
11491 // Connect hull tetrahedra together (at six edges of firsttet).
11492 esym(tetopc, worktet);
11493 esym(tetopd, worktet1);
11494 bond(worktet, worktet1); // ab
11495 esym(tetopa, worktet);
11496 eprevesym(tetopd, worktet1);
11497 bond(worktet, worktet1); // bc
11498 esym(tetopb, worktet);
11499 enextesym(tetopd, worktet1);
11500 bond(worktet, worktet1); // ca
11501 eprevesym(tetopc, worktet);
11502 enextesym(tetopb, worktet1);
11503 bond(worktet, worktet1); // da
11504 eprevesym(tetopa, worktet);
11505 enextesym(tetopc, worktet1);
11506 bond(worktet, worktet1); // db
11507 eprevesym(tetopb, worktet);
11508 enextesym(tetopa, worktet1);
11509 bond(worktet, worktet1); // dc
11510
11511 // Set the vertex type.
11512 if (pointtype(pa) == UNUSEDVERTEX) {
11513 setpointtype(pa, VOLVERTEX);
11514 }
11515 if (pointtype(pb) == UNUSEDVERTEX) {
11516 setpointtype(pb, VOLVERTEX);
11517 }
11518 if (pointtype(pc) == UNUSEDVERTEX) {
11519 setpointtype(pc, VOLVERTEX);
11520 }
11521 if (pointtype(pd) == UNUSEDVERTEX) {
11522 setpointtype(pd, VOLVERTEX);
11523 }
11524
11525 setpoint2tet(pa, encode(firsttet));
11526 setpoint2tet(pb, encode(firsttet));
11527 setpoint2tet(pc, encode(firsttet));
11528 setpoint2tet(pd, encode(firsttet));
11529
11530 // Remember the first tetrahedron.
11531 recenttet = firsttet;
11532}
11533
11534///////////////////////////////////////////////////////////////////////////////
11535// //
11536// incrementaldelaunay() Create a Delaunay tetrahedralization by //
11537// the incremental approach. //
11538// //
11539///////////////////////////////////////////////////////////////////////////////
11540
11541
11542void tetgenmesh::incrementaldelaunay(clock_t& tv)
11543{
11544 triface searchtet;
11545 point *permutarray, swapvertex;
11546 REAL v1[3], v2[3], n[3];
11547 REAL bboxsize, bboxsize2, bboxsize3, ori;
11548 int randindex;
11549 int ngroup = 0;
11550 int i, j;
11551
11552 if (!b->quiet) {
11553 printf("Delaunizing vertices...\n");
11554 }
11555
11556 // Form a random permuation (uniformly at random) of the set of vertices.
11557 permutarray = new point[in->numberofpoints];
11558 points->traversalinit();
11559
11560 if (b->no_sort) {
11561 if (b->verbose) {
11562 printf(" Using the input order.\n");
11563 }
11564 for (i = 0; i < in->numberofpoints; i++) {
11565 permutarray[i] = (point) points->traverse();
11566 }
11567 } else {
11568 if (b->verbose) {
11569 printf(" Permuting vertices.\n");
11570 }
11571 srand(in->numberofpoints);
11572 for (i = 0; i < in->numberofpoints; i++) {
11573 randindex = rand() % (i + 1); // randomnation(i + 1);
11574 permutarray[i] = permutarray[randindex];
11575 permutarray[randindex] = (point) points->traverse();
11576 }
11577 if (b->brio_hilbert) { // -b option
11578 if (b->verbose) {
11579 printf(" Sorting vertices.\n");
11580 }
11581 hilbert_init(in->mesh_dim);
11582 brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold,
11583 b->brio_ratio, &ngroup);
11584 }
11585 }
11586
11587 tv = clock(); // Remember the time for sorting points.
11588
11589 // Calculate the diagonal size of its bounding box.
11590 bboxsize = sqrt(norm2(xmax - xmin, ymax - ymin, zmax - zmin));
11591 bboxsize2 = bboxsize * bboxsize;
11592 bboxsize3 = bboxsize2 * bboxsize;
11593
11594 // Make sure the second vertex is not identical with the first one.
11595 i = 1;
11596 while ((distance(permutarray[0],permutarray[i])/bboxsize)<b->epsilon) {
11597 i++;
11598 if (i == in->numberofpoints - 1) {
11599 printf("Exception: All vertices are (nearly) identical (Tol = %g).\n",
11600 b->epsilon);
11601 terminatetetgen(this, 10);
11602 }
11603 }
11604 if (i > 1) {
11605 // Swap to move the non-identical vertex from index i to index 1.
11606 swapvertex = permutarray[i];
11607 permutarray[i] = permutarray[1];
11608 permutarray[1] = swapvertex;
11609 }
11610
11611 // Make sure the third vertex is not collinear with the first two.
11612 // Acknowledgement: Thanks Jan Pomplun for his correction by using
11613 // epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
11614 i = 2;
11615 for (j = 0; j < 3; j++) {
11616 v1[j] = permutarray[1][j] - permutarray[0][j];
11617 v2[j] = permutarray[i][j] - permutarray[0][j];
11618 }
11619 cross(v1, v2, n);
11620 while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) <
11621 (b->epsilon * b->epsilon)) {
11622 i++;
11623 if (i == in->numberofpoints - 1) {
11624 printf("Exception: All vertices are (nearly) collinear (Tol = %g).\n",
11625 b->epsilon);
11626 terminatetetgen(this, 10);
11627 }
11628 for (j = 0; j < 3; j++) {
11629 v2[j] = permutarray[i][j] - permutarray[0][j];
11630 }
11631 cross(v1, v2, n);
11632 }
11633 if (i > 2) {
11634 // Swap to move the non-identical vertex from index i to index 1.
11635 swapvertex = permutarray[i];
11636 permutarray[i] = permutarray[2];
11637 permutarray[2] = swapvertex;
11638 }
11639
11640 // Make sure the fourth vertex is not coplanar with the first three.
11641 i = 3;
11642 ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
11643 permutarray[i]);
11644 while ((fabs(ori) / bboxsize3) < (b->epsilon * b->epsilon * b->epsilon)) {
11645 i++;
11646 if (i == in->numberofpoints) {
11647 printf("Exception: All vertices are coplanar (Tol = %g).\n",
11648 b->epsilon);
11649 terminatetetgen(this, 10);
11650 }
11651 ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
11652 permutarray[i]);
11653 }
11654 if (i > 3) {
11655 // Swap to move the non-identical vertex from index i to index 1.
11656 swapvertex = permutarray[i];
11657 permutarray[i] = permutarray[3];
11658 permutarray[3] = swapvertex;
11659 }
11660
11661 // Orient the first four vertices in permutarray so that they follow the
11662 // right-hand rule.
11663 if (ori > 0.0) {
11664 // Swap the first two vertices.
11665 swapvertex = permutarray[0];
11666 permutarray[0] = permutarray[1];
11667 permutarray[1] = swapvertex;
11668 }
11669
11670 // Create the initial Delaunay tetrahedralization.
11671 initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
11672 permutarray[3]);
11673
11674 if (b->verbose) {
11675 printf(" Incrementally inserting vertices.\n");
11676 }
11677 insertvertexflags ivf;
11678 flipconstraints fc;
11679
11680 // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
11681 if (b->incrflip) {
11682 ivf.bowywat = 0;
11683 ivf.lawson = 1;
11684 fc.enqflag = 1;
11685 } else {
11686 ivf.bowywat = 1;
11687 ivf.lawson = 0;
11688 }
11689
11690
11691 for (i = 4; i < in->numberofpoints; i++) {
11692 if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
11693 setpointtype(permutarray[i], VOLVERTEX);
11694 }
11695 if (b->brio_hilbert || b->no_sort) { // -b or -b/1
11696 // Start the last updated tet.
11697 searchtet.tet = recenttet.tet;
11698 } else { // -b0
11699 // Randomly choose the starting tet for point location.
11700 searchtet.tet = NULL;
11701 }
11702 ivf.iloc = (int) OUTSIDE;
11703 // Insert the vertex.
11704 if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
11705 if (flipstack != NULL) {
11706 // Perform flip to recover Delaunayness.
11707 incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
11708 }
11709 } else {
11710 if (ivf.iloc == (int) ONVERTEX) {
11711 // The point already exists. Mark it and do nothing on it.
11712 swapvertex = org(searchtet);
11713 assert(swapvertex != permutarray[i]); // SELF_CHECK
11714 if (b->object != tetgenbehavior::STL) {
11715 if (!b->quiet) {
11716 printf("Warning: Point #%d is coincident with #%d. Ignored!\n",
11717 pointmark(permutarray[i]), pointmark(swapvertex));
11718 }
11719 }
11720 setpoint2ppt(permutarray[i], swapvertex);
11721 setpointtype(permutarray[i], DUPLICATEDVERTEX);
11722 dupverts++;
11723 } else if (ivf.iloc == (int) NEARVERTEX) {
11724 swapvertex = point2ppt(permutarray[i]);
11725 if (!b->quiet) {
11726 printf("Warning: Point %d is replaced by point %d.\n",
11727 pointmark(permutarray[i]), pointmark(swapvertex));
11728 printf(" Avoid creating a very short edge (len = %g) (< %g).\n",
11729 permutarray[i][3], b->minedgelength);
11730 printf(" You may try a smaller tolerance (-T) (current is %g)\n",
11731 b->epsilon);
11732 printf(" or use the option -M0/1 to avoid such replacement.\n");
11733 }
11734 // Remember it is a duplicated point.
11735 setpointtype(permutarray[i], DUPLICATEDVERTEX);
11736 // Count the number of duplicated points.
11737 dupverts++;
11738 }
11739 }
11740 }
11741
11742
11743
11744 delete [] permutarray;
11745}
11746
11747//// ////
11748//// ////
11749//// delaunay_cxx /////////////////////////////////////////////////////////////
11750
11751//// surface_cxx //////////////////////////////////////////////////////////////
11752//// ////
11753//// ////
11754
11755///////////////////////////////////////////////////////////////////////////////
11756// //
11757// flipshpush() Push a facet edge into flip stack. //
11758// //
11759///////////////////////////////////////////////////////////////////////////////
11760
11761void tetgenmesh::flipshpush(face* flipedge)
11762{
11763 badface *newflipface;
11764
11765 newflipface = (badface *) flippool->alloc();
11766 newflipface->ss = *flipedge;
11767 newflipface->forg = sorg(*flipedge);
11768 newflipface->fdest = sdest(*flipedge);
11769 newflipface->nextitem = flipstack;
11770 flipstack = newflipface;
11771}
11772
11773///////////////////////////////////////////////////////////////////////////////
11774// //
11775// flip22() Perform a 2-to-2 flip in surface mesh. //
11776// //
11777// 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and //
11778// [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
11779// is replaced by edge [c,d]. //
11780// //
11781///////////////////////////////////////////////////////////////////////////////
11782
11783void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
11784{
11785 face bdedges[4], outfaces[4], infaces[4];
11786 face bdsegs[4];
11787 face checkface;
11788 point pa, pb, pc, pd;
11789 int i;
11790
11791 pa = sorg(flipfaces[0]);
11792 pb = sdest(flipfaces[0]);
11793 pc = sapex(flipfaces[0]);
11794 pd = sapex(flipfaces[1]);
11795
11796 if (sorg(flipfaces[1]) != pb) {
11797 sesymself(flipfaces[1]);
11798 }
11799
11800 flip22count++;
11801
11802 // Collect the four boundary edges.
11803 senext(flipfaces[0], bdedges[0]);
11804 senext2(flipfaces[0], bdedges[1]);
11805 senext(flipfaces[1], bdedges[2]);
11806 senext2(flipfaces[1], bdedges[3]);
11807
11808 // Collect outer boundary faces.
11809 for (i = 0; i < 4; i++) {
11810 spivot(bdedges[i], outfaces[i]);
11811 infaces[i] = outfaces[i];
11812 sspivot(bdedges[i], bdsegs[i]);
11813 if (outfaces[i].sh != NULL) {
11814 if (isshsubseg(bdedges[i])) {
11815 spivot(infaces[i], checkface);
11816 while (checkface.sh != bdedges[i].sh) {
11817 infaces[i] = checkface;
11818 spivot(infaces[i], checkface);
11819 }
11820 }
11821 }
11822 }
11823
11824 // The flags set in these two subfaces do not change.
11825 // Shellmark does not change.
11826 // area constraint does not change.
11827
11828 // Transform [a,b,c] -> [c,d,b].
11829 setshvertices(flipfaces[0], pc, pd, pb);
11830 // Transform [b,a,d] -> [d,c,a].
11831 setshvertices(flipfaces[1], pd, pc, pa);
11832
11833 // Update the point-to-subface map.
11834 if (pointtype(pa) == FREEFACETVERTEX) {
11835 setpoint2sh(pa, sencode(flipfaces[1]));
11836 }
11837 if (pointtype(pb) == FREEFACETVERTEX) {
11838 setpoint2sh(pb, sencode(flipfaces[0]));
11839 }
11840 if (pointtype(pc) == FREEFACETVERTEX) {
11841 setpoint2sh(pc, sencode(flipfaces[0]));
11842 }
11843 if (pointtype(pd) == FREEFACETVERTEX) {
11844 setpoint2sh(pd, sencode(flipfaces[0]));
11845 }
11846
11847 // Reconnect boundary edges to outer boundary faces.
11848 for (i = 0; i < 4; i++) {
11849 if (outfaces[(3 + i) % 4].sh != NULL) {
11850 // Make sure that the subface has the ori as the segment.
11851 if (bdsegs[(3 + i) % 4].sh != NULL) {
11852 bdsegs[(3 + i) % 4].shver = 0;
11853 if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
11854 sesymself(bdedges[i]);
11855 }
11856 }
11857 sbond1(bdedges[i], outfaces[(3 + i) % 4]);
11858 sbond1(infaces[(3 + i) % 4], bdedges[i]);
11859 } else {
11860 sdissolve(bdedges[i]);
11861 }
11862 if (bdsegs[(3 + i) % 4].sh != NULL) {
11863 ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
11864 if (chkencflag & 1) {
11865 // Queue this segment for encroaching check.
11866 enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
11867 }
11868 } else {
11869 ssdissolve(bdedges[i]);
11870 }
11871 }
11872
11873 if (chkencflag & 2) {
11874 // Queue the flipped subfaces for quality/encroaching checks.
11875 for (i = 0; i < 2; i++) {
11876 enqueuesubface(badsubfacs, &(flipfaces[i]));
11877 }
11878 }
11879
11880 recentsh = flipfaces[0];
11881
11882 if (flipflag) {
11883 // Put the boundary edges into flip stack.
11884 for (i = 0; i < 4; i++) {
11885 flipshpush(&(bdedges[i]));
11886 }
11887 }
11888}
11889
11890///////////////////////////////////////////////////////////////////////////////
11891// //
11892// flip31() Remove a vertex by transforming 3-to-1 subfaces. //
11893// //
11894// 'flipfaces' is an array of subfaces. Its length is at least 4. On input, //
11895// the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine //
11896// replaces them by one face [a,b,c], it is returned in flipfaces[3]. //
11897// //
11898// NOTE: The three old subfaces are not deleted within this routine. They //
11899// still hold pointers to their adjacent subfaces. These informations are //
11900// needed by the routine 'sremovevertex()' for recovering a segment. //
11901// The caller of this routine must delete the old subfaces after their uses. //
11902// //
11903///////////////////////////////////////////////////////////////////////////////
11904
11905void tetgenmesh::flip31(face* flipfaces, int flipflag)
11906{
11907 face bdedges[3], outfaces[3], infaces[3];
11908 face bdsegs[3];
11909 face checkface;
11910 point pa, pb, pc;
11911 int i;
11912
11913 pa = sdest(flipfaces[0]);
11914 pb = sdest(flipfaces[1]);
11915 pc = sdest(flipfaces[2]);
11916
11917 flip31count++;
11918
11919 // Collect all infos at the three boundary edges.
11920 for (i = 0; i < 3; i++) {
11921 senext(flipfaces[i], bdedges[i]);
11922 spivot(bdedges[i], outfaces[i]);
11923 infaces[i] = outfaces[i];
11924 sspivot(bdedges[i], bdsegs[i]);
11925 if (outfaces[i].sh != NULL) {
11926 if (isshsubseg(bdedges[i])) {
11927 spivot(infaces[i], checkface);
11928 while (checkface.sh != bdedges[i].sh) {
11929 infaces[i] = checkface;
11930 spivot(infaces[i], checkface);
11931 }
11932 }
11933 }
11934 } // i
11935
11936 // Create a new subface.
11937 makeshellface(subfaces, &(flipfaces[3]));
11938 setshvertices(flipfaces[3], pa, pb,pc);
11939 setshellmark(flipfaces[3], shellmark(flipfaces[0]));
11940 if (checkconstraints) {
11941 //area = areabound(flipfaces[0]);
11942 setareabound(flipfaces[3], areabound(flipfaces[0]));
11943 }
11944 if (useinsertradius) {
11945 setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
11946 }
11947
11948 // Update the point-to-subface map.
11949 if (pointtype(pa) == FREEFACETVERTEX) {
11950 setpoint2sh(pa, sencode(flipfaces[3]));
11951 }
11952 if (pointtype(pb) == FREEFACETVERTEX) {
11953 setpoint2sh(pb, sencode(flipfaces[3]));
11954 }
11955 if (pointtype(pc) == FREEFACETVERTEX) {
11956 setpoint2sh(pc, sencode(flipfaces[3]));
11957 }
11958
11959 // Update the three new boundary edges.
11960 bdedges[0] = flipfaces[3]; // [a,b]
11961 senext(flipfaces[3], bdedges[1]); // [b,c]
11962 senext2(flipfaces[3], bdedges[2]); // [c,a]
11963
11964 // Reconnect boundary edges to outer boundary faces.
11965 for (i = 0; i < 3; i++) {
11966 if (outfaces[i].sh != NULL) {
11967 // Make sure that the subface has the ori as the segment.
11968 if (bdsegs[i].sh != NULL) {
11969 bdsegs[i].shver = 0;
11970 if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
11971 sesymself(bdedges[i]);
11972 }
11973 }
11974 sbond1(bdedges[i], outfaces[i]);
11975 sbond1(infaces[i], bdedges[i]);
11976 }
11977 if (bdsegs[i].sh != NULL) {
11978 ssbond(bdedges[i], bdsegs[i]);
11979 }
11980 }
11981
11982 recentsh = flipfaces[3];
11983
11984 if (flipflag) {
11985 // Put the boundary edges into flip stack.
11986 for (i = 0; i < 3; i++) {
11987 flipshpush(&(bdedges[i]));
11988 }
11989 }
11990}
11991
11992///////////////////////////////////////////////////////////////////////////////
11993// //
11994// lawsonflip() Flip non-locally Delaunay edges. //
11995// //
11996///////////////////////////////////////////////////////////////////////////////
11997
11998long tetgenmesh::lawsonflip()
11999{
12000 badface *popface;
12001 face flipfaces[2];
12002 point pa, pb, pc, pd;
12003 REAL sign;
12004 long flipcount = 0;
12005
12006 if (b->verbose > 2) {
12007 printf(" Lawson flip %ld edges.\n", flippool->items);
12008 }
12009
12010 while (flipstack != (badface *) NULL) {
12011
12012 // Pop an edge from the stack.
12013 popface = flipstack;
12014 flipfaces[0] = popface->ss;
12015 pa = popface->forg;
12016 pb = popface->fdest;
12017 flipstack = popface->nextitem; // The next top item in stack.
12018 flippool->dealloc((void *) popface);
12019
12020 // Skip it if it is dead.
12021 if (flipfaces[0].sh[3] == NULL) continue;
12022 // Skip it if it is not the same edge as we saved.
12023 if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
12024 // Skip it if it is a subsegment.
12025 if (isshsubseg(flipfaces[0])) continue;
12026
12027 // Get the adjacent face.
12028 spivot(flipfaces[0], flipfaces[1]);
12029 if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
12030 pc = sapex(flipfaces[0]);
12031 pd = sapex(flipfaces[1]);
12032
12033 sign = incircle3d(pa, pb, pc, pd);
12034
12035 if (sign < 0) {
12036 // It is non-locally Delaunay. Flip it.
12037 flip22(flipfaces, 1, 0);
12038 flipcount++;
12039 }
12040 }
12041
12042 if (b->verbose > 2) {
12043 printf(" Performed %ld flips.\n", flipcount);
12044 }
12045
12046 return flipcount;
12047}
12048
12049///////////////////////////////////////////////////////////////////////////////
12050// //
12051// sinsertvertex() Insert a vertex into a triangulation of a facet. //
12052// //
12053// This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
12054// 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p), //
12055// 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a //
12056// segment, 'cavesegshlist' returns the two new subsegments. //
12057// //
12058// 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
12059// will first locate the point. It starts searching from 'searchsh' or 'rec- //
12060// entsh' if 'searchsh' is NULL. //
12061// //
12062// If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert //
12063// the vertex. Otherwise, only insert the vertex in the initial cavity. //
12064// //
12065// If 'iloc' is 'INSTAR', this means the cavity of this vertex was already //
12066// provided in the list 'caveshlist'. //
12067// //
12068// If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
12069// be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'. //
12070// //
12071// 'rflag' (rounding) is a parameter passed to slocate() function. If it is //
12072// set, after the location of the point is found, either ONEDGE or ONFACE, //
12073// round the result using an epsilon. //
12074// //
12075// NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
12076// want to remove the new point immediately. //
12077// //
12078///////////////////////////////////////////////////////////////////////////////
12079
12080int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
12081 int iloc, int bowywat, int rflag)
12082{
12083 face cavesh, neighsh, *parysh;
12084 face newsh, casout, casin;
12085 face checkseg;
12086 point pa, pb;
12087 enum locateresult loc = OUTSIDE;
12088 REAL sign, ori;
12089 int i, j;
12090
12091 if (b->verbose > 2) {
12092 printf(" Insert facet point %d.\n", pointmark(insertpt));
12093 }
12094
12095 if (bowywat == 3) {
12096 loc = INSTAR;
12097 }
12098
12099 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12100 // A segment is going to be split, no point location.
12101 spivot(*splitseg, *searchsh);
12102 if (loc != INSTAR) loc = ONEDGE;
12103 } else {
12104 if (loc != INSTAR) loc = (enum locateresult) iloc;
12105 if (loc == OUTSIDE) {
12106 // Do point location in surface mesh.
12107 if (searchsh->sh == NULL) {
12108 *searchsh = recentsh;
12109 }
12110 // Search the vertex. An above point must be provided ('aflag' = 1).
12111 loc = slocate(insertpt, searchsh, 1, 1, rflag);
12112 }
12113 }
12114
12115
12116 // Form the initial sC(p).
12117 if (loc == ONFACE) {
12118 // Add the face into list (in B-W cavity).
12119 smarktest(*searchsh);
12120 caveshlist->newindex((void **) &parysh);
12121 *parysh = *searchsh;
12122 } else if (loc == ONEDGE) {
12123 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12124 splitseg->shver = 0;
12125 pa = sorg(*splitseg);
12126 } else {
12127 pa = sorg(*searchsh);
12128 }
12129 if (searchsh->sh != NULL) {
12130 // Collect all subfaces share at this edge.
12131 neighsh = *searchsh;
12132 while (1) {
12133 // Adjust the origin of its edge to be 'pa'.
12134 if (sorg(neighsh) != pa) sesymself(neighsh);
12135 // Add this face into list (in B-W cavity).
12136 smarktest(neighsh);
12137 caveshlist->newindex((void **) &parysh);
12138 *parysh = neighsh;
12139 // Add this face into face-at-splitedge list.
12140 cavesegshlist->newindex((void **) &parysh);
12141 *parysh = neighsh;
12142 // Go to the next face at the edge.
12143 spivotself(neighsh);
12144 // Stop if all faces at the edge have been visited.
12145 if (neighsh.sh == searchsh->sh) break;
12146 if (neighsh.sh == NULL) break;
12147 }
12148 } // If (not a non-dangling segment).
12149 } else if (loc == ONVERTEX) {
12150 return (int) loc;
12151 } else if (loc == OUTSIDE) {
12152 // Comment: This should only happen during the surface meshing step.
12153 // Enlarge the convex hull of the triangulation by including p.
12154 // An above point of the facet is set in 'dummypoint' to replace
12155 // orient2d tests by orient3d tests.
12156 // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
12157 // plane, and a->b is directed from left to right, p lies above a->b.
12158 // Find the right-most edge of the triangulation which is visible by p.
12159 neighsh = *searchsh;
12160 while (1) {
12161 senext2self(neighsh);
12162 spivot(neighsh, casout);
12163 if (casout.sh == NULL) {
12164 // A convex hull edge. Is it visible by p.
12165 ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
12166 if (ori < 0) {
12167 *searchsh = neighsh; // Visible, update 'searchsh'.
12168 } else {
12169 break; // 'searchsh' is the right-most visible edge.
12170 }
12171 } else {
12172 if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12173 neighsh = casout;
12174 }
12175 }
12176 // Create new triangles for all visible edges of p (from right to left).
12177 casin.sh = NULL; // No adjacent face at right.
12178 pa = sorg(*searchsh);
12179 pb = sdest(*searchsh);
12180 while (1) {
12181 // Create a new subface on top of the (visible) edge.
12182 makeshellface(subfaces, &newsh);
12183 setshvertices(newsh, pb, pa, insertpt);
12184 setshellmark(newsh, shellmark(*searchsh));
12185 if (checkconstraints) {
12186 //area = areabound(*searchsh);
12187 setareabound(newsh, areabound(*searchsh));
12188 }
12189 if (useinsertradius) {
12190 setfacetindex(newsh, getfacetindex(*searchsh));
12191 }
12192 // Connect the new subface to the bottom subfaces.
12193 sbond1(newsh, *searchsh);
12194 sbond1(*searchsh, newsh);
12195 // Connect the new subface to its right-adjacent subface.
12196 if (casin.sh != NULL) {
12197 senext(newsh, casout);
12198 sbond1(casout, casin);
12199 sbond1(casin, casout);
12200 }
12201 // The left-adjacent subface has not been created yet.
12202 senext2(newsh, casin);
12203 // Add the new face into list (inside the B-W cavity).
12204 smarktest(newsh);
12205 caveshlist->newindex((void **) &parysh);
12206 *parysh = newsh;
12207 // Move to the convex hull edge at the left of 'searchsh'.
12208 neighsh = *searchsh;
12209 while (1) {
12210 senextself(neighsh);
12211 spivot(neighsh, casout);
12212 if (casout.sh == NULL) {
12213 *searchsh = neighsh;
12214 break;
12215 }
12216 if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12217 neighsh = casout;
12218 }
12219 // A convex hull edge. Is it visible by p.
12220 pa = sorg(*searchsh);
12221 pb = sdest(*searchsh);
12222 ori = orient3d(pa, pb, dummypoint, insertpt);
12223 // Finish the process if p is not visible by the hull edge.
12224 if (ori >= 0) break;
12225 }
12226 } else if (loc == INSTAR) {
12227 // Under this case, the sub-cavity sC(p) has already been formed in
12228 // insertvertex().
12229 }
12230
12231 // Form the Bowyer-Watson cavity sC(p).
12232 for (i = 0; i < caveshlist->objects; i++) {
12233 cavesh = * (face *) fastlookup(caveshlist, i);
12234 for (j = 0; j < 3; j++) {
12235 if (!isshsubseg(cavesh)) {
12236 spivot(cavesh, neighsh);
12237 if (neighsh.sh != NULL) {
12238 // The adjacent face exists.
12239 if (!smarktested(neighsh)) {
12240 if (bowywat) {
12241 if (loc == INSTAR) { // if (bowywat > 2) {
12242 // It must be a boundary edge.
12243 sign = 1;
12244 } else {
12245 // Check if this subface is connected to adjacent tet(s).
12246 if (!isshtet(neighsh)) {
12247 // Check if the subface is non-Delaunay wrt. the new pt.
12248 sign = incircle3d(sorg(neighsh), sdest(neighsh),
12249 sapex(neighsh), insertpt);
12250 } else {
12251 // It is connected to an adjacent tet. A boundary edge.
12252 sign = 1;
12253 }
12254 }
12255 if (sign < 0) {
12256 // Add the adjacent face in list (in B-W cavity).
12257 smarktest(neighsh);
12258 caveshlist->newindex((void **) &parysh);
12259 *parysh = neighsh;
12260 }
12261 } else {
12262 sign = 1; // A boundary edge.
12263 }
12264 } else {
12265 sign = -1; // Not a boundary edge.
12266 }
12267 } else {
12268 // No adjacent face. It is a hull edge.
12269 if (loc == OUTSIDE) {
12270 // It is a boundary edge if it does not contain p.
12271 if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
12272 sign = -1; // Not a boundary edge.
12273 } else {
12274 sign = 1; // A boundary edge.
12275 }
12276 } else {
12277 sign = 1; // A boundary edge.
12278 }
12279 }
12280 } else {
12281 // Do not across a segment. It is a boundary edge.
12282 sign = 1;
12283 }
12284 if (sign >= 0) {
12285 // Add a boundary edge.
12286 caveshbdlist->newindex((void **) &parysh);
12287 *parysh = cavesh;
12288 }
12289 senextself(cavesh);
12290 } // j
12291 } // i
12292
12293
12294 // Creating new subfaces.
12295 for (i = 0; i < caveshbdlist->objects; i++) {
12296 parysh = (face *) fastlookup(caveshbdlist, i);
12297 sspivot(*parysh, checkseg);
12298 if ((parysh->shver & 01) != 0) sesymself(*parysh);
12299 pa = sorg(*parysh);
12300 pb = sdest(*parysh);
12301 // Create a new subface.
12302 makeshellface(subfaces, &newsh);
12303 setshvertices(newsh, pa, pb, insertpt);
12304 setshellmark(newsh, shellmark(*parysh));
12305 if (checkconstraints) {
12306 //area = areabound(*parysh);
12307 setareabound(newsh, areabound(*parysh));
12308 }
12309 if (useinsertradius) {
12310 setfacetindex(newsh, getfacetindex(*parysh));
12311 }
12312 // Update the point-to-subface map.
12313 if (pointtype(pa) == FREEFACETVERTEX) {
12314 setpoint2sh(pa, sencode(newsh));
12315 }
12316 if (pointtype(pb) == FREEFACETVERTEX) {
12317 setpoint2sh(pb, sencode(newsh));
12318 }
12319 // Connect newsh to outer subfaces.
12320 spivot(*parysh, casout);
12321 if (casout.sh != NULL) {
12322 casin = casout;
12323 if (checkseg.sh != NULL) {
12324 // Make sure that newsh has the right ori at this segment.
12325 checkseg.shver = 0;
12326 if (sorg(newsh) != sorg(checkseg)) {
12327 sesymself(newsh);
12328 sesymself(*parysh); // This side should also be inverse.
12329 }
12330 spivot(casin, neighsh);
12331 while (neighsh.sh != parysh->sh) {
12332 casin = neighsh;
12333 spivot(casin, neighsh);
12334 }
12335 }
12336 sbond1(newsh, casout);
12337 sbond1(casin, newsh);
12338 }
12339 if (checkseg.sh != NULL) {
12340 ssbond(newsh, checkseg);
12341 }
12342 // Connect oldsh <== newsh (for connecting adjacent new subfaces).
12343 // *parysh and newsh point to the same edge and the same ori.
12344 sbond1(*parysh, newsh);
12345 }
12346
12347 if (newsh.sh != NULL) {
12348 // Set a handle for searching.
12349 recentsh = newsh;
12350 }
12351
12352 // Update the point-to-subface map.
12353 if (pointtype(insertpt) == FREEFACETVERTEX) {
12354 setpoint2sh(insertpt, sencode(newsh));
12355 }
12356
12357 // Connect adjacent new subfaces together.
12358 for (i = 0; i < caveshbdlist->objects; i++) {
12359 // Get an old subface at edge [a, b].
12360 parysh = (face *) fastlookup(caveshbdlist, i);
12361 spivot(*parysh, newsh); // The new subface [a, b, p].
12362 senextself(newsh); // At edge [b, p].
12363 spivot(newsh, neighsh);
12364 if (neighsh.sh == NULL) {
12365 // Find the adjacent new subface at edge [b, p].
12366 pb = sdest(*parysh);
12367 neighsh = *parysh;
12368 while (1) {
12369 senextself(neighsh);
12370 spivotself(neighsh);
12371 if (neighsh.sh == NULL) break;
12372 if (!smarktested(neighsh)) break;
12373 if (sdest(neighsh) != pb) sesymself(neighsh);
12374 }
12375 if (neighsh.sh != NULL) {
12376 // Now 'neighsh' is a new subface at edge [b, #].
12377 if (sorg(neighsh) != pb) sesymself(neighsh);
12378 senext2self(neighsh); // Go to the open edge [p, b].
12379 sbond(newsh, neighsh);
12380 } else {
12381 // There is no adjacent new face at this side.
12382 assert(loc == OUTSIDE); // SELF_CHECK
12383 }
12384 }
12385 spivot(*parysh, newsh); // The new subface [a, b, p].
12386 senext2self(newsh); // At edge [p, a].
12387 spivot(newsh, neighsh);
12388 if (neighsh.sh == NULL) {
12389 // Find the adjacent new subface at edge [p, a].
12390 pa = sorg(*parysh);
12391 neighsh = *parysh;
12392 while (1) {
12393 senext2self(neighsh);
12394 spivotself(neighsh);
12395 if (neighsh.sh == NULL) break;
12396 if (!smarktested(neighsh)) break;
12397 if (sorg(neighsh) != pa) sesymself(neighsh);
12398 }
12399 if (neighsh.sh != NULL) {
12400 // Now 'neighsh' is a new subface at edge [#, a].
12401 if (sdest(neighsh) != pa) sesymself(neighsh);
12402 senextself(neighsh); // Go to the open edge [a, p].
12403 sbond(newsh, neighsh);
12404 } else {
12405 // There is no adjacent new face at this side.
12406 assert(loc == OUTSIDE); // SELF_CHECK
12407 }
12408 }
12409 }
12410
12411 if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
12412 || (cavesegshlist->objects > 0l)) {
12413 // An edge is being split. We distinguish two cases:
12414 // (1) the edge is not on the boundary of the cavity;
12415 // (2) the edge is on the boundary of the cavity.
12416 // In case (2), the edge is either a segment or a hull edge. There are
12417 // degenerated new faces in the cavity. They must be removed.
12418 face aseg, bseg, aoutseg, boutseg;
12419
12420 for (i = 0; i < cavesegshlist->objects; i++) {
12421 // Get the saved old subface.
12422 parysh = (face *) fastlookup(cavesegshlist, i);
12423 // Get a possible new degenerated subface.
12424 spivot(*parysh, cavesh);
12425 if (sapex(cavesh) == insertpt) {
12426 // Found a degenerated new subface, i.e., case (2).
12427 if (cavesegshlist->objects > 1) {
12428 // There are more than one subface share at this edge.
12429 j = (i + 1) % (int) cavesegshlist->objects;
12430 parysh = (face *) fastlookup(cavesegshlist, j);
12431 spivot(*parysh, neighsh);
12432 // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
12433 if (sorg(neighsh) != sorg(cavesh)) {
12434 sesymself(neighsh);
12435 assert(sorg(neighsh) == sorg(cavesh)); // SELF_CHECK
12436 }
12437 assert(sapex(neighsh) == insertpt); // SELF_CHECK
12438 // Connect adjacent faces at two other edges of cavesh and neighsh.
12439 // As a result, the two degenerated new faces are squeezed from the
12440 // new triangulation of the cavity. Note that the squeezed faces
12441 // still hold the adjacent informations which will be used in
12442 // re-connecting subsegments (if they exist).
12443 for (j = 0; j < 2; j++) {
12444 senextself(cavesh);
12445 senextself(neighsh);
12446 spivot(cavesh, newsh);
12447 spivot(neighsh, casout);
12448 sbond1(newsh, casout); // newsh <- casout.
12449 }
12450 } else {
12451 // There is only one subface containing this edge [a,b]. Squeeze the
12452 // degenerated new face [a,b,c] by disconnecting it from its two
12453 // adjacent subfaces at edges [b,c] and [c,a]. Note that the face
12454 // [a,b,c] still hold the connection to them.
12455 for (j = 0; j < 2; j++) {
12456 senextself(cavesh);
12457 spivot(cavesh, newsh);
12458 sdissolve(newsh);
12459 }
12460 }
12461 //recentsh = newsh;
12462 // Update the point-to-subface map.
12463 if (pointtype(insertpt) == FREEFACETVERTEX) {
12464 setpoint2sh(insertpt, sencode(newsh));
12465 }
12466 }
12467 }
12468
12469 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12470 if (loc != INSTAR) { // if (bowywat < 3) {
12471 smarktest(*splitseg); // Mark it as being processed.
12472 }
12473
12474 aseg = *splitseg;
12475 pa = sorg(*splitseg);
12476 pb = sdest(*splitseg);
12477
12478 // Insert the new point p.
12479 makeshellface(subsegs, &aseg);
12480 makeshellface(subsegs, &bseg);
12481
12482 setshvertices(aseg, pa, insertpt, NULL);
12483 setshvertices(bseg, insertpt, pb, NULL);
12484 setshellmark(aseg, shellmark(*splitseg));
12485 setshellmark(bseg, shellmark(*splitseg));
12486 if (checkconstraints) {
12487 setareabound(aseg, areabound(*splitseg));
12488 setareabound(bseg, areabound(*splitseg));
12489 }
12490 if (useinsertradius) {
12491 setfacetindex(aseg, getfacetindex(*splitseg));
12492 setfacetindex(bseg, getfacetindex(*splitseg));
12493 }
12494
12495 // Connect [#, a]<->[a, p].
12496 senext2(*splitseg, boutseg); // Temporarily use boutseg.
12497 spivotself(boutseg);
12498 if (boutseg.sh != NULL) {
12499 senext2(aseg, aoutseg);
12500 sbond(boutseg, aoutseg);
12501 }
12502 // Connect [p, b]<->[b, #].
12503 senext(*splitseg, aoutseg);
12504 spivotself(aoutseg);
12505 if (aoutseg.sh != NULL) {
12506 senext(bseg, boutseg);
12507 sbond(boutseg, aoutseg);
12508 }
12509 // Connect [a, p] <-> [p, b].
12510 senext(aseg, aoutseg);
12511 senext2(bseg, boutseg);
12512 sbond(aoutseg, boutseg);
12513
12514 // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
12515 // Although the degenerated new faces have been squeezed. They still
12516 // hold the connections to the actual new faces.
12517 for (i = 0; i < cavesegshlist->objects; i++) {
12518 parysh = (face *) fastlookup(cavesegshlist, i);
12519 spivot(*parysh, neighsh);
12520 // neighsh is a degenerated new face.
12521 if (sorg(neighsh) != pa) {
12522 sesymself(neighsh);
12523 }
12524 senext2(neighsh, newsh);
12525 spivotself(newsh); // The edge [p, a] in newsh
12526 ssbond(newsh, aseg);
12527 senext(neighsh, newsh);
12528 spivotself(newsh); // The edge [b, p] in newsh
12529 ssbond(newsh, bseg);
12530 }
12531
12532
12533 // Let the point remember the segment it lies on.
12534 if (pointtype(insertpt) == FREESEGVERTEX) {
12535 setpoint2sh(insertpt, sencode(aseg));
12536 }
12537 // Update the point-to-seg map.
12538 if (pointtype(pa) == FREESEGVERTEX) {
12539 setpoint2sh(pa, sencode(aseg));
12540 }
12541 if (pointtype(pb) == FREESEGVERTEX) {
12542 setpoint2sh(pb, sencode(bseg));
12543 }
12544 } // if ((splitseg != NULL) && (splitseg->sh != NULL))
12545
12546 // Delete all degenerated new faces.
12547 for (i = 0; i < cavesegshlist->objects; i++) {
12548 parysh = (face *) fastlookup(cavesegshlist, i);
12549 spivotself(*parysh);
12550 if (sapex(*parysh) == insertpt) {
12551 shellfacedealloc(subfaces, parysh->sh);
12552 }
12553 }
12554 cavesegshlist->restart();
12555
12556 if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12557 // Return the two new subsegments (for further process).
12558 // Re-use 'cavesegshlist'.
12559 cavesegshlist->newindex((void **) &parysh);
12560 *parysh = aseg;
12561 cavesegshlist->newindex((void **) &parysh);
12562 *parysh = bseg;
12563 }
12564 } // if (loc == ONEDGE)
12565
12566
12567 return (int) loc;
12568}
12569
12570///////////////////////////////////////////////////////////////////////////////
12571// //
12572// sremovevertex() Remove a vertex from the surface mesh. //
12573// //
12574// 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
12575// a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a //
12576// facet vertex, and the origin of 'parentsh' is p. //
12577// //
12578// Within each facet, we first use a sequence of 2-to-2 flips to flip any //
12579// edge at p, finally use a 3-to-1 flip to remove p. //
12580// //
12581// All new created subfaces are returned in the global array 'caveshbdlist'. //
12582// The new segment (when p is on segment) is returned in 'parentseg'. //
12583// //
12584// If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay- //
12585// ness after p is removed. //
12586// //
12587///////////////////////////////////////////////////////////////////////////////
12588
12589int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
12590 int lawson)
12591{
12592 face flipfaces[4], spinsh, *parysh;
12593 point pa, pb, pc, pd;
12594 REAL ori1, ori2;
12595 int it, i, j;
12596
12597 if (parentseg != NULL) {
12598 // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
12599 // where 'parentseg' should be [p,b]. Find the segment [a,p].
12600 face startsh, neighsh, nextsh;
12601 face abseg, prevseg, checkseg;
12602 face adjseg1, adjseg2;
12603 face fakesh;
12604 senext2(*parentseg, prevseg);
12605 spivotself(prevseg);
12606 prevseg.shver = 0;
12607 assert(sdest(prevseg) == delpt);
12608 // Restore the original segment [a,b].
12609 pa = sorg(prevseg);
12610 pb = sdest(*parentseg);
12611 if (b->verbose > 2) {
12612 printf(" Remove vertex %d from segment [%d, %d].\n",
12613 pointmark(delpt), pointmark(pa), pointmark(pb));
12614 }
12615 makeshellface(subsegs, &abseg);
12616 setshvertices(abseg, pa, pb, NULL);
12617 setshellmark(abseg, shellmark(*parentseg));
12618 if (checkconstraints) {
12619 setareabound(abseg, areabound(*parentseg));
12620 }
12621 if (useinsertradius) {
12622 setfacetindex(abseg, getfacetindex(*parentseg));
12623 }
12624 // Connect [#, a]<->[a, b].
12625 senext2(prevseg, adjseg1);
12626 spivotself(adjseg1);
12627 if (adjseg1.sh != NULL) {
12628 adjseg1.shver = 0;
12629 assert(sdest(adjseg1) == pa);
12630 senextself(adjseg1);
12631 senext2(abseg, adjseg2);
12632 sbond(adjseg1, adjseg2);
12633 }
12634 // Connect [a, b]<->[b, #].
12635 senext(*parentseg, adjseg1);
12636 spivotself(adjseg1);
12637 if (adjseg1.sh != NULL) {
12638 adjseg1.shver = 0;
12639 assert(sorg(adjseg1) == pb);
12640 senext2self(adjseg1);
12641 senext(abseg, adjseg2);
12642 sbond(adjseg1, adjseg2);
12643 }
12644 // Update the point-to-segment map.
12645 setpoint2sh(pa, sencode(abseg));
12646 setpoint2sh(pb, sencode(abseg));
12647
12648 // Get the faces in face ring at segment [p, b].
12649 // Re-use array 'caveshlist'.
12650 spivot(*parentseg, *parentsh);
12651 if (parentsh->sh != NULL) {
12652 spinsh = *parentsh;
12653 while (1) {
12654 // Save this face in list.
12655 caveshlist->newindex((void **) &parysh);
12656 *parysh = spinsh;
12657 // Go to the next face in the ring.
12658 spivotself(spinsh);
12659 if (spinsh.sh == parentsh->sh) break;
12660 }
12661 }
12662
12663 // Create the face ring of the new segment [a,b]. Each face in the ring
12664 // is [a,b,p] (degenerated!). It will be removed (automatically).
12665 for (i = 0; i < caveshlist->objects; i++) {
12666 parysh = (face *) fastlookup(caveshlist, i);
12667 startsh = *parysh;
12668 if (sorg(startsh) != delpt) {
12669 sesymself(startsh);
12670 assert(sorg(startsh) == delpt);
12671 }
12672 // startsh is [p, b, #1], find the subface [a, p, #2].
12673 neighsh = startsh;
12674 while (1) {
12675 senext2self(neighsh);
12676 sspivot(neighsh, checkseg);
12677 if (checkseg.sh != NULL) {
12678 // It must be the segment [a, p].
12679 assert(checkseg.sh == prevseg.sh);
12680 break;
12681 }
12682 spivotself(neighsh);
12683 assert(neighsh.sh != NULL);
12684 if (sorg(neighsh) != delpt) sesymself(neighsh);
12685 }
12686 // Now neighsh is [a, p, #2].
12687 if (neighsh.sh != startsh.sh) {
12688 // Detach the two subsegments [a,p] and [p,b] from subfaces.
12689 ssdissolve(startsh);
12690 ssdissolve(neighsh);
12691 // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
12692 // new segment [a,b]; (2) connect to the two adjacent subfaces
12693 // [p,b,#] and [a,p,#].
12694 makeshellface(subfaces, &fakesh);
12695 setshvertices(fakesh, pa, pb, delpt);
12696 setshellmark(fakesh, shellmark(startsh));
12697 // Connect fakesh to the segment [a,b].
12698 ssbond(fakesh, abseg);
12699 // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
12700 senext(fakesh, nextsh);
12701 sbond(nextsh, startsh);
12702 senext2(fakesh, nextsh);
12703 sbond(nextsh, neighsh);
12704 smarktest(fakesh); // Mark it as faked.
12705 } else {
12706 // Special case. There exists already a degenerated face [a,b,p]!
12707 // There is no need to create a faked subface here.
12708 senext2self(neighsh); // [a,b,p]
12709 assert(sapex(neighsh) == delpt);
12710 // Since we will re-connect the face ring using the faked subfaces.
12711 // We put the adjacent face of [a,b,p] to the list.
12712 spivot(neighsh, startsh); // The original adjacent subface.
12713 if (sorg(startsh) != pa) sesymself(startsh);
12714 sdissolve(startsh);
12715 // Connect fakesh to the segment [a,b].
12716 ssbond(startsh, abseg);
12717 fakesh = startsh; // Do not mark it!
12718 // Delete the degenerated subface.
12719 shellfacedealloc(subfaces, neighsh.sh);
12720 }
12721 // Save the fakesh in list (for re-creating the face ring).
12722 cavesegshlist->newindex((void **) &parysh);
12723 *parysh = fakesh;
12724 } // i
12725 caveshlist->restart();
12726
12727 // Re-create the face ring.
12728 if (cavesegshlist->objects > 1) {
12729 for (i = 0; i < cavesegshlist->objects; i++) {
12730 parysh = (face *) fastlookup(cavesegshlist, i);
12731 fakesh = *parysh;
12732 // Get the next face in the ring.
12733 j = (i + 1) % cavesegshlist->objects;
12734 parysh = (face *) fastlookup(cavesegshlist, j);
12735 nextsh = *parysh;
12736 sbond1(fakesh, nextsh);
12737 }
12738 }
12739
12740 // Delete the two subsegments containing p.
12741 shellfacedealloc(subsegs, parentseg->sh);
12742 shellfacedealloc(subsegs, prevseg.sh);
12743 // Return the new segment.
12744 *parentseg = abseg;
12745 } else {
12746 // p is inside the surface.
12747 if (b->verbose > 2) {
12748 printf(" Remove vertex %d from surface.\n", pointmark(delpt));
12749 }
12750 assert(sorg(*parentsh) == delpt);
12751 // Let 'delpt' be its apex.
12752 senextself(*parentsh);
12753 // For unifying the code, we add parentsh to list.
12754 cavesegshlist->newindex((void **) &parysh);
12755 *parysh = *parentsh;
12756 }
12757
12758 // Remove the point (p).
12759
12760 for (it = 0; it < cavesegshlist->objects; it++) {
12761 parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
12762 senextself(*parentsh); // [b,p,a].
12763 spivotself(*parentsh);
12764 if (sorg(*parentsh) != delpt) sesymself(*parentsh);
12765 // now parentsh is [p,b,#].
12766 if (sorg(*parentsh) != delpt) {
12767 // The vertex has already been removed in above special case.
12768 assert(!smarktested(*parentsh));
12769 continue;
12770 }
12771
12772 while (1) {
12773 // Initialize the flip edge list. Re-use 'caveshlist'.
12774 spinsh = *parentsh; // [p, b, #]
12775 while (1) {
12776 caveshlist->newindex((void **) &parysh);
12777 *parysh = spinsh;
12778 senext2self(spinsh);
12779 spivotself(spinsh);
12780 assert(spinsh.sh != NULL);
12781 if (spinsh.sh == parentsh->sh) break;
12782 if (sorg(spinsh) != delpt) sesymself(spinsh);
12783 assert(sorg(spinsh) == delpt);
12784 } // while (1)
12785
12786 if (caveshlist->objects == 3) {
12787 // Delete the point by a 3-to-1 flip.
12788 for (i = 0; i < 3; i++) {
12789 parysh = (face *) fastlookup(caveshlist, i);
12790 flipfaces[i] = *parysh;
12791 }
12792 flip31(flipfaces, lawson);
12793 for (i = 0; i < 3; i++) {
12794 shellfacedealloc(subfaces, flipfaces[i].sh);
12795 }
12796 caveshlist->restart();
12797 // Save the new subface.
12798 caveshbdlist->newindex((void **) &parysh);
12799 *parysh = flipfaces[3];
12800 // The vertex is removed.
12801 break;
12802 }
12803
12804 // Search an edge to flip.
12805 for (i = 0; i < caveshlist->objects; i++) {
12806 parysh = (face *) fastlookup(caveshlist, i);
12807 flipfaces[0] = *parysh;
12808 spivot(flipfaces[0], flipfaces[1]);
12809 if (sorg(flipfaces[0]) != sdest(flipfaces[1]))
12810 sesymself(flipfaces[1]);
12811 // Skip this edge if it belongs to a faked subface.
12812 if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
12813 pa = sorg(flipfaces[0]);
12814 pb = sdest(flipfaces[0]);
12815 pc = sapex(flipfaces[0]);
12816 pd = sapex(flipfaces[1]);
12817 calculateabovepoint4(pa, pb, pc, pd);
12818 // Check if a 2-to-2 flip is possible.
12819 ori1 = orient3d(pc, pd, dummypoint, pa);
12820 ori2 = orient3d(pc, pd, dummypoint, pb);
12821 if (ori1 * ori2 < 0) {
12822 // A 2-to-2 flip is found.
12823 flip22(flipfaces, lawson, 0);
12824 // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
12825 // changed. The 'flipfaces[1]' contains p as its apex.
12826 senext2(flipfaces[1], *parentsh);
12827 // Save the new subface.
12828 caveshbdlist->newindex((void **) &parysh);
12829 *parysh = flipfaces[0];
12830 break;
12831 }
12832 } //
12833 } // i
12834
12835 if (i == caveshlist->objects) {
12836 // This can happen only if there are 4 edges at p, and they are
12837 // orthogonal to each other, see Fig. 2010-11-01.
12838 assert(caveshlist->objects == 4);
12839 // Do a flip22 and a flip31 to remove p.
12840 parysh = (face *) fastlookup(caveshlist, 0);
12841 flipfaces[0] = *parysh;
12842 spivot(flipfaces[0], flipfaces[1]);
12843 if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
12844 sesymself(flipfaces[1]);
12845 }
12846 flip22(flipfaces, lawson, 0);
12847 senext2(flipfaces[1], *parentsh);
12848 // Save the new subface.
12849 caveshbdlist->newindex((void **) &parysh);
12850 *parysh = flipfaces[0];
12851 }
12852
12853 // The edge list at p are changed.
12854 caveshlist->restart();
12855 } // while (1)
12856
12857 } // it
12858
12859 cavesegshlist->restart();
12860
12861 if (b->verbose > 2) {
12862 printf(" Created %ld new subfaces.\n", caveshbdlist->objects);
12863 }
12864
12865
12866 if (lawson) {
12867 lawsonflip();
12868 }
12869
12870 return 0;
12871}
12872
12873///////////////////////////////////////////////////////////////////////////////
12874// //
12875// slocate() Locate a point in a surface triangulation. //
12876// //
12877// Staring the search from 'searchsh'(it should not be NULL). Perform a line //
12878// walk search for a subface containing the point (p). //
12879// //
12880// If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies //
12881// above the 'searchsh' in its current orientation. The test if c is CCW to //
12882// the line a->b can be done by the test if c is below the oriented plane //
12883// a->b->dummypoint. //
12884// //
12885// If 'cflag' is not TRUE, the triangulation may not be convex. Stop search //
12886// when a segment is met and return OUTSIDE. //
12887// //
12888// If 'rflag' (rounding) is set, after the location of the point is found, //
12889// either ONEDGE or ONFACE, round the result using an epsilon. //
12890// //
12891// The returned value indicates the following cases: //
12892// - ONVERTEX, p is the origin of 'searchsh'. //
12893// - ONEDGE, p lies on the edge of 'searchsh'. //
12894// - ONFACE, p lies in the interior of 'searchsh'. //
12895// - OUTSIDE, p lies outside of the triangulation, p is on the left-hand //
12896// side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW. //
12897// //
12898///////////////////////////////////////////////////////////////////////////////
12899
12900enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
12901 face* searchsh, int aflag, int cflag, int rflag)
12902{
12903 face neighsh;
12904 point pa, pb, pc;
12905 enum locateresult loc;
12906 enum {MOVE_BC, MOVE_CA} nextmove;
12907 REAL ori, ori_bc, ori_ca;
12908 int i;
12909
12910 pa = sorg(*searchsh);
12911 pb = sdest(*searchsh);
12912 pc = sapex(*searchsh);
12913
12914 if (!aflag) {
12915 // No above point is given. Calculate an above point for this facet.
12916 calculateabovepoint4(pa, pb, pc, searchpt);
12917 }
12918
12919 // 'dummypoint' is given. Make sure it is above [a,b,c]
12920 ori = orient3d(pa, pb, pc, dummypoint);
12921 assert(ori != 0); // SELF_CHECK
12922 if (ori > 0) {
12923 sesymself(*searchsh); // Reverse the face orientation.
12924 }
12925
12926 // Find an edge of the face s.t. p lies on its right-hand side (CCW).
12927 for (i = 0; i < 3; i++) {
12928 pa = sorg(*searchsh);
12929 pb = sdest(*searchsh);
12930 ori = orient3d(pa, pb, dummypoint, searchpt);
12931 if (ori > 0) break;
12932 senextself(*searchsh);
12933 }
12934 assert(i < 3); // SELF_CHECK
12935
12936 pc = sapex(*searchsh);
12937
12938 if (pc == searchpt) {
12939 senext2self(*searchsh);
12940 return ONVERTEX;
12941 }
12942
12943 while (1) {
12944
12945 ori_bc = orient3d(pb, pc, dummypoint, searchpt);
12946 ori_ca = orient3d(pc, pa, dummypoint, searchpt);
12947
12948 if (ori_bc < 0) {
12949 if (ori_ca < 0) { // (--)
12950 // Any of the edges is a viable move.
12951 if (randomnation(2)) {
12952 nextmove = MOVE_CA;
12953 } else {
12954 nextmove = MOVE_BC;
12955 }
12956 } else { // (-#)
12957 // Edge [b, c] is viable.
12958 nextmove = MOVE_BC;
12959 }
12960 } else {
12961 if (ori_ca < 0) { // (#-)
12962 // Edge [c, a] is viable.
12963 nextmove = MOVE_CA;
12964 } else {
12965 if (ori_bc > 0) {
12966 if (ori_ca > 0) { // (++)
12967 loc = ONFACE; // Inside [a, b, c].
12968 break;
12969 } else { // (+0)
12970 senext2self(*searchsh); // On edge [c, a].
12971 loc = ONEDGE;
12972 break;
12973 }
12974 } else { // ori_bc == 0
12975 if (ori_ca > 0) { // (0+)
12976 senextself(*searchsh); // On edge [b, c].
12977 loc = ONEDGE;
12978 break;
12979 } else { // (00)
12980 // p is coincident with vertex c.
12981 senext2self(*searchsh);
12982 return ONVERTEX;
12983 }
12984 }
12985 }
12986 }
12987
12988 // Move to the next face.
12989 if (nextmove == MOVE_BC) {
12990 senextself(*searchsh);
12991 } else {
12992 senext2self(*searchsh);
12993 }
12994 if (!cflag) {
12995 // NON-convex case. Check if we will cross a boundary.
12996 if (isshsubseg(*searchsh)) {
12997 return ENCSEGMENT;
12998 }
12999 }
13000 spivot(*searchsh, neighsh);
13001 if (neighsh.sh == NULL) {
13002 return OUTSIDE; // A hull edge.
13003 }
13004 // Adjust the edge orientation.
13005 if (sorg(neighsh) != sdest(*searchsh)) {
13006 sesymself(neighsh);
13007 }
13008 assert(sorg(neighsh) == sdest(*searchsh)); // SELF_CHECK
13009
13010 // Update the newly discovered face and its endpoints.
13011 *searchsh = neighsh;
13012 pa = sorg(*searchsh);
13013 pb = sdest(*searchsh);
13014 pc = sapex(*searchsh);
13015
13016 if (pc == searchpt) {
13017 senext2self(*searchsh);
13018 return ONVERTEX;
13019 }
13020
13021 } // while (1)
13022
13023 // assert(loc == ONFACE || loc == ONEDGE);
13024
13025
13026 if (rflag) {
13027 // Round the locate result before return.
13028 REAL n[3], area_abc, area_abp, area_bcp, area_cap;
13029
13030 pa = sorg(*searchsh);
13031 pb = sdest(*searchsh);
13032 pc = sapex(*searchsh);
13033
13034 facenormal(pa, pb, pc, n, 1, NULL);
13035 area_abc = sqrt(dot(n, n));
13036
13037 facenormal(pb, pc, searchpt, n, 1, NULL);
13038 area_bcp = sqrt(dot(n, n));
13039 if ((area_bcp / area_abc) < b->epsilon) {
13040 area_bcp = 0; // Rounding.
13041 }
13042
13043 facenormal(pc, pa, searchpt, n, 1, NULL);
13044 area_cap = sqrt(dot(n, n));
13045 if ((area_cap / area_abc) < b->epsilon) {
13046 area_cap = 0; // Rounding
13047 }
13048
13049 if ((loc == ONFACE) || (loc == OUTSIDE)) {
13050 facenormal(pa, pb, searchpt, n, 1, NULL);
13051 area_abp = sqrt(dot(n, n));
13052 if ((area_abp / area_abc) < b->epsilon) {
13053 area_abp = 0; // Rounding
13054 }
13055 } else { // loc == ONEDGE
13056 area_abp = 0;
13057 }
13058
13059 if (area_abp == 0) {
13060 if (area_bcp == 0) {
13061 assert(area_cap != 0);
13062 senextself(*searchsh);
13063 loc = ONVERTEX; // p is close to b.
13064 } else {
13065 if (area_cap == 0) {
13066 loc = ONVERTEX; // p is close to a.
13067 } else {
13068 loc = ONEDGE; // p is on edge [a,b].
13069 }
13070 }
13071 } else if (area_bcp == 0) {
13072 if (area_cap == 0) {
13073 senext2self(*searchsh);
13074 loc = ONVERTEX; // p is close to c.
13075 } else {
13076 senextself(*searchsh);
13077 loc = ONEDGE; // p is on edge [b,c].
13078 }
13079 } else if (area_cap == 0) {
13080 senext2self(*searchsh);
13081 loc = ONEDGE; // p is on edge [c,a].
13082 } else {
13083 loc = ONFACE; // p is on face [a,b,c].
13084 }
13085 } // if (rflag)
13086
13087 return loc;
13088}
13089
13090///////////////////////////////////////////////////////////////////////////////
13091// //
13092// sscoutsegment() Look for a segment in surface triangulation. //
13093// //
13094// The segment is given by the origin of 'searchsh' and 'endpt'. Assume the //
13095// orientation of 'searchsh' is CCW w.r.t. the above point. //
13096// //
13097// If an edge in T is found matching this segment, the segment is "locked" //
13098// in T at the edge. Otherwise, flip the first edge in T that the segment //
13099// crosses. Continue the search from the flipped face. //
13100// //
13101///////////////////////////////////////////////////////////////////////////////
13102
13103enum tetgenmesh::interresult tetgenmesh::sscoutsegment(face *searchsh,
13104 point endpt)
13105{
13106 face flipshs[2], neighsh;
13107 face newseg;
13108 point startpt, pa, pb, pc, pd;
13109 enum interresult dir;
13110 enum {MOVE_AB, MOVE_CA} nextmove;
13111 REAL ori_ab, ori_ca, len;
13112
13113 // The origin of 'searchsh' is fixed.
13114 startpt = sorg(*searchsh); // pa = startpt;
13115 nextmove = MOVE_AB; // Avoid compiler warning.
13116
13117 if (b->verbose > 2) {
13118 printf(" Scout segment (%d, %d).\n", pointmark(startpt),
13119 pointmark(endpt));
13120 }
13121 len = distance(startpt, endpt);
13122
13123 // Search an edge in 'searchsh' on the path of this segment.
13124 while (1) {
13125
13126 pb = sdest(*searchsh);
13127 if (pb == endpt) {
13128 dir = SHAREEDGE; // Found!
13129 break;
13130 }
13131
13132 pc = sapex(*searchsh);
13133 if (pc == endpt) {
13134 senext2self(*searchsh);
13135 sesymself(*searchsh);
13136 dir = SHAREEDGE; // Found!
13137 break;
13138 }
13139
13140 // Round the results.
13141 if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
13142 ori_ab = 0.0;
13143 } else {
13144 ori_ab = orient3d(startpt, pb, dummypoint, endpt);
13145 }
13146 if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
13147 ori_ca = 0.0;
13148 } else {
13149 ori_ca = orient3d(pc, startpt, dummypoint, endpt);
13150 }
13151
13152 if (ori_ab < 0) {
13153 if (ori_ca < 0) { // (--)
13154 // Both sides are viable moves.
13155 if (randomnation(2)) {
13156 nextmove = MOVE_CA;
13157 } else {
13158 nextmove = MOVE_AB;
13159 }
13160 } else { // (-#)
13161 nextmove = MOVE_AB;
13162 }
13163 } else {
13164 if (ori_ca < 0) { // (#-)
13165 nextmove = MOVE_CA;
13166 } else {
13167 if (ori_ab > 0) {
13168 if (ori_ca > 0) { // (++)
13169 // The segment intersects with edge [b, c].
13170 dir = ACROSSEDGE;
13171 break;
13172 } else { // (+0)
13173 // The segment collinear with edge [c, a].
13174 senext2self(*searchsh);
13175 sesymself(*searchsh);
13176 dir = ACROSSVERT;
13177 break;
13178 }
13179 } else {
13180 if (ori_ca > 0) { // (0+)
13181 // The segment collinear with edge [a, b].
13182 dir = ACROSSVERT;
13183 break;
13184 } else { // (00)
13185 // startpt == endpt. Not possible.
13186 assert(0); // SELF_CHECK
13187 }
13188 }
13189 }
13190 }
13191
13192 // Move 'searchsh' to the next face, keep the origin unchanged.
13193 if (nextmove == MOVE_AB) {
13194 spivot(*searchsh, neighsh);
13195 if (neighsh.sh != NULL) {
13196 if (sorg(neighsh) != pb) sesymself(neighsh);
13197 senext(neighsh, *searchsh);
13198 } else {
13199 // This side (startpt->pb) is outside. It is caused by rounding error.
13200 // Try the next side, i.e., (pc->startpt).
13201 senext2(*searchsh, neighsh);
13202 spivotself(neighsh);
13203 assert(neighsh.sh != NULL);
13204 if (sdest(neighsh) != pc) sesymself(neighsh);
13205 *searchsh = neighsh;
13206 }
13207 } else {
13208 senext2(*searchsh, neighsh);
13209 spivotself(neighsh);
13210 if (neighsh.sh != NULL) {
13211 if (sdest(neighsh) != pc) sesymself(neighsh);
13212 *searchsh = neighsh;
13213 } else {
13214 // The same reason as above.
13215 // Try the next side, i.e., (startpt->pb).
13216 spivot(*searchsh, neighsh);
13217 assert(neighsh.sh != NULL);
13218 if (sorg(neighsh) != pb) sesymself(neighsh);
13219 senext(neighsh, *searchsh);
13220 }
13221 }
13222 assert(sorg(*searchsh) == startpt); // SELF_CHECK
13223
13224 } // while
13225
13226 if (dir == SHAREEDGE) {
13227 // Insert the segment into the triangulation.
13228 makeshellface(subsegs, &newseg);
13229 setshvertices(newseg, startpt, endpt, NULL);
13230 // Set the default segment marker.
13231 setshellmark(newseg, 1);
13232 ssbond(*searchsh, newseg);
13233 spivot(*searchsh, neighsh);
13234 if (neighsh.sh != NULL) {
13235 ssbond(neighsh, newseg);
13236 }
13237 return dir;
13238 }
13239
13240 if (dir == ACROSSVERT) {
13241 // A point is found collinear with this segment.
13242 return dir;
13243 }
13244
13245 if (dir == ACROSSEDGE) {
13246 // Edge [b, c] intersects with the segment.
13247 senext(*searchsh, flipshs[0]);
13248 if (isshsubseg(flipshs[0])) {
13249 printf("Error: Invalid PLC.\n");
13250 pb = sorg(flipshs[0]);
13251 pc = sdest(flipshs[0]);
13252 printf(" Two segments (%d, %d) and (%d, %d) intersect.\n",
13253 pointmark(startpt), pointmark(endpt), pointmark(pb), pointmark(pc));
13254 terminatetetgen(this, 3);
13255 }
13256 // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
13257 spivot(flipshs[0], flipshs[1]);
13258 assert(flipshs[1].sh != NULL); // SELF_CHECK
13259 if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
13260 flip22(flipshs, 1, 0);
13261 // The flip may create an inverted triangle, check it.
13262 pa = sapex(flipshs[1]);
13263 pb = sapex(flipshs[0]);
13264 pc = sorg(flipshs[0]);
13265 pd = sdest(flipshs[0]);
13266 // Check if pa and pb are on the different sides of [pc, pd].
13267 // Re-use ori_ab, ori_ca for the tests.
13268 ori_ab = orient3d(pc, pd, dummypoint, pb);
13269 ori_ca = orient3d(pd, pc, dummypoint, pa);
13270 //assert(ori_ab * ori_ca != 0); // SELF_CHECK
13271 if (ori_ab < 0) {
13272 flipshpush(&(flipshs[0])); // push it to 'flipstack'
13273 } else if (ori_ca < 0) {
13274 flipshpush(&(flipshs[1])); // // push it to 'flipstack'
13275 }
13276 // Set 'searchsh' s.t. its origin is 'startpt'.
13277 *searchsh = flipshs[0];
13278 assert(sorg(*searchsh) == startpt);
13279 }
13280
13281 return sscoutsegment(searchsh, endpt);
13282}
13283
13284///////////////////////////////////////////////////////////////////////////////
13285// //
13286// scarveholes() Remove triangles not in the facet. //
13287// //
13288// This routine re-uses the two global arrays: caveshlist and caveshbdlist. //
13289// //
13290///////////////////////////////////////////////////////////////////////////////
13291
13292void tetgenmesh::scarveholes(int holes, REAL* holelist)
13293{
13294 face *parysh, searchsh, neighsh;
13295 enum locateresult loc;
13296 int i, j;
13297
13298 // Get all triangles. Infect unprotected convex hull triangles.
13299 smarktest(recentsh);
13300 caveshlist->newindex((void **) &parysh);
13301 *parysh = recentsh;
13302 for (i = 0; i < caveshlist->objects; i++) {
13303 parysh = (face *) fastlookup(caveshlist, i);
13304 searchsh = *parysh;
13305 searchsh.shver = 0;
13306 for (j = 0; j < 3; j++) {
13307 spivot(searchsh, neighsh);
13308 // Is this side on the convex hull?
13309 if (neighsh.sh != NULL) {
13310 if (!smarktested(neighsh)) {
13311 smarktest(neighsh);
13312 caveshlist->newindex((void **) &parysh);
13313 *parysh = neighsh;
13314 }
13315 } else {
13316 // A hull side. Check if it is protected by a segment.
13317 if (!isshsubseg(searchsh)) {
13318 // Not protected. Save this face.
13319 if (!sinfected(searchsh)) {
13320 sinfect(searchsh);
13321 caveshbdlist->newindex((void **) &parysh);
13322 *parysh = searchsh;
13323 }
13324 }
13325 }
13326 senextself(searchsh);
13327 }
13328 }
13329
13330 // Infect the triangles in the holes.
13331 for (i = 0; i < 3 * holes; i += 3) {
13332 searchsh = recentsh;
13333 loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
13334 if (loc != OUTSIDE) {
13335 sinfect(searchsh);
13336 caveshbdlist->newindex((void **) &parysh);
13337 *parysh = searchsh;
13338 }
13339 }
13340
13341 // Find and infect all exterior triangles.
13342 for (i = 0; i < caveshbdlist->objects; i++) {
13343 parysh = (face *) fastlookup(caveshbdlist, i);
13344 searchsh = *parysh;
13345 searchsh.shver = 0;
13346 for (j = 0; j < 3; j++) {
13347 spivot(searchsh, neighsh);
13348 if (neighsh.sh != NULL) {
13349 if (!isshsubseg(searchsh)) {
13350 if (!sinfected(neighsh)) {
13351 sinfect(neighsh);
13352 caveshbdlist->newindex((void **) &parysh);
13353 *parysh = neighsh;
13354 }
13355 } else {
13356 sdissolve(neighsh); // Disconnect a protected face.
13357 }
13358 }
13359 senextself(searchsh);
13360 }
13361 }
13362
13363 // Delete exterior triangles, unmark interior triangles.
13364 for (i = 0; i < caveshlist->objects; i++) {
13365 parysh = (face *) fastlookup(caveshlist, i);
13366 if (sinfected(*parysh)) {
13367 shellfacedealloc(subfaces, parysh->sh);
13368 } else {
13369 sunmarktest(*parysh);
13370 }
13371 }
13372
13373 caveshlist->restart();
13374 caveshbdlist->restart();
13375}
13376
13377///////////////////////////////////////////////////////////////////////////////
13378// //
13379// triangulate() Create a CDT for the facet. //
13380// //
13381// All vertices of the triangulation have type FACETVERTEX. The actual type //
13382// of boundary vertices are set by the routine unifysements(). //
13383// //
13384///////////////////////////////////////////////////////////////////////////////
13385
13386void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
13387 int holes, REAL* holelist)
13388{
13389 face searchsh, newsh, *parysh;
13390 face newseg;
13391 point pa, pb, pc, *ppt, *cons;
13392 int iloc;
13393 int i, j;
13394
13395 if (b->verbose > 2) {
13396 printf(" f%d: %ld vertices, %ld segments", shmark, ptlist->objects,
13397 conlist->objects);
13398 if (holes > 0) {
13399 printf(", %d holes", holes);
13400 }
13401 printf(".\n");
13402 }
13403
13404 if (ptlist->objects < 2l) {
13405 // Not a segment or a facet.
13406 return;
13407 }
13408
13409 if (ptlist->objects == 2l) {
13410 pa = * (point *) fastlookup(ptlist, 0);
13411 pb = * (point *) fastlookup(ptlist, 1);
13412 if (distance(pa, pb) > 0) {
13413 // It is a single segment.
13414 makeshellface(subsegs, &newseg);
13415 setshvertices(newseg, pa, pb, NULL);
13416 // Set the default segment marker '1'.
13417 setshellmark(newseg, 1);
13418 }
13419 if (pointtype(pa) == VOLVERTEX) {
13420 setpointtype(pa, FACETVERTEX);
13421 }
13422 if (pointtype(pb) == VOLVERTEX) {
13423 setpointtype(pb, FACETVERTEX);
13424 }
13425 return;
13426 }
13427
13428
13429 if (ptlist->objects == 3) {
13430 pa = * (point *) fastlookup(ptlist, 0);
13431 pb = * (point *) fastlookup(ptlist, 1);
13432 pc = * (point *) fastlookup(ptlist, 2);
13433 } else {
13434 // Calculate an above point of this facet.
13435 if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
13436 return; // The point set is degenerate.
13437 }
13438 }
13439
13440 // Create an initial triangulation.
13441 makeshellface(subfaces, &newsh);
13442 setshvertices(newsh, pa, pb, pc);
13443 setshellmark(newsh, shmark);
13444 recentsh = newsh;
13445
13446 if (pointtype(pa) == VOLVERTEX) {
13447 setpointtype(pa, FACETVERTEX);
13448 }
13449 if (pointtype(pb) == VOLVERTEX) {
13450 setpointtype(pb, FACETVERTEX);
13451 }
13452 if (pointtype(pc) == VOLVERTEX) {
13453 setpointtype(pc, FACETVERTEX);
13454 }
13455
13456 // Are there area constraints?
13457 if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
13458 int idx, fmarker;
13459 REAL area;
13460 idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
13461 for (i = 0; i < in->numberoffacetconstraints; i++) {
13462 fmarker = (int) in->facetconstraintlist[i * 2];
13463 if (fmarker == idx) {
13464 area = in->facetconstraintlist[i * 2 + 1];
13465 setareabound(newsh, area);
13466 break;
13467 }
13468 }
13469 }
13470
13471 if (ptlist->objects == 3) {
13472 // The triangulation only has one element.
13473 for (i = 0; i < 3; i++) {
13474 makeshellface(subsegs, &newseg);
13475 setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
13476 // Set the default segment marker '1'.
13477 setshellmark(newseg, 1);
13478 ssbond(newsh, newseg);
13479 senextself(newsh);
13480 }
13481 return;
13482 }
13483
13484 // Incrementally build the triangulation.
13485 pinfect(pa);
13486 pinfect(pb);
13487 pinfect(pc);
13488 for (i = 0; i < ptlist->objects; i++) {
13489 ppt = (point *) fastlookup(ptlist, i);
13490 if (!pinfected(*ppt)) {
13491 searchsh = recentsh; // Start from 'recentsh'.
13492 iloc = (int) OUTSIDE;
13493 // Insert the vertex. Use Bowyer-Watson algo. Round the location.
13494 iloc = sinsertvertex(*ppt, &searchsh, NULL, iloc, 1, 1);
13495 if (pointtype(*ppt) == VOLVERTEX) {
13496 setpointtype(*ppt, FACETVERTEX);
13497 }
13498 // Delete all removed subfaces.
13499 for (j = 0; j < caveshlist->objects; j++) {
13500 parysh = (face *) fastlookup(caveshlist, j);
13501 shellfacedealloc(subfaces, parysh->sh);
13502 }
13503 // Clear the global lists.
13504 caveshbdlist->restart();
13505 caveshlist->restart();
13506 cavesegshlist->restart();
13507 } else {
13508 puninfect(*ppt); // This point has inserted.
13509 }
13510 }
13511
13512 // Insert the segments.
13513 for (i = 0; i < conlist->objects; i++) {
13514 cons = (point *) fastlookup(conlist, i);
13515 searchsh = recentsh;
13516 iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
13517 if (iloc != (enum locateresult) ONVERTEX) {
13518 // Not found due to roundoff errors. Do a brute-force search.
13519 subfaces->traversalinit();
13520 searchsh.sh = shellfacetraverse(subfaces);
13521 while (searchsh.sh != NULL) {
13522 // Only search the subface in the same facet.
13523 if (shellmark(searchsh) == shmark) {
13524 if ((point) searchsh.sh[3] == cons[0]) {
13525 searchsh.shver = 0; break;
13526 } else if ((point) searchsh.sh[4] == cons[0]) {
13527 searchsh.shver = 2; break;
13528 } else if ((point) searchsh.sh[5] == cons[0]) {
13529 searchsh.shver = 4; break;
13530 }
13531 }
13532 searchsh.sh = shellfacetraverse(subfaces);
13533 }
13534 assert(searchsh.sh != NULL);
13535 }
13536 // Recover the segment. Some edges may be flipped.
13537 sscoutsegment(&searchsh, cons[1]);
13538 if (flipstack != NULL) {
13539 // Recover locally Delaunay edges.
13540 lawsonflip();
13541 }
13542 }
13543
13544 // Remove exterior and hole triangles.
13545 scarveholes(holes, holelist);
13546}
13547
13548///////////////////////////////////////////////////////////////////////////////
13549// //
13550// unifysubfaces() Unify two identical subfaces. //
13551// //
13552// Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b]. //
13553// If c = d, then f1 and f2 are identical. Otherwise, these two subfaces //
13554// intersect, and the mesher is stopped. //
13555// //
13556// If the two subfaces are identical, we try to replace f2 by f1, i.e, all //
13557// neighbors of f2 are re-connected to f1. //
13558// //
13559///////////////////////////////////////////////////////////////////////////////
13560
13561void tetgenmesh::unifysubfaces(face *f1, face *f2)
13562{
13563 if (b->psc) {
13564 // In this case, it is possible that two subfaces are identical.
13565 // While they must belong to two different surfaces.
13566 return;
13567 }
13568
13569 point pa, pb, pc, pd;
13570
13571 pa = sorg(*f1);
13572 pb = sdest(*f1);
13573 pc = sapex(*f1);
13574 pd = sapex(*f2);
13575
13576 if (pc != pd) {
13577 printf("Found two facets intersect each other.\n");
13578 printf(" 1st: [%d, %d, %d] #%d\n",
13579 pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
13580 printf(" 2nd: [%d, %d, %d] #%d\n",
13581 pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
13582 terminatetetgen(this, 3);
13583 } else {
13584 printf("Found two duplicated facets.\n");
13585 printf(" 1st: [%d, %d, %d] #%d\n",
13586 pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
13587 printf(" 2nd: [%d, %d, %d] #%d\n",
13588 pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
13589 terminatetetgen(this, 3);
13590 }
13591
13592}
13593
13594///////////////////////////////////////////////////////////////////////////////
13595// //
13596// unifysegments() Remove redundant segments and create face links. //
13597// //
13598// After this routine, although segments are unique, but some of them may be //
13599// removed later by mergefacet(). All vertices still have type FACETVERTEX. //
13600// //
13601///////////////////////////////////////////////////////////////////////////////
13602
13603void tetgenmesh::unifysegments()
13604{
13605 badface *facelink = NULL, *newlinkitem, *f1, *f2;
13606 face *facperverlist, sface;
13607 face subsegloop, testseg;
13608 point torg, tdest;
13609 REAL ori1, ori2, ori3;
13610 REAL n1[3], n2[3];
13611 int *idx2faclist;
13612 int idx, k, m;
13613
13614 if (b->verbose > 1) {
13615 printf(" Unifying segments.\n");
13616 }
13617
13618 // Create a mapping from vertices to subfaces.
13619 makepoint2submap(subfaces, idx2faclist, facperverlist);
13620
13621 if (b->psc) {
13622 face sface1;
13623 face seg, seg1;
13624 int fmarker, fmarker1;
13625 // First only connect subfaces which belong to the same surfaces.
13626 subsegloop.shver = 0;
13627 subsegs->traversalinit();
13628 subsegloop.sh = shellfacetraverse(subsegs);
13629 while (subsegloop.sh != (shellface *) NULL) {
13630 torg = sorg(subsegloop);
13631 tdest = sdest(subsegloop);
13632
13633 idx = pointmark(torg) - in->firstnumber;
13634 for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
13635 sface = facperverlist[k];
13636 // The face may be deleted if it is a duplicated face.
13637 if (sface.sh[3] == NULL) continue;
13638 // Search the edge torg->tdest.
13639 assert(sorg(sface) == torg); // SELF_CHECK
13640 if (sdest(sface) != tdest) {
13641 senext2self(sface);
13642 sesymself(sface);
13643 }
13644 if (sdest(sface) != tdest) continue;
13645
13646 sspivot(sface, seg);
13647 if (seg.sh == NULL) continue;
13648 // assert(seg.sh != NULL); It may or may not be subsegloop.
13649
13650 // Find the adjacent subface on the same facet.
13651 fmarker = in->facetmarkerlist[shellmark(sface) - 1];
13652 sface1.sh = NULL;
13653 k++;
13654 for (; k < idx2faclist[idx + 1]; k++) {
13655 sface1 = facperverlist[k];
13656 // The face may be deleted if it is a duplicated face.
13657 if (sface1.sh[3] == NULL) continue;
13658 // Search the edge torg->tdest.
13659 assert(sorg(sface1) == torg); // SELF_CHECK
13660 if (sdest(sface1) != tdest) {
13661 senext2self(sface1);
13662 sesymself(sface1);
13663 }
13664 if (sdest(sface1) != tdest) continue;
13665 // Found a subface sharing at the same edge.
13666 fmarker1 = in->facetmarkerlist[shellmark(sface1) - 1];
13667 if (fmarker1 == fmarker) {
13668 // Found a pair of adjacent subfaces. Connect them.
13669 // Delete a redundent segment.
13670 sspivot(sface1, seg1);
13671 assert(seg1.sh != NULL); // SELF_CHECK
13672 shellfacedealloc(subsegs, seg.sh);
13673 shellfacedealloc(subsegs, seg1.sh);
13674 ssdissolve(sface);
13675 ssdissolve(sface1);
13676 // Connect them.
13677 sbond(sface, sface1);
13678 // Set Steiner point -to- subface map.
13679 if (pointtype(torg) == FREEFACETVERTEX) {
13680 setpoint2sh(torg, sencode(sface));
13681 }
13682 if (pointtype(tdest) == FREEFACETVERTEX) {
13683 setpoint2sh(tdest, sencode(sface));
13684 }
13685 break;
13686 }
13687 }
13688 break;
13689 }
13690 subsegloop.sh = shellfacetraverse(subsegs);
13691 }
13692 } // if (b->psc)
13693
13694 subsegloop.shver = 0;
13695 subsegs->traversalinit();
13696 subsegloop.sh = shellfacetraverse(subsegs);
13697 while (subsegloop.sh != (shellface *) NULL) {
13698 torg = sorg(subsegloop);
13699 tdest = sdest(subsegloop);
13700
13701 idx = pointmark(torg) - in->firstnumber;
13702 // Loop through the set of subfaces containing 'torg'. Get all the
13703 // subfaces containing the edge (torg, tdest). Save and order them
13704 // in 'sfacelist', the ordering is defined by the right-hand rule
13705 // with thumb points from torg to tdest.
13706 for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
13707 sface = facperverlist[k];
13708 // The face may be deleted if it is a duplicated face.
13709 if (sface.sh[3] == NULL) continue;
13710 // Search the edge torg->tdest.
13711 assert(sorg(sface) == torg); // SELF_CHECK
13712 if (sdest(sface) != tdest) {
13713 senext2self(sface);
13714 sesymself(sface);
13715 }
13716 if (sdest(sface) != tdest) continue;
13717
13718 // Save the face f in facelink.
13719 if (flippool->items >= 2) {
13720 f1 = facelink;
13721 for (m = 0; m < flippool->items - 1; m++) {
13722 f2 = f1->nextitem;
13723 ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
13724 ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
13725 if (ori1 > 0) {
13726 // apex(f2) is below f1.
13727 if (ori2 > 0) {
13728 // apex(f) is below f1 (see Fig.1).
13729 ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13730 if (ori3 > 0) {
13731 // apex(f) is below f2, insert it.
13732 break;
13733 } else if (ori3 < 0) {
13734 // apex(f) is above f2, continue.
13735 } else { // ori3 == 0;
13736 // f is coplanar and codirection with f2.
13737 unifysubfaces(&(f2->ss), &sface);
13738 break;
13739 }
13740 } else if (ori2 < 0) {
13741 // apex(f) is above f1 below f2, inset it (see Fig. 2).
13742 break;
13743 } else { // ori2 == 0;
13744 // apex(f) is coplanar with f1 (see Fig. 5).
13745 ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13746 if (ori3 > 0) {
13747 // apex(f) is below f2, insert it.
13748 break;
13749 } else {
13750 // f is coplanar and codirection with f1.
13751 unifysubfaces(&(f1->ss), &sface);
13752 break;
13753 }
13754 }
13755 } else if (ori1 < 0) {
13756 // apex(f2) is above f1.
13757 if (ori2 > 0) {
13758 // apex(f) is below f1, continue (see Fig. 3).
13759 } else if (ori2 < 0) {
13760 // apex(f) is above f1 (see Fig.4).
13761 ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13762 if (ori3 > 0) {
13763 // apex(f) is below f2, insert it.
13764 break;
13765 } else if (ori3 < 0) {
13766 // apex(f) is above f2, continue.
13767 } else { // ori3 == 0;
13768 // f is coplanar and codirection with f2.
13769 unifysubfaces(&(f2->ss), &sface);
13770 break;
13771 }
13772 } else { // ori2 == 0;
13773 // f is coplanar and with f1 (see Fig. 6).
13774 ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13775 if (ori3 > 0) {
13776 // f is also codirection with f1.
13777 unifysubfaces(&(f1->ss), &sface);
13778 break;
13779 } else {
13780 // f is above f2, continue.
13781 }
13782 }
13783 } else { // ori1 == 0;
13784 // apex(f2) is coplanar with f1. By assumption, f1 is not
13785 // coplanar and codirection with f2.
13786 if (ori2 > 0) {
13787 // apex(f) is below f1, continue (see Fig. 7).
13788 } else if (ori2 < 0) {
13789 // apex(f) is above f1, insert it (see Fig. 7).
13790 break;
13791 } else { // ori2 == 0.
13792 // apex(f) is coplanar with f1 (see Fig. 8).
13793 // f is either codirection with f1 or is codirection with f2.
13794 facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
13795 facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
13796 if (dot(n1, n2) > 0) {
13797 unifysubfaces(&(f1->ss), &sface);
13798 } else {
13799 unifysubfaces(&(f2->ss), &sface);
13800 }
13801 break;
13802 }
13803 }
13804 // Go to the next item;
13805 f1 = f2;
13806 } // for (m = 0; ...)
13807 if (sface.sh[3] != NULL) {
13808 // Insert sface between f1 and f2.
13809 newlinkitem = (badface *) flippool->alloc();
13810 newlinkitem->ss = sface;
13811 newlinkitem->nextitem = f1->nextitem;
13812 f1->nextitem = newlinkitem;
13813 }
13814 } else if (flippool->items == 1) {
13815 f1 = facelink;
13816 // Make sure that f is not coplanar and codirection with f1.
13817 ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
13818 if (ori1 == 0) {
13819 // f is coplanar with f1 (see Fig. 8).
13820 facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
13821 facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
13822 if (dot(n1, n2) > 0) {
13823 // The two faces are codirectional as well.
13824 unifysubfaces(&(f1->ss), &sface);
13825 }
13826 }
13827 // Add this face to link if it is not deleted.
13828 if (sface.sh[3] != NULL) {
13829 // Add this face into link.
13830 newlinkitem = (badface *) flippool->alloc();
13831 newlinkitem->ss = sface;
13832 newlinkitem->nextitem = NULL;
13833 f1->nextitem = newlinkitem;
13834 }
13835 } else {
13836 // The first face.
13837 newlinkitem = (badface *) flippool->alloc();
13838 newlinkitem->ss = sface;
13839 newlinkitem->nextitem = NULL;
13840 facelink = newlinkitem;
13841 }
13842 } // for (k = idx2faclist[idx]; ...)
13843
13844 if (b->psc) {
13845 // Set Steiner point -to- segment map.
13846 if (pointtype(torg) == FREESEGVERTEX) {
13847 setpoint2sh(torg, sencode(subsegloop));
13848 }
13849 if (pointtype(tdest) == FREESEGVERTEX) {
13850 setpoint2sh(tdest, sencode(subsegloop));
13851 }
13852 }
13853
13854 // Set the connection between this segment and faces containing it,
13855 // at the same time, remove redundant segments.
13856 f1 = facelink;
13857 for (k = 0; k < flippool->items; k++) {
13858 sspivot(f1->ss, testseg);
13859 // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
13860 if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
13861 shellfacedealloc(subsegs, testseg.sh);
13862 }
13863 // Bonds the subface and the segment together.
13864 ssbond(f1->ss, subsegloop);
13865 f1 = f1->nextitem;
13866 }
13867
13868 // Create the face ring at the segment.
13869 if (flippool->items > 1) {
13870 f1 = facelink;
13871 for (k = 1; k <= flippool->items; k++) {
13872 k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
13873 sbond1(f1->ss, f2->ss);
13874 f1 = f2;
13875 }
13876 }
13877
13878 // All identified segments has an init marker "0".
13879 flippool->restart();
13880
13881 // Are there length constraints?
13882 if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
13883 int e1, e2;
13884 REAL len;
13885 for (k = 0; k < in->numberofsegmentconstraints; k++) {
13886 e1 = (int) in->segmentconstraintlist[k * 3];
13887 e2 = (int) in->segmentconstraintlist[k * 3 + 1];
13888 if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
13889 ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
13890 len = in->segmentconstraintlist[k * 3 + 2];
13891 setareabound(subsegloop, len);
13892 break;
13893 }
13894 }
13895 }
13896
13897 subsegloop.sh = shellfacetraverse(subsegs);
13898 }
13899
13900 delete [] idx2faclist;
13901 delete [] facperverlist;
13902}
13903
13904///////////////////////////////////////////////////////////////////////////////
13905// //
13906// mergefacets() Merge adjacent facets. //
13907// //
13908///////////////////////////////////////////////////////////////////////////////
13909
13910void tetgenmesh::mergefacets()
13911{
13912 face parentsh, neighsh, neineish;
13913 face segloop;
13914 point pa, pb, pc, pd;
13915 REAL ang_tol, ang;
13916 int remsegcount;
13917 int fidx1, fidx2;
13918 int fmrk1, fmrk2;
13919
13920 if (b->verbose > 1) {
13921 printf(" Merging adjacent facets.\n");
13922 }
13923
13924 // The dihedral angle bound for two different facets.
13925 // Set by -p option. Default is 179 degree.
13926 ang_tol = b->facet_ang_tol / 180.0 * PI;
13927 remsegcount = 0;
13928
13929 // Loop all segments, merge adjacent coplanar facets.
13930 subsegs->traversalinit();
13931 segloop.sh = shellfacetraverse(subsegs);
13932 while (segloop.sh != (shellface *) NULL) {
13933 spivot(segloop, parentsh);
13934 if (parentsh.sh != NULL) {
13935 spivot(parentsh, neighsh);
13936 if (neighsh.sh != NULL) {
13937 spivot(neighsh, neineish);
13938 if (neineish.sh == parentsh.sh) {
13939 // Exactly two subfaces at this segment.
13940 fidx1 = shellmark(parentsh) - 1;
13941 fidx2 = shellmark(neighsh) - 1;
13942 // Only merge them if they are in different facet.
13943 if (fidx1 != fidx2) {
13944 // The two subfaces are not in the same facet.
13945 if (in->facetmarkerlist != NULL) {
13946 fmrk1 = in->facetmarkerlist[fidx1];
13947 fmrk2 = in->facetmarkerlist[fidx2];
13948 } else {
13949 fmrk1 = fmrk2 = 0;
13950 }
13951 // Only merge them if they have the same boundary marker.
13952 if (fmrk1 == fmrk2) {
13953 pa = sorg(segloop);
13954 pb = sdest(segloop);
13955 pc = sapex(parentsh);
13956 pd = sapex(neighsh);
13957 // Calculate the dihedral angle at the segment [a,b].
13958 ang = facedihedral(pa, pb, pc, pd);
13959 if (ang > PI) ang = (2 * PI - ang);
13960 if (ang > ang_tol) {
13961 remsegcount++;
13962 ssdissolve(parentsh);
13963 ssdissolve(neighsh);
13964 shellfacedealloc(subsegs, segloop.sh);
13965 // Add the edge to flip stack.
13966 flipshpush(&parentsh);
13967 } // if (ang > ang_tol)
13968 } // if (fmrk1 == fmrk2)
13969 } // if (fidx1 != fidx2)
13970 } // if (neineish.sh == parentsh.sh)
13971 }
13972 }
13973 segloop.sh = shellfacetraverse(subsegs);
13974 }
13975
13976 if (flipstack != NULL) {
13977 lawsonflip(); // Recover Delaunayness.
13978 }
13979
13980 if (b->verbose > 1) {
13981 printf(" %d segments are removed.\n", remsegcount);
13982 }
13983}
13984
13985///////////////////////////////////////////////////////////////////////////////
13986// //
13987// identifypscedges() Identify PSC edges. //
13988// //
13989// The set of PSC edges are provided in the 'in->edgelist'. Each edge should //
13990// also be an edge in the surface mesh. We find the corresponding edges in //
13991// the surface mesh and make them segments of the mesh. //
13992// //
13993// It is possible to give an edge which is not in any facet, i.e., it is a //
13994// dangling edge inside the volume. //
13995// //
13996///////////////////////////////////////////////////////////////////////////////
13997
13998void tetgenmesh::identifypscedges(point *idx2verlist)
13999{
14000 face* shperverlist;
14001 int* idx2shlist;
14002 face searchsh, neighsh;
14003 face segloop, checkseg, newseg;
14004 point checkpt, pa = NULL, pb = NULL;
14005 int *endpts;
14006 int edgemarker;
14007 int idx, i, j;
14008
14009 int e1, e2;
14010 REAL len;
14011
14012 if (!b->quiet) {
14013 printf("Inserting edges ...\n");
14014 }
14015
14016 // All identified segments have the initial marker '1'.
14017 // All segments inserted here should have a marker 'k >= 0'.
14018
14019 if (b->psc) {
14020 // First mark all segments of the mesh with a marker '-1'.
14021 subsegs->traversalinit();
14022 segloop.sh = shellfacetraverse(subsegs);
14023 while (segloop.sh != NULL) {
14024 setshellmark(segloop, -1);
14025 segloop.sh = shellfacetraverse(subsegs);
14026 }
14027 }
14028
14029 // Construct a map from points to subfaces.
14030 makepoint2submap(subfaces, idx2shlist, shperverlist);
14031
14032 // Process the set of PSC edges.
14033 for (i = 0; i < in->numberofedges; i++) {
14034 endpts = &(in->edgelist[(i << 1)]);
14035 edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : 0;
14036
14037 // Find a face contains the edge.
14038 newseg.sh = NULL;
14039 searchsh.sh = NULL;
14040 idx = endpts[0] - in->firstnumber;
14041 for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
14042 checkpt = sdest(shperverlist[j]);
14043 if (pointmark(checkpt) == endpts[1]) {
14044 searchsh = shperverlist[j];
14045 break; // Found.
14046 } else {
14047 checkpt = sapex(shperverlist[j]);
14048 if (pointmark(checkpt) == endpts[1]) {
14049 senext2(shperverlist[j], searchsh);
14050 sesymself(searchsh);
14051 break;
14052 }
14053 }
14054 } // j
14055
14056 if (searchsh.sh != NULL) {
14057 // Check if this edge is already a segment of the mesh.
14058 sspivot(searchsh, checkseg);
14059 if (checkseg.sh != NULL) {
14060 // This segment already exist.
14061 newseg = checkseg;
14062 } else {
14063 // Create a new segment at this edge.
14064 pa = sorg(searchsh);
14065 pb = sdest(searchsh);
14066 makeshellface(subsegs, &newseg);
14067 setshvertices(newseg, pa, pb, NULL);
14068 ssbond(searchsh, newseg);
14069 spivot(searchsh, neighsh);
14070 if (neighsh.sh != NULL) {
14071 ssbond(neighsh, newseg);
14072 }
14073 if (b->psc) {
14074 if (pointtype(pa) == FREESEGVERTEX) {
14075 setpoint2sh(pa, sencode(newseg));
14076 }
14077 if (pointtype(pb) == FREESEGVERTEX) {
14078 setpoint2sh(pb, sencode(newseg));
14079 }
14080 }
14081 }
14082 } else {
14083 // It is a dangling segment (not belong to any facets).
14084 // Get the two endpoints of this segment.
14085 pa = idx2verlist[endpts[0]];
14086 pb = idx2verlist[endpts[1]];
14087 // Check if segment [a,b] already exists.
14088 // TODO: Change the brute-force search. Slow!
14089 point *ppt;
14090 subsegs->traversalinit();
14091 segloop.sh = shellfacetraverse(subsegs);
14092 while (segloop.sh != NULL) {
14093 ppt = (point *) &(segloop.sh[3]);
14094 if (((ppt[0] == pa) && (ppt[1] == pb)) ||
14095 ((ppt[0] == pb) && (ppt[1] == pa))) {
14096 // Found!
14097 newseg = segloop;
14098 break;
14099 }
14100 segloop.sh = shellfacetraverse(subsegs);
14101 }
14102 if (newseg.sh == NULL) {
14103 makeshellface(subsegs, &newseg);
14104 setshvertices(newseg, pa, pb, NULL);
14105 if (b->psc) {
14106 if (pointtype(pa) == FREESEGVERTEX) {
14107 setpoint2sh(pa, sencode(newseg));
14108 }
14109 if (pointtype(pb) == FREESEGVERTEX) {
14110 setpoint2sh(pb, sencode(newseg));
14111 }
14112 }
14113 }
14114 }
14115
14116 setshellmark(newseg, edgemarker);
14117
14118 if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
14119 for (i = 0; i < in->numberofsegmentconstraints; i++) {
14120 e1 = (int) in->segmentconstraintlist[i * 3];
14121 e2 = (int) in->segmentconstraintlist[i * 3 + 1];
14122 if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
14123 ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
14124 len = in->segmentconstraintlist[i * 3 + 2];
14125 setareabound(newseg, len);
14126 break;
14127 }
14128 }
14129 }
14130 } // i
14131
14132
14133 delete [] shperverlist;
14134 delete [] idx2shlist;
14135
14136 if (b->psc) {
14137 // Removing all segments with a marker '-1'.
14138 subsegs->traversalinit();
14139 segloop.sh = shellfacetraverse(subsegs);
14140 while (segloop.sh != NULL) {
14141 if (shellmark(segloop) == -1) {
14142 shellfacedealloc(subsegs, segloop.sh);
14143 }
14144 segloop.sh = shellfacetraverse(subsegs);
14145 }
14146
14147 // Connecting subsegments at Steiner points.
14148 face seg1, seg2;
14149 // Re-use 'idx2shlist' and 'shperverlist'.
14150 makepoint2submap(subsegs, idx2shlist, shperverlist);
14151
14152 points->traversalinit();
14153 pa = pointtraverse();
14154 while (pa != NULL) {
14155 if (pointtype(pa) == FREESEGVERTEX) {
14156 idx = pointmark(pa) - in->firstnumber;
14157 // There must be only two segments containing this vertex.
14158 assert((idx2shlist[idx + 1] - idx2shlist[idx]) == 2);
14159 i = idx2shlist[idx];
14160 seg1 = shperverlist[i];
14161 seg2 = shperverlist[i+1];
14162 senextself(seg1);
14163 senextself(seg2);
14164 sbond(seg1, seg2);
14165 }
14166 pa = pointtraverse();
14167 }
14168
14169 delete [] shperverlist;
14170 delete [] idx2shlist;
14171 }
14172}
14173
14174///////////////////////////////////////////////////////////////////////////////
14175// //
14176// meshsurface() Create a surface mesh of the input PLC. //
14177// //
14178///////////////////////////////////////////////////////////////////////////////
14179
14180void tetgenmesh::meshsurface()
14181{
14182 arraypool *ptlist, *conlist;
14183 point *idx2verlist;
14184 point tstart, tend, *pnewpt, *cons;
14185 tetgenio::facet *f;
14186 tetgenio::polygon *p;
14187 int end1, end2;
14188 int shmark, i, j;
14189
14190 if (!b->quiet) {
14191 printf("Creating surface mesh ...\n");
14192 }
14193
14194 // Create a map from indices to points.
14195 makeindex2pointmap(idx2verlist);
14196
14197 // Initialize arrays (block size: 2^8 = 256).
14198 ptlist = new arraypool(sizeof(point *), 8);
14199 conlist = new arraypool(2 * sizeof(point *), 8);
14200
14201 // Loop the facet list, triangulate each facet.
14202 for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
14203
14204 // Get a facet F.
14205 f = &in->facetlist[shmark - 1];
14206
14207 // Process the duplicated points first, they are marked with type
14208 // DUPLICATEDVERTEX. If p and q are duplicated, and p'index > q's,
14209 // then p is substituted by q.
14210 if (dupverts > 0l) {
14211 // Loop all polygons of this facet.
14212 for (i = 0; i < f->numberofpolygons; i++) {
14213 p = &(f->polygonlist[i]);
14214 // Loop other vertices of this polygon.
14215 for (j = 0; j < p->numberofvertices; j++) {
14216 end1 = p->vertexlist[j];
14217 tstart = idx2verlist[end1];
14218 if (pointtype(tstart) == DUPLICATEDVERTEX) {
14219 // Reset the index of vertex-j.
14220 tend = point2ppt(tstart);
14221 end2 = pointmark(tend);
14222 p->vertexlist[j] = end2;
14223 }
14224 }
14225 }
14226 }
14227
14228 // Loop polygons of F, get the set of vertices and segments.
14229 for (i = 0; i < f->numberofpolygons; i++) {
14230 // Get a polygon.
14231 p = &(f->polygonlist[i]);
14232 // Get the first vertex.
14233 end1 = p->vertexlist[0];
14234 if ((end1 < in->firstnumber) ||
14235 (end1 >= in->firstnumber + in->numberofpoints)) {
14236 if (!b->quiet) {
14237 printf("Warning: Invalid the 1st vertex %d of polygon", end1);
14238 printf(" %d in facet %d.\n", i + 1, shmark);
14239 }
14240 continue; // Skip this polygon.
14241 }
14242 tstart = idx2verlist[end1];
14243 // Add tstart to V if it haven't been added yet.
14244 if (!pinfected(tstart)) {
14245 pinfect(tstart);
14246 ptlist->newindex((void **) &pnewpt);
14247 *pnewpt = tstart;
14248 }
14249 // Loop other vertices of this polygon.
14250 for (j = 1; j <= p->numberofvertices; j++) {
14251 // get a vertex.
14252 if (j < p->numberofvertices) {
14253 end2 = p->vertexlist[j];
14254 } else {
14255 end2 = p->vertexlist[0]; // Form a loop from last to first.
14256 }
14257 if ((end2 < in->firstnumber) ||
14258 (end2 >= in->firstnumber + in->numberofpoints)) {
14259 if (!b->quiet) {
14260 printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1);
14261 printf(" in facet %d.\n", shmark);
14262 }
14263 } else {
14264 if (end1 != end2) {
14265 // 'end1' and 'end2' form a segment.
14266 tend = idx2verlist[end2];
14267 // Add tstart to V if it haven't been added yet.
14268 if (!pinfected(tend)) {
14269 pinfect(tend);
14270 ptlist->newindex((void **) &pnewpt);
14271 *pnewpt = tend;
14272 }
14273 // Save the segment in S (conlist).
14274 conlist->newindex((void **) &cons);
14275 cons[0] = tstart;
14276 cons[1] = tend;
14277 // Set the start for next continuous segment.
14278 end1 = end2;
14279 tstart = tend;
14280 } else {
14281 // Two identical vertices mean an isolated vertex of F.
14282 if (p->numberofvertices > 2) {
14283 // This may be an error in the input, anyway, we can continue
14284 // by simply skipping this segment.
14285 if (!b->quiet) {
14286 printf("Warning: Polygon %d has two identical verts", i + 1);
14287 printf(" in facet %d.\n", shmark);
14288 }
14289 }
14290 // Ignore this vertex.
14291 }
14292 }
14293 // Is the polygon degenerate (a segment or a vertex)?
14294 if (p->numberofvertices == 2) break;
14295 }
14296 }
14297 // Unmark vertices.
14298 for (i = 0; i < ptlist->objects; i++) {
14299 pnewpt = (point *) fastlookup(ptlist, i);
14300 puninfect(*pnewpt);
14301 }
14302
14303 // Triangulate F into a CDT.
14304 triangulate(shmark, ptlist, conlist, f->numberofholes, f->holelist);
14305
14306 // Clear working lists.
14307 ptlist->restart();
14308 conlist->restart();
14309 }
14310
14311 if (!b->diagnose) {
14312 // Remove redundant segments and build the face links.
14313 unifysegments();
14314 if (!b->psc && !b->nomergefacet && !b->nobisect) {
14315 // Merge adjacent coplanar facets.
14316 mergefacets();
14317 }
14318 if (in->numberofedges > 0) { // if (b->psc)
14319 // There are segments specified by the user. Read and create them.
14320 identifypscedges(idx2verlist);
14321 }
14322 if (!b->psc) {
14323 // Mark all segment vertices to be RIDGEVERTEX.
14324 face segloop;
14325 point *ppt;
14326 subsegs->traversalinit();
14327 segloop.sh = shellfacetraverse(subsegs);
14328 while (segloop.sh != NULL) {
14329 ppt = (point *) &(segloop.sh[3]);
14330 setpointtype(ppt[0], RIDGEVERTEX);
14331 setpointtype(ppt[1], RIDGEVERTEX);
14332 segloop.sh = shellfacetraverse(subsegs);
14333 }
14334 }
14335 }
14336
14337 if (b->object == tetgenbehavior::STL) {
14338 // Remove redundant vertices (for .stl input mesh).
14339 jettisonnodes();
14340 }
14341
14342 if (b->verbose) {
14343 printf(" %ld (%ld) subfaces (segments).\n", subfaces->items,
14344 subsegs->items);
14345 }
14346
14347 // The total number of iunput segments.
14348 insegments = subsegs->items;
14349
14350 delete [] idx2verlist;
14351 delete ptlist;
14352 delete conlist;
14353}
14354
14355///////////////////////////////////////////////////////////////////////////////
14356// //
14357// interecursive() Recursively do intersection test on a set of triangles.//
14358// //
14359// Recursively split the set 'subfacearray' of subfaces into two sets using //
14360// a cut plane parallel to x-, or, y-, or z-axis. The split criteria are //
14361// follows. Assume the cut plane is H, and H+ denotes the left halfspace of //
14362// H, and H- denotes the right halfspace of H; and s be a subface: //
14363// //
14364// (1) If all points of s lie at H+, put it into left array; //
14365// (2) If all points of s lie at H-, put it into right array; //
14366// (3) If some points of s lie at H+ and some of lie at H-, or some //
14367// points lie on H, put it into both arraies. //
14368// //
14369// Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis //
14370// if axis == '2'. If current cut plane is parallel to the x-axis, the next //
14371// one will be parallel to y-axis, and the next one after the next is z-axis,//
14372// and then alternately return back to x-axis. //
14373// //
14374// Stop splitting when the number of triangles of the input array is not //
14375// decreased anymore. Do tests on the current set. //
14376// //
14377///////////////////////////////////////////////////////////////////////////////
14378
14379void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
14380 int axis, REAL bxmin, REAL bxmax, REAL bymin,
14381 REAL bymax, REAL bzmin, REAL bzmax,
14382 int* internum)
14383{
14384 shellface **leftarray, **rightarray;
14385 face sface1, sface2;
14386 point p1, p2, p3;
14387 point p4, p5, p6;
14388 enum interresult intersect;
14389 REAL split;
14390 bool toleft, toright;
14391 int leftsize, rightsize;
14392 int i, j;
14393
14394 if (b->verbose > 2) {
14395 printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
14396 arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
14397 axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
14398 }
14399
14400 leftarray = new shellface*[arraysize];
14401 if (leftarray == NULL) {
14402 terminatetetgen(this, 1);
14403 }
14404 rightarray = new shellface*[arraysize];
14405 if (rightarray == NULL) {
14406 terminatetetgen(this, 1);
14407 }
14408 leftsize = rightsize = 0;
14409
14410 if (axis == 0) {
14411 // Split along x-axis.
14412 split = 0.5 * (bxmin + bxmax);
14413 } else if (axis == 1) {
14414 // Split along y-axis.
14415 split = 0.5 * (bymin + bymax);
14416 } else {
14417 // Split along z-axis.
14418 split = 0.5 * (bzmin + bzmax);
14419 }
14420
14421 for (i = 0; i < arraysize; i++) {
14422 sface1.sh = subfacearray[i];
14423 p1 = (point) sface1.sh[3];
14424 p2 = (point) sface1.sh[4];
14425 p3 = (point) sface1.sh[5];
14426 toleft = toright = false;
14427 if (p1[axis] < split) {
14428 toleft = true;
14429 if (p2[axis] >= split || p3[axis] >= split) {
14430 toright = true;
14431 }
14432 } else if (p1[axis] > split) {
14433 toright = true;
14434 if (p2[axis] <= split || p3[axis] <= split) {
14435 toleft = true;
14436 }
14437 } else {
14438 // p1[axis] == split;
14439 toleft = true;
14440 toright = true;
14441 }
14442 // At least one is true;
14443 assert(!(toleft == false && toright == false));
14444 if (toleft) {
14445 leftarray[leftsize] = sface1.sh;
14446 leftsize++;
14447 }
14448 if (toright) {
14449 rightarray[rightsize] = sface1.sh;
14450 rightsize++;
14451 }
14452 }
14453
14454 if (leftsize < arraysize && rightsize < arraysize) {
14455 // Continue to partition the input set. Now 'subfacearray' has been
14456 // split into two sets, it's memory can be freed. 'leftarray' and
14457 // 'rightarray' will be freed in the next recursive (after they're
14458 // partitioned again or performing tests).
14459 delete [] subfacearray;
14460 // Continue to split these two sets.
14461 if (axis == 0) {
14462 interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
14463 bzmin, bzmax, internum);
14464 interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
14465 bzmin, bzmax, internum);
14466 } else if (axis == 1) {
14467 interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
14468 bzmin, bzmax, internum);
14469 interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
14470 bzmin, bzmax, internum);
14471 } else {
14472 interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
14473 bzmin, split, internum);
14474 interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
14475 split, bzmax, internum);
14476 }
14477 } else {
14478 if (b->verbose > 1) {
14479 printf(" Checking intersecting faces.\n");
14480 }
14481 // Perform a brute-force compare on the set.
14482 for (i = 0; i < arraysize; i++) {
14483 sface1.sh = subfacearray[i];
14484 p1 = (point) sface1.sh[3];
14485 p2 = (point) sface1.sh[4];
14486 p3 = (point) sface1.sh[5];
14487 for (j = i + 1; j < arraysize; j++) {
14488 sface2.sh = subfacearray[j];
14489 p4 = (point) sface2.sh[3];
14490 p5 = (point) sface2.sh[4];
14491 p6 = (point) sface2.sh[5];
14492 intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
14493 if (intersect == INTERSECT || intersect == SHAREFACE) {
14494 if (!b->quiet) {
14495 if (intersect == INTERSECT) {
14496 printf(" Facet #%d intersects facet #%d at triangles:\n",
14497 shellmark(sface1), shellmark(sface2));
14498 printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
14499 pointmark(p1), pointmark(p2), pointmark(p3),
14500 pointmark(p4), pointmark(p5), pointmark(p6));
14501 } else {
14502 printf(" Facet #%d duplicates facet #%d at triangle:\n",
14503 shellmark(sface1), shellmark(sface2));
14504 printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
14505 pointmark(p1), pointmark(p2), pointmark(p3),
14506 pointmark(p4), pointmark(p5), pointmark(p6));
14507 }
14508 }
14509 // Increase the number of intersecting pairs.
14510 (*internum)++;
14511 // Infect these two faces (although they may already be infected).
14512 sinfect(sface1);
14513 sinfect(sface2);
14514 }
14515 }
14516 }
14517 // Don't forget to free all three arrays. No further partition.
14518 delete [] leftarray;
14519 delete [] rightarray;
14520 delete [] subfacearray;
14521 }
14522}
14523
14524///////////////////////////////////////////////////////////////////////////////
14525// //
14526// detectinterfaces() Detect intersecting triangles. //
14527// //
14528// Given a set of triangles, find the pairs of intersecting triangles from //
14529// them. Here the set of triangles is in 'subfaces' which is a surface mesh //
14530// of a PLC (.poly or .smesh). //
14531// //
14532// To detect whether two triangles are intersecting is done by the routine //
14533// 'tri_tri_inter()'. The algorithm for the test is very simple and stable. //
14534// It is based on geometric orientation test which uses exact arithmetics. //
14535// //
14536// Use divide-and-conquer algorithm for reducing the number of intersection //
14537// tests. Start from the bounding box of the input point set, recursively //
14538// partition the box into smaller boxes, until the number of triangles in a //
14539// box is not decreased anymore. Then perform triangle-triangle tests on the //
14540// remaining set of triangles. The memory allocated in the input set is //
14541// freed immediately after it has been partitioned into two arrays. So it //
14542// can be re-used for the consequent partitions. //
14543// //
14544// On return, the pool 'subfaces' will be cleared, and only the intersecting //
14545// triangles remain for output (to a .face file). //
14546// //
14547///////////////////////////////////////////////////////////////////////////////
14548
14549void tetgenmesh::detectinterfaces()
14550{
14551 shellface **subfacearray;
14552 face shloop;
14553 int internum;
14554 int i;
14555
14556 if (!b->quiet) {
14557 printf("Detecting self-intersecting facets...\n");
14558 }
14559
14560 // Construct a map from indices to subfaces;
14561 subfacearray = new shellface*[subfaces->items];
14562 subfaces->traversalinit();
14563 shloop.sh = shellfacetraverse(subfaces);
14564 i = 0;
14565 while (shloop.sh != (shellface *) NULL) {
14566 subfacearray[i] = shloop.sh;
14567 shloop.sh = shellfacetraverse(subfaces);
14568 i++;
14569 }
14570
14571 internum = 0;
14572 // Recursively split the set of triangles into two sets using a cut plane
14573 // parallel to x-, or, y-, or z-axis. Stop splitting when the number
14574 // of subfaces is not decreasing anymore. Do tests on the current set.
14575 interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
14576 zmin, zmax, &internum);
14577
14578 if (!b->quiet) {
14579 if (internum > 0) {
14580 printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
14581 } else {
14582 printf("\nNo faces are intersecting.\n\n");
14583 }
14584 }
14585
14586 if (internum > 0) {
14587 // Traverse all subfaces, deallocate those have not been infected (they
14588 // are not intersecting faces). Uninfect those have been infected.
14589 // After this loop, only intersecting faces remain.
14590 subfaces->traversalinit();
14591 shloop.sh = shellfacetraverse(subfaces);
14592 while (shloop.sh != (shellface *) NULL) {
14593 if (sinfected(shloop)) {
14594 suninfect(shloop);
14595 } else {
14596 shellfacedealloc(subfaces, shloop.sh);
14597 }
14598 shloop.sh = shellfacetraverse(subfaces);
14599 }
14600 } else {
14601 // Deallocate all subfaces.
14602 subfaces->restart();
14603 }
14604}
14605
14606//// ////
14607//// ////
14608//// surface_cxx //////////////////////////////////////////////////////////////
14609
14610//// constrained_cxx //////////////////////////////////////////////////////////
14611//// ////
14612//// ////
14613
14614///////////////////////////////////////////////////////////////////////////////
14615// //
14616// makesegmentendpointsmap() Create a map from a segment to its endpoints.//
14617// //
14618// The map is saved in the array 'segmentendpointslist'. The length of this //
14619// array is twice the number of segments. Each segment is assigned a unique //
14620// index (starting from 0). //
14621// //
14622///////////////////////////////////////////////////////////////////////////////
14623
14624void tetgenmesh::makesegmentendpointsmap()
14625{
14626 arraypool *segptlist;
14627 face segloop, prevseg, nextseg;
14628 point eorg, edest, *parypt;
14629 int segindex = 0, idx = 0;
14630 int i;
14631
14632 if (b->verbose > 0) {
14633 printf(" Creating the segment-endpoints map.\n");
14634 }
14635
14636 segptlist = new arraypool(2 * sizeof(point), 10);
14637
14638 // A segment s may have been split into many subsegments. Operate the one
14639 // which contains the origin of s. Then mark the rest of subsegments.
14640 subsegs->traversalinit();
14641 segloop.sh = shellfacetraverse(subsegs);
14642 segloop.shver = 0;
14643 while (segloop.sh != NULL) {
14644 senext2(segloop, prevseg);
14645 spivotself(prevseg);
14646 if (prevseg.sh == NULL) {
14647 eorg = sorg(segloop);
14648 edest = sdest(segloop);
14649 setfacetindex(segloop, segindex);
14650 senext(segloop, nextseg);
14651 spivotself(nextseg);
14652 while (nextseg.sh != NULL) {
14653 setfacetindex(nextseg, segindex);
14654 nextseg.shver = 0;
14655 if (sorg(nextseg) != edest) sesymself(nextseg);
14656 assert(sorg(nextseg) == edest);
14657 edest = sdest(nextseg);
14658 // Go the next connected subsegment at edest.
14659 senextself(nextseg);
14660 spivotself(nextseg);
14661 }
14662 segptlist->newindex((void **) &parypt);
14663 parypt[0] = eorg;
14664 parypt[1] = edest;
14665 segindex++;
14666 }
14667 segloop.sh = shellfacetraverse(subsegs);
14668 }
14669
14670 if (b->verbose) {
14671 printf(" Found %ld segments.\n", segptlist->objects);
14672 }
14673
14674 segmentendpointslist = new point[segptlist->objects * 2];
14675
14676 totalworkmemory += (segptlist->objects * 2) * sizeof(point *);
14677
14678 for (i = 0; i < segptlist->objects; i++) {
14679 parypt = (point *) fastlookup(segptlist, i);
14680 segmentendpointslist[idx++] = parypt[0];
14681 segmentendpointslist[idx++] = parypt[1];
14682 }
14683
14684 delete segptlist;
14685}
14686
14687
14688///////////////////////////////////////////////////////////////////////////////
14689// //
14690// finddirection() Find the tet on the path from one point to another. //
14691// //
14692// The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
14693// 'searchtet' contains a tet on the path, its origin does not change. //
14694// //
14695// The return value indicates one of the following cases (let 'searchtet' be //
14696// abcd, a is the origin of the path): //
14697// - ACROSSVERT, edge ab is collinear with the path; //
14698// - ACROSSEDGE, edge bc intersects with the path; //
14699// - ACROSSFACE, face bcd intersects with the path. //
14700// //
14701// WARNING: This routine is designed for convex triangulations, and will not //
14702// generally work after the holes and concavities have been carved. //
14703// //
14704///////////////////////////////////////////////////////////////////////////////
14705
14706enum tetgenmesh::interresult
14707 tetgenmesh::finddirection(triface* searchtet, point endpt)
14708{
14709 triface neightet;
14710 point pa, pb, pc, pd;
14711 enum {HMOVE, RMOVE, LMOVE} nextmove;
14712 REAL hori, rori, lori;
14713 int t1ver;
14714 int s;
14715
14716 // The origin is fixed.
14717 pa = org(*searchtet);
14718 if ((point) searchtet->tet[7] == dummypoint) {
14719 // A hull tet. Choose the neighbor of its base face.
14720 decode(searchtet->tet[3], *searchtet);
14721 // Reset the origin to be pa.
14722 if ((point) searchtet->tet[4] == pa) {
14723 searchtet->ver = 11;
14724 } else if ((point) searchtet->tet[5] == pa) {
14725 searchtet->ver = 3;
14726 } else if ((point) searchtet->tet[6] == pa) {
14727 searchtet->ver = 7;
14728 } else {
14729 assert((point) searchtet->tet[7] == pa);
14730 searchtet->ver = 0;
14731 }
14732 }
14733
14734 pb = dest(*searchtet);
14735 // Check whether the destination or apex is 'endpt'.
14736 if (pb == endpt) {
14737 // pa->pb is the search edge.
14738 return ACROSSVERT;
14739 }
14740
14741 pc = apex(*searchtet);
14742 if (pc == endpt) {
14743 // pa->pc is the search edge.
14744 eprevesymself(*searchtet);
14745 return ACROSSVERT;
14746 }
14747
14748 // Walk through tets around pa until the right one is found.
14749 while (1) {
14750
14751 pd = oppo(*searchtet);
14752 // Check whether the opposite vertex is 'endpt'.
14753 if (pd == endpt) {
14754 // pa->pd is the search edge.
14755 esymself(*searchtet);
14756 enextself(*searchtet);
14757 return ACROSSVERT;
14758 }
14759 // Check if we have entered outside of the domain.
14760 if (pd == dummypoint) {
14761 // This is possible when the mesh is non-convex.
14762 assert(nonconvex);
14763 return ACROSSSUB; // Hit a bounday.
14764 }
14765
14766 // Now assume that the base face abc coincides with the horizon plane,
14767 // and d lies above the horizon. The search point 'endpt' may lie
14768 // above or below the horizon. We test the orientations of 'endpt'
14769 // with respect to three planes: abc (horizon), bad (right plane),
14770 // and acd (left plane).
14771 hori = orient3d(pa, pb, pc, endpt);
14772 rori = orient3d(pb, pa, pd, endpt);
14773 lori = orient3d(pa, pc, pd, endpt);
14774
14775 // Now decide the tet to move. It is possible there are more than one
14776 // tets are viable moves. Is so, randomly choose one.
14777 if (hori > 0) {
14778 if (rori > 0) {
14779 if (lori > 0) {
14780 // Any of the three neighbors is a viable move.
14781 s = randomnation(3);
14782 if (s == 0) {
14783 nextmove = HMOVE;
14784 } else if (s == 1) {
14785 nextmove = RMOVE;
14786 } else {
14787 nextmove = LMOVE;
14788 }
14789 } else {
14790 // Two tets, below horizon and below right, are viable.
14791 //s = randomnation(2);
14792 if (randomnation(2)) {
14793 nextmove = HMOVE;
14794 } else {
14795 nextmove = RMOVE;
14796 }
14797 }
14798 } else {
14799 if (lori > 0) {
14800 // Two tets, below horizon and below left, are viable.
14801 //s = randomnation(2);
14802 if (randomnation(2)) {
14803 nextmove = HMOVE;
14804 } else {
14805 nextmove = LMOVE;
14806 }
14807 } else {
14808 // The tet below horizon is chosen.
14809 nextmove = HMOVE;
14810 }
14811 }
14812 } else {
14813 if (rori > 0) {
14814 if (lori > 0) {
14815 // Two tets, below right and below left, are viable.
14816 //s = randomnation(2);
14817 if (randomnation(2)) {
14818 nextmove = RMOVE;
14819 } else {
14820 nextmove = LMOVE;
14821 }
14822 } else {
14823 // The tet below right is chosen.
14824 nextmove = RMOVE;
14825 }
14826 } else {
14827 if (lori > 0) {
14828 // The tet below left is chosen.
14829 nextmove = LMOVE;
14830 } else {
14831 // 'endpt' lies either on the plane(s) or across face bcd.
14832 if (hori == 0) {
14833 if (rori == 0) {
14834 // pa->'endpt' is COLLINEAR with pa->pb.
14835 return ACROSSVERT;
14836 }
14837 if (lori == 0) {
14838 // pa->'endpt' is COLLINEAR with pa->pc.
14839 eprevesymself(*searchtet); // // [a,c,d]
14840 return ACROSSVERT;
14841 }
14842 // pa->'endpt' crosses the edge pb->pc.
14843 return ACROSSEDGE;
14844 }
14845 if (rori == 0) {
14846 if (lori == 0) {
14847 // pa->'endpt' is COLLINEAR with pa->pd.
14848 esymself(*searchtet); // face bad.
14849 enextself(*searchtet); // face [a,d,b]
14850 return ACROSSVERT;
14851 }
14852 // pa->'endpt' crosses the edge pb->pd.
14853 esymself(*searchtet); // face bad.
14854 enextself(*searchtet); // face adb
14855 return ACROSSEDGE;
14856 }
14857 if (lori == 0) {
14858 // pa->'endpt' crosses the edge pc->pd.
14859 eprevesymself(*searchtet); // [a,c,d]
14860 return ACROSSEDGE;
14861 }
14862 // pa->'endpt' crosses the face bcd.
14863 return ACROSSFACE;
14864 }
14865 }
14866 }
14867
14868 // Move to the next tet, fix pa as its origin.
14869 if (nextmove == RMOVE) {
14870 fnextself(*searchtet);
14871 } else if (nextmove == LMOVE) {
14872 eprevself(*searchtet);
14873 fnextself(*searchtet);
14874 enextself(*searchtet);
14875 } else { // HMOVE
14876 fsymself(*searchtet);
14877 enextself(*searchtet);
14878 }
14879 assert(org(*searchtet) == pa);
14880 pb = dest(*searchtet);
14881 pc = apex(*searchtet);
14882
14883 } // while (1)
14884
14885}
14886
14887///////////////////////////////////////////////////////////////////////////////
14888// //
14889// scoutsegment() Search an edge in the tetrahedralization. //
14890// //
14891// If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the //
14892// edge from startpt to endpt. //
14893// //
14894// If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
14895// indicates that the edge intersects an edge or a face. If 'refpt' is NULL,//
14896// 'searchtet' returns the edge or face. If 'refpt' is not NULL, it returns //
14897// a vertex which encroaches upon this edge, and 'searchtet' returns a tet //
14898// which containing 'refpt'. //
14899// //
14900// The following cases can happen when the input PLC is not valid. //
14901// - ACROSSVERT, the edge intersects a vertex return by the origin of //
14902// 'searchtet'. //
14903// - ACROSSSEG, the edge intersects a segment returned by 'searchtet'. //
14904// - ACROSSSUB, the edge intersects a subface returned by 'searchtet'. //
14905// //
14906///////////////////////////////////////////////////////////////////////////////
14907
14908enum tetgenmesh::interresult
14909 tetgenmesh::scoutsegment(point startpt, point endpt, triface* searchtet,
14910 point* refpt, arraypool* intfacelist)
14911{
14912 point pd;
14913 enum interresult dir;
14914 int t1ver;
14915
14916 if (b->verbose > 2) {
14917 printf(" Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
14918 }
14919
14920 point2tetorg(startpt, *searchtet);
14921 dir = finddirection(searchtet, endpt);
14922
14923 if (dir == ACROSSVERT) {
14924 pd = dest(*searchtet);
14925 if (pd == endpt) {
14926 // The job is done.
14927 return SHAREEDGE;
14928 } else {
14929 // A point is on the path.
14930 // Let the origin of the searchtet be the vertex.
14931 enextself(*searchtet);
14932 if (refpt) *refpt = pd;
14933 return ACROSSVERT;
14934 }
14935 } // if (dir == ACROSSVERT)
14936
14937 // dir is either ACROSSEDGE or ACROSSFACE.
14938
14939 enextesymself(*searchtet); // Go to the opposite face.
14940 fsymself(*searchtet); // Enter the adjacent tet.
14941
14942 if (dir == ACROSSEDGE) {
14943 // Check whether two segments are intersecting.
14944 if (issubseg(*searchtet)) {
14945 return ACROSSSEG;
14946 }
14947 } else if (dir == ACROSSFACE) {
14948 if (checksubfaceflag) {
14949 // Check whether a segment and a subface are intersecting.
14950 if (issubface(*searchtet)) {
14951 return ACROSSSUB;
14952 }
14953 }
14954 }
14955
14956 if (refpt == NULL) {
14957 // Do not need a reference point. Return.
14958 return dir;
14959 }
14960
14961 triface neightet, reftet;
14962 point pa, pb, pc;
14963 REAL angmax, ang;
14964 int types[2], poss[4];
14965 int pos = 0, i, j;
14966
14967 pa = org(*searchtet);
14968 angmax = interiorangle(pa, startpt, endpt, NULL);
14969 *refpt = pa;
14970 pb = dest(*searchtet);
14971 ang = interiorangle(pb, startpt, endpt, NULL);
14972 if (ang > angmax) {
14973 angmax = ang;
14974 *refpt = pb;
14975 }
14976 pc = apex(*searchtet);
14977 ang = interiorangle(pc, startpt, endpt, NULL);
14978 if (ang > angmax) {
14979 angmax = ang;
14980 *refpt = pc;
14981 }
14982 reftet = *searchtet; // Save the tet containing the refpt.
14983
14984 // Search intersecting faces along the segment.
14985 while (1) {
14986
14987
14988 pd = oppo(*searchtet);
14989 assert(pd != dummypoint); // SELF_CHECK
14990
14991
14992 // Stop if we meet 'endpt'.
14993 if (pd == endpt) break;
14994
14995 ang = interiorangle(pd, startpt, endpt, NULL);
14996 if (ang > angmax) {
14997 angmax = ang;
14998 *refpt = pd;
14999 reftet = *searchtet;
15000 }
15001
15002 // Find a face intersecting the segment.
15003 if (dir == ACROSSFACE) {
15004 // One of the three oppo faces in 'searchtet' intersects the segment.
15005 neightet = *searchtet;
15006 j = (neightet.ver & 3); // j is the current face number.
15007 for (i = j + 1; i < j + 4; i++) {
15008 neightet.ver = (i % 4);
15009 pa = org(neightet);
15010 pb = dest(neightet);
15011 pc = apex(neightet);
15012 pd = oppo(neightet); // The above point.
15013 if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15014 dir = (enum interresult) types[0];
15015 pos = poss[0];
15016 break;
15017 } else {
15018 dir = DISJOINT;
15019 pos = 0;
15020 }
15021 }
15022 assert(dir != DISJOINT); // SELF_CHECK
15023 } else { // dir == ACROSSEDGE
15024 // Check the two opposite faces (of the edge) in 'searchtet'.
15025 for (i = 0; i < 2; i++) {
15026 if (i == 0) {
15027 enextesym(*searchtet, neightet);
15028 } else {
15029 eprevesym(*searchtet, neightet);
15030 }
15031 pa = org(neightet);
15032 pb = dest(neightet);
15033 pc = apex(neightet);
15034 pd = oppo(neightet); // The above point.
15035 if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15036 dir = (enum interresult) types[0];
15037 pos = poss[0];
15038 break;
15039 } else {
15040 dir = DISJOINT;
15041 pos = 0;
15042 }
15043 }
15044 if (dir == DISJOINT) {
15045 // No intersection. Rotate to the next tet at the edge.
15046 dir = ACROSSEDGE;
15047 fnextself(*searchtet);
15048 continue;
15049 }
15050 }
15051
15052 if (dir == ACROSSVERT) {
15053 // This segment passing a vertex. Choose it and return.
15054 for (i = 0; i < pos; i++) {
15055 enextself(neightet);
15056 }
15057 pd = org(neightet);
15058 *refpt = pd;
15059 // break;
15060 return ACROSSVERT;
15061 } else if (dir == ACROSSEDGE) {
15062 // Get the edge intersects with the segment.
15063 for (i = 0; i < pos; i++) {
15064 enextself(neightet);
15065 }
15066 }
15067 // Go to the next tet.
15068 fsym(neightet, *searchtet);
15069
15070 if (dir == ACROSSEDGE) {
15071 // Check whether two segments are intersecting.
15072 if (issubseg(*searchtet)) {
15073 return ACROSSSEG;
15074 }
15075 } else if (dir == ACROSSFACE) {
15076 if (checksubfaceflag) {
15077 // Check whether a segment and a subface are intersecting.
15078 if (issubface(*searchtet)) {
15079 return ACROSSSUB;
15080 }
15081 }
15082 }
15083
15084 } // while (1)
15085
15086 // A valid reference point should inside the diametrial circumsphere of
15087 // the missing segment, i.e., it encroaches upon it.
15088 if (2.0 * angmax < PI) {
15089 *refpt = NULL;
15090 }
15091
15092
15093 *searchtet = reftet;
15094 return dir;
15095}
15096
15097///////////////////////////////////////////////////////////////////////////////
15098// //
15099// getsteinerpointonsegment() Get a Steiner point on a segment. //
15100// //
15101// Return '1' if 'refpt' lies on an adjacent segment of this segment. Other- //
15102// wise, return '0'. //
15103// //
15104///////////////////////////////////////////////////////////////////////////////
15105
15106int tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
15107{
15108 point ei = sorg(*seg);
15109 point ej = sdest(*seg);
15110 int adjflag = 0, i;
15111
15112 if (refpt != NULL) {
15113 REAL L, L1, t;
15114
15115 if (pointtype(refpt) == FREESEGVERTEX) {
15116 face parentseg;
15117 sdecode(point2sh(refpt), parentseg);
15118 int sidx1 = getfacetindex(parentseg);
15119 point far_pi = segmentendpointslist[sidx1 * 2];
15120 point far_pj = segmentendpointslist[sidx1 * 2 + 1];
15121 int sidx2 = getfacetindex(*seg);
15122 point far_ei = segmentendpointslist[sidx2 * 2];
15123 point far_ej = segmentendpointslist[sidx2 * 2 + 1];
15124 if ((far_pi == far_ei) || (far_pj == far_ei)) {
15125 // Create a Steiner point at the intersection of the segment
15126 // [far_ei, far_ej] and the sphere centered at far_ei with
15127 // radius |far_ei - refpt|.
15128 L = distance(far_ei, far_ej);
15129 L1 = distance(far_ei, refpt);
15130 t = L1 / L;
15131 for (i = 0; i < 3; i++) {
15132 steinpt[i] = far_ei[i] + t * (far_ej[i] - far_ei[i]);
15133 }
15134 adjflag = 1;
15135 } else if ((far_pi == far_ej) || (far_pj == far_ej)) {
15136 L = distance(far_ei, far_ej);
15137 L1 = distance(far_ej, refpt);
15138 t = L1 / L;
15139 for (i = 0; i < 3; i++) {
15140 steinpt[i] = far_ej[i] + t * (far_ei[i] - far_ej[i]);
15141 }
15142 adjflag = 1;
15143 } else {
15144 // Cut the segment by the projection point of refpt.
15145 projpt2edge(refpt, ei, ej, steinpt);
15146 }
15147 } else {
15148 // Cut the segment by the projection point of refpt.
15149 projpt2edge(refpt, ei, ej, steinpt);
15150 }
15151
15152 // Make sure that steinpt is not too close to ei and ej.
15153 L = distance(ei, ej);
15154 L1 = distance(steinpt, ei);
15155 t = L1 / L;
15156 if ((t < 0.2) || (t > 0.8)) {
15157 // Split the point at the middle.
15158 for (i = 0; i < 3; i++) {
15159 steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15160 }
15161 }
15162 } else {
15163 // Split the point at the middle.
15164 for (i = 0; i < 3; i++) {
15165 steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15166 }
15167 }
15168
15169
15170 return adjflag;
15171}
15172
15173
15174
15175///////////////////////////////////////////////////////////////////////////////
15176// //
15177// delaunizesegments() Recover segments in a DT. //
15178// //
15179// All segments need to be recovered are in 'subsegstack' (Q). They will be //
15180// be recovered one by one (in a random order). //
15181// //
15182// Given a segment s in the Q, this routine first queries s in the DT, if s //
15183// matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split //
15184// by inserting a new point p in both the DT and itself. The two new subseg- //
15185// ments of s are queued in Q. The process continues until Q is empty. //
15186// //
15187///////////////////////////////////////////////////////////////////////////////
15188
15189void tetgenmesh::delaunizesegments()
15190{
15191 triface searchtet, spintet;
15192 face searchsh;
15193 face sseg, *psseg;
15194 point refpt, newpt;
15195 enum interresult dir;
15196 insertvertexflags ivf;
15197 int t1ver;
15198
15199
15200 ivf.bowywat = 1; // Use Bowyer-Watson insertion.
15201 ivf.assignmeshsize = b->metric;
15202 ivf.sloc = (int) ONEDGE; // on 'sseg'.
15203 ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
15204
15205 // Loop until 'subsegstack' is empty.
15206 while (subsegstack->objects > 0l) {
15207 // seglist is used as a stack.
15208 subsegstack->objects--;
15209 psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
15210 sseg = *psseg;
15211
15212 // Check if this segment has been recovered.
15213 sstpivot1(sseg, searchtet);
15214 if (searchtet.tet != NULL) {
15215 continue; // Not a missing segment.
15216 }
15217
15218 // Search the segment.
15219 dir = scoutsegment(sorg(sseg), sdest(sseg), &searchtet, &refpt, NULL);
15220
15221 if (dir == SHAREEDGE) {
15222 // Found this segment, insert it.
15223 if (!issubseg(searchtet)) {
15224 // Let the segment remember an adjacent tet.
15225 sstbond1(sseg, searchtet);
15226 // Bond the segment to all tets containing it.
15227 spintet = searchtet;
15228 do {
15229 tssbond1(spintet, sseg);
15230 fnextself(spintet);
15231 } while (spintet.tet != searchtet.tet);
15232 } else {
15233 // Collision! Maybe a bug.
15234 assert(0);
15235 }
15236 } else {
15237 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15238 // The segment is missing. Split it.
15239 // Create a new point.
15240 makepoint(&newpt, FREESEGVERTEX);
15241 //setpointtype(newpt, FREESEGVERTEX);
15242 getsteinerptonsegment(&sseg, refpt, newpt);
15243
15244 // Start searching from 'searchtet'.
15245 ivf.iloc = (int) OUTSIDE;
15246 // Insert the new point into the tetrahedralization T.
15247 // Missing segments and subfaces are queued for recovery.
15248 // Note that T is convex (nonconvex = 0).
15249 if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
15250 // The new point has been inserted.
15251 st_segref_count++;
15252 if (steinerleft > 0) steinerleft--;
15253 } else {
15254 assert (ivf.iloc == (enum locateresult) NEARVERTEX);
15255 terminatetetgen(this, 4);
15256 }
15257 } else {
15258 // Indicate it is an input problem.
15259 terminatetetgen(this, 3);
15260 }
15261 }
15262 } // while
15263}
15264
15265///////////////////////////////////////////////////////////////////////////////
15266// //
15267// scoutsubface() Search subface in the tetrahedralization. //
15268// //
15269// 'searchsh' is searched in T. If it exists, it is 'locked' at the face in //
15270// T. 'searchtet' refers to the face. Otherwise, it is missing. //
15271// //
15272// The return value indicates one of the following cases: //
15273// - SHAREFACE, 'searchsh' exists and is inserted in T. //
15274// - COLLISIONFACE, 'searchsh' exists in T, but it conflicts with another //
15275// subface which was inserted earlier. It is not inserted. //
15276// //
15277///////////////////////////////////////////////////////////////////////////////
15278
15279enum tetgenmesh::interresult
15280 tetgenmesh::scoutsubface(face* searchsh, triface* searchtet)
15281{
15282 triface spintet;
15283 point pa, pb, pc;
15284 enum interresult dir;
15285 int t1ver;
15286
15287 pa = sorg(*searchsh);
15288 pb = sdest(*searchsh);
15289
15290
15291 // Get a tet whose origin is a.
15292 point2tetorg(pa, *searchtet);
15293 // Search the edge [a,b].
15294 dir = finddirection(searchtet, pb);
15295 if (dir == ACROSSVERT) {
15296 // Check validity of a PLC.
15297 if (dest(*searchtet) != pb) {
15298 // A vertex lies on the search edge.
15299 enextself(*searchtet);
15300 // It is possible a PLC self-intersection problem.
15301 terminatetetgen(this, 3);
15302 return TOUCHEDGE;
15303 }
15304 // The edge exists. Check if the face exists.
15305 pc = sapex(*searchsh);
15306 // Searchtet holds edge [a,b]. Search a face with apex c.
15307 spintet = *searchtet;
15308 while (1) {
15309 if (apex(spintet) == pc) {
15310 // Found a face matching to 'searchsh'!
15311 if (!issubface(spintet)) {
15312 // Insert 'searchsh'.
15313 tsbond(spintet, *searchsh);
15314 fsymself(spintet);
15315 sesymself(*searchsh);
15316 tsbond(spintet, *searchsh);
15317 *searchtet = spintet;
15318 return SHAREFACE;
15319 } else {
15320 // Another subface is already inserted.
15321 face checksh;
15322 tspivot(spintet, checksh);
15323 assert(checksh.sh != searchsh->sh); // SELF_CHECK
15324 // This is possibly an input problem, i.e., two facets overlap.
15325 // Report this problem and exit.
15326 printf("Warning: Found two facets nearly overlap.\n");
15327 terminatetetgen(this, 5);
15328 // unifysubfaces(&checksh, searchsh);
15329 *searchtet = spintet;
15330 return COLLISIONFACE;
15331 }
15332 }
15333 fnextself(spintet);
15334 if (spintet.tet == searchtet->tet) break;
15335 }
15336 }
15337
15338 // dir is either ACROSSEDGE or ACROSSFACE.
15339 return dir;
15340}
15341
15342///////////////////////////////////////////////////////////////////////////////
15343// //
15344// formregion() Form the missing region of a missing subface. //
15345// //
15346// 'missh' is a missing subface. From it we form a missing region R which is //
15347// a connected region formed by a set of missing subfaces of a facet. //
15348// Comment: There should be no segment inside R. //
15349// //
15350// 'missingshs' returns the list of subfaces in R. All subfaces in this list //
15351// are oriented as the 'missh'. 'missingshbds' returns the list of boundary //
15352// edges (tetrahedral handles) of R. 'missingshverts' returns all vertices //
15353// of R. They are all pmarktested. //
15354// //
15355// Except the first one (which is 'missh') in 'missingshs', each subface in //
15356// this list represents an internal edge of R, i.e., it is missing in the //
15357// tetrahedralization. Since R may contain interior vertices, not all miss- //
15358// ing edges can be found by this way. //
15359///////////////////////////////////////////////////////////////////////////////
15360
15361void tetgenmesh::formregion(face* missh, arraypool* missingshs,
15362 arraypool* missingshbds, arraypool* missingshverts)
15363{
15364 triface searchtet, spintet;
15365 face neighsh, *parysh;
15366 face neighseg, fakeseg;
15367 point pa, pb, *parypt;
15368 enum interresult dir;
15369 int t1ver;
15370 int i, j;
15371
15372 smarktest(*missh);
15373 missingshs->newindex((void **) &parysh);
15374 *parysh = *missh;
15375
15376 // Incrementally find other missing subfaces.
15377 for (i = 0; i < missingshs->objects; i++) {
15378 missh = (face *) fastlookup(missingshs, i);
15379 for (j = 0; j < 3; j++) {
15380 pa = sorg(*missh);
15381 pb = sdest(*missh);
15382 point2tetorg(pa, searchtet);
15383 dir = finddirection(&searchtet, pb);
15384 if (dir != ACROSSVERT) {
15385 // This edge is missing. Its neighbor is a missing subface.
15386 spivot(*missh, neighsh);
15387 if (!smarktested(neighsh)) {
15388 // Adjust the face orientation.
15389 if (sorg(neighsh) != pb) sesymself(neighsh);
15390 smarktest(neighsh);
15391 missingshs->newindex((void **) &parysh);
15392 *parysh = neighsh;
15393 }
15394 } else {
15395 if (dest(searchtet) != pb) {
15396 // This might be a self-intersection problem.
15397 terminatetetgen(this, 3);
15398 }
15399 }
15400 // Collect the vertices of R.
15401 if (!pmarktested(pa)) {
15402 pmarktest(pa);
15403 missingshverts->newindex((void **) &parypt);
15404 *parypt = pa;
15405 }
15406 senextself(*missh);
15407 } // j
15408 } // i
15409
15410 // Get the boundary edges of R.
15411 for (i = 0; i < missingshs->objects; i++) {
15412 missh = (face *) fastlookup(missingshs, i);
15413 for (j = 0; j < 3; j++) {
15414 spivot(*missh, neighsh);
15415 if ((neighsh.sh == NULL) || !smarktested(neighsh)) {
15416 // A boundary edge of R.
15417 // Let the segment point to the adjacent tet.
15418 point2tetorg(sorg(*missh), searchtet);
15419 finddirection(&searchtet, sdest(*missh));
15420 missingshbds->newindex((void **) &parysh);
15421 *parysh = *missh;
15422 // Check if this edge is a segment.
15423 sspivot(*missh, neighseg);
15424 if (neighseg.sh == NULL) {
15425 // Temporarily create a segment at this edge.
15426 makeshellface(subsegs, &fakeseg);
15427 setsorg(fakeseg, sorg(*missh));
15428 setsdest(fakeseg, sdest(*missh));
15429 sinfect(fakeseg); // Mark it as faked.
15430 // Connect it to all tets at this edge.
15431 spintet = searchtet;
15432 while (1) {
15433 tssbond1(spintet, fakeseg);
15434 fnextself(spintet);
15435 if (spintet.tet == searchtet.tet) break;
15436 }
15437 neighseg = fakeseg;
15438 }
15439 // Let the segment and the boundary edge point to each other.
15440 ssbond(*missh, neighseg);
15441 sstbond1(neighseg, searchtet);
15442 }
15443 senextself(*missh);
15444 } // j
15445 } // i
15446
15447
15448 // Unmarktest collected missing subfaces.
15449 for (i = 0; i < missingshs->objects; i++) {
15450 parysh = (face *) fastlookup(missingshs, i);
15451 sunmarktest(*parysh);
15452 }
15453}
15454
15455///////////////////////////////////////////////////////////////////////////////
15456// //
15457// scoutcrossedge() Search an edge that crosses the missing region. //
15458// //
15459// Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
15460// over, the edge is oriented such that its origin lies below R. Return 0 //
15461// if no such edge is found. //
15462// //
15463// Assumption: All vertices of the missing region are marktested. //
15464// //
15465///////////////////////////////////////////////////////////////////////////////
15466
15467int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds,
15468 arraypool* missingshs)
15469{
15470 triface searchtet, spintet;
15471 face *parysh;
15472 face neighseg;
15473 point pa, pb, pc, pd, pe;
15474 enum interresult dir;
15475 REAL ori;
15476 int types[2], poss[4];
15477 int searchflag, interflag;
15478 int t1ver;
15479 int i, j;
15480
15481 searchflag = 0;
15482
15483 for (j = 0; j < missingshbds->objects && !searchflag; j++) {
15484 parysh = (face *) fastlookup(missingshbds, j);
15485 sspivot(*parysh, neighseg);
15486 sstpivot1(neighseg, searchtet);
15487 interflag = 0;
15488 // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
15489 spintet = searchtet;
15490 while (1) {
15491 pd = apex(spintet);
15492 pe = oppo(spintet);
15493 // Skip a hull edge.
15494 if ((pd != dummypoint) && (pe != dummypoint)) {
15495 // Skip an edge containing a vertex of R.
15496 if (!pmarktested(pd) && !pmarktested(pe)) {
15497 // Check if [d,e] intersects R.
15498 for (i = 0; i < missingshs->objects && !interflag; i++) {
15499 parysh = (face *) fastlookup(missingshs, i);
15500 pa = sorg(*parysh);
15501 pb = sdest(*parysh);
15502 pc = sapex(*parysh);
15503 interflag=tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
15504 if (interflag > 0) {
15505 if (interflag == 2) {
15506 // They intersect at a single point.
15507 dir = (enum interresult) types[0];
15508 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15509 //pos = poss[0];
15510 // Go to the crossing edge [d,e,#,#].
15511 edestoppo(spintet, crosstet); // // [d,e,#,#].
15512 // Check if it is a segment.
15513 if (issubseg(crosstet)) {
15514 //face checkseg;
15515 //tsspivot1(crosstet, checkseg);
15516 //reportselfintersect(&checkseg, parysh);
15517 terminatetetgen(this, 3);
15518 }
15519 // Adjust the edge such that d lies below [a,b,c].
15520 ori = orient3d(pa, pb, pc, pd);
15521 assert(ori != 0);
15522 if (ori < 0) {
15523 esymself(crosstet);
15524 }
15525 searchflag = 1;
15526 }
15527 }
15528 break;
15529 } // if (interflag > 0)
15530 }
15531 }
15532 }
15533 // Leave search at this bdry edge if an intersection is found.
15534 if (interflag > 0) break;
15535 // Go to the next tetrahedron.
15536 fnextself(spintet);
15537 if (spintet.tet == searchtet.tet) break;
15538 } // while (1)
15539 } // j
15540
15541 return searchflag;
15542}
15543
15544///////////////////////////////////////////////////////////////////////////////
15545// //
15546// formcavity() Form the cavity of a missing region. //
15547// //
15548// The missing region R is formed by a set of missing subfaces 'missingshs'. //
15549// In the following, we assume R is horizontal and oriented. (All subfaces //
15550// of R are oriented in the same way.) 'searchtet' is a tetrahedron [d,e,#, //
15551// #] which intersects R in its interior, where the edge [d,e] intersects R, //
15552// and d lies below R. //
15553// //
15554// 'crosstets' returns the set of crossing tets. Every tet in it has the //
15555// form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R. The //
15556// set of tets form the cavity C, which is divided into two parts by R, one //
15557// at top and one at bottom. 'topfaces' and 'botfaces' return the upper and //
15558// lower boundary faces of C. 'toppoints' contains vertices of 'crosstets' //
15559// in the top part of C, and so does 'botpoints'. Both 'toppoints' and //
15560// 'botpoints' contain vertices of R. //
15561// //
15562// Important: This routine assumes all vertices of the facet containing this //
15563// subface are marked, i.e., pmarktested(p) returns true. //
15564// //
15565///////////////////////////////////////////////////////////////////////////////
15566
15567bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
15568 arraypool* crosstets, arraypool* topfaces,
15569 arraypool* botfaces, arraypool* toppoints,
15570 arraypool* botpoints)
15571{
15572 arraypool *crossedges;
15573 triface spintet, neightet, *parytet;
15574 face *parysh = NULL;
15575 point pa, pd, pe, *parypt;
15576 enum interresult dir;
15577 bool testflag, invalidflag;
15578 int types[2], poss[4];
15579 int t1ver;
15580 int i, j, k;
15581
15582 // Temporarily re-use 'topfaces' for all crossing edges.
15583 crossedges = topfaces;
15584
15585 if (b->verbose > 2) {
15586 printf(" Form the cavity of a missing region.\n");
15587 }
15588 // Mark this edge to avoid testing it later.
15589 markedge(*searchtet);
15590 crossedges->newindex((void **) &parytet);
15591 *parytet = *searchtet;
15592
15593 invalidflag = 0;
15594
15595 // Collect all crossing tets. Each cross tet is saved in the standard
15596 // form [d,e,#,#], where [d,e] is a crossing edge, d lies below R.
15597 // NEITHER d NOR e is a vertex of R (!pmarktested).
15598 for (i = 0; i < crossedges->objects; i++) {
15599 // Get a crossing edge [d,e,#,#].
15600 searchtet = (triface *) fastlookup(crossedges, i);
15601
15602 // Sort vertices into the bottom and top arrays.
15603 pd = org(*searchtet);
15604 if (!pinfected(pd)) {
15605 pinfect(pd);
15606 botpoints->newindex((void **) &parypt);
15607 *parypt = pd;
15608 }
15609 pe = dest(*searchtet);
15610 if (!pinfected(pe)) {
15611 pinfect(pe);
15612 toppoints->newindex((void **) &parypt);
15613 *parypt = pe;
15614 }
15615
15616 // All tets sharing this edge are crossing tets.
15617 spintet = *searchtet;
15618 while (1) {
15619 if (!infected(spintet)) {
15620 infect(spintet);
15621 crosstets->newindex((void **) &parytet);
15622 *parytet = spintet;
15623 }
15624 // Go to the next crossing tet.
15625 fnextself(spintet);
15626 if (spintet.tet == searchtet->tet) break;
15627 } // while (1)
15628
15629 // Detect new crossing edges.
15630 spintet = *searchtet;
15631 while (1) {
15632 // spintet is [d,e,a,#], where d lies below R, and e lies above R.
15633 pa = apex(spintet);
15634 if (pa != dummypoint) {
15635 if (!pmarktested(pa)) {
15636 // There exists a crossing edge, either [e,a] or [a,d]. First check
15637 // if the crossing edge has already be added, i.e., check if a
15638 // tetrahedron at this edge is marked.
15639 testflag = true;
15640 for (j = 0; j < 2 && testflag; j++) {
15641 if (j == 0) {
15642 enext(spintet, neightet);
15643 } else {
15644 eprev(spintet, neightet);
15645 }
15646 while (1) {
15647 if (edgemarked(neightet)) {
15648 // This crossing edge has already been tested. Skip it.
15649 testflag = false;
15650 break;
15651 }
15652 fnextself(neightet);
15653 if (neightet.tet == spintet.tet) break;
15654 }
15655 } // j
15656 if (testflag) {
15657 // Test if [e,a] or [a,d] intersects R.
15658 // Do a brute-force search in the set of subfaces of R. Slow!
15659 // Need to be improved!
15660 pd = org(spintet);
15661 pe = dest(spintet);
15662 for (k = 0; k < missingshs->objects; k++) {
15663 parysh = (face *) fastlookup(missingshs, k);
15664 if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
15665 pe, pa, NULL, 1, types, poss)) {
15666 // Found intersection. 'a' lies below R.
15667 enext(spintet, neightet);
15668 dir = (enum interresult) types[0];
15669 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15670 // A valid intersection.
15671 } else {
15672 // A non-valid intersection. Maybe a PLC problem.
15673 invalidflag = 1;
15674 }
15675 break;
15676 }
15677 if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
15678 pa, pd, NULL, 1, types, poss)) {
15679 // Found intersection. 'a' lies above R.
15680 eprev(spintet, neightet);
15681 dir = (enum interresult) types[0];
15682 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15683 // A valid intersection.
15684 } else {
15685 // A non-valid intersection. Maybe a PLC problem.
15686 invalidflag = 1;
15687 }
15688 break;
15689 }
15690 } // k
15691 if (k < missingshs->objects) {
15692 // Found a pair of triangle - edge intersection.
15693 if (invalidflag) {
15694 if (!b->quiet) {
15695 printf("Warning: A non-valid facet - edge intersection\n");
15696 printf(" subface: (%d, %d, %d) edge: (%d, %d)\n",
15697 pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
15698 pointmark(sapex(*parysh)), pointmark(org(neightet)),
15699 pointmark(dest(neightet)));
15700 }
15701 // It may be a PLC problem.
15702 terminatetetgen(this, 3);
15703 }
15704 // Adjust the edge direction, so that its origin lies below R,
15705 // and its destination lies above R.
15706 esymself(neightet);
15707 // Check if this edge is a segment.
15708 if (issubseg(neightet)) {
15709 // Invalid PLC!
15710 //face checkseg;
15711 //tsspivot1(neightet, checkseg);
15712 //reportselfintersect(&checkseg, parysh);
15713 terminatetetgen(this, 3);
15714 }
15715 // Mark this edge to avoid testing it again.
15716 markedge(neightet);
15717 crossedges->newindex((void **) &parytet);
15718 *parytet = neightet;
15719 } else {
15720 // No intersection is found. It may be a PLC problem.
15721 invalidflag = 1;
15722 // Split the subface intersecting [d,e].
15723 for (k = 0; k < missingshs->objects; k++) {
15724 parysh = (face *) fastlookup(missingshs, k);
15725 // Test if this face intersects [e,a].
15726 if (tri_edge_test(sorg(*parysh),sdest(*parysh),sapex(*parysh),
15727 pd, pe, NULL, 1, types, poss)) {
15728 break;
15729 }
15730 } // k
15731 if (k == missingshs->objects) {
15732 // Not found such an edge.
15733 // Arbitrarily choose an edge (except the first) to split.
15734 k = randomnation(missingshs->objects - 1);
15735 parysh = (face *) fastlookup(missingshs, k + 1);
15736 }
15737 recentsh = *parysh;
15738 recenttet = spintet; // For point location.
15739 break; // the while (1) loop
15740 } // if (k == missingshs->objects)
15741 } // if (testflag)
15742 } // if (!pmarktested(pa) || b->psc)
15743 } // if (pa != dummypoint)
15744 // Go to the next crossing tet.
15745 fnextself(spintet);
15746 if (spintet.tet == searchtet->tet) break;
15747 } // while (1)
15748
15749 //if (b->psc) {
15750 if (invalidflag) break;
15751 //}
15752 } // i
15753
15754 if (b->verbose > 2) {
15755 printf(" Formed cavity: %ld (%ld) cross tets (edges).\n",
15756 crosstets->objects, crossedges->objects);
15757 }
15758
15759 // Unmark all marked edges.
15760 for (i = 0; i < crossedges->objects; i++) {
15761 searchtet = (triface *) fastlookup(crossedges, i);
15762 assert(edgemarked(*searchtet)); // SELF_CHECK
15763 unmarkedge(*searchtet);
15764 }
15765 crossedges->restart();
15766
15767
15768 if (invalidflag) {
15769 // Unmark all collected tets.
15770 for (i = 0; i < crosstets->objects; i++) {
15771 searchtet = (triface *) fastlookup(crosstets, i);
15772 uninfect(*searchtet);
15773 }
15774 // Unmark all collected vertices.
15775 for (i = 0; i < botpoints->objects; i++) {
15776 parypt = (point *) fastlookup(botpoints, i);
15777 puninfect(*parypt);
15778 }
15779 for (i = 0; i < toppoints->objects; i++) {
15780 parypt = (point *) fastlookup(toppoints, i);
15781 puninfect(*parypt);
15782 }
15783 crosstets->restart();
15784 botpoints->restart();
15785 toppoints->restart();
15786
15787 // Randomly split an interior edge of R.
15788 i = randomnation(missingshs->objects - 1);
15789 recentsh = * (face *) fastlookup(missingshs, i);
15790 return false;
15791 }
15792
15793
15794 // Collect the top and bottom faces and the middle vertices. Since all top
15795 // and bottom vertices have been infected. Uninfected vertices must be
15796 // middle vertices (i.e., the vertices of R).
15797 // NOTE 1: Hull tets may be collected. Process them as a normal one.
15798 // NOTE 2: Some previously recovered subfaces may be completely inside the
15799 // cavity. In such case, we remove these subfaces from the cavity and put
15800 // them into 'subfacstack'. They will be recovered later.
15801 // NOTE 3: Some segments may be completely inside the cavity, e.g., they
15802 // attached to a subface which is inside the cavity. Such segments are
15803 // put in 'subsegstack'. They will be recovered later.
15804 // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
15805 // are identified in the routine "carvecavity()".
15806
15807 for (i = 0; i < crosstets->objects; i++) {
15808 searchtet = (triface *) fastlookup(crosstets, i);
15809 // searchtet is [d,e,a,b].
15810 eorgoppo(*searchtet, spintet);
15811 fsym(spintet, neightet); // neightet is [a,b,e,#]
15812 if (!infected(neightet)) {
15813 // A top face.
15814 topfaces->newindex((void **) &parytet);
15815 *parytet = neightet;
15816 }
15817 edestoppo(*searchtet, spintet);
15818 fsym(spintet, neightet); // neightet is [b,a,d,#]
15819 if (!infected(neightet)) {
15820 // A bottom face.
15821 botfaces->newindex((void **) &parytet);
15822 *parytet = neightet;
15823 }
15824 // Add middle vertices if there are (skip dummypoint).
15825 pa = org(neightet);
15826 if (!pinfected(pa)) {
15827 if (pa != dummypoint) {
15828 pinfect(pa);
15829 botpoints->newindex((void **) &parypt);
15830 *parypt = pa;
15831 toppoints->newindex((void **) &parypt);
15832 *parypt = pa;
15833 }
15834 }
15835 pa = dest(neightet);
15836 if (!pinfected(pa)) {
15837 if (pa != dummypoint) {
15838 pinfect(pa);
15839 botpoints->newindex((void **) &parypt);
15840 *parypt = pa;
15841 toppoints->newindex((void **) &parypt);
15842 *parypt = pa;
15843 }
15844 }
15845 } // i
15846
15847 // Uninfect all collected top, bottom, and middle vertices.
15848 for (i = 0; i < toppoints->objects; i++) {
15849 parypt = (point *) fastlookup(toppoints, i);
15850 puninfect(*parypt);
15851 }
15852 for (i = 0; i < botpoints->objects; i++) {
15853 parypt = (point *) fastlookup(botpoints, i);
15854 puninfect(*parypt);
15855 }
15856 cavitycount++;
15857
15858 return true;
15859}
15860
15861///////////////////////////////////////////////////////////////////////////////
15862// //
15863// delaunizecavity() Fill a cavity by Delaunay tetrahedra. //
15864// //
15865// The cavity C to be tetrahedralized is the top or bottom part of a whole //
15866// cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
15867// faces' do not form a closed polyhedron. The "open" side are subfaces of //
15868// the missing facet. These faces will be recovered later in fillcavity(). //
15869// //
15870// This routine first constructs the DT of the vertices. Then it identifies //
15871// the half boundary faces of the cavity in DT. Possiblely the cavity C will //
15872// be enlarged. //
15873// //
15874// The DT is returned in 'newtets'. //
15875// //
15876///////////////////////////////////////////////////////////////////////////////
15877
15878void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
15879 arraypool *cavshells, arraypool *newtets,
15880 arraypool *crosstets, arraypool *misfaces)
15881{
15882 triface searchtet, neightet, *parytet, *parytet1;
15883 face tmpsh, *parysh;
15884 point pa, pb, pc, pd, pt[3], *parypt;
15885 enum interresult dir;
15886 insertvertexflags ivf;
15887 REAL ori;
15888 long baknum, bakhullsize;
15889 int bakchecksubsegflag, bakchecksubfaceflag;
15890 int t1ver;
15891 int i, j;
15892
15893 if (b->verbose > 2) {
15894 printf(" Delaunizing cavity: %ld points, %ld faces.\n",
15895 cavpoints->objects, cavfaces->objects);
15896 }
15897 // Remember the current number of crossing tets. It may be enlarged later.
15898 baknum = crosstets->objects;
15899 bakhullsize = hullsize;
15900 bakchecksubsegflag = checksubsegflag;
15901 bakchecksubfaceflag = checksubfaceflag;
15902 hullsize = 0l;
15903 checksubsegflag = 0;
15904 checksubfaceflag = 0;
15905 b->verbose--; // Suppress informations for creating Delaunay tetra.
15906 b->plc = 0; // Do not check near vertices.
15907
15908 ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
15909
15910 // Get four non-coplanar points (no dummypoint).
15911 pa = pb = pc = NULL;
15912 for (i = 0; i < cavfaces->objects; i++) {
15913 parytet = (triface *) fastlookup(cavfaces, i);
15914 parytet->ver = epivot[parytet->ver];
15915 if (apex(*parytet) != dummypoint) {
15916 pa = org(*parytet);
15917 pb = dest(*parytet);
15918 pc = apex(*parytet);
15919 break;
15920 }
15921 }
15922 pd = NULL;
15923 for (; i < cavfaces->objects; i++) {
15924 parytet = (triface *) fastlookup(cavfaces, i);
15925 pt[0] = org(*parytet);
15926 pt[1] = dest(*parytet);
15927 pt[2] = apex(*parytet);
15928 for (j = 0; j < 3; j++) {
15929 if (pt[j] != dummypoint) { // Do not include a hull point.
15930 ori = orient3d(pa, pb, pc, pt[j]);
15931 if (ori != 0) {
15932 pd = pt[j];
15933 if (ori > 0) { // Swap pa and pb.
15934 pt[j] = pa; pa = pb; pb = pt[j];
15935 }
15936 break;
15937 }
15938 }
15939 }
15940 if (pd != NULL) break;
15941 }
15942 assert(i < cavfaces->objects); // SELF_CHECK
15943
15944 // Create an init DT.
15945 initialdelaunay(pa, pb, pc, pd);
15946
15947 // Incrementally insert the vertices (duplicated vertices are ignored).
15948 for (i = 0; i < cavpoints->objects; i++) {
15949 pt[0] = * (point *) fastlookup(cavpoints, i);
15950 searchtet = recenttet;
15951 ivf.iloc = (int) OUTSIDE;
15952 insertpoint(pt[0], &searchtet, NULL, NULL, &ivf);
15953 }
15954
15955 if (b->verbose > 2) {
15956 printf(" Identifying %ld boundary faces of the cavity.\n",
15957 cavfaces->objects);
15958 }
15959
15960 while (1) {
15961
15962 // Identify boundary faces. Mark interior tets. Save missing faces.
15963 for (i = 0; i < cavfaces->objects; i++) {
15964 parytet = (triface *) fastlookup(cavfaces, i);
15965 // Skip an interior face (due to the enlargement of the cavity).
15966 if (infected(*parytet)) continue;
15967 parytet->ver = epivot[parytet->ver];
15968 pt[0] = org(*parytet);
15969 pt[1] = dest(*parytet);
15970 pt[2] = apex(*parytet);
15971 // Create a temp subface.
15972 makeshellface(subfaces, &tmpsh);
15973 setshvertices(tmpsh, pt[0], pt[1], pt[2]);
15974 // Insert tmpsh in DT.
15975 searchtet.tet = NULL;
15976 dir = scoutsubface(&tmpsh, &searchtet);
15977 if (dir == SHAREFACE) {
15978 // Inserted! 'tmpsh' must face toward the inside of the cavity.
15979 // Remember the boundary tet (outside the cavity) in tmpsh
15980 // (use the adjacent tet slot).
15981 tmpsh.sh[0] = (shellface) encode(*parytet);
15982 // Save this subface.
15983 cavshells->newindex((void **) &parysh);
15984 *parysh = tmpsh;
15985 }
15986 else {
15987 // This boundary face is missing.
15988 shellfacedealloc(subfaces, tmpsh.sh);
15989 // Save this face in list.
15990 misfaces->newindex((void **) &parytet1);
15991 *parytet1 = *parytet;
15992 }
15993 } // i
15994
15995 if (misfaces->objects > 0) {
15996 if (b->verbose > 2) {
15997 printf(" Enlarging the cavity. %ld missing bdry faces\n",
15998 misfaces->objects);
15999 }
16000
16001 // Removing all temporary subfaces.
16002 for (i = 0; i < cavshells->objects; i++) {
16003 parysh = (face *) fastlookup(cavshells, i);
16004 stpivot(*parysh, neightet);
16005 tsdissolve(neightet); // Detach it from adj. tets.
16006 fsymself(neightet);
16007 tsdissolve(neightet);
16008 shellfacedealloc(subfaces, parysh->sh);
16009 }
16010 cavshells->restart();
16011
16012 // Infect the points which are of the cavity.
16013 for (i = 0; i < cavpoints->objects; i++) {
16014 pt[0] = * (point *) fastlookup(cavpoints, i);
16015 pinfect(pt[0]); // Mark it as inserted.
16016 }
16017
16018 // Enlarge the cavity.
16019 for (i = 0; i < misfaces->objects; i++) {
16020 // Get a missing face.
16021 parytet = (triface *) fastlookup(misfaces, i);
16022 if (!infected(*parytet)) {
16023 // Put it into crossing tet list.
16024 infect(*parytet);
16025 crosstets->newindex((void **) &parytet1);
16026 *parytet1 = *parytet;
16027 // Insert the opposite point if it is not in DT.
16028 pd = oppo(*parytet);
16029 if (!pinfected(pd)) {
16030 searchtet = recenttet;
16031 ivf.iloc = (int) OUTSIDE;
16032 insertpoint(pd, &searchtet, NULL, NULL, &ivf);
16033 pinfect(pd);
16034 cavpoints->newindex((void **) &parypt);
16035 *parypt = pd;
16036 }
16037 // Add three opposite faces into the boundary list.
16038 for (j = 0; j < 3; j++) {
16039 esym(*parytet, neightet);
16040 fsymself(neightet);
16041 if (!infected(neightet)) {
16042 cavfaces->newindex((void **) &parytet1);
16043 *parytet1 = neightet;
16044 }
16045 enextself(*parytet);
16046 } // j
16047 } // if (!infected(parytet))
16048 } // i
16049
16050 // Uninfect the points which are of the cavity.
16051 for (i = 0; i < cavpoints->objects; i++) {
16052 pt[0] = * (point *) fastlookup(cavpoints, i);
16053 puninfect(pt[0]);
16054 }
16055
16056 misfaces->restart();
16057 continue;
16058 } // if (misfaces->objects > 0)
16059
16060 break;
16061
16062 } // while (1)
16063
16064 // Collect all tets of the DT. All new tets are marktested.
16065 marktest(recenttet);
16066 newtets->newindex((void **) &parytet);
16067 *parytet = recenttet;
16068 for (i = 0; i < newtets->objects; i++) {
16069 searchtet = * (triface *) fastlookup(newtets, i);
16070 for (j = 0; j < 4; j++) {
16071 decode(searchtet.tet[j], neightet);
16072 if (!marktested(neightet)) {
16073 marktest(neightet);
16074 newtets->newindex((void **) &parytet);
16075 *parytet = neightet;
16076 }
16077 }
16078 }
16079
16080 cavpoints->restart();
16081 cavfaces->restart();
16082
16083 if (crosstets->objects > baknum) {
16084 // The cavity has been enlarged.
16085 cavityexpcount++;
16086 }
16087
16088 // Restore the original values.
16089 hullsize = bakhullsize;
16090 checksubsegflag = bakchecksubsegflag;
16091 checksubfaceflag = bakchecksubfaceflag;
16092 b->verbose++;
16093 b->plc = 1;
16094}
16095
16096///////////////////////////////////////////////////////////////////////////////
16097// //
16098// fillcavity() Fill new tets into the cavity. //
16099// //
16100// The new tets are stored in two disjoint sets(which share the same facet). //
16101// 'topfaces' and 'botfaces' are the boundaries of these two sets, respect- //
16102// ively. 'midfaces' is empty on input, and will store faces in the facet. //
16103// //
16104// Important: This routine assumes all vertices of the missing region R are //
16105// marktested, i.e., pmarktested(p) returns true. //
16106// //
16107///////////////////////////////////////////////////////////////////////////////
16108
16109bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
16110 arraypool* midfaces, arraypool* missingshs,
16111 arraypool* topnewtets, arraypool* botnewtets,
16112 triface* crossedge)
16113{
16114 arraypool *cavshells;
16115 triface bdrytet, neightet, *parytet;
16116 triface searchtet, spintet;
16117 face *parysh;
16118 face checkseg;
16119 point pa, pb, pc;
16120 bool mflag;
16121 int t1ver;
16122 int i, j;
16123
16124 // Connect newtets to tets outside the cavity. These connections are needed
16125 // for identifying the middle faces (which belong to R).
16126 for (j = 0; j < 2; j++) {
16127 cavshells = (j == 0 ? topshells : botshells);
16128 if (cavshells != NULL) {
16129 for (i = 0; i < cavshells->objects; i++) {
16130 // Get a temp subface.
16131 parysh = (face *) fastlookup(cavshells, i);
16132 // Get the boundary tet outside the cavity (saved in sh[0]).
16133 decode(parysh->sh[0], bdrytet);
16134 pa = org(bdrytet);
16135 pb = dest(bdrytet);
16136 pc = apex(bdrytet);
16137 // Get the adjacent new tet inside the cavity.
16138 stpivot(*parysh, neightet);
16139 // Mark neightet as an interior tet of this cavity.
16140 infect(neightet);
16141 // Connect the two tets (the old connections are replaced).
16142 bond(bdrytet, neightet);
16143 tsdissolve(neightet); // Clear the pointer to tmpsh.
16144 // Update the point-to-tets map.
16145 setpoint2tet(pa, (tetrahedron) neightet.tet);
16146 setpoint2tet(pb, (tetrahedron) neightet.tet);
16147 setpoint2tet(pc, (tetrahedron) neightet.tet);
16148 } // i
16149 } // if (cavshells != NULL)
16150 } // j
16151
16152 if (crossedge != NULL) {
16153 // Glue top and bottom tets at their common facet.
16154 triface toptet, bottet, spintet, *midface;
16155 point pd, pe;
16156 REAL ori;
16157 int types[2], poss[4];
16158 int interflag;
16159 int bflag;
16160
16161 mflag = false;
16162 pd = org(*crossedge);
16163 pe = dest(*crossedge);
16164
16165 // Search the first (middle) face in R.
16166 // Since R may be non-convex, we must make sure that the face is in the
16167 // interior of R. We search a face in 'topnewtets' whose three vertices
16168 // are on R and it intersects 'crossedge' in its interior. Then search
16169 // a matching face in 'botnewtets'.
16170 for (i = 0; i < topnewtets->objects && !mflag; i++) {
16171 searchtet = * (triface *) fastlookup(topnewtets, i);
16172 for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
16173 pa = org(searchtet);
16174 if (pmarktested(pa)) {
16175 pb = dest(searchtet);
16176 if (pmarktested(pb)) {
16177 pc = apex(searchtet);
16178 if (pmarktested(pc)) {
16179 // Check if this face intersects [d,e].
16180 interflag = tri_edge_test(pa,pb,pc,pd,pe,NULL,1,types,poss);
16181 if (interflag == 2) {
16182 // They intersect at a single point. Found.
16183 toptet = searchtet;
16184 // The face lies in the interior of R.
16185 // Get the tet (in topnewtets) which lies above R.
16186 ori = orient3d(pa, pb, pc, pd);
16187 assert(ori != 0);
16188 if (ori < 0) {
16189 fsymself(toptet);
16190 pa = org(toptet);
16191 pb = dest(toptet);
16192 }
16193 // Search the face [b,a,c] in 'botnewtets'.
16194 for (j = 0; j < botnewtets->objects; j++) {
16195 neightet = * (triface *) fastlookup(botnewtets, j);
16196 // Is neightet contains 'b'.
16197 if ((point) neightet.tet[4] == pb) {
16198 neightet.ver = 11;
16199 } else if ((point) neightet.tet[5] == pb) {
16200 neightet.ver = 3;
16201 } else if ((point) neightet.tet[6] == pb) {
16202 neightet.ver = 7;
16203 } else if ((point) neightet.tet[7] == pb) {
16204 neightet.ver = 0;
16205 } else {
16206 continue;
16207 }
16208 // Is the 'neightet' contains edge [b,a].
16209 if (dest(neightet) == pa) {
16210 // 'neightet' is just the edge.
16211 } else if (apex(neightet) == pa) {
16212 eprevesymself(neightet);
16213 } else if (oppo(neightet) == pa) {
16214 esymself(neightet);
16215 enextself(neightet);
16216 } else {
16217 continue;
16218 }
16219 // Is 'neightet' the face [b,a,c].
16220 if (apex(neightet) == pc) {
16221 bottet = neightet;
16222 mflag = true;
16223 break;
16224 }
16225 } // j
16226 } // if (interflag == 2)
16227 } // pc
16228 } // pb
16229 } // pa
16230 } // toptet.ver
16231 } // i
16232
16233 if (mflag) {
16234 // Found a pair of matched faces in 'toptet' and 'bottet'.
16235 bond(toptet, bottet);
16236 // Both are interior tets.
16237 infect(toptet);
16238 infect(bottet);
16239 // Add this face into search list.
16240 markface(toptet);
16241 midfaces->newindex((void **) &parytet);
16242 *parytet = toptet;
16243 } else {
16244 // No pair of 'toptet' and 'bottet'.
16245 toptet.tet = NULL;
16246 // Randomly split an interior edge of R.
16247 i = randomnation(missingshs->objects - 1);
16248 recentsh = * (face *) fastlookup(missingshs, i);
16249 }
16250
16251 // Find other middle faces, connect top and bottom tets.
16252 for (i = 0; i < midfaces->objects && mflag; i++) {
16253 // Get a matched middle face [a, b, c]
16254 midface = (triface *) fastlookup(midfaces, i);
16255 // The tet must be a new created tet (marktested).
16256 assert(marktested(*midface)); // SELF_CHECK
16257 // Check the neighbors at the edges of this face.
16258 for (j = 0; j < 3 && mflag; j++) {
16259 toptet = *midface;
16260 bflag = false;
16261 while (1) {
16262 // Go to the next face in the same tet.
16263 esymself(toptet);
16264 pc = apex(toptet);
16265 if (pmarktested(pc)) {
16266 break; // Find a subface.
16267 }
16268 if (pc == dummypoint) {
16269 assert(0); // Check this case.
16270 break; // Find a subface.
16271 }
16272 // Go to the adjacent tet.
16273 fsymself(toptet);
16274 // Do we walk outside the cavity?
16275 if (!marktested(toptet)) {
16276 // Yes, the adjacent face is not a middle face.
16277 bflag = true; break;
16278 }
16279 }
16280 if (!bflag) {
16281 // assert(marktested(toptet)); // SELF_CHECK
16282 if (!facemarked(toptet)) {
16283 fsym(*midface, bottet);
16284 spintet = bottet;
16285 while (1) {
16286 esymself(bottet);
16287 pd = apex(bottet);
16288 if (pd == pc) break; // Face matched.
16289 fsymself(bottet);
16290 if (bottet.tet == spintet.tet) {
16291 // Not found a matched bottom face.
16292 mflag = false;
16293 break;
16294 }
16295 } // while (1)
16296 if (mflag) {
16297 if (marktested(bottet)) {
16298 // Connect two tets together.
16299 bond(toptet, bottet);
16300 // Both are interior tets.
16301 infect(toptet);
16302 infect(bottet);
16303 // Add this face into list.
16304 markface(toptet);
16305 midfaces->newindex((void **) &parytet);
16306 *parytet = toptet;
16307 }
16308 } else { // mflag == false
16309 // Adjust 'toptet' and 'bottet' to be the crossing edges.
16310 fsym(*midface, bottet);
16311 spintet = bottet;
16312 while (1) {
16313 esymself(bottet);
16314 pd = apex(bottet);
16315 if (pmarktested(pd)) {
16316 // assert(pd != pc);
16317 // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
16318 // Adjust 'toptet' and 'bottet' to be the crossing edges.
16319 // Test orient3d(b,c,#,d).
16320 ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
16321 if (ori < 0) {
16322 // Edges [a,d] and [b,c] cross each other.
16323 enextself(toptet); // [b,c]
16324 enextself(bottet); // [a,d]
16325 } else if (ori > 0) {
16326 // Edges [a,c] and [b,d] cross each other.
16327 eprevself(toptet); // [c,a]
16328 eprevself(bottet); // [d,b]
16329 } else {
16330 // b,c,#,and d are coplanar!.
16331 assert(0);
16332 }
16333 break; // Not matched
16334 }
16335 fsymself(bottet);
16336 assert (bottet.tet != spintet.tet);
16337 }
16338 } // if (!mflag)
16339 } // if (!facemarked(toptet))
16340 } // if (!bflag)
16341 enextself(*midface);
16342 } // j
16343 } // i
16344
16345 if (mflag) {
16346 if (b->verbose > 2) {
16347 printf(" Found %ld middle subfaces.\n", midfaces->objects);
16348 }
16349 face oldsh, newsh, casout, casin, neighsh;
16350
16351 oldsh = * (face *) fastlookup(missingshs, 0);
16352
16353 // Create new subfaces to fill the region R.
16354 for (i = 0; i < midfaces->objects; i++) {
16355 // Get a matched middle face [a, b, c]
16356 midface = (triface *) fastlookup(midfaces, i);
16357 unmarkface(*midface);
16358 makeshellface(subfaces, &newsh);
16359 setsorg(newsh, org(*midface));
16360 setsdest(newsh, dest(*midface));
16361 setsapex(newsh, apex(*midface));
16362 // The new subface gets its markers from the old one.
16363 setshellmark(newsh, shellmark(oldsh));
16364 if (checkconstraints) {
16365 setareabound(newsh, areabound(oldsh));
16366 }
16367 // Connect the new subface to adjacent tets.
16368 tsbond(*midface, newsh);
16369 fsym(*midface, neightet);
16370 sesymself(newsh);
16371 tsbond(neightet, newsh);
16372 }
16373
16374 // Connect new subfaces together and to the bdry of R.
16375 // Delete faked segments.
16376 for (i = 0; i < midfaces->objects; i++) {
16377 // Get a matched middle face [a, b, c]
16378 midface = (triface *) fastlookup(midfaces, i);
16379 for (j = 0; j < 3; j++) {
16380 tspivot(*midface, newsh);
16381 spivot(newsh, casout);
16382 if (casout.sh == NULL) {
16383 // Search its neighbor.
16384 fnext(*midface, searchtet);
16385 while (1) {
16386 // (1) First check if this side is a bdry edge of R.
16387 tsspivot1(searchtet, checkseg);
16388 if (checkseg.sh != NULL) {
16389 // It's a bdry edge of R.
16390 assert(!infected(searchtet)); // It must not be a cavity tet.
16391 // Get the old subface.
16392 checkseg.shver = 0;
16393 spivot(checkseg, oldsh);
16394 if (sinfected(checkseg)) {
16395 // It's a faked segment. Delete it.
16396 spintet = searchtet;
16397 while (1) {
16398 tssdissolve1(spintet);
16399 fnextself(spintet);
16400 if (spintet.tet == searchtet.tet) break;
16401 }
16402 shellfacedealloc(subsegs, checkseg.sh);
16403 ssdissolve(oldsh);
16404 checkseg.sh = NULL;
16405 }
16406 spivot(oldsh, casout);
16407 if (casout.sh != NULL) {
16408 casin = casout;
16409 if (checkseg.sh != NULL) {
16410 // Make sure that the subface has the right ori at the
16411 // segment.
16412 checkseg.shver = 0;
16413 if (sorg(newsh) != sorg(checkseg)) {
16414 sesymself(newsh);
16415 }
16416 spivot(casin, neighsh);
16417 while (neighsh.sh != oldsh.sh) {
16418 casin = neighsh;
16419 spivot(casin, neighsh);
16420 }
16421 }
16422 sbond1(newsh, casout);
16423 sbond1(casin, newsh);
16424 }
16425 if (checkseg.sh != NULL) {
16426 ssbond(newsh, checkseg);
16427 }
16428 break;
16429 } // if (checkseg.sh != NULL)
16430 // (2) Second check if this side is an interior edge of R.
16431 tspivot(searchtet, neighsh);
16432 if (neighsh.sh != NULL) {
16433 // Found an adjacent subface of newsh (an interior edge).
16434 sbond(newsh, neighsh);
16435 break;
16436 }
16437 fnextself(searchtet);
16438 assert(searchtet.tet != midface->tet);
16439 } // while (1)
16440 } // if (casout.sh == NULL)
16441 enextself(*midface);
16442 } // j
16443 } // i
16444
16445 // Delete old subfaces.
16446 for (i = 0; i < missingshs->objects; i++) {
16447 parysh = (face *) fastlookup(missingshs, i);
16448 shellfacedealloc(subfaces, parysh->sh);
16449 }
16450 } else {
16451 if (toptet.tet != NULL) {
16452 // Faces at top and bottom are not matched.
16453 // Choose a Steiner point in R.
16454 // Split one of the crossing edges.
16455 pa = org(toptet);
16456 pb = dest(toptet);
16457 pc = org(bottet);
16458 pd = dest(bottet);
16459 // Search an edge in R which is either [a,b] or [c,d].
16460 // Reminder: Subfaces in this list 'missingshs', except the first
16461 // one, represents an interior edge of R.
16462 for (i = 1; i < missingshs->objects; i++) {
16463 parysh = (face *) fastlookup(missingshs, i);
16464 if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
16465 ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
16466 if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
16467 ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
16468 }
16469 if (i < missingshs->objects) {
16470 // Found. Return it.
16471 recentsh = *parysh;
16472 } else {
16473 assert(0);
16474 }
16475 }
16476 }
16477
16478 midfaces->restart();
16479 } else {
16480 mflag = true;
16481 }
16482
16483 // Delete the temp subfaces.
16484 for (j = 0; j < 2; j++) {
16485 cavshells = (j == 0 ? topshells : botshells);
16486 if (cavshells != NULL) {
16487 for (i = 0; i < cavshells->objects; i++) {
16488 parysh = (face *) fastlookup(cavshells, i);
16489 shellfacedealloc(subfaces, parysh->sh);
16490 }
16491 }
16492 }
16493
16494 topshells->restart();
16495 if (botshells != NULL) {
16496 botshells->restart();
16497 }
16498
16499 return mflag;
16500}
16501
16502///////////////////////////////////////////////////////////////////////////////
16503// //
16504// carvecavity() Delete old tets and outer new tets of the cavity. //
16505// //
16506///////////////////////////////////////////////////////////////////////////////
16507
16508void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
16509 arraypool *botnewtets)
16510{
16511 arraypool *newtets;
16512 shellface *sptr, *ssptr;
16513 triface *parytet, *pnewtet, newtet, neightet, spintet;
16514 face checksh, *parysh;
16515 face checkseg, *paryseg;
16516 int t1ver;
16517 int i, j;
16518
16519 if (b->verbose > 2) {
16520 printf(" Carve cavity: %ld old tets.\n", crosstets->objects);
16521 }
16522
16523 // First process subfaces and segments which are adjacent to the cavity.
16524 // They must be re-connected to new tets in the cavity.
16525 // Comment: It is possible that some subfaces and segments are completely
16526 // inside the cavity. This can happen even if the cavity is not enlarged.
16527 // Before deleting the old tets, find and queue all interior subfaces
16528 // and segments. They will be recovered later. 2010-05-06.
16529
16530 // Collect all subfaces and segments which attached to the old tets.
16531 for (i = 0; i < crosstets->objects; i++) {
16532 parytet = (triface *) fastlookup(crosstets, i);
16533 if ((sptr = (shellface*) parytet->tet[9]) != NULL) {
16534 for (j = 0; j < 4; j++) {
16535 if (sptr[j]) {
16536 sdecode(sptr[j], checksh);
16537 if (!sinfected(checksh)) {
16538 sinfect(checksh);
16539 cavetetshlist->newindex((void **) &parysh);
16540 *parysh = checksh;
16541 }
16542 }
16543 } // j
16544 }
16545 if ((ssptr = (shellface*) parytet->tet[8]) != NULL) {
16546 for (j = 0; j < 6; j++) {
16547 if (ssptr[j]) {
16548 sdecode(ssptr[j], checkseg);
16549 // Skip a deleted segment (was a faked segment)
16550 if (checkseg.sh[3] != NULL) {
16551 if (!sinfected(checkseg)) {
16552 sinfect(checkseg);
16553 cavetetseglist->newindex((void **) &paryseg);
16554 *paryseg = checkseg;
16555 }
16556 }
16557 }
16558 } // j
16559 }
16560 } // i
16561
16562 // Uninfect collected subfaces.
16563 for (i = 0; i < cavetetshlist->objects; i++) {
16564 parysh = (face *) fastlookup(cavetetshlist, i);
16565 suninfect(*parysh);
16566 }
16567 // Uninfect collected segments.
16568 for (i = 0; i < cavetetseglist->objects; i++) {
16569 paryseg = (face *) fastlookup(cavetetseglist, i);
16570 suninfect(*paryseg);
16571 }
16572
16573 // Connect subfaces to new tets.
16574 for (i = 0; i < cavetetshlist->objects; i++) {
16575 parysh = (face *) fastlookup(cavetetshlist, i);
16576 // Get an adjacent tet at this subface.
16577 stpivot(*parysh, neightet);
16578 // Does this tet lie inside the cavity.
16579 if (infected(neightet)) {
16580 // Yes. Get the other adjacent tet at this subface.
16581 sesymself(*parysh);
16582 stpivot(*parysh, neightet);
16583 // Does this tet lie inside the cavity.
16584 if (infected(neightet)) {
16585 checksh = *parysh;
16586 stdissolve(checksh);
16587 caveencshlist->newindex((void **) &parysh);
16588 *parysh = checksh;
16589 }
16590 }
16591 if (!infected(neightet)) {
16592 // Found an outside tet. Re-connect this subface to a new tet.
16593 fsym(neightet, newtet);
16594 assert(marktested(newtet)); // It's a new tet.
16595 sesymself(*parysh);
16596 tsbond(newtet, *parysh);
16597 }
16598 } // i
16599
16600
16601 for (i = 0; i < cavetetseglist->objects; i++) {
16602 checkseg = * (face *) fastlookup(cavetetseglist, i);
16603 // Check if the segment is inside the cavity.
16604 sstpivot1(checkseg, neightet);
16605 spintet = neightet;
16606 while (1) {
16607 if (!infected(spintet)) {
16608 // This segment is on the boundary of the cavity.
16609 break;
16610 }
16611 fnextself(spintet);
16612 if (spintet.tet == neightet.tet) {
16613 sstdissolve1(checkseg);
16614 caveencseglist->newindex((void **) &paryseg);
16615 *paryseg = checkseg;
16616 break;
16617 }
16618 }
16619 if (!infected(spintet)) {
16620 // A boundary segment. Connect this segment to the new tets.
16621 sstbond1(checkseg, spintet);
16622 neightet = spintet;
16623 while (1) {
16624 tssbond1(spintet, checkseg);
16625 fnextself(spintet);
16626 if (spintet.tet == neightet.tet) break;
16627 }
16628 }
16629 } // i
16630
16631
16632 cavetetshlist->restart();
16633 cavetetseglist->restart();
16634
16635 // Delete the old tets in cavity.
16636 for (i = 0; i < crosstets->objects; i++) {
16637 parytet = (triface *) fastlookup(crosstets, i);
16638 if (ishulltet(*parytet)) {
16639 hullsize--;
16640 }
16641 tetrahedrondealloc(parytet->tet);
16642 }
16643
16644 crosstets->restart(); // crosstets will be re-used.
16645
16646 // Collect new tets in cavity. Some new tets have already been found
16647 // (and infected) in the fillcavity(). We first collect them.
16648 for (j = 0; j < 2; j++) {
16649 newtets = (j == 0 ? topnewtets : botnewtets);
16650 if (newtets != NULL) {
16651 for (i = 0; i < newtets->objects; i++) {
16652 parytet = (triface *) fastlookup(newtets, i);
16653 if (infected(*parytet)) {
16654 crosstets->newindex((void **) &pnewtet);
16655 *pnewtet = *parytet;
16656 }
16657 } // i
16658 }
16659 } // j
16660
16661 // Now we collect all new tets in cavity.
16662 for (i = 0; i < crosstets->objects; i++) {
16663 parytet = (triface *) fastlookup(crosstets, i);
16664 for (j = 0; j < 4; j++) {
16665 decode(parytet->tet[j], neightet);
16666 if (marktested(neightet)) { // Is it a new tet?
16667 if (!infected(neightet)) {
16668 // Find an interior tet.
16669 //assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
16670 infect(neightet);
16671 crosstets->newindex((void **) &pnewtet);
16672 *pnewtet = neightet;
16673 }
16674 }
16675 } // j
16676 } // i
16677
16678 parytet = (triface *) fastlookup(crosstets, 0);
16679 recenttet = *parytet; // Remember a live handle.
16680
16681 // Delete outer new tets.
16682 for (j = 0; j < 2; j++) {
16683 newtets = (j == 0 ? topnewtets : botnewtets);
16684 if (newtets != NULL) {
16685 for (i = 0; i < newtets->objects; i++) {
16686 parytet = (triface *) fastlookup(newtets, i);
16687 if (infected(*parytet)) {
16688 // This is an interior tet.
16689 uninfect(*parytet);
16690 unmarktest(*parytet);
16691 if (ishulltet(*parytet)) {
16692 hullsize++;
16693 }
16694 } else {
16695 // An outer tet. Delete it.
16696 tetrahedrondealloc(parytet->tet);
16697 }
16698 }
16699 }
16700 }
16701
16702 crosstets->restart();
16703 topnewtets->restart();
16704 if (botnewtets != NULL) {
16705 botnewtets->restart();
16706 }
16707}
16708
16709///////////////////////////////////////////////////////////////////////////////
16710// //
16711// restorecavity() Reconnect old tets and delete new tets of the cavity. //
16712// //
16713///////////////////////////////////////////////////////////////////////////////
16714
16715void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
16716 arraypool *botnewtets, arraypool *missingshbds)
16717{
16718 triface *parytet, neightet, spintet;
16719 face *parysh;
16720 face checkseg;
16721 point *ppt;
16722 int t1ver;
16723 int i, j;
16724
16725 // Reconnect crossing tets to cavity boundary.
16726 for (i = 0; i < crosstets->objects; i++) {
16727 parytet = (triface *) fastlookup(crosstets, i);
16728 assert(infected(*parytet)); // SELF_CHECK
16729 parytet->ver = 0;
16730 for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
16731 fsym(*parytet, neightet);
16732 if (!infected(neightet)) {
16733 // Restore the old connections of tets.
16734 bond(*parytet, neightet);
16735 }
16736 }
16737 // Update the point-to-tet map.
16738 parytet->ver = 0;
16739 ppt = (point *) &(parytet->tet[4]);
16740 for (j = 0; j < 4; j++) {
16741 setpoint2tet(ppt[j], encode(*parytet));
16742 }
16743 }
16744
16745 // Uninfect all crossing tets.
16746 for (i = 0; i < crosstets->objects; i++) {
16747 parytet = (triface *) fastlookup(crosstets, i);
16748 uninfect(*parytet);
16749 }
16750
16751 // Remember a live handle.
16752 recenttet = * (triface *) fastlookup(crosstets, 0);
16753
16754 // Delete faked segments.
16755 for (i = 0; i < missingshbds->objects; i++) {
16756 parysh = (face *) fastlookup(missingshbds, i);
16757 sspivot(*parysh, checkseg);
16758 assert(checkseg.sh != NULL);
16759 if (checkseg.sh[3] != NULL) {
16760 if (sinfected(checkseg)) {
16761 // It's a faked segment. Delete it.
16762 sstpivot1(checkseg, neightet);
16763 spintet = neightet;
16764 while (1) {
16765 tssdissolve1(spintet);
16766 fnextself(spintet);
16767 if (spintet.tet == neightet.tet) break;
16768 }
16769 shellfacedealloc(subsegs, checkseg.sh);
16770 ssdissolve(*parysh);
16771 //checkseg.sh = NULL;
16772 }
16773 }
16774 } // i
16775
16776 // Delete new tets.
16777 for (i = 0; i < topnewtets->objects; i++) {
16778 parytet = (triface *) fastlookup(topnewtets, i);
16779 tetrahedrondealloc(parytet->tet);
16780 }
16781
16782 if (botnewtets != NULL) {
16783 for (i = 0; i < botnewtets->objects; i++) {
16784 parytet = (triface *) fastlookup(botnewtets, i);
16785 tetrahedrondealloc(parytet->tet);
16786 }
16787 }
16788
16789 crosstets->restart();
16790 topnewtets->restart();
16791 if (botnewtets != NULL) {
16792 botnewtets->restart();
16793 }
16794}
16795
16796///////////////////////////////////////////////////////////////////////////////
16797// //
16798// flipcertify() Insert a crossing face into priority queue. //
16799// //
16800// A crossing face of a facet must have at least one top and one bottom ver- //
16801// tex of the facet. //
16802// //
16803///////////////////////////////////////////////////////////////////////////////
16804
16805void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
16806 point plane_pb, point plane_pc)
16807{
16808 badface *parybf, *prevbf, *nextbf;
16809 triface neightet;
16810 face checksh;
16811 point p[5];
16812 REAL w[5];
16813 REAL insph, ori4;
16814 int topi, boti;
16815 int i;
16816
16817 // Compute the flip time \tau.
16818 fsym(*chkface, neightet);
16819
16820 p[0] = org(*chkface);
16821 p[1] = dest(*chkface);
16822 p[2] = apex(*chkface);
16823 p[3] = oppo(*chkface);
16824 p[4] = oppo(neightet);
16825
16826 // Check if the face is a crossing face.
16827 topi = boti = 0;
16828 for (i = 0; i < 3; i++) {
16829 if (pmarktest2ed(p[i])) topi++;
16830 if (pmarktest3ed(p[i])) boti++;
16831 }
16832 if ((topi == 0) || (boti == 0)) {
16833 // It is not a crossing face.
16834 // return;
16835 for (i = 3; i < 5; i++) {
16836 if (pmarktest2ed(p[i])) topi++;
16837 if (pmarktest3ed(p[i])) boti++;
16838 }
16839 if ((topi == 0) || (boti == 0)) {
16840 // The two tets sharing at this face are on one side of the facet.
16841 // Check if this face is locally Delaunay (due to rounding error).
16842 if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
16843 // Do not check it if it is a subface.
16844 tspivot(*chkface, checksh);
16845 if (checksh.sh == NULL) {
16846 insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
16847 assert(insph != 0);
16848 if (insph > 0) {
16849 // Add the face into queue.
16850 if (b->verbose > 2) {
16851 printf(" A locally non-Delanay face (%d, %d, %d)-%d,%d\n",
16852 pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
16853 pointmark(p[3]), pointmark(p[4]));
16854 }
16855 parybf = (badface *) flippool->alloc();
16856 parybf->key = 0.; // tau = 0, do immediately.
16857 parybf->tt = *chkface;
16858 parybf->forg = p[0];
16859 parybf->fdest = p[1];
16860 parybf->fapex = p[2];
16861 parybf->foppo = p[3];
16862 parybf->noppo = p[4];
16863 // Add it at the top of the priority queue.
16864 if (*pqueue == NULL) {
16865 *pqueue = parybf;
16866 parybf->nextitem = NULL;
16867 } else {
16868 parybf->nextitem = *pqueue;
16869 *pqueue = parybf;
16870 }
16871 } // if (insph > 0)
16872 } // if (checksh.sh == NULL)
16873 }
16874 //return;
16875 }
16876 return; // Test: omit this face.
16877 }
16878
16879 // Decide the "height" for each point.
16880 for (i = 0; i < 5; i++) {
16881 if (pmarktest2ed(p[i])) {
16882 // A top point has a positive weight.
16883 w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);
16884 if (w[i] < 0) w[i] = -w[i];
16885 assert(w[i] != 0);
16886 } else {
16887 w[i] = 0;
16888 }
16889 }
16890
16891 // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
16892 // Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
16893 // p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
16894 // The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
16895 // p[4] lies below the oriented hyperplane passing through
16896 // p[1], p[0], p[2], p[3].
16897
16898 insph = insphere(p[1], p[0], p[2], p[3], p[4]);
16899 ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
16900
16901 if (b->verbose > 2) {
16902 printf(" Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]);
16903 printf(" Insph: %g, ori4: %g, tau = %g\n", insph, ori4, -insph/ori4);
16904 }
16905
16906 if (ori4 > 0) {
16907 // Add the face into queue.
16908 if (b->verbose > 2) {
16909 printf(" Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
16910 pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
16911 }
16912
16913 parybf = (badface *) flippool->alloc();
16914
16915 parybf->key = -insph / ori4;
16916 parybf->tt = *chkface;
16917 parybf->forg = p[0];
16918 parybf->fdest = p[1];
16919 parybf->fapex = p[2];
16920 parybf->foppo = p[3];
16921 parybf->noppo = p[4];
16922
16923 // Push the face into priority queue.
16924 //pq.push(bface);
16925 if (*pqueue == NULL) {
16926 *pqueue = parybf;
16927 parybf->nextitem = NULL;
16928 } else {
16929 // Search an item whose key is larger or equal to current key.
16930 prevbf = NULL;
16931 nextbf = *pqueue;
16932 //if (!b->flipinsert_random) { // Default use a priority queue.
16933 // Insert the item into priority queue.
16934 while (nextbf != NULL) {
16935 if (nextbf->key < parybf->key) {
16936 prevbf = nextbf;
16937 nextbf = nextbf->nextitem;
16938 } else {
16939 break;
16940 }
16941 }
16942 //} // if (!b->flipinsert_random)
16943 // Insert the new item between prev and next items.
16944 if (prevbf == NULL) {
16945 *pqueue = parybf;
16946 } else {
16947 prevbf->nextitem = parybf;
16948 }
16949 parybf->nextitem = nextbf;
16950 }
16951 } else if (ori4 == 0) {
16952
16953 }
16954}
16955
16956///////////////////////////////////////////////////////////////////////////////
16957// //
16958// flipinsertfacet() Insert a facet into a CDT by flips. //
16959// //
16960// The algorithm is described in Shewchuk's paper "Updating and Constructing //
16961// Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
16962// Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003. //
16963// //
16964// 'crosstets' contains the set of crossing tetrahedra (infected) of the //
16965// facet. 'toppoints' and 'botpoints' are points lies above and below the //
16966// facet, not on the facet. //
16967// //
16968///////////////////////////////////////////////////////////////////////////////
16969
16970void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
16971 arraypool *botpoints, arraypool *midpoints)
16972{
16973 arraypool *crossfaces, *bfacearray;
16974 triface fliptets[6], baktets[2], fliptet, newface;
16975 triface neightet, *parytet;
16976 face checksh;
16977 face checkseg;
16978 badface *pqueue;
16979 badface *popbf, bface;
16980 point plane_pa, plane_pb, plane_pc;
16981 point p1, p2, pd, pe;
16982 point *parypt;
16983 flipconstraints fc;
16984 REAL ori[3];
16985 int convcount, copcount;
16986 int flipflag, fcount;
16987 int n, i;
16988 long f23count, f32count, f44count;
16989 long totalfcount;
16990
16991 f23count = flip23count;
16992 f32count = flip32count;
16993 f44count = flip44count;
16994
16995 // Get three affinely independent vertices in the missing region R.
16996 calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
16997
16998 // Mark top and bottom points. Do not mark midpoints.
16999 for (i = 0; i < toppoints->objects; i++) {
17000 parypt = (point *) fastlookup(toppoints, i);
17001 if (!pmarktested(*parypt)) {
17002 pmarktest2(*parypt);
17003 }
17004 }
17005 for (i = 0; i < botpoints->objects; i++) {
17006 parypt = (point *) fastlookup(botpoints, i);
17007 if (!pmarktested(*parypt)) {
17008 pmarktest3(*parypt);
17009 }
17010 }
17011
17012 // Collect crossing faces.
17013 crossfaces = cavetetlist; // Re-use array 'cavetetlist'.
17014
17015 // Each crossing face contains at least one bottom vertex and
17016 // one top vertex.
17017 for (i = 0; i < crosstets->objects; i++) {
17018 parytet = (triface *) fastlookup(crosstets, i);
17019 fliptet = *parytet;
17020 for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
17021 fsym(fliptet, neightet);
17022 if (infected(neightet)) { // It is an interior face.
17023 if (!marktested(neightet)) { // It is an unprocessed face.
17024 crossfaces->newindex((void **) &parytet);
17025 *parytet = fliptet;
17026 }
17027 }
17028 }
17029 marktest(fliptet);
17030 }
17031
17032 if (b->verbose > 1) {
17033 printf(" Found %ld crossing faces.\n", crossfaces->objects);
17034 }
17035
17036 for (i = 0; i < crosstets->objects; i++) {
17037 parytet = (triface *) fastlookup(crosstets, i);
17038 unmarktest(*parytet);
17039 uninfect(*parytet);
17040 }
17041
17042 // Initialize the priority queue.
17043 pqueue = NULL;
17044
17045 for (i = 0; i < crossfaces->objects; i++) {
17046 parytet = (triface *) fastlookup(crossfaces, i);
17047 flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17048 }
17049 crossfaces->restart();
17050
17051 // The list for temporarily storing unflipable faces.
17052 bfacearray = new arraypool(sizeof(triface), 4);
17053
17054
17055 fcount = 0; // Count the number of flips.
17056
17057 // Flip insert the facet.
17058 while (pqueue != NULL) {
17059
17060 // Pop a face from the priority queue.
17061 popbf = pqueue;
17062 bface = *popbf;
17063
17064 // Update the queue.
17065 pqueue = pqueue->nextitem;
17066
17067 // Delete the popped item from the pool.
17068 flippool->dealloc((void *) popbf);
17069
17070 if (!isdeadtet(bface.tt)) {
17071 if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
17072 (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
17073 // It is still a crossing face of R.
17074 fliptet = bface.tt;
17075 fsym(fliptet, neightet);
17076 assert(!isdeadtet(neightet));
17077 if (oppo(neightet) == bface.noppo) {
17078 pd = oppo(fliptet);
17079 pe = oppo(neightet);
17080
17081 if (b->verbose > 2) {
17082 printf(" Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17083 pointmark(bface.forg), pointmark(bface.fdest),
17084 pointmark(bface.fapex), pointmark(bface.foppo),
17085 pointmark(bface.noppo), bface.key);
17086 }
17087 flipflag = 0;
17088
17089 // Check for which type of flip can we do.
17090 convcount = 3;
17091 copcount = 0;
17092 for (i = 0; i < 3; i++) {
17093 p1 = org(fliptet);
17094 p2 = dest(fliptet);
17095 ori[i] = orient3d(p1, p2, pd, pe);
17096 if (ori[i] < 0) {
17097 convcount--;
17098 //break;
17099 } else if (ori[i] == 0) {
17100 convcount--; // Possible 4-to-4 flip.
17101 copcount++;
17102 //break;
17103 }
17104 enextself(fliptet);
17105 }
17106
17107 if (convcount == 3) {
17108 // A 2-to-3 flip is found.
17109 // The face should not be a subface.
17110 tspivot(fliptet, checksh);
17111 assert(checksh.sh == NULL);
17112
17113 fliptets[0] = fliptet; // abcd, d may be the new vertex.
17114 fliptets[1] = neightet; // bace.
17115 flip23(fliptets, 1, &fc);
17116 // Put the link faces into check list.
17117 for (i = 0; i < 3; i++) {
17118 eprevesym(fliptets[i], newface);
17119 crossfaces->newindex((void **) &parytet);
17120 *parytet = newface;
17121 }
17122 for (i = 0; i < 3; i++) {
17123 enextesym(fliptets[i], newface);
17124 crossfaces->newindex((void **) &parytet);
17125 *parytet = newface;
17126 }
17127 flipflag = 1;
17128 } else if (convcount == 2) {
17129 assert(copcount <= 1);
17130 //if (copcount <= 1) {
17131 // A 3-to-2 or 4-to-4 may be possible.
17132 // Get the edge which is locally non-convex or flat.
17133 for (i = 0; i < 3; i++) {
17134 if (ori[i] <= 0) break;
17135 enextself(fliptet);
17136 }
17137 // The edge should not be a segment.
17138 tsspivot1(fliptet, checkseg);
17139 assert(checkseg.sh == NULL);
17140
17141 // Collect tets sharing at this edge.
17142 // NOTE: This operation may collect tets which lie outside the
17143 // cavity, e.g., when the edge lies on the boundary of the
17144 // cavity. Do not flip if there are outside tets at this edge.
17145 // 2012-07-27.
17146 esym(fliptet, fliptets[0]); // [b,a,d,c]
17147 n = 0;
17148 do {
17149 p1 = apex(fliptets[n]);
17150 if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
17151 // This apex is not on the cavity. Hence the face does not
17152 // lie inside the cavity. Do not flip this edge.
17153 n = 1000; break;
17154 }
17155 fnext(fliptets[n], fliptets[n + 1]);
17156 n++;
17157 } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
17158
17159 if (n == 3) {
17160 // Found a 3-to-2 flip.
17161 flip32(fliptets, 1, &fc);
17162 // Put the link faces into check list.
17163 for (i = 0; i < 3; i++) {
17164 esym(fliptets[0], newface);
17165 crossfaces->newindex((void **) &parytet);
17166 *parytet = newface;
17167 enextself(fliptets[0]);
17168 }
17169 for (i = 0; i < 3; i++) {
17170 esym(fliptets[1], newface);
17171 crossfaces->newindex((void **) &parytet);
17172 *parytet = newface;
17173 enextself(fliptets[1]);
17174 }
17175 flipflag = 1;
17176 } else if (n == 4) {
17177 if (copcount == 1) {
17178 // Found a 4-to-4 flip.
17179 // Let the six vertices are: a,b,c,d,e,f, where
17180 // fliptets[0] = [b,a,d,c]
17181 // [1] = [b,a,c,e]
17182 // [2] = [b,a,e,f]
17183 // [3] = [b,a,f,d]
17184 // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
17185 // is created.
17186 // First do a 2-to-3 flip.
17187 // Comment: This flip temporarily creates a degenerated
17188 // tet (whose volume is zero). It will be removed by the
17189 // followed 3-to-2 flip.
17190 fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
17191 // fliptets[1]; // = [b,a,c,e].
17192 baktets[0] = fliptets[2]; // = [b,a,e,f]
17193 baktets[1] = fliptets[3]; // = [b,a,f,d]
17194 // The flip may involve hull tets.
17195 flip23(fliptets, 1, &fc);
17196 // Put the "outer" link faces into check list.
17197 // fliptets[0] = [e,d,a,b] => will be flipped, so
17198 // [a,b,d] and [a,b,e] are not "outer" link faces.
17199 for (i = 1; i < 3; i++) {
17200 eprevesym(fliptets[i], newface);
17201 crossfaces->newindex((void **) &parytet);
17202 *parytet = newface;
17203 }
17204 for (i = 1; i < 3; i++) {
17205 enextesym(fliptets[i], newface);
17206 crossfaces->newindex((void **) &parytet);
17207 *parytet = newface;
17208 }
17209 // Then do a 3-to-2 flip.
17210 enextesymself(fliptets[0]); // fliptets[0] is [e,d,a,b].
17211 eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
17212 fliptets[1] = baktets[0]; // = [b,a,e,f]
17213 fliptets[2] = baktets[1]; // = [b,a,f,d]
17214 flip32(fliptets, 1, &fc);
17215 // Put the "outer" link faces into check list.
17216 // fliptets[0] = [d,e,f,a]
17217 // fliptets[1] = [e,d,f,b]
17218 // Faces [a,b,d] and [a,b,e] are not "outer" link faces.
17219 enextself(fliptets[0]);
17220 for (i = 1; i < 3; i++) {
17221 esym(fliptets[0], newface);
17222 crossfaces->newindex((void **) &parytet);
17223 *parytet = newface;
17224 enextself(fliptets[0]);
17225 }
17226 enextself(fliptets[1]);
17227 for (i = 1; i < 3; i++) {
17228 esym(fliptets[1], newface);
17229 crossfaces->newindex((void **) &parytet);
17230 *parytet = newface;
17231 enextself(fliptets[1]);
17232 }
17233 flip23count--;
17234 flip32count--;
17235 flip44count++;
17236 flipflag = 1;
17237 } else {
17238 //n == 4, convflag != 0; assert(0);
17239 }
17240 } else {
17241 // n > 4 => unflipable. //assert(0);
17242 }
17243 } else {
17244 // There are more than 1 non-convex or coplanar cases.
17245 flipflag = -1; // Ignore this face.
17246 if (b->verbose > 2) {
17247 printf(" Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17248 pointmark(bface.forg), pointmark(bface.fdest),
17249 pointmark(bface.fapex), pointmark(bface.foppo),
17250 pointmark(bface.noppo), bface.key);
17251 }
17252 } // if (convcount == 1)
17253
17254 if (flipflag == 1) {
17255 // Update the priority queue.
17256 for (i = 0; i < crossfaces->objects; i++) {
17257 parytet = (triface *) fastlookup(crossfaces, i);
17258 flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17259 }
17260 crossfaces->restart();
17261 if (1) { // if (!b->flipinsert_random) {
17262 // Insert all queued unflipped faces.
17263 for (i = 0; i < bfacearray->objects; i++) {
17264 parytet = (triface *) fastlookup(bfacearray, i);
17265 // This face may be changed.
17266 if (!isdeadtet(*parytet)) {
17267 flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17268 }
17269 }
17270 bfacearray->restart();
17271 }
17272 fcount++;
17273 } else if (flipflag == 0) {
17274 // Queue an unflippable face. To process it later.
17275 bfacearray->newindex((void **) &parytet);
17276 *parytet = fliptet;
17277 }
17278 } // if (pe == bface.noppo)
17279 } // if ((pa == bface.forg) && ...)
17280 } // if (bface.tt != NULL)
17281
17282 } // while (pqueue != NULL)
17283
17284 if (bfacearray->objects > 0) {
17285 if (fcount == 0) {
17286 printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
17287 assert(0);
17288 }
17289 }
17290
17291 // 'bfacearray' may be not empty (for what reason ??).
17292 //dbg_unflip_facecount += bfacearray->objects;
17293
17294 assert(flippool->items == 0l);
17295 delete bfacearray;
17296
17297 // Un-mark top and bottom points.
17298 for (i = 0; i < toppoints->objects; i++) {
17299 parypt = (point *) fastlookup(toppoints, i);
17300 punmarktest2(*parypt);
17301 }
17302 for (i = 0; i < botpoints->objects; i++) {
17303 parypt = (point *) fastlookup(botpoints, i);
17304 punmarktest3(*parypt);
17305 }
17306
17307 f23count = flip23count - f23count;
17308 f32count = flip32count - f32count;
17309 f44count = flip44count - f44count;
17310 totalfcount = f23count + f32count + f44count;
17311 if (b->verbose > 2) {
17312 printf(" Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
17313 totalfcount, f23count, f32count, f44count);
17314 }
17315}
17316
17317///////////////////////////////////////////////////////////////////////////////
17318// //
17319// fillregion() Fill the missing region by a set of new subfaces. //
17320// //
17321// 'missingshs' contains the list of subfaces in R. Moreover, each subface //
17322// (except the first one) in this list represents an interior edge of R. //
17323// //
17324// Note: We assume that all vertices of R are marktested so we can detect //
17325// new subface by checking the flag in apexes. //
17326// //
17327///////////////////////////////////////////////////////////////////////////////
17328
17329bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds,
17330 arraypool* newshs)
17331{
17332 badface *newflipface, *popface;
17333 triface searchtet, spintet, neightet;
17334 face oldsh, newsh, opensh, *parysh;
17335 face casout, casin, neighsh, checksh;
17336 face neighseg, checkseg;
17337 point pc;
17338 int success;
17339 int t1ver;
17340 int i, j;
17341
17342
17343 // Search the first new subface to fill the region.
17344 for (i = 0; i < missingshbds->objects; i++) {
17345 parysh = (face *) fastlookup(missingshbds, i);
17346 sspivot(*parysh, neighseg);
17347 sstpivot1(neighseg, searchtet);
17348 j = 0; // Count the number of passes of R.
17349 spintet = searchtet;
17350 while (1) {
17351 pc = apex(spintet);
17352 if (pmarktested(pc)) {
17353 neightet = spintet;
17354 j++;
17355 }
17356 fnextself(spintet);
17357 if (spintet.tet == searchtet.tet) break;
17358 }
17359 assert(j >= 1);
17360 if (j == 1) {
17361 // Found an interior new subface.
17362 searchtet = neightet;
17363 oldsh = *parysh;
17364 break;
17365 }
17366 } // i
17367
17368 if (i == missingshbds->objects) {
17369 // Failed to find any interior subface.
17370 // Need Steiner points.
17371 return false;
17372 }
17373
17374 makeshellface(subfaces, &newsh);
17375 setsorg(newsh, org(searchtet));
17376 setsdest(newsh, dest(searchtet));
17377 setsapex(newsh, apex(searchtet));
17378 // The new subface gets its markers from the old one.
17379 setshellmark(newsh, shellmark(oldsh));
17380 if (checkconstraints) {
17381 setareabound(newsh, areabound(oldsh));
17382 }
17383 // Connect the new subface to adjacent tets.
17384 tsbond(searchtet, newsh);
17385 fsymself(searchtet);
17386 sesymself(newsh);
17387 tsbond(searchtet, newsh);
17388 // Connect newsh to outer subfaces.
17389 sspivot(oldsh, checkseg);
17390 if (sinfected(checkseg)) {
17391 // It's a faked segment. Delete it.
17392 spintet = searchtet;
17393 while (1) {
17394 tssdissolve1(spintet);
17395 fnextself(spintet);
17396 if (spintet.tet == searchtet.tet) break;
17397 }
17398 shellfacedealloc(subsegs, checkseg.sh);
17399 ssdissolve(oldsh);
17400 checkseg.sh = NULL;
17401 }
17402 spivot(oldsh, casout);
17403 if (casout.sh != NULL) {
17404 casin = casout;
17405 if (checkseg.sh != NULL) {
17406 // Make sure that the subface has the right ori at the segment.
17407 checkseg.shver = 0;
17408 if (sorg(newsh) != sorg(checkseg)) {
17409 sesymself(newsh);
17410 }
17411 spivot(casin, neighsh);
17412 while (neighsh.sh != oldsh.sh) {
17413 casin = neighsh;
17414 spivot(casin, neighsh);
17415 }
17416 }
17417 sbond1(newsh, casout);
17418 sbond1(casin, newsh);
17419 }
17420 if (checkseg.sh != NULL) {
17421 ssbond(newsh, checkseg);
17422 }
17423 // Add this new subface into list.
17424 sinfect(newsh);
17425 newshs->newindex((void **) &parysh);
17426 *parysh = newsh;
17427
17428 // Push two "open" side of the new subface into stack.
17429 for (i = 0; i < 2; i++) {
17430 senextself(newsh);
17431 newflipface = (badface *) flippool->alloc();
17432 newflipface->ss = newsh;
17433 newflipface->nextitem = flipstack;
17434 flipstack = newflipface;
17435 }
17436
17437 success = 1;
17438
17439 // Loop until 'flipstack' is empty.
17440 while ((flipstack != NULL) && success) {
17441 // Pop an "open" side from the stack.
17442 popface = flipstack;
17443 opensh = popface->ss;
17444 flipstack = popface->nextitem; // The next top item in stack.
17445 flippool->dealloc((void *) popface);
17446
17447 // opensh is either (1) an interior edge or (2) a bdry edge.
17448 stpivot(opensh, searchtet);
17449 tsspivot1(searchtet, checkseg);
17450 if (checkseg.sh == NULL) {
17451 // No segment. It is an interior edge of R.
17452 // Search for a new face in R.
17453 spintet = searchtet;
17454 fnextself(spintet); // Skip the current face.
17455 while (1) {
17456 pc = apex(spintet);
17457 if (pmarktested(pc)) {
17458 // 'opensh' is an interior edge.
17459 if (!issubface(spintet)) {
17460 // Create a new subface.
17461 makeshellface(subfaces, &newsh);
17462 setsorg(newsh, org(spintet));
17463 setsdest(newsh, dest(spintet));
17464 setsapex(newsh, pc);
17465 // The new subface gets its markers from its neighbor.
17466 setshellmark(newsh, shellmark(opensh));
17467 if (checkconstraints) {
17468 setareabound(newsh, areabound(opensh));
17469 }
17470 // Connect the new subface to adjacent tets.
17471 tsbond(spintet, newsh);
17472 fsymself(spintet);
17473 sesymself(newsh);
17474 tsbond(spintet, newsh);
17475 // Connect newsh to its adjacent subface.
17476 sbond(newsh, opensh);
17477 // Add this new subface into list.
17478 sinfect(newsh);
17479 newshs->newindex((void **) &parysh);
17480 *parysh = newsh;
17481 // Push two "open" side of the new subface into stack.
17482 for (i = 0; i < 2; i++) {
17483 senextself(newsh);
17484 newflipface = (badface *) flippool->alloc();
17485 newflipface->ss = newsh;
17486 newflipface->nextitem = flipstack;
17487 flipstack = newflipface;
17488 }
17489 } else {
17490 // Connect to another open edge.
17491 tspivot(spintet, checksh);
17492 sbond(opensh, checksh);
17493 }
17494 break;
17495 } // if (pmarktested(pc))
17496 fnextself(spintet);
17497 if (spintet.tet == searchtet.tet) {
17498 // Not find any face to fill in R at this side.
17499 // Suggest a point to split the edge.
17500 success = 0;
17501 break;
17502 }
17503 } // while (1)
17504 } else {
17505 // This side coincident with a boundary edge of R.
17506 checkseg.shver = 0;
17507 spivot(checkseg, oldsh);
17508 if (sinfected(checkseg)) {
17509 // It's a faked segment. Delete it.
17510 spintet = searchtet;
17511 while (1) {
17512 tssdissolve1(spintet);
17513 fnextself(spintet);
17514 if (spintet.tet == searchtet.tet) break;
17515 }
17516 shellfacedealloc(subsegs, checkseg.sh);
17517 ssdissolve(oldsh);
17518 checkseg.sh = NULL;
17519 }
17520 spivot(oldsh, casout);
17521 if (casout.sh != NULL) {
17522 casin = casout;
17523 if (checkseg.sh != NULL) {
17524 // Make sure that the subface has the right ori at the segment.
17525 checkseg.shver = 0;
17526 if (sorg(opensh) != sorg(checkseg)) {
17527 sesymself(opensh);
17528 }
17529 spivot(casin, neighsh);
17530 while (neighsh.sh != oldsh.sh) {
17531 casin = neighsh;
17532 spivot(casin, neighsh);
17533 }
17534 }
17535 sbond1(opensh, casout);
17536 sbond1(casin, opensh);
17537 }
17538 if (checkseg.sh != NULL) {
17539 ssbond(opensh, checkseg);
17540 }
17541 } // if (checkseg.sh != NULL)
17542 } // while ((flipstack != NULL) && success)
17543
17544 if (success) {
17545 // Uninfect all new subfaces.
17546 for (i = 0; i < newshs->objects; i++) {
17547 parysh = (face *) fastlookup(newshs, i);
17548 suninfect(*parysh);
17549 }
17550 // Delete old subfaces.
17551 for (i = 0; i < missingshs->objects; i++) {
17552 parysh = (face *) fastlookup(missingshs, i);
17553 shellfacedealloc(subfaces, parysh->sh);
17554 }
17555 fillregioncount++;
17556 } else {
17557 // Failed to fill the region.
17558 // Re-connect old subfaces at boundaries of R.
17559 // Also delete fake segments.
17560 for (i = 0; i < missingshbds->objects; i++) {
17561 parysh = (face *) fastlookup(missingshbds, i);
17562 // It still connect to 'casout'.
17563 // Re-connect 'casin' to it.
17564 spivot(*parysh, casout);
17565 casin = casout;
17566 spivot(casin, neighsh);
17567 while (1) {
17568 if (sinfected(neighsh)) break;
17569 if (neighsh.sh == parysh->sh) break;
17570 casin = neighsh;
17571 spivot(casin, neighsh);
17572 }
17573 if (sinfected(neighsh)) {
17574 sbond1(casin, *parysh);
17575 }
17576 sspivot(*parysh, checkseg);
17577 if (checkseg.sh != NULL) {
17578 if (checkseg.sh[3] != NULL) {
17579 if (sinfected(checkseg)) {
17580 sstpivot1(checkseg, searchtet);
17581 spintet = searchtet;
17582 while (1) {
17583 tssdissolve1(spintet);
17584 fnextself(spintet);
17585 if (spintet.tet == searchtet.tet) break;
17586 }
17587 ssdissolve(*parysh);
17588 shellfacedealloc(subsegs, checkseg.sh);
17589 }
17590 }
17591 }
17592 }
17593 // Delete all new subfaces.
17594 for (i = 0; i < newshs->objects; i++) {
17595 parysh = (face *) fastlookup(newshs, i);
17596 shellfacedealloc(subfaces, parysh->sh);
17597 }
17598 // Clear the flip pool.
17599 flippool->restart();
17600 flipstack = NULL;
17601
17602 // Choose an interior edge of R to split.
17603 assert(missingshs->objects > 1);
17604 // Skip the first subface in 'missingshs'.
17605 i = randomnation(missingshs->objects - 1) + 1;
17606 parysh = (face *) fastlookup(missingshs, i);
17607 recentsh = *parysh;
17608 }
17609
17610 newshs->restart();
17611
17612 return success > 0 ? true : false;
17613}
17614
17615///////////////////////////////////////////////////////////////////////////////
17616// //
17617// insertpoint_cdt() Insert a new point into a CDT. //
17618// //
17619///////////////////////////////////////////////////////////////////////////////
17620
17621int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh,
17622 face *splitseg, insertvertexflags *ivf,
17623 arraypool *cavpoints, arraypool *cavfaces,
17624 arraypool *cavshells, arraypool *newtets,
17625 arraypool *crosstets, arraypool *misfaces)
17626{
17627 triface neightet, *parytet;
17628 face checksh, *parysh, *parysh1;
17629 face *paryseg, *paryseg1;
17630 point *parypt;
17631 int t1ver;
17632 int i;
17633
17634 if (b->verbose > 2) {
17635 printf(" Insert point %d into CDT\n", pointmark(newpt));
17636 }
17637
17638 if (!insertpoint(newpt, searchtet, NULL, NULL, ivf)) {
17639 // Point is not inserted. Check ivf->iloc for reason.
17640 return 0;
17641 }
17642
17643
17644 for (i = 0; i < cavetetvertlist->objects; i++) {
17645 cavpoints->newindex((void **) &parypt);
17646 *parypt = * (point *) fastlookup(cavetetvertlist, i);
17647 }
17648 // Add the new point into the point list.
17649 cavpoints->newindex((void **) &parypt);
17650 *parypt = newpt;
17651
17652 for (i = 0; i < cavebdrylist->objects; i++) {
17653 cavfaces->newindex((void **) &parytet);
17654 *parytet = * (triface *) fastlookup(cavebdrylist, i);
17655 }
17656
17657 for (i = 0; i < caveoldtetlist->objects; i++) {
17658 crosstets->newindex((void **) &parytet);
17659 *parytet = * (triface *) fastlookup(caveoldtetlist, i);
17660 }
17661
17662 cavetetvertlist->restart();
17663 cavebdrylist->restart();
17664 caveoldtetlist->restart();
17665
17666 // Insert the point using the cavity algorithm.
17667 delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets,
17668 misfaces);
17669 fillcavity(cavshells, NULL, NULL, NULL, NULL, NULL, NULL);
17670 carvecavity(crosstets, newtets, NULL);
17671
17672 if ((splitsh != NULL) || (splitseg != NULL)) {
17673 // Insert the point into the surface mesh.
17674 sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
17675
17676 // Put all new subfaces into stack.
17677 for (i = 0; i < caveshbdlist->objects; i++) {
17678 // Get an old subface at edge [a, b].
17679 parysh = (face *) fastlookup(caveshbdlist, i);
17680 spivot(*parysh, checksh); // The new subface [a, b, p].
17681 // Do not recover a deleted new face (degenerated).
17682 if (checksh.sh[3] != NULL) {
17683 subfacstack->newindex((void **) &parysh);
17684 *parysh = checksh;
17685 }
17686 }
17687
17688 if (splitseg != NULL) {
17689 // Queue two new subsegments in C(p) for recovery.
17690 for (i = 0; i < cavesegshlist->objects; i++) {
17691 paryseg = (face *) fastlookup(cavesegshlist, i);
17692 subsegstack->newindex((void **) &paryseg1);
17693 *paryseg1 = *paryseg;
17694 }
17695 } // if (splitseg != NULL)
17696
17697 // Delete the old subfaces in sC(p).
17698 for (i = 0; i < caveshlist->objects; i++) {
17699 parysh = (face *) fastlookup(caveshlist, i);
17700 if (checksubfaceflag) {
17701 // It is possible that this subface still connects to adjacent
17702 // tets which are not in C(p). If so, clear connections in the
17703 // adjacent tets at this subface.
17704 stpivot(*parysh, neightet);
17705 if (neightet.tet != NULL) {
17706 if (neightet.tet[4] != NULL) {
17707 // Found an adjacent tet. It must be not in C(p).
17708 assert(!infected(neightet));
17709 tsdissolve(neightet);
17710 fsymself(neightet);
17711 assert(!infected(neightet));
17712 tsdissolve(neightet);
17713 }
17714 }
17715 }
17716 shellfacedealloc(subfaces, parysh->sh);
17717 }
17718 if (splitseg != NULL) {
17719 // Delete the old segment in sC(p).
17720 shellfacedealloc(subsegs, splitseg->sh);
17721 }
17722
17723 // Clear working lists.
17724 caveshlist->restart();
17725 caveshbdlist->restart();
17726 cavesegshlist->restart();
17727 } // if ((splitsh != NULL) || (splitseg != NULL))
17728
17729 // Put all interior subfaces into stack for recovery.
17730 // They were collected in carvecavity().
17731 // Note: Some collected subfaces may be deleted by sinsertvertex().
17732 for (i = 0; i < caveencshlist->objects; i++) {
17733 parysh = (face *) fastlookup(caveencshlist, i);
17734 if (parysh->sh[3] != NULL) {
17735 subfacstack->newindex((void **) &parysh1);
17736 *parysh1 = *parysh;
17737 }
17738 }
17739
17740 // Put all interior segments into stack for recovery.
17741 // They were collected in carvecavity().
17742 // Note: Some collected segments may be deleted by sinsertvertex().
17743 for (i = 0; i < caveencseglist->objects; i++) {
17744 paryseg = (face *) fastlookup(caveencseglist, i);
17745 if (paryseg->sh[3] != NULL) {
17746 subsegstack->newindex((void **) &paryseg1);
17747 *paryseg1 = *paryseg;
17748 }
17749 }
17750
17751 caveencshlist->restart();
17752 caveencseglist->restart();
17753
17754 return 1;
17755}
17756
17757///////////////////////////////////////////////////////////////////////////////
17758// //
17759// refineregion() Refine a missing region by inserting points. //
17760// //
17761// 'splitsh' represents an edge of the facet to be split. It must be not a //
17762// segment.
17763// //
17764// Assumption: The current mesh is a CDT and is convex. //
17765// //
17766///////////////////////////////////////////////////////////////////////////////
17767
17768void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints,
17769 arraypool *cavfaces, arraypool *cavshells,
17770 arraypool *newtets, arraypool *crosstets,
17771 arraypool *misfaces)
17772{
17773 triface searchtet, spintet;
17774 face splitseg, *paryseg;
17775 point steinpt, pa, pb, refpt;
17776 insertvertexflags ivf;
17777 enum interresult dir;
17778 long baknum = points->items;
17779 int t1ver;
17780 int i;
17781
17782 if (b->verbose > 2) {
17783 printf(" Refining region at edge (%d, %d, %d).\n",
17784 pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
17785 pointmark(sapex(splitsh)));
17786 }
17787
17788 // Add the Steiner point at the barycenter of the face.
17789 pa = sorg(splitsh);
17790 pb = sdest(splitsh);
17791 // Create a new point.
17792 makepoint(&steinpt, FREEFACETVERTEX);
17793 for (i = 0; i < 3; i++) {
17794 steinpt[i] = 0.5 * (pa[i] + pb[i]);
17795 }
17796
17797 ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
17798 ivf.cdtflag = 1; // Only create the initial cavity.
17799 ivf.sloc = (int) ONEDGE;
17800 ivf.sbowywat = 1;
17801 ivf.assignmeshsize = b->metric;
17802
17803 point2tetorg(pa, searchtet); // Start location from it.
17804 ivf.iloc = (int) OUTSIDE;
17805
17806 ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
17807 if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, NULL, &ivf, cavpoints,
17808 cavfaces, cavshells, newtets, crosstets, misfaces)) {
17809 if (ivf.iloc == (int) ENCSEGMENT) {
17810 pointdealloc(steinpt);
17811 // Split an encroached segment.
17812 assert(encseglist->objects > 0);
17813 i = randomnation(encseglist->objects);
17814 paryseg = (face *) fastlookup(encseglist, i);
17815 splitseg = *paryseg;
17816 encseglist->restart();
17817
17818 // Split the segment.
17819 pa = sorg(splitseg);
17820 pb = sdest(splitseg);
17821 // Create a new point.
17822 makepoint(&steinpt, FREESEGVERTEX);
17823 for (i = 0; i < 3; i++) {
17824 steinpt[i] = 0.5 * (pa[i] + pb[i]);
17825 }
17826 point2tetorg(pa, searchtet);
17827 ivf.iloc = (int) OUTSIDE;
17828 ivf.rejflag = 0;
17829 if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
17830 cavpoints, cavfaces, cavshells, newtets,
17831 crosstets, misfaces)) {
17832 assert(0);
17833 }
17834 st_segref_count++;
17835 if (steinerleft > 0) steinerleft--;
17836 } else {
17837 assert(0);
17838 }
17839 } else {
17840 st_facref_count++;
17841 if (steinerleft > 0) steinerleft--;
17842 }
17843
17844 while (subsegstack->objects > 0l) {
17845 // seglist is used as a stack.
17846 subsegstack->objects--;
17847 paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
17848 splitseg = *paryseg;
17849
17850 // Check if this segment has been recovered.
17851 sstpivot1(splitseg, searchtet);
17852 if (searchtet.tet != NULL) continue;
17853
17854 // Search the segment.
17855 dir = scoutsegment(sorg(splitseg), sdest(splitseg), &searchtet, &refpt,
17856 NULL);
17857 if (dir == SHAREEDGE) {
17858 // Found this segment, insert it.
17859 if (!issubseg(searchtet)) {
17860 // Let the segment remember an adjacent tet.
17861 sstbond1(splitseg, searchtet);
17862 // Bond the segment to all tets containing it.
17863 spintet = searchtet;
17864 do {
17865 tssbond1(spintet, splitseg);
17866 fnextself(spintet);
17867 } while (spintet.tet != searchtet.tet);
17868 } else {
17869 // Collision! Should not happen.
17870 assert(0);
17871 }
17872 } else {
17873 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
17874 // Split the segment.
17875 // Create a new point.
17876 makepoint(&steinpt, FREESEGVERTEX);
17877 //setpointtype(newpt, FREESEGVERTEX);
17878 getsteinerptonsegment(&splitseg, refpt, steinpt);
17879 ivf.iloc = (int) OUTSIDE;
17880 ivf.rejflag = 0;
17881 if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
17882 cavpoints, cavfaces, cavshells, newtets,
17883 crosstets, misfaces)) {
17884 assert(0);
17885 }
17886 st_segref_count++;
17887 if (steinerleft > 0) steinerleft--;
17888 } else {
17889 // Maybe a PLC problem.
17890 assert(0);
17891 }
17892 }
17893 } // while
17894
17895 if (b->verbose > 2) {
17896 printf(" Added %ld Steiner points.\n", points->items - baknum);
17897 }
17898}
17899
17900///////////////////////////////////////////////////////////////////////////////
17901// //
17902// constrainedfacets() Recover constrained facets in a CDT. //
17903// //
17904// All unrecovered subfaces are queued in 'subfacestack'. //
17905// //
17906///////////////////////////////////////////////////////////////////////////////
17907
17908void tetgenmesh::constrainedfacets()
17909{
17910 arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
17911 arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
17912 arraypool *tg_topshells, *tg_botshells, *tg_facfaces;
17913 arraypool *tg_toppoints, *tg_botpoints;
17914 arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
17915 triface searchtet, neightet, crossedge;
17916 face searchsh, *parysh, *parysh1;
17917 face *paryseg;
17918 point *parypt;
17919 enum interresult dir;
17920 int facetcount;
17921 int success;
17922 int t1ver;
17923 int i, j;
17924
17925 // Initialize arrays.
17926 tg_crosstets = new arraypool(sizeof(triface), 10);
17927 tg_topnewtets = new arraypool(sizeof(triface), 10);
17928 tg_botnewtets = new arraypool(sizeof(triface), 10);
17929 tg_topfaces = new arraypool(sizeof(triface), 10);
17930 tg_botfaces = new arraypool(sizeof(triface), 10);
17931 tg_midfaces = new arraypool(sizeof(triface), 10);
17932 tg_toppoints = new arraypool(sizeof(point), 8);
17933 tg_botpoints = new arraypool(sizeof(point), 8);
17934 tg_facfaces = new arraypool(sizeof(face), 10);
17935 tg_topshells = new arraypool(sizeof(face), 10);
17936 tg_botshells = new arraypool(sizeof(face), 10);
17937 tg_missingshs = new arraypool(sizeof(face), 10);
17938 tg_missingshbds = new arraypool(sizeof(face), 10);
17939 tg_missingshverts = new arraypool(sizeof(point), 8);
17940 // This is a global array used by refineregion().
17941 encseglist = new arraypool(sizeof(face), 4);
17942
17943 facetcount = 0;
17944
17945 while (subfacstack->objects > 0l) {
17946
17947 subfacstack->objects--;
17948 parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
17949 searchsh = *parysh;
17950
17951 if (searchsh.sh[3] == NULL) continue; // It is dead.
17952 if (isshtet(searchsh)) continue; // It is recovered.
17953
17954 // Collect all unrecovered subfaces which are co-facet.
17955 smarktest(searchsh);
17956 tg_facfaces->newindex((void **) &parysh);
17957 *parysh = searchsh;
17958 for (i = 0; i < tg_facfaces->objects; i++) {
17959 parysh = (face *) fastlookup(tg_facfaces, i);
17960 for (j = 0; j < 3; j++) {
17961 if (!isshsubseg(*parysh)) {
17962 spivot(*parysh, searchsh);
17963 assert(searchsh.sh != NULL); // SELF_CHECK
17964 if (!smarktested(searchsh)) {
17965 if (!isshtet(searchsh)) {
17966 smarktest(searchsh);
17967 tg_facfaces->newindex((void **) &parysh1);
17968 *parysh1 = searchsh;
17969 }
17970 }
17971 }
17972 senextself(*parysh);
17973 } // j
17974 } // i
17975 // Have found all facet subfaces. Unmark them.
17976 for (i = 0; i < tg_facfaces->objects; i++) {
17977 parysh = (face *) fastlookup(tg_facfaces, i);
17978 sunmarktest(*parysh);
17979 }
17980
17981 if (b->verbose > 2) {
17982 printf(" Recovering facet #%d: %ld subfaces.\n", facetcount + 1,
17983 tg_facfaces->objects);
17984 }
17985 facetcount++;
17986
17987 while (tg_facfaces->objects > 0l) {
17988
17989 tg_facfaces->objects--;
17990 parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
17991 searchsh = *parysh;
17992
17993 if (searchsh.sh[3] == NULL) continue; // It is dead.
17994 if (isshtet(searchsh)) continue; // It is recovered.
17995
17996 searchtet.tet = NULL;
17997 dir = scoutsubface(&searchsh, &searchtet);
17998 if (dir == SHAREFACE) continue; // The subface is inserted.
17999
18000 // The subface is missing. Form the missing region.
18001 // Re-use 'tg_crosstets' for 'adjtets'.
18002 formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
18003
18004 if (scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs)) {
18005 // Save this crossing edge, will be used by fillcavity().
18006 crossedge = searchtet;
18007 // Form a cavity of crossing tets.
18008 success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
18009 tg_topfaces, tg_botfaces, tg_toppoints,
18010 tg_botpoints);
18011 if (success) {
18012 if (!b->flipinsert) {
18013 // Tetrahedralize the top part. Re-use 'tg_midfaces'.
18014 delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
18015 tg_topnewtets, tg_crosstets, tg_midfaces);
18016 // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
18017 delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
18018 tg_botnewtets, tg_crosstets, tg_midfaces);
18019 // Fill the cavity with new tets.
18020 success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
18021 tg_missingshs, tg_topnewtets, tg_botnewtets,
18022 &crossedge);
18023 if (success) {
18024 // Cavity is remeshed. Delete old tets and outer new tets.
18025 carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
18026 } else {
18027 restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18028 tg_missingshbds);
18029 }
18030 } else {
18031 // Use the flip algorithm of Shewchuk to recover the subfaces.
18032 flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints,
18033 tg_missingshverts);
18034 // Recover the missing region.
18035 success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
18036 assert(success);
18037 // Clear working lists.
18038 tg_crosstets->restart();
18039 tg_topfaces->restart();
18040 tg_botfaces->restart();
18041 tg_toppoints->restart();
18042 tg_botpoints->restart();
18043 } // b->flipinsert
18044
18045 if (success) {
18046 // Recover interior subfaces.
18047 for (i = 0; i < caveencshlist->objects; i++) {
18048 parysh = (face *) fastlookup(caveencshlist, i);
18049 dir = scoutsubface(parysh, &searchtet);
18050 if (dir != SHAREFACE) {
18051 // Add this face at the end of the list, so it will be
18052 // processed immediately.
18053 tg_facfaces->newindex((void **) &parysh1);
18054 *parysh1 = *parysh;
18055 }
18056 }
18057 caveencshlist->restart();
18058 // Recover interior segments. This should always be recovered.
18059 for (i = 0; i < caveencseglist->objects; i++) {
18060 paryseg = (face *) fastlookup(caveencseglist, i);
18061 dir = scoutsegment(sorg(*paryseg),sdest(*paryseg),&searchtet,
18062 NULL, NULL);
18063 assert(dir == SHAREEDGE);
18064 // Insert this segment.
18065 if (!issubseg(searchtet)) {
18066 // Let the segment remember an adjacent tet.
18067 sstbond1(*paryseg, searchtet);
18068 // Bond the segment to all tets containing it.
18069 neightet = searchtet;
18070 do {
18071 tssbond1(neightet, *paryseg);
18072 fnextself(neightet);
18073 } while (neightet.tet != searchtet.tet);
18074 } else {
18075 // Collision! Should not happen.
18076 assert(0);
18077 }
18078 }
18079 caveencseglist->restart();
18080 } // success - remesh cavity
18081 } // success - form cavity
18082 } else {
18083 // Recover subfaces by retriangulate the surface mesh.
18084 // Re-use tg_topshells for newshs.
18085 success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
18086 }
18087
18088 // Unmarktest all points of the missing region.
18089 for (i = 0; i < tg_missingshverts->objects; i++) {
18090 parypt = (point *) fastlookup(tg_missingshverts, i);
18091 punmarktest(*parypt);
18092 }
18093 tg_missingshverts->restart();
18094 tg_missingshbds->restart();
18095 tg_missingshs->restart();
18096
18097 if (!success) {
18098 // The missing region can not be recovered. Refine it.
18099 refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
18100 tg_topnewtets, tg_crosstets, tg_midfaces);
18101 // Clean the current list of facet subfaces.
18102 // tg_facfaces->restart();
18103 }
18104 } // while (tg_facfaces->objects)
18105
18106 } // while ((subfacstack->objects)
18107
18108 // Accumulate the dynamic memory.
18109 totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
18110 tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
18111 tg_botfaces->totalmemory + tg_midfaces->totalmemory +
18112 tg_toppoints->totalmemory + tg_botpoints->totalmemory +
18113 tg_facfaces->totalmemory + tg_topshells->totalmemory +
18114 tg_botshells->totalmemory + tg_missingshs->totalmemory +
18115 tg_missingshbds->totalmemory +
18116 tg_missingshverts->totalmemory +
18117 encseglist->totalmemory);
18118
18119 // Delete arrays.
18120 delete tg_crosstets;
18121 delete tg_topnewtets;
18122 delete tg_botnewtets;
18123 delete tg_topfaces;
18124 delete tg_botfaces;
18125 delete tg_midfaces;
18126 delete tg_toppoints;
18127 delete tg_botpoints;
18128 delete tg_facfaces;
18129 delete tg_topshells;
18130 delete tg_botshells;
18131 delete tg_missingshs;
18132 delete tg_missingshbds;
18133 delete tg_missingshverts;
18134 delete encseglist;
18135}
18136
18137///////////////////////////////////////////////////////////////////////////////
18138// //
18139// constraineddelaunay() Create a constrained Delaunay tetrahedralization.//
18140// //
18141///////////////////////////////////////////////////////////////////////////////
18142
18143void tetgenmesh::constraineddelaunay(clock_t& tv)
18144{
18145 face searchsh, *parysh;
18146 face searchseg, *paryseg;
18147 int s, i;
18148
18149 // Statistics.
18150 long bakfillregioncount;
18151 long bakcavitycount, bakcavityexpcount;
18152 long bakseg_ref_count;
18153
18154 if (!b->quiet) {
18155 printf("Constrained Delaunay...\n");
18156 }
18157
18158 makesegmentendpointsmap();
18159
18160 if (b->verbose) {
18161 printf(" Delaunizing segments.\n");
18162 }
18163
18164 checksubsegflag = 1;
18165
18166 // Put all segments into the list (in random order).
18167 subsegs->traversalinit();
18168 for (i = 0; i < subsegs->items; i++) {
18169 s = randomnation(i + 1);
18170 // Move the s-th seg to the i-th.
18171 subsegstack->newindex((void **) &paryseg);
18172 *paryseg = * (face *) fastlookup(subsegstack, s);
18173 // Put i-th seg to be the s-th.
18174 searchseg.sh = shellfacetraverse(subsegs);
18175 //sinfect(searchseg); // Only save it once.
18176 paryseg = (face *) fastlookup(subsegstack, s);
18177 *paryseg = searchseg;
18178 }
18179
18180 // Recover non-Delaunay segments.
18181 delaunizesegments();
18182
18183 if (b->verbose) {
18184 printf(" Inserted %ld Steiner points.\n", st_segref_count);
18185 }
18186
18187 tv = clock();
18188
18189 if (b->verbose) {
18190 printf(" Constraining facets.\n");
18191 }
18192
18193 // Subfaces will be introduced.
18194 checksubfaceflag = 1;
18195
18196 bakfillregioncount = fillregioncount;
18197 bakcavitycount = cavitycount;
18198 bakcavityexpcount = cavityexpcount;
18199 bakseg_ref_count = st_segref_count;
18200
18201 // Randomly order the subfaces.
18202 subfaces->traversalinit();
18203 for (i = 0; i < subfaces->items; i++) {
18204 s = randomnation(i + 1);
18205 // Move the s-th subface to the i-th.
18206 subfacstack->newindex((void **) &parysh);
18207 *parysh = * (face *) fastlookup(subfacstack, s);
18208 // Put i-th subface to be the s-th.
18209 searchsh.sh = shellfacetraverse(subfaces);
18210 parysh = (face *) fastlookup(subfacstack, s);
18211 *parysh = searchsh;
18212 }
18213
18214 // Recover facets.
18215 constrainedfacets();
18216
18217 if (b->verbose) {
18218 if (fillregioncount > bakfillregioncount) {
18219 printf(" Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
18220 }
18221 if (cavitycount > bakcavitycount) {
18222 printf(" Remeshed %ld cavities", cavitycount - bakcavitycount);
18223 if (cavityexpcount - bakcavityexpcount) {
18224 printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
18225 }
18226 printf(".\n");
18227 }
18228 if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
18229 printf(" Inserted %ld (%ld, %ld) refine points.\n",
18230 st_segref_count + st_facref_count - bakseg_ref_count,
18231 st_segref_count - bakseg_ref_count, st_facref_count);
18232 }
18233 }
18234}
18235
18236//// ////
18237//// ////
18238//// constrained_cxx //////////////////////////////////////////////////////////
18239
18240//// steiner_cxx //////////////////////////////////////////////////////////////
18241//// ////
18242//// ////
18243
18244///////////////////////////////////////////////////////////////////////////////
18245// //
18246// checkflipeligibility() A call back function for boundary recovery. //
18247// //
18248// 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
18249// and 2 : 3-to-2, respectively. //
18250// //
18251// 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is //
18252// the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
18253// other points must not be 'dummypoint'. //
18254// //
18255///////////////////////////////////////////////////////////////////////////////
18256
18257int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
18258 point pc, point pd, point pe,
18259 int level, int edgepivot,
18260 flipconstraints* fc)
18261{
18262 point tmppts[3];
18263 enum interresult dir;
18264 int types[2], poss[4];
18265 int intflag;
18266 int rejflag = 0;
18267 int i;
18268
18269 if (fc->seg[0] != NULL) {
18270 // A constraining edge is given (e.g., for edge recovery).
18271 if (fliptype == 1) {
18272 // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18273 tmppts[0] = pa;
18274 tmppts[1] = pb;
18275 tmppts[2] = pc;
18276 for (i = 0; i < 3 && !rejflag; i++) {
18277 if (tmppts[i] != dummypoint) {
18278 // Test if the face [e,d,#] intersects the edge.
18279 intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1],
18280 NULL, 1, types, poss);
18281 if (intflag == 2) {
18282 // They intersect at a single point.
18283 dir = (enum interresult) types[0];
18284 if (dir == ACROSSFACE) {
18285 // The interior of [e,d,#] intersect the segment.
18286 rejflag = 1;
18287 } else if (dir == ACROSSEDGE) {
18288 if (poss[0] == 0) {
18289 // The interior of [e,d] intersect the segment.
18290 // Since [e,d] is the newly created edge. Reject this flip.
18291 rejflag = 1;
18292 }
18293 }
18294 } else if (intflag == 4) {
18295 // They may intersect at either a point or a line segment.
18296 dir = (enum interresult) types[0];
18297 if (dir == ACROSSEDGE) {
18298 if (poss[0] == 0) {
18299 // The interior of [e,d] intersect the segment.
18300 // Since [e,d] is the newly created edge. Reject this flip.
18301 rejflag = 1;
18302 }
18303 }
18304 }
18305 } // if (tmppts[0] != dummypoint)
18306 } // i
18307 } else if (fliptype == 2) {
18308 // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18309 if (pc != dummypoint) {
18310 // Check if the new face [a,b,c] intersect the edge in its interior.
18311 intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL,
18312 1, types, poss);
18313 if (intflag == 2) {
18314 // They intersect at a single point.
18315 dir = (enum interresult) types[0];
18316 if (dir == ACROSSFACE) {
18317 // The interior of [a,b,c] intersect the segment.
18318 rejflag = 1; // Do not flip.
18319 }
18320 } else if (intflag == 4) {
18321 // [a,b,c] is coplanar with the edge.
18322 dir = (enum interresult) types[0];
18323 if (dir == ACROSSEDGE) {
18324 // The boundary of [a,b,c] intersect the segment.
18325 rejflag = 1; // Do not flip.
18326 }
18327 }
18328 } // if (pc != dummypoint)
18329 }
18330 } // if (fc->seg[0] != NULL)
18331
18332 if ((fc->fac[0] != NULL) && !rejflag) {
18333 // A constraining face is given (e.g., for face recovery).
18334 if (fliptype == 1) {
18335 // A 2-to-3 flip.
18336 // Test if the new edge [e,d] intersects the face.
18337 intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd,
18338 NULL, 1, types, poss);
18339 if (intflag == 2) {
18340 // They intersect at a single point.
18341 dir = (enum interresult) types[0];
18342 if (dir == ACROSSFACE) {
18343 rejflag = 1;
18344 } else if (dir == ACROSSEDGE) {
18345 rejflag = 1;
18346 }
18347 } else if (intflag == 4) {
18348 // The edge [e,d] is coplanar with the face.
18349 // There may be two intersections.
18350 for (i = 0; i < 2 && !rejflag; i++) {
18351 dir = (enum interresult) types[i];
18352 if (dir == ACROSSFACE) {
18353 rejflag = 1;
18354 } else if (dir == ACROSSEDGE) {
18355 rejflag = 1;
18356 }
18357 }
18358 }
18359 } // if (fliptype == 1)
18360 } // if (fc->fac[0] != NULL)
18361
18362 if ((fc->remvert != NULL) && !rejflag) {
18363 // The vertex is going to be removed. Do not create a new edge which
18364 // contains this vertex.
18365 if (fliptype == 1) {
18366 // A 2-to-3 flip.
18367 if ((pd == fc->remvert) || (pe == fc->remvert)) {
18368 rejflag = 1;
18369 }
18370 }
18371 }
18372
18373 if (fc->remove_large_angle && !rejflag) {
18374 // Remove a large dihedral angle. Do not create a new small angle.
18375 REAL cosmaxd = 0, diff;
18376 if (fliptype == 1) {
18377 // We assume that neither 'a' nor 'b' is dummypoint.
18378 assert((pa != dummypoint) && (pb != dummypoint)); // SELF_CHECK
18379 // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18380 // The new tet [e,d,a,b] will be flipped later. Only two new tets:
18381 // [e,d,b,c] and [e,d,c,a] need to be checked.
18382 if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
18383 // Get the largest dihedral angle of [e,d,b,c].
18384 tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
18385 diff = cosmaxd - fc->cosdihed_in;
18386 if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18387 if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18388 rejflag = 1;
18389 } else {
18390 // Record the largest new angle.
18391 if (cosmaxd < fc->cosdihed_out) {
18392 fc->cosdihed_out = cosmaxd;
18393 }
18394 // Get the largest dihedral angle of [e,d,c,a].
18395 tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
18396 diff = cosmaxd - fc->cosdihed_in;
18397 if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18398 if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18399 rejflag = 1;
18400 } else {
18401 // Record the largest new angle.
18402 if (cosmaxd < fc->cosdihed_out) {
18403 fc->cosdihed_out = cosmaxd;
18404 }
18405 }
18406 }
18407 } // if (pc != dummypoint && ...)
18408 } else if (fliptype == 2) {
18409 // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18410 // We assume that neither 'e' nor 'd' is dummypoint.
18411 assert((pe != dummypoint) && (pd != dummypoint)); // SELF_CHECK
18412 if (level == 0) {
18413 // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
18414 if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18415 // Get the largest dihedral angle of [a,b,c,d].
18416 tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18417 diff = cosmaxd - fc->cosdihed_in;
18418 if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
18419 if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18420 rejflag = 1;
18421 } else {
18422 // Record the largest new angle.
18423 if (cosmaxd < fc->cosdihed_out) {
18424 fc->cosdihed_out = cosmaxd;
18425 }
18426 // Get the largest dihedral angle of [b,a,c,e].
18427 tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18428 diff = cosmaxd - fc->cosdihed_in;
18429 if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18430 if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18431 rejflag = 1;
18432 } else {
18433 // Record the largest new angle.
18434 if (cosmaxd < fc->cosdihed_out) {
18435 fc->cosdihed_out = cosmaxd;
18436 }
18437 }
18438 }
18439 }
18440 } else { // level > 0
18441 assert(edgepivot != 0);
18442 if (edgepivot == 1) {
18443 // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
18444 if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18445 // Get the largest dihedral angle of [b,a,c,e].
18446 tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18447 diff = cosmaxd - fc->cosdihed_in;
18448 if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18449 if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18450 rejflag = 1;
18451 } else {
18452 // Record the largest new angle.
18453 if (cosmaxd < fc->cosdihed_out) {
18454 fc->cosdihed_out = cosmaxd;
18455 }
18456 }
18457 }
18458 } else {
18459 assert(edgepivot == 2);
18460 // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
18461 if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18462 // Get the largest dihedral angle of [b,a,c,e].
18463 tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18464 diff = cosmaxd - fc->cosdihed_in;
18465 if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18466 if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18467 rejflag = 1;
18468 } else {
18469 // Record the largest new angle.
18470 if (cosmaxd < fc->cosdihed_out) {
18471 fc->cosdihed_out = cosmaxd;
18472 }
18473 }
18474 }
18475 } // edgepivot
18476 } // level
18477 }
18478 }
18479
18480 return rejflag;
18481}
18482
18483///////////////////////////////////////////////////////////////////////////////
18484// //
18485// removeedgebyflips() Remove an edge by flips. //
18486// //
18487// 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed. //
18488// //
18489// The return value is a positive integer, it indicates whether the edge is //
18490// removed or not. A value "2" means the edge is removed, otherwise, the //
18491// edge is not removed and the value (must >= 3) is the current number of //
18492// tets in the edge star. //
18493// //
18494///////////////////////////////////////////////////////////////////////////////
18495
18496int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
18497{
18498 triface *abtets, spintet;
18499 int t1ver;
18500 int n, nn, i;
18501
18502
18503 if (checksubsegflag) {
18504 // Do not flip a segment.
18505 if (issubseg(*flipedge)) {
18506 if (fc->collectencsegflag) {
18507 face checkseg, *paryseg;
18508 tsspivot1(*flipedge, checkseg);
18509 if (!sinfected(checkseg)) {
18510 // Queue this segment in list.
18511 sinfect(checkseg);
18512 caveencseglist->newindex((void **) &paryseg);
18513 *paryseg = checkseg;
18514 }
18515 }
18516 return 0;
18517 }
18518 }
18519
18520 // Count the number of tets at edge [a,b].
18521 n = 0;
18522 spintet = *flipedge;
18523 while (1) {
18524 n++;
18525 fnextself(spintet);
18526 if (spintet.tet == flipedge->tet) break;
18527 }
18528 assert(n >= 3);
18529
18530 if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
18531 // The star size exceeds the limit.
18532 return 0; // Do not flip it.
18533 }
18534
18535 // Allocate spaces.
18536 abtets = new triface[n];
18537 // Collect the tets at edge [a,b].
18538 spintet = *flipedge;
18539 i = 0;
18540 while (1) {
18541 abtets[i] = spintet;
18542 setelemcounter(abtets[i], 1);
18543 i++;
18544 fnextself(spintet);
18545 if (spintet.tet == flipedge->tet) break;
18546 }
18547
18548
18549 // Try to flip the edge (level = 0, edgepivot = 0).
18550 nn = flipnm(abtets, n, 0, 0, fc);
18551
18552
18553 if (nn > 2) {
18554 // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
18555 for (i = 0; i < nn; i++) {
18556 setelemcounter(abtets[i], 0);
18557 }
18558 // Restore the input edge (needed by Lawson's flip).
18559 *flipedge = abtets[0];
18560 }
18561
18562 // Release the temporary allocated spaces.
18563 // NOTE: fc->unflip must be 0.
18564 int bakunflip = fc->unflip;
18565 fc->unflip = 0;
18566 flipnm_post(abtets, n, nn, 0, fc);
18567 fc->unflip = bakunflip;
18568
18569 delete [] abtets;
18570
18571 return nn;
18572}
18573
18574///////////////////////////////////////////////////////////////////////////////
18575// //
18576// removefacebyflips() Remove a face by flips. //
18577// //
18578// Return 1 if the face is removed. Otherwise, return 0. //
18579// //
18580// ASSUMPTIONS: //
18581// - 'flipface' must not be a hull face. //
18582// //
18583///////////////////////////////////////////////////////////////////////////////
18584
18585int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
18586{
18587 if (checksubfaceflag) {
18588 if (issubface(*flipface)) {
18589 return 0;
18590 }
18591 }
18592
18593 triface fliptets[3], flipedge;
18594 point pa, pb, pc, pd, pe;
18595 REAL ori;
18596 int reducflag = 0;
18597
18598 fliptets[0] = *flipface;
18599 fsym(*flipface, fliptets[1]);
18600 pa = org(fliptets[0]);
18601 pb = dest(fliptets[0]);
18602 pc = apex(fliptets[0]);
18603 pd = oppo(fliptets[0]);
18604 pe = oppo(fliptets[1]);
18605
18606 ori = orient3d(pa, pb, pd, pe);
18607 if (ori > 0) {
18608 ori = orient3d(pb, pc, pd, pe);
18609 if (ori > 0) {
18610 ori = orient3d(pc, pa, pd, pe);
18611 if (ori > 0) {
18612 // Found a 2-to-3 flip.
18613 reducflag = 1;
18614 } else {
18615 eprev(*flipface, flipedge); // [c,a]
18616 }
18617 } else {
18618 enext(*flipface, flipedge); // [b,c]
18619 }
18620 } else {
18621 flipedge = *flipface; // [a,b]
18622 }
18623
18624 if (reducflag) {
18625 // A 2-to-3 flip is found.
18626 flip23(fliptets, 0, fc);
18627 return 1;
18628 } else {
18629 // Try to flip the selected edge of this face.
18630 if (removeedgebyflips(&flipedge, fc) == 2) {
18631 return 1;
18632 }
18633 }
18634
18635 // Face is not removed.
18636 return 0;
18637}
18638
18639///////////////////////////////////////////////////////////////////////////////
18640// //
18641// recoveredge() Recover an edge in current tetrahedralization. //
18642// //
18643// If the edge is recovered, 'searchtet' returns a tet containing the edge. //
18644// //
18645// This edge may intersect a set of faces and edges in the mesh. All these //
18646// faces or edges are needed to be removed. //
18647// //
18648// If the parameter 'fullsearch' is set, it tries to flip any face or edge //
18649// that intersects the recovering edge. Otherwise, only the face or edge //
18650// which is visible by 'startpt' is tried. //
18651// //
18652///////////////////////////////////////////////////////////////////////////////
18653
18654int tetgenmesh::recoveredgebyflips(point startpt, point endpt,
18655 triface* searchtet, int fullsearch)
18656{
18657 flipconstraints fc;
18658 enum interresult dir;
18659
18660 fc.seg[0] = startpt;
18661 fc.seg[1] = endpt;
18662 fc.checkflipeligibility = 1;
18663
18664 // The mainloop of the edge reocvery.
18665 while (1) { // Loop I
18666
18667 // Search the edge from 'startpt'.
18668 point2tetorg(startpt, *searchtet);
18669 dir = finddirection(searchtet, endpt);
18670 if (dir == ACROSSVERT) {
18671 if (dest(*searchtet) == endpt) {
18672 return 1; // Edge is recovered.
18673 } else {
18674 terminatetetgen(this, 3); // // It may be a PLC problem.
18675 }
18676 }
18677
18678 // The edge is missing.
18679
18680 // Try to flip the first intersecting face/edge.
18681 enextesymself(*searchtet); // Go to the opposite face.
18682 if (dir == ACROSSFACE) {
18683 // A face is intersected with the segment. Try to flip it.
18684 if (removefacebyflips(searchtet, &fc)) {
18685 continue;
18686 }
18687 } else if (dir == ACROSSEDGE) {
18688 // An edge is intersected with the segment. Try to flip it.
18689 if (removeedgebyflips(searchtet, &fc) == 2) {
18690 continue;
18691 }
18692 } else {
18693 terminatetetgen(this, 3); // It may be a PLC problem.
18694 }
18695
18696 // The edge is missing.
18697
18698 if (fullsearch) {
18699 // Try to flip one of the faces/edges which intersects the edge.
18700 triface neightet, spintet;
18701 point pa, pb, pc, pd;
18702 badface bakface;
18703 enum interresult dir1;
18704 int types[2], poss[4], pos = 0;
18705 int success = 0;
18706 int t1ver;
18707 int i, j;
18708
18709 // Loop through the sequence of intersecting faces/edges from
18710 // 'startpt' to 'endpt'.
18711 point2tetorg(startpt, *searchtet);
18712 dir = finddirection(searchtet, endpt);
18713 //assert(dir != ACROSSVERT);
18714
18715 // Go to the face/edge intersecting the searching edge.
18716 enextesymself(*searchtet); // Go to the opposite face.
18717 // This face/edge has been tried in previous step.
18718
18719 while (1) { // Loop I-I
18720
18721 // Find the next intersecting face/edge.
18722 fsymself(*searchtet);
18723 if (dir == ACROSSFACE) {
18724 neightet = *searchtet;
18725 j = (neightet.ver & 3); // j is the current face number.
18726 for (i = j + 1; i < j + 4; i++) {
18727 neightet.ver = (i % 4);
18728 pa = org(neightet);
18729 pb = dest(neightet);
18730 pc = apex(neightet);
18731 pd = oppo(neightet); // The above point.
18732 if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
18733 dir = (enum interresult) types[0];
18734 pos = poss[0];
18735 break;
18736 } else {
18737 dir = DISJOINT;
18738 pos = 0;
18739 }
18740 } // i
18741 // There must be an intersection face/edge.
18742 assert(dir != DISJOINT); // SELF_CHECK
18743 } else {
18744 assert(dir == ACROSSEDGE);
18745 while (1) { // Loop I-I-I
18746 // Check the two opposite faces (of the edge) in 'searchtet'.
18747 for (i = 0; i < 2; i++) {
18748 if (i == 0) {
18749 enextesym(*searchtet, neightet);
18750 } else {
18751 eprevesym(*searchtet, neightet);
18752 }
18753 pa = org(neightet);
18754 pb = dest(neightet);
18755 pc = apex(neightet);
18756 pd = oppo(neightet); // The above point.
18757 if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
18758 dir = (enum interresult) types[0];
18759 pos = poss[0];
18760 break; // for loop
18761 } else {
18762 dir = DISJOINT;
18763 pos = 0;
18764 }
18765 } // i
18766 if (dir != DISJOINT) {
18767 // Find an intersection face/edge.
18768 break; // Loop I-I-I
18769 }
18770 // No intersection. Rotate to the next tet at the edge.
18771 fnextself(*searchtet);
18772 } // while (1) // Loop I-I-I
18773 }
18774
18775 // Adjust to the intersecting edge/vertex.
18776 for (i = 0; i < pos; i++) {
18777 enextself(neightet);
18778 }
18779
18780 if (dir == SHAREVERT) {
18781 // Check if we have reached the 'endpt'.
18782 pd = org(neightet);
18783 if (pd == endpt) {
18784 // Failed to recover the edge.
18785 break; // Loop I-I
18786 } else {
18787 // We need to further check this case. It might be a PLC problem
18788 // or a Steiner point that was added at a bad location.
18789 assert(0);
18790 }
18791 }
18792
18793 // The next to be flipped face/edge.
18794 *searchtet = neightet;
18795
18796 // Bakup this face (tetrahedron).
18797 bakface.forg = org(*searchtet);
18798 bakface.fdest = dest(*searchtet);
18799 bakface.fapex = apex(*searchtet);
18800 bakface.foppo = oppo(*searchtet);
18801
18802 // Try to flip this intersecting face/edge.
18803 if (dir == ACROSSFACE) {
18804 if (removefacebyflips(searchtet, &fc)) {
18805 success = 1;
18806 break; // Loop I-I
18807 }
18808 } else if (dir == ACROSSEDGE) {
18809 if (removeedgebyflips(searchtet, &fc) == 2) {
18810 success = 1;
18811 break; // Loop I-I
18812 }
18813 } else {
18814 assert(0); // A PLC problem.
18815 }
18816
18817 // The face/edge is not flipped.
18818 if ((searchtet->tet == NULL) ||
18819 (org(*searchtet) != bakface.forg) ||
18820 (dest(*searchtet) != bakface.fdest) ||
18821 (apex(*searchtet) != bakface.fapex) ||
18822 (oppo(*searchtet) != bakface.foppo)) {
18823 // 'searchtet' was flipped. We must restore it.
18824 point2tetorg(bakface.forg, *searchtet);
18825 dir1 = finddirection(searchtet, bakface.fdest);
18826 if (dir1 == ACROSSVERT) {
18827 assert(dest(*searchtet) == bakface.fdest);
18828 spintet = *searchtet;
18829 while (1) {
18830 if (apex(spintet) == bakface.fapex) {
18831 // Found the face.
18832 *searchtet = spintet;
18833 break;
18834 }
18835 fnextself(spintet);
18836 if (spintet.tet == searchtet->tet) {
18837 searchtet->tet = NULL;
18838 break; // Not find.
18839 }
18840 } // while (1)
18841 if (searchtet->tet != NULL) {
18842 if (oppo(*searchtet) != bakface.foppo) {
18843 fsymself(*searchtet);
18844 if (oppo(*searchtet) != bakface.foppo) {
18845 assert(0); // Check this case.
18846 searchtet->tet = NULL;
18847 break; // Not find.
18848 }
18849 }
18850 }
18851 } else {
18852 searchtet->tet = NULL; // Not find.
18853 }
18854 if (searchtet->tet == NULL) {
18855 success = 0; // This face/edge has been destroyed.
18856 break; // Loop I-I
18857 }
18858 }
18859 } // while (1) // Loop I-I
18860
18861 if (success) {
18862 // One of intersecting faces/edges is flipped.
18863 continue;
18864 }
18865
18866 } // if (fullsearch)
18867
18868 // The edge is missing.
18869 break; // Loop I
18870
18871 } // while (1) // Loop I
18872
18873 return 0;
18874}
18875
18876///////////////////////////////////////////////////////////////////////////////
18877// //
18878// add_steinerpt_in_schoenhardtpoly() Insert a Steiner point in a Schoen- //
18879// hardt polyhedron. //
18880// //
18881// 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
18882// tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)]. Moreover, //
18883// the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'. A special //
18884// case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b]. //
18885// Such set of tets arises when we want to recover an edge from 'p0' to 'p_ //
18886// (n-1)', and the number of tets at [a,b] can not be reduced by any flip. //
18887// //
18888///////////////////////////////////////////////////////////////////////////////
18889
18890int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
18891 int chkencflag)
18892{
18893 triface worktet, *parytet;
18894 triface faketet1, faketet2;
18895 point pc, pd, steinerpt;
18896 insertvertexflags ivf;
18897 optparameters opm;
18898 REAL vcd[3], sampt[3], smtpt[3];
18899 REAL maxminvol = 0.0, minvol = 0.0, ori;
18900 int success, maxidx = 0;
18901 int it, i;
18902
18903
18904 pc = apex(abtets[0]); // pc = p0
18905 pd = oppo(abtets[n-1]); // pd = p_(n-1)
18906
18907
18908 // Find an optimial point in edge [c,d]. It is visible by all outer faces
18909 // of 'abtets', and it maxmizes the min volume.
18910
18911 // initialize the list of 2n boundary faces.
18912 for (i = 0; i < n; i++) {
18913 edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
18914 cavetetlist->newindex((void **) &parytet);
18915 *parytet = worktet;
18916 eorgoppo(abtets[i], worktet); // [p_i+1,p_i,b]
18917 cavetetlist->newindex((void **) &parytet);
18918 *parytet = worktet;
18919 }
18920
18921 int N = 100;
18922 REAL stepi = 0.01;
18923
18924 // Search the point along the edge [c,d].
18925 for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
18926
18927 // Sample N points in edge [c,d].
18928 for (it = 1; it < N; it++) {
18929 for (i = 0; i < 3; i++) {
18930 sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
18931 }
18932 for (i = 0; i < cavetetlist->objects; i++) {
18933 parytet = (triface *) fastlookup(cavetetlist, i);
18934 ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
18935 if (i == 0) {
18936 minvol = ori;
18937 } else {
18938 if (minvol > ori) minvol = ori;
18939 }
18940 } // i
18941 if (it == 1) {
18942 maxminvol = minvol;
18943 maxidx = it;
18944 } else {
18945 if (maxminvol < minvol) {
18946 maxminvol = minvol;
18947 maxidx = it;
18948 }
18949 }
18950 } // it
18951
18952 if (maxminvol <= 0) {
18953 cavetetlist->restart();
18954 return 0;
18955 }
18956
18957 for (i = 0; i < 3; i++) {
18958 smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
18959 }
18960
18961 // Create two faked tets to hold the two non-existing boundary faces:
18962 // [d,c,a] and [c,d,b].
18963 maketetrahedron(&faketet1);
18964 setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
18965 cavetetlist->newindex((void **) &parytet);
18966 *parytet = faketet1;
18967 maketetrahedron(&faketet2);
18968 setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
18969 cavetetlist->newindex((void **) &parytet);
18970 *parytet = faketet2;
18971
18972 // Point smooth options.
18973 opm.max_min_volume = 1;
18974 opm.numofsearchdirs = 20;
18975 opm.searchstep = 0.001;
18976 opm.maxiter = 100; // Limit the maximum iterations.
18977 opm.initval = 0.0; // Initial volume is zero.
18978
18979 // Try to relocate the point into the inside of the polyhedron.
18980 success = smoothpoint(smtpt, cavetetlist, 1, &opm);
18981
18982 if (success) {
18983 while (opm.smthiter == 100) {
18984 // It was relocated and the prescribed maximum iteration reached.
18985 // Try to increase the search stepsize.
18986 opm.searchstep *= 10.0;
18987 //opm.maxiter = 100; // Limit the maximum iterations.
18988 opm.initval = opm.imprval;
18989 opm.smthiter = 0; // Init.
18990 smoothpoint(smtpt, cavetetlist, 1, &opm);
18991 }
18992 } // if (success)
18993
18994 // Delete the two faked tets.
18995 tetrahedrondealloc(faketet1.tet);
18996 tetrahedrondealloc(faketet2.tet);
18997
18998 cavetetlist->restart();
18999
19000 if (!success) {
19001 return 0;
19002 }
19003
19004
19005 // Insert the Steiner point.
19006 makepoint(&steinerpt, FREEVOLVERTEX);
19007 for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
19008
19009 // Insert the created Steiner point.
19010 for (i = 0; i < n; i++) {
19011 infect(abtets[i]);
19012 caveoldtetlist->newindex((void **) &parytet);
19013 *parytet = abtets[i];
19014 }
19015 worktet = abtets[0]; // No need point location.
19016 ivf.iloc = (int) INSTAR;
19017 ivf.chkencflag = chkencflag;
19018 ivf.assignmeshsize = b->metric;
19019 if (ivf.assignmeshsize) {
19020 // Search the tet containing 'steinerpt' for size interpolation.
19021 locate(steinerpt, &(abtets[0]));
19022 worktet = abtets[0];
19023 }
19024
19025 // Insert the new point into the tetrahedralization T.
19026 // Note that T is convex (nonconvex = 0).
19027 if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
19028 // The vertex has been inserted.
19029 st_volref_count++;
19030 if (steinerleft > 0) steinerleft--;
19031 return 1;
19032 } else {
19033 // Not inserted.
19034 pointdealloc(steinerpt);
19035 return 0;
19036 }
19037}
19038
19039///////////////////////////////////////////////////////////////////////////////
19040// //
19041// add_steinerpt_in_segment() Add a Steiner point inside a segment. //
19042// //
19043///////////////////////////////////////////////////////////////////////////////
19044
19045int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
19046{
19047 triface searchtet;
19048 face *paryseg, candseg;
19049 point startpt, endpt, pc, pd;
19050 flipconstraints fc;
19051 enum interresult dir;
19052 REAL P[3], Q[3], tp, tq;
19053 REAL len, smlen = 0, split = 0, split_q = 0;
19054 int success;
19055 int i;
19056 (void)success;
19057
19058 startpt = sorg(*misseg);
19059 endpt = sdest(*misseg);
19060
19061 fc.seg[0] = startpt;
19062 fc.seg[1] = endpt;
19063 fc.checkflipeligibility = 1;
19064 fc.collectencsegflag = 1;
19065
19066 point2tetorg(startpt, searchtet);
19067 dir = finddirection(&searchtet, endpt);
19068 //assert(dir != ACROSSVERT);
19069
19070 // Try to flip the first intersecting face/edge.
19071 enextesymself(searchtet); // Go to the opposite face.
19072
19073 int bak_fliplinklevel = b->fliplinklevel;
19074 b->fliplinklevel = searchlevel;
19075
19076 if (dir == ACROSSFACE) {
19077 // A face is intersected with the segment. Try to flip it.
19078 success = removefacebyflips(&searchtet, &fc);
19079 assert(success == 0);
19080 } else if (dir == ACROSSEDGE) {
19081 // An edge is intersected with the segment. Try to flip it.
19082 success = removeedgebyflips(&searchtet, &fc);
19083 assert(success != 2);
19084 } else {
19085 terminatetetgen(this, 3); // It may be a PLC problem.
19086 }
19087
19088 split = 0;
19089 for (i = 0; i < caveencseglist->objects; i++) {
19090 paryseg = (face *) fastlookup(caveencseglist, i);
19091 suninfect(*paryseg);
19092 // Calculate the shortest edge between the two lines.
19093 pc = sorg(*paryseg);
19094 pd = sdest(*paryseg);
19095 tp = tq = 0;
19096 if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
19097 // Does the shortest edge lie between the two segments?
19098 // Round tp and tq.
19099 if ((tp > 0) && (tq < 1)) {
19100 if (tp < 0.5) {
19101 if (tp < (b->epsilon * 1e+3)) tp = 0.0;
19102 } else {
19103 if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
19104 }
19105 }
19106 if ((tp <= 0) || (tp >= 1)) continue;
19107 if ((tq > 0) && (tq < 1)) {
19108 if (tq < 0.5) {
19109 if (tq < (b->epsilon * 1e+3)) tq = 0.0;
19110 } else {
19111 if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
19112 }
19113 }
19114 if ((tq <= 0) || (tq >= 1)) continue;
19115 // It is a valid shortest edge. Calculate its length.
19116 len = distance(P, Q);
19117 if (split == 0) {
19118 smlen = len;
19119 split = tp;
19120 split_q = tq;
19121 candseg = *paryseg;
19122 } else {
19123 if (len < smlen) {
19124 smlen = len;
19125 split = tp;
19126 split_q = tq;
19127 candseg = *paryseg;
19128 }
19129 }
19130 }
19131 }
19132
19133 caveencseglist->restart();
19134 b->fliplinklevel = bak_fliplinklevel;
19135
19136 if (split == 0) {
19137 // Found no crossing segment.
19138 return 0;
19139 }
19140
19141 face splitsh;
19142 face splitseg;
19143 point steinerpt, *parypt;
19144 insertvertexflags ivf;
19145
19146 if (b->addsteiner_algo == 1) {
19147 // Split the segment at the closest point to a near segment.
19148 makepoint(&steinerpt, FREESEGVERTEX);
19149 for (i = 0; i < 3; i++) {
19150 steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19151 }
19152 } else { // b->addsteiner_algo == 2
19153 for (i = 0; i < 3; i++) {
19154 P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19155 }
19156 pc = sorg(candseg);
19157 pd = sdest(candseg);
19158 for (i = 0; i < 3; i++) {
19159 Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
19160 }
19161 makepoint(&steinerpt, FREEVOLVERTEX);
19162 for (i = 0; i < 3; i++) {
19163 steinerpt[i] = 0.5 * (P[i] + Q[i]);
19164 }
19165 }
19166
19167 // We need to locate the point. Start searching from 'searchtet'.
19168 if (split < 0.5) {
19169 point2tetorg(startpt, searchtet);
19170 } else {
19171 point2tetorg(endpt, searchtet);
19172 }
19173 if (b->addsteiner_algo == 1) {
19174 splitseg = *misseg;
19175 spivot(*misseg, splitsh);
19176 } else {
19177 splitsh.sh = NULL;
19178 splitseg.sh = NULL;
19179 }
19180 ivf.iloc = (int) OUTSIDE;
19181 ivf.bowywat = 1;
19182 ivf.lawson = 0;
19183 ivf.rejflag = 0;
19184 ivf.chkencflag = 0;
19185 ivf.sloc = (int) ONEDGE;
19186 ivf.sbowywat = 1;
19187 ivf.splitbdflag = 0;
19188 ivf.validflag = 1;
19189 ivf.respectbdflag = 1;
19190 ivf.assignmeshsize = b->metric;
19191
19192 if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
19193 pointdealloc(steinerpt);
19194 return 0;
19195 }
19196
19197 if (b->addsteiner_algo == 1) {
19198 // Save this Steiner point (for removal).
19199 // Re-use the array 'subvertstack'.
19200 subvertstack->newindex((void **) &parypt);
19201 *parypt = steinerpt;
19202 st_segref_count++;
19203 } else { // b->addsteiner_algo == 2
19204 // Queue the segment for recovery.
19205 subsegstack->newindex((void **) &paryseg);
19206 *paryseg = *misseg;
19207 st_volref_count++;
19208 }
19209 if (steinerleft > 0) steinerleft--;
19210
19211 return 1;
19212}
19213
19214///////////////////////////////////////////////////////////////////////////////
19215// //
19216// addsteiner4recoversegment() Add a Steiner point for recovering a seg. //
19217// //
19218///////////////////////////////////////////////////////////////////////////////
19219
19220int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
19221{
19222 triface *abtets, searchtet, spintet;
19223 face splitsh;
19224 face *paryseg;
19225 point startpt, endpt;
19226 point pa, pb, pd, steinerpt, *parypt;
19227 enum interresult dir;
19228 insertvertexflags ivf;
19229 int types[2], poss[4];
19230 int n, endi, success;
19231 int t1ver;
19232 int i;
19233
19234 startpt = sorg(*misseg);
19235 if (pointtype(startpt) == FREESEGVERTEX) {
19236 sesymself(*misseg);
19237 startpt = sorg(*misseg);
19238 }
19239 endpt = sdest(*misseg);
19240
19241 // Try to recover the edge by adding Steiner points.
19242 point2tetorg(startpt, searchtet);
19243 dir = finddirection(&searchtet, endpt);
19244 enextself(searchtet);
19245 //assert(apex(searchtet) == startpt);
19246
19247 if (dir == ACROSSFACE) {
19248 // The segment is crossing at least 3 faces. Find the common edge of
19249 // the first 3 crossing faces.
19250 esymself(searchtet);
19251 fsym(searchtet, spintet);
19252 pd = oppo(spintet);
19253 for (i = 0; i < 3; i++) {
19254 pa = org(spintet);
19255 pb = dest(spintet);
19256 //pc = apex(neightet);
19257 if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
19258 break; // Found the edge.
19259 }
19260 enextself(spintet);
19261 eprevself(searchtet);
19262 }
19263 assert(i < 3);
19264 esymself(searchtet);
19265 } else {
19266 assert(dir == ACROSSEDGE);
19267 // PLC check.
19268 if (issubseg(searchtet)) {
19269 face checkseg;
19270 tsspivot1(searchtet, checkseg);
19271 printf("Found two segments intersect each other.\n");
19272 pa = farsorg(*misseg);
19273 pb = farsdest(*misseg);
19274 printf(" 1st: [%d,%d] %d.\n", pointmark(pa), pointmark(pb),
19275 shellmark(*misseg));
19276 pa = farsorg(checkseg);
19277 pb = farsdest(checkseg);
19278 printf(" 2nd: [%d,%d] %d.\n", pointmark(pa), pointmark(pb),
19279 shellmark(checkseg));
19280 terminatetetgen(this, 3);
19281 }
19282 }
19283 assert(apex(searchtet) == startpt);
19284
19285 spintet = searchtet;
19286 n = 0; endi = -1;
19287 while (1) {
19288 // Check if the endpt appears in the star.
19289 if (apex(spintet) == endpt) {
19290 endi = n; // Remember the position of endpt.
19291 }
19292 n++; // Count a tet in the star.
19293 fnextself(spintet);
19294 if (spintet.tet == searchtet.tet) break;
19295 }
19296 assert(n >= 3);
19297
19298 if (endi > 0) {
19299 // endpt is also in the edge star
19300 // Get all tets in the edge star.
19301 abtets = new triface[n];
19302 spintet = searchtet;
19303 for (i = 0; i < n; i++) {
19304 abtets[i] = spintet;
19305 fnextself(spintet);
19306 }
19307
19308 success = 0;
19309
19310 if (dir == ACROSSFACE) {
19311 // Find a Steiner points inside the polyhedron.
19312 if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19313 success = 1;
19314 }
19315 } else if (dir == ACROSSEDGE) {
19316 if (n > 4) {
19317 // In this case, 'abtets' is separated by the plane (containing the
19318 // two intersecting edges) into two parts, P1 and P2, where P1
19319 // consists of 'endi' tets: abtets[0], abtets[1], ...,
19320 // abtets[endi-1], and P2 consists of 'n - endi' tets:
19321 // abtets[endi], abtets[endi+1], abtets[n-1].
19322 if (endi > 2) { // P1
19323 // There are at least 3 tets in the first part.
19324 if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19325 success++;
19326 }
19327 }
19328 if ((n - endi) > 2) { // P2
19329 // There are at least 3 tets in the first part.
19330 if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
19331 success++;
19332 }
19333 }
19334 } else {
19335 // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
19336 // However, there will be invalid tets (either zero or negtive
19337 // volume). Otherwise, [c,d] should already be recovered by the
19338 // recoveredge() function.
19339 terminatetetgen(this, 2); // Report a bug.
19340 }
19341 } else {
19342 terminatetetgen(this, 10); // A PLC problem.
19343 }
19344
19345 delete [] abtets;
19346
19347 if (success) {
19348 // Add the missing segment back to the recovering list.
19349 subsegstack->newindex((void **) &paryseg);
19350 *paryseg = *misseg;
19351 return 1;
19352 }
19353 } // if (endi > 0)
19354
19355 if (!splitsegflag) {
19356 return 0;
19357 }
19358
19359 if (b->verbose > 2) {
19360 printf(" Splitting segment (%d, %d)\n", pointmark(startpt),
19361 pointmark(endpt));
19362 }
19363 steinerpt = NULL;
19364
19365 if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
19366 if (add_steinerpt_in_segment(misseg, 3)) {
19367 return 1;
19368 }
19369 sesymself(*misseg);
19370 if (add_steinerpt_in_segment(misseg, 3)) {
19371 return 1;
19372 }
19373 sesymself(*misseg);
19374 }
19375
19376
19377
19378
19379 if (steinerpt == NULL) {
19380 // Split the segment at its midpoint.
19381 makepoint(&steinerpt, FREESEGVERTEX);
19382 for (i = 0; i < 3; i++) {
19383 steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
19384 }
19385
19386 // We need to locate the point.
19387 assert(searchtet.tet != NULL); // Start searching from 'searchtet'.
19388 spivot(*misseg, splitsh);
19389 ivf.iloc = (int) OUTSIDE;
19390 ivf.bowywat = 1;
19391 ivf.lawson = 0;
19392 ivf.rejflag = 0;
19393 ivf.chkencflag = 0;
19394 ivf.sloc = (int) ONEDGE;
19395 ivf.sbowywat = 1;
19396 ivf.splitbdflag = 0;
19397 ivf.validflag = 1;
19398 ivf.respectbdflag = 1;
19399 ivf.assignmeshsize = b->metric;
19400 if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
19401 assert(0);
19402 }
19403 } // if (endi > 0)
19404
19405 // Save this Steiner point (for removal).
19406 // Re-use the array 'subvertstack'.
19407 subvertstack->newindex((void **) &parypt);
19408 *parypt = steinerpt;
19409
19410 st_segref_count++;
19411 if (steinerleft > 0) steinerleft--;
19412
19413 return 1;
19414}
19415
19416///////////////////////////////////////////////////////////////////////////////
19417// //
19418// recoversegments() Recover all segments. //
19419// //
19420// All segments need to be recovered are in 'subsegstack'. //
19421// //
19422// This routine first tries to recover each segment by only using flips. If //
19423// no flip is possible, and the flag 'steinerflag' is set, it then tries to //
19424// insert Steiner points near or in the segment. //
19425// //
19426///////////////////////////////////////////////////////////////////////////////
19427
19428int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
19429 int steinerflag)
19430{
19431 triface searchtet, spintet;
19432 face sseg, *paryseg;
19433 point startpt, endpt;
19434 int success;
19435 int t1ver;
19436 long bak_inpoly_count = st_volref_count;
19437 long bak_segref_count = st_segref_count;
19438
19439 if (b->verbose > 1) {
19440 printf(" Recover segments [%s level = %2d] #: %ld.\n",
19441 (b->fliplinklevel > 0) ? "fixed" : "auto",
19442 (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
19443 subsegstack->objects);
19444 }
19445
19446 // Loop until 'subsegstack' is empty.
19447 while (subsegstack->objects > 0l) {
19448 // seglist is used as a stack.
19449 subsegstack->objects--;
19450 paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
19451 sseg = *paryseg;
19452
19453 // Check if this segment has been recovered.
19454 sstpivot1(sseg, searchtet);
19455 if (searchtet.tet != NULL) {
19456 continue; // Not a missing segment.
19457 }
19458
19459 startpt = sorg(sseg);
19460 endpt = sdest(sseg);
19461
19462 if (b->verbose > 2) {
19463 printf(" Recover segment (%d, %d).\n", pointmark(startpt),
19464 pointmark(endpt));
19465 }
19466
19467 success = 0;
19468
19469 if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
19470 success = 1;
19471 } else {
19472 // Try to recover it from the other direction.
19473 if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
19474 success = 1;
19475 }
19476 }
19477
19478 if (!success && fullsearch) {
19479 if (recoveredgebyflips(startpt, endpt, &searchtet, fullsearch)) {
19480 success = 1;
19481 }
19482 }
19483
19484 if (success) {
19485 // Segment is recovered. Insert it.
19486 // Let the segment remember an adjacent tet.
19487 sstbond1(sseg, searchtet);
19488 // Bond the segment to all tets containing it.
19489 spintet = searchtet;
19490 do {
19491 tssbond1(spintet, sseg);
19492 fnextself(spintet);
19493 } while (spintet.tet != searchtet.tet);
19494 } else {
19495 if (steinerflag > 0) {
19496 // Try to recover the segment but do not split it.
19497 if (addsteiner4recoversegment(&sseg, 0)) {
19498 success = 1;
19499 }
19500 if (!success && (steinerflag > 1)) {
19501 // Split the segment.
19502 addsteiner4recoversegment(&sseg, 1);
19503 success = 1;
19504 }
19505 }
19506 if (!success) {
19507 if (misseglist != NULL) {
19508 // Save this segment.
19509 misseglist->newindex((void **) &paryseg);
19510 *paryseg = sseg;
19511 }
19512 }
19513 }
19514
19515 } // while (subsegstack->objects > 0l)
19516
19517 if (steinerflag) {
19518 if (b->verbose > 1) {
19519 // Report the number of added Steiner points.
19520 if (st_volref_count > bak_inpoly_count) {
19521 printf(" Add %ld Steiner points in volume.\n",
19522 st_volref_count - bak_inpoly_count);
19523 }
19524 if (st_segref_count > bak_segref_count) {
19525 printf(" Add %ld Steiner points in segments.\n",
19526 st_segref_count - bak_segref_count);
19527 }
19528 }
19529 }
19530
19531 return 0;
19532}
19533
19534///////////////////////////////////////////////////////////////////////////////
19535// //
19536// recoverfacebyflips() Recover a face by flips. //
19537// //
19538// If 'searchsh' is not NULL, it is a subface to be recovered. It is only //
19539// used for checking self-intersections. //
19540// //
19541///////////////////////////////////////////////////////////////////////////////
19542
19543int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
19544 face *searchsh, triface* searchtet)
19545{
19546 triface spintet, flipedge;
19547 point pd, pe;
19548 enum interresult dir;
19549 flipconstraints fc;
19550 int types[2], poss[4], intflag;
19551 int success, success1;
19552 int t1ver;
19553 int i, j;
19554
19555
19556 fc.fac[0] = pa;
19557 fc.fac[1] = pb;
19558 fc.fac[2] = pc;
19559 fc.checkflipeligibility = 1;
19560 success = 0;
19561
19562 for (i = 0; i < 3 && !success; i++) {
19563 while (1) {
19564 // Get a tet containing the edge [a,b].
19565 point2tetorg(fc.fac[i], *searchtet);
19566 dir = finddirection(searchtet, fc.fac[(i+1)%3]);
19567 //assert(dir == ACROSSVERT);
19568 assert(dest(*searchtet) == fc.fac[(i+1)%3]);
19569 // Search the face [a,b,c]
19570 spintet = *searchtet;
19571 while (1) {
19572 if (apex(spintet) == fc.fac[(i+2)%3]) {
19573 // Found the face.
19574 *searchtet = spintet;
19575 // Return the face [a,b,c].
19576 for (j = i; j > 0; j--) {
19577 eprevself(*searchtet);
19578 }
19579 success = 1;
19580 break;
19581 }
19582 fnextself(spintet);
19583 if (spintet.tet == searchtet->tet) break;
19584 } // while (1)
19585 if (success) break;
19586 // The face is missing. Try to recover it.
19587 success1 = 0;
19588 // Find a crossing edge of this face.
19589 spintet = *searchtet;
19590 while (1) {
19591 pd = apex(spintet);
19592 pe = oppo(spintet);
19593 if ((pd != dummypoint) && (pe != dummypoint)) {
19594 // Check if [d,e] intersects [a,b,c]
19595 intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
19596 if (intflag > 0) {
19597 // By our assumptions, they can only intersect at a single point.
19598 if (intflag == 2) {
19599 // Check the intersection type.
19600 dir = (enum interresult) types[0];
19601 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
19602 // Go to the edge [d,e].
19603 edestoppo(spintet, flipedge); // [d,e,a,b]
19604 if (searchsh != NULL) {
19605 // Check if [e,d] is a segment.
19606 if (issubseg(flipedge)) {
19607 if (!b->quiet) {
19608 face checkseg;
19609 tsspivot1(flipedge, checkseg);
19610 printf("Found a segment and a subface intersect.\n");
19611 pd = farsorg(checkseg);
19612 pe = farsdest(checkseg);
19613 printf(" 1st: [%d, %d] %d.\n", pointmark(pd),
19614 pointmark(pe), shellmark(checkseg));
19615 printf(" 2nd: [%d,%d,%d] %d\n", pointmark(pa),
19616 pointmark(pb), pointmark(pc), shellmark(*searchsh));
19617 }
19618 terminatetetgen(this, 3);
19619 }
19620 }
19621 // Try to flip the edge [d,e].
19622 success1 = (removeedgebyflips(&flipedge, &fc) == 2);
19623 } else {
19624 if (dir == TOUCHFACE) {
19625 point touchpt, *parypt;
19626 if (poss[1] == 0) {
19627 touchpt = pd; // pd is a coplanar vertex.
19628 } else {
19629 touchpt = pe; // pe is a coplanar vertex.
19630 }
19631 if (pointtype(touchpt) == FREEVOLVERTEX) {
19632 // A volume Steiner point was added in this subface.
19633 // Split this subface by this point.
19634 face checksh, *parysh;
19635 int siloc = (int) ONFACE;
19636 int sbowat = 0; // Only split this subface.
19637 setpointtype(touchpt, FREEFACETVERTEX);
19638 sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
19639 st_volref_count--;
19640 st_facref_count++;
19641 // Queue this vertex for removal.
19642 subvertstack->newindex((void **) &parypt);
19643 *parypt = touchpt;
19644 // Queue new subfaces for recovery.
19645 // Put all new subfaces into stack for recovery.
19646 for (i = 0; i < caveshbdlist->objects; i++) {
19647 // Get an old subface at edge [a, b].
19648 parysh = (face *) fastlookup(caveshbdlist, i);
19649 spivot(*parysh, checksh); // The new subface [a, b, p].
19650 // Do not recover a deleted new face (degenerated).
19651 if (checksh.sh[3] != NULL) {
19652 subfacstack->newindex((void **) &parysh);
19653 *parysh = checksh;
19654 }
19655 }
19656 // Delete the old subfaces in sC(p).
19657 assert(caveshlist->objects == 1);
19658 for (i = 0; i < caveshlist->objects; i++) {
19659 parysh = (face *) fastlookup(caveshlist, i);
19660 shellfacedealloc(subfaces, parysh->sh);
19661 }
19662 // Clear working lists.
19663 caveshlist->restart();
19664 caveshbdlist->restart();
19665 cavesegshlist->restart();
19666 // We can return this function.
19667 searchsh->sh = NULL; // It has been split.
19668 success1 = 0;
19669 success = 1;
19670 } else {
19671 // It should be a PLC problem.
19672 if (pointtype(touchpt) == FREESEGVERTEX) {
19673 // A segment and a subface intersect.
19674 } else if (pointtype(touchpt) == FREEFACETVERTEX) {
19675 // Two facets self-intersect.
19676 }
19677 terminatetetgen(this, 3);
19678 }
19679 } else {
19680 assert(0); // Unknown cases. Debug.
19681 }
19682 }
19683 break;
19684 } else { // intflag == 4. Coplanar case.
19685 // This may be an input PLC error.
19686 assert(0);
19687 }
19688 } // if (intflag > 0)
19689 }
19690 fnextself(spintet);
19691 assert(spintet.tet != searchtet->tet);
19692 } // while (1)
19693 if (!success1) break;
19694 } // while (1)
19695 } // i
19696
19697 return success;
19698}
19699
19700///////////////////////////////////////////////////////////////////////////////
19701// //
19702// recoversubfaces() Recover all subfaces. //
19703// //
19704///////////////////////////////////////////////////////////////////////////////
19705
19706int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
19707{
19708 triface searchtet, neightet, spintet;
19709 face searchsh, neighsh, neineish, *parysh;
19710 face bdsegs[3];
19711 point startpt, endpt, apexpt, *parypt;
19712 point steinerpt;
19713 enum interresult dir;
19714 insertvertexflags ivf;
19715 int success;
19716 int t1ver;
19717 int i, j;
19718
19719 if (b->verbose > 1) {
19720 printf(" Recover subfaces [%s level = %2d] #: %ld.\n",
19721 (b->fliplinklevel > 0) ? "fixed" : "auto",
19722 (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
19723 subfacstack->objects);
19724 }
19725
19726 // Loop until 'subfacstack' is empty.
19727 while (subfacstack->objects > 0l) {
19728
19729 subfacstack->objects--;
19730 parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
19731 searchsh = *parysh;
19732
19733 if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
19734
19735 stpivot(searchsh, neightet);
19736 if (neightet.tet != NULL) continue; // Skip a recovered subface.
19737
19738
19739 if (b->verbose > 2) {
19740 printf(" Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
19741 pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
19742 }
19743
19744 // The three edges of the face need to be existed first.
19745 for (i = 0; i < 3; i++) {
19746 sspivot(searchsh, bdsegs[i]);
19747 if (bdsegs[i].sh != NULL) {
19748 // The segment must exist.
19749 sstpivot1(bdsegs[i], searchtet);
19750 if (searchtet.tet == NULL) {
19751 assert(0);
19752 }
19753 } else {
19754 // This edge is not a segment (due to a Steiner point).
19755 // Check whether it exists or not.
19756 success = 0;
19757 startpt = sorg(searchsh);
19758 endpt = sdest(searchsh);
19759 point2tetorg(startpt, searchtet);
19760 dir = finddirection(&searchtet, endpt);
19761 if (dir == ACROSSVERT) {
19762 if (dest(searchtet) == endpt) {
19763 success = 1;
19764 } else {
19765 //assert(0); // A PLC problem.
19766 terminatetetgen(this, 3);
19767 }
19768 } else {
19769 // The edge is missing. Try to recover it.
19770 if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
19771 success = 1;
19772 } else {
19773 if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
19774 success = 1;
19775 }
19776 }
19777 }
19778 if (success) {
19779 // Insert a temporary segment to protect this edge.
19780 makeshellface(subsegs, &(bdsegs[i]));
19781 setshvertices(bdsegs[i], startpt, endpt, NULL);
19782 smarktest2(bdsegs[i]); // It's a temporary segment.
19783 // Insert this segment into surface mesh.
19784 ssbond(searchsh, bdsegs[i]);
19785 spivot(searchsh, neighsh);
19786 if (neighsh.sh != NULL) {
19787 ssbond(neighsh, bdsegs[i]);
19788 }
19789 // Insert this segment into tetrahedralization.
19790 sstbond1(bdsegs[i], searchtet);
19791 // Bond the segment to all tets containing it.
19792 spintet = searchtet;
19793 do {
19794 tssbond1(spintet, bdsegs[i]);
19795 fnextself(spintet);
19796 } while (spintet.tet != searchtet.tet);
19797 } else {
19798 // An edge of this subface is missing. Can't recover this subface.
19799 // Delete any temporary segment that has been created.
19800 for (j = (i - 1); j >= 0; j--) {
19801 if (smarktest2ed(bdsegs[j])) {
19802 spivot(bdsegs[j], neineish);
19803 assert(neineish.sh != NULL);
19804 //if (neineish.sh != NULL) {
19805 ssdissolve(neineish);
19806 spivot(neineish, neighsh);
19807 if (neighsh.sh != NULL) {
19808 ssdissolve(neighsh);
19809 // There should be only two subfaces at this segment.
19810 spivotself(neighsh); // SELF_CHECK
19811 assert(neighsh.sh == neineish.sh);
19812 }
19813 //}
19814 sstpivot1(bdsegs[j], searchtet);
19815 assert(searchtet.tet != NULL);
19816 //if (searchtet.tet != NULL) {
19817 spintet = searchtet;
19818 while (1) {
19819 tssdissolve1(spintet);
19820 fnextself(spintet);
19821 if (spintet.tet == searchtet.tet) break;
19822 }
19823 //}
19824 shellfacedealloc(subsegs, bdsegs[j].sh);
19825 }
19826 } // j
19827 if (steinerflag) {
19828 // Add a Steiner point at the midpoint of this edge.
19829 if (b->verbose > 2) {
19830 printf(" Add a Steiner point in subedge (%d, %d).\n",
19831 pointmark(startpt), pointmark(endpt));
19832 }
19833 makepoint(&steinerpt, FREEFACETVERTEX);
19834 for (j = 0; j < 3; j++) {
19835 steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
19836 }
19837
19838 point2tetorg(startpt, searchtet); // Start from 'searchtet'.
19839 ivf.iloc = (int) OUTSIDE; // Need point location.
19840 ivf.bowywat = 1;
19841 ivf.lawson = 0;
19842 ivf.rejflag = 0;
19843 ivf.chkencflag = 0;
19844 ivf.sloc = (int) ONEDGE;
19845 ivf.sbowywat = 1; // Allow flips in facet.
19846 ivf.splitbdflag = 0;
19847 ivf.validflag = 1;
19848 ivf.respectbdflag = 1;
19849 ivf.assignmeshsize = b->metric;
19850 if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
19851 assert(0);
19852 }
19853 // Save this Steiner point (for removal).
19854 // Re-use the array 'subvertstack'.
19855 subvertstack->newindex((void **) &parypt);
19856 *parypt = steinerpt;
19857
19858 st_facref_count++;
19859 if (steinerleft > 0) steinerleft--;
19860 } // if (steinerflag)
19861 break;
19862 }
19863 }
19864 senextself(searchsh);
19865 } // i
19866
19867 if (i == 3) {
19868 // Recover the subface.
19869 startpt = sorg(searchsh);
19870 endpt = sdest(searchsh);
19871 apexpt = sapex(searchsh);
19872
19873 success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
19874
19875 // Delete any temporary segment that has been created.
19876 for (j = 0; j < 3; j++) {
19877 if (smarktest2ed(bdsegs[j])) {
19878 spivot(bdsegs[j], neineish);
19879 assert(neineish.sh != NULL);
19880 //if (neineish.sh != NULL) {
19881 ssdissolve(neineish);
19882 spivot(neineish, neighsh);
19883 if (neighsh.sh != NULL) {
19884 ssdissolve(neighsh);
19885 // There should be only two subfaces at this segment.
19886 spivotself(neighsh); // SELF_CHECK
19887 assert(neighsh.sh == neineish.sh);
19888 }
19889 //}
19890 sstpivot1(bdsegs[j], neightet);
19891 assert(neightet.tet != NULL);
19892 //if (neightet.tet != NULL) {
19893 spintet = neightet;
19894 while (1) {
19895 tssdissolve1(spintet);
19896 fnextself(spintet);
19897 if (spintet.tet == neightet.tet) break;
19898 }
19899 //}
19900 shellfacedealloc(subsegs, bdsegs[j].sh);
19901 }
19902 } // j
19903
19904 if (success) {
19905 if (searchsh.sh != NULL) {
19906 // Face is recovered. Insert it.
19907 tsbond(searchtet, searchsh);
19908 fsymself(searchtet);
19909 sesymself(searchsh);
19910 tsbond(searchtet, searchsh);
19911 }
19912 } else {
19913 if (steinerflag) {
19914 // Add a Steiner point at the barycenter of this subface.
19915 if (b->verbose > 2) {
19916 printf(" Add a Steiner point in subface (%d, %d, %d).\n",
19917 pointmark(startpt), pointmark(endpt), pointmark(apexpt));
19918 }
19919 makepoint(&steinerpt, FREEFACETVERTEX);
19920 for (j = 0; j < 3; j++) {
19921 steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
19922 }
19923
19924 point2tetorg(startpt, searchtet); // Start from 'searchtet'.
19925 ivf.iloc = (int) OUTSIDE; // Need point location.
19926 ivf.bowywat = 1;
19927 ivf.lawson = 0;
19928 ivf.rejflag = 0;
19929 ivf.chkencflag = 0;
19930 ivf.sloc = (int) ONFACE;
19931 ivf.sbowywat = 1; // Allow flips in facet.
19932 ivf.splitbdflag = 0;
19933 ivf.validflag = 1;
19934 ivf.respectbdflag = 1;
19935 ivf.assignmeshsize = b->metric;
19936 if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
19937 assert(0);
19938 }
19939 // Save this Steiner point (for removal).
19940 // Re-use the array 'subvertstack'.
19941 subvertstack->newindex((void **) &parypt);
19942 *parypt = steinerpt;
19943
19944 st_facref_count++;
19945 if (steinerleft > 0) steinerleft--;
19946 } // if (steinerflag)
19947 }
19948 } else {
19949 success = 0;
19950 }
19951
19952 if (!success) {
19953 if (misshlist != NULL) {
19954 // Save this subface.
19955 misshlist->newindex((void **) &parysh);
19956 *parysh = searchsh;
19957 }
19958 }
19959
19960 } // while (subfacstack->objects > 0l)
19961
19962 return 0;
19963}
19964
19965///////////////////////////////////////////////////////////////////////////////
19966// //
19967// getvertexstar() Return the star of a vertex. //
19968// //
19969// If the flag 'fullstar' is set, return the complete star of this vertex. //
19970// Otherwise, only a part of the star which is bounded by facets is returned.//
19971// //
19972// 'tetlist' returns the list of tets in the star of the vertex 'searchpt'. //
19973// Every tet in 'tetlist' is at the face opposing to 'searchpt'. //
19974// //
19975// 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
19976// //
19977// 'shlist' returns the list of subfaces in the star. Each subface must face //
19978// to the interior of this star. //
19979// //
19980///////////////////////////////////////////////////////////////////////////////
19981
19982int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
19983 arraypool* vertlist, arraypool* shlist)
19984{
19985 triface searchtet, neightet, *parytet;
19986 face checksh, *parysh;
19987 point pt, *parypt;
19988 int collectflag;
19989 int t1ver;
19990 int i, j;
19991
19992 point2tetorg(searchpt, searchtet);
19993
19994 // Go to the opposite face (the link face) of the vertex.
19995 enextesymself(searchtet);
19996 //assert(oppo(searchtet) == searchpt);
19997 infect(searchtet); // Collect this tet (link face).
19998 tetlist->newindex((void **) &parytet);
19999 *parytet = searchtet;
20000 if (vertlist != NULL) {
20001 // Collect three (link) vertices.
20002 j = (searchtet.ver & 3); // The current vertex index.
20003 for (i = 1; i < 4; i++) {
20004 pt = (point) searchtet.tet[4 + ((j + i) % 4)];
20005 pinfect(pt);
20006 vertlist->newindex((void **) &parypt);
20007 *parypt = pt;
20008 }
20009 }
20010
20011 collectflag = 1;
20012 esym(searchtet, neightet);
20013 if (issubface(neightet)) {
20014 if (shlist != NULL) {
20015 tspivot(neightet, checksh);
20016 if (!sinfected(checksh)) {
20017 // Collect this subface (link edge).
20018 sinfected(checksh);
20019 shlist->newindex((void **) &parysh);
20020 *parysh = checksh;
20021 }
20022 }
20023 if (!fullstar) {
20024 collectflag = 0;
20025 }
20026 }
20027 if (collectflag) {
20028 fsymself(neightet); // Goto the adj tet of this face.
20029 esymself(neightet); // Goto the oppo face of this vertex.
20030 // assert(oppo(neightet) == searchpt);
20031 infect(neightet); // Collect this tet (link face).
20032 tetlist->newindex((void **) &parytet);
20033 *parytet = neightet;
20034 if (vertlist != NULL) {
20035 // Collect its apex.
20036 pt = apex(neightet);
20037 pinfect(pt);
20038 vertlist->newindex((void **) &parypt);
20039 *parypt = pt;
20040 }
20041 } // if (collectflag)
20042
20043 // Continue to collect all tets in the star.
20044 for (i = 0; i < tetlist->objects; i++) {
20045 searchtet = * (triface *) fastlookup(tetlist, i);
20046 // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
20047 // tet at the current edge is already collected.
20048 // Check the neighbors at the other two edges of this face.
20049 for (j = 0; j < 2; j++) {
20050 collectflag = 1;
20051 enextself(searchtet);
20052 esym(searchtet, neightet);
20053 if (issubface(neightet)) {
20054 if (shlist != NULL) {
20055 tspivot(neightet, checksh);
20056 if (!sinfected(checksh)) {
20057 // Collect this subface (link edge).
20058 sinfected(checksh);
20059 shlist->newindex((void **) &parysh);
20060 *parysh = checksh;
20061 }
20062 }
20063 if (!fullstar) {
20064 collectflag = 0;
20065 }
20066 }
20067 if (collectflag) {
20068 fsymself(neightet);
20069 if (!infected(neightet)) {
20070 esymself(neightet); // Go to the face opposite to 'searchpt'.
20071 infect(neightet);
20072 tetlist->newindex((void **) &parytet);
20073 *parytet = neightet;
20074 if (vertlist != NULL) {
20075 // Check if a vertex is collected.
20076 pt = apex(neightet);
20077 if (!pinfected(pt)) {
20078 pinfect(pt);
20079 vertlist->newindex((void **) &parypt);
20080 *parypt = pt;
20081 }
20082 }
20083 } // if (!infected(neightet))
20084 } // if (collectflag)
20085 } // j
20086 } // i
20087
20088
20089 // Uninfect the list of tets and vertices.
20090 for (i = 0; i < tetlist->objects; i++) {
20091 parytet = (triface *) fastlookup(tetlist, i);
20092 uninfect(*parytet);
20093 }
20094
20095 if (vertlist != NULL) {
20096 for (i = 0; i < vertlist->objects; i++) {
20097 parypt = (point *) fastlookup(vertlist, i);
20098 puninfect(*parypt);
20099 }
20100 }
20101
20102 if (shlist != NULL) {
20103 for (i = 0; i < shlist->objects; i++) {
20104 parysh = (face *) fastlookup(shlist, i);
20105 suninfect(*parysh);
20106 }
20107 }
20108
20109 return (int) tetlist->objects;
20110}
20111
20112///////////////////////////////////////////////////////////////////////////////
20113// //
20114// getedge() Get a tetrahedron having the two endpoints. //
20115// //
20116// The method here is to search the second vertex in the link faces of the //
20117// first vertex. The global array 'cavetetlist' is re-used for searching. //
20118// //
20119// This function is used for the case when the mesh is non-convex. Otherwise,//
20120// the function finddirection() should be faster than this. //
20121// //
20122///////////////////////////////////////////////////////////////////////////////
20123
20124int tetgenmesh::getedge(point e1, point e2, triface *tedge)
20125{
20126 triface searchtet, neightet, *parytet;
20127 point pt;
20128 int done;
20129 int i, j;
20130
20131 if (b->verbose > 2) {
20132 printf(" Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
20133 }
20134
20135 // Quickly check if 'tedge' is just this edge.
20136 if (!isdeadtet(*tedge)) {
20137 if (org(*tedge) == e1) {
20138 if (dest(*tedge) == e2) {
20139 return 1;
20140 }
20141 } else if (org(*tedge) == e2) {
20142 if (dest(*tedge) == e1) {
20143 esymself(*tedge);
20144 return 1;
20145 }
20146 }
20147 }
20148
20149 // Search for the edge [e1, e2].
20150 point2tetorg(e1, *tedge);
20151 finddirection(tedge, e2);
20152 if (dest(*tedge) == e2) {
20153 return 1;
20154 } else {
20155 // Search for the edge [e2, e1].
20156 point2tetorg(e2, *tedge);
20157 finddirection(tedge, e1);
20158 if (dest(*tedge) == e1) {
20159 esymself(*tedge);
20160 return 1;
20161 }
20162 }
20163
20164
20165 // Go to the link face of e1.
20166 point2tetorg(e1, searchtet);
20167 enextesymself(searchtet);
20168 //assert(oppo(searchtet) == e1);
20169
20170 assert(cavebdrylist->objects == 0l); // It will re-use this list.
20171 arraypool *tetlist = cavebdrylist;
20172
20173 // Search e2.
20174 for (i = 0; i < 3; i++) {
20175 pt = apex(searchtet);
20176 if (pt == e2) {
20177 // Found. 'searchtet' is [#,#,e2,e1].
20178 eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
20179 return 1;
20180 }
20181 enextself(searchtet);
20182 }
20183
20184 // Get the adjacent link face at 'searchtet'.
20185 fnext(searchtet, neightet);
20186 esymself(neightet);
20187 // assert(oppo(neightet) == e1);
20188 pt = apex(neightet);
20189 if (pt == e2) {
20190 // Found. 'neightet' is [#,#,e2,e1].
20191 eorgoppo(neightet, *tedge); // [e1,e2,#,#].
20192 return 1;
20193 }
20194
20195 // Continue searching in the link face of e1.
20196 infect(searchtet);
20197 tetlist->newindex((void **) &parytet);
20198 *parytet = searchtet;
20199 infect(neightet);
20200 tetlist->newindex((void **) &parytet);
20201 *parytet = neightet;
20202
20203 done = 0;
20204
20205 for (i = 0; (i < tetlist->objects) && !done; i++) {
20206 parytet = (triface *) fastlookup(tetlist, i);
20207 searchtet = *parytet;
20208 for (j = 0; (j < 2) && !done; j++) {
20209 enextself(searchtet);
20210 fnext(searchtet, neightet);
20211 if (!infected(neightet)) {
20212 esymself(neightet);
20213 pt = apex(neightet);
20214 if (pt == e2) {
20215 // Found. 'neightet' is [#,#,e2,e1].
20216 eorgoppo(neightet, *tedge);
20217 done = 1;
20218 } else {
20219 infect(neightet);
20220 tetlist->newindex((void **) &parytet);
20221 *parytet = neightet;
20222 }
20223 }
20224 } // j
20225 } // i
20226
20227 // Uninfect the list of visited tets.
20228 for (i = 0; i < tetlist->objects; i++) {
20229 parytet = (triface *) fastlookup(tetlist, i);
20230 uninfect(*parytet);
20231 }
20232 tetlist->restart();
20233
20234 return done;
20235}
20236
20237///////////////////////////////////////////////////////////////////////////////
20238// //
20239// reduceedgesatvertex() Reduce the number of edges at a given vertex. //
20240// //
20241// 'endptlist' contains the endpoints of edges connecting at the vertex. //
20242// //
20243///////////////////////////////////////////////////////////////////////////////
20244
20245int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
20246{
20247 triface searchtet;
20248 point *pendpt, *parypt;
20249 enum interresult dir;
20250 flipconstraints fc;
20251 int reduceflag;
20252 int count;
20253 int n, i, j;
20254
20255
20256 fc.remvert = startpt;
20257 fc.checkflipeligibility = 1;
20258
20259 while (1) {
20260
20261 count = 0;
20262
20263 for (i = 0; i < endptlist->objects; i++) {
20264 pendpt = (point *) fastlookup(endptlist, i);
20265 if (*pendpt == dummypoint) {
20266 continue; // Do not reduce a virtual edge.
20267 }
20268 reduceflag = 0;
20269 // Find the edge.
20270 if (nonconvex) {
20271 if (getedge(startpt, *pendpt, &searchtet)) {
20272 dir = ACROSSVERT;
20273 } else {
20274 // The edge does not exist (was flipped).
20275 dir = INTERSECT;
20276 }
20277 } else {
20278 point2tetorg(startpt, searchtet);
20279 dir = finddirection(&searchtet, *pendpt);
20280 }
20281 if (dir == ACROSSVERT) {
20282 if (dest(searchtet) == *pendpt) {
20283 // Do not flip a segment.
20284 if (!issubseg(searchtet)) {
20285 n = removeedgebyflips(&searchtet, &fc);
20286 if (n == 2) {
20287 reduceflag = 1;
20288 }
20289 }
20290 } else {
20291 assert(0); // A plc problem.
20292 }
20293 } else {
20294 // The edge has been flipped.
20295 reduceflag = 1;
20296 }
20297 if (reduceflag) {
20298 count++;
20299 // Move the last vertex into this slot.
20300 j = endptlist->objects - 1;
20301 parypt = (point *) fastlookup(endptlist, j);
20302 *pendpt = *parypt;
20303 endptlist->objects--;
20304 i--;
20305 }
20306 } // i
20307
20308 if (count == 0) {
20309 // No edge is reduced.
20310 break;
20311 }
20312
20313 } // while (1)
20314
20315 return (int) endptlist->objects;
20316}
20317
20318///////////////////////////////////////////////////////////////////////////////
20319// //
20320// removevertexbyflips() Remove a vertex by flips. //
20321// //
20322// This routine attempts to remove the given vertex 'rempt' (p) from the //
20323// tetrahedralization (T) by a sequence of flips. //
20324// //
20325// The algorithm used here is a simple edge reduce method. Suppose there are //
20326// n edges connected at p. We try to reduce the number of edges by flipping //
20327// any edge (not a segment) that is connecting at p. //
20328// //
20329// Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
20330// can be successfully removed. //
20331// //
20332///////////////////////////////////////////////////////////////////////////////
20333
20334int tetgenmesh::removevertexbyflips(point steinerpt)
20335{
20336 triface *fliptets = NULL, wrktets[4];
20337 triface searchtet, spintet, neightet;
20338 face parentsh, spinsh, checksh;
20339 face leftseg, rightseg, checkseg;
20340 point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
20341 flipconstraints fc;
20342 enum verttype vt;
20343 enum locateresult loc;
20344 int valence, removeflag;
20345 int slawson;
20346 int t1ver;
20347 int n, i;
20348
20349 vt = pointtype(steinerpt);
20350
20351 if (vt == FREESEGVERTEX) {
20352 sdecode(point2sh(steinerpt), leftseg);
20353 assert(leftseg.sh != NULL);
20354 leftseg.shver = 0;
20355 if (sdest(leftseg) == steinerpt) {
20356 senext(leftseg, rightseg);
20357 spivotself(rightseg);
20358 assert(rightseg.sh != NULL);
20359 rightseg.shver = 0;
20360 assert(sorg(rightseg) == steinerpt);
20361 } else {
20362 assert(sorg(leftseg) == steinerpt);
20363 rightseg = leftseg;
20364 senext2(rightseg, leftseg);
20365 spivotself(leftseg);
20366 assert(leftseg.sh != NULL);
20367 leftseg.shver = 0;
20368 assert(sdest(leftseg) == steinerpt);
20369 }
20370 lpt = sorg(leftseg);
20371 rpt = sdest(rightseg);
20372 if (b->verbose > 2) {
20373 printf(" Removing Steiner point %d in segment (%d, %d).\n",
20374 pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
20375
20376 }
20377 } else if (vt == FREEFACETVERTEX) {
20378 if (b->verbose > 2) {
20379 printf(" Removing Steiner point %d in facet.\n",
20380 pointmark(steinerpt));
20381 }
20382 } else if (vt == FREEVOLVERTEX) {
20383 if (b->verbose > 2) {
20384 printf(" Removing Steiner point %d in volume.\n",
20385 pointmark(steinerpt));
20386 }
20387 } else if (vt == VOLVERTEX) {
20388 if (b->verbose > 2) {
20389 printf(" Removing a point %d in volume.\n",
20390 pointmark(steinerpt));
20391 }
20392 } else {
20393 // It is not a Steiner point.
20394 return 0;
20395 }
20396
20397 // Try to reduce the number of edges at 'p' by flips.
20398 getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
20399 cavetetlist->restart(); // This list may be re-used.
20400 if (cavetetvertlist->objects > 3l) {
20401 valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
20402 } else {
20403 valence = cavetetvertlist->objects;
20404 }
20405 assert(cavetetlist->objects == 0l);
20406 cavetetvertlist->restart();
20407
20408 removeflag = 0;
20409
20410 if (valence == 4) {
20411 // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
20412 // vertices. This case is due to that 'p' is not exactly on the segment.
20413 point2tetorg(steinerpt, searchtet);
20414 loc = INTETRAHEDRON;
20415 removeflag = 1;
20416 } else if (valence == 5) {
20417 // There are 5 edges.
20418 if (vt == FREESEGVERTEX) {
20419 sstpivot1(leftseg, searchtet);
20420 if (org(searchtet) != steinerpt) {
20421 esymself(searchtet);
20422 }
20423 assert(org(searchtet) == steinerpt);
20424 assert(dest(searchtet) == lpt);
20425 i = 0; // Count the numbe of tet at the edge [p,lpt].
20426 neightet.tet = NULL; // Init the face.
20427 spintet = searchtet;
20428 while (1) {
20429 i++;
20430 if (apex(spintet) == rpt) {
20431 // Remember the face containing the edge [lpt, rpt].
20432 neightet = spintet;
20433 }
20434 fnextself(spintet);
20435 if (spintet.tet == searchtet.tet) break;
20436 }
20437 if (i == 3) {
20438 // This case has been checked below.
20439 } else if (i == 4) {
20440 // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
20441 // at [p,rpt]. There must be a face [p, lpt, rpt].
20442 if (apex(neightet) == rpt) {
20443 // The edge (segment) has been already recovered!
20444 // Check if a 6-to-2 flip is possible (to remove 'p').
20445 // Let 'searchtet' be [p,d,a,b]
20446 esym(neightet, searchtet);
20447 enextself(searchtet);
20448 // Check if there are exactly three tets at edge [p,d].
20449 wrktets[0] = searchtet; // [p,d,a,b]
20450 for (i = 0; i < 2; i++) {
20451 fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
20452 }
20453 if (apex(wrktets[0]) == oppo(wrktets[2])) {
20454 loc = ONFACE;
20455 removeflag = 1;
20456 }
20457 }
20458 }
20459 } else if (vt == FREEFACETVERTEX) {
20460 // It is possible to do a 6-to-2 flip to remove the vertex.
20461 point2tetorg(steinerpt, searchtet);
20462 // Get the three faces of 'searchtet' which share at p.
20463 // All faces has p as origin.
20464 wrktets[0] = searchtet;
20465 wrktets[1] = searchtet;
20466 esymself(wrktets[1]);
20467 enextself(wrktets[1]);
20468 wrktets[2] = searchtet;
20469 eprevself(wrktets[2]);
20470 esymself(wrktets[2]);
20471 // All internal edges of the six tets have valance either 3 or 4.
20472 // Get one edge which has valance 3.
20473 searchtet.tet = NULL;
20474 for (i = 0; i < 3; i++) {
20475 spintet = wrktets[i];
20476 valence = 0;
20477 while (1) {
20478 valence++;
20479 fnextself(spintet);
20480 if (spintet.tet == wrktets[i].tet) break;
20481 }
20482 if (valence == 3) {
20483 // Found the edge.
20484 searchtet = wrktets[i];
20485 break;
20486 } else {
20487 assert(valence == 4);
20488 }
20489 }
20490 assert(searchtet.tet != NULL);
20491 // Note, we do not detach the three subfaces at p.
20492 // They will be removed within a 4-to-1 flip.
20493 loc = ONFACE;
20494 removeflag = 1;
20495 } else {
20496 // assert(0); DEBUG IT
20497 }
20498 //removeflag = 1;
20499 }
20500
20501 if (!removeflag) {
20502 if (vt == FREESEGVERTEX) {
20503 // Check is it possible to recover the edge [lpt,rpt].
20504 // The condition to check is: Whether each tet containing 'leftseg' is
20505 // adjacent to a tet containing 'rightseg'.
20506 sstpivot1(leftseg, searchtet);
20507 if (org(searchtet) != steinerpt) {
20508 esymself(searchtet);
20509 }
20510 assert(org(searchtet) == steinerpt);
20511 assert(dest(searchtet) == lpt);
20512 spintet = searchtet;
20513 while (1) {
20514 // Go to the bottom face of this tet.
20515 eprev(spintet, neightet);
20516 esymself(neightet); // [steinerpt, p1, p2, lpt]
20517 // Get the adjacent tet.
20518 fsymself(neightet); // [p1, steinerpt, p2, rpt]
20519 if (oppo(neightet) != rpt) {
20520 // Found a non-matching adjacent tet.
20521 break;
20522 }
20523 fnextself(spintet);
20524 if (spintet.tet == searchtet.tet) {
20525 // 'searchtet' is [p,d,p1,p2].
20526 loc = ONEDGE;
20527 removeflag = 1;
20528 break;
20529 }
20530 }
20531 } // if (vt == FREESEGVERTEX)
20532 }
20533
20534 if (!removeflag) {
20535 if (vt == FREESEGVERTEX) {
20536 // Check if the edge [lpt, rpt] exists.
20537 if (getedge(lpt, rpt, &searchtet)) {
20538 // We have recovered this edge. Shift the vertex into the volume.
20539 // We can recover this edge if the subfaces are not recovered yet.
20540 if (!checksubfaceflag) {
20541 // Remove the vertex from the surface mesh.
20542 // This will re-create the segment [lpt, rpt] and re-triangulate
20543 // all the facets at the segment.
20544 // Detach the subsegments from their surrounding tets.
20545 for (i = 0; i < 2; i++) {
20546 checkseg = (i == 0) ? leftseg : rightseg;
20547 sstpivot1(checkseg, neightet);
20548 spintet = neightet;
20549 while (1) {
20550 tssdissolve1(spintet);
20551 fnextself(spintet);
20552 if (spintet.tet == neightet.tet) break;
20553 }
20554 sstdissolve1(checkseg);
20555 } // i
20556 slawson = 1; // Do lawson flip after removal.
20557 spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
20558 sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
20559 // Clear the list for new subfaces.
20560 caveshbdlist->restart();
20561 // Insert the new segment.
20562 assert(org(searchtet) == lpt);
20563 assert(dest(searchtet) == rpt);
20564 sstbond1(rightseg, searchtet);
20565 spintet = searchtet;
20566 while (1) {
20567 tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
20568 assert(checkseg.sh == NULL); // FOR DEBUG ONLY
20569 tssbond1(spintet, rightseg);
20570 fnextself(spintet);
20571 if (spintet.tet == searchtet.tet) break;
20572 }
20573 // The Steiner point has been shifted into the volume.
20574 setpointtype(steinerpt, FREEVOLVERTEX);
20575 st_segref_count--;
20576 st_volref_count++;
20577 return 1;
20578 } // if (!checksubfaceflag)
20579 } // if (getedge(...))
20580 } // if (vt == FREESEGVERTEX)
20581 } // if (!removeflag)
20582
20583 if (!removeflag) {
20584 return 0;
20585 }
20586
20587 assert(org(searchtet) == steinerpt);
20588
20589 if (vt == FREESEGVERTEX) {
20590 // Detach the subsegments from their surronding tets.
20591 for (i = 0; i < 2; i++) {
20592 checkseg = (i == 0) ? leftseg : rightseg;
20593 sstpivot1(checkseg, neightet);
20594 spintet = neightet;
20595 while (1) {
20596 tssdissolve1(spintet);
20597 fnextself(spintet);
20598 if (spintet.tet == neightet.tet) break;
20599 }
20600 sstdissolve1(checkseg);
20601 } // i
20602 if (checksubfaceflag) {
20603 // Detach the subfaces at the subsegments from their attached tets.
20604 for (i = 0; i < 2; i++) {
20605 checkseg = (i == 0) ? leftseg : rightseg;
20606 spivot(checkseg, parentsh);
20607 if (parentsh.sh != NULL) {
20608 spinsh = parentsh;
20609 while (1) {
20610 stpivot(spinsh, neightet);
20611 if (neightet.tet != NULL) {
20612 tsdissolve(neightet);
20613 }
20614 sesymself(spinsh);
20615 stpivot(spinsh, neightet);
20616 if (neightet.tet != NULL) {
20617 tsdissolve(neightet);
20618 }
20619 stdissolve(spinsh);
20620 spivotself(spinsh); // Go to the next subface.
20621 if (spinsh.sh == parentsh.sh) break;
20622 }
20623 }
20624 } // i
20625 } // if (checksubfaceflag)
20626 }
20627
20628 if (loc == INTETRAHEDRON) {
20629 // Collect the four tets containing 'p'.
20630 fliptets = new triface[4];
20631 fliptets[0] = searchtet; // [p,d,a,b]
20632 for (i = 0; i < 2; i++) {
20633 fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
20634 }
20635 eprev(fliptets[0], fliptets[3]);
20636 fnextself(fliptets[3]); // it is [a,p,b,c]
20637 eprevself(fliptets[3]);
20638 esymself(fliptets[3]); // [a,b,c,p].
20639 // Remove p by a 4-to-1 flip.
20640 //flip41(fliptets, 1, 0, 0);
20641 flip41(fliptets, 1, &fc);
20642 //recenttet = fliptets[0];
20643 } else if (loc == ONFACE) {
20644 // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
20645 // face [a,b,c]. Let 'searchtet' be the tet [p,d,a,b].
20646 // Collect the six tets containing 'p'.
20647 fliptets = new triface[6];
20648 fliptets[0] = searchtet; // [p,d,a,b]
20649 for (i = 0; i < 2; i++) {
20650 fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
20651 }
20652 eprev(fliptets[0], fliptets[3]);
20653 fnextself(fliptets[3]); // [a,p,b,e]
20654 esymself(fliptets[3]); // [p,a,e,b]
20655 eprevself(fliptets[3]); // [e,p,a,b]
20656 for (i = 3; i < 5; i++) {
20657 fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
20658 }
20659 if (vt == FREEFACETVERTEX) {
20660 // We need to determine the location of three subfaces at p.
20661 valence = 0; // Re-use it.
20662 // Check if subfaces are all located in the lower three tets.
20663 // i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a].
20664 for (i = 3; i < 6; i++) {
20665 if (issubface(fliptets[i])) valence++;
20666 }
20667 if (valence > 0) {
20668 assert(valence == 2);
20669 // We must do 3-to-2 flip in the upper part. We simply re-arrange
20670 // the six tets.
20671 for (i = 0; i < 3; i++) {
20672 esym(fliptets[i+3], wrktets[i]);
20673 esym(fliptets[i], fliptets[i+3]);
20674 fliptets[i] = wrktets[i];
20675 }
20676 // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
20677 wrktets[1] = fliptets[1];
20678 fliptets[1] = fliptets[2];
20679 fliptets[2] = wrktets[1];
20680 wrktets[1] = fliptets[4];
20681 fliptets[4] = fliptets[5];
20682 fliptets[5] = wrktets[1];
20683 }
20684 }
20685 // Remove p by a 6-to-2 flip, which is a combination of two flips:
20686 // a 3-to-2 (deletes the edge [e,p]), and
20687 // a 4-to-1 (deletes the vertex p).
20688 // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
20689 // two new tets: [a,b,c,p] and [b,a,c,e]. The new tet [a,b,c,p] is
20690 // degenerate (has zero volume). It will be deleted in the followed
20691 // 4-to-1 flip.
20692 //flip32(&(fliptets[3]), 1, 0, 0);
20693 flip32(&(fliptets[3]), 1, &fc);
20694 // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
20695 // This creates a new tet [a,b,c,d].
20696 //flip41(fliptets, 1, 0, 0);
20697 flip41(fliptets, 1, &fc);
20698 //recenttet = fliptets[0];
20699 } else if (loc == ONEDGE) {
20700 // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
20701 // tets sharing at edge [e,d] originally. We number the link vertices
20702 // of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
20703 // Count the number of tets at edge [e,p] and [p,d] (this is n).
20704 n = 0;
20705 spintet = searchtet;
20706 while (1) {
20707 n++;
20708 fnextself(spintet);
20709 if (spintet.tet == searchtet.tet) break;
20710 }
20711 assert(n >= 3);
20712 // Collect the 2n tets containing 'p'.
20713 fliptets = new triface[2 * n];
20714 fliptets[0] = searchtet; // [p,b,p_0,p_1]
20715 for (i = 0; i < (n - 1); i++) {
20716 fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
20717 }
20718 eprev(fliptets[0], fliptets[n]);
20719 fnextself(fliptets[n]); // [p_0,p,p_1,e]
20720 esymself(fliptets[n]); // [p,p_0,e,p_1]
20721 eprevself(fliptets[n]); // [e,p,p_0,p_1]
20722 for (i = n; i < (2 * n - 1); i++) {
20723 fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
20724 }
20725 // Remove p by a 2n-to-n flip, it is a sequence of n flips:
20726 // - Do a 2-to-3 flip on
20727 // [p_0,p_1,p,d] and
20728 // [p,p_1,p_0,e].
20729 // This produces:
20730 // [e,d,p_0,p_1],
20731 // [e,d,p_1,p] (degenerated), and
20732 // [e,d,p,p_0] (degenerated).
20733 wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
20734 eprevself(wrktets[0]); // [p_0,p,d,p_1]
20735 esymself(wrktets[0]); // [p,p_0,p_1,d]
20736 enextself(wrktets[0]); // [p_0,p_1,p,d] [0]
20737 wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
20738 enextself(wrktets[1]); // [p,p_0,e,p_1]
20739 esymself(wrktets[1]); // [p_0,p,p_1,e]
20740 eprevself(wrktets[1]); // [p_1,p_0,p,e] [1]
20741 //flip23(wrktets, 1, 0, 0);
20742 flip23(wrktets, 1, &fc);
20743 // Save the new tet [e,d,p,p_0] (degenerated).
20744 fliptets[n] = wrktets[2];
20745 // Save the new tet [e,d,p_0,p_1].
20746 fliptets[0] = wrktets[0];
20747 // - Repeat from i = 1 to n-2: (n - 2) flips
20748 // - Do a 3-to-2 flip on
20749 // [p,p_i,d,e],
20750 // [p,p_i,e,p_i+1], and
20751 // [p,p_i,p_i+1,d].
20752 // This produces:
20753 // [d,e,p_i+1,p_i], and
20754 // [e,d,p_i+1,p] (degenerated).
20755 for (i = 1; i < (n - 1); i++) {
20756 wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
20757 enextself(wrktets[0]); // [d,p_i,e,p] (...)
20758 esymself(wrktets[0]); // [p_i,d,p,e] (...)
20759 eprevself(wrktets[0]); // [p,p_i,d,e] (degenerated) [0].
20760 wrktets[1] = fliptets[n+i]; // [e,p,p_i,p_i+1]
20761 enextself(wrktets[1]); // [p,p_i,e,p_i+1] [1]
20762 wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
20763 eprevself(wrktets[2]); // [p_i,p,d,p_i+1]
20764 esymself(wrktets[2]); // [p,p_i,p_i+1,d] [2]
20765 //flip32(wrktets, 1, 0, 0);
20766 flip32(wrktets, 1, &fc);
20767 // Save the new tet [e,d,p_i,p_i+1]. // FOR DEBUG ONLY
20768 fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
20769 esymself(fliptets[i]); // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
20770 }
20771 // - Do a 4-to-1 flip on
20772 // [p,p_0,e,d], [d,e,p_0,p],
20773 // [p,p_0,d,p_n-1], [e,p_n-1,p_0,p],
20774 // [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
20775 // [e,d,p_n-1,p].
20776 // This produces
20777 // [e,d,p_n-1,p_0] and
20778 // deletes p.
20779 wrktets[3] = wrktets[1]; // [e,d,p_n-1,p] (degenerated) [3]
20780 wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
20781 eprevself(wrktets[0]); // [p,e,d,p_0] (...)
20782 esymself(wrktets[0]); // [e,p,p_0,d] (...)
20783 enextself(wrktets[0]); // [p,p_0,e,d] (degenerated) [0]
20784 wrktets[1] = fliptets[n-1]; // [p,d,p_n-1,p_0]
20785 esymself(wrktets[1]); // [d,p,p_0,p_n-1]
20786 enextself(wrktets[1]); // [p,p_0,d,p_n-1] [1]
20787 wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
20788 enextself(wrktets[2]); // [p_p_n-1,e,p_0]
20789 esymself(wrktets[2]); // [p_n-1,p,p_0,e]
20790 enextself(wrktets[2]); // [p,p_0,p_n-1,e] [2]
20791 //flip41(wrktets, 1, 0, 0);
20792 flip41(wrktets, 1, &fc);
20793 // Save the new tet [e,d,p_n-1,p_0] // FOR DEBUG ONLY
20794 fliptets[n-1] = wrktets[0]; // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
20795 //recenttet = fliptets[0];
20796 } else {
20797 assert(0); // Unknown location.
20798 } // if (iloc == ...)
20799
20800 delete [] fliptets;
20801
20802 if (vt == FREESEGVERTEX) {
20803 // Remove the vertex from the surface mesh.
20804 // This will re-create the segment [lpt, rpt] and re-triangulate
20805 // all the facets at the segment.
20806 // Only do lawson flip when subfaces are not recovery yet.
20807 slawson = (checksubfaceflag ? 0 : 1);
20808 spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
20809 sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
20810
20811 // The original segment is returned in 'rightseg'.
20812 rightseg.shver = 0;
20813 assert(sorg(rightseg) == lpt);
20814 assert(sdest(rightseg) == rpt);
20815
20816 // Insert the new segment.
20817 point2tetorg(lpt, searchtet);
20818 finddirection(&searchtet, rpt);
20819 assert(dest(searchtet) == rpt);
20820 sstbond1(rightseg, searchtet);
20821 spintet = searchtet;
20822 while (1) {
20823 tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
20824 assert(checkseg.sh == NULL); // FOR DEBUG ONLY
20825 tssbond1(spintet, rightseg);
20826 fnextself(spintet);
20827 if (spintet.tet == searchtet.tet) break;
20828 }
20829
20830 if (checksubfaceflag) {
20831 // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
20832 spivot(rightseg, parentsh);
20833 if (parentsh.sh != NULL) {
20834 spinsh = parentsh;
20835 while (1) {
20836 if (sorg(spinsh) != lpt) {
20837 sesymself(spinsh);
20838 assert(sorg(spinsh) == lpt);
20839 }
20840 assert(sdest(spinsh) == rpt);
20841 apexpt = sapex(spinsh);
20842 // Find the adjacent tet of [lpt,rpt,apexpt];
20843 spintet = searchtet;
20844 while (1) {
20845 if (apex(spintet) == apexpt) {
20846 tsbond(spintet, spinsh);
20847 sesymself(spinsh); // Get to another side of this face.
20848 fsym(spintet, neightet);
20849 tsbond(neightet, spinsh);
20850 sesymself(spinsh); // Get back to the original side.
20851 break;
20852 }
20853 fnextself(spintet);
20854 assert(spintet.tet != searchtet.tet);
20855 //if (spintet.tet == searchtet.tet) break;
20856 }
20857 spivotself(spinsh);
20858 if (spinsh.sh == parentsh.sh) break;
20859 }
20860 }
20861 } // if (checksubfaceflag)
20862
20863 // Clear the set of new subfaces.
20864 caveshbdlist->restart();
20865 } // if (vt == FREESEGVERTEX)
20866
20867 // The point has been removed.
20868 if (pointtype(steinerpt) != UNUSEDVERTEX) {
20869 setpointtype(steinerpt, UNUSEDVERTEX);
20870 unuverts++;
20871 }
20872 if (vt != VOLVERTEX) {
20873 // Update the correspinding counters.
20874 if (vt == FREESEGVERTEX) {
20875 st_segref_count--;
20876 } else if (vt == FREEFACETVERTEX) {
20877 st_facref_count--;
20878 } else if (vt == FREEVOLVERTEX) {
20879 st_volref_count--;
20880 }
20881 if (steinerleft > 0) steinerleft++;
20882 }
20883
20884 return 1;
20885}
20886
20887///////////////////////////////////////////////////////////////////////////////
20888// //
20889// suppressbdrysteinerpoint() Suppress a boundary Steiner point //
20890// //
20891///////////////////////////////////////////////////////////////////////////////
20892
20893int tetgenmesh::suppressbdrysteinerpoint(point steinerpt)
20894{
20895 face parentsh, spinsh, *parysh;
20896 face leftseg, rightseg;
20897 point lpt = NULL, rpt = NULL;
20898 int i;
20899
20900 verttype vt = pointtype(steinerpt);
20901
20902 if (vt == FREESEGVERTEX) {
20903 sdecode(point2sh(steinerpt), leftseg);
20904 leftseg.shver = 0;
20905 if (sdest(leftseg) == steinerpt) {
20906 senext(leftseg, rightseg);
20907 spivotself(rightseg);
20908 assert(rightseg.sh != NULL);
20909 rightseg.shver = 0;
20910 assert(sorg(rightseg) == steinerpt);
20911 } else {
20912 assert(sorg(leftseg) == steinerpt);
20913 rightseg = leftseg;
20914 senext2(rightseg, leftseg);
20915 spivotself(leftseg);
20916 assert(leftseg.sh != NULL);
20917 leftseg.shver = 0;
20918 assert(sdest(leftseg) == steinerpt);
20919 }
20920 lpt = sorg(leftseg);
20921 rpt = sdest(rightseg);
20922 if (b->verbose > 2) {
20923 printf(" Suppressing Steiner point %d in segment (%d, %d).\n",
20924 pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
20925 }
20926 // Get all subfaces at the left segment [lpt, steinerpt].
20927 spivot(leftseg, parentsh);
20928 spinsh = parentsh;
20929 while (1) {
20930 cavesegshlist->newindex((void **) &parysh);
20931 *parysh = spinsh;
20932 // Orient the face consistently.
20933 if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
20934 spivotself(spinsh);
20935 if (spinsh.sh == NULL) break;
20936 if (spinsh.sh == parentsh.sh) break;
20937 }
20938 if (cavesegshlist->objects < 2) {
20939 // It is a single segment. Not handle it yet.
20940 cavesegshlist->restart();
20941 return 0;
20942 }
20943 } else if (vt == FREEFACETVERTEX) {
20944 if (b->verbose > 2) {
20945 printf(" Suppressing Steiner point %d from facet.\n",
20946 pointmark(steinerpt));
20947 }
20948 sdecode(point2sh(steinerpt), parentsh);
20949 // A facet Steiner point. There are exactly two sectors.
20950 for (i = 0; i < 2; i++) {
20951 cavesegshlist->newindex((void **) &parysh);
20952 *parysh = parentsh;
20953 sesymself(parentsh);
20954 }
20955 } else {
20956 return 0;
20957 }
20958
20959 triface searchtet, neightet, *parytet;
20960 point pa, pb, pc, pd;
20961 REAL v1[3], v2[3], len, u;
20962
20963 REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
20964 REAL ori, minvol, smallvol;
20965 int samplesize;
20966 int it, j, k;
20967
20968 int n = (int) cavesegshlist->objects;
20969 point *newsteiners = new point[n];
20970 for (i = 0; i < n; i++) newsteiners[i] = NULL;
20971
20972 // Search for each sector an interior vertex.
20973 for (i = 0; i < cavesegshlist->objects; i++) {
20974 parysh = (face *) fastlookup(cavesegshlist, i);
20975 stpivot(*parysh, searchtet);
20976 // Skip it if it is outside.
20977 if (ishulltet(searchtet)) continue;
20978 // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
20979 // opposite. Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
20980 // Moreover, subfaces are oriented towards the interior of the ball.
20981 setpoint2tet(steinerpt, encode(searchtet));
20982 getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
20983 // Calculate the searching vector.
20984 pa = sorg(*parysh);
20985 pb = sdest(*parysh);
20986 pc = sapex(*parysh);
20987 facenormal(pa, pb, pc, v1, 1, NULL);
20988 len = sqrt(dot(v1, v1));
20989 assert(len > 0.0);
20990 v1[0] /= len;
20991 v1[1] /= len;
20992 v1[2] /= len;
20993 if (vt == FREESEGVERTEX) {
20994 parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
20995 pd = sapex(*parysh);
20996 facenormal(pb, pa, pd, v2, 1, NULL);
20997 len = sqrt(dot(v2, v2));
20998 assert(len > 0.0);
20999 v2[0] /= len;
21000 v2[1] /= len;
21001 v2[2] /= len;
21002 // Average the two vectors.
21003 v1[0] = 0.5 * (v1[0] + v2[0]);
21004 v1[1] = 0.5 * (v1[1] + v2[1]);
21005 v1[2] = 0.5 * (v1[2] + v2[2]);
21006 }
21007 // Search the intersection of the ray starting from 'steinerpt' to
21008 // the search direction 'v1' and the shell of the half-ball.
21009 // - Construct an endpoint.
21010 len = distance(pa, pb);
21011 v2[0] = steinerpt[0] + len * v1[0];
21012 v2[1] = steinerpt[1] + len * v1[1];
21013 v2[2] = steinerpt[2] + len * v1[2];
21014 for (j = 0; j < cavetetlist->objects; j++) {
21015 parytet = (triface *) fastlookup(cavetetlist, j);
21016 pa = org(*parytet);
21017 pb = dest(*parytet);
21018 pc = apex(*parytet);
21019 // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
21020 // is the apex, and three sides are defined by the triangle
21021 // [pa, pb, pc].
21022 ori = orient3d(steinerpt, pa, pb, v2);
21023 if (ori >= 0) {
21024 ori = orient3d(steinerpt, pb, pc, v2);
21025 if (ori >= 0) {
21026 ori = orient3d(steinerpt, pc, pa, v2);
21027 if (ori >= 0) {
21028 // Found! Calculate the intersection.
21029 planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
21030 assert(u != 0.0);
21031 break;
21032 }
21033 }
21034 }
21035 } // j
21036 assert(j < cavetetlist->objects); // There must be an intersection.
21037 // Close the ball by adding the subfaces.
21038 for (j = 0; j < caveshlist->objects; j++) {
21039 parysh = (face *) fastlookup(caveshlist, j);
21040 stpivot(*parysh, neightet);
21041 cavetetlist->newindex((void **) &parytet);
21042 *parytet = neightet;
21043 }
21044 // Search a best point inside the segment [startpt, steinerpt].
21045 it = 0;
21046 samplesize = 100;
21047 v1[0] = steinerpt[0] - startpt[0];
21048 v1[1] = steinerpt[1] - startpt[1];
21049 v1[2] = steinerpt[2] - startpt[2];
21050 minvol = -1.0;
21051 while (it < 3) {
21052 for (j = 1; j < samplesize - 1; j++) {
21053 samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
21054 samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
21055 samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
21056 // Find the minimum volume for 'samplept'.
21057 smallvol = -1;
21058 for (k = 0; k < cavetetlist->objects; k++) {
21059 parytet = (triface *) fastlookup(cavetetlist, k);
21060 pa = org(*parytet);
21061 pb = dest(*parytet);
21062 pc = apex(*parytet);
21063 ori = orient3d(pb, pa, pc, samplept);
21064 if (ori <= 0) {
21065 break; // An invalid tet.
21066 }
21067 if (smallvol == -1) {
21068 smallvol = ori;
21069 } else {
21070 if (ori < smallvol) smallvol = ori;
21071 }
21072 } // k
21073 if (k == cavetetlist->objects) {
21074 // Found a valid point. Remember it.
21075 if (minvol == -1.0) {
21076 candpt[0] = samplept[0];
21077 candpt[1] = samplept[1];
21078 candpt[2] = samplept[2];
21079 minvol = smallvol;
21080 } else {
21081 if (minvol < smallvol) {
21082 // It is a better location. Remember it.
21083 candpt[0] = samplept[0];
21084 candpt[1] = samplept[1];
21085 candpt[2] = samplept[2];
21086 minvol = smallvol;
21087 } else {
21088 // No improvement of smallest volume.
21089 // Since we are searching along the line [startpt, steinerpy],
21090 // The smallest volume can only be decreased later.
21091 break;
21092 }
21093 }
21094 }
21095 } // j
21096 if (minvol > 0) break;
21097 samplesize *= 10;
21098 it++;
21099 } // while (it < 3)
21100 if (minvol == -1.0) {
21101 // Failed to find a valid point.
21102 cavetetlist->restart();
21103 caveshlist->restart();
21104 break;
21105 }
21106 // Create a new Steiner point inside this section.
21107 makepoint(&(newsteiners[i]), FREEVOLVERTEX);
21108 newsteiners[i][0] = candpt[0];
21109 newsteiners[i][1] = candpt[1];
21110 newsteiners[i][2] = candpt[2];
21111 cavetetlist->restart();
21112 caveshlist->restart();
21113 } // i
21114
21115 if (i < cavesegshlist->objects) {
21116 // Failed to suppress the vertex.
21117 for (; i > 0; i--) {
21118 if (newsteiners[i - 1] != NULL) {
21119 pointdealloc(newsteiners[i - 1]);
21120 }
21121 }
21122 delete [] newsteiners;
21123 cavesegshlist->restart();
21124 return 0;
21125 }
21126
21127 // Remove p from the segment or the facet.
21128 triface newtet, newface, spintet;
21129 face newsh, neighsh;
21130 face *splitseg, checkseg;
21131 int slawson = 0; // Do not do flip afterword.
21132 int t1ver;
21133
21134 if (vt == FREESEGVERTEX) {
21135 // Detach 'leftseg' and 'rightseg' from their adjacent tets.
21136 // These two subsegments will be deleted.
21137 sstpivot1(leftseg, neightet);
21138 spintet = neightet;
21139 while (1) {
21140 tssdissolve1(spintet);
21141 fnextself(spintet);
21142 if (spintet.tet == neightet.tet) break;
21143 }
21144 sstpivot1(rightseg, neightet);
21145 spintet = neightet;
21146 while (1) {
21147 tssdissolve1(spintet);
21148 fnextself(spintet);
21149 if (spintet.tet == neightet.tet) break;
21150 }
21151 }
21152
21153 // Loop through all sectors bounded by facets at this segment.
21154 // Within each sector, create a new Steiner point 'np', and replace 'p'
21155 // by 'np' for all tets in this sector.
21156 for (i = 0; i < cavesegshlist->objects; i++) {
21157 parysh = (face *) fastlookup(cavesegshlist, i);
21158 // 'parysh' is the face [lpt, steinerpt, #].
21159 stpivot(*parysh, neightet);
21160 // Get all tets in this sector.
21161 setpoint2tet(steinerpt, encode(neightet));
21162 getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
21163 if (!ishulltet(neightet)) {
21164 // Within each tet in the ball, replace 'p' by 'np'.
21165 for (j = 0; j < cavetetlist->objects; j++) {
21166 parytet = (triface *) fastlookup(cavetetlist, j);
21167 setoppo(*parytet, newsteiners[i]);
21168 } // j
21169 // Point to a parent tet.
21170 parytet = (triface *) fastlookup(cavetetlist, 0);
21171 setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet));
21172 st_volref_count++;
21173 if (steinerleft > 0) steinerleft--;
21174 }
21175 // Disconnect the set of boundary faces. They're temporarily open faces.
21176 // They will be connected to the new tets after 'p' is removed.
21177 for (j = 0; j < caveshlist->objects; j++) {
21178 // Get a boundary face.
21179 parysh = (face *) fastlookup(caveshlist, j);
21180 stpivot(*parysh, neightet);
21181 //assert(apex(neightet) == newpt);
21182 // Clear the connection at this face.
21183 dissolve(neightet);
21184 tsdissolve(neightet);
21185 }
21186 // Clear the working lists.
21187 cavetetlist->restart();
21188 caveshlist->restart();
21189 } // i
21190 cavesegshlist->restart();
21191
21192 if (vt == FREESEGVERTEX) {
21193 spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21194 splitseg = &rightseg;
21195 } else {
21196 if (sdest(parentsh) == steinerpt) {
21197 senextself(parentsh);
21198 } else if (sapex(parentsh) == steinerpt) {
21199 senext2self(parentsh);
21200 }
21201 assert(sorg(parentsh) == steinerpt);
21202 splitseg = NULL;
21203 }
21204 sremovevertex(steinerpt, &parentsh, splitseg, slawson);
21205
21206 if (vt == FREESEGVERTEX) {
21207 // The original segment is returned in 'rightseg'.
21208 rightseg.shver = 0;
21209 }
21210
21211 // For each new subface, create two new tets at each side of it.
21212 // Both of the two new tets have its opposite be dummypoint.
21213 for (i = 0; i < caveshbdlist->objects; i++) {
21214 parysh = (face *) fastlookup(caveshbdlist, i);
21215 sinfect(*parysh); // Mark it for connecting new tets.
21216 newsh = *parysh;
21217 pa = sorg(newsh);
21218 pb = sdest(newsh);
21219 pc = sapex(newsh);
21220 maketetrahedron(&newtet);
21221 maketetrahedron(&neightet);
21222 setvertices(newtet, pa, pb, pc, dummypoint);
21223 setvertices(neightet, pb, pa, pc, dummypoint);
21224 bond(newtet, neightet);
21225 tsbond(newtet, newsh);
21226 sesymself(newsh);
21227 tsbond(neightet, newsh);
21228 }
21229 // Temporarily increase the hullsize.
21230 hullsize += (caveshbdlist->objects * 2l);
21231
21232 if (vt == FREESEGVERTEX) {
21233 // Connecting new tets at the recovered segment.
21234 spivot(rightseg, parentsh);
21235 assert(parentsh.sh != NULL);
21236 spinsh = parentsh;
21237 while (1) {
21238 if (sorg(spinsh) != lpt) sesymself(spinsh);
21239 // Get the new tet at this subface.
21240 stpivot(spinsh, newtet);
21241 tssbond1(newtet, rightseg);
21242 // Go to the other face at this segment.
21243 spivot(spinsh, neighsh);
21244 if (sorg(neighsh) != lpt) sesymself(neighsh);
21245 sesymself(neighsh);
21246 stpivot(neighsh, neightet);
21247 tssbond1(neightet, rightseg);
21248 sstbond1(rightseg, neightet);
21249 // Connecting two adjacent tets at this segment.
21250 esymself(newtet);
21251 esymself(neightet);
21252 // Connect the two tets (at rightseg) together.
21253 bond(newtet, neightet);
21254 // Go to the next subface.
21255 spivotself(spinsh);
21256 if (spinsh.sh == parentsh.sh) break;
21257 }
21258 }
21259
21260 // Connecting new tets at new subfaces together.
21261 for (i = 0; i < caveshbdlist->objects; i++) {
21262 parysh = (face *) fastlookup(caveshbdlist, i);
21263 newsh = *parysh;
21264 //assert(sinfected(newsh));
21265 // Each new subface contains two new tets.
21266 for (k = 0; k < 2; k++) {
21267 stpivot(newsh, newtet);
21268 for (j = 0; j < 3; j++) {
21269 // Check if this side is open.
21270 esym(newtet, newface);
21271 if (newface.tet[newface.ver & 3] == NULL) {
21272 // An open face. Connect it to its adjacent tet.
21273 sspivot(newsh, checkseg);
21274 if (checkseg.sh != NULL) {
21275 // A segment. It must not be the recovered segment.
21276 tssbond1(newtet, checkseg);
21277 sstbond1(checkseg, newtet);
21278 }
21279 spivot(newsh, neighsh);
21280 if (neighsh.sh != NULL) {
21281 // The adjacent subface exists. It's not a dangling segment.
21282 if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
21283 stpivot(neighsh, neightet);
21284 if (sinfected(neighsh)) {
21285 esymself(neightet);
21286 assert(neightet.tet[neightet.ver & 3] == NULL);
21287 } else {
21288 // Search for an open face at this edge.
21289 spintet = neightet;
21290 while (1) {
21291 esym(spintet, searchtet);
21292 fsym(searchtet, spintet);
21293 if (spintet.tet == NULL) break;
21294 assert(spintet.tet != neightet.tet);
21295 }
21296 // Found an open face at 'searchtet'.
21297 neightet = searchtet;
21298 }
21299 } else {
21300 // The edge (at 'newsh') is a dangling segment.
21301 assert(checkseg.sh != NULL);
21302 // Get an adjacent tet at this segment.
21303 sstpivot1(checkseg, neightet);
21304 assert(!isdeadtet(neightet));
21305 if (org(neightet) != sdest(newsh)) esymself(neightet);
21306 assert((org(neightet) == sdest(newsh)) &&
21307 (dest(neightet) == sorg(newsh)));
21308 // Search for an open face at this edge.
21309 spintet = neightet;
21310 while (1) {
21311 esym(spintet, searchtet);
21312 fsym(searchtet, spintet);
21313 if (spintet.tet == NULL) break;
21314 assert(spintet.tet != neightet.tet);
21315 }
21316 // Found an open face at 'searchtet'.
21317 neightet = searchtet;
21318 }
21319 pc = apex(newface);
21320 if (apex(neightet) == steinerpt) {
21321 // Exterior case. The 'neightet' is a hull tet which contain
21322 // 'steinerpt'. It will be deleted after 'steinerpt' is removed.
21323 assert(pc == dummypoint);
21324 caveoldtetlist->newindex((void **) &parytet);
21325 *parytet = neightet;
21326 // Connect newface to the adjacent hull tet of 'neightet', which
21327 // has the same edge as 'newface', and does not has 'steinerpt'.
21328 fnextself(neightet);
21329 } else {
21330 if (pc == dummypoint) {
21331 if (apex(neightet) != dummypoint) {
21332 setapex(newface, apex(neightet));
21333 // A hull tet has turned into an interior tet.
21334 hullsize--; // Must update the hullsize.
21335 }
21336 }
21337 }
21338 bond(newface, neightet);
21339 } // if (newface.tet[newface.ver & 3] == NULL)
21340 enextself(newtet);
21341 senextself(newsh);
21342 } // j
21343 sesymself(newsh);
21344 } // k
21345 } // i
21346
21347 // Unmark all new subfaces.
21348 for (i = 0; i < caveshbdlist->objects; i++) {
21349 parysh = (face *) fastlookup(caveshbdlist, i);
21350 suninfect(*parysh);
21351 }
21352 caveshbdlist->restart();
21353
21354 if (caveoldtetlist->objects > 0l) {
21355 // Delete hull tets which contain 'steinerpt'.
21356 for (i = 0; i < caveoldtetlist->objects; i++) {
21357 parytet = (triface *) fastlookup(caveoldtetlist, i);
21358 tetrahedrondealloc(parytet->tet);
21359 }
21360 // Must update the hullsize.
21361 hullsize -= caveoldtetlist->objects;
21362 caveoldtetlist->restart();
21363 }
21364
21365 setpointtype(steinerpt, UNUSEDVERTEX);
21366 unuverts++;
21367 if (vt == FREESEGVERTEX) {
21368 st_segref_count--;
21369 } else { // vt == FREEFACETVERTEX
21370 st_facref_count--;
21371 }
21372 if (steinerleft > 0) steinerleft++; // We've removed a Steiner points.
21373
21374
21375 point *parypt;
21376 int steinercount = 0;
21377
21378 int bak_fliplinklevel = b->fliplinklevel;
21379 b->fliplinklevel = 100000; // Unlimited flip level.
21380
21381 // Try to remove newly added Steiner points.
21382 for (i = 0; i < n; i++) {
21383 if (newsteiners[i] != NULL) {
21384 if (!removevertexbyflips(newsteiners[i])) {
21385 if (b->nobisect_param > 0) { // Not -Y0
21386 // Save it in subvertstack for removal.
21387 subvertstack->newindex((void **) &parypt);
21388 *parypt = newsteiners[i];
21389 }
21390 steinercount++;
21391 }
21392 }
21393 }
21394
21395 b->fliplinklevel = bak_fliplinklevel;
21396
21397 if (steinercount > 0) {
21398 if (b->verbose > 2) {
21399 printf(" Added %d interior Steiner points.\n", steinercount);
21400 }
21401 }
21402
21403 delete [] newsteiners;
21404
21405 return 1;
21406}
21407
21408
21409///////////////////////////////////////////////////////////////////////////////
21410// //
21411// suppresssteinerpoints() Suppress Steiner points. //
21412// //
21413// All Steiner points have been saved in 'subvertstack' in the routines //
21414// carveholes() and suppresssteinerpoint(). //
21415// Each Steiner point is either removed or shifted into the interior. //
21416// //
21417///////////////////////////////////////////////////////////////////////////////
21418
21419int tetgenmesh::suppresssteinerpoints()
21420{
21421
21422 if (!b->quiet) {
21423 printf("Suppressing Steiner points ...\n");
21424 }
21425
21426 point rempt, *parypt;
21427
21428 int bak_fliplinklevel = b->fliplinklevel;
21429 b->fliplinklevel = 100000; // Unlimited flip level.
21430 int suppcount = 0, remcount = 0;
21431 int i;
21432
21433 // Try to suppress boundary Steiner points.
21434 for (i = 0; i < subvertstack->objects; i++) {
21435 parypt = (point *) fastlookup(subvertstack, i);
21436 rempt = *parypt;
21437 if (pointtype(rempt) != UNUSEDVERTEX) {
21438 if ((pointtype(rempt) == FREESEGVERTEX) ||
21439 (pointtype(rempt) == FREEFACETVERTEX)) {
21440 if (suppressbdrysteinerpoint(rempt)) {
21441 suppcount++;
21442 }
21443 }
21444 }
21445 } // i
21446
21447 if (suppcount > 0) {
21448 if (b->verbose) {
21449 printf(" Suppressed %d boundary Steiner points.\n", suppcount);
21450 }
21451 }
21452
21453 if (b->nobisect_param > 0) { // -Y1
21454 for (i = 0; i < subvertstack->objects; i++) {
21455 parypt = (point *) fastlookup(subvertstack, i);
21456 rempt = *parypt;
21457 if (pointtype(rempt) != UNUSEDVERTEX) {
21458 if (pointtype(rempt) == FREEVOLVERTEX) {
21459 if (removevertexbyflips(rempt)) {
21460 remcount++;
21461 }
21462 }
21463 }
21464 }
21465 }
21466
21467 if (remcount > 0) {
21468 if (b->verbose) {
21469 printf(" Removed %d interior Steiner points.\n", remcount);
21470 }
21471 }
21472
21473 b->fliplinklevel = bak_fliplinklevel;
21474
21475 if (b->nobisect_param > 1) { // -Y2
21476 // Smooth interior Steiner points.
21477 optparameters opm;
21478 triface *parytet;
21479 point *ppt;
21480 REAL ori;
21481 int smtcount, count, ivcount;
21482 int nt, j;
21483
21484 // Point smooth options.
21485 opm.max_min_volume = 1;
21486 opm.numofsearchdirs = 20;
21487 opm.searchstep = 0.001;
21488 opm.maxiter = 30; // Limit the maximum iterations.
21489
21490 smtcount = 0;
21491
21492 do {
21493
21494 nt = 0;
21495
21496 while (1) {
21497 count = 0;
21498 ivcount = 0; // Clear the inverted count.
21499
21500 for (i = 0; i < subvertstack->objects; i++) {
21501 parypt = (point *) fastlookup(subvertstack, i);
21502 rempt = *parypt;
21503 if (pointtype(rempt) == FREEVOLVERTEX) {
21504 getvertexstar(1, rempt, cavetetlist, NULL, NULL);
21505 // Calculate the initial smallest volume (maybe zero or negative).
21506 for (j = 0; j < cavetetlist->objects; j++) {
21507 parytet = (triface *) fastlookup(cavetetlist, j);
21508 ppt = (point *) &(parytet->tet[4]);
21509 ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
21510 if (j == 0) {
21511 opm.initval = ori;
21512 } else {
21513 if (opm.initval > ori) opm.initval = ori;
21514 }
21515 }
21516 if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
21517 count++;
21518 }
21519 if (opm.imprval <= 0.0) {
21520 ivcount++; // The mesh contains inverted elements.
21521 }
21522 cavetetlist->restart();
21523 }
21524 } // i
21525
21526 smtcount += count;
21527
21528 if (count == 0) {
21529 // No point has been smoothed.
21530 break;
21531 }
21532
21533 nt++;
21534 if (nt > 2) {
21535 break; // Already three iterations.
21536 }
21537 } // while
21538
21539 if (ivcount > 0) {
21540 // There are inverted elements!
21541 if (opm.maxiter > 0) {
21542 // Set unlimited smoothing steps. Try again.
21543 opm.numofsearchdirs = 30;
21544 opm.searchstep = 0.0001;
21545 opm.maxiter = -1;
21546 continue;
21547 }
21548 }
21549
21550 break;
21551 } while (1); // Additional loop for (ivcount > 0)
21552
21553 if (ivcount > 0) {
21554 printf("BUG Report! The mesh contain inverted elements.\n");
21555 }
21556
21557 if (b->verbose) {
21558 if (smtcount > 0) {
21559 printf(" Smoothed %d Steiner points.\n", smtcount);
21560 }
21561 }
21562 } // -Y2
21563
21564 subvertstack->restart();
21565
21566 return 1;
21567}
21568
21569///////////////////////////////////////////////////////////////////////////////
21570// //
21571// recoverboundary() Recover segments and facets. //
21572// //
21573///////////////////////////////////////////////////////////////////////////////
21574
21575void tetgenmesh::recoverboundary(clock_t& tv)
21576{
21577 arraypool *misseglist, *misshlist;
21578 arraypool *bdrysteinerptlist;
21579 face searchsh, *parysh;
21580 face searchseg, *paryseg;
21581 point rempt, *parypt;
21582 long ms; // The number of missing segments/subfaces.
21583 int nit; // The number of iterations.
21584 int s, i;
21585
21586 // Counters.
21587 long bak_segref_count, bak_facref_count, bak_volref_count;
21588
21589 if (!b->quiet) {
21590 printf("Recovering boundaries...\n");
21591 }
21592
21593
21594 if (b->verbose) {
21595 printf(" Recovering segments.\n");
21596 }
21597
21598 // Segments will be introduced.
21599 checksubsegflag = 1;
21600
21601 misseglist = new arraypool(sizeof(face), 8);
21602 bdrysteinerptlist = new arraypool(sizeof(point), 8);
21603
21604 // In random order.
21605 subsegs->traversalinit();
21606 for (i = 0; i < subsegs->items; i++) {
21607 s = randomnation(i + 1);
21608 // Move the s-th seg to the i-th.
21609 subsegstack->newindex((void **) &paryseg);
21610 *paryseg = * (face *) fastlookup(subsegstack, s);
21611 // Put i-th seg to be the s-th.
21612 searchseg.sh = shellfacetraverse(subsegs);
21613 paryseg = (face *) fastlookup(subsegstack, s);
21614 *paryseg = searchseg;
21615 }
21616
21617 // The init number of missing segments.
21618 ms = subsegs->items;
21619 nit = 0;
21620 if (b->fliplinklevel < 0) {
21621 autofliplinklevel = 1; // Init value.
21622 }
21623
21624 // First, trying to recover segments by only doing flips.
21625 while (1) {
21626 recoversegments(misseglist, 0, 0);
21627
21628 if (misseglist->objects > 0) {
21629 if (b->fliplinklevel >= 0) {
21630 break;
21631 } else {
21632 if (misseglist->objects >= ms) {
21633 nit++;
21634 if (nit >= 3) {
21635 //break;
21636 // Do the last round with unbounded flip link level.
21637 b->fliplinklevel = 100000;
21638 }
21639 } else {
21640 ms = misseglist->objects;
21641 if (nit > 0) {
21642 nit--;
21643 }
21644 }
21645 for (i = 0; i < misseglist->objects; i++) {
21646 subsegstack->newindex((void **) &paryseg);
21647 *paryseg = * (face *) fastlookup(misseglist, i);
21648 }
21649 misseglist->restart();
21650 autofliplinklevel+=b->fliplinklevelinc;
21651 }
21652 } else {
21653 // All segments are recovered.
21654 break;
21655 }
21656 } // while (1)
21657
21658 if (b->verbose) {
21659 printf(" %ld (%ld) segments are recovered (missing).\n",
21660 subsegs->items - misseglist->objects, misseglist->objects);
21661 }
21662
21663 if (misseglist->objects > 0) {
21664 // Second, trying to recover segments by doing more flips (fullsearch).
21665 while (misseglist->objects > 0) {
21666 ms = misseglist->objects;
21667 for (i = 0; i < misseglist->objects; i++) {
21668 subsegstack->newindex((void **) &paryseg);
21669 *paryseg = * (face *) fastlookup(misseglist, i);
21670 }
21671 misseglist->restart();
21672
21673 recoversegments(misseglist, 1, 0);
21674
21675 if (misseglist->objects < ms) {
21676 // The number of missing segments is reduced.
21677 continue;
21678 } else {
21679 break;
21680 }
21681 }
21682 if (b->verbose) {
21683 printf(" %ld (%ld) segments are recovered (missing).\n",
21684 subsegs->items - misseglist->objects, misseglist->objects);
21685 }
21686 }
21687
21688 if (misseglist->objects > 0) {
21689 // Third, trying to recover segments by doing more flips (fullsearch)
21690 // and adding Steiner points in the volume.
21691 while (misseglist->objects > 0) {
21692 ms = misseglist->objects;
21693 for (i = 0; i < misseglist->objects; i++) {
21694 subsegstack->newindex((void **) &paryseg);
21695 *paryseg = * (face *) fastlookup(misseglist, i);
21696 }
21697 misseglist->restart();
21698
21699 recoversegments(misseglist, 1, 1);
21700
21701 if (misseglist->objects < ms) {
21702 // The number of missing segments is reduced.
21703 continue;
21704 } else {
21705 break;
21706 }
21707 }
21708 if (b->verbose) {
21709 printf(" Added %ld Steiner points in volume.\n", st_volref_count);
21710 }
21711 }
21712
21713 if (misseglist->objects > 0) {
21714 // Last, trying to recover segments by doing more flips (fullsearch),
21715 // and adding Steiner points in the volume, and splitting segments.
21716 long bak_inpoly_count = st_volref_count; //st_inpoly_count;
21717 for (i = 0; i < misseglist->objects; i++) {
21718 subsegstack->newindex((void **) &paryseg);
21719 *paryseg = * (face *) fastlookup(misseglist, i);
21720 }
21721 misseglist->restart();
21722
21723 recoversegments(misseglist, 1, 2);
21724
21725 if (b->verbose) {
21726 printf(" Added %ld Steiner points in segments.\n", st_segref_count);
21727 if (st_volref_count > bak_inpoly_count) {
21728 printf(" Added another %ld Steiner points in volume.\n",
21729 st_volref_count - bak_inpoly_count);
21730 }
21731 }
21732 assert(misseglist->objects == 0l);
21733 }
21734
21735
21736 if (st_segref_count > 0) {
21737 // Try to remove the Steiner points added in segments.
21738 bak_segref_count = st_segref_count;
21739 bak_volref_count = st_volref_count;
21740 for (i = 0; i < subvertstack->objects; i++) {
21741 // Get the Steiner point.
21742 parypt = (point *) fastlookup(subvertstack, i);
21743 rempt = *parypt;
21744 if (!removevertexbyflips(rempt)) {
21745 // Save it in list.
21746 bdrysteinerptlist->newindex((void **) &parypt);
21747 *parypt = rempt;
21748 }
21749 }
21750 if (b->verbose) {
21751 if (st_segref_count < bak_segref_count) {
21752 if (bak_volref_count < st_volref_count) {
21753 printf(" Suppressed %ld Steiner points in segments.\n",
21754 st_volref_count - bak_volref_count);
21755 }
21756 if ((st_segref_count + (st_volref_count - bak_volref_count)) <
21757 bak_segref_count) {
21758 printf(" Removed %ld Steiner points in segments.\n",
21759 bak_segref_count -
21760 (st_segref_count + (st_volref_count - bak_volref_count)));
21761 }
21762 }
21763 }
21764 subvertstack->restart();
21765 }
21766
21767
21768 tv = clock();
21769
21770 if (b->verbose) {
21771 printf(" Recovering facets.\n");
21772 }
21773
21774 // Subfaces will be introduced.
21775 checksubfaceflag = 1;
21776
21777 misshlist = new arraypool(sizeof(face), 8);
21778
21779 // Randomly order the subfaces.
21780 subfaces->traversalinit();
21781 for (i = 0; i < subfaces->items; i++) {
21782 s = randomnation(i + 1);
21783 // Move the s-th subface to the i-th.
21784 subfacstack->newindex((void **) &parysh);
21785 *parysh = * (face *) fastlookup(subfacstack, s);
21786 // Put i-th subface to be the s-th.
21787 searchsh.sh = shellfacetraverse(subfaces);
21788 parysh = (face *) fastlookup(subfacstack, s);
21789 *parysh = searchsh;
21790 }
21791
21792 ms = subfaces->items;
21793 nit = 0;
21794 b->fliplinklevel = -1; // Init.
21795 if (b->fliplinklevel < 0) {
21796 autofliplinklevel = 1; // Init value.
21797 }
21798
21799 while (1) {
21800 recoversubfaces(misshlist, 0);
21801
21802 if (misshlist->objects > 0) {
21803 if (b->fliplinklevel >= 0) {
21804 break;
21805 } else {
21806 if (misshlist->objects >= ms) {
21807 nit++;
21808 if (nit >= 3) {
21809 //break;
21810 // Do the last round with unbounded flip link level.
21811 b->fliplinklevel = 100000;
21812 }
21813 } else {
21814 ms = misshlist->objects;
21815 if (nit > 0) {
21816 nit--;
21817 }
21818 }
21819 for (i = 0; i < misshlist->objects; i++) {
21820 subfacstack->newindex((void **) &parysh);
21821 *parysh = * (face *) fastlookup(misshlist, i);
21822 }
21823 misshlist->restart();
21824 autofliplinklevel+=b->fliplinklevelinc;
21825 }
21826 } else {
21827 // All subfaces are recovered.
21828 break;
21829 }
21830 } // while (1)
21831
21832 if (b->verbose) {
21833 printf(" %ld (%ld) subfaces are recovered (missing).\n",
21834 subfaces->items - misshlist->objects, misshlist->objects);
21835 }
21836
21837 if (misshlist->objects > 0) {
21838 // There are missing subfaces. Add Steiner points.
21839 for (i = 0; i < misshlist->objects; i++) {
21840 subfacstack->newindex((void **) &parysh);
21841 *parysh = * (face *) fastlookup(misshlist, i);
21842 }
21843 misshlist->restart();
21844
21845 recoversubfaces(NULL, 1);
21846
21847 if (b->verbose) {
21848 printf(" Added %ld Steiner points in facets.\n", st_facref_count);
21849 }
21850 }
21851
21852
21853 if (st_facref_count > 0) {
21854 // Try to remove the Steiner points added in facets.
21855 bak_facref_count = st_facref_count;
21856 for (i = 0; i < subvertstack->objects; i++) {
21857 // Get the Steiner point.
21858 parypt = (point *) fastlookup(subvertstack, i);
21859 rempt = *parypt;
21860 if (!removevertexbyflips(*parypt)) {
21861 // Save it in list.
21862 bdrysteinerptlist->newindex((void **) &parypt);
21863 *parypt = rempt;
21864 }
21865 }
21866 if (b->verbose) {
21867 if (st_facref_count < bak_facref_count) {
21868 printf(" Removed %ld Steiner points in facets.\n",
21869 bak_facref_count - st_facref_count);
21870 }
21871 }
21872 subvertstack->restart();
21873 }
21874
21875
21876 if (bdrysteinerptlist->objects > 0) {
21877 if (b->verbose) {
21878 printf(" %ld Steiner points remained in boundary.\n",
21879 bdrysteinerptlist->objects);
21880 }
21881 } // if
21882
21883
21884 // Accumulate the dynamic memory.
21885 totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
21886 bdrysteinerptlist->totalmemory);
21887
21888 delete bdrysteinerptlist;
21889 delete misseglist;
21890 delete misshlist;
21891}
21892
21893//// ////
21894//// ////
21895//// steiner_cxx //////////////////////////////////////////////////////////////
21896
21897
21898//// reconstruct_cxx //////////////////////////////////////////////////////////
21899//// ////
21900//// ////
21901
21902///////////////////////////////////////////////////////////////////////////////
21903// //
21904// carveholes() Remove tetrahedra not in the mesh domain. //
21905// //
21906///////////////////////////////////////////////////////////////////////////////
21907
21908
21909void tetgenmesh::carveholes()
21910{
21911 arraypool *tetarray, *hullarray;
21912 triface tetloop, neightet, *parytet, *parytet1;
21913 triface *regiontets = NULL;
21914 face checksh, *parysh;
21915 face checkseg;
21916 point ptloop, *parypt;
21917 int t1ver;
21918 int i, j, k;
21919
21920 if (!b->quiet) {
21921 if (b->convex) {
21922 printf("Marking exterior tetrahedra ...\n");
21923 } else {
21924 printf("Removing exterior tetrahedra ...\n");
21925 }
21926 }
21927
21928 // Initialize the pool of exterior tets.
21929 tetarray = new arraypool(sizeof(triface), 10);
21930 hullarray = new arraypool(sizeof(triface), 10);
21931
21932 // Collect unprotected tets and hull tets.
21933 tetrahedrons->traversalinit();
21934 tetloop.ver = 11; // The face opposite to dummypoint.
21935 tetloop.tet = alltetrahedrontraverse();
21936 while (tetloop.tet != (tetrahedron *) NULL) {
21937 if (ishulltet(tetloop)) {
21938 // Is this side protected by a subface?
21939 if (!issubface(tetloop)) {
21940 // Collect an unprotected hull tet and tet.
21941 infect(tetloop);
21942 hullarray->newindex((void **) &parytet);
21943 *parytet = tetloop;
21944 // tetloop's face number is 11 & 3 = 3.
21945 decode(tetloop.tet[3], neightet);
21946 if (!infected(neightet)) {
21947 infect(neightet);
21948 tetarray->newindex((void **) &parytet);
21949 *parytet = neightet;
21950 }
21951 }
21952 }
21953 tetloop.tet = alltetrahedrontraverse();
21954 }
21955
21956 if (in->numberofholes > 0) {
21957 // Mark as infected any tets inside volume holes.
21958 for (i = 0; i < 3 * in->numberofholes; i += 3) {
21959 // Search a tet containing the i-th hole point.
21960 neightet.tet = NULL;
21961 randomsample(&(in->holelist[i]), &neightet);
21962 if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
21963 // The tet 'neightet' contain this point.
21964 if (!infected(neightet)) {
21965 infect(neightet);
21966 tetarray->newindex((void **) &parytet);
21967 *parytet = neightet;
21968 // Add its adjacent tet if it is not protected.
21969 if (!issubface(neightet)) {
21970 decode(neightet.tet[neightet.ver & 3], tetloop);
21971 if (!infected(tetloop)) {
21972 infect(tetloop);
21973 if (ishulltet(tetloop)) {
21974 hullarray->newindex((void **) &parytet);
21975 } else {
21976 tetarray->newindex((void **) &parytet);
21977 }
21978 *parytet = tetloop;
21979 }
21980 }
21981 else {
21982 // It is protected. Check if its adjacent tet is a hull tet.
21983 decode(neightet.tet[neightet.ver & 3], tetloop);
21984 if (ishulltet(tetloop)) {
21985 // It is hull tet, add it into the list. Moreover, the subface
21986 // is dead, i.e., both sides are in exterior.
21987 if (!infected(tetloop)) {
21988 infect(tetloop);
21989 hullarray->newindex((void **) &parytet);
21990 *parytet = tetloop;
21991 }
21992 }
21993 if (infected(tetloop)) {
21994 // Both sides of this subface are in exterior.
21995 tspivot(neightet, checksh);
21996 sinfect(checksh); // Only queue it once.
21997 subfacstack->newindex((void **) &parysh);
21998 *parysh = checksh;
21999 }
22000 }
22001 } // if (!infected(neightet))
22002 } else {
22003 // A hole point locates outside of the convex hull.
22004 if (!b->quiet) {
22005 printf("Warning: The %d-th hole point ", i/3 + 1);
22006 printf("lies outside the convex hull.\n");
22007 }
22008 }
22009 } // i
22010 } // if (in->numberofholes > 0)
22011
22012 if (b->regionattrib && (in->numberofregions > 0)) { // -A option.
22013 // Record the tetrahedra that contains the region points for assigning
22014 // region attributes after the holes have been carved.
22015 regiontets = new triface[in->numberofregions];
22016 // Mark as marktested any tetrahedra inside volume regions.
22017 for (i = 0; i < 5 * in->numberofregions; i += 5) {
22018 // Search a tet containing the i-th region point.
22019 neightet.tet = NULL;
22020 randomsample(&(in->regionlist[i]), &neightet);
22021 if (locate(&(in->regionlist[i]), &neightet) != OUTSIDE) {
22022 regiontets[i/5] = neightet;
22023 } else {
22024 if (!b->quiet) {
22025 printf("Warning: The %d-th region point ", i/5+1);
22026 printf("lies outside the convex hull.\n");
22027 }
22028 regiontets[i/5].tet = NULL;
22029 }
22030 }
22031 }
22032
22033 // Collect all exterior tets (in concave place and in holes).
22034 for (i = 0; i < tetarray->objects; i++) {
22035 parytet = (triface *) fastlookup(tetarray, i);
22036 j = (parytet->ver & 3); // j is the current face number.
22037 // Check the other three adjacent tets.
22038 for (k = 1; k < 4; k++) {
22039 decode(parytet->tet[(j + k) % 4], neightet);
22040 // neightet may be a hull tet.
22041 if (!infected(neightet)) {
22042 // Is neightet protected by a subface.
22043 if (!issubface(neightet)) {
22044 // Not proected. Collect it. (It must not be a hull tet).
22045 infect(neightet);
22046 tetarray->newindex((void **) &parytet1);
22047 *parytet1 = neightet;
22048 } else {
22049 // Protected. Check if it is a hull tet.
22050 if (ishulltet(neightet)) {
22051 // A hull tet. Collect it.
22052 infect(neightet);
22053 hullarray->newindex((void **) &parytet1);
22054 *parytet1 = neightet;
22055 // Both sides of this subface are exterior.
22056 tspivot(neightet, checksh);
22057 // Queue this subface (to be deleted later).
22058 assert(!sinfected(checksh));
22059 sinfect(checksh); // Only queue it once.
22060 subfacstack->newindex((void **) &parysh);
22061 *parysh = checksh;
22062 }
22063 }
22064 } else {
22065 // Both sides of this face are in exterior.
22066 // If there is a subface. It should be collected.
22067 if (issubface(neightet)) {
22068 tspivot(neightet, checksh);
22069 if (!sinfected(checksh)) {
22070 sinfect(checksh);
22071 subfacstack->newindex((void **) &parysh);
22072 *parysh = checksh;
22073 }
22074 }
22075 }
22076 } // j, k
22077 } // i
22078
22079 if (b->regionattrib && (in->numberofregions > 0)) {
22080 // Re-check saved region tets to see if they lie outside.
22081 for (i = 0; i < in->numberofregions; i++) {
22082 if (infected(regiontets[i])) {
22083 if (b->verbose) {
22084 printf("Warning: The %d-th region point ", i+1);
22085 printf("lies in the exterior of the domain.\n");
22086 }
22087 regiontets[i].tet = NULL;
22088 }
22089 }
22090 }
22091
22092 // Collect vertices which point to infected tets. These vertices
22093 // may get deleted after the removal of exterior tets.
22094 // If -Y1 option is used, collect all Steiner points for removal.
22095 // The lists 'cavetetvertlist' and 'subvertstack' are re-used.
22096 points->traversalinit();
22097 ptloop = pointtraverse();
22098 while (ptloop != NULL) {
22099 if ((pointtype(ptloop) != UNUSEDVERTEX) &&
22100 (pointtype(ptloop) != DUPLICATEDVERTEX)) {
22101 decode(point2tet(ptloop), neightet);
22102 if (infected(neightet)) {
22103 cavetetvertlist->newindex((void **) &parypt);
22104 *parypt = ptloop;
22105 }
22106 if (b->nobisect && (b->nobisect_param > 0)) { // -Y1
22107 // Queue it if it is a Steiner point.
22108 if (pointmark(ptloop) >
22109 (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22110 subvertstack->newindex((void **) &parypt);
22111 *parypt = ptloop;
22112 }
22113 }
22114 }
22115 ptloop = pointtraverse();
22116 }
22117
22118 if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
22119 // Remove exterior tets. Hull tets are updated.
22120 arraypool *newhullfacearray;
22121 triface hulltet, casface;
22122 point pa, pb, pc;
22123
22124 newhullfacearray = new arraypool(sizeof(triface), 10);
22125
22126 // Create and save new hull tets.
22127 for (i = 0; i < tetarray->objects; i++) {
22128 parytet = (triface *) fastlookup(tetarray, i);
22129 for (j = 0; j < 4; j++) {
22130 decode(parytet->tet[j], tetloop);
22131 if (!infected(tetloop)) {
22132 // Found a new hull face (must be a subface).
22133 tspivot(tetloop, checksh);
22134 maketetrahedron(&hulltet);
22135 pa = org(tetloop);
22136 pb = dest(tetloop);
22137 pc = apex(tetloop);
22138 setvertices(hulltet, pb, pa, pc, dummypoint);
22139 bond(tetloop, hulltet);
22140 // Update the subface-to-tet map.
22141 sesymself(checksh);
22142 tsbond(hulltet, checksh);
22143 // Update the segment-to-tet map.
22144 for (k = 0; k < 3; k++) {
22145 if (issubseg(tetloop)) {
22146 tsspivot1(tetloop, checkseg);
22147 tssbond1(hulltet, checkseg);
22148 sstbond1(checkseg, hulltet);
22149 }
22150 enextself(tetloop);
22151 eprevself(hulltet);
22152 }
22153 // Update the point-to-tet map.
22154 setpoint2tet(pa, (tetrahedron) tetloop.tet);
22155 setpoint2tet(pb, (tetrahedron) tetloop.tet);
22156 setpoint2tet(pc, (tetrahedron) tetloop.tet);
22157 // Save the exterior tet at this hull face. It still holds pointer
22158 // to the adjacent interior tet. Use it to connect new hull tets.
22159 newhullfacearray->newindex((void **) &parytet1);
22160 parytet1->tet = parytet->tet;
22161 parytet1->ver = j;
22162 } // if (!infected(tetloop))
22163 } // j
22164 } // i
22165
22166 // Connect new hull tets.
22167 for (i = 0; i < newhullfacearray->objects; i++) {
22168 parytet = (triface *) fastlookup(newhullfacearray, i);
22169 fsym(*parytet, neightet);
22170 // Get the new hull tet.
22171 fsym(neightet, hulltet);
22172 for (j = 0; j < 3; j++) {
22173 esym(hulltet, casface);
22174 if (casface.tet[casface.ver & 3] == NULL) {
22175 // Since the boundary of the domain may not be a manifold, we
22176 // find the adjacent hull face by traversing the tets in the
22177 // exterior (which are all infected tets).
22178 neightet = *parytet;
22179 while (1) {
22180 fnextself(neightet);
22181 if (!infected(neightet)) break;
22182 }
22183 if (!ishulltet(neightet)) {
22184 // An interior tet. Get the new hull tet.
22185 fsymself(neightet);
22186 esymself(neightet);
22187 }
22188 // Bond them together.
22189 bond(casface, neightet);
22190 }
22191 enextself(hulltet);
22192 enextself(*parytet);
22193 } // j
22194 } // i
22195
22196 if (subfacstack->objects > 0l) {
22197 // Remove all subfaces which do not attach to any tetrahedron.
22198 // Segments which are not attached to any subfaces and tets
22199 // are deleted too.
22200 face casingout, casingin;
22201 long delsegcount = 0l;
22202
22203 for (i = 0; i < subfacstack->objects; i++) {
22204 parysh = (face *) fastlookup(subfacstack, i);
22205 if (i == 0) {
22206 if (b->verbose) {
22207 printf("Warning: Removing an open face (%d, %d, %d)\n",
22208 pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
22209 pointmark(sapex(*parysh)));
22210 }
22211 }
22212 // Dissolve this subface from face links.
22213 for (j = 0; j < 3; j++) {
22214 spivot(*parysh, casingout);
22215 sspivot(*parysh, checkseg);
22216 if (casingout.sh != NULL) {
22217 casingin = casingout;
22218 while (1) {
22219 spivot(casingin, checksh);
22220 if (checksh.sh == parysh->sh) break;
22221 casingin = checksh;
22222 }
22223 if (casingin.sh != casingout.sh) {
22224 // Update the link: ... -> casingin -> casingout ->...
22225 sbond1(casingin, casingout);
22226 } else {
22227 // Only one subface at this edge is left.
22228 sdissolve(casingout);
22229 }
22230 if (checkseg.sh != NULL) {
22231 // Make sure the segment does not connect to a dead one.
22232 ssbond(casingout, checkseg);
22233 }
22234 } else {
22235 if (checkseg.sh != NULL) {
22236 // The segment is also dead.
22237 if (delsegcount == 0) {
22238 if (b->verbose) {
22239 printf("Warning: Removing a dangling segment (%d, %d)\n",
22240 pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
22241 }
22242 }
22243 shellfacedealloc(subsegs, checkseg.sh);
22244 delsegcount++;
22245 }
22246 }
22247 senextself(*parysh);
22248 } // j
22249 // Delete this subface.
22250 shellfacedealloc(subfaces, parysh->sh);
22251 } // i
22252 if (b->verbose) {
22253 printf(" Deleted %ld subfaces.\n", subfacstack->objects);
22254 if (delsegcount > 0) {
22255 printf(" Deleted %ld segments.\n", delsegcount);
22256 }
22257 }
22258 subfacstack->restart();
22259 } // if (subfacstack->objects > 0l)
22260
22261 if (cavetetvertlist->objects > 0l) {
22262 // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
22263 long delvertcount = unuverts;
22264 long delsteinercount = 0l;
22265
22266 for (i = 0; i < cavetetvertlist->objects; i++) {
22267 parypt = (point *) fastlookup(cavetetvertlist, i);
22268 decode(point2tet(*parypt), neightet);
22269 if (infected(neightet)) {
22270 // Found an exterior vertex.
22271 if (pointmark(*parypt) >
22272 (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22273 // A Steiner point.
22274 if (pointtype(*parypt) == FREESEGVERTEX) {
22275 st_segref_count--;
22276 } else if (pointtype(*parypt) == FREEFACETVERTEX) {
22277 st_facref_count--;
22278 } else {
22279 assert(pointtype(*parypt) == FREEVOLVERTEX);
22280 st_volref_count--;
22281 }
22282 delsteinercount++;
22283 if (steinerleft > 0) steinerleft++;
22284 }
22285 setpointtype(*parypt, UNUSEDVERTEX);
22286 unuverts++;
22287 }
22288 }
22289
22290 if (b->verbose) {
22291 if (unuverts > delvertcount) {
22292 if (delsteinercount > 0l) {
22293 if (unuverts > (delvertcount + delsteinercount)) {
22294 printf(" Removed %ld exterior input vertices.\n",
22295 unuverts - delvertcount - delsteinercount);
22296 }
22297 printf(" Removed %ld exterior Steiner vertices.\n",
22298 delsteinercount);
22299 } else {
22300 printf(" Removed %ld exterior input vertices.\n",
22301 unuverts - delvertcount);
22302 }
22303 }
22304 }
22305 cavetetvertlist->restart();
22306 // Comment: 'subvertstack' will be cleaned in routine
22307 // suppresssteinerpoints().
22308 } // if (cavetetvertlist->objects > 0l)
22309
22310 // Update the hull size.
22311 hullsize += (newhullfacearray->objects - hullarray->objects);
22312
22313 // Delete all exterior tets and old hull tets.
22314 for (i = 0; i < tetarray->objects; i++) {
22315 parytet = (triface *) fastlookup(tetarray, i);
22316 tetrahedrondealloc(parytet->tet);
22317 }
22318 tetarray->restart();
22319
22320 for (i = 0; i < hullarray->objects; i++) {
22321 parytet = (triface *) fastlookup(hullarray, i);
22322 tetrahedrondealloc(parytet->tet);
22323 }
22324 hullarray->restart();
22325
22326 delete newhullfacearray;
22327 } // if (!b->convex && (tetarray->objects > 0l))
22328
22329 if (b->convex && (tetarray->objects > 0l)) { // With -c option
22330 // In this case, all exterior tets get a region marker '-1'.
22331 assert(b->regionattrib > 0); // -A option must be enabled.
22332 int attrnum = numelemattrib - 1;
22333
22334 for (i = 0; i < tetarray->objects; i++) {
22335 parytet = (triface *) fastlookup(tetarray, i);
22336 setelemattribute(parytet->tet, attrnum, -1);
22337 }
22338 tetarray->restart();
22339
22340 for (i = 0; i < hullarray->objects; i++) {
22341 parytet = (triface *) fastlookup(hullarray, i);
22342 uninfect(*parytet);
22343 }
22344 hullarray->restart();
22345
22346 if (subfacstack->objects > 0l) {
22347 for (i = 0; i < subfacstack->objects; i++) {
22348 parysh = (face *) fastlookup(subfacstack, i);
22349 suninfect(*parysh);
22350 }
22351 subfacstack->restart();
22352 }
22353
22354 if (cavetetvertlist->objects > 0l) {
22355 cavetetvertlist->restart();
22356 }
22357 } // if (b->convex && (tetarray->objects > 0l))
22358
22359 if (b->regionattrib) { // With -A option.
22360 if (!b->quiet) {
22361 printf("Spreading region attributes.\n");
22362 }
22363 REAL volume;
22364 int attr, maxattr = 0; // Choose a small number here.
22365 int attrnum = numelemattrib - 1;
22366 // Comment: The element region marker is at the end of the list of
22367 // the element attributes.
22368 int regioncount = 0;
22369
22370 // If has user-defined region attributes.
22371 if (in->numberofregions > 0) {
22372 // Spread region attributes.
22373 for (i = 0; i < 5 * in->numberofregions; i += 5) {
22374 if (regiontets[i/5].tet != NULL) {
22375 attr = (int) in->regionlist[i + 3];
22376 if (attr > maxattr) {
22377 maxattr = attr;
22378 }
22379 volume = in->regionlist[i + 4];
22380 tetarray->restart(); // Re-use this array.
22381 infect(regiontets[i/5]);
22382 tetarray->newindex((void **) &parytet);
22383 *parytet = regiontets[i/5];
22384 // Collect and set attrs for all tets of this region.
22385 for (j = 0; j < tetarray->objects; j++) {
22386 parytet = (triface *) fastlookup(tetarray, j);
22387 tetloop = *parytet;
22388 setelemattribute(tetloop.tet, attrnum, attr);
22389 if (b->varvolume) { // If has -a option.
22390 setvolumebound(tetloop.tet, volume);
22391 }
22392 for (k = 0; k < 4; k++) {
22393 decode(tetloop.tet[k], neightet);
22394 // Is the adjacent already checked?
22395 if (!infected(neightet)) {
22396 // Is this side protected by a subface?
22397 if (!issubface(neightet)) {
22398 infect(neightet);
22399 tetarray->newindex((void **) &parytet);
22400 *parytet = neightet;
22401 }
22402 }
22403 } // k
22404 } // j
22405 regioncount++;
22406 } // if (regiontets[i/5].tet != NULL)
22407 } // i
22408 }
22409
22410 // Set attributes for all tetrahedra.
22411 attr = maxattr + 1;
22412 tetrahedrons->traversalinit();
22413 tetloop.tet = tetrahedrontraverse();
22414 while (tetloop.tet != (tetrahedron *) NULL) {
22415 if (!infected(tetloop)) {
22416 // An unmarked region.
22417 tetarray->restart(); // Re-use this array.
22418 infect(tetloop);
22419 tetarray->newindex((void **) &parytet);
22420 *parytet = tetloop;
22421 // Find and mark all tets.
22422 for (j = 0; j < tetarray->objects; j++) {
22423 parytet = (triface *) fastlookup(tetarray, j);
22424 tetloop = *parytet;
22425 setelemattribute(tetloop.tet, attrnum, attr);
22426 for (k = 0; k < 4; k++) {
22427 decode(tetloop.tet[k], neightet);
22428 // Is the adjacent tet already checked?
22429 if (!infected(neightet)) {
22430 // Is this side protected by a subface?
22431 if (!issubface(neightet)) {
22432 infect(neightet);
22433 tetarray->newindex((void **) &parytet);
22434 *parytet = neightet;
22435 }
22436 }
22437 } // k
22438 } // j
22439 attr++; // Increase the attribute.
22440 regioncount++;
22441 }
22442 tetloop.tet = tetrahedrontraverse();
22443 }
22444 // Until here, every tet has a region attribute.
22445
22446 // Uninfect processed tets.
22447 tetrahedrons->traversalinit();
22448 tetloop.tet = tetrahedrontraverse();
22449 while (tetloop.tet != (tetrahedron *) NULL) {
22450 uninfect(tetloop);
22451 tetloop.tet = tetrahedrontraverse();
22452 }
22453
22454 if (b->verbose) {
22455 //assert(regioncount > 0);
22456 if (regioncount > 1) {
22457 printf(" Found %d subdomains.\n", regioncount);
22458 } else {
22459 printf(" Found %d domain.\n", regioncount);
22460 }
22461 }
22462 } // if (b->regionattrib)
22463
22464 if (regiontets != NULL) {
22465 delete [] regiontets;
22466 }
22467 delete tetarray;
22468 delete hullarray;
22469
22470 if (!b->convex) { // No -c option
22471 // The mesh is non-convex now.
22472 nonconvex = 1;
22473
22474 // Push all hull tets into 'flipstack'.
22475 tetrahedrons->traversalinit();
22476 tetloop.ver = 11; // The face opposite to dummypoint.
22477 tetloop.tet = alltetrahedrontraverse();
22478 while (tetloop.tet != (tetrahedron *) NULL) {
22479 if ((point) tetloop.tet[7] == dummypoint) {
22480 fsym(tetloop, neightet);
22481 flippush(flipstack, &neightet);
22482 }
22483 tetloop.tet = alltetrahedrontraverse();
22484 }
22485
22486 flipconstraints fc;
22487 fc.enqflag = 2;
22488 long sliver_peel_count = lawsonflip3d(&fc);
22489
22490 if (sliver_peel_count > 0l) {
22491 if (b->verbose) {
22492 printf(" Removed %ld hull slivers.\n", sliver_peel_count);
22493 }
22494 }
22495 unflipqueue->restart();
22496 } // if (!b->convex)
22497}
22498
22499///////////////////////////////////////////////////////////////////////////////
22500// //
22501// reconstructmesh() Reconstruct a tetrahedral mesh. //
22502// //
22503///////////////////////////////////////////////////////////////////////////////
22504
22505void tetgenmesh::reconstructmesh()
22506{
22507 tetrahedron *ver2tetarray;
22508 point *idx2verlist;
22509 triface tetloop, checktet, prevchktet;
22510 triface hulltet, face1, face2;
22511 tetrahedron tptr;
22512 face subloop, neighsh, nextsh;
22513 face segloop;
22514 shellface sptr;
22515 point p[4], q[3];
22516 REAL ori, attrib, volume;
22517 REAL angtol, ang;
22518 int eextras, marker = 0;
22519 int bondflag;
22520 int t1ver;
22521 int idx, i, j, k;
22522
22523 if (!b->quiet) {
22524 printf("Reconstructing mesh ...\n");
22525 }
22526
22527 if (b->convex) { // -c option.
22528 // Assume the mesh is convex. Exterior tets have region attribute -1.
22529 assert(in->numberoftetrahedronattributes > 0);
22530 } else {
22531 // Assume the mesh is non-convex.
22532 nonconvex = 1;
22533 }
22534
22535 // Create a map from indices to vertices.
22536 makeindex2pointmap(idx2verlist);
22537 // 'idx2verlist' has length 'in->numberofpoints + 1'.
22538 if (in->firstnumber == 1) {
22539 idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
22540 }
22541
22542 // Allocate an array that maps each vertex to its adjacent tets.
22543 ver2tetarray = new tetrahedron[in->numberofpoints + 1];
22544 //for (i = 0; i < in->numberofpoints + 1; i++) {
22545 for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
22546 setpointtype(idx2verlist[i], VOLVERTEX); // initial type.
22547 ver2tetarray[i] = NULL;
22548 }
22549
22550 // Create the tetrahedra and connect those that share a common face.
22551 for (i = 0; i < in->numberoftetrahedra; i++) {
22552 // Get the four vertices.
22553 idx = i * in->numberofcorners;
22554 for (j = 0; j < 4; j++) {
22555 p[j] = idx2verlist[in->tetrahedronlist[idx++]];
22556 }
22557 // Check the orientation.
22558 ori = orient3d(p[0], p[1], p[2], p[3]);
22559 if (ori > 0.0) {
22560 // Swap the first two vertices.
22561 q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
22562 } else if (ori == 0.0) {
22563 if (!b->quiet) {
22564 printf("Warning: Tet #%d is degenerate.\n", i + in->firstnumber);
22565 }
22566 }
22567 // Create a new tetrahedron.
22568 maketetrahedron(&tetloop); // tetloop.ver = 11.
22569 setvertices(tetloop, p[0], p[1], p[2], p[3]);
22570 // Set element attributes if they exist.
22571 for (j = 0; j < in->numberoftetrahedronattributes; j++) {
22572 idx = i * in->numberoftetrahedronattributes;
22573 attrib = in->tetrahedronattributelist[idx + j];
22574 setelemattribute(tetloop.tet, j, attrib);
22575 }
22576 // If -a switch is used (with no number follows) Set a volume
22577 // constraint if it exists.
22578 if (b->varvolume) {
22579 if (in->tetrahedronvolumelist != (REAL *) NULL) {
22580 volume = in->tetrahedronvolumelist[i];
22581 } else {
22582 volume = -1.0;
22583 }
22584 setvolumebound(tetloop.tet, volume);
22585 }
22586 // Try connecting this tet to others that share the common faces.
22587 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22588 p[3] = oppo(tetloop);
22589 // Look for other tets having this vertex.
22590 idx = pointmark(p[3]);
22591 tptr = ver2tetarray[idx];
22592 // Link the current tet to the next one in the stack.
22593 tetloop.tet[8 + tetloop.ver] = tptr;
22594 // Push the current tet onto the stack.
22595 ver2tetarray[idx] = encode(tetloop);
22596 decode(tptr, checktet);
22597 if (checktet.tet != NULL) {
22598 p[0] = org(tetloop); // a
22599 p[1] = dest(tetloop); // b
22600 p[2] = apex(tetloop); // c
22601 prevchktet = tetloop;
22602 do {
22603 q[0] = org(checktet); // a'
22604 q[1] = dest(checktet); // b'
22605 q[2] = apex(checktet); // c'
22606 // Check the three faces at 'd' in 'checktet'.
22607 bondflag = 0;
22608 for (j = 0; j < 3; j++) {
22609 // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
22610 esym(checktet, face2);
22611 if (face2.tet[face2.ver & 3] == NULL) {
22612 k = ((j + 1) % 3);
22613 if (q[k] == p[0]) { // b', c', a' = a
22614 if (q[j] == p[1]) { // a', b', c' = b
22615 // [#,#,d] is matched to [b,a,d].
22616 esym(tetloop, face1);
22617 bond(face1, face2);
22618 bondflag++;
22619 }
22620 }
22621 if (q[k] == p[1]) { // b',c',a' = b
22622 if (q[j] == p[2]) { // a',b',c' = c
22623 // [#,#,d] is matched to [c,b,d].
22624 enext(tetloop, face1);
22625 esymself(face1);
22626 bond(face1, face2);
22627 bondflag++;
22628 }
22629 }
22630 if (q[k] == p[2]) { // b',c',a' = c
22631 if (q[j] == p[0]) { // a',b',c' = a
22632 // [#,#,d] is matched to [a,c,d].
22633 eprev(tetloop, face1);
22634 esymself(face1);
22635 bond(face1, face2);
22636 bondflag++;
22637 }
22638 }
22639 } else {
22640 bondflag++;
22641 }
22642 enextself(checktet);
22643 } // j
22644 // Go to the next tet in the link.
22645 tptr = checktet.tet[8 + checktet.ver];
22646 if (bondflag == 3) {
22647 // All three faces at d in 'checktet' have been connected.
22648 // It can be removed from the link.
22649 prevchktet.tet[8 + prevchktet.ver] = tptr;
22650 } else {
22651 // Bakup the previous tet in the link.
22652 prevchktet = checktet;
22653 }
22654 decode(tptr, checktet);
22655 } while (checktet.tet != NULL);
22656 } // if (checktet.tet != NULL)
22657 } // for (tetloop.ver = 0; ...
22658 } // i
22659
22660 // Remember a tet of the mesh.
22661 recenttet = tetloop;
22662
22663 // Create hull tets, create the point-to-tet map, and clean up the
22664 // temporary spaces used in each tet.
22665 hullsize = tetrahedrons->items;
22666
22667 tetrahedrons->traversalinit();
22668 tetloop.tet = tetrahedrontraverse();
22669 while (tetloop.tet != (tetrahedron *) NULL) {
22670 tptr = encode(tetloop);
22671 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22672 if (tetloop.tet[tetloop.ver] == NULL) {
22673 // Create a hull tet.
22674 maketetrahedron(&hulltet);
22675 p[0] = org(tetloop);
22676 p[1] = dest(tetloop);
22677 p[2] = apex(tetloop);
22678 setvertices(hulltet, p[1], p[0], p[2], dummypoint);
22679 bond(tetloop, hulltet);
22680 // Try connecting this to others that share common hull edges.
22681 for (j = 0; j < 3; j++) {
22682 fsym(hulltet, face2);
22683 while (1) {
22684 if (face2.tet == NULL) break;
22685 esymself(face2);
22686 if (apex(face2) == dummypoint) break;
22687 fsymself(face2);
22688 }
22689 if (face2.tet != NULL) {
22690 // Found an adjacent hull tet.
22691 assert(face2.tet[face2.ver & 3] == NULL);
22692 esym(hulltet, face1);
22693 bond(face1, face2);
22694 }
22695 enextself(hulltet);
22696 }
22697 //hullsize++;
22698 }
22699 // Create the point-to-tet map.
22700 setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
22701 // Clean the temporary used space.
22702 tetloop.tet[8 + tetloop.ver] = NULL;
22703 }
22704 tetloop.tet = tetrahedrontraverse();
22705 }
22706
22707 hullsize = tetrahedrons->items - hullsize;
22708
22709 // Subfaces will be inserted into the mesh.
22710 if (in->trifacelist != NULL) {
22711 // A .face file is given. It may contain boundary faces. Insert them.
22712 for (i = 0; i < in->numberoftrifaces; i++) {
22713 // Is it a subface?
22714 if (in->trifacemarkerlist != NULL) {
22715 marker = in->trifacemarkerlist[i];
22716 } else {
22717 // Face markers are not available. Assume all of them are subfaces.
22718 marker = 1;
22719 }
22720 if (marker > 0) {
22721 idx = i * 3;
22722 for (j = 0; j < 3; j++) {
22723 p[j] = idx2verlist[in->trifacelist[idx++]];
22724 }
22725 // Search the subface.
22726 bondflag = 0;
22727 // Make sure all vertices are in the mesh. Avoid crash.
22728 for (j = 0; j < 3; j++) {
22729 decode(point2tet(p[j]), checktet);
22730 if (checktet.tet == NULL) break;
22731 }
22732 if ((j == 3) && getedge(p[0], p[1], &checktet)) {
22733 tetloop = checktet;
22734 q[2] = apex(checktet);
22735 while (1) {
22736 if (apex(tetloop) == p[2]) {
22737 // Found the face.
22738 // Check if there exist a subface already?
22739 tspivot(tetloop, neighsh);
22740 if (neighsh.sh != NULL) {
22741 // Found a duplicated subface.
22742 // This happens when the mesh was generated by other mesher.
22743 bondflag = 0;
22744 } else {
22745 bondflag = 1;
22746 }
22747 break;
22748 }
22749 fnextself(tetloop);
22750 if (apex(tetloop) == q[2]) break;
22751 }
22752 }
22753 if (bondflag) {
22754 // Create a new subface.
22755 makeshellface(subfaces, &subloop);
22756 setshvertices(subloop, p[0], p[1], p[2]);
22757 // Create the point-to-subface map.
22758 sptr = sencode(subloop);
22759 for (j = 0; j < 3; j++) {
22760 setpointtype(p[j], FACETVERTEX); // initial type.
22761 setpoint2sh(p[j], sptr);
22762 }
22763 if (in->trifacemarkerlist != NULL) {
22764 setshellmark(subloop, in->trifacemarkerlist[i]);
22765 }
22766 // Insert the subface into the mesh.
22767 tsbond(tetloop, subloop);
22768 fsymself(tetloop);
22769 sesymself(subloop);
22770 tsbond(tetloop, subloop);
22771 } else {
22772 if (!b->quiet) {
22773 if (neighsh.sh == NULL) {
22774 printf("Warning: Subface #%d [%d,%d,%d] is missing.\n",
22775 i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
22776 pointmark(p[2]));
22777 } else {
22778 printf("Warning: Ignore a dunplicated subface #%d [%d,%d,%d].\n",
22779 i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
22780 pointmark(p[2]));
22781 }
22782 }
22783 } // if (bondflag)
22784 } // if (marker > 0)
22785 } // i
22786 } // if (in->trifacelist)
22787
22788 // Indentify subfaces from the mesh.
22789 // Create subfaces for hull faces (if they're not subface yet) and
22790 // interior faces which separate two different materials.
22791 eextras = in->numberoftetrahedronattributes;
22792 tetrahedrons->traversalinit();
22793 tetloop.tet = tetrahedrontraverse();
22794 while (tetloop.tet != (tetrahedron *) NULL) {
22795 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22796 tspivot(tetloop, neighsh);
22797 if (neighsh.sh == NULL) {
22798 bondflag = 0;
22799 fsym(tetloop, checktet);
22800 if (ishulltet(checktet)) {
22801 // A hull face.
22802 if (!b->convex) {
22803 bondflag = 1; // Insert a hull subface.
22804 }
22805 } else {
22806 if (eextras > 0) {
22807 if (elemattribute(tetloop.tet, eextras - 1) !=
22808 elemattribute(checktet.tet, eextras - 1)) {
22809 bondflag = 1; // Insert an interior interface.
22810 }
22811 }
22812 }
22813 if (bondflag) {
22814 // Create a new subface.
22815 makeshellface(subfaces, &subloop);
22816 p[0] = org(tetloop);
22817 p[1] = dest(tetloop);
22818 p[2] = apex(tetloop);
22819 setshvertices(subloop, p[0], p[1], p[2]);
22820 // Create the point-to-subface map.
22821 sptr = sencode(subloop);
22822 for (j = 0; j < 3; j++) {
22823 setpointtype(p[j], FACETVERTEX); // initial type.
22824 setpoint2sh(p[j], sptr);
22825 }
22826 setshellmark(subloop, 0); // Default marker.
22827 // Insert the subface into the mesh.
22828 tsbond(tetloop, subloop);
22829 sesymself(subloop);
22830 tsbond(checktet, subloop);
22831 } // if (bondflag)
22832 } // if (neighsh.sh == NULL)
22833 }
22834 tetloop.tet = tetrahedrontraverse();
22835 }
22836
22837 // Connect subfaces together.
22838 subfaces->traversalinit();
22839 subloop.shver = 0;
22840 subloop.sh = shellfacetraverse(subfaces);
22841 while (subloop.sh != (shellface *) NULL) {
22842 for (i = 0; i < 3; i++) {
22843 spivot(subloop, neighsh);
22844 if (neighsh.sh == NULL) {
22845 // Form a subface ring by linking all subfaces at this edge.
22846 // Traversing all faces of the tets at this edge.
22847 stpivot(subloop, tetloop);
22848 q[2] = apex(tetloop);
22849 neighsh = subloop;
22850 while (1) {
22851 fnextself(tetloop);
22852 tspivot(tetloop, nextsh);
22853 if (nextsh.sh != NULL) {
22854 // Link neighsh <= nextsh.
22855 sbond1(neighsh, nextsh);
22856 neighsh = nextsh;
22857 }
22858 if (apex(tetloop) == q[2]) {
22859 assert(nextsh.sh == subloop.sh); // It's a ring.
22860 break;
22861 }
22862 } // while (1)
22863 } // if (neighsh.sh == NULL)
22864 senextself(subloop);
22865 }
22866 subloop.sh = shellfacetraverse(subfaces);
22867 }
22868
22869
22870 // Segments will be introduced.
22871 if (in->edgelist != NULL) {
22872 // A .edge file is given. It may contain boundary edges. Insert them.
22873 for (i = 0; i < in->numberofedges; i++) {
22874 // Is it a segment?
22875 if (in->edgemarkerlist != NULL) {
22876 marker = in->edgemarkerlist[i];
22877 } else {
22878 // Edge markers are not available. Assume all of them are segments.
22879 marker = 1;
22880 }
22881 if (marker != 0) {
22882 // Insert a segment.
22883 idx = i * 2;
22884 for (j = 0; j < 2; j++) {
22885 p[j] = idx2verlist[in->edgelist[idx++]];
22886 }
22887 // Make sure all vertices are in the mesh. Avoid crash.
22888 for (j = 0; j < 2; j++) {
22889 decode(point2tet(p[j]), checktet);
22890 if (checktet.tet == NULL) break;
22891 }
22892 // Search the segment.
22893 if ((j == 2) && getedge(p[0], p[1], &checktet)) {
22894 // Create a new subface.
22895 makeshellface(subsegs, &segloop);
22896 setshvertices(segloop, p[0], p[1], NULL);
22897 // Create the point-to-segment map.
22898 sptr = sencode(segloop);
22899 for (j = 0; j < 2; j++) {
22900 setpointtype(p[j], RIDGEVERTEX); // initial type.
22901 setpoint2sh(p[j], sptr);
22902 }
22903 if (in->edgemarkerlist != NULL) {
22904 setshellmark(segloop, marker);
22905 }
22906 // Insert the segment into the mesh.
22907 tetloop = checktet;
22908 q[2] = apex(checktet);
22909 subloop.sh = NULL;
22910 while (1) {
22911 tssbond1(tetloop, segloop);
22912 tspivot(tetloop, subloop);
22913 if (subloop.sh != NULL) {
22914 ssbond1(subloop, segloop);
22915 sbond1(segloop, subloop);
22916 }
22917 fnextself(tetloop);
22918 if (apex(tetloop) == q[2]) break;
22919 } // while (1)
22920 // Remember an adjacent tet for this segment.
22921 sstbond1(segloop, tetloop);
22922 } else {
22923 if (!b->quiet) {
22924 printf("Warning: Segment #%d [%d,%d] is missing.\n",
22925 i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
22926 }
22927 }
22928 } // if (marker != 0)
22929 } // i
22930 } // if (in->edgelist)
22931
22932 // Identify segments from the mesh.
22933 // Create segments for non-manifold edges (which are shared by more
22934 // than two subfaces), and for non-coplanar edges, i.e., two subfaces
22935 // form an dihedral angle > 'b->facet_ang_tol' (degree).
22936 angtol = b->facet_ang_tol / 180.0 * PI;
22937 subfaces->traversalinit();
22938 subloop.shver = 0;
22939 subloop.sh = shellfacetraverse(subfaces);
22940 while (subloop.sh != (shellface *) NULL) {
22941 for (i = 0; i < 3; i++) {
22942 sspivot(subloop, segloop);
22943 if (segloop.sh == NULL) {
22944 // Check if this edge is a segment.
22945 bondflag = 0;
22946 // Counter the number of subfaces at this edge.
22947 idx = 0;
22948 nextsh = subloop;
22949 while (1) {
22950 idx++;
22951 spivotself(nextsh);
22952 if (nextsh.sh == subloop.sh) break;
22953 }
22954 if (idx != 2) {
22955 // It's a non-manifold edge. Insert a segment.
22956 p[0] = sorg(subloop);
22957 p[1] = sdest(subloop);
22958 bondflag = 1;
22959 } else {
22960 spivot(subloop, neighsh);
22961 if (shellmark(subloop) != shellmark(neighsh)) {
22962 // It's an interior interface. Insert a segment.
22963 p[0] = sorg(subloop);
22964 p[1] = sdest(subloop);
22965 bondflag = 1;
22966 } else {
22967 if (!b->convex) {
22968 // Check the dihedral angle formed by the two subfaces.
22969 p[0] = sorg(subloop);
22970 p[1] = sdest(subloop);
22971 p[2] = sapex(subloop);
22972 p[3] = sapex(neighsh);
22973 ang = facedihedral(p[0], p[1], p[2], p[3]);
22974 if (ang > PI) ang = 2 * PI - ang;
22975 if (ang < angtol) {
22976 bondflag = 1;
22977 }
22978 }
22979 }
22980 }
22981 if (bondflag) {
22982 // Create a new segment.
22983 makeshellface(subsegs, &segloop);
22984 setshvertices(segloop, p[0], p[1], NULL);
22985 // Create the point-to-segment map.
22986 sptr = sencode(segloop);
22987 for (j = 0; j < 2; j++) {
22988 setpointtype(p[j], RIDGEVERTEX); // initial type.
22989 setpoint2sh(p[j], sptr);
22990 }
22991 setshellmark(segloop, 0); // Initially has no marker.
22992 // Insert the subface into the mesh.
22993 stpivot(subloop, tetloop);
22994 q[2] = apex(tetloop);
22995 while (1) {
22996 tssbond1(tetloop, segloop);
22997 tspivot(tetloop, neighsh);
22998 if (neighsh.sh != NULL) {
22999 ssbond1(neighsh, segloop);
23000 }
23001 fnextself(tetloop);
23002 if (apex(tetloop) == q[2]) break;
23003 } // while (1)
23004 // Remember an adjacent tet for this segment.
23005 sstbond1(segloop, tetloop);
23006 sbond1(segloop, subloop);
23007 } // if (bondflag)
23008 } // if (neighsh.sh == NULL)
23009 senextself(subloop);
23010 } // i
23011 subloop.sh = shellfacetraverse(subfaces);
23012 }
23013
23014 // Remember the number of input segments.
23015 insegments = subsegs->items;
23016
23017 if (!b->nobisect || checkconstraints) {
23018 // Mark Steiner points on segments and facets.
23019 // - all vertices which remaining type FEACTVERTEX become
23020 // Steiner points in facets (= FREEFACERVERTEX).
23021 // - vertices on segment need to be checked.
23022 face* segperverlist;
23023 int* idx2seglist;
23024 face parentseg, nextseg;
23025 verttype vt;
23026 REAL area, len, l1, l2;
23027 int fmarker;
23028
23029 makepoint2submap(subsegs, idx2seglist, segperverlist);
23030
23031 points->traversalinit();
23032 point ptloop = pointtraverse();
23033 while (ptloop != NULL) {
23034 vt = pointtype(ptloop);
23035 if (vt == VOLVERTEX) {
23036 setpointtype(ptloop, FREEVOLVERTEX);
23037 st_volref_count++;
23038 } else if (vt == FACETVERTEX) {
23039 setpointtype(ptloop, FREEFACETVERTEX);
23040 st_facref_count++;
23041 } else if (vt == RIDGEVERTEX) {
23042 idx = pointmark(ptloop) - in->firstnumber;
23043 if ((idx2seglist[idx + 1] - idx2seglist[idx]) == 2) {
23044 i = idx2seglist[idx];
23045 parentseg = segperverlist[i];
23046 nextseg = segperverlist[i + 1];
23047 sesymself(nextseg);
23048 p[0] = sorg(nextseg);
23049 p[1] = sdest(parentseg);
23050 // Check if three points p[0], ptloop, p[2] are (nearly) collinear.
23051 len = distance(p[0], p[1]);
23052 l1 = distance(p[0], ptloop);
23053 l2 = distance(ptloop, p[1]);
23054 if (((l1 + l2 - len) / len) < b->epsilon) {
23055 // They are (nearly) collinear.
23056 setpointtype(ptloop, FREESEGVERTEX);
23057 // Connect nextseg and parentseg together at ptloop.
23058 senextself(nextseg);
23059 senext2self(parentseg);
23060 sbond(nextseg, parentseg);
23061 st_segref_count++;
23062 }
23063 }
23064 }
23065 ptloop = pointtraverse();
23066 }
23067
23068 // Are there area constraints?
23069 if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
23070 // Set maximum area constraints on facets.
23071 for (i = 0; i < in->numberoffacetconstraints; i++) {
23072 fmarker = (int) in->facetconstraintlist[i * 2];
23073 area = in->facetconstraintlist[i * 2 + 1];
23074 subfaces->traversalinit();
23075 subloop.sh = shellfacetraverse(subfaces);
23076 while (subloop.sh != NULL) {
23077 if (shellmark(subloop) == fmarker) {
23078 setareabound(subloop, area);
23079 }
23080 subloop.sh = shellfacetraverse(subfaces);
23081 }
23082 }
23083 }
23084
23085 // Are there length constraints?
23086 if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
23087 // Set maximum length constraints on segments.
23088 int e1, e2;
23089 for (i = 0; i < in->numberofsegmentconstraints; i++) {
23090 e1 = (int) in->segmentconstraintlist[i * 3];
23091 e2 = (int) in->segmentconstraintlist[i * 3 + 1];
23092 len = in->segmentconstraintlist[i * 3 + 2];
23093 // Search for edge [e1, e2].
23094 idx = e1 - in->firstnumber;
23095 for (j = idx2seglist[idx]; j < idx2seglist[idx + 1]; j++) {
23096 parentseg = segperverlist[j];
23097 if (pointmark(sdest(parentseg)) == e2) {
23098 setareabound(parentseg, len);
23099 break;
23100 }
23101 }
23102 }
23103 }
23104
23105 delete [] idx2seglist;
23106 delete [] segperverlist;
23107 }
23108
23109
23110 // Set global flags.
23111 checksubsegflag = 1;
23112 checksubfaceflag = 1;
23113
23114 delete [] idx2verlist;
23115 delete [] ver2tetarray;
23116}
23117
23118///////////////////////////////////////////////////////////////////////////////
23119// //
23120// scoutpoint() Search a point in mesh. //
23121// //
23122// This function searches the point in a mesh whose domain may be not convex.//
23123// In case of a convex domain, the locate() function is sufficient. //
23124// //
23125// If 'randflag' is used, randomly select a start searching tet. Otherwise, //
23126// start searching directly from 'searchtet'. //
23127// //
23128///////////////////////////////////////////////////////////////////////////////
23129
23130int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
23131{
23132 point pa, pb, pc, pd;
23133 enum locateresult loc = OUTSIDE;
23134 REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
23135 int t1ver;
23136
23137
23138 // Randomly select a good starting tet.
23139 if (randflag) {
23140 randomsample(searchpt, searchtet);
23141 } else {
23142 if (searchtet->tet == NULL) {
23143 *searchtet = recenttet;
23144 }
23145 }
23146 loc = locate(searchpt, searchtet);
23147
23148 if (loc == OUTSIDE) {
23149 if (b->convex) { // -c option
23150 // The point lies outside of the convex hull.
23151 return (int) loc;
23152 }
23153 // Test if it lies nearly on the hull face.
23154 // Reuse vol, ori1.
23155 pa = org(*searchtet);
23156 pb = dest(*searchtet);
23157 pc = apex(*searchtet);
23158 vol = triarea(pa, pb, pc);
23159 ori1 = orient3dfast(pa, pb, pc, searchpt);
23160 if (fabs(ori1 / vol) < b->epsilon) {
23161 loc = ONFACE; // On face (or on edge, or on vertex).
23162 fsymself(*searchtet);
23163 }
23164 }
23165
23166 if (loc != OUTSIDE) {
23167 // Round the result of location.
23168 pa = org(*searchtet);
23169 pb = dest(*searchtet);
23170 pc = apex(*searchtet);
23171 pd = oppo(*searchtet);
23172 vol = orient3dfast(pa, pb, pc, pd);
23173 ori1 = orient3dfast(pa, pb, pc, searchpt);
23174 ori2 = orient3dfast(pb, pa, pd, searchpt);
23175 ori3 = orient3dfast(pc, pb, pd, searchpt);
23176 ori4 = orient3dfast(pa, pc, pd, searchpt);
23177 if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
23178 if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
23179 if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
23180 if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
23181 } else { // if (loc == OUTSIDE) {
23182 // Do a brute force search for the point (with rounding).
23183 tetrahedrons->traversalinit();
23184 searchtet->tet = tetrahedrontraverse();
23185 while (searchtet->tet != NULL) {
23186 pa = org(*searchtet);
23187 pb = dest(*searchtet);
23188 pc = apex(*searchtet);
23189 pd = oppo(*searchtet);
23190
23191 vol = orient3dfast(pa, pb, pc, pd);
23192 if (vol < 0) {
23193 ori1 = orient3dfast(pa, pb, pc, searchpt);
23194 if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
23195 if (ori1 <= 0) {
23196 ori2 = orient3dfast(pb, pa, pd, searchpt);
23197 if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
23198 if (ori2 <= 0) {
23199 ori3 = orient3dfast(pc, pb, pd, searchpt);
23200 if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
23201 if (ori3 <= 0) {
23202 ori4 = orient3dfast(pa, pc, pd, searchpt);
23203 if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
23204 if (ori4 <= 0) {
23205 // Found the tet. Return its location.
23206 break;
23207 } // ori4
23208 } // ori3
23209 } // ori2
23210 } // ori1
23211 }
23212
23213 searchtet->tet = tetrahedrontraverse();
23214 } // while (searchtet->tet != NULL)
23215 nonregularcount++; // Re-use this counter.
23216 }
23217
23218 if (searchtet->tet != NULL) {
23219 // Return the point location.
23220 if (ori1 == 0) { // on face [a,b,c]
23221 if (ori2 == 0) { // on edge [a,b].
23222 if (ori3 == 0) { // on vertex [b].
23223 assert(ori4 != 0);
23224 enextself(*searchtet); // [b,c,a,d]
23225 loc = ONVERTEX;
23226 } else {
23227 if (ori4 == 0) { // on vertex [a]
23228 loc = ONVERTEX; // [a,b,c,d]
23229 } else {
23230 loc = ONEDGE; // [a,b,c,d]
23231 }
23232 }
23233 } else { // ori2 != 0
23234 if (ori3 == 0) { // on edge [b,c]
23235 if (ori4 == 0) { // on vertex [c]
23236 eprevself(*searchtet); // [c,a,b,d]
23237 loc = ONVERTEX;
23238 } else {
23239 enextself(*searchtet); // [b,c,a,d]
23240 loc = ONEDGE;
23241 }
23242 } else { // ori3 != 0
23243 if (ori4 == 0) { // on edge [c,a]
23244 eprevself(*searchtet); // [c,a,b,d]
23245 loc = ONEDGE;
23246 } else {
23247 loc = ONFACE;
23248 }
23249 }
23250 }
23251 } else { // ori1 != 0
23252 if (ori2 == 0) { // on face [b,a,d]
23253 esymself(*searchtet); // [b,a,d,c]
23254 if (ori3 == 0) { // on edge [b,d]
23255 eprevself(*searchtet); // [d,b,a,c]
23256 if (ori4 == 0) { // on vertex [d]
23257 loc = ONVERTEX;
23258 } else {
23259 loc = ONEDGE;
23260 }
23261 } else { // ori3 != 0
23262 if (ori4 == 0) { // on edge [a,d]
23263 enextself(*searchtet); // [a,d,b,c]
23264 loc = ONEDGE;
23265 } else {
23266 loc = ONFACE;
23267 }
23268 }
23269 } else { // ori2 != 0
23270 if (ori3 == 0) { // on face [c,b,d]
23271 enextself(*searchtet);
23272 esymself(*searchtet);
23273 if (ori4 == 0) { // on edge [c,d]
23274 eprevself(*searchtet);
23275 loc = ONEDGE;
23276 } else {
23277 loc = ONFACE;
23278 }
23279 } else {
23280 if (ori4 == 0) { // on face [a,c,d]
23281 eprevself(*searchtet);
23282 esymself(*searchtet);
23283 loc = ONFACE;
23284 } else { // inside tet [a,b,c,d]
23285 loc = INTETRAHEDRON;
23286 } // ori4
23287 } // ori3
23288 } // ori2
23289 } // ori1
23290 } else {
23291 loc = OUTSIDE;
23292 }
23293
23294 return (int) loc;
23295}
23296
23297///////////////////////////////////////////////////////////////////////////////
23298// //
23299// getpointmeshsize() Interpolate the mesh size at given point. //
23300// //
23301// 'iloc' indicates the location of the point w.r.t. 'searchtet'. The size //
23302// is obtained by linear interpolation on the vertices of the tet. //
23303// //
23304///////////////////////////////////////////////////////////////////////////////
23305
23306REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
23307{
23308 point *pts, pa, pb, pc;
23309 REAL volume, vol[4], wei[4];
23310 REAL size;
23311 int i;
23312
23313 size = 0;
23314
23315 if (iloc == (int) INTETRAHEDRON) {
23316 pts = (point *) &(searchtet->tet[4]);
23317 assert(pts[3] != dummypoint);
23318 // Only do interpolation if all vertices have non-zero sizes.
23319 if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
23320 (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) {
23321 // P1 interpolation.
23322 volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
23323 vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
23324 vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
23325 vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
23326 vol[3] = orient3dfast(pts[0], pts[1], pts[2], searchpt);
23327 for (i = 0; i < 4; i++) {
23328 wei[i] = fabs(vol[i] / volume);
23329 size += (wei[i] * pts[i][pointmtrindex]);
23330 }
23331 }
23332 } else if (iloc == (int) ONFACE) {
23333 pa = org(*searchtet);
23334 pb = dest(*searchtet);
23335 pc = apex(*searchtet);
23336 if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
23337 (pc[pointmtrindex] > 0)) {
23338 volume = triarea(pa, pb, pc);
23339 vol[0] = triarea(searchpt, pb, pc);
23340 vol[1] = triarea(pa, searchpt, pc);
23341 vol[2] = triarea(pa, pb, searchpt);
23342 size = (vol[0] / volume) * pa[pointmtrindex]
23343 + (vol[1] / volume) * pb[pointmtrindex]
23344 + (vol[2] / volume) * pc[pointmtrindex];
23345 }
23346 } else if (iloc == (int) ONEDGE) {
23347 pa = org(*searchtet);
23348 pb = dest(*searchtet);
23349 if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
23350 volume = distance(pa, pb);
23351 vol[0] = distance(searchpt, pb);
23352 vol[1] = distance(pa, searchpt);
23353 size = (vol[0] / volume) * pa[pointmtrindex]
23354 + (vol[1] / volume) * pb[pointmtrindex];
23355 }
23356 } else if (iloc == (int) ONVERTEX) {
23357 pa = org(*searchtet);
23358 if (pa[pointmtrindex] > 0) {
23359 size = pa[pointmtrindex];
23360 }
23361 }
23362
23363 return size;
23364}
23365
23366///////////////////////////////////////////////////////////////////////////////
23367// //
23368// interpolatemeshsize() Interpolate the mesh size from a background mesh //
23369// (source) to the current mesh (destination). //
23370// //
23371///////////////////////////////////////////////////////////////////////////////
23372
23373void tetgenmesh::interpolatemeshsize()
23374{
23375 triface searchtet;
23376 point ploop;
23377 REAL minval = 0.0, maxval = 0.0;
23378 int iloc;
23379 int count;
23380
23381 if (!b->quiet) {
23382 printf("Interpolating mesh size ...\n");
23383 }
23384
23385 long bak_nonregularcount = nonregularcount;
23386 nonregularcount = 0l; // Count the number of (slow) global searches.
23387 long baksmaples = bgm->samples;
23388 bgm->samples = 3l;
23389 count = 0; // Count the number of interpolated points.
23390
23391 // Interpolate sizes for all points in the current mesh.
23392 points->traversalinit();
23393 ploop = pointtraverse();
23394 while (ploop != NULL) {
23395 // Search a tet in bgm which containing this point.
23396 searchtet.tet = NULL;
23397 iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
23398 if (iloc != (int) OUTSIDE) {
23399 // Interpolate the mesh size.
23400 ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
23401 setpoint2bgmtet(ploop, bgm->encode(searchtet));
23402 if (count == 0) {
23403 // This is the first interpolated point.
23404 minval = maxval = ploop[pointmtrindex];
23405 } else {
23406 if (ploop[pointmtrindex] < minval) {
23407 minval = ploop[pointmtrindex];
23408 }
23409 if (ploop[pointmtrindex] > maxval) {
23410 maxval = ploop[pointmtrindex];
23411 }
23412 }
23413 count++;
23414 } else {
23415 if (!b->quiet) {
23416 printf("Warnning: Failed to locate point %d in source mesh.\n",
23417 pointmark(ploop));
23418 }
23419 }
23420 ploop = pointtraverse();
23421 }
23422
23423 if (b->verbose) {
23424 printf(" Interoplated %d points.\n", count);
23425 if (nonregularcount > 0l) {
23426 printf(" Performed %ld brute-force searches.\n", nonregularcount);
23427 }
23428 printf(" Size rangle [%.17g, %.17g].\n", minval, maxval);
23429 }
23430
23431 bgm->samples = baksmaples;
23432 nonregularcount = bak_nonregularcount;
23433}
23434
23435///////////////////////////////////////////////////////////////////////////////
23436// //
23437// insertconstrainedpoints() Insert a list of points into the mesh. //
23438// //
23439// Assumption: The bounding box of the insert point set should be no larger //
23440// than the bounding box of the mesh. (Required by point sorting). //
23441// //
23442///////////////////////////////////////////////////////////////////////////////
23443
23444void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen,
23445 int rejflag)
23446{
23447 triface searchtet, spintet;
23448 face splitsh;
23449 face splitseg;
23450 insertvertexflags ivf;
23451 flipconstraints fc;
23452 int randflag = 0;
23453 int t1ver;
23454 int i;
23455
23456 if (b->verbose) {
23457 printf(" Inserting %d constrained points\n", arylen);
23458 }
23459
23460 if (b->no_sort) { // -b/1 option.
23461 if (b->verbose) {
23462 printf(" Using the input order.\n");
23463 }
23464 } else {
23465 if (b->verbose) {
23466 printf(" Permuting vertices.\n");
23467 }
23468 point swappoint;
23469 int randindex;
23470 srand(arylen);
23471 for (i = 0; i < arylen; i++) {
23472 randindex = rand() % (i + 1);
23473 swappoint = insertarray[i];
23474 insertarray[i] = insertarray[randindex];
23475 insertarray[randindex] = swappoint;
23476 }
23477 if (b->brio_hilbert) { // -b1 option
23478 if (b->verbose) {
23479 printf(" Sorting vertices.\n");
23480 }
23481 hilbert_init(in->mesh_dim);
23482 int ngroup = 0;
23483 brio_multiscale_sort(insertarray, arylen, b->brio_threshold,
23484 b->brio_ratio, &ngroup);
23485 } else { // -b0 option.
23486 randflag = 1;
23487 } // if (!b->brio_hilbert)
23488 } // if (!b->no_sort)
23489
23490 long bak_nonregularcount = nonregularcount;
23491 nonregularcount = 0l;
23492 long baksmaples = samples;
23493 samples = 3l; // Use at least 3 samples. Updated in randomsample().
23494
23495 long bak_seg_count = st_segref_count;
23496 long bak_fac_count = st_facref_count;
23497 long bak_vol_count = st_volref_count;
23498
23499 // Initialize the insertion parameters.
23500 if (b->incrflip) { // -l option
23501 // Use incremental flip algorithm.
23502 ivf.bowywat = 0;
23503 ivf.lawson = 1;
23504 ivf.validflag = 0; // No need to validate the cavity.
23505 fc.enqflag = 2;
23506 } else {
23507 // Use Bowyer-Watson algorithm.
23508 ivf.bowywat = 1;
23509 ivf.lawson = 0;
23510 ivf.validflag = 1; // Validate the B-W cavity.
23511 }
23512 ivf.rejflag = rejflag;
23513 ivf.chkencflag = 0;
23514 ivf.sloc = (int) INSTAR;
23515 ivf.sbowywat = 3;
23516 ivf.splitbdflag = 1;
23517 ivf.respectbdflag = 1;
23518 ivf.assignmeshsize = b->metric;
23519
23520 encseglist = new arraypool(sizeof(face), 8);
23521 encshlist = new arraypool(sizeof(badface), 8);
23522
23523 // Insert the points.
23524 for (i = 0; i < arylen; i++) {
23525 // Find the location of the inserted point.
23526 // Do not use 'recenttet', since the mesh may be non-convex.
23527 searchtet.tet = NULL;
23528 ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
23529
23530 // Decide the right type for this point.
23531 setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
23532 splitsh.sh = NULL;
23533 splitseg.sh = NULL;
23534 if (ivf.iloc == (int) ONEDGE) {
23535 if (issubseg(searchtet)) {
23536 tsspivot1(searchtet, splitseg);
23537 setpointtype(insertarray[i], FREESEGVERTEX);
23538 //ivf.rejflag = 0;
23539 } else {
23540 // Check if it is a subface edge.
23541 spintet = searchtet;
23542 while (1) {
23543 if (issubface(spintet)) {
23544 tspivot(spintet, splitsh);
23545 setpointtype(insertarray[i], FREEFACETVERTEX);
23546 //ivf.rejflag |= 1;
23547 break;
23548 }
23549 fnextself(spintet);
23550 if (spintet.tet == searchtet.tet) break;
23551 }
23552 }
23553 } else if (ivf.iloc == (int) ONFACE) {
23554 if (issubface(searchtet)) {
23555 tspivot(searchtet, splitsh);
23556 setpointtype(insertarray[i], FREEFACETVERTEX);
23557 //ivf.rejflag |= 1;
23558 }
23559 }
23560
23561 // Now insert the point.
23562 if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
23563 if (flipstack != NULL) {
23564 // There are queued faces. Use flips to recover Delaunayness.
23565 lawsonflip3d(&fc);
23566 // There may be unflippable edges. Ignore them.
23567 unflipqueue->restart();
23568 }
23569 // Update the Steiner counters.
23570 if (pointtype(insertarray[i]) == FREESEGVERTEX) {
23571 st_segref_count++;
23572 } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
23573 st_facref_count++;
23574 } else {
23575 st_volref_count++;
23576 }
23577 } else {
23578 // Point is not inserted.
23579 //pointdealloc(insertarray[i]);
23580 setpointtype(insertarray[i], UNUSEDVERTEX);
23581 unuverts++;
23582 encseglist->restart();
23583 encshlist->restart();
23584 }
23585 } // i
23586
23587 delete encseglist;
23588 delete encshlist;
23589
23590 if (b->verbose) {
23591 printf(" Inserted %ld (%ld, %ld, %ld) vertices.\n",
23592 st_segref_count + st_facref_count + st_volref_count -
23593 (bak_seg_count + bak_fac_count + bak_vol_count),
23594 st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
23595 st_volref_count - bak_vol_count);
23596 if (nonregularcount > 0l) {
23597 printf(" Performed %ld brute-force searches.\n", nonregularcount);
23598 }
23599 }
23600
23601 nonregularcount = bak_nonregularcount;
23602 samples = baksmaples;
23603}
23604
23605void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
23606{
23607 point *insertarray, newpt;
23608 REAL x, y, z, w;
23609 int index, attribindex, mtrindex;
23610 int arylen, i, j;
23611
23612 if (!b->quiet) {
23613 printf("Inserting constrained points ...\n");
23614 }
23615
23616 insertarray = new point[addio->numberofpoints];
23617 arylen = 0;
23618 index = 0;
23619 attribindex = 0;
23620 mtrindex = 0;
23621
23622 for (i = 0; i < addio->numberofpoints; i++) {
23623 x = addio->pointlist[index++];
23624 y = addio->pointlist[index++];
23625 z = addio->pointlist[index++];
23626 // Test if this point lies inside the bounding box.
23627 if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
23628 (z < zmin) || (z > zmax)) {
23629 if (b->verbose) {
23630 printf("Warning: Point #%d lies outside the bounding box. Ignored\n",
23631 i + in->firstnumber);
23632 }
23633 continue;
23634 }
23635 makepoint(&newpt, UNUSEDVERTEX);
23636 newpt[0] = x;
23637 newpt[1] = y;
23638 newpt[2] = z;
23639 // Read the point attributes. (Including point weights.)
23640 for (j = 0; j < addio->numberofpointattributes; j++) {
23641 newpt[3 + j] = addio->pointattributelist[attribindex++];
23642 }
23643 // Read the point metric tensor.
23644 for (j = 0; j < addio->numberofpointmtrs; j++) {
23645 newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
23646 }
23647 if (b->weighted) { // -w option
23648 if (addio->numberofpointattributes > 0) {
23649 // The first point attribute is its weight.
23650 w = newpt[3];
23651 } else {
23652 // No given weight available. Default choose the maximum
23653 // absolute value among its coordinates.
23654 w = fabs(x);
23655 if (w < fabs(y)) w = fabs(y);
23656 if (w < fabs(z)) w = fabs(z);
23657 }
23658 if (b->weighted_param == 0) {
23659 newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
23660 } else { // -w1 option
23661 newpt[3] = w; // Regular tetrahedralization.
23662 }
23663 }
23664 insertarray[arylen] = newpt;
23665 arylen++;
23666 } // i
23667
23668 // Insert the points.
23669 int rejflag = 0; // Do not check encroachment.
23670 if (b->metric) { // -m option.
23671 rejflag |= 4; // Reject it if it lies in some protecting balls.
23672 }
23673
23674 insertconstrainedpoints(insertarray, arylen, rejflag);
23675
23676 delete [] insertarray;
23677}
23678
23679///////////////////////////////////////////////////////////////////////////////
23680// //
23681// meshcoarsening() Deleting (selected) vertices. //
23682// //
23683///////////////////////////////////////////////////////////////////////////////
23684
23685void tetgenmesh::collectremovepoints(arraypool *remptlist)
23686{
23687 point ptloop, *parypt;
23688 verttype vt;
23689
23690 // If a mesh sizing function is given. Collect vertices whose mesh size
23691 // is greater than its smallest edge length.
23692 if (b->metric) { // -m option
23693 REAL len, smlen;
23694 int i;
23695 points->traversalinit();
23696 ptloop = pointtraverse();
23697 while (ptloop != NULL) {
23698 if (ptloop[pointmtrindex] > 0) {
23699 // Get the smallest edge length at this vertex.
23700 getvertexstar(1, ptloop, cavetetlist, cavetetvertlist, NULL);
23701 parypt = (point *) fastlookup(cavetetvertlist, 0);
23702 smlen = distance(ptloop, *parypt);
23703 for (i = 1; i < cavetetvertlist->objects; i++) {
23704 parypt = (point *) fastlookup(cavetetvertlist, i);
23705 len = distance(ptloop, *parypt);
23706 if (len < smlen) {
23707 smlen = len;
23708 }
23709 }
23710 cavetetvertlist->restart();
23711 cavetetlist->restart();
23712 if (smlen < ptloop[pointmtrindex]) {
23713 pinfect(ptloop);
23714 remptlist->newindex((void **) &parypt);
23715 *parypt = ptloop;
23716 }
23717 }
23718 ptloop = pointtraverse();
23719 }
23720 if (b->verbose > 1) {
23721 printf(" Coarsen %ld oversized points.\n", remptlist->objects);
23722 }
23723 }
23724
23725 // If 'in->pointmarkerlist' exists, Collect vertices with markers '-1'.
23726 if (in->pointmarkerlist != NULL) {
23727 long bak_count = remptlist->objects;
23728 points->traversalinit();
23729 ptloop = pointtraverse();
23730 int index = 0;
23731 while (ptloop != NULL) {
23732 if (index < in->numberofpoints) {
23733 if (in->pointmarkerlist[index] == -1) {
23734 pinfect(ptloop);
23735 remptlist->newindex((void **) &parypt);
23736 *parypt = ptloop;
23737 }
23738 } else {
23739 // Remaining are not input points. Stop here.
23740 break;
23741 }
23742 index++;
23743 ptloop = pointtraverse();
23744 }
23745 if (b->verbose > 1) {
23746 printf(" Coarsen %ld marked points.\n", remptlist->objects - bak_count);
23747 }
23748 } // if (in->pointmarkerlist != NULL)
23749
23750 if (b->coarsen_param > 0) { // -R1/#
23751 // Remove a coarsen_percent number of interior points.
23752 assert((b->coarsen_percent > 0) && (b->coarsen_percent <= 1.0));
23753 if (b->verbose > 1) {
23754 printf(" Coarsen %g percent of interior points.\n",
23755 b->coarsen_percent * 100.0);
23756 }
23757 arraypool *intptlist = new arraypool(sizeof(point *), 10);
23758 // Count the total number of interior points.
23759 points->traversalinit();
23760 ptloop = pointtraverse();
23761 while (ptloop != NULL) {
23762 vt = pointtype(ptloop);
23763 if ((vt == VOLVERTEX) || (vt == FREEVOLVERTEX) ||
23764 (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX)) {
23765 intptlist->newindex((void **) &parypt);
23766 *parypt = ptloop;
23767 }
23768 ptloop = pointtraverse();
23769 }
23770 if (intptlist->objects > 0l) {
23771 // Sort the list of points randomly.
23772 point *parypt_i, swappt;
23773 int randindex, i;
23774 srand(intptlist->objects);
23775 for (i = 0; i < intptlist->objects; i++) {
23776 randindex = rand() % (i + 1); // randomnation(i + 1);
23777 parypt_i = (point *) fastlookup(intptlist, i);
23778 parypt = (point *) fastlookup(intptlist, randindex);
23779 // Swap this two points.
23780 swappt = *parypt_i;
23781 *parypt_i = *parypt;
23782 *parypt = swappt;
23783 }
23784 int remcount = (int) ((REAL) intptlist->objects * b->coarsen_percent);
23785 // Return the first remcount points.
23786 for (i = 0; i < remcount; i++) {
23787 parypt_i = (point *) fastlookup(intptlist, i);
23788 if (!pinfected(*parypt_i)) {
23789 pinfected(*parypt_i);
23790 remptlist->newindex((void **) &parypt);
23791 *parypt = *parypt_i;
23792 }
23793 }
23794 }
23795 delete intptlist;
23796 }
23797
23798 // Unmark all collected vertices.
23799 for (int i = 0; i < remptlist->objects; i++) {
23800 parypt = (point *) fastlookup(remptlist, i);
23801 puninfect(*parypt);
23802 }
23803}
23804
23805void tetgenmesh::meshcoarsening()
23806{
23807 arraypool *remptlist;
23808
23809 if (!b->quiet) {
23810 printf("Mesh coarsening ...\n");
23811 }
23812
23813 // Collect the set of points to be removed
23814 remptlist = new arraypool(sizeof(point *), 10);
23815 collectremovepoints(remptlist);
23816
23817 if (remptlist->objects == 0l) {
23818 delete remptlist;
23819 return;
23820 }
23821
23822 if (b->verbose) {
23823 if (remptlist->objects > 0l) {
23824 printf(" Removing %ld points...\n", remptlist->objects);
23825 }
23826 }
23827
23828 point *parypt, *plastpt;
23829 long ms = remptlist->objects;
23830 int nit = 0;
23831 int bak_fliplinklevel = b->fliplinklevel;
23832 b->fliplinklevel = -1;
23833 autofliplinklevel = 1; // Init value.
23834 int i;
23835
23836 while (1) {
23837
23838 if (b->verbose > 1) {
23839 printf(" Removing points [%s level = %2d] #: %ld.\n",
23840 (b->fliplinklevel > 0) ? "fixed" : "auto",
23841 (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
23842 remptlist->objects);
23843 }
23844
23845 // Remove the list of points.
23846 for (i = 0; i < remptlist->objects; i++) {
23847 parypt = (point *) fastlookup(remptlist, i);
23848 assert(pointtype(*parypt) != UNUSEDVERTEX);
23849 if (removevertexbyflips(*parypt)) {
23850 // Move the last entry to the current place.
23851 plastpt = (point *) fastlookup(remptlist, remptlist->objects - 1);
23852 *parypt = *plastpt;
23853 remptlist->objects--;
23854 i--;
23855 }
23856 }
23857
23858 if (remptlist->objects > 0l) {
23859 if (b->fliplinklevel >= 0) {
23860 break; // We have tried all levels.
23861 }
23862 if (remptlist->objects == ms) {
23863 nit++;
23864 if (nit >= 3) {
23865 // Do the last round with unbounded flip link level.
23866 b->fliplinklevel = 100000;
23867 }
23868 } else {
23869 ms = remptlist->objects;
23870 if (nit > 0) {
23871 nit--;
23872 }
23873 }
23874 autofliplinklevel+=b->fliplinklevelinc;
23875 } else {
23876 // All points are removed.
23877 break;
23878 }
23879 } // while (1)
23880
23881 if (remptlist->objects > 0l) {
23882 if (b->verbose) {
23883 printf(" %ld points are not removed !\n", remptlist->objects);
23884 }
23885 }
23886
23887 b->fliplinklevel = bak_fliplinklevel;
23888 delete remptlist;
23889}
23890
23891//// ////
23892//// ////
23893//// reconstruct_cxx //////////////////////////////////////////////////////////
23894
23895//// refine_cxx ///////////////////////////////////////////////////////////////
23896//// ////
23897//// ////
23898
23899///////////////////////////////////////////////////////////////////////////////
23900// //
23901// makefacetverticesmap() Create a map from facet to its vertices. //
23902// //
23903// All facets will be indexed (starting from 0). The map is saved in two //
23904// global arrays: 'idx2facetlist' and 'facetverticeslist'. //
23905// //
23906///////////////////////////////////////////////////////////////////////////////
23907
23908void tetgenmesh::makefacetverticesmap()
23909{
23910 arraypool *facetvertexlist, *vertlist, **paryvertlist;
23911 face subloop, neighsh, *parysh, *parysh1;
23912 point pa, *ppt, *parypt;
23913 verttype vt;
23914 int facetindex, totalvertices;
23915 int i, j, k;
23916
23917 if (b->verbose) {
23918 printf(" Creating the facet vertices map.\n");
23919 }
23920
23921 facetvertexlist = new arraypool(sizeof(arraypool *), 10);
23922 facetindex = totalvertices = 0;
23923
23924 subfaces->traversalinit();
23925 subloop.sh = shellfacetraverse(subfaces);
23926 while (subloop.sh != NULL) {
23927 if (!sinfected(subloop)) {
23928 // A new facet. Create its vertices list.
23929 vertlist = new arraypool(sizeof(point *), 8);
23930 ppt = (point *) &(subloop.sh[3]);
23931 for (k = 0; k < 3; k++) {
23932 vt = pointtype(ppt[k]);
23933 if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
23934 pinfect(ppt[k]);
23935 vertlist->newindex((void **) &parypt);
23936 *parypt = ppt[k];
23937 }
23938 }
23939 sinfect(subloop);
23940 caveshlist->newindex((void **) &parysh);
23941 *parysh = subloop;
23942 for (i = 0; i < caveshlist->objects; i++) {
23943 parysh = (face *) fastlookup(caveshlist, i);
23944 setfacetindex(*parysh, facetindex);
23945 for (j = 0; j < 3; j++) {
23946 if (!isshsubseg(*parysh)) {
23947 spivot(*parysh, neighsh);
23948 assert(neighsh.sh != NULL);
23949 if (!sinfected(neighsh)) {
23950 pa = sapex(neighsh);
23951 if (!pinfected(pa)) {
23952 vt = pointtype(pa);
23953 if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
23954 pinfect(pa);
23955 vertlist->newindex((void **) &parypt);
23956 *parypt = pa;
23957 }
23958 }
23959 sinfect(neighsh);
23960 caveshlist->newindex((void **) &parysh1);
23961 *parysh1 = neighsh;
23962 }
23963 }
23964 senextself(*parysh);
23965 }
23966 } // i
23967 totalvertices += (int) vertlist->objects;
23968 // Uninfect facet vertices.
23969 for (k = 0; k < vertlist->objects; k++) {
23970 parypt = (point *) fastlookup(vertlist, k);
23971 puninfect(*parypt);
23972 }
23973 caveshlist->restart();
23974 // Save this vertex list.
23975 facetvertexlist->newindex((void **) &paryvertlist);
23976 *paryvertlist = vertlist;
23977 facetindex++;
23978 }
23979 subloop.sh = shellfacetraverse(subfaces);
23980 }
23981
23982 // All subfaces are infected. Uninfect them.
23983 subfaces->traversalinit();
23984 subloop.sh = shellfacetraverse(subfaces);
23985 while (subloop.sh != NULL) {
23986 assert(sinfected(subloop));
23987 suninfect(subloop);
23988 subloop.sh = shellfacetraverse(subfaces);
23989 }
23990
23991 if (b->verbose) {
23992 printf(" Found %ld facets.\n", facetvertexlist->objects);
23993 }
23994
23995 idx2facetlist = new int[facetindex + 1];
23996 facetverticeslist = new point[totalvertices];
23997
23998 totalworkmemory += ((facetindex + 1) * sizeof(int) +
23999 totalvertices * sizeof(point *));
24000
24001 idx2facetlist[0] = 0;
24002 for (i = 0, k = 0; i < facetindex; i++) {
24003 paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24004 vertlist = *paryvertlist;
24005 idx2facetlist[i + 1] = (idx2facetlist[i] + (int) vertlist->objects);
24006 for (j = 0; j < vertlist->objects; j++) {
24007 parypt = (point *) fastlookup(vertlist, j);
24008 facetverticeslist[k] = *parypt;
24009 k++;
24010 }
24011 }
24012 assert(k == totalvertices);
24013
24014 // Free the lists.
24015 for (i = 0; i < facetvertexlist->objects; i++) {
24016 paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24017 vertlist = *paryvertlist;
24018 delete vertlist;
24019 }
24020 delete facetvertexlist;
24021}
24022
24023///////////////////////////////////////////////////////////////////////////////
24024// //
24025// Check whether two segments, or a segment and a facet, or two facets are //
24026// adjacent to each other. //
24027// //
24028///////////////////////////////////////////////////////////////////////////////
24029
24030int tetgenmesh::segsegadjacent(face *seg1, face *seg2)
24031{
24032 int segidx1 = getfacetindex(*seg1);
24033 int segidx2 = getfacetindex(*seg2);
24034
24035 if (segidx1 == segidx2) return 0;
24036
24037 point pa1 = segmentendpointslist[segidx1 * 2];
24038 point pb1 = segmentendpointslist[segidx1 * 2 + 1];
24039 point pa2 = segmentendpointslist[segidx2 * 2];
24040 point pb2 = segmentendpointslist[segidx2 * 2 + 1];
24041
24042 if ((pa1 == pa2) || (pa1 == pb2) || (pb1 == pa2) || (pb1 == pb2)) {
24043 return 1;
24044 }
24045 return 0;
24046}
24047
24048int tetgenmesh::segfacetadjacent(face *subseg, face *subsh)
24049{
24050 int segidx = getfacetindex(*subseg);
24051 point pa = segmentendpointslist[segidx * 2];
24052 point pb = segmentendpointslist[segidx * 2 + 1];
24053
24054 pinfect(pa);
24055 pinfect(pb);
24056
24057 int fidx = getfacetindex(*subsh);
24058 int count = 0, i;
24059
24060 for (i = idx2facetlist[fidx]; i < idx2facetlist[fidx+1]; i++) {
24061 if (pinfected(facetverticeslist[i])) count++;
24062 }
24063
24064 puninfect(pa);
24065 puninfect(pb);
24066
24067 return count == 1;
24068}
24069
24070int tetgenmesh::facetfacetadjacent(face *subsh1, face *subsh2)
24071{
24072 int count = 0, i;
24073
24074 int fidx1 = getfacetindex(*subsh1);
24075 int fidx2 = getfacetindex(*subsh2);
24076
24077 if (fidx1 == fidx2) return 0;
24078
24079 for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24080 pinfect(facetverticeslist[i]);
24081 }
24082
24083 for (i = idx2facetlist[fidx2]; i < idx2facetlist[fidx2+1]; i++) {
24084 if (pinfected(facetverticeslist[i])) count++;
24085 }
24086
24087 // Uninfect the vertices.
24088 for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24089 puninfect(facetverticeslist[i]);
24090 }
24091
24092 return count > 0;
24093}
24094
24095///////////////////////////////////////////////////////////////////////////////
24096// //
24097// checkseg4encroach() Check if an edge is encroached upon by a point. //
24098// //
24099///////////////////////////////////////////////////////////////////////////////
24100
24101int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
24102{
24103 // Check if the point lies inside the diametrical sphere of this seg.
24104 REAL v1[3], v2[3];
24105
24106 v1[0] = pa[0] - checkpt[0];
24107 v1[1] = pa[1] - checkpt[1];
24108 v1[2] = pa[2] - checkpt[2];
24109 v2[0] = pb[0] - checkpt[0];
24110 v2[1] = pb[1] - checkpt[1];
24111 v2[2] = pb[2] - checkpt[2];
24112
24113 if (dot(v1, v2) < 0) {
24114 // Inside.
24115 if (b->metric) { // -m option.
24116 if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
24117 // The projection of 'checkpt' lies inside the segment [a,b].
24118 REAL prjpt[3], u, v, t;
24119 projpt2edge(checkpt, pa, pb, prjpt);
24120 // Interoplate the mesh size at the location 'prjpt'.
24121 u = distance(pa, pb);
24122 v = distance(pa, prjpt);
24123 t = v / u;
24124 // 'u' is the mesh size at 'prjpt'
24125 u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
24126 v = distance(checkpt, prjpt);
24127 if (v < u) {
24128 return 1; // Encroached prot-ball!
24129 }
24130 } else {
24131 return 1; // NO protecting ball. Encroached.
24132 }
24133 } else {
24134 return 1; // Inside! Encroached.
24135 }
24136 }
24137
24138 return 0;
24139}
24140
24141///////////////////////////////////////////////////////////////////////////////
24142// //
24143// checkseg4split() Check if we need to split a segment. //
24144// //
24145// A segment needs to be split if it is in the following case: //
24146// (1) It is encroached by an existing vertex. //
24147// (2) It has bad quality (too long). //
24148// (3) Its length is larger than the mesh sizes at its endpoints. //
24149// //
24150// Return 1 if it needs to be split, otherwise, return 0. 'pencpt' returns //
24151// an encroaching point if there exists. 'qflag' returns '1' if the segment //
24152// has a length larger than the desired edge length. //
24153// //
24154///////////////////////////////////////////////////////////////////////////////
24155
24156int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
24157{
24158 REAL ccent[3], len, r;
24159 int i;
24160
24161 point forg = sorg(*chkseg);
24162 point fdest = sdest(*chkseg);
24163
24164 // Initialize the return values.
24165 encpt = NULL;
24166 qflag = 0;
24167
24168 len = distance(forg, fdest);
24169 r = 0.5 * len;
24170 for (i = 0; i < 3; i++) {
24171 ccent[i] = 0.5 * (forg[i] + fdest[i]);
24172 }
24173
24174 // First check its quality.
24175 if (checkconstraints && (areabound(*chkseg) > 0.0)) {
24176 if (len > areabound(*chkseg)) {
24177 qflag = 1;
24178 return 1;
24179 }
24180 }
24181
24182 if (b->fixedvolume) {
24183 if ((len * len * len) > b->maxvolume) {
24184 qflag = 1;
24185 return 1;
24186 }
24187 }
24188
24189 if (b->metric) { // -m option. Check mesh size.
24190 // Check if the ccent lies outside one of the prot.balls at vertices.
24191 if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
24192 ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
24193 qflag = 1; // Enforce mesh size.
24194 return 1;
24195 }
24196 }
24197
24198
24199 // Second check if it is encroached.
24200 // Comment: There may exist more than one encroaching points of this segment.
24201 // The 'encpt' returns the one which is closet to it.
24202 triface searchtet, spintet;
24203 point eapex;
24204 REAL d, diff, smdist = 0;
24205 int t1ver;
24206
24207 sstpivot1(*chkseg, searchtet);
24208 spintet = searchtet;
24209 while (1) {
24210 eapex = apex(spintet);
24211 if (eapex != dummypoint) {
24212 d = distance(ccent, eapex);
24213 diff = d - r;
24214 if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
24215 if (diff < 0) {
24216 // This segment is encroached by eapex.
24217 if (useinsertradius) {
24218 if (encpt == NULL) {
24219 encpt = eapex;
24220 smdist = d;
24221 } else {
24222 // Choose the closet encroaching point.
24223 if (d < smdist) {
24224 encpt = eapex;
24225 smdist = d;
24226 }
24227 }
24228 } else {
24229 encpt = eapex;
24230 break;
24231 }
24232 }
24233 }
24234 fnextself(spintet);
24235 if (spintet.tet == searchtet.tet) break;
24236 } // while (1)
24237
24238 if (encpt != NULL) {
24239 return 1;
24240 }
24241
24242 return 0; // No need to split it.
24243}
24244
24245///////////////////////////////////////////////////////////////////////////////
24246// //
24247// splitsegment() Split a segment. //
24248// //
24249// The segment 'splitseg' is intended to be split. It will be split if it //
24250// is in one of the following cases: //
24251// (1) It is encroached by an existing vertex 'encpt != NULL'; or //
24252// (2) It is in bad quality 'qflag == 1'; or //
24253// (3) Its length is larger than the mesh sizes at its endpoints. //
24254// //
24255///////////////////////////////////////////////////////////////////////////////
24256
24257int tetgenmesh::splitsegment(face *splitseg, point encpt, REAL rrp,
24258 point encpt1, point encpt2, int qflag,
24259 int chkencflag)
24260{
24261 point pa = sorg(*splitseg);
24262 point pb = sdest(*splitseg);
24263
24264
24265
24266 if ((encpt == NULL) && (qflag == 0)) {
24267 if (useinsertradius) {
24268 // Do not split this segment if the length is smaller than the smaller
24269 // insertion radius at its endpoints.
24270 REAL len = distance(pa, pb);
24271 REAL smrrv = getpointinsradius(pa);
24272 REAL rrv = getpointinsradius(pb);
24273 if (rrv > 0) {
24274 if (smrrv > 0) {
24275 if (rrv < smrrv) {
24276 smrrv = rrv;
24277 }
24278 } else {
24279 smrrv = rrv;
24280 }
24281 }
24282 if (smrrv > 0) {
24283 if ((fabs(smrrv - len) / len) < b->epsilon) smrrv = len;
24284 if (len < smrrv) {
24285 return 0;
24286 }
24287 }
24288 }
24289 }
24290
24291 if (b->nobisect) { // With -Y option.
24292 // Only split this segment if it is allowed to be split.
24293 if (checkconstraints) {
24294 // Check if it has a non-zero length bound.
24295 if (areabound(*splitseg) == 0) {
24296 // It is not allowed. However, if all of facets containing this seg
24297 // is allowed to be split, we still split it.
24298 face parentsh, spinsh;
24299 //splitseg.shver = 0;
24300 spivot(*splitseg, parentsh);
24301 if (parentsh.sh == NULL) {
24302 return 0; // A dangling segment. Do not split it.
24303 }
24304 spinsh = parentsh;
24305 while (1) {
24306 if (areabound(spinsh) == 0) break;
24307 spivotself(spinsh);
24308 if (spinsh.sh == parentsh.sh) break;
24309 }
24310 if (areabound(spinsh) == 0) {
24311 // All facets at this seg are not allowed to be split.
24312 return 0; // Do not split it.
24313 }
24314 }
24315 } else {
24316 return 0; // Do not split this segment.
24317 }
24318 } // if (b->nobisect)
24319
24320 triface searchtet;
24321 face searchsh;
24322 point newpt;
24323 insertvertexflags ivf;
24324
24325 makepoint(&newpt, FREESEGVERTEX);
24326 getsteinerptonsegment(splitseg, encpt, newpt);
24327
24328 // Split the segment by the Bowyer-Watson algorithm.
24329 sstpivot1(*splitseg, searchtet);
24330 ivf.iloc = (int) ONEDGE;
24331 // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
24332 ivf.bowywat = 3;
24333 ivf.validflag = 1; // Validate the B-W cavity.
24334 ivf.lawson = 2; // Do flips to recover Delaunayness.
24335 ivf.rejflag = 0; // Do not check encroachment of new segments/facets.
24336 if (b->metric) {
24337 ivf.rejflag |= 4; // Do check encroachment of protecting balls.
24338 }
24339 ivf.chkencflag = chkencflag;
24340 ivf.sloc = (int) INSTAR; // ivf.iloc;
24341 ivf.sbowywat = 3; // ivf.bowywat; // Surface mesh options.
24342 ivf.splitbdflag = 1;
24343 ivf.respectbdflag = 1;
24344 ivf.assignmeshsize = b->metric;
24345 ivf.smlenflag = useinsertradius;
24346
24347
24348 if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
24349 st_segref_count++;
24350 if (steinerleft > 0) steinerleft--;
24351 if (useinsertradius) {
24352 // Update 'rv' (to be the shortest distance).
24353 REAL rv = ivf.smlen, rp;
24354 if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
24355 face parentseg1, parentseg2;
24356 sdecode(point2sh(newpt), parentseg1);
24357 sdecode(point2sh(ivf.parentpt), parentseg2);
24358 if (segsegadjacent(&parentseg1, &parentseg2)) {
24359 rp = getpointinsradius(ivf.parentpt);
24360 if (rv < rp) {
24361 rv = rp; // The relaxed insertion radius of 'newpt'.
24362 }
24363 }
24364 } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
24365 face parentseg, parentsh;
24366 sdecode(point2sh(newpt), parentseg);
24367 sdecode(point2sh(ivf.parentpt), parentsh);
24368 if (segfacetadjacent(&parentseg, &parentsh)) {
24369 rp = getpointinsradius(ivf.parentpt);
24370 if (rv < rp) {
24371 rv = rp; // The relaxed insertion radius of 'newpt'.
24372 }
24373 }
24374 }
24375 setpointinsradius(newpt, rv);
24376 }
24377 if (flipstack != NULL) {
24378 flipconstraints fc;
24379 fc.chkencflag = chkencflag;
24380 fc.enqflag = 2;
24381 lawsonflip3d(&fc);
24382 unflipqueue->restart();
24383 }
24384 return 1;
24385 } else {
24386 // Point is not inserted.
24387 pointdealloc(newpt);
24388 return 0;
24389 }
24390}
24391
24392///////////////////////////////////////////////////////////////////////////////
24393// //
24394// repairencsegs() Repair encroached (sub) segments. //
24395// //
24396///////////////////////////////////////////////////////////////////////////////
24397
24398void tetgenmesh::repairencsegs(int chkencflag)
24399{
24400 face *bface;
24401 point encpt = NULL;
24402 int qflag = 0;
24403
24404 // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
24405 // if an unlimited number of Steiner points is allowed.
24406 while ((badsubsegs->items > 0) && (steinerleft != 0)) {
24407 badsubsegs->traversalinit();
24408 bface = (face *) badsubsegs->traverse();
24409 while ((bface != NULL) && (steinerleft != 0)) {
24410 // Skip a deleleted element.
24411 if (bface->shver >= 0) {
24412 // A queued segment may have been deleted (split).
24413 if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24414 // A queued segment may have been processed.
24415 if (smarktest2ed(*bface)) {
24416 sunmarktest2(*bface);
24417 if (checkseg4split(bface, encpt, qflag)) {
24418 splitsegment(bface, encpt, 0, NULL, NULL, qflag, chkencflag);
24419 }
24420 }
24421 }
24422 // Remove this entry from list.
24423 bface->shver = -1; // Signal it as a deleted element.
24424 badsubsegs->dealloc((void *) bface);
24425 }
24426 bface = (face *) badsubsegs->traverse();
24427 }
24428 }
24429
24430 if (badsubsegs->items > 0) {
24431 if (steinerleft == 0) {
24432 if (b->verbose) {
24433 printf("The desired number of Steiner points is reached.\n");
24434 }
24435 } else {
24436 assert(0); // Unknown case.
24437 }
24438 badsubsegs->traversalinit();
24439 bface = (face *) badsubsegs->traverse();
24440 while (bface != NULL) {
24441 // Skip a deleleted element.
24442 if (bface->shver >= 0) {
24443 if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24444 if (smarktest2ed(*bface)) {
24445 sunmarktest2(*bface);
24446 }
24447 }
24448 }
24449 bface = (face *) badsubsegs->traverse();
24450 }
24451 badsubsegs->restart();
24452 }
24453}
24454
24455///////////////////////////////////////////////////////////////////////////////
24456// //
24457// enqueuesubface() Queue a subface or a subsegment for encroachment chk. //
24458// //
24459///////////////////////////////////////////////////////////////////////////////
24460
24461void tetgenmesh::enqueuesubface(memorypool *pool, face *chkface)
24462{
24463 if (!smarktest2ed(*chkface)) {
24464 smarktest2(*chkface); // Only queue it once.
24465 face *queface = (face *) pool->alloc();
24466 *queface = *chkface;
24467 }
24468}
24469
24470///////////////////////////////////////////////////////////////////////////////
24471// //
24472// checkfac4encroach() Check if a subface is encroached by a point. //
24473// //
24474///////////////////////////////////////////////////////////////////////////////
24475
24476int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
24477 REAL* cent, REAL* r)
24478{
24479 REAL rd, len;
24480
24481 circumsphere(pa, pb, pc, NULL, cent, &rd);
24482 assert(rd != 0);
24483 len = distance(cent, checkpt);
24484 if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
24485
24486 if (len < rd) {
24487 // The point lies inside the circumsphere of this face.
24488 if (b->metric) { // -m option.
24489 if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
24490 (pc[pointmtrindex] > 0)) {
24491 // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
24492 REAL prjpt[3], n[3];
24493 REAL a, a1, a2, a3;
24494 projpt2face(checkpt, pa, pb, pc, prjpt);
24495 // Get the face area of [a,b,c].
24496 facenormal(pa, pb, pc, n, 1, NULL);
24497 a = sqrt(dot(n,n));
24498 // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
24499 facenormal(pa, pb, prjpt, n, 1, NULL);
24500 a1 = sqrt(dot(n,n));
24501 facenormal(pb, pc, prjpt, n, 1, NULL);
24502 a2 = sqrt(dot(n,n));
24503 facenormal(pc, pa, prjpt, n, 1, NULL);
24504 a3 = sqrt(dot(n,n));
24505 if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
24506 // This face contains the projection.
24507 // Get the mesh size at the location of the projection point.
24508 rd = a1 / a * pc[pointmtrindex]
24509 + a2 / a * pa[pointmtrindex]
24510 + a3 / a * pb[pointmtrindex];
24511 len = distance(prjpt, checkpt);
24512 if (len < rd) {
24513 return 1; // Encroached.
24514 }
24515 }
24516 } else {
24517 return 1; // No protecting ball. Encroached.
24518 }
24519 } else {
24520 *r = rd;
24521 return 1; // Encroached.
24522 }
24523 }
24524
24525 return 0;
24526}
24527
24528///////////////////////////////////////////////////////////////////////////////
24529// //
24530// checkfac4split() Check if a subface needs to be split. //
24531// //
24532// A subface needs to be split if it is in the following case: //
24533// (1) It is encroached by an existing vertex. //
24534// (2) It has bad quality (has a small angle, -q). //
24535// (3) It's area is larger than a prescribed value (.var). //
24536// //
24537// Return 1 if it needs to be split, otherwise, return 0. //
24538// 'chkfac' represents its longest edge. //
24539// //
24540///////////////////////////////////////////////////////////////////////////////
24541
24542int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
24543 REAL *cent)
24544{
24545 point pa, pb, pc;
24546 REAL area, rd, len;
24547 REAL A[4][4], rhs[4], D;
24548 int indx[4];
24549 int i;
24550
24551 encpt = NULL;
24552 qflag = 0;
24553
24554 pa = sorg(*chkfac);
24555 pb = sdest(*chkfac);
24556 pc = sapex(*chkfac);
24557
24558 // Compute the coefficient matrix A (3x3).
24559 A[0][0] = pb[0] - pa[0];
24560 A[0][1] = pb[1] - pa[1];
24561 A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
24562 A[1][0] = pc[0] - pa[0];
24563 A[1][1] = pc[1] - pa[1];
24564 A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
24565 cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
24566
24567 area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
24568
24569 // Compute the right hand side vector b (3x1).
24570 rhs[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
24571 rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
24572 rhs[2] = 0.0;
24573
24574 // Solve the 3 by 3 equations use LU decomposition with partial
24575 // pivoting and backward and forward substitute.
24576 if (!lu_decmp(A, 3, indx, &D, 0)) {
24577 // A degenerate triangle.
24578 assert(0);
24579 }
24580
24581 lu_solve(A, 3, indx, rhs, 0);
24582 cent[0] = pa[0] + rhs[0];
24583 cent[1] = pa[1] + rhs[1];
24584 cent[2] = pa[2] + rhs[2];
24585 rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
24586
24587 if (checkconstraints && (areabound(*chkfac) > 0.0)) {
24588 // Check if the subface has too big area.
24589 if (area > areabound(*chkfac)) {
24590 qflag = 1;
24591 return 1;
24592 }
24593 }
24594
24595 if (b->fixedvolume) {
24596 if ((area * sqrt(area)) > b->maxvolume) {
24597 qflag = 1;
24598 return 1;
24599 }
24600 }
24601
24602 if (b->varvolume) {
24603 triface adjtet;
24604 REAL volbnd;
24605 int t1ver;
24606
24607 stpivot(*chkfac, adjtet);
24608 if (!ishulltet(adjtet)) {
24609 volbnd = volumebound(adjtet.tet);
24610 if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
24611 qflag = 1;
24612 return 1;
24613 }
24614 }
24615 fsymself(adjtet);
24616 if (!ishulltet(adjtet)) {
24617 volbnd = volumebound(adjtet.tet);
24618 if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
24619 qflag = 1;
24620 return 1;
24621 }
24622 }
24623 }
24624
24625 if (b->metric) { // -m option. Check mesh size.
24626 // Check if the ccent lies outside one of the prot.balls at vertices.
24627 if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
24628 ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
24629 ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
24630 qflag = 1; // Enforce mesh size.
24631 return 1;
24632 }
24633 }
24634
24635 triface searchtet;
24636 REAL smlen = 0;
24637
24638 // Check if this subface is locally encroached.
24639 for (i = 0; i < 2; i++) {
24640 stpivot(*chkfac, searchtet);
24641 if (!ishulltet(searchtet)) {
24642 len = distance(oppo(searchtet), cent);
24643 if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
24644 if (len < rd) {
24645 if (smlen == 0) {
24646 smlen = len;
24647 encpt = oppo(searchtet);
24648 } else {
24649 if (len < smlen) {
24650 smlen = len;
24651 encpt = oppo(searchtet);
24652 }
24653 }
24654 //return 1;
24655 }
24656 }
24657 sesymself(*chkfac);
24658 }
24659
24660 return encpt != NULL; //return 0;
24661}
24662
24663///////////////////////////////////////////////////////////////////////////////
24664// //
24665// splitsubface() Split a subface. //
24666// //
24667// The subface may be encroached, or in bad-quality. It is split at its cir- //
24668// cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg- //
24669// ment. Instead, one of the encroached segments is split. It is possible //
24670// that none of the encroached segments can be split. //
24671// //
24672// The return value indicates whether a new point is inserted (> 0) or not //
24673// (= 0). Furthermore, it is inserted on an encroached segment (= 1) or //
24674// in-side the facet (= 2). //
24675// //
24676// 'encpt' is a vertex encroaching upon this subface, i.e., it causes the //
24677// split of this subface. If 'encpt' is NULL, then the cause of the split //
24678// this subface is a rejected tet circumcenter 'p', and 'encpt1' is the //
24679// parent of 'p'. //
24680// //
24681///////////////////////////////////////////////////////////////////////////////
24682
24683int tetgenmesh::splitsubface(face *splitfac, point encpt, point encpt1,
24684 int qflag, REAL *ccent, int chkencflag)
24685{
24686 point pa = sorg(*splitfac);
24687 point pb = sdest(*splitfac);
24688 point pc = sapex(*splitfac);
24689
24690
24691
24692 if (b->nobisect) { // With -Y option.
24693 if (checkconstraints) {
24694 // Only split if it is allowed to be split.
24695 // Check if this facet has a non-zero constraint.
24696 if (areabound(*splitfac) == 0) {
24697 return 0; // Do not split it.
24698 }
24699 } else {
24700 return 0;
24701 }
24702 } // if (b->nobisect)
24703
24704 face searchsh;
24705 insertvertexflags ivf;
24706 point newpt;
24707 REAL rv = 0., rp; // Insertion radius of newpt.
24708 int i;
24709
24710 // Initialize the inserting point.
24711 makepoint(&newpt, FREEFACETVERTEX);
24712 // Split the subface at its circumcenter.
24713 for (i = 0; i < 3; i++) newpt[i] = ccent[i];
24714
24715 if (useinsertradius) {
24716 if (encpt != NULL) {
24717 rv = distance(newpt, encpt);
24718 if (pointtype(encpt) == FREESEGVERTEX) {
24719 face parentseg;
24720 sdecode(point2sh(encpt), parentseg);
24721 if (segfacetadjacent(&parentseg, splitfac)) {
24722 rp = getpointinsradius(encpt);
24723 if (rv < (sqrt(2.0) * rp)) {
24724 // This insertion may cause no termination.
24725 pointdealloc(newpt);
24726 return 0; // Reject the insertion of newpt.
24727 }
24728 }
24729 } else if (pointtype(encpt) == FREEFACETVERTEX) {
24730 face parentsh;
24731 sdecode(point2sh(encpt), parentsh);
24732 if (facetfacetadjacent(&parentsh, splitfac)) {
24733 rp = getpointinsradius(encpt);
24734 if (rv < rp) {
24735 pointdealloc(newpt);
24736 return 0; // Reject the insertion of newpt.
24737 }
24738 }
24739 }
24740 }
24741 } // if (useinsertradius)
24742
24743 // Search a subface which contains 'newpt'.
24744 searchsh = *splitfac;
24745 // Calculate an above point. It lies above the plane containing
24746 // the subface [a,b,c], and save it in dummypoint. Moreover,
24747 // the vector cent->dummypoint is the normal of the plane.
24748 calculateabovepoint4(newpt, pa, pb, pc);
24749 // Parameters: 'aflag' = 1, - above point exists.
24750 // 'cflag' = 0, - non-convex, check co-planarity of the result.
24751 // 'rflag' = 0, - no need to round the locating result.
24752 ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
24753
24754 if (!((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE))) {
24755 pointdealloc(newpt);
24756 return 0;
24757 }
24758
24759
24760 triface searchtet;
24761 face *paryseg;
24762 int splitflag;
24763
24764 // Insert the point.
24765 stpivot(searchsh, searchtet);
24766 //assert((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE));
24767 // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
24768 ivf.bowywat = 3;
24769 ivf.lawson = 2;
24770 ivf.rejflag = 1; // Do check the encroachment of segments.
24771 if (b->metric) {
24772 ivf.rejflag |= 4; // Do check encroachment of protecting balls.
24773 }
24774 ivf.chkencflag = chkencflag;
24775 ivf.sloc = (int) INSTAR; // ivf.iloc;
24776 ivf.sbowywat = 3; // ivf.bowywat;
24777 ivf.splitbdflag = 1;
24778 ivf.validflag = 1;
24779 ivf.respectbdflag = 1;
24780 ivf.assignmeshsize = b->metric;
24781
24782 ivf.refineflag = 2;
24783 ivf.refinesh = searchsh;
24784 ivf.smlenflag = useinsertradius; // Update the insertion radius.
24785
24786
24787 if (insertpoint(newpt, &searchtet, &searchsh, NULL, &ivf)) {
24788 st_facref_count++;
24789 if (steinerleft > 0) steinerleft--;
24790 if (useinsertradius) {
24791 // Update 'rv' (to be the shortest distance).
24792 rv = ivf.smlen;
24793 if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
24794 face parentseg, parentsh;
24795 sdecode(point2sh(ivf.parentpt), parentseg);
24796 sdecode(point2sh(newpt), parentsh);
24797 if (segfacetadjacent(&parentseg, &parentsh)) {
24798 rp = getpointinsradius(ivf.parentpt);
24799 if (rv < (sqrt(2.0) * rp)) {
24800 rv = sqrt(2.0) * rp; // The relaxed insertion radius of 'newpt'.
24801 }
24802 }
24803 } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
24804 face parentsh1, parentsh2;
24805 sdecode(point2sh(ivf.parentpt), parentsh1);
24806 sdecode(point2sh(newpt), parentsh2);
24807 if (facetfacetadjacent(&parentsh1, &parentsh2)) {
24808 rp = getpointinsradius(ivf.parentpt);
24809 if (rv < rp) {
24810 rv = rp; // The relaxed insertion radius of 'newpt'.
24811 }
24812 }
24813 }
24814 setpointinsradius(newpt, rv);
24815 } // if (useinsertradius)
24816 if (flipstack != NULL) {
24817 flipconstraints fc;
24818 fc.chkencflag = chkencflag;
24819 fc.enqflag = 2;
24820 lawsonflip3d(&fc);
24821 unflipqueue->restart();
24822 }
24823 return 1;
24824 } else {
24825 // Point was not inserted.
24826 pointdealloc(newpt);
24827 if (ivf.iloc == (int) ENCSEGMENT) {
24828 // Select an encroached segment and split it.
24829 splitflag = 0;
24830 for (i = 0; i < encseglist->objects; i++) {
24831 paryseg = (face *) fastlookup(encseglist, i);
24832 if (splitsegment(paryseg, NULL, rv, encpt, encpt1, qflag,
24833 chkencflag | 1)) {
24834 splitflag = 1; // A point is inserted on a segment.
24835 break;
24836 }
24837 }
24838 encseglist->restart();
24839 if (splitflag) {
24840 // Some segments may need to be repaired.
24841 repairencsegs(chkencflag | 1);
24842 // Queue this subface if it is still alive and not queued.
24843 //if ((splitfac->sh != NULL) && (splitfac->sh[3] != NULL)) {
24844 // // Only queue it if 'qflag' is set.
24845 // if (qflag) {
24846 // enqueuesubface(badsubfacs, splitfac);
24847 // }
24848 //}
24849 }
24850 return splitflag;
24851 } else {
24852 return 0;
24853 }
24854 }
24855}
24856
24857///////////////////////////////////////////////////////////////////////////////
24858// //
24859// repairencfacs() Repair encroached subfaces. //
24860// //
24861///////////////////////////////////////////////////////////////////////////////
24862
24863void tetgenmesh::repairencfacs(int chkencflag)
24864{
24865 face *bface;
24866 point encpt = NULL;
24867 int qflag = 0;
24868 REAL ccent[3];
24869
24870 // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
24871 // if an unlimited number of Steiner points is allowed.
24872 while ((badsubfacs->items > 0) && (steinerleft != 0)) {
24873 badsubfacs->traversalinit();
24874 bface = (face *) badsubfacs->traverse();
24875 while ((bface != NULL) && (steinerleft != 0)) {
24876 // Skip a deleted element.
24877 if (bface->shver >= 0) {
24878 // A queued subface may have been deleted (split).
24879 if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24880 // A queued subface may have been processed.
24881 if (smarktest2ed(*bface)) {
24882 sunmarktest2(*bface);
24883 if (checkfac4split(bface, encpt, qflag, ccent)) {
24884 splitsubface(bface, encpt, NULL, qflag, ccent, chkencflag);
24885 }
24886 }
24887 }
24888 bface->shver = -1; // Signal it as a deleted element.
24889 badsubfacs->dealloc((void *) bface); // Remove this entry from list.
24890 }
24891 bface = (face *) badsubfacs->traverse();
24892 }
24893 }
24894
24895 if (badsubfacs->items > 0) {
24896 if (steinerleft == 0) {
24897 if (b->verbose) {
24898 printf("The desired number of Steiner points is reached.\n");
24899 }
24900 } else {
24901 assert(0); // Unknown case.
24902 }
24903 badsubfacs->traversalinit();
24904 bface = (face *) badsubfacs->traverse();
24905 while (bface != NULL) {
24906 // Skip a deleted element.
24907 if (bface->shver >= 0) {
24908 if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24909 if (smarktest2ed(*bface)) {
24910 sunmarktest2(*bface);
24911 }
24912 }
24913 }
24914 bface = (face *) badsubfacs->traverse();
24915 }
24916 badsubfacs->restart();
24917 }
24918}
24919
24920///////////////////////////////////////////////////////////////////////////////
24921// //
24922// enqueuetetrahedron() Queue a tetrahedron for quality check. //
24923// //
24924///////////////////////////////////////////////////////////////////////////////
24925
24926void tetgenmesh::enqueuetetrahedron(triface *chktet)
24927{
24928 if (!marktest2ed(*chktet)) {
24929 marktest2(*chktet); // Only queue it once.
24930 triface *quetet = (triface *) badtetrahedrons->alloc();
24931 *quetet = *chktet;
24932 }
24933}
24934
24935///////////////////////////////////////////////////////////////////////////////
24936// //
24937// checktet4split() Check if the tet needs to be split. //
24938// //
24939///////////////////////////////////////////////////////////////////////////////
24940
24941int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
24942{
24943 point pa, pb, pc, pd, *ppt;
24944 REAL vda[3], vdb[3], vdc[3];
24945 REAL vab[3], vbc[3], vca[3];
24946 REAL N[4][3], L[4], cosd[6], elen[6];
24947 REAL maxcosd, vol, volbnd, smlen = 0, rd;
24948 REAL A[4][4], rhs[4], D;
24949 int indx[4];
24950 int i, j;
24951
24952 if (b->convex) { // -c
24953 // Skip this tet if it lies in the exterior.
24954 if (elemattribute(chktet->tet, numelemattrib - 1) == -1.0) {
24955 return 0;
24956 }
24957 }
24958
24959 qflag = 0;
24960
24961 pd = (point) chktet->tet[7];
24962 if (pd == dummypoint) {
24963 return 0; // Do not split a hull tet.
24964 }
24965
24966 pa = (point) chktet->tet[4];
24967 pb = (point) chktet->tet[5];
24968 pc = (point) chktet->tet[6];
24969
24970 // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
24971 // Set the matrix A = [vda, vdb, vdc]^T.
24972 for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
24973 for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
24974 for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
24975
24976 // Get the other edge vectors.
24977 for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
24978 for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
24979 for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
24980
24981 if (!lu_decmp(A, 3, indx, &D, 0)) {
24982 // A degenerated tet (vol = 0).
24983 // This is possible due to the use of exact arithmetic. We temporarily
24984 // leave this tet. It should be fixed by mesh optimization.
24985 return 0;
24986 }
24987
24988 // Check volume if '-a#' and '-a' options are used.
24989 if (b->varvolume || b->fixedvolume) {
24990 vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
24991 if (b->fixedvolume) {
24992 if (vol > b->maxvolume) {
24993 qflag = 1;
24994 }
24995 }
24996 if (!qflag && b->varvolume) {
24997 volbnd = volumebound(chktet->tet);
24998 if ((volbnd > 0.0) && (vol > volbnd)) {
24999 qflag = 1;
25000 }
25001 }
25002 if (qflag == 1) {
25003 // Calculate the circumcenter of this tet.
25004 rhs[0] = 0.5 * dot(vda, vda);
25005 rhs[1] = 0.5 * dot(vdb, vdb);
25006 rhs[2] = 0.5 * dot(vdc, vdc);
25007 lu_solve(A, 3, indx, rhs, 0);
25008 for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25009 return 1;
25010 }
25011 }
25012
25013 if (b->metric) { // -m option. Check mesh size.
25014 // Calculate the circumradius of this tet.
25015 rhs[0] = 0.5 * dot(vda, vda);
25016 rhs[1] = 0.5 * dot(vdb, vdb);
25017 rhs[2] = 0.5 * dot(vdc, vdc);
25018 lu_solve(A, 3, indx, rhs, 0);
25019 for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25020 rd = sqrt(dot(rhs, rhs));
25021 // Check if the ccent lies outside one of the prot.balls at vertices.
25022 ppt = (point *) &(chktet->tet[4]);
25023 for (i = 0; i < 4; i++) {
25024 if (ppt[i][pointmtrindex] > 0) {
25025 if (rd > ppt[i][pointmtrindex]) {
25026 qflag = 1; // Enforce mesh size.
25027 return 1;
25028 }
25029 }
25030 }
25031 }
25032
25033 if (in->tetunsuitable != NULL) {
25034 // Execute the user-defined meshing sizing evaluation.
25035 if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
25036 // Calculate the circumcenter of this tet.
25037 rhs[0] = 0.5 * dot(vda, vda);
25038 rhs[1] = 0.5 * dot(vdb, vdb);
25039 rhs[2] = 0.5 * dot(vdc, vdc);
25040 lu_solve(A, 3, indx, rhs, 0);
25041 for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25042 return 1;
25043 }
25044 }
25045
25046 if (useinsertradius) {
25047 // Do not split this tet if the shortest edge is shorter than the
25048 // insertion radius of one of its endpoints.
25049 triface checkedge;
25050 point e1, e2;
25051 REAL rrv, smrrv;
25052
25053 // Get the shortest edge of this tet.
25054 checkedge.tet = chktet->tet;
25055 for (i = 0; i < 6; i++) {
25056 checkedge.ver = edge2ver[i];
25057 e1 = org(checkedge);
25058 e2 = dest(checkedge);
25059 elen[i] = distance(e1, e2);
25060 if (i == 0) {
25061 smlen = elen[i];
25062 j = 0;
25063 } else {
25064 if (elen[i] < smlen) {
25065 smlen = elen[i];
25066 j = i;
25067 }
25068 }
25069 }
25070 // Check if the edge is too short.
25071 checkedge.ver = edge2ver[j];
25072 // Get the smallest rrv of e1 and e2.
25073 // Note: if rrv of e1 and e2 is zero. Do not use it.
25074 e1 = org(checkedge);
25075 smrrv = getpointinsradius(e1);
25076 e2 = dest(checkedge);
25077 rrv = getpointinsradius(e2);
25078 if (rrv > 0) {
25079 if (smrrv > 0) {
25080 if (rrv < smrrv) {
25081 smrrv = rrv;
25082 }
25083 } else {
25084 smrrv = rrv;
25085 }
25086 }
25087 if (smrrv > 0) {
25088 // To avoid rounding error, round smrrv before doing comparison.
25089 if ((fabs(smrrv - smlen) / smlen) < b->epsilon) {
25090 smrrv = smlen;
25091 }
25092 if (smrrv > smlen) {
25093 return 0;
25094 }
25095 }
25096 } // if (useinsertradius)
25097
25098 // Check the radius-edge ratio. Set by -q#.
25099 if (b->minratio > 0) {
25100 // Calculate the circumcenter and radius of this tet.
25101 rhs[0] = 0.5 * dot(vda, vda);
25102 rhs[1] = 0.5 * dot(vdb, vdb);
25103 rhs[2] = 0.5 * dot(vdc, vdc);
25104 lu_solve(A, 3, indx, rhs, 0);
25105 for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25106 rd = sqrt(dot(rhs, rhs));
25107 if (!useinsertradius) {
25108 // Calculate the shortest edge length.
25109 elen[0] = dot(vda, vda);
25110 elen[1] = dot(vdb, vdb);
25111 elen[2] = dot(vdc, vdc);
25112 elen[3] = dot(vab, vab);
25113 elen[4] = dot(vbc, vbc);
25114 elen[5] = dot(vca, vca);
25115 smlen = elen[0]; //sidx = 0;
25116 for (i = 1; i < 6; i++) {
25117 if (smlen > elen[i]) {
25118 smlen = elen[i]; //sidx = i;
25119 }
25120 }
25121 smlen = sqrt(smlen);
25122 }
25123 D = rd / smlen;
25124 if (D > b->minratio) {
25125 // A bad radius-edge ratio.
25126 return 1;
25127 }
25128 }
25129
25130 // Check the minimum dihedral angle. Set by -qq#.
25131 if (b->mindihedral > 0) {
25132 // Compute the 4 face normals (N[0], ..., N[3]).
25133 for (j = 0; j < 3; j++) {
25134 for (i = 0; i < 3; i++) N[j][i] = 0.0;
25135 N[j][j] = 1.0; // Positive means the inside direction
25136 lu_solve(A, 3, indx, N[j], 0);
25137 }
25138 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
25139 // Normalize the normals.
25140 for (i = 0; i < 4; i++) {
25141 L[i] = sqrt(dot(N[i], N[i]));
25142 assert(L[i] > 0);
25143 //if (L[i] > 0.0) {
25144 for (j = 0; j < 3; j++) N[i][j] /= L[i];
25145 //}
25146 }
25147 // Calculate the six dihedral angles.
25148 cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
25149 cosd[1] = -dot(N[0], N[2]);
25150 cosd[2] = -dot(N[0], N[3]);
25151 cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
25152 cosd[4] = -dot(N[1], N[3]);
25153 cosd[5] = -dot(N[2], N[3]); // Edge ab
25154 // Get the smallest dihedral angle.
25155 //maxcosd = mincosd = cosd[0];
25156 maxcosd = cosd[0];
25157 for (i = 1; i < 6; i++) {
25158 //if (cosd[i] > maxcosd) maxcosd = cosd[i];
25159 maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
25160 //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
25161 }
25162 if (maxcosd > cosmindihed) {
25163 // Calculate the circumcenter of this tet.
25164 // A bad dihedral angle.
25165 //if ((b->quality & 1) == 0) {
25166 rhs[0] = 0.5 * dot(vda, vda);
25167 rhs[1] = 0.5 * dot(vdb, vdb);
25168 rhs[2] = 0.5 * dot(vdc, vdc);
25169 lu_solve(A, 3, indx, rhs, 0);
25170 for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25171 //*rd = sqrt(dot(rhs, rhs));
25172 //}
25173 return 1;
25174 }
25175 }
25176
25177 return 0;
25178}
25179
25180///////////////////////////////////////////////////////////////////////////////
25181// //
25182// splittetrahedron() Split a tetrahedron. //
25183// //
25184///////////////////////////////////////////////////////////////////////////////
25185
25186int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
25187 int chkencflag)
25188{
25189 triface searchtet;
25190 face *paryseg;
25191 point newpt;
25192 badface *bface;
25193 insertvertexflags ivf;
25194 int splitflag;
25195 int i;
25196
25197
25198
25199 REAL rv = 0.; // Insertion radius of 'newpt'.
25200
25201 makepoint(&newpt, FREEVOLVERTEX);
25202 for (i = 0; i < 3; i++) newpt[i] = ccent[i];
25203
25204 if (useinsertradius) {
25205 rv = distance(newpt, org(*splittet));
25206 setpointinsradius(newpt, rv);
25207 }
25208
25209 searchtet = *splittet;
25210 ivf.iloc = (int) OUTSIDE;
25211 // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
25212 ivf.bowywat = 3;
25213 ivf.lawson = 2;
25214 ivf.rejflag = 3; // Do check for encroached segments and subfaces.
25215 if (b->metric) {
25216 ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
25217 }
25218 ivf.chkencflag = chkencflag;
25219 ivf.sloc = ivf.sbowywat = 0; // No use.
25220 ivf.splitbdflag = 0; // No use.
25221 ivf.validflag = 1;
25222 ivf.respectbdflag = 1;
25223 ivf.assignmeshsize = b->metric;
25224
25225 ivf.refineflag = 1;
25226 ivf.refinetet = *splittet;
25227
25228
25229 if (insertpoint(newpt, &searchtet, NULL, NULL, &ivf)) {
25230 // Vertex is inserted.
25231 st_volref_count++;
25232 if (steinerleft > 0) steinerleft--;
25233 if (flipstack != NULL) {
25234 flipconstraints fc;
25235 fc.chkencflag = chkencflag;
25236 fc.enqflag = 2;
25237 lawsonflip3d(&fc);
25238 unflipqueue->restart();
25239 }
25240 return 1;
25241 } else {
25242 // Point is not inserted.
25243 pointdealloc(newpt);
25244 // Check if there are encroached segments/subfaces.
25245 if (ivf.iloc == (int) ENCSEGMENT) {
25246 splitflag = 0;
25247 //if (!b->nobisect) { // not -Y option
25248 if (!b->nobisect || checkconstraints) {
25249 // Select an encroached segment and split it.
25250 for (i = 0; i < encseglist->objects; i++) {
25251 paryseg = (face *) fastlookup(encseglist, i);
25252 if (splitsegment(paryseg, NULL, rv, org(*splittet), NULL, qflag,
25253 chkencflag | 3)) {
25254 splitflag = 1; // A point is inserted on a segment.
25255 break;
25256 }
25257 }
25258 } // if (!b->nobisect)
25259 encseglist->restart();
25260 if (splitflag) {
25261 // Some segments may need to be repaired.
25262 repairencsegs(chkencflag | 3);
25263 // Some subfaces may need to be repaired.
25264 repairencfacs(chkencflag | 2);
25265 // Queue the tet if it is still alive and not queued.
25266 if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
25267 enqueuetetrahedron(splittet);
25268 }
25269 }
25270 return splitflag;
25271 } else if (ivf.iloc == (int) ENCSUBFACE) {
25272 splitflag = 0;
25273 //if (!b->nobisect) { // not -Y option
25274 if (!b->nobisect || checkconstraints) {
25275 // Select an encroached subface and split it.
25276 for (i = 0; i < encshlist->objects; i++) {
25277 bface = (badface *) fastlookup(encshlist, i);
25278 if (splitsubface(&(bface->ss), NULL, org(*splittet), qflag,
25279 bface->cent, chkencflag | 2)){
25280 splitflag = 1; // A point is inserted on a subface or a segment.
25281 break;
25282 }
25283 }
25284 } // if (!b->nobisect)
25285 encshlist->restart();
25286 if (splitflag) {
25287 assert(badsubsegs->items == 0l);
25288 // Some subfaces may need to be repaired.
25289 repairencfacs(chkencflag | 2);
25290 // Queue the tet if it is still alive.
25291 if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
25292 enqueuetetrahedron(splittet);
25293 }
25294 }
25295 return splitflag;
25296 }
25297 return 0;
25298 }
25299}
25300
25301///////////////////////////////////////////////////////////////////////////////
25302// //
25303// repairbadtets() Repair bad quality tetrahedra. //
25304// //
25305///////////////////////////////////////////////////////////////////////////////
25306
25307void tetgenmesh::repairbadtets(int chkencflag)
25308{
25309 triface *bface;
25310 REAL ccent[3];
25311 int qflag = 0;
25312
25313
25314 // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
25315 // if an unlimited number of Steiner points is allowed.
25316 while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
25317 badtetrahedrons->traversalinit();
25318 bface = (triface *) badtetrahedrons->traverse();
25319 while ((bface != NULL) && (steinerleft != 0)) {
25320 // Skip a deleted element.
25321 if (bface->ver >= 0) {
25322 // A queued tet may have been deleted.
25323 if (!isdeadtet(*bface)) {
25324 // A queued tet may have been processed.
25325 if (marktest2ed(*bface)) {
25326 unmarktest2(*bface);
25327 if (checktet4split(bface, qflag, ccent)) {
25328 splittetrahedron(bface, qflag, ccent, chkencflag);
25329 }
25330 }
25331 }
25332 bface->ver = -1; // Signal it as a deleted element.
25333 badtetrahedrons->dealloc((void *) bface);
25334 }
25335 bface = (triface *) badtetrahedrons->traverse();
25336 }
25337 }
25338
25339 if (badtetrahedrons->items > 0) {
25340 if (steinerleft == 0) {
25341 if (b->verbose) {
25342 printf("The desired number of Steiner points is reached.\n");
25343 }
25344 } else {
25345 assert(0); // Unknown case.
25346 }
25347 // Unmark all queued tet.
25348 badtetrahedrons->traversalinit();
25349 bface = (triface *) badtetrahedrons->traverse();
25350 while (bface != NULL) {
25351 // Skip a deleted element.
25352 if (bface->ver >= 0) {
25353 if (!isdeadtet(*bface)) {
25354 if (marktest2ed(*bface)) {
25355 unmarktest2(*bface);
25356 }
25357 }
25358 }
25359 bface = (triface *) badtetrahedrons->traverse();
25360 }
25361 // Clear the pool.
25362 badtetrahedrons->restart();
25363 }
25364}
25365
25366///////////////////////////////////////////////////////////////////////////////
25367// //
25368// delaunayrefinement() Refine the mesh by Delaunay refinement. //
25369// //
25370///////////////////////////////////////////////////////////////////////////////
25371
25372void tetgenmesh::delaunayrefinement()
25373{
25374 triface checktet;
25375 face checksh;
25376 face checkseg;
25377 long steinercount;
25378 int chkencflag;
25379
25380 long bak_segref_count, bak_facref_count, bak_volref_count;
25381 long bak_flipcount = flip23count + flip32count + flip44count;
25382
25383 if (!b->quiet) {
25384 printf("Refining mesh...\n");
25385 }
25386
25387 if (b->verbose) {
25388 printf(" Min radiu-edge ratio = %g.\n", b->minratio);
25389 printf(" Min dihedral angle = %g.\n", b->mindihedral);
25390 //printf(" Min Edge length = %g.\n", b->minedgelength);
25391 }
25392
25393 steinerleft = b->steinerleft; // Upperbound of # Steiner points (by -S#).
25394 if (steinerleft > 0) {
25395 // Check if we've already used up the given number of Steiner points.
25396 steinercount = st_segref_count + st_facref_count + st_volref_count;
25397 if (steinercount < steinerleft) {
25398 steinerleft -= steinercount;
25399 } else {
25400 if (!b->quiet) {
25401 printf("\nWarning: ");
25402 printf("The desired number of Steiner points (%d) has reached.\n\n",
25403 b->steinerleft);
25404 }
25405 return; // No more Steiner points.
25406 }
25407 }
25408
25409 if (useinsertradius) {
25410 if ((b->plc && b->nobisect) || b->refine) { // '-pY' or '-r' option.
25411 makesegmentendpointsmap();
25412 }
25413 makefacetverticesmap();
25414 }
25415
25416
25417 encseglist = new arraypool(sizeof(face), 8);
25418 encshlist = new arraypool(sizeof(badface), 8);
25419
25420
25421 //if (!b->nobisect) { // if no '-Y' option
25422 if (!b->nobisect || checkconstraints) {
25423 if (b->verbose) {
25424 printf(" Splitting encroached subsegments.\n");
25425 }
25426
25427 chkencflag = 1; // Only check encroaching subsegments.
25428 steinercount = points->items;
25429
25430 // Initialize the pool of encroached subsegments.
25431 badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock,
25432 sizeof(void *), 0);
25433
25434 // Add all segments into the pool.
25435 subsegs->traversalinit();
25436 checkseg.sh = shellfacetraverse(subsegs);
25437 while (checkseg.sh != (shellface *) NULL) {
25438 enqueuesubface(badsubsegs, &checkseg);
25439 checkseg.sh = shellfacetraverse(subsegs);
25440 }
25441
25442 // Split all encroached segments.
25443 repairencsegs(chkencflag);
25444
25445 if (b->verbose) {
25446 printf(" Added %ld Steiner points.\n", points->items - steinercount);
25447 }
25448
25449 if (b->reflevel > 1) { // '-D2' option
25450 if (b->verbose) {
25451 printf(" Splitting encroached subfaces.\n");
25452 }
25453
25454 chkencflag = 2; // Only check encroaching subfaces.
25455 steinercount = points->items;
25456 bak_segref_count = st_segref_count;
25457 bak_facref_count = st_facref_count;
25458
25459 // Initialize the pool of encroached subfaces.
25460 badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock,
25461 sizeof(void *), 0);
25462
25463 // Add all subfaces into the pool.
25464 subfaces->traversalinit();
25465 checksh.sh = shellfacetraverse(subfaces);
25466 while (checksh.sh != (shellface *) NULL) {
25467 enqueuesubface(badsubfacs, &checksh);
25468 checksh.sh = shellfacetraverse(subfaces);
25469 }
25470
25471 // Split all encroached subfaces.
25472 repairencfacs(chkencflag);
25473
25474 if (b->verbose) {
25475 printf(" Added %ld (%ld,%ld) Steiner points.\n",
25476 points->items-steinercount, st_segref_count-bak_segref_count,
25477 st_facref_count-bak_facref_count);
25478 }
25479 } // if (b->reflevel > 1)
25480 } // if (!b->nobisect)
25481
25482 if (b->reflevel > 2) { // '-D3' option (The default option)
25483 if (b->verbose) {
25484 printf(" Splitting bad quality tets.\n");
25485 }
25486
25487 chkencflag = 4; // Only check tetrahedra.
25488 steinercount = points->items;
25489 bak_segref_count = st_segref_count;
25490 bak_facref_count = st_facref_count;
25491 bak_volref_count = st_volref_count;
25492
25493 // The cosine value of the min dihedral angle (-qq) for tetrahedra.
25494 cosmindihed = cos(b->mindihedral / 180.0 * PI);
25495
25496 // Initialize the pool of bad quality tetrahedra.
25497 badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
25498 sizeof(void *), 0);
25499 // Add all tetrahedra (no hull tets) into the pool.
25500 tetrahedrons->traversalinit();
25501 checktet.tet = tetrahedrontraverse();
25502 while (checktet.tet != NULL) {
25503 enqueuetetrahedron(&checktet);
25504 checktet.tet = tetrahedrontraverse();
25505 }
25506
25507 // Split all bad quality tetrahedra.
25508 repairbadtets(chkencflag);
25509
25510 if (b->verbose) {
25511 printf(" Added %ld (%ld,%ld,%ld) Steiner points.\n",
25512 points->items - steinercount,
25513 st_segref_count - bak_segref_count,
25514 st_facref_count - bak_facref_count,
25515 st_volref_count - bak_volref_count);
25516 }
25517 } // if (b->reflevel > 2)
25518
25519 if (b->verbose) {
25520 if (flip23count + flip32count + flip44count > bak_flipcount) {
25521 printf(" Performed %ld flips.\n", flip23count + flip32count +
25522 flip44count - bak_flipcount);
25523 }
25524 }
25525
25526 if (steinerleft == 0) {
25527 if (!b->quiet) {
25528 printf("\nWarnning: ");
25529 printf("The desired number of Steiner points (%d) is reached.\n\n",
25530 b->steinerleft);
25531 }
25532 }
25533
25534
25535 delete encseglist;
25536 delete encshlist;
25537
25538 //if (!b->nobisect) {
25539 if (!b->nobisect || checkconstraints) {
25540 totalworkmemory += (badsubsegs->maxitems * badsubsegs->itembytes);
25541 delete badsubsegs;
25542 if (b->reflevel > 1) {
25543 totalworkmemory += (badsubfacs->maxitems * badsubfacs->itembytes);
25544 delete badsubfacs;
25545 }
25546 }
25547 if (b->reflevel > 2) {
25548 totalworkmemory += (badtetrahedrons->maxitems*badtetrahedrons->itembytes);
25549 delete badtetrahedrons;
25550 }
25551}
25552
25553//// ////
25554//// ////
25555//// refine_cxx ///////////////////////////////////////////////////////////////
25556
25557//// optimize_cxx /////////////////////////////////////////////////////////////
25558//// ////
25559//// ////
25560
25561///////////////////////////////////////////////////////////////////////////////
25562// //
25563// lawsonflip3d() A three-dimensional Lawson's algorithm. //
25564// //
25565///////////////////////////////////////////////////////////////////////////////
25566
25567long tetgenmesh::lawsonflip3d(flipconstraints *fc)
25568{
25569 triface fliptets[5], neightet, hulltet;
25570 face checksh, casingout;
25571 badface *popface, *bface;
25572 point pd, pe, *pts;
25573 REAL sign, ori;
25574 long flipcount, totalcount = 0l;
25575 long sliver_peels = 0l;
25576 int t1ver;
25577 int i;
25578
25579
25580 while (1) {
25581
25582 if (b->verbose > 2) {
25583 printf(" Lawson flip %ld faces.\n", flippool->items);
25584 }
25585 flipcount = 0l;
25586
25587 while (flipstack != (badface *) NULL) {
25588 // Pop a face from the stack.
25589 popface = flipstack;
25590 fliptets[0] = popface->tt;
25591 flipstack = flipstack->nextitem; // The next top item in stack.
25592 flippool->dealloc((void *) popface);
25593
25594 // Skip it if it is a dead tet (destroyed by previous flips).
25595 if (isdeadtet(fliptets[0])) continue;
25596 // Skip it if it is not the same tet as we saved.
25597 if (!facemarked(fliptets[0])) continue;
25598
25599 unmarkface(fliptets[0]);
25600
25601 if (ishulltet(fliptets[0])) continue;
25602
25603 fsym(fliptets[0], fliptets[1]);
25604 if (ishulltet(fliptets[1])) {
25605 if (nonconvex) {
25606 // Check if 'fliptets[0]' it is a hull sliver.
25607 tspivot(fliptets[0], checksh);
25608 for (i = 0; i < 3; i++) {
25609 if (!isshsubseg(checksh)) {
25610 spivot(checksh, casingout);
25611 //assert(casingout.sh != NULL);
25612 if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
25613 stpivot(casingout, neightet);
25614 if (neightet.tet == fliptets[0].tet) {
25615 // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where
25616 // [e,d,a] and [d,e,b] are hull faces.
25617 edestoppo(neightet, hulltet); // [a,b,e,d]
25618 fsymself(hulltet); // [b,a,e,#]
25619 if (oppo(hulltet) == dummypoint) {
25620 pe = org(neightet);
25621 if ((pointtype(pe) == FREEFACETVERTEX) ||
25622 (pointtype(pe) == FREESEGVERTEX)) {
25623 removevertexbyflips(pe);
25624 }
25625 } else {
25626 eorgoppo(neightet, hulltet); // [b,a,d,e]
25627 fsymself(hulltet); // [a,b,d,#]
25628 if (oppo(hulltet) == dummypoint) {
25629 pd = dest(neightet);
25630 if ((pointtype(pd) == FREEFACETVERTEX) ||
25631 (pointtype(pd) == FREESEGVERTEX)) {
25632 removevertexbyflips(pd);
25633 }
25634 } else {
25635 // Perform a 3-to-2 flip to remove the sliver.
25636 fliptets[0] = neightet; // [e,d,a,b]
25637 fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
25638 fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
25639 flip32(fliptets, 1, fc);
25640 // Update counters.
25641 flip32count--;
25642 flip22count--;
25643 sliver_peels++;
25644 if (fc->remove_ndelaunay_edge) {
25645 // Update the volume (must be decreased).
25646 //assert(fc->tetprism_vol_sum <= 0);
25647 tetprism_vol_sum += fc->tetprism_vol_sum;
25648 fc->tetprism_vol_sum = 0.0; // Clear it.
25649 }
25650 }
25651 }
25652 break;
25653 } // if (neightet.tet == fliptets[0].tet)
25654 } // if (!isshsubseg(checksh))
25655 senextself(checksh);
25656 } // i
25657 } // if (nonconvex)
25658 continue;
25659 }
25660
25661 if (checksubfaceflag) {
25662 // Do not flip if it is a subface.
25663 if (issubface(fliptets[0])) continue;
25664 }
25665
25666 // Test whether the face is locally Delaunay or not.
25667 pts = (point *) fliptets[1].tet;
25668 sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
25669
25670 if (sign < 0) {
25671 // A non-Delaunay face. Try to flip it.
25672 pd = oppo(fliptets[0]);
25673 pe = oppo(fliptets[1]);
25674
25675 // Check the convexity of its three edges. Stop checking either a
25676 // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
25677 // encountered, and 'fliptet' represents that edge.
25678 for (i = 0; i < 3; i++) {
25679 ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
25680 if (ori <= 0) break;
25681 enextself(fliptets[0]);
25682 }
25683
25684 if (ori > 0) {
25685 // A 2-to-3 flip is found.
25686 // [0] [a,b,c,d],
25687 // [1] [b,a,c,e]. no dummypoint.
25688 flip23(fliptets, 0, fc);
25689 flipcount++;
25690 if (fc->remove_ndelaunay_edge) {
25691 // Update the volume (must be decreased).
25692 //assert(fc->tetprism_vol_sum <= 0);
25693 tetprism_vol_sum += fc->tetprism_vol_sum;
25694 fc->tetprism_vol_sum = 0.0; // Clear it.
25695 }
25696 continue;
25697 } else { // ori <= 0
25698 // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
25699 // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
25700 if (checksubsegflag) {
25701 // Do not flip if it is a segment.
25702 if (issubseg(fliptets[0])) continue;
25703 }
25704 // Check if there are three or four tets sharing at this edge.
25705 esymself(fliptets[0]); // [b,a,d,c]
25706 for (i = 0; i < 3; i++) {
25707 fnext(fliptets[i], fliptets[i+1]);
25708 }
25709 if (fliptets[3].tet == fliptets[0].tet) {
25710 // A 3-to-2 flip is found. (No hull tet.)
25711 flip32(fliptets, 0, fc);
25712 flipcount++;
25713 if (fc->remove_ndelaunay_edge) {
25714 // Update the volume (must be decreased).
25715 //assert(fc->tetprism_vol_sum <= 0);
25716 tetprism_vol_sum += fc->tetprism_vol_sum;
25717 fc->tetprism_vol_sum = 0.0; // Clear it.
25718 }
25719 continue;
25720 } else {
25721 // There are more than 3 tets at this edge.
25722 fnext(fliptets[3], fliptets[4]);
25723 if (fliptets[4].tet == fliptets[0].tet) {
25724 // There are exactly 4 tets at this edge.
25725 if (nonconvex) {
25726 if (apex(fliptets[3]) == dummypoint) {
25727 // This edge is locally non-convex on the hull.
25728 // It can be removed by a 4-to-4 flip.
25729 ori = 0;
25730 }
25731 } // if (nonconvex)
25732 if (ori == 0) {
25733 // A 4-to-4 flip is found. (Two hull tets may be involved.)
25734 // Current tets in 'fliptets':
25735 // [0] [b,a,d,c] (d may be newpt)
25736 // [1] [b,a,c,e]
25737 // [2] [b,a,e,f] (f may be dummypoint)
25738 // [3] [b,a,f,d]
25739 esymself(fliptets[0]); // [a,b,c,d]
25740 // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
25741 // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
25742 // It will be removed by the followed 3-to-2 flip.
25743 flip23(fliptets, 0, fc); // No hull tet.
25744 fnext(fliptets[3], fliptets[1]);
25745 fnext(fliptets[1], fliptets[2]);
25746 // Current tets in 'fliptets':
25747 // [0] [...]
25748 // [1] [b,a,d,e] (degenerated, d may be new point).
25749 // [2] [b,a,e,f] (f may be dummypoint)
25750 // [3] [b,a,f,d]
25751 // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
25752 // Hull tets may be involved (f may be dummypoint).
25753 flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
25754 flipcount++;
25755 flip23count--;
25756 flip32count--;
25757 flip44count++;
25758 if (fc->remove_ndelaunay_edge) {
25759 // Update the volume (must be decreased).
25760 //assert(fc->tetprism_vol_sum <= 0);
25761 tetprism_vol_sum += fc->tetprism_vol_sum;
25762 fc->tetprism_vol_sum = 0.0; // Clear it.
25763 }
25764 continue;
25765 } // if (ori == 0)
25766 }
25767 }
25768 } // if (ori <= 0)
25769
25770 // This non-Delaunay face is unflippable. Save it.
25771 unflipqueue->newindex((void **) &bface);
25772 bface->tt = fliptets[0];
25773 bface->forg = org(fliptets[0]);
25774 bface->fdest = dest(fliptets[0]);
25775 bface->fapex = apex(fliptets[0]);
25776 } // if (sign < 0)
25777 } // while (flipstack)
25778
25779 if (b->verbose > 2) {
25780 if (flipcount > 0) {
25781 printf(" Performed %ld flips.\n", flipcount);
25782 }
25783 }
25784 // Accumulate the counter of flips.
25785 totalcount += flipcount;
25786
25787 assert(flippool->items == 0l);
25788 // Return if no unflippable faces left.
25789 if (unflipqueue->objects == 0l) break;
25790 // Return if no flip has been performed.
25791 if (flipcount == 0l) break;
25792
25793 // Try to flip the unflippable faces.
25794 for (i = 0; i < unflipqueue->objects; i++) {
25795 bface = (badface *) fastlookup(unflipqueue, i);
25796 if (!isdeadtet(bface->tt) &&
25797 (org(bface->tt) == bface->forg) &&
25798 (dest(bface->tt) == bface->fdest) &&
25799 (apex(bface->tt) == bface->fapex)) {
25800 flippush(flipstack, &(bface->tt));
25801 }
25802 }
25803 unflipqueue->restart();
25804
25805 } // while (1)
25806
25807 if (b->verbose > 2) {
25808 if (totalcount > 0) {
25809 printf(" Performed %ld flips.\n", totalcount);
25810 }
25811 if (sliver_peels > 0) {
25812 printf(" Removed %ld hull slivers.\n", sliver_peels);
25813 }
25814 if (unflipqueue->objects > 0l) {
25815 printf(" %ld unflippable edges remained.\n", unflipqueue->objects);
25816 }
25817 }
25818
25819 return totalcount + sliver_peels;
25820}
25821
25822///////////////////////////////////////////////////////////////////////////////
25823// //
25824// recoverdelaunay() Recovery the locally Delaunay property. //
25825// //
25826///////////////////////////////////////////////////////////////////////////////
25827
25828void tetgenmesh::recoverdelaunay()
25829{
25830 arraypool *flipqueue, *nextflipqueue, *swapqueue;
25831 triface tetloop, neightet, *parytet;
25832 badface *bface, *parybface;
25833 point *ppt;
25834 flipconstraints fc;
25835 int i, j;
25836
25837 if (!b->quiet) {
25838 printf("Recovering Delaunayness...\n");
25839 }
25840
25841 tetprism_vol_sum = 0.0; // Initialize it.
25842
25843 // Put all interior faces of the mesh into 'flipstack'.
25844 tetrahedrons->traversalinit();
25845 tetloop.tet = tetrahedrontraverse();
25846 while (tetloop.tet != NULL) {
25847 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
25848 decode(tetloop.tet[tetloop.ver], neightet);
25849 if (!facemarked(neightet)) {
25850 flippush(flipstack, &tetloop);
25851 }
25852 }
25853 ppt = (point *) &(tetloop.tet[4]);
25854 tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
25855 tetloop.tet = tetrahedrontraverse();
25856 }
25857
25858 // Calulate a relatively lower bound for small improvement.
25859 // Used to avoid rounding error in volume calculation.
25860 fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
25861
25862 if (b->verbose) {
25863 printf(" Initial obj = %.17g\n", tetprism_vol_sum);
25864 }
25865
25866 if (b->verbose > 1) {
25867 printf(" Recover Delaunay [Lawson] : %ld\n", flippool->items);
25868 }
25869
25870 // First only use the basic Lawson's flip.
25871 fc.remove_ndelaunay_edge = 1;
25872 fc.enqflag = 2;
25873
25874 lawsonflip3d(&fc);
25875
25876 if (b->verbose > 1) {
25877 printf(" obj (after Lawson) = %.17g\n", tetprism_vol_sum);
25878 }
25879
25880 if (unflipqueue->objects == 0l) {
25881 return; // The mesh is Delaunay.
25882 }
25883
25884 fc.unflip = 1; // Unflip if the edge is not flipped.
25885 fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
25886 fc.enqflag = 0;
25887
25888 autofliplinklevel = 1; // Init level.
25889 b->fliplinklevel = -1; // No fixed level.
25890
25891 // For efficiency reason, we limit the maximium size of the edge star.
25892 int bakmaxflipstarsize = b->flipstarsize;
25893 b->flipstarsize = 10; // default
25894
25895 flipqueue = new arraypool(sizeof(badface), 10);
25896 nextflipqueue = new arraypool(sizeof(badface), 10);
25897
25898 // Swap the two flip queues.
25899 swapqueue = flipqueue;
25900 flipqueue = unflipqueue;
25901 unflipqueue = swapqueue;
25902
25903 while (flipqueue->objects > 0l) {
25904
25905 if (b->verbose > 1) {
25906 printf(" Recover Delaunay [level = %2d] #: %ld.\n",
25907 autofliplinklevel, flipqueue->objects);
25908 }
25909
25910 for (i = 0; i < flipqueue->objects; i++) {
25911 bface = (badface *) fastlookup(flipqueue, i);
25912 if (getedge(bface->forg, bface->fdest, &bface->tt)) {
25913 if (removeedgebyflips(&(bface->tt), &fc) == 2) {
25914 tetprism_vol_sum += fc.tetprism_vol_sum;
25915 fc.tetprism_vol_sum = 0.0; // Clear it.
25916 // Queue new faces for flips.
25917 for (j = 0; j < cavetetlist->objects; j++) {
25918 parytet = (triface *) fastlookup(cavetetlist, j);
25919 // A queued new tet may be dead.
25920 if (!isdeadtet(*parytet)) {
25921 for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
25922 // Avoid queue a face twice.
25923 decode(parytet->tet[parytet->ver], neightet);
25924 if (!facemarked(neightet)) {
25925 flippush(flipstack, parytet);
25926 }
25927 } // parytet->ver
25928 }
25929 } // j
25930 cavetetlist->restart();
25931 // Remove locally non-Delaunay faces. New non-Delaunay edges
25932 // may be found. They are saved in 'unflipqueue'.
25933 fc.enqflag = 2;
25934 lawsonflip3d(&fc);
25935 fc.enqflag = 0;
25936 // There may be unflipable faces. Add them in flipqueue.
25937 for (j = 0; j < unflipqueue->objects; j++) {
25938 bface = (badface *) fastlookup(unflipqueue, j);
25939 flipqueue->newindex((void **) &parybface);
25940 *parybface = *bface;
25941 }
25942 unflipqueue->restart();
25943 } else {
25944 // Unable to remove this edge. Save it.
25945 nextflipqueue->newindex((void **) &parybface);
25946 *parybface = *bface;
25947 // Normally, it should be zero.
25948 //assert(fc.tetprism_vol_sum == 0.0);
25949 // However, due to rounding errors, a tiny value may appear.
25950 fc.tetprism_vol_sum = 0.0;
25951 }
25952 }
25953 } // i
25954
25955 if (b->verbose > 1) {
25956 printf(" obj (after level %d) = %.17g.\n", autofliplinklevel,
25957 tetprism_vol_sum);
25958 }
25959 flipqueue->restart();
25960
25961 // Swap the two flip queues.
25962 swapqueue = flipqueue;
25963 flipqueue = nextflipqueue;
25964 nextflipqueue = swapqueue;
25965
25966 if (flipqueue->objects > 0l) {
25967 // default 'b->delmaxfliplevel' is 1.
25968 if (autofliplinklevel >= b->delmaxfliplevel) {
25969 // For efficiency reason, we do not search too far.
25970 break;
25971 }
25972 autofliplinklevel+=b->fliplinklevelinc;
25973 }
25974 } // while (flipqueue->objects > 0l)
25975
25976 if (flipqueue->objects > 0l) {
25977 if (b->verbose > 1) {
25978 printf(" %ld non-Delaunay edges remained.\n", flipqueue->objects);
25979 }
25980 }
25981
25982 if (b->verbose) {
25983 printf(" Final obj = %.17g\n", tetprism_vol_sum);
25984 }
25985
25986 b->flipstarsize = bakmaxflipstarsize;
25987 delete flipqueue;
25988 delete nextflipqueue;
25989}
25990
25991///////////////////////////////////////////////////////////////////////////////
25992// //
25993// gettetrahedron() Get a tetrahedron which have the given vertices. //
25994// //
25995///////////////////////////////////////////////////////////////////////////////
25996
25997int tetgenmesh::gettetrahedron(point pa, point pb, point pc, point pd,
25998 triface *searchtet)
25999{
26000 triface spintet;
26001 int t1ver;
26002
26003 if (getedge(pa, pb, searchtet)) {
26004 spintet = *searchtet;
26005 while (1) {
26006 if (apex(spintet) == pc) {
26007 *searchtet = spintet;
26008 break;
26009 }
26010 fnextself(spintet);
26011 if (spintet.tet == searchtet->tet) break;
26012 }
26013 if (apex(*searchtet) == pc) {
26014 if (oppo(*searchtet) == pd) {
26015 return 1;
26016 } else {
26017 fsymself(*searchtet);
26018 if (oppo(*searchtet) == pd) {
26019 return 1;
26020 }
26021 }
26022 }
26023 }
26024
26025 return 0;
26026}
26027
26028///////////////////////////////////////////////////////////////////////////////
26029// //
26030// improvequalitybyflips() Improve the mesh quality by flips. //
26031// //
26032///////////////////////////////////////////////////////////////////////////////
26033
26034long tetgenmesh::improvequalitybyflips()
26035{
26036 arraypool *flipqueue, *nextflipqueue, *swapqueue;
26037 badface *bface, *parybface;
26038 triface *parytet;
26039 point *ppt;
26040 flipconstraints fc;
26041 REAL *cosdd, ncosdd[6], maxdd;
26042 long totalremcount, remcount;
26043 int remflag;
26044 int n, i, j, k;
26045
26046 //assert(unflipqueue->objects > 0l);
26047 flipqueue = new arraypool(sizeof(badface), 10);
26048 nextflipqueue = new arraypool(sizeof(badface), 10);
26049
26050 // Backup flip edge options.
26051 int bakautofliplinklevel = autofliplinklevel;
26052 int bakfliplinklevel = b->fliplinklevel;
26053 int bakmaxflipstarsize = b->flipstarsize;
26054
26055 // Set flip edge options.
26056 autofliplinklevel = 1;
26057 b->fliplinklevel = -1;
26058 b->flipstarsize = 10; // b->optmaxflipstarsize;
26059
26060 fc.remove_large_angle = 1;
26061 fc.unflip = 1;
26062 fc.collectnewtets = 1;
26063 fc.checkflipeligibility = 1;
26064
26065 totalremcount = 0l;
26066
26067 // Swap the two flip queues.
26068 swapqueue = flipqueue;
26069 flipqueue = unflipqueue;
26070 unflipqueue = swapqueue;
26071
26072 while (flipqueue->objects > 0l) {
26073
26074 remcount = 0l;
26075
26076 while (flipqueue->objects > 0l) {
26077 if (b->verbose > 1) {
26078 printf(" Improving mesh qualiy by flips [%d]#: %ld.\n",
26079 autofliplinklevel, flipqueue->objects);
26080 }
26081
26082 for (k = 0; k < flipqueue->objects; k++) {
26083 bface = (badface *) fastlookup(flipqueue, k);
26084 if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26085 bface->foppo, &bface->tt)) {
26086 //assert(!ishulltet(bface->tt));
26087 // There are bad dihedral angles in this tet.
26088 if (bface->tt.ver != 11) {
26089 // The dihedral angles are permuted.
26090 // Here we simply re-compute them. Slow!!.
26091 ppt = (point *) & (bface->tt.tet[4]);
26092 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26093 &bface->key, NULL);
26094 bface->forg = ppt[0];
26095 bface->fdest = ppt[1];
26096 bface->fapex = ppt[2];
26097 bface->foppo = ppt[3];
26098 bface->tt.ver = 11;
26099 }
26100 if (bface->key == 0) {
26101 // Re-comput the quality values. Due to smoothing operations.
26102 ppt = (point *) & (bface->tt.tet[4]);
26103 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26104 &bface->key, NULL);
26105 }
26106 cosdd = bface->cent;
26107 remflag = 0;
26108 for (i = 0; (i < 6) && !remflag; i++) {
26109 if (cosdd[i] < cosmaxdihed) {
26110 // Found a large dihedral angle.
26111 bface->tt.ver = edge2ver[i]; // Go to the edge.
26112 fc.cosdihed_in = cosdd[i];
26113 fc.cosdihed_out = 0.0; // 90 degree.
26114 n = removeedgebyflips(&(bface->tt), &fc);
26115 if (n == 2) {
26116 // Edge is flipped.
26117 remflag = 1;
26118 if (fc.cosdihed_out < cosmaxdihed) {
26119 // Queue new bad tets for further improvements.
26120 for (j = 0; j < cavetetlist->objects; j++) {
26121 parytet = (triface *) fastlookup(cavetetlist, j);
26122 if (!isdeadtet(*parytet)) {
26123 ppt = (point *) & (parytet->tet[4]);
26124 // Do not test a hull tet.
26125 if (ppt[3] != dummypoint) {
26126 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd,
26127 &maxdd, NULL);
26128 if (maxdd < cosmaxdihed) {
26129 // There are bad dihedral angles in this tet.
26130 nextflipqueue->newindex((void **) &parybface);
26131 parybface->tt.tet = parytet->tet;
26132 parybface->tt.ver = 11;
26133 parybface->forg = ppt[0];
26134 parybface->fdest = ppt[1];
26135 parybface->fapex = ppt[2];
26136 parybface->foppo = ppt[3];
26137 parybface->key = maxdd;
26138 for (n = 0; n < 6; n++) {
26139 parybface->cent[n] = ncosdd[n];
26140 }
26141 }
26142 } // if (ppt[3] != dummypoint)
26143 }
26144 } // j
26145 } // if (fc.cosdihed_out < cosmaxdihed)
26146 cavetetlist->restart();
26147 remcount++;
26148 }
26149 }
26150 } // i
26151 if (!remflag) {
26152 // An unremoved bad tet. Queue it again.
26153 unflipqueue->newindex((void **) &parybface);
26154 *parybface = *bface;
26155 }
26156 } // if (gettetrahedron(...))
26157 } // k
26158
26159 flipqueue->restart();
26160
26161 // Swap the two flip queues.
26162 swapqueue = flipqueue;
26163 flipqueue = nextflipqueue;
26164 nextflipqueue = swapqueue;
26165 } // while (flipqueues->objects > 0)
26166
26167 if (b->verbose > 1) {
26168 printf(" Removed %ld bad tets.\n", remcount);
26169 }
26170 totalremcount += remcount;
26171
26172 if (unflipqueue->objects > 0l) {
26173 //if (autofliplinklevel >= b->optmaxfliplevel) {
26174 if (autofliplinklevel >= b->optlevel) {
26175 break;
26176 }
26177 autofliplinklevel+=b->fliplinklevelinc;
26178 //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
26179 }
26180
26181 // Swap the two flip queues.
26182 swapqueue = flipqueue;
26183 flipqueue = unflipqueue;
26184 unflipqueue = swapqueue;
26185 } // while (flipqueues->objects > 0)
26186
26187 // Restore original flip edge options.
26188 autofliplinklevel = bakautofliplinklevel;
26189 b->fliplinklevel = bakfliplinklevel;
26190 b->flipstarsize = bakmaxflipstarsize;
26191
26192 delete flipqueue;
26193 delete nextflipqueue;
26194
26195 return totalremcount;
26196}
26197
26198///////////////////////////////////////////////////////////////////////////////
26199// //
26200// smoothpoint() Moving a vertex to improve the mesh quality. //
26201// //
26202// 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point. //
26203// It may be not a vertex of the mesh. //
26204// //
26205// This routine tries to move 'p' inside its star until a selected objective //
26206// function over all tetrahedra in the star is improved. The function may be //
26207// the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
26208// simply the volume of the tetrahedra. //
26209// //
26210// 'linkfacelist' contains the list of link faces of 'p'. Since a link face //
26211// has two orientations, ccw or cw, with respect to 'p'. 'ccw' indicates //
26212// the orientation is ccw (1) or not (0). //
26213// //
26214// 'opm' is a structure contains the parameters of the objective function. //
26215// It is needed by the evaluation of the function value. //
26216// //
26217// The return value indicates weather the point is smoothed or not. //
26218// //
26219// ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
26220// no face has 'dummypoint' as its vertex. //
26221// //
26222///////////////////////////////////////////////////////////////////////////////
26223
26224int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
26225 optparameters *opm)
26226{
26227 triface *parytet, *parytet1, swaptet;
26228 point pa, pb, pc;
26229 REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
26230 REAL oldval, minval = 0.0, val;
26231 REAL maxcosd; // oldang, newang;
26232 REAL ori, diff;
26233 int numdirs, iter;
26234 int i, j, k;
26235
26236 // Decide the number of moving directions.
26237 numdirs = (int) linkfacelist->objects;
26238 if (numdirs > opm->numofsearchdirs) {
26239 numdirs = opm->numofsearchdirs; // Maximum search directions.
26240 }
26241
26242 // Set the initial value.
26243 if (!opm->max_min_volume) {
26244 assert(opm->initval >= 0.0);
26245 }
26246 opm->imprval = opm->initval;
26247 iter = 0;
26248
26249 for (i = 0; i < 3; i++) {
26250 bestpt[i] = startpt[i] = smtpt[i];
26251 }
26252
26253 // Iterate until the obj function is not improved.
26254 while (1) {
26255
26256 // Find the best next location.
26257 oldval = opm->imprval;
26258
26259 for (i = 0; i < numdirs; i++) {
26260 // Randomly pick a link face (0 <= k <= objects - i - 1).
26261 k = (int) randomnation(linkfacelist->objects - i);
26262 parytet = (triface *) fastlookup(linkfacelist, k);
26263 // Calculate a new position from 'p' to the center of this face.
26264 pa = org(*parytet);
26265 pb = dest(*parytet);
26266 pc = apex(*parytet);
26267 for (j = 0; j < 3; j++) {
26268 fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
26269 }
26270 for (j = 0; j < 3; j++) {
26271 nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]);
26272 }
26273 // Calculate the largest minimum function value for the new location.
26274 for (j = 0; j < linkfacelist->objects; j++) {
26275 parytet = (triface *) fastlookup(linkfacelist, j);
26276 if (ccw) {
26277 pa = org(*parytet);
26278 pb = dest(*parytet);
26279 } else {
26280 pb = org(*parytet);
26281 pa = dest(*parytet);
26282 }
26283 pc = apex(*parytet);
26284 ori = orient3d(pa, pb, pc, nextpt);
26285 if (ori < 0.0) {
26286 // Calcuate the objective function value.
26287 if (opm->max_min_volume) {
26288 //val = -ori;
26289 val = - orient3dfast(pa, pb, pc, nextpt);
26290 } else if (opm->max_min_aspectratio) {
26291 val = tetaspectratio(pa, pb, pc, nextpt);
26292 } else if (opm->min_max_dihedangle) {
26293 tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
26294 if (maxcosd < -1) maxcosd = -1.0; // Rounding.
26295 val = maxcosd + 1.0; // Make it be positive.
26296 } else {
26297 // Unknown objective function.
26298 val = 0.0;
26299 }
26300 } else { // ori >= 0.0;
26301 // An invalid new tet.
26302 // This may happen if the mesh contains inverted elements.
26303 if (opm->max_min_volume) {
26304 //val = -ori;
26305 val = - orient3dfast(pa, pb, pc, nextpt);
26306 } else {
26307 // Discard this point.
26308 break; // j
26309 }
26310 } // if (ori >= 0.0)
26311 // Stop looping when the object value is not improved.
26312 if (val <= opm->imprval) {
26313 break; // j
26314 } else {
26315 // Remember the smallest improved value.
26316 if (j == 0) {
26317 minval = val;
26318 } else {
26319 minval = (val < minval) ? val : minval;
26320 }
26321 }
26322 } // j
26323 if (j == linkfacelist->objects) {
26324 // The function value has been improved.
26325 opm->imprval = minval;
26326 // Save the new location of the point.
26327 for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
26328 }
26329 // Swap k-th and (object-i-1)-th entries.
26330 j = linkfacelist->objects - i - 1;
26331 parytet = (triface *) fastlookup(linkfacelist, k);
26332 parytet1 = (triface *) fastlookup(linkfacelist, j);
26333 swaptet = *parytet1;
26334 *parytet1 = *parytet;
26335 *parytet = swaptet;
26336 } // i
26337
26338 diff = opm->imprval - oldval;
26339 if (diff > 0.0) {
26340 // Is the function value improved effectively?
26341 if (opm->max_min_volume) {
26342 //if ((diff / oldval) < b->epsilon) diff = 0.0;
26343 } else if (opm->max_min_aspectratio) {
26344 if ((diff / oldval) < 1e-3) diff = 0.0;
26345 } else if (opm->min_max_dihedangle) {
26346 //oldang = acos(oldval - 1.0);
26347 //newang = acos(opm->imprval - 1.0);
26348 //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
26349 } else {
26350 // Unknown objective function.
26351 assert(0); // Not possible.
26352 }
26353 }
26354
26355 if (diff > 0.0) {
26356 // Yes, move p to the new location and continue.
26357 for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
26358 iter++;
26359 if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
26360 // Maximum smoothing iterations reached.
26361 break;
26362 }
26363 } else {
26364 break;
26365 }
26366
26367 } // while (1)
26368
26369 if (iter > 0) {
26370 // The point has been smoothed.
26371 opm->smthiter = iter; // Remember the number of iterations.
26372 // The point has been smoothed. Update it to its new position.
26373 for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
26374 }
26375
26376 return iter;
26377}
26378
26379
26380///////////////////////////////////////////////////////////////////////////////
26381// //
26382// improvequalitysmoothing() Improve mesh quality by smoothing. //
26383// //
26384///////////////////////////////////////////////////////////////////////////////
26385
26386long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
26387{
26388 arraypool *flipqueue, *swapqueue;
26389 triface *parytet;
26390 badface *bface, *parybface;
26391 point *ppt;
26392 long totalsmtcount, smtcount;
26393 int smtflag;
26394 int iter, i, j, k;
26395
26396 //assert(unflipqueue->objects > 0l);
26397 flipqueue = new arraypool(sizeof(badface), 10);
26398
26399 // Swap the two flip queues.
26400 swapqueue = flipqueue;
26401 flipqueue = unflipqueue;
26402 unflipqueue = swapqueue;
26403
26404 totalsmtcount = 0l;
26405 iter = 0;
26406
26407 while (flipqueue->objects > 0l) {
26408
26409 smtcount = 0l;
26410
26411 if (b->verbose > 1) {
26412 printf(" Improving mesh quality by smoothing [%d]#: %ld.\n",
26413 iter, flipqueue->objects);
26414 }
26415
26416 for (k = 0; k < flipqueue->objects; k++) {
26417 bface = (badface *) fastlookup(flipqueue, k);
26418 if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26419 bface->foppo, &bface->tt)) {
26420 // Operate on it if it is not in 'unflipqueue'.
26421 if (!marktested(bface->tt)) {
26422 // Here we simply re-compute the quality. Since other smoothing
26423 // operation may have moved the vertices of this tet.
26424 ppt = (point *) & (bface->tt.tet[4]);
26425 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26426 &bface->key, NULL);
26427 if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
26428 // It is a sliver. Try to smooth its vertices.
26429 smtflag = 0;
26430 opm->initval = bface->key + 1.0;
26431 for (i = 0; (i < 4) && !smtflag; i++) {
26432 if (pointtype(ppt[i]) == FREEVOLVERTEX) {
26433 getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
26434 opm->searchstep = 0.001; // Search step size
26435 smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
26436 if (smtflag) {
26437 while (opm->smthiter == opm->maxiter) {
26438 opm->searchstep *= 10.0; // Increase the step size.
26439 opm->initval = opm->imprval;
26440 opm->smthiter = 0; // reset
26441 smoothpoint(ppt[i], cavetetlist, 1, opm);
26442 }
26443 // This tet is modifed.
26444 smtcount++;
26445 if ((opm->imprval - 1.0) < cossmtdihed) {
26446 // There are slivers in new tets. Queue them.
26447 for (j = 0; j < cavetetlist->objects; j++) {
26448 parytet = (triface *) fastlookup(cavetetlist, j);
26449 assert(!isdeadtet(*parytet));
26450 // Operate it if it is not in 'unflipqueue'.
26451 if (!marktested(*parytet)) {
26452 // Evaluate its quality.
26453 // Re-use ppt, bface->key, bface->cent.
26454 ppt = (point *) & (parytet->tet[4]);
26455 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3],
26456 bface->cent, &bface->key, NULL);
26457 if (bface->key < cossmtdihed) {
26458 // A new sliver. Queue it.
26459 marktest(*parytet); // It is in unflipqueue.
26460 unflipqueue->newindex((void **) &parybface);
26461 parybface->tt = *parytet;
26462 parybface->forg = ppt[0];
26463 parybface->fdest = ppt[1];
26464 parybface->fapex = ppt[2];
26465 parybface->foppo = ppt[3];
26466 parybface->tt.ver = 11;
26467 parybface->key = 0.0;
26468 }
26469 }
26470 } // j
26471 } // if ((opm->imprval - 1.0) < cossmtdihed)
26472 } // if (smtflag)
26473 cavetetlist->restart();
26474 } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
26475 } // i
26476 if (!smtflag) {
26477 // Didn't smooth. Queue it again.
26478 marktest(bface->tt); // It is in unflipqueue.
26479 unflipqueue->newindex((void **) &parybface);
26480 parybface->tt = bface->tt;
26481 parybface->forg = ppt[0];
26482 parybface->fdest = ppt[1];
26483 parybface->fapex = ppt[2];
26484 parybface->foppo = ppt[3];
26485 parybface->tt.ver = 11;
26486 parybface->key = 0.0;
26487 }
26488 } // if (maxdd < cosslidihed)
26489 } // if (!marktested(...))
26490 } // if (gettetrahedron(...))
26491 } // k
26492
26493 flipqueue->restart();
26494
26495 // Unmark the tets in unflipqueue.
26496 for (i = 0; i < unflipqueue->objects; i++) {
26497 bface = (badface *) fastlookup(unflipqueue, i);
26498 unmarktest(bface->tt);
26499 }
26500
26501 if (b->verbose > 1) {
26502 printf(" Smooth %ld points.\n", smtcount);
26503 }
26504 totalsmtcount += smtcount;
26505
26506 if (smtcount == 0l) {
26507 // No point has been smoothed.
26508 break;
26509 } else {
26510 iter++;
26511 if (iter == 2) { //if (iter >= b->optpasses) {
26512 break;
26513 }
26514 }
26515
26516 // Swap the two flip queues.
26517 swapqueue = flipqueue;
26518 flipqueue = unflipqueue;
26519 unflipqueue = swapqueue;
26520 } // while
26521
26522 delete flipqueue;
26523
26524 return totalsmtcount;
26525}
26526
26527///////////////////////////////////////////////////////////////////////////////
26528// //
26529// splitsliver() Split a sliver. //
26530// //
26531///////////////////////////////////////////////////////////////////////////////
26532
26533int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
26534{
26535 triface *abtets;
26536 triface searchtet, spintet, *parytet;
26537 point pa, pb, steinerpt;
26538 optparameters opm;
26539 insertvertexflags ivf;
26540 REAL smtpt[3], midpt[3];
26541 int success;
26542 int t1ver;
26543 int n, i;
26544
26545 // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle.
26546 // Go to the opposite edge [a,b].
26547 edestoppo(*slitet, searchtet); // [a,b,c,d].
26548
26549 // Do not split a segment.
26550 if (issubseg(searchtet)) {
26551 return 0;
26552 }
26553
26554 // Count the number of tets shared at [a,b].
26555 // Do not split it if it is a hull edge.
26556 spintet = searchtet;
26557 n = 0;
26558 while (1) {
26559 if (ishulltet(spintet)) break;
26560 n++;
26561 fnextself(spintet);
26562 if (spintet.tet == searchtet.tet) break;
26563 }
26564 if (ishulltet(spintet)) {
26565 return 0; // It is a hull edge.
26566 }
26567 assert(n >= 3);
26568
26569 // Get all tets at edge [a,b].
26570 abtets = new triface[n];
26571 spintet = searchtet;
26572 for (i = 0; i < n; i++) {
26573 abtets[i] = spintet;
26574 fnextself(spintet);
26575 }
26576
26577 // Initialize the list of 2n boundary faces.
26578 for (i = 0; i < n; i++) {
26579 eprev(abtets[i], searchtet);
26580 esymself(searchtet); // [a,p_i,p_i+1].
26581 cavetetlist->newindex((void **) &parytet);
26582 *parytet = searchtet;
26583 enext(abtets[i], searchtet);
26584 esymself(searchtet); // [p_i,b,p_i+1].
26585 cavetetlist->newindex((void **) &parytet);
26586 *parytet = searchtet;
26587 }
26588
26589 // Init the Steiner point at the midpoint of edge [a,b].
26590 pa = org(abtets[0]);
26591 pb = dest(abtets[0]);
26592 for (i = 0; i < 3; i++) {
26593 smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
26594 }
26595
26596 // Point smooth options.
26597 opm.min_max_dihedangle = 1;
26598 opm.initval = cosd + 1.0; // Initial volume is zero.
26599 opm.numofsearchdirs = 20;
26600 opm.searchstep = 0.001;
26601 opm.maxiter = 100; // Limit the maximum iterations.
26602
26603 success = smoothpoint(smtpt, cavetetlist, 1, &opm);
26604
26605 if (success) {
26606 while (opm.smthiter == opm.maxiter) {
26607 // It was relocated and the prescribed maximum iteration reached.
26608 // Try to increase the search stepsize.
26609 opm.searchstep *= 10.0;
26610 //opm.maxiter = 100; // Limit the maximum iterations.
26611 opm.initval = opm.imprval;
26612 opm.smthiter = 0; // Init.
26613 smoothpoint(smtpt, cavetetlist, 1, &opm);
26614 }
26615 } // if (success)
26616
26617 cavetetlist->restart();
26618
26619 if (!success) {
26620 delete [] abtets;
26621 return 0;
26622 }
26623
26624
26625 // Insert the Steiner point.
26626 makepoint(&steinerpt, FREEVOLVERTEX);
26627 for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
26628
26629 // Insert the created Steiner point.
26630 for (i = 0; i < n; i++) {
26631 infect(abtets[i]);
26632 caveoldtetlist->newindex((void **) &parytet);
26633 *parytet = abtets[i];
26634 }
26635
26636 searchtet = abtets[0]; // No need point location.
26637 if (b->metric) {
26638 locate(steinerpt, &searchtet); // For size interpolation.
26639 }
26640
26641 delete [] abtets;
26642
26643 ivf.iloc = (int) INSTAR;
26644 ivf.chkencflag = chkencflag;
26645 ivf.assignmeshsize = b->metric;
26646
26647
26648 if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
26649 // The vertex has been inserted.
26650 st_volref_count++;
26651 if (steinerleft > 0) steinerleft--;
26652 return 1;
26653 } else {
26654 // The Steiner point is too close to an existing vertex. Reject it.
26655 pointdealloc(steinerpt);
26656 return 0;
26657 }
26658}
26659
26660///////////////////////////////////////////////////////////////////////////////
26661// //
26662// removeslivers() Remove slivers by adding Steiner points. //
26663// //
26664///////////////////////////////////////////////////////////////////////////////
26665
26666long tetgenmesh::removeslivers(int chkencflag)
26667{
26668 arraypool *flipqueue, *swapqueue;
26669 badface *bface, *parybface;
26670 triface slitet, *parytet;
26671 point *ppt;
26672 REAL cosdd[6], maxcosd;
26673 long totalsptcount, sptcount;
26674 int iter, i, j, k;
26675
26676 //assert(unflipqueue->objects > 0l);
26677 flipqueue = new arraypool(sizeof(badface), 10);
26678
26679 // Swap the two flip queues.
26680 swapqueue = flipqueue;
26681 flipqueue = unflipqueue;
26682 unflipqueue = swapqueue;
26683
26684 totalsptcount = 0l;
26685 iter = 0;
26686
26687 while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
26688
26689 sptcount = 0l;
26690
26691 if (b->verbose > 1) {
26692 printf(" Splitting bad quality tets [%d]#: %ld.\n",
26693 iter, flipqueue->objects);
26694 }
26695
26696 for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {
26697 bface = (badface *) fastlookup(flipqueue, k);
26698 if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26699 bface->foppo, &bface->tt)) {
26700 if ((bface->key == 0) || (bface->tt.ver != 11)) {
26701 // Here we need to re-compute the quality. Since other smoothing
26702 // operation may have moved the vertices of this tet.
26703 ppt = (point *) & (bface->tt.tet[4]);
26704 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26705 &bface->key, NULL);
26706 }
26707 if (bface->key < cosslidihed) {
26708 // It is a sliver. Try to split it.
26709 slitet.tet = bface->tt.tet;
26710 //cosdd = bface->cent;
26711 for (j = 0; j < 6; j++) {
26712 if (bface->cent[j] < cosslidihed) {
26713 // Found a large dihedral angle.
26714 slitet.ver = edge2ver[j]; // Go to the edge.
26715 if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
26716 sptcount++;
26717 break;
26718 }
26719 }
26720 } // j
26721 if (j < 6) {
26722 // A sliver is split. Queue new slivers.
26723 badtetrahedrons->traversalinit();
26724 parytet = (triface *) badtetrahedrons->traverse();
26725 while (parytet != NULL) {
26726 unmarktest2(*parytet);
26727 ppt = (point *) & (parytet->tet[4]);
26728 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd,
26729 &maxcosd, NULL);
26730 if (maxcosd < cosslidihed) {
26731 // A new sliver. Queue it.
26732 unflipqueue->newindex((void **) &parybface);
26733 parybface->forg = ppt[0];
26734 parybface->fdest = ppt[1];
26735 parybface->fapex = ppt[2];
26736 parybface->foppo = ppt[3];
26737 parybface->tt.tet = parytet->tet;
26738 parybface->tt.ver = 11;
26739 parybface->key = maxcosd;
26740 for (i = 0; i < 6; i++) {
26741 parybface->cent[i] = cosdd[i];
26742 }
26743 }
26744 parytet = (triface *) badtetrahedrons->traverse();
26745 }
26746 badtetrahedrons->restart();
26747 } else {
26748 // Didn't split. Queue it again.
26749 unflipqueue->newindex((void **) &parybface);
26750 *parybface = *bface;
26751 } // if (j == 6)
26752 } // if (bface->key < cosslidihed)
26753 } // if (gettetrahedron(...))
26754 } // k
26755
26756 flipqueue->restart();
26757
26758 if (b->verbose > 1) {
26759 printf(" Split %ld tets.\n", sptcount);
26760 }
26761 totalsptcount += sptcount;
26762
26763 if (sptcount == 0l) {
26764 // No point has been smoothed.
26765 break;
26766 } else {
26767 iter++;
26768 if (iter == 2) { //if (iter >= b->optpasses) {
26769 break;
26770 }
26771 }
26772
26773 // Swap the two flip queues.
26774 swapqueue = flipqueue;
26775 flipqueue = unflipqueue;
26776 unflipqueue = swapqueue;
26777 } // while
26778
26779 delete flipqueue;
26780
26781 return totalsptcount;
26782}
26783
26784///////////////////////////////////////////////////////////////////////////////
26785// //
26786// optimizemesh() Optimize mesh for specified objective functions. //
26787// //
26788///////////////////////////////////////////////////////////////////////////////
26789
26790void tetgenmesh::optimizemesh()
26791{
26792 badface *parybface;
26793 triface checktet;
26794 point *ppt;
26795 int optpasses;
26796 optparameters opm;
26797 REAL ncosdd[6], maxdd;
26798 long totalremcount, remcount;
26799 long totalsmtcount, smtcount;
26800 long totalsptcount, sptcount;
26801 int chkencflag;
26802 int iter;
26803 int n;
26804
26805 if (!b->quiet) {
26806 printf("Optimizing mesh...\n");
26807 }
26808
26809 optpasses = ((1 << b->optlevel) - 1);
26810
26811 if (b->verbose) {
26812 printf(" Optimization level = %d.\n", b->optlevel);
26813 printf(" Optimization scheme = %d.\n", b->optscheme);
26814 printf(" Number of iteration = %d.\n", optpasses);
26815 printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral);
26816 }
26817
26818 totalsmtcount = totalsptcount = totalremcount = 0l;
26819
26820 cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
26821 cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
26822 cosslidihed = cos(b->optminslidihed / 180.0 * PI);
26823
26824 int attrnum = numelemattrib - 1;
26825
26826 // Put all bad tetrahedra into array.
26827 tetrahedrons->traversalinit();
26828 checktet.tet = tetrahedrontraverse();
26829 while (checktet.tet != NULL) {
26830 if (b->convex) { // -c
26831 // Skip this tet if it lies in the exterior.
26832 if (elemattribute(checktet.tet, attrnum) == -1.0) {
26833 checktet.tet = tetrahedrontraverse();
26834 continue;
26835 }
26836 }
26837 ppt = (point *) & (checktet.tet[4]);
26838 tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
26839 if (maxdd < cosmaxdihed) {
26840 // There are bad dihedral angles in this tet.
26841 unflipqueue->newindex((void **) &parybface);
26842 parybface->tt.tet = checktet.tet;
26843 parybface->tt.ver = 11;
26844 parybface->forg = ppt[0];
26845 parybface->fdest = ppt[1];
26846 parybface->fapex = ppt[2];
26847 parybface->foppo = ppt[3];
26848 parybface->key = maxdd;
26849 for (n = 0; n < 6; n++) {
26850 parybface->cent[n] = ncosdd[n];
26851 }
26852 }
26853 checktet.tet = tetrahedrontraverse();
26854 }
26855
26856 totalremcount = improvequalitybyflips();
26857
26858 if ((unflipqueue->objects > 0l) &&
26859 ((b->optscheme & 2) || (b->optscheme & 4))) {
26860 // The pool is only used by removeslivers().
26861 badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
26862 sizeof(void *), 0);
26863
26864 // Smoothing options.
26865 opm.min_max_dihedangle = 1;
26866 opm.numofsearchdirs = 10;
26867 // opm.searchstep = 0.001;
26868 opm.maxiter = 30; // Limit the maximum iterations.
26869 //opm.checkencflag = 4; // Queue affected tets after smoothing.
26870 chkencflag = 4; // Queue affected tets after splitting a sliver.
26871 iter = 0;
26872
26873 while (iter < optpasses) {
26874 smtcount = sptcount = remcount = 0l;
26875 if (b->optscheme & 2) {
26876 smtcount += improvequalitybysmoothing(&opm);
26877 totalsmtcount += smtcount;
26878 if (smtcount > 0l) {
26879 remcount = improvequalitybyflips();
26880 totalremcount += remcount;
26881 }
26882 }
26883 if (unflipqueue->objects > 0l) {
26884 if (b->optscheme & 4) {
26885 sptcount += removeslivers(chkencflag);
26886 totalsptcount += sptcount;
26887 if (sptcount > 0l) {
26888 remcount = improvequalitybyflips();
26889 totalremcount += remcount;
26890 }
26891 }
26892 }
26893 if (unflipqueue->objects > 0l) {
26894 if (remcount > 0l) {
26895 iter++;
26896 } else {
26897 break;
26898 }
26899 } else {
26900 break;
26901 }
26902 } // while (iter)
26903
26904 delete badtetrahedrons;
26905
26906 }
26907
26908 if (unflipqueue->objects > 0l) {
26909 if (b->verbose > 1) {
26910 printf(" %ld bad tets remained.\n", unflipqueue->objects);
26911 }
26912 unflipqueue->restart();
26913 }
26914
26915 if (b->verbose) {
26916 if (totalremcount > 0l) {
26917 printf(" Removed %ld edges.\n", totalremcount);
26918 }
26919 if (totalsmtcount > 0l) {
26920 printf(" Smoothed %ld points.\n", totalsmtcount);
26921 }
26922 if (totalsptcount > 0l) {
26923 printf(" Split %ld slivers.\n", totalsptcount);
26924 }
26925 }
26926}
26927
26928//// ////
26929//// ////
26930//// optimize_cxx /////////////////////////////////////////////////////////////
26931
26932//// meshstat_cxx /////////////////////////////////////////////////////////////
26933//// ////
26934//// ////
26935
26936///////////////////////////////////////////////////////////////////////////////
26937// //
26938// printfcomma() Print a (large) number with the 'thousands separator'. //
26939// //
26940// The following code was simply copied from "stackoverflow". //
26941// //
26942///////////////////////////////////////////////////////////////////////////////
26943
26944void tetgenmesh::printfcomma(unsigned long n)
26945{
26946 unsigned long n2 = 0;
26947 int scale = 1;
26948 while (n >= 1000) {
26949 n2 = n2 + scale * (n % 1000);
26950 n /= 1000;
26951 scale *= 1000;
26952 }
26953 printf ("%ld", n);
26954 while (scale != 1) {
26955 scale /= 1000;
26956 n = n2 / scale;
26957 n2 = n2 % scale;
26958 printf (",%03ld", n);
26959 }
26960}
26961
26962///////////////////////////////////////////////////////////////////////////////
26963// //
26964// checkmesh() Test the mesh for topological consistency. //
26965// //
26966// If 'topoflag' is set, only check the topological connection of the mesh, //
26967// i.e., do not report degenerated or inverted elements. //
26968// //
26969///////////////////////////////////////////////////////////////////////////////
26970
26971int tetgenmesh::checkmesh(int topoflag)
26972{
26973 triface tetloop, neightet, symtet;
26974 point pa, pb, pc, pd;
26975 REAL ori;
26976 int horrors, i;
26977
26978 if (!b->quiet) {
26979 printf(" Checking consistency of mesh...\n");
26980 }
26981
26982 horrors = 0;
26983 tetloop.ver = 0;
26984 // Run through the list of tetrahedra, checking each one.
26985 tetrahedrons->traversalinit();
26986 tetloop.tet = alltetrahedrontraverse();
26987 while (tetloop.tet != (tetrahedron *) NULL) {
26988 // Check all four faces of the tetrahedron.
26989 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
26990 pa = org(tetloop);
26991 pb = dest(tetloop);
26992 pc = apex(tetloop);
26993 pd = oppo(tetloop);
26994 if (tetloop.ver == 0) { // Only test for inversion once.
26995 if (!ishulltet(tetloop)) { // Only do test if it is not a hull tet.
26996 if (!topoflag) {
26997 ori = orient3d(pa, pb, pc, pd);
26998 if (ori >= 0.0) {
26999 printf(" !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
27000 printf(" (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
27001 pointmark(pb), pointmark(pc), pointmark(pd), ori);
27002 horrors++;
27003 }
27004 }
27005 }
27006 if (infected(tetloop)) {
27007 // This may be a bug. Report it.
27008 printf(" !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
27009 pointmark(pb), pointmark(pc), pointmark(pd));
27010 horrors++;
27011 }
27012 if (marktested(tetloop)) {
27013 // This may be a bug. Report it.
27014 printf(" !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
27015 pointmark(pb), pointmark(pc), pointmark(pd));
27016 horrors++;
27017 }
27018 }
27019 if (tetloop.tet[tetloop.ver] == NULL) {
27020 printf(" !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
27021 pointmark(pb), pointmark(pc));
27022 horrors++;
27023 } else {
27024 // Find the neighboring tetrahedron on this face.
27025 fsym(tetloop, neightet);
27026 // Check that the tetrahedron's neighbor knows it's a neighbor.
27027 fsym(neightet, symtet);
27028 if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
27029 printf(" !! !! Asymmetric tetra-tetra bond:\n");
27030 if (tetloop.tet == symtet.tet) {
27031 printf(" (Right tetrahedron, wrong orientation)\n");
27032 }
27033 printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27034 pointmark(pb), pointmark(pc), pointmark(pd));
27035 printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27036 pointmark(dest(neightet)), pointmark(apex(neightet)),
27037 pointmark(oppo(neightet)));
27038 horrors++;
27039 }
27040 // Check if they have the same edge (the bond() operation).
27041 if ((org(neightet) != pb) || (dest(neightet) != pa)) {
27042 printf(" !! !! Wrong edge-edge bond:\n");
27043 printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27044 pointmark(pb), pointmark(pc), pointmark(pd));
27045 printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27046 pointmark(dest(neightet)), pointmark(apex(neightet)),
27047 pointmark(oppo(neightet)));
27048 horrors++;
27049 }
27050 // Check if they have the same apex.
27051 if (apex(neightet) != pc) {
27052 printf(" !! !! Wrong face-face bond:\n");
27053 printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27054 pointmark(pb), pointmark(pc), pointmark(pd));
27055 printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27056 pointmark(dest(neightet)), pointmark(apex(neightet)),
27057 pointmark(oppo(neightet)));
27058 horrors++;
27059 }
27060 // Check if they have the same opposite.
27061 if (oppo(neightet) == pd) {
27062 printf(" !! !! Two identical tetra:\n");
27063 printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27064 pointmark(pb), pointmark(pc), pointmark(pd));
27065 printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27066 pointmark(dest(neightet)), pointmark(apex(neightet)),
27067 pointmark(oppo(neightet)));
27068 horrors++;
27069 }
27070 }
27071 if (facemarked(tetloop)) {
27072 // This may be a bug. Report it.
27073 printf(" !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
27074 pointmark(pb), pointmark(pc), pointmark(pd));
27075 }
27076 }
27077 // Check the six edges of this tet.
27078 for (i = 0; i < 6; i++) {
27079 tetloop.ver = edge2ver[i];
27080 if (edgemarked(tetloop)) {
27081 // This may be a bug. Report it.
27082 printf(" !! tetedge (%d, %d) %d, %d is marked.\n",
27083 pointmark(org(tetloop)), pointmark(dest(tetloop)),
27084 pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
27085 }
27086 }
27087 tetloop.tet = alltetrahedrontraverse();
27088 }
27089 if (horrors == 0) {
27090 if (!b->quiet) {
27091 printf(" In my studied opinion, the mesh appears to be consistent.\n");
27092 }
27093 } else {
27094 printf(" !! !! !! !! %d %s witnessed.\n", horrors,
27095 horrors > 1 ? "abnormity" : "abnormities");
27096 }
27097
27098 return horrors;
27099}
27100
27101///////////////////////////////////////////////////////////////////////////////
27102// //
27103// checkshells() Test the boundary mesh for topological consistency. //
27104// //
27105///////////////////////////////////////////////////////////////////////////////
27106
27107int tetgenmesh::checkshells()
27108{
27109 triface neightet, symtet;
27110 face shloop, spinsh, nextsh;
27111 face checkseg;
27112 point pa, pb;
27113 int bakcount;
27114 int horrors, i;
27115
27116 if (!b->quiet) {
27117 printf(" Checking consistency of the mesh boundary...\n");
27118 }
27119 horrors = 0;
27120
27121 void **bakpathblock = subfaces->pathblock;
27122 void *bakpathitem = subfaces->pathitem;
27123 int bakpathitemsleft = subfaces->pathitemsleft;
27124 int bakalignbytes = subfaces->alignbytes;
27125
27126 subfaces->traversalinit();
27127 shloop.sh = shellfacetraverse(subfaces);
27128 while (shloop.sh != NULL) {
27129 shloop.shver = 0;
27130 for (i = 0; i < 3; i++) {
27131 // Check the face ring at this edge.
27132 pa = sorg(shloop);
27133 pb = sdest(shloop);
27134 spinsh = shloop;
27135 spivot(spinsh, nextsh);
27136 bakcount = horrors;
27137 while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
27138 if (nextsh.sh[3] == NULL) {
27139 printf(" !! !! Wrong subface-subface connection (Dead subface).\n");
27140 printf(" First: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27141 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27142 pointmark(sapex(spinsh)));
27143 printf(" Second: x%" PRIxPTR " (DEAD)\n", (uintptr_t) nextsh.sh);
27144 horrors++;
27145 break;
27146 }
27147 // check if they have the same edge.
27148 if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) ||
27149 ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) {
27150 printf(" !! !! Wrong subface-subface connection.\n");
27151 printf(" First: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27152 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27153 pointmark(sapex(spinsh)));
27154 printf(" Scond: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
27155 pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
27156 pointmark(sapex(nextsh)));
27157 horrors++;
27158 break;
27159 }
27160 // Check they should not have the same apex.
27161 if (sapex(nextsh) == sapex(spinsh)) {
27162 printf(" !! !! Existing two duplicated subfaces.\n");
27163 printf(" First: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27164 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27165 pointmark(sapex(spinsh)));
27166 printf(" Scond: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
27167 pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
27168 pointmark(sapex(nextsh)));
27169 horrors++;
27170 break;
27171 }
27172 spinsh = nextsh;
27173 spivot(spinsh, nextsh);
27174 }
27175 // Check subface-subseg bond.
27176 sspivot(shloop, checkseg);
27177 if (checkseg.sh != NULL) {
27178 if (checkseg.sh[3] == NULL) {
27179 printf(" !! !! Wrong subface-subseg connection (Dead subseg).\n");
27180 printf(" Sub: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27181 pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27182 pointmark(sapex(shloop)));
27183 printf(" Sub: x%" PRIxPTR " (Dead)\n", (uintptr_t) checkseg.sh);
27184 horrors++;
27185 } else {
27186 if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) ||
27187 ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) {
27188 printf(" !! !! Wrong subface-subseg connection.\n");
27189 printf(" Sub: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27190 pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27191 pointmark(sapex(shloop)));
27192 printf(" Seg: x%" PRIxPTR " (%d, %d).\n", (uintptr_t) checkseg.sh,
27193 pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
27194 horrors++;
27195 }
27196 }
27197 }
27198 if (horrors > bakcount) break; // An error detected.
27199 senextself(shloop);
27200 }
27201 // Check tet-subface connection.
27202 stpivot(shloop, neightet);
27203 if (neightet.tet != NULL) {
27204 if (neightet.tet[4] == NULL) {
27205 printf(" !! !! Wrong sub-to-tet connection (Dead tet)\n");
27206 printf(" Sub: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27207 pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27208 pointmark(sapex(shloop)));
27209 printf(" Tet: x%" PRIxPTR " (DEAD)\n", (uintptr_t) neightet.tet);
27210 horrors++;
27211 } else {
27212 if (!((sorg(shloop) == org(neightet)) &&
27213 (sdest(shloop) == dest(neightet)))) {
27214 printf(" !! !! Wrong sub-to-tet connection\n");
27215 printf(" Sub: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27216 pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27217 pointmark(sapex(shloop)));
27218 printf(" Tet: x%" PRIxPTR " (%d, %d, %d, %d).\n",
27219 (uintptr_t) neightet.tet, pointmark(org(neightet)),
27220 pointmark(dest(neightet)), pointmark(apex(neightet)),
27221 pointmark(oppo(neightet)));
27222 horrors++;
27223 }
27224 tspivot(neightet, spinsh);
27225 if (!((sorg(spinsh) == org(neightet)) &&
27226 (sdest(spinsh) == dest(neightet)))) {
27227 printf(" !! !! Wrong tet-sub connection.\n");
27228 printf(" Sub: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27229 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27230 pointmark(sapex(spinsh)));
27231 printf(" Tet: x%" PRIxPTR " (%d, %d, %d, %d).\n",
27232 (uintptr_t) neightet.tet, pointmark(org(neightet)),
27233 pointmark(dest(neightet)), pointmark(apex(neightet)),
27234 pointmark(oppo(neightet)));
27235 horrors++;
27236 }
27237 fsym(neightet, symtet);
27238 tspivot(symtet, spinsh);
27239 if (spinsh.sh != NULL) {
27240 if (!((sorg(spinsh) == org(symtet)) &&
27241 (sdest(spinsh) == dest(symtet)))) {
27242 printf(" !! !! Wrong tet-sub connection.\n");
27243 printf(" Sub: x%" PRIxPTR " (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27244 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27245 pointmark(sapex(spinsh)));
27246 printf(" Tet: x%" PRIxPTR " (%d, %d, %d, %d).\n",
27247 (uintptr_t) symtet.tet, pointmark(org(symtet)),
27248 pointmark(dest(symtet)), pointmark(apex(symtet)),
27249 pointmark(oppo(symtet)));
27250 horrors++;
27251 }
27252 } else {
27253 printf(" Warning: Broken tet-sub-tet connection.\n");
27254 }
27255 }
27256 }
27257 if (sinfected(shloop)) {
27258 // This may be a bug. report it.
27259 printf(" !! A infected subface: (%d, %d, %d).\n",
27260 pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27261 pointmark(sapex(shloop)));
27262 }
27263 if (smarktested(shloop)) {
27264 // This may be a bug. report it.
27265 printf(" !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)),
27266 pointmark(sdest(shloop)), pointmark(sapex(shloop)));
27267 }
27268 shloop.sh = shellfacetraverse(subfaces);
27269 }
27270
27271 if (horrors == 0) {
27272 if (!b->quiet) {
27273 printf(" Mesh boundaries connected correctly.\n");
27274 }
27275 } else {
27276 printf(" !! !! !! !! %d boundary connection viewed with horror.\n",
27277 horrors);
27278 }
27279
27280 subfaces->pathblock = bakpathblock;
27281 subfaces->pathitem = bakpathitem;
27282 subfaces->pathitemsleft = bakpathitemsleft;
27283 subfaces->alignbytes = bakalignbytes;
27284
27285 return horrors;
27286}
27287
27288///////////////////////////////////////////////////////////////////////////////
27289// //
27290// checksegments() Check the connections between tetrahedra and segments. //
27291// //
27292///////////////////////////////////////////////////////////////////////////////
27293
27294int tetgenmesh::checksegments()
27295{
27296 triface tetloop, neightet, spintet;
27297 shellface *segs;
27298 face neighsh, spinsh, checksh;
27299 face sseg, checkseg;
27300 point pa, pb;
27301 int miscount;
27302 int t1ver;
27303 int horrors, i;
27304
27305
27306 if (!b->quiet) {
27307 printf(" Checking tet->seg connections...\n");
27308 }
27309
27310 horrors = 0;
27311 tetrahedrons->traversalinit();
27312 tetloop.tet = tetrahedrontraverse();
27313 while (tetloop.tet != NULL) {
27314 // Loop the six edges of the tet.
27315 if (tetloop.tet[8] != NULL) {
27316 segs = (shellface *) tetloop.tet[8];
27317 for (i = 0; i < 6; i++) {
27318 sdecode(segs[i], sseg);
27319 if (sseg.sh != NULL) {
27320 // Get the edge of the tet.
27321 tetloop.ver = edge2ver[i];
27322 // Check if they are the same edge.
27323 pa = (point) sseg.sh[3];
27324 pb = (point) sseg.sh[4];
27325 if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
27326 ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
27327 printf(" !! Wrong tet-seg connection.\n");
27328 printf(" Tet: x%" PRIxPTR " (%d, %d, %d, %d) - Seg: x%" PRIxPTR " (%d, %d).\n",
27329 (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
27330 pointmark(dest(tetloop)), pointmark(apex(tetloop)),
27331 pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
27332 pointmark(pa), pointmark(pb));
27333 horrors++;
27334 } else {
27335 // Loop all tets sharing at this edge.
27336 neightet = tetloop;
27337 do {
27338 tsspivot1(neightet, checkseg);
27339 if (checkseg.sh != sseg.sh) {
27340 printf(" !! Wrong tet->seg connection.\n");
27341 printf(" Tet: x%" PRIxPTR " (%d, %d, %d, %d) - ",
27342 (uintptr_t) neightet.tet, pointmark(org(neightet)),
27343 pointmark(dest(neightet)), pointmark(apex(neightet)),
27344 pointmark(oppo(neightet)));
27345 if (checkseg.sh != NULL) {
27346 printf("Seg x%" PRIxPTR " (%d, %d).\n", (uintptr_t) checkseg.sh,
27347 pointmark(sorg(checkseg)),pointmark(sdest(checkseg)));
27348 } else {
27349 printf("Seg: NULL.\n");
27350 }
27351 horrors++;
27352 }
27353 fnextself(neightet);
27354 } while (neightet.tet != tetloop.tet);
27355 }
27356 // Check the seg->tet pointer.
27357 sstpivot1(sseg, neightet);
27358 if (neightet.tet == NULL) {
27359 printf(" !! Wrong seg->tet connection (A NULL tet).\n");
27360 horrors++;
27361 } else {
27362 if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
27363 ((org(neightet) == pb) && (dest(neightet) == pa)))) {
27364 printf(" !! Wrong seg->tet connection (Wrong edge).\n");
27365 printf(" Tet: x%" PRIxPTR " (%d, %d, %d, %d) - Seg: x%" PRIxPTR " (%d, %d).\n",
27366 (uintptr_t) neightet.tet, pointmark(org(neightet)),
27367 pointmark(dest(neightet)), pointmark(apex(neightet)),
27368 pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
27369 pointmark(pa), pointmark(pb));
27370 horrors++;
27371 }
27372 }
27373 }
27374 }
27375 }
27376 // Loop the six edge of this tet.
27377 neightet.tet = tetloop.tet;
27378 for (i = 0; i < 6; i++) {
27379 neightet.ver = edge2ver[i];
27380 if (edgemarked(neightet)) {
27381 // A possible bug. Report it.
27382 printf(" !! A marked edge: (%d, %d, %d, %d) -- x%" PRIxPTR " %d.\n",
27383 pointmark(org(neightet)), pointmark(dest(neightet)),
27384 pointmark(apex(neightet)), pointmark(oppo(neightet)),
27385 (uintptr_t) neightet.tet, neightet.ver);
27386 // Check if all tets at the edge are marked.
27387 spintet = neightet;
27388 while (1) {
27389 fnextself(spintet);
27390 if (!edgemarked(spintet)) {
27391 printf(" !! !! An unmarked edge (%d, %d, %d, %d) -- x%" PRIxPTR " %d.\n",
27392 pointmark(org(spintet)), pointmark(dest(spintet)),
27393 pointmark(apex(spintet)), pointmark(oppo(spintet)),
27394 (uintptr_t) spintet.tet, spintet.ver);
27395 horrors++;
27396 }
27397 if (spintet.tet == neightet.tet) break;
27398 }
27399 }
27400 }
27401 tetloop.tet = tetrahedrontraverse();
27402 }
27403
27404 if (!b->quiet) {
27405 printf(" Checking seg->tet connections...\n");
27406 }
27407
27408 miscount = 0; // Count the number of unrecovered segments.
27409 subsegs->traversalinit();
27410 sseg.shver = 0;
27411 sseg.sh = shellfacetraverse(subsegs);
27412 while (sseg.sh != NULL) {
27413 pa = sorg(sseg);
27414 pb = sdest(sseg);
27415 spivot(sseg, neighsh);
27416 if (neighsh.sh != NULL) {
27417 spinsh = neighsh;
27418 while (1) {
27419 // Check seg-subface bond.
27420 if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
27421 ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
27422 // Keep the same rotate direction.
27423 //if (sorg(spinsh) != pa) {
27424 // sesymself(spinsh);
27425 // printf(" !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
27426 // pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27427 // pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
27428 // spinsh.shver);
27429 // horrors++;
27430 //}
27431 stpivot(spinsh, spintet);
27432 if (spintet.tet != NULL) {
27433 // Check if all tets at this segment.
27434 while (1) {
27435 tsspivot1(spintet, checkseg);
27436 if (checkseg.sh == NULL) {
27437 printf(" !! !! No seg at tet (%d, %d, %d, %d) -- x%" PRIxPTR " %d\n",
27438 pointmark(org(spintet)), pointmark(dest(spintet)),
27439 pointmark(apex(spintet)), pointmark(oppo(spintet)),
27440 (uintptr_t) spintet.tet, spintet.ver);
27441 horrors++;
27442 }
27443 if (checkseg.sh != sseg.sh) {
27444 printf(" !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
27445 pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
27446 pointmark(org(spintet)), pointmark(dest(spintet)),
27447 pointmark(apex(spintet)), pointmark(oppo(spintet)));
27448 horrors++;
27449 }
27450 fnextself(spintet);
27451 // Stop at the next subface.
27452 tspivot(spintet, checksh);
27453 if (checksh.sh != NULL) break;
27454 } // while (1)
27455 }
27456 } else {
27457 printf(" !! Wrong seg-subface (%d, %d, %d) -- x%" PRIxPTR " %d connect\n",
27458 pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27459 pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
27460 spinsh.shver);
27461 horrors++;
27462 break;
27463 } // if pa, pb
27464 spivotself(spinsh);
27465 if (spinsh.sh == NULL) break; // A dangling segment.
27466 if (spinsh.sh == neighsh.sh) break;
27467 } // while (1)
27468 } // if (neighsh.sh != NULL)
27469 // Count the number of "un-recovered" segments.
27470 sstpivot1(sseg, neightet);
27471 if (neightet.tet == NULL) {
27472 miscount++;
27473 }
27474 sseg.sh = shellfacetraverse(subsegs);
27475 }
27476
27477 if (!b->quiet) {
27478 printf(" Checking seg->seg connections...\n");
27479 }
27480
27481 points->traversalinit();
27482 pa = pointtraverse();
27483 while (pa != NULL) {
27484 if (pointtype(pa) == FREESEGVERTEX) {
27485 // There should be two subsegments connected at 'pa'.
27486 // Get a subsegment containing 'pa'.
27487 sdecode(point2sh(pa), sseg);
27488 if ((sseg.sh == NULL) || sseg.sh[3] == NULL) {
27489 printf(" !! Dead point-to-seg pointer at point %d.\n",
27490 pointmark(pa));
27491 horrors++;
27492 } else {
27493 sseg.shver = 0;
27494 if (sorg(sseg) != pa) {
27495 if (sdest(sseg) != pa) {
27496 printf(" !! Wrong point-to-seg pointer at point %d.\n",
27497 pointmark(pa));
27498 horrors++;
27499 } else {
27500 // Find the next subsegment at 'pa'.
27501 senext(sseg, checkseg);
27502 if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
27503 printf(" !! Dead seg-seg connection at point %d.\n",
27504 pointmark(pa));
27505 horrors++;
27506 } else {
27507 spivotself(checkseg);
27508 checkseg.shver = 0;
27509 if (sorg(checkseg) != pa) {
27510 printf(" !! Wrong seg-seg connection at point %d.\n",
27511 pointmark(pa));
27512 horrors++;
27513 }
27514 }
27515 }
27516 } else {
27517 // Find the previous subsegment at 'pa'.
27518 senext2(sseg, checkseg);
27519 if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
27520 printf(" !! Dead seg-seg connection at point %d.\n",
27521 pointmark(pa));
27522 horrors++;
27523 } else {
27524 spivotself(checkseg);
27525 checkseg.shver = 0;
27526 if (sdest(checkseg) != pa) {
27527 printf(" !! Wrong seg-seg connection at point %d.\n",
27528 pointmark(pa));
27529 horrors++;
27530 }
27531 }
27532 }
27533 }
27534 }
27535 pa = pointtraverse();
27536 }
27537
27538 if (horrors == 0) {
27539 printf(" Segments are connected properly.\n");
27540 } else {
27541 printf(" !! !! !! !! Found %d missing connections.\n", horrors);
27542 }
27543 if (miscount > 0) {
27544 printf(" !! !! Found %d missing segments.\n", miscount);
27545 }
27546
27547 return horrors;
27548}
27549
27550///////////////////////////////////////////////////////////////////////////////
27551// //
27552// checkdelaunay() Ensure that the mesh is (constrained) Delaunay. //
27553// //
27554///////////////////////////////////////////////////////////////////////////////
27555
27556int tetgenmesh::checkdelaunay()
27557{
27558 triface tetloop;
27559 triface symtet;
27560 face checksh;
27561 point pa, pb, pc, pd, pe;
27562 REAL sign;
27563 int ndcount; // Count the non-locally Delaunay faces.
27564 int horrors;
27565
27566 if (!b->quiet) {
27567 printf(" Checking Delaunay property of the mesh...\n");
27568 }
27569
27570 ndcount = 0;
27571 horrors = 0;
27572 tetloop.ver = 0;
27573 // Run through the list of triangles, checking each one.
27574 tetrahedrons->traversalinit();
27575 tetloop.tet = tetrahedrontraverse();
27576 while (tetloop.tet != (tetrahedron *) NULL) {
27577 // Check all four faces of the tetrahedron.
27578 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27579 fsym(tetloop, symtet);
27580 // Only do test if its adjoining tet is not a hull tet or its pointer
27581 // is larger (to ensure that each pair isn't tested twice).
27582 if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
27583 pa = org(tetloop);
27584 pb = dest(tetloop);
27585 pc = apex(tetloop);
27586 pd = oppo(tetloop);
27587 pe = oppo(symtet);
27588 sign = insphere_s(pa, pb, pc, pd, pe);
27589 if (sign < 0.0) {
27590 ndcount++;
27591 if (checksubfaceflag) {
27592 tspivot(tetloop, checksh);
27593 }
27594 if (checksh.sh == NULL) {
27595 printf(" !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
27596 pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
27597 pointmark(pe));
27598 horrors++;
27599 }
27600 }
27601 }
27602 }
27603 tetloop.tet = tetrahedrontraverse();
27604 }
27605
27606 if (horrors == 0) {
27607 if (!b->quiet) {
27608 if (ndcount > 0) {
27609 printf(" The mesh is constrained Delaunay.\n");
27610 } else {
27611 printf(" The mesh is Delaunay.\n");
27612 }
27613 }
27614 } else {
27615 printf(" !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
27616 }
27617
27618 return horrors;
27619}
27620
27621///////////////////////////////////////////////////////////////////////////////
27622// //
27623// Check if the current tetrahedralization is (constrained) regular. //
27624// //
27625// The parameter 'type' determines which regularity should be checked: //
27626// - 0: check the Delaunay property. //
27627// - 1: check the Delaunay property with symbolic perturbation. //
27628// - 2: check the regular property, the weights are stored in p[3]. //
27629// - 3: check the regular property with symbolic perturbation. //
27630// //
27631///////////////////////////////////////////////////////////////////////////////
27632
27633int tetgenmesh::checkregular(int type)
27634{
27635 triface tetloop;
27636 triface symtet;
27637 face checksh;
27638 point p[5];
27639 REAL sign;
27640 int ndcount; // Count the non-locally Delaunay faces.
27641 int horrors;
27642
27643 if (!b->quiet) {
27644 printf(" Checking %s %s property of the mesh...\n",
27645 (type & 2) == 0 ? "Delaunay" : "regular",
27646 (type & 1) == 0 ? " " : "(s)");
27647 }
27648
27649 // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
27650 // Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
27651 // p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
27652 // The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
27653 // p[4] lies below the oriented hyperplane passing through
27654 // p[1], p[0], p[2], p[3].
27655
27656 ndcount = 0;
27657 horrors = 0;
27658 tetloop.ver = 0;
27659 // Run through the list of triangles, checking each one.
27660 tetrahedrons->traversalinit();
27661 tetloop.tet = tetrahedrontraverse();
27662 while (tetloop.tet != (tetrahedron *) NULL) {
27663 // Check all four faces of the tetrahedron.
27664 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27665 fsym(tetloop, symtet);
27666 // Only do test if its adjoining tet is not a hull tet or its pointer
27667 // is larger (to ensure that each pair isn't tested twice).
27668 if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
27669 p[0] = org(tetloop); // pa
27670 p[1] = dest(tetloop); // pb
27671 p[2] = apex(tetloop); // pc
27672 p[3] = oppo(tetloop); // pd
27673 p[4] = oppo(symtet); // pe
27674
27675 if (type == 0) {
27676 sign = insphere(p[1], p[0], p[2], p[3], p[4]);
27677 } else if (type == 1) {
27678 sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
27679 } else if (type == 2) {
27680 sign = orient4d(p[1], p[0], p[2], p[3], p[4],
27681 p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
27682 } else { // type == 3
27683 sign = orient4d_s(p[1], p[0], p[2], p[3], p[4],
27684 p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
27685 }
27686
27687 if (sign > 0.0) {
27688 ndcount++;
27689 if (checksubfaceflag) {
27690 tspivot(tetloop, checksh);
27691 }
27692 if (checksh.sh == NULL) {
27693 printf(" !! Non-locally %s (%d, %d, %d) - %d, %d\n",
27694 (type & 2) == 0 ? "Delaunay" : "regular",
27695 pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
27696 pointmark(p[3]), pointmark(p[4]));
27697 horrors++;
27698 }
27699 }
27700 }
27701 }
27702 tetloop.tet = tetrahedrontraverse();
27703 }
27704
27705 if (horrors == 0) {
27706 if (!b->quiet) {
27707 if (ndcount > 0) {
27708 printf(" The mesh is constrained %s.\n",
27709 (type & 2) == 0 ? "Delaunay" : "regular");
27710 } else {
27711 printf(" The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
27712 }
27713 }
27714 } else {
27715 printf(" !! !! !! !! Found %d non-%s faces.\n", horrors,
27716 (type & 2) == 0 ? "Delaunay" : "regular");
27717 }
27718
27719 return horrors;
27720}
27721
27722///////////////////////////////////////////////////////////////////////////////
27723// //
27724// checkconforming() Ensure that the mesh is conforming Delaunay. //
27725// //
27726// If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces. //
27727// If 'flag' is 3, check both subsegments and subfaces. //
27728// //
27729///////////////////////////////////////////////////////////////////////////////
27730
27731int tetgenmesh::checkconforming(int flag)
27732{
27733 triface searchtet, neightet, spintet;
27734 face shloop;
27735 face segloop;
27736 point eorg, edest, eapex, pa, pb, pc;
27737 REAL cent[3], radius, dist, diff, rd, len;
27738 bool enq;
27739 int encsubsegs, encsubfaces;
27740 int t1ver;
27741 int i;
27742
27743 REAL A[4][4], rhs[4], D;
27744 int indx[4];
27745 REAL elen[3];
27746
27747 encsubsegs = 0;
27748
27749 if (flag & 1) {
27750 if (!b->quiet) {
27751 printf(" Checking conforming property of segments...\n");
27752 }
27753 encsubsegs = 0;
27754
27755 // Run through the list of subsegments, check each one.
27756 subsegs->traversalinit();
27757 segloop.sh = shellfacetraverse(subsegs);
27758 while (segloop.sh != (shellface *) NULL) {
27759 eorg = (point) segloop.sh[3];
27760 edest = (point) segloop.sh[4];
27761 radius = 0.5 * distance(eorg, edest);
27762 for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
27763
27764 enq = false;
27765 sstpivot1(segloop, neightet);
27766 if (neightet.tet != NULL) {
27767 spintet = neightet;
27768 while (1) {
27769 eapex= apex(spintet);
27770 if (eapex != dummypoint) {
27771 dist = distance(eapex, cent);
27772 diff = dist - radius;
27773 if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
27774 if (diff < 0) {
27775 enq = true; break;
27776 }
27777 }
27778 fnextself(spintet);
27779 if (spintet.tet == neightet.tet) break;
27780 }
27781 }
27782 if (enq) {
27783 printf(" !! !! Non-conforming segment: (%d, %d)\n",
27784 pointmark(eorg), pointmark(edest));
27785 encsubsegs++;
27786 }
27787 segloop.sh = shellfacetraverse(subsegs);
27788 }
27789
27790 if (encsubsegs == 0) {
27791 if (!b->quiet) {
27792 printf(" The segments are conforming Delaunay.\n");
27793 }
27794 } else {
27795 printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs);
27796 }
27797 } // if (flag & 1)
27798
27799 encsubfaces = 0;
27800
27801 if (flag & 2) {
27802 if (!b->quiet) {
27803 printf(" Checking conforming property of subfaces...\n");
27804 }
27805
27806 // Run through the list of subfaces, check each one.
27807 subfaces->traversalinit();
27808 shloop.sh = shellfacetraverse(subfaces);
27809 while (shloop.sh != (shellface *) NULL) {
27810 pa = (point) shloop.sh[3];
27811 pb = (point) shloop.sh[4];
27812 pc = (point) shloop.sh[5];
27813
27814 // Compute the coefficient matrix A (3x3).
27815 A[0][0] = pb[0] - pa[0];
27816 A[0][1] = pb[1] - pa[1];
27817 A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
27818 A[1][0] = pc[0] - pa[0];
27819 A[1][1] = pc[1] - pa[1];
27820 A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
27821 cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
27822
27823 // Compute the right hand side vector b (3x1).
27824 elen[0] = dot(A[0], A[0]);
27825 elen[1] = dot(A[1], A[1]);
27826 rhs[0] = 0.5 * elen[0];
27827 rhs[1] = 0.5 * elen[1];
27828 rhs[2] = 0.0;
27829
27830 if (lu_decmp(A, 3, indx, &D, 0)) {
27831 lu_solve(A, 3, indx, rhs, 0);
27832 cent[0] = pa[0] + rhs[0];
27833 cent[1] = pa[1] + rhs[1];
27834 cent[2] = pa[2] + rhs[2];
27835 rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
27836
27837 // Check if this subface is encroached.
27838 for (i = 0; i < 2; i++) {
27839 stpivot(shloop, searchtet);
27840 if (!ishulltet(searchtet)) {
27841 len = distance(oppo(searchtet), cent);
27842 if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
27843 if (len < rd) {
27844 printf(" !! !! Non-conforming subface: (%d, %d, %d)\n",
27845 pointmark(pa), pointmark(pb), pointmark(pc));
27846 encsubfaces++;
27847 enq = true; break;
27848 }
27849 }
27850 sesymself(shloop);
27851 }
27852 }
27853 shloop.sh = shellfacetraverse(subfaces);
27854 }
27855
27856 if (encsubfaces == 0) {
27857 if (!b->quiet) {
27858 printf(" The subfaces are conforming Delaunay.\n");
27859 }
27860 } else {
27861 printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces);
27862 }
27863 } // if (flag & 2)
27864
27865 return encsubsegs + encsubfaces;
27866}
27867
27868///////////////////////////////////////////////////////////////////////////////
27869// //
27870// qualitystatistics() Print statistics about the quality of the mesh. //
27871// //
27872///////////////////////////////////////////////////////////////////////////////
27873
27874void tetgenmesh::qualitystatistics()
27875{
27876 triface tetloop, neightet;
27877 point p[4];
27878 char sbuf[128];
27879 REAL radiusratiotable[12];
27880 REAL aspectratiotable[12];
27881 REAL A[4][4], rhs[4], D;
27882 REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
27883 REAL edgelength[6], alldihed[6], faceangle[3];
27884 REAL shortest, longest;
27885 REAL smallestvolume, biggestvolume;
27886 REAL smallestratio, biggestratio;
27887 REAL smallestdiangle, biggestdiangle;
27888 REAL smallestfaangle, biggestfaangle;
27889 REAL total_tet_vol, total_tetprism_vol;
27890 REAL tetvol, minaltitude;
27891 REAL cirradius, minheightinv; // insradius;
27892 REAL shortlen, longlen;
27893 REAL tetaspect, tetradius;
27894 REAL smalldiangle, bigdiangle;
27895 REAL smallfaangle, bigfaangle;
27896 unsigned long radiustable[12];
27897 unsigned long aspecttable[16];
27898 unsigned long dihedangletable[18];
27899 unsigned long faceangletable[18];
27900 int indx[4];
27901 int radiusindex;
27902 int aspectindex;
27903 int tendegree;
27904 int i, j;
27905
27906 printf("Mesh quality statistics:\n\n");
27907
27908 shortlen = longlen = 0.0;
27909 smalldiangle = bigdiangle = 0.0;
27910 total_tet_vol = 0.0;
27911 total_tetprism_vol = 0.0;
27912
27913 radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0;
27914 radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2;
27915 radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6;
27916 radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0;
27917 radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0;
27918 radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0;
27919
27920 aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0;
27921 aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0;
27922 aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0;
27923 aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0;
27924 aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0;
27925 aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0;
27926
27927 for (i = 0; i < 12; i++) radiustable[i] = 0l;
27928 for (i = 0; i < 12; i++) aspecttable[i] = 0l;
27929 for (i = 0; i < 18; i++) dihedangletable[i] = 0l;
27930 for (i = 0; i < 18; i++) faceangletable[i] = 0l;
27931
27932 minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
27933 minaltitude = minaltitude * minaltitude;
27934 shortest = minaltitude;
27935 longest = 0.0;
27936 smallestvolume = minaltitude;
27937 biggestvolume = 0.0;
27938 smallestratio = 1e+16; // minaltitude;
27939 biggestratio = 0.0;
27940 smallestdiangle = smallestfaangle = 180.0;
27941 biggestdiangle = biggestfaangle = 0.0;
27942
27943
27944 int attrnum = numelemattrib - 1;
27945
27946 // Loop all elements, calculate quality parameters for each element.
27947 tetrahedrons->traversalinit();
27948 tetloop.tet = tetrahedrontraverse();
27949 while (tetloop.tet != (tetrahedron *) NULL) {
27950
27951 if (b->convex) {
27952 // Skip tets in the exterior.
27953 if (elemattribute(tetloop.tet, attrnum) == -1.0) {
27954 tetloop.tet = tetrahedrontraverse();
27955 continue;
27956 }
27957 }
27958
27959 // Get four vertices: p0, p1, p2, p3.
27960 for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
27961
27962 // Get the tet volume.
27963 tetvol = orient3dfast(p[1], p[0], p[2], p[3]) / 6.0;
27964 total_tet_vol += tetvol;
27965 total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
27966
27967 // Calculate the largest and smallest volume.
27968 if (tetvol < smallestvolume) {
27969 smallestvolume = tetvol;
27970 }
27971 if (tetvol > biggestvolume) {
27972 biggestvolume = tetvol;
27973 }
27974
27975 // Set the edge vectors: V[0], ..., V[5]
27976 for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
27977 for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
27978 for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
27979 for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
27980 for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
27981 for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
27982
27983 // Get the squares of the edge lengths.
27984 for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
27985
27986 // Calculate the longest and shortest edge length.
27987 for (i = 0; i < 6; i++) {
27988 if (i == 0) {
27989 shortlen = longlen = edgelength[i];
27990 } else {
27991 shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
27992 longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
27993 }
27994 if (edgelength[i] > longest) {
27995 longest = edgelength[i];
27996 }
27997 if (edgelength[i] < shortest) {
27998 shortest = edgelength[i];
27999 }
28000 }
28001
28002 // Set the matrix A = [V[0], V[1], V[2]]^T.
28003 for (j = 0; j < 3; j++) {
28004 for (i = 0; i < 3; i++) A[j][i] = V[j][i];
28005 }
28006
28007 // Decompose A just once.
28008 if (lu_decmp(A, 3, indx, &D, 0)) {
28009 // Get the three faces normals.
28010 for (j = 0; j < 3; j++) {
28011 for (i = 0; i < 3; i++) rhs[i] = 0.0;
28012 rhs[j] = 1.0; // Positive means the inside direction
28013 lu_solve(A, 3, indx, rhs, 0);
28014 for (i = 0; i < 3; i++) N[j][i] = rhs[i];
28015 }
28016 // Get the fourth face normal by summing up the first three.
28017 for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
28018 // Get the radius of the circumsphere.
28019 for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
28020 lu_solve(A, 3, indx, rhs, 0);
28021 cirradius = sqrt(dot(rhs, rhs));
28022 // Normalize the face normals.
28023 for (i = 0; i < 4; i++) {
28024 // H[i] is the inverse of height of its corresponding face.
28025 H[i] = sqrt(dot(N[i], N[i]));
28026 for (j = 0; j < 3; j++) N[i][j] /= H[i];
28027 }
28028 // Get the radius of the inscribed sphere.
28029 // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
28030 // Get the biggest H[i] (corresponding to the smallest height).
28031 minheightinv = H[0];
28032 for (i = 1; i < 3; i++) {
28033 if (H[i] > minheightinv) minheightinv = H[i];
28034 }
28035 } else {
28036 // A nearly degenerated tet.
28037 if (tetvol <= 0.0) {
28038 // assert(tetvol != 0.0);
28039 printf(" !! Warning: A %s tet (%d,%d,%d,%d).\n",
28040 tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
28041 pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
28042 // Skip it.
28043 tetloop.tet = tetrahedrontraverse();
28044 continue;
28045 }
28046 // Calculate the four face normals.
28047 facenormal(p[2], p[1], p[3], N[0], 1, NULL);
28048 facenormal(p[0], p[2], p[3], N[1], 1, NULL);
28049 facenormal(p[1], p[0], p[3], N[2], 1, NULL);
28050 facenormal(p[0], p[1], p[2], N[3], 1, NULL);
28051 // Normalize the face normals.
28052 for (i = 0; i < 4; i++) {
28053 // H[i] is the twice of the area of the face.
28054 H[i] = sqrt(dot(N[i], N[i]));
28055 for (j = 0; j < 3; j++) N[i][j] /= H[i];
28056 }
28057 // Get the biggest H[i] / tetvol (corresponding to the smallest height).
28058 minheightinv = (H[0] / tetvol);
28059 for (i = 1; i < 3; i++) {
28060 if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
28061 }
28062 // Let the circumradius to be the half of its longest edge length.
28063 cirradius = 0.5 * sqrt(longlen);
28064 }
28065
28066 // Get the dihedrals (in degree) at each edges.
28067 j = 0;
28068 for (i = 1; i < 4; i++) {
28069 alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
28070 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28071 else if (alldihed[j] > 1.0) alldihed[j] = 1;
28072 alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28073 j++;
28074 }
28075 for (i = 2; i < 4; i++) {
28076 alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
28077 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28078 else if (alldihed[j] > 1.0) alldihed[j] = 1;
28079 alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28080 j++;
28081 }
28082 alldihed[j] = -dot(N[2], N[3]); // Edge ab.
28083 if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28084 else if (alldihed[j] > 1.0) alldihed[j] = 1;
28085 alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28086
28087 // Calculate the largest and smallest dihedral angles.
28088 for (i = 0; i < 6; i++) {
28089 if (i == 0) {
28090 smalldiangle = bigdiangle = alldihed[i];
28091 } else {
28092 smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
28093 bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
28094 }
28095 if (alldihed[i] < smallestdiangle) {
28096 smallestdiangle = alldihed[i];
28097 }
28098 if (alldihed[i] > biggestdiangle) {
28099 biggestdiangle = alldihed[i];
28100 }
28101 // Accumulate the corresponding number in the dihedral angle histogram.
28102 if (alldihed[i] < 5.0) {
28103 tendegree = 0;
28104 } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
28105 tendegree = 1;
28106 } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
28107 tendegree = 9; // Angles between 80 to 110 degree are in one entry.
28108 } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
28109 tendegree = 16;
28110 } else if (alldihed[i] >= 175.0) {
28111 tendegree = 17;
28112 } else {
28113 tendegree = (int) (alldihed[i] / 10.);
28114 if (alldihed[i] < 80.0) {
28115 tendegree++; // In the left column.
28116 } else {
28117 tendegree--; // In the right column.
28118 }
28119 }
28120 dihedangletable[tendegree]++;
28121 }
28122
28123
28124
28125 // Calculate the largest and smallest face angles.
28126 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28127 fsym(tetloop, neightet);
28128 // Only do the calulation once for a face.
28129 if (((point) neightet.tet[7] == dummypoint) ||
28130 (tetloop.tet < neightet.tet)) {
28131 p[0] = org(tetloop);
28132 p[1] = dest(tetloop);
28133 p[2] = apex(tetloop);
28134 faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
28135 faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
28136 faceangle[2] = PI - (faceangle[0] + faceangle[1]);
28137 // Translate angles into degrees.
28138 for (i = 0; i < 3; i++) {
28139 faceangle[i] = (faceangle[i] * 180.0) / PI;
28140 }
28141 // Calculate the largest and smallest face angles.
28142 for (i = 0; i < 3; i++) {
28143 if (i == 0) {
28144 smallfaangle = bigfaangle = faceangle[i];
28145 } else {
28146 smallfaangle = faceangle[i] < smallfaangle ?
28147 faceangle[i] : smallfaangle;
28148 bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
28149 }
28150 if (faceangle[i] < smallestfaangle) {
28151 smallestfaangle = faceangle[i];
28152 }
28153 if (faceangle[i] > biggestfaangle) {
28154 biggestfaangle = faceangle[i];
28155 }
28156 tendegree = (int) (faceangle[i] / 10.);
28157 faceangletable[tendegree]++;
28158 }
28159 }
28160 }
28161
28162 // Calculate aspect ratio and radius-edge ratio for this element.
28163 tetradius = cirradius / sqrt(shortlen);
28164 // tetaspect = sqrt(longlen) / (2.0 * insradius);
28165 tetaspect = sqrt(longlen) * minheightinv;
28166 // Remember the largest and smallest aspect ratio.
28167 if (tetaspect < smallestratio) {
28168 smallestratio = tetaspect;
28169 }
28170 if (tetaspect > biggestratio) {
28171 biggestratio = tetaspect;
28172 }
28173 // Accumulate the corresponding number in the aspect ratio histogram.
28174 aspectindex = 0;
28175 while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
28176 aspectindex++;
28177 }
28178 aspecttable[aspectindex]++;
28179 radiusindex = 0;
28180 while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
28181 radiusindex++;
28182 }
28183 radiustable[radiusindex]++;
28184
28185 tetloop.tet = tetrahedrontraverse();
28186 }
28187
28188 shortest = sqrt(shortest);
28189 longest = sqrt(longest);
28190 minaltitude = sqrt(minaltitude);
28191
28192 printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n",
28193 smallestvolume, biggestvolume);
28194 printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
28195 shortest, longest);
28196 printf(" Smallest asp.ratio: %13.5g | Largest asp.ratio: %13.5g\n",
28197 smallestratio, biggestratio);
28198 sprintf(sbuf, "%.17g", biggestfaangle);
28199 if (strlen(sbuf) > 8) {
28200 sbuf[8] = '\0';
28201 }
28202 printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
28203 smallestfaangle, sbuf);
28204 sprintf(sbuf, "%.17g", biggestdiangle);
28205 if (strlen(sbuf) > 8) {
28206 sbuf[8] = '\0';
28207 }
28208 printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
28209 smallestdiangle, sbuf);
28210
28211 printf(" Aspect ratio histogram:\n");
28212 printf(" < %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
28213 aspectratiotable[0], aspecttable[0], aspectratiotable[5],
28214 aspectratiotable[6], aspecttable[6]);
28215 for (i = 1; i < 5; i++) {
28216 printf(" %6.6g - %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
28217 aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
28218 aspectratiotable[i + 5], aspectratiotable[i + 6],
28219 aspecttable[i + 6]);
28220 }
28221 printf(" %6.6g - %-6.6g : %8ld | %6.6g - : %8ld\n",
28222 aspectratiotable[4], aspectratiotable[5], aspecttable[5],
28223 aspectratiotable[10], aspecttable[11]);
28224 printf(" (A tetrahedron's aspect ratio is its longest edge length");
28225 printf(" divided by its\n");
28226 printf(" smallest side height)\n\n");
28227
28228 printf(" Face angle histogram:\n");
28229 for (i = 0; i < 9; i++) {
28230 printf(" %3d - %3d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28231 i * 10, i * 10 + 10, faceangletable[i],
28232 i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
28233 }
28234 if (minfaceang != PI) {
28235 printf(" Minimum input face angle is %g (degree).\n",
28236 minfaceang / PI * 180.0);
28237 }
28238 printf("\n");
28239
28240 printf(" Dihedral angle histogram:\n");
28241 // Print the three two rows:
28242 printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28243 0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
28244 printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28245 5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
28246 // Print the third to seventh rows.
28247 for (i = 2; i < 7; i++) {
28248 printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28249 (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
28250 (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
28251 }
28252 // Print the last two rows.
28253 printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28254 60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
28255 printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28256 70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
28257 if (minfacetdihed != PI) {
28258 printf(" Minimum input dihedral angle is %g (degree).\n",
28259 minfacetdihed / PI * 180.0);
28260 }
28261 printf("\n");
28262
28263 printf("\n");
28264}
28265
28266
28267///////////////////////////////////////////////////////////////////////////////
28268// //
28269// memorystatistics() Report the memory usage. //
28270// //
28271///////////////////////////////////////////////////////////////////////////////
28272
28273void tetgenmesh::memorystatistics()
28274{
28275 printf("Memory usage statistics:\n\n");
28276
28277 // Count the number of blocks of tetrahedra.
28278 int tetblocks = 0;
28279 tetrahedrons->pathblock = tetrahedrons->firstblock;
28280 while (tetrahedrons->pathblock != NULL) {
28281 tetblocks++;
28282 tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);
28283 }
28284
28285 // Calculate the total memory (in bytes) used by storing meshes.
28286 unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
28287 totalmeshmemory = points->maxitems * points->itembytes +
28288 tetrahedrons->maxitems * tetrahedrons->itembytes;
28289 if (b->plc || b->refine) {
28290 totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
28291 subsegs->maxitems * subsegs->itembytes);
28292 totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
28293 tet2segpool->maxitems * tet2segpool->itembytes);
28294 }
28295
28296 unsigned long totalalgomemory = 0l;
28297 totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
28298 caveoldtetlist->totalmemory +
28299 flippool->maxitems * flippool->itembytes;
28300 if (b->plc || b->refine) {
28301 totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
28302 subvertstack->totalmemory +
28303 caveshlist->totalmemory + caveshbdlist->totalmemory +
28304 cavesegshlist->totalmemory +
28305 cavetetshlist->totalmemory +
28306 cavetetseglist->totalmemory +
28307 caveencshlist->totalmemory +
28308 caveencseglist->totalmemory +
28309 cavetetvertlist->totalmemory +
28310 unflipqueue->totalmemory);
28311 }
28312
28313 printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
28314 printf(" Maximum number of tet blocks (blocksize = %d): %d\n",
28315 b->tetrahedraperblock, tetblocks);
28316 /*
28317 if (b->plc || b->refine) {
28318 printf(" Approximate memory for tetrahedral mesh (bytes): %ld\n",
28319 totalmeshmemory);
28320
28321 printf(" Approximate memory for extra pointers (bytes): %ld\n",
28322 totalt2shmemory);
28323 } else {
28324 printf(" Approximate memory for tetrahedralization (bytes): %ld\n",
28325 totalmeshmemory);
28326 }
28327 printf(" Approximate memory for algorithms (bytes): %ld\n",
28328 totalalgomemory);
28329 printf(" Approximate memory for working arrays (bytes): %ld\n",
28330 totalworkmemory);
28331 printf(" Approximate total used memory (bytes): %ld\n",
28332 totalmeshmemory + totalt2shmemory + totalalgomemory +
28333 totalworkmemory);
28334 */
28335 if (b->plc || b->refine) {
28336 printf(" Approximate memory for tetrahedral mesh (bytes): ");
28337 printfcomma(totalmeshmemory); printf("\n");
28338
28339 printf(" Approximate memory for extra pointers (bytes): ");
28340 printfcomma(totalt2shmemory); printf("\n");
28341 } else {
28342 printf(" Approximate memory for tetrahedralization (bytes): ");
28343 printfcomma(totalmeshmemory); printf("\n");
28344 }
28345 printf(" Approximate memory for algorithms (bytes): ");
28346 printfcomma(totalalgomemory); printf("\n");
28347 printf(" Approximate memory for working arrays (bytes): ");
28348 printfcomma(totalworkmemory); printf("\n");
28349 printf(" Approximate total used memory (bytes): ");
28350 printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory +
28351 totalworkmemory);
28352 printf("\n");
28353
28354 printf("\n");
28355}
28356
28357///////////////////////////////////////////////////////////////////////////////
28358// //
28359// statistics() Print all sorts of cool facts. //
28360// //
28361///////////////////////////////////////////////////////////////////////////////
28362
28363void tetgenmesh::statistics()
28364{
28365 long tetnumber, facenumber;
28366
28367 printf("\nStatistics:\n\n");
28368 printf(" Input points: %d\n", in->numberofpoints);
28369 if (b->refine) {
28370 printf(" Input tetrahedra: %d\n", in->numberoftetrahedra);
28371 }
28372 if (b->plc) {
28373 printf(" Input facets: %d\n", in->numberoffacets);
28374 printf(" Input segments: %ld\n", insegments);
28375 printf(" Input holes: %d\n", in->numberofholes);
28376 printf(" Input regions: %d\n", in->numberofregions);
28377 }
28378
28379 tetnumber = tetrahedrons->items - hullsize;
28380 facenumber = (tetnumber * 4l + hullsize) / 2l;
28381
28382 if (b->weighted) { // -w option
28383 printf("\n Mesh points: %ld\n", points->items - nonregularcount);
28384 } else {
28385 printf("\n Mesh points: %ld\n", points->items);
28386 }
28387 printf(" Mesh tetrahedra: %ld\n", tetnumber);
28388 printf(" Mesh faces: %ld\n", facenumber);
28389 if (meshedges > 0l) {
28390 printf(" Mesh edges: %ld\n", meshedges);
28391 } else {
28392 if (!nonconvex) {
28393 long vsize = points->items - dupverts - unuverts;
28394 if (b->weighted) vsize -= nonregularcount;
28395 meshedges = vsize + facenumber - tetnumber - 1;
28396 printf(" Mesh edges: %ld\n", meshedges);
28397 }
28398 }
28399
28400 if (b->plc || b->refine) {
28401 printf(" Mesh faces on facets: %ld\n", subfaces->items);
28402 printf(" Mesh edges on segments: %ld\n", subsegs->items);
28403 if (st_volref_count > 0l) {
28404 printf(" Steiner points inside domain: %ld\n", st_volref_count);
28405 }
28406 if (st_facref_count > 0l) {
28407 printf(" Steiner points on facets: %ld\n", st_facref_count);
28408 }
28409 if (st_segref_count > 0l) {
28410 printf(" Steiner points on segments: %ld\n", st_segref_count);
28411 }
28412 } else {
28413 printf(" Convex hull faces: %ld\n", hullsize);
28414 if (meshhulledges > 0l) {
28415 printf(" Convex hull edges: %ld\n", meshhulledges);
28416 }
28417 }
28418 if (b->weighted) { // -w option
28419 printf(" Skipped non-regular points: %ld\n", nonregularcount);
28420 }
28421 printf("\n");
28422
28423
28424 if (b->verbose > 0) {
28425 if (b->plc || b->refine) { // -p or -r
28426 if (tetrahedrons->items > 0l) {
28427 qualitystatistics();
28428 }
28429 }
28430 if (tetrahedrons->items > 0l) {
28431 memorystatistics();
28432 }
28433 }
28434}
28435
28436//// ////
28437//// ////
28438//// meshstat_cxx /////////////////////////////////////////////////////////////
28439
28440//// output_cxx ///////////////////////////////////////////////////////////////
28441//// ////
28442//// ////
28443
28444///////////////////////////////////////////////////////////////////////////////
28445// //
28446// jettisonnodes() Jettison unused or duplicated vertices. //
28447// //
28448// Unused points are those input points which are outside the mesh domain or //
28449// have no connection (isolated) to the mesh. Duplicated points exist for //
28450// example if the input PLC is read from a .stl mesh file (marked during the //
28451// Delaunay tetrahedralization step. This routine remove these points from //
28452// points list. All existing points are reindexed. //
28453// //
28454///////////////////////////////////////////////////////////////////////////////
28455
28456void tetgenmesh::jettisonnodes()
28457{
28458 point pointloop;
28459 bool jetflag;
28460 int oldidx, newidx;
28461 int remcount;
28462
28463 if (!b->quiet) {
28464 printf("Jettisoning redundant points.\n");
28465 }
28466
28467 points->traversalinit();
28468 pointloop = pointtraverse();
28469 oldidx = newidx = 0; // in->firstnumber;
28470 remcount = 0;
28471 while (pointloop != (point) NULL) {
28472 jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
28473 (pointtype(pointloop) == UNUSEDVERTEX);
28474 if (jetflag) {
28475 // It is a duplicated or unused point, delete it.
28476 pointdealloc(pointloop);
28477 remcount++;
28478 } else {
28479 // Re-index it.
28480 setpointmark(pointloop, newidx + in->firstnumber);
28481 if (in->pointmarkerlist != (int *) NULL) {
28482 if (oldidx < in->numberofpoints) {
28483 // Re-index the point marker as well.
28484 in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
28485 }
28486 }
28487 newidx++;
28488 }
28489 oldidx++;
28490 pointloop = pointtraverse();
28491 }
28492 if (b->verbose) {
28493 printf(" %ld duplicated vertices are removed.\n", dupverts);
28494 printf(" %ld unused vertices are removed.\n", unuverts);
28495 }
28496 dupverts = 0l;
28497 unuverts = 0l;
28498
28499 // The following line ensures that dead items in the pool of nodes cannot
28500 // be allocated for the new created nodes. This ensures that the input
28501 // nodes will occur earlier in the output files, and have lower indices.
28502 points->deaditemstack = (void *) NULL;
28503}
28504
28505///////////////////////////////////////////////////////////////////////////////
28506// //
28507// highorder() Create extra nodes for quadratic subparametric elements. //
28508// //
28509// 'highordertable' is an array (size = numberoftetrahedra * 6) for storing //
28510// high-order nodes of each tetrahedron. This routine is used only when -o2 //
28511// switch is used. //
28512// //
28513///////////////////////////////////////////////////////////////////////////////
28514
28515void tetgenmesh::highorder()
28516{
28517 triface tetloop, worktet, spintet;
28518 point *extralist, *adjextralist;
28519 point torg, tdest, newpoint;
28520 int highorderindex;
28521 int t1ver;
28522 int i, j;
28523
28524 if (!b->quiet) {
28525 printf("Adding vertices for second-order tetrahedra.\n");
28526 }
28527
28528 // Initialize the 'highordertable'.
28529 highordertable = new point[tetrahedrons->items * 6];
28530 if (highordertable == (point *) NULL) {
28531 terminatetetgen(this, 1);
28532 }
28533
28534 // This will overwrite the slot for element markers.
28535 highorderindex = 11;
28536
28537 // The following line ensures that dead items in the pool of nodes cannot
28538 // be allocated for the extra nodes associated with high order elements.
28539 // This ensures that the primary nodes (at the corners of elements) will
28540 // occur earlier in the output files, and have lower indices, than the
28541 // extra nodes.
28542 points->deaditemstack = (void *) NULL;
28543
28544 // Assign an entry for each tetrahedron to find its extra nodes. At the
28545 // mean while, initialize all extra nodes be NULL.
28546 i = 0;
28547 tetrahedrons->traversalinit();
28548 tetloop.tet = tetrahedrontraverse();
28549 while (tetloop.tet != (tetrahedron *) NULL) {
28550 tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
28551 for (j = 0; j < 6; j++) {
28552 highordertable[i + j] = (point) NULL;
28553 }
28554 i += 6;
28555 tetloop.tet = tetrahedrontraverse();
28556 }
28557
28558 // To create a unique node on each edge. Loop over all tetrahedra, and
28559 // look at the six edges of each tetrahedron. If the extra node in
28560 // the tetrahedron corresponding to this edge is NULL, create a node
28561 // for this edge, at the same time, set the new node into the extra
28562 // node lists of all other tetrahedra sharing this edge.
28563 tetrahedrons->traversalinit();
28564 tetloop.tet = tetrahedrontraverse();
28565 while (tetloop.tet != (tetrahedron *) NULL) {
28566 // Get the list of extra nodes.
28567 extralist = (point *) tetloop.tet[highorderindex];
28568 worktet.tet = tetloop.tet;
28569 for (i = 0; i < 6; i++) {
28570 if (extralist[i] == (point) NULL) {
28571 // Go to the ith-edge.
28572 worktet.ver = edge2ver[i];
28573 // Create a new point in the middle of this edge.
28574 torg = org(worktet);
28575 tdest = dest(worktet);
28576 makepoint(&newpoint, FREEVOLVERTEX);
28577 for (j = 0; j < 3 + numpointattrib; j++) {
28578 newpoint[j] = 0.5 * (torg[j] + tdest[j]);
28579 }
28580 // Interpolate its metrics.
28581 for (j = 0; j < in->numberofpointmtrs; j++) {
28582 newpoint[pointmtrindex + j] =
28583 0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
28584 }
28585 // Set this point into all extra node lists at this edge.
28586 spintet = worktet;
28587 while (1) {
28588 if (!ishulltet(spintet)) {
28589 adjextralist = (point *) spintet.tet[highorderindex];
28590 adjextralist[ver2edge[spintet.ver]] = newpoint;
28591 }
28592 fnextself(spintet);
28593 if (spintet.tet == worktet.tet) break;
28594 }
28595 } // if (!extralist[i])
28596 } // i
28597 tetloop.tet = tetrahedrontraverse();
28598 }
28599}
28600
28601///////////////////////////////////////////////////////////////////////////////
28602// //
28603// numberedges() Count the number of edges, save in "meshedges". //
28604// //
28605// This routine is called when '-p' or '-r', and '-E' options are used. The //
28606// total number of edges depends on the genus of the input surface mesh. //
28607// //
28608// NOTE: This routine must be called after outelements(). So all elements //
28609// have been indexed. //
28610// //
28611///////////////////////////////////////////////////////////////////////////////
28612
28613void tetgenmesh::numberedges()
28614{
28615 triface worktet, spintet;
28616 int ishulledge;
28617 int t1ver;
28618 int i;
28619
28620 meshedges = meshhulledges = 0l;
28621
28622 tetrahedrons->traversalinit();
28623 worktet.tet = tetrahedrontraverse();
28624 while (worktet.tet != NULL) {
28625 // Count the number of Voronoi faces. Look at the six edges of this
28626 // tet. Count an edge only if this tet's index is smaller than
28627 // those of other non-hull tets which share this edge.
28628 for (i = 0; i < 6; i++) {
28629 worktet.ver = edge2ver[i];
28630 ishulledge = 0;
28631 fnext(worktet, spintet);
28632 do {
28633 if (!ishulltet(spintet)) {
28634 if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
28635 } else {
28636 ishulledge = 1;
28637 }
28638 fnextself(spintet);
28639 } while (spintet.tet != worktet.tet);
28640 // Count this edge if no adjacent tets are smaller than this tet.
28641 if (spintet.tet == worktet.tet) {
28642 meshedges++;
28643 if (ishulledge) meshhulledges++;
28644 }
28645 }
28646 worktet.tet = tetrahedrontraverse();
28647 }
28648}
28649
28650///////////////////////////////////////////////////////////////////////////////
28651// //
28652// outnodes() Output the points to a .node file or a tetgenio structure. //
28653// //
28654// Note: each point has already been numbered on input (the first index is //
28655// 'in->firstnumber'). //
28656// //
28657///////////////////////////////////////////////////////////////////////////////
28658
28659void tetgenmesh::outnodes(tetgenio* out)
28660{
28661 FILE *outfile = NULL;
28662 char outnodefilename[FILENAMESIZE];
28663 face parentsh;
28664 point pointloop;
28665 int nextras, bmark, marker = 0, weightDT = 0;
28666 int coordindex, attribindex;
28667 int pointnumber, firstindex;
28668 int index, i;
28669
28670 if (out == (tetgenio *) NULL) {
28671 strcpy(outnodefilename, b->outfilename);
28672 strcat(outnodefilename, ".node");
28673 }
28674
28675 if (!b->quiet) {
28676 if (out == (tetgenio *) NULL) {
28677 printf("Writing %s.\n", outnodefilename);
28678 } else {
28679 printf("Writing nodes.\n");
28680 }
28681 }
28682
28683 nextras = numpointattrib;
28684 if (b->weighted) { // -w
28685 if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
28686 }
28687
28688 bmark = !b->nobound && in->pointmarkerlist;
28689
28690 if (out == (tetgenio *) NULL) {
28691 outfile = fopen(outnodefilename, "w");
28692 if (outfile == (FILE *) NULL) {
28693 printf("File I/O Error: Cannot create file %s.\n", outnodefilename);
28694 terminatetetgen(this, 1);
28695 }
28696 // Number of points, number of dimensions, number of point attributes,
28697 // and number of boundary markers (zero or one).
28698 fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark);
28699 } else {
28700 // Allocate space for 'pointlist';
28701 out->pointlist = new REAL[points->items * 3];
28702 if (out->pointlist == (REAL *) NULL) {
28703 printf("Error: Out of memory.\n");
28704 terminatetetgen(this, 1);
28705 }
28706 // Allocate space for 'pointattributelist' if necessary;
28707 if (nextras > 0) {
28708 out->pointattributelist = new REAL[points->items * nextras];
28709 if (out->pointattributelist == (REAL *) NULL) {
28710 printf("Error: Out of memory.\n");
28711 terminatetetgen(this, 1);
28712 }
28713 }
28714 // Allocate space for 'pointmarkerlist' if necessary;
28715 if (bmark) {
28716 out->pointmarkerlist = new int[points->items];
28717 if (out->pointmarkerlist == (int *) NULL) {
28718 printf("Error: Out of memory.\n");
28719 terminatetetgen(this, 1);
28720 }
28721 }
28722 if (b->psc) {
28723 out->pointparamlist = new tetgenio::pointparam[points->items];
28724 if (out->pointparamlist == NULL) {
28725 printf("Error: Out of memory.\n");
28726 terminatetetgen(this, 1);
28727 }
28728 }
28729 out->numberofpoints = points->items;
28730 out->numberofpointattributes = nextras;
28731 coordindex = 0;
28732 attribindex = 0;
28733 }
28734
28735 // Determine the first index (0 or 1).
28736 firstindex = b->zeroindex ? 0 : in->firstnumber;
28737
28738 points->traversalinit();
28739 pointloop = pointtraverse();
28740 pointnumber = firstindex; // in->firstnumber;
28741 index = 0;
28742 while (pointloop != (point) NULL) {
28743 if (bmark) {
28744 // Default the vertex has a zero marker.
28745 marker = 0;
28746 // Is it an input vertex?
28747 if (index < in->numberofpoints) {
28748 // Input point's marker is directly copied to output.
28749 marker = in->pointmarkerlist[index];
28750 } else {
28751 if ((pointtype(pointloop) == FREESEGVERTEX) ||
28752 (pointtype(pointloop) == FREEFACETVERTEX)) {
28753 sdecode(point2sh(pointloop), parentsh);
28754 if (parentsh.sh != NULL) {
28755 marker = shellmark(parentsh);
28756 if (pointtype(pointloop) == FREEFACETVERTEX) {
28757 if (in->facetmarkerlist != NULL) {
28758 marker = in->facetmarkerlist[marker - 1];
28759 }
28760 }
28761 }
28762 } // if (pointtype(...))
28763 }
28764 }
28765 if (out == (tetgenio *) NULL) {
28766 // Point number, x, y and z coordinates.
28767 fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
28768 pointloop[0], pointloop[1], pointloop[2]);
28769 for (i = 0; i < nextras; i++) {
28770 // Write an attribute.
28771 if ((i == 0) && weightDT) {
28772 fprintf(outfile, " %.17g", pointloop[0] * pointloop[0] +
28773 pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2]
28774 - pointloop[3 + i]);
28775 } else {
28776 fprintf(outfile, " %.17g", pointloop[3 + i]);
28777 }
28778 }
28779 if (bmark) {
28780 // Write the boundary marker.
28781 fprintf(outfile, " %d", marker);
28782 }
28783 if (b->psc) {
28784 fprintf(outfile, " %.8g %.8g %d", pointgeomuv(pointloop, 0),
28785 pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
28786 if (pointtype(pointloop) == RIDGEVERTEX) {
28787 fprintf(outfile, " 0");
28788 } else if (pointtype(pointloop) == ACUTEVERTEX) {
28789 fprintf(outfile, " 0");
28790 } else if (pointtype(pointloop) == FREESEGVERTEX) {
28791 fprintf(outfile, " 1");
28792 } else if (pointtype(pointloop) == FREEFACETVERTEX) {
28793 fprintf(outfile, " 2");
28794 } else if (pointtype(pointloop) == FREEVOLVERTEX) {
28795 fprintf(outfile, " 3");
28796 } else {
28797 fprintf(outfile, " -1"); // Unknown type.
28798 }
28799 }
28800 fprintf(outfile, "\n");
28801 } else {
28802 // X, y, and z coordinates.
28803 out->pointlist[coordindex++] = pointloop[0];
28804 out->pointlist[coordindex++] = pointloop[1];
28805 out->pointlist[coordindex++] = pointloop[2];
28806 // Point attributes.
28807 for (i = 0; i < nextras; i++) {
28808 // Output an attribute.
28809 if ((i == 0) && weightDT) {
28810 out->pointattributelist[attribindex++] =
28811 pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] +
28812 pointloop[2] * pointloop[2] - pointloop[3 + i];
28813 } else {
28814 out->pointattributelist[attribindex++] = pointloop[3 + i];
28815 }
28816 }
28817 if (bmark) {
28818 // Output the boundary marker.
28819 out->pointmarkerlist[index] = marker;
28820 }
28821 if (b->psc) {
28822 out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
28823 out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
28824 out->pointparamlist[index].tag = pointgeomtag(pointloop);
28825 if (pointtype(pointloop) == RIDGEVERTEX) {
28826 out->pointparamlist[index].type = 0;
28827 } else if (pointtype(pointloop) == ACUTEVERTEX) {
28828 out->pointparamlist[index].type = 0;
28829 } else if (pointtype(pointloop) == FREESEGVERTEX) {
28830 out->pointparamlist[index].type = 1;
28831 } else if (pointtype(pointloop) == FREEFACETVERTEX) {
28832 out->pointparamlist[index].type = 2;
28833 } else if (pointtype(pointloop) == FREEVOLVERTEX) {
28834 out->pointparamlist[index].type = 3;
28835 } else {
28836 out->pointparamlist[index].type = -1; // Unknown type.
28837 }
28838 }
28839 }
28840 pointloop = pointtraverse();
28841 pointnumber++;
28842 index++;
28843 }
28844
28845 if (out == (tetgenio *) NULL) {
28846 fprintf(outfile, "# Generated by %s\n", b->commandline);
28847 fclose(outfile);
28848 }
28849}
28850
28851///////////////////////////////////////////////////////////////////////////////
28852// //
28853// outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. //
28854// //
28855///////////////////////////////////////////////////////////////////////////////
28856
28857void tetgenmesh::outmetrics(tetgenio* out)
28858{
28859 FILE *outfile = NULL;
28860 char outmtrfilename[FILENAMESIZE];
28861 point ptloop;
28862 int mtrindex;
28863
28864 if (out == (tetgenio *) NULL) {
28865 strcpy(outmtrfilename, b->outfilename);
28866 strcat(outmtrfilename, ".mtr");
28867 }
28868
28869 if (!b->quiet) {
28870 if (out == (tetgenio *) NULL) {
28871 printf("Writing %s.\n", outmtrfilename);
28872 } else {
28873 printf("Writing metrics.\n");
28874 }
28875 }
28876
28877 if (out == (tetgenio *) NULL) {
28878 outfile = fopen(outmtrfilename, "w");
28879 if (outfile == (FILE *) NULL) {
28880 printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
28881 terminatetetgen(this, 3);
28882 }
28883 // Number of points, number of point metrices,
28884 // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3);
28885 fprintf(outfile, "%ld %d\n", points->items, 1);
28886 } else {
28887 // Allocate space for 'pointmtrlist' if necessary;
28888 // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
28889 out->pointmtrlist = new REAL[points->items];
28890 if (out->pointmtrlist == (REAL *) NULL) {
28891 terminatetetgen(this, 1);
28892 }
28893 out->numberofpointmtrs = 1; // (sizeoftensor + 3);
28894 mtrindex = 0;
28895 }
28896
28897 points->traversalinit();
28898 ptloop = pointtraverse();
28899 while (ptloop != (point) NULL) {
28900 if (out == (tetgenio *) NULL) {
28901 // for (i = 0; i < sizeoftensor; i++) {
28902 // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
28903 // }
28904 fprintf(outfile, "%-16.8e\n", ptloop[pointmtrindex]);
28905 } else {
28906 // for (i = 0; i < sizeoftensor; i++) {
28907 // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
28908 // }
28909 out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex];
28910 }
28911 ptloop = pointtraverse();
28912 }
28913
28914 if (out == (tetgenio *) NULL) {
28915 fprintf(outfile, "# Generated by %s\n", b->commandline);
28916 fclose(outfile);
28917 }
28918}
28919
28920///////////////////////////////////////////////////////////////////////////////
28921// //
28922// outelements() Output the tetrahedra to an .ele file or a tetgenio //
28923// structure. //
28924// //
28925// This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
28926// firstnumber). The total number of mesh edges is counted in 'meshedges'. //
28927// //
28928///////////////////////////////////////////////////////////////////////////////
28929
28930void tetgenmesh::outelements(tetgenio* out)
28931{
28932 FILE *outfile = NULL;
28933 char outelefilename[FILENAMESIZE];
28934 tetrahedron* tptr;
28935 point p1, p2, p3, p4;
28936 point *extralist;
28937 REAL *talist = NULL;
28938 int *tlist = NULL;
28939 long ntets;
28940 int firstindex, shift;
28941 int pointindex, attribindex;
28942 int highorderindex = 11;
28943 int elementnumber;
28944 int eextras;
28945 int i;
28946
28947 if (out == (tetgenio *) NULL) {
28948 strcpy(outelefilename, b->outfilename);
28949 strcat(outelefilename, ".ele");
28950 }
28951
28952 if (!b->quiet) {
28953 if (out == (tetgenio *) NULL) {
28954 printf("Writing %s.\n", outelefilename);
28955 } else {
28956 printf("Writing elements.\n");
28957 }
28958 }
28959
28960 // The number of tets excluding hull tets.
28961 ntets = tetrahedrons->items - hullsize;
28962
28963 eextras = numelemattrib;
28964 if (out == (tetgenio *) NULL) {
28965 outfile = fopen(outelefilename, "w");
28966 if (outfile == (FILE *) NULL) {
28967 printf("File I/O Error: Cannot create file %s.\n", outelefilename);
28968 terminatetetgen(this, 1);
28969 }
28970 // Number of tetras, points per tetra, attributes per tetra.
28971 fprintf(outfile, "%ld %d %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
28972 } else {
28973 // Allocate memory for output tetrahedra.
28974 out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
28975 if (out->tetrahedronlist == (int *) NULL) {
28976 printf("Error: Out of memory.\n");
28977 terminatetetgen(this, 1);
28978 }
28979 // Allocate memory for output tetrahedron attributes if necessary.
28980 if (eextras > 0) {
28981 out->tetrahedronattributelist = new REAL[ntets * eextras];
28982 if (out->tetrahedronattributelist == (REAL *) NULL) {
28983 printf("Error: Out of memory.\n");
28984 terminatetetgen(this, 1);
28985 }
28986 }
28987 out->numberoftetrahedra = ntets;
28988 out->numberofcorners = b->order == 1 ? 4 : 10;
28989 out->numberoftetrahedronattributes = eextras;
28990 tlist = out->tetrahedronlist;
28991 talist = out->tetrahedronattributelist;
28992 pointindex = 0;
28993 attribindex = 0;
28994 }
28995
28996 // Determine the first index (0 or 1).
28997 firstindex = b->zeroindex ? 0 : in->firstnumber;
28998 shift = 0; // Default no shift.
28999 if ((in->firstnumber == 1) && (firstindex == 0)) {
29000 shift = 1; // Shift the output indices by 1.
29001 }
29002
29003 tetrahedrons->traversalinit();
29004 tptr = tetrahedrontraverse();
29005 elementnumber = firstindex; // in->firstnumber;
29006 while (tptr != (tetrahedron *) NULL) {
29007 if (!b->reversetetori) {
29008 p1 = (point) tptr[4];
29009 p2 = (point) tptr[5];
29010 } else {
29011 p1 = (point) tptr[5];
29012 p2 = (point) tptr[4];
29013 }
29014 p3 = (point) tptr[6];
29015 p4 = (point) tptr[7];
29016 if (out == (tetgenio *) NULL) {
29017 // Tetrahedron number, indices for four points.
29018 fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
29019 pointmark(p1) - shift, pointmark(p2) - shift,
29020 pointmark(p3) - shift, pointmark(p4) - shift);
29021 if (b->order == 2) {
29022 extralist = (point *) tptr[highorderindex];
29023 // indices for six extra points.
29024 fprintf(outfile, " %5d %5d %5d %5d %5d %5d",
29025 pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
29026 pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
29027 pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
29028 }
29029 for (i = 0; i < eextras; i++) {
29030 fprintf(outfile, " %.17g", elemattribute(tptr, i));
29031 }
29032 fprintf(outfile, "\n");
29033 } else {
29034 tlist[pointindex++] = pointmark(p1) - shift;
29035 tlist[pointindex++] = pointmark(p2) - shift;
29036 tlist[pointindex++] = pointmark(p3) - shift;
29037 tlist[pointindex++] = pointmark(p4) - shift;
29038 if (b->order == 2) {
29039 extralist = (point *) tptr[highorderindex];
29040 tlist[pointindex++] = pointmark(extralist[0]) - shift;
29041 tlist[pointindex++] = pointmark(extralist[1]) - shift;
29042 tlist[pointindex++] = pointmark(extralist[2]) - shift;
29043 tlist[pointindex++] = pointmark(extralist[3]) - shift;
29044 tlist[pointindex++] = pointmark(extralist[4]) - shift;
29045 tlist[pointindex++] = pointmark(extralist[5]) - shift;
29046 }
29047 for (i = 0; i < eextras; i++) {
29048 talist[attribindex++] = elemattribute(tptr, i);
29049 }
29050 }
29051 // Remember the index of this element (for counting edges).
29052 setelemindex(tptr, elementnumber);
29053 tptr = tetrahedrontraverse();
29054 elementnumber++;
29055 }
29056
29057
29058 if (out == (tetgenio *) NULL) {
29059 fprintf(outfile, "# Generated by %s\n", b->commandline);
29060 fclose(outfile);
29061 }
29062}
29063
29064///////////////////////////////////////////////////////////////////////////////
29065// //
29066// outfaces() Output all faces to a .face file or a tetgenio object. //
29067// //
29068///////////////////////////////////////////////////////////////////////////////
29069
29070void tetgenmesh::outfaces(tetgenio* out)
29071{
29072 FILE *outfile = NULL;
29073 char facefilename[FILENAMESIZE];
29074 triface tface, tsymface;
29075 face checkmark;
29076 point torg, tdest, tapex;
29077 long ntets, faces;
29078 int *elist = NULL, *emlist = NULL;
29079 int neigh1 = 0, neigh2 = 0;
29080 int faceid, marker = 0;
29081 int firstindex, shift;
29082 int facenumber;
29083 int index = 0;
29084
29085 // For -o2 option.
29086 triface workface;
29087 point *extralist, pp[3] = {0,0,0};
29088 int highorderindex = 11;
29089 int o2index = 0, i;
29090
29091 if (out == (tetgenio *) NULL) {
29092 strcpy(facefilename, b->outfilename);
29093 strcat(facefilename, ".face");
29094 }
29095
29096 if (!b->quiet) {
29097 if (out == (tetgenio *) NULL) {
29098 printf("Writing %s.\n", facefilename);
29099 } else {
29100 printf("Writing faces.\n");
29101 }
29102 }
29103
29104 ntets = tetrahedrons->items - hullsize;
29105 faces = (ntets * 4l + hullsize) / 2l;
29106
29107 if (out == (tetgenio *) NULL) {
29108 outfile = fopen(facefilename, "w");
29109 if (outfile == (FILE *) NULL) {
29110 printf("File I/O Error: Cannot create file %s.\n", facefilename);
29111 terminatetetgen(this, 1);
29112 }
29113 fprintf(outfile, "%ld %d\n", faces, !b->nobound);
29114 } else {
29115 // Allocate memory for 'trifacelist'.
29116 out->trifacelist = new int[faces * 3];
29117 if (out->trifacelist == (int *) NULL) {
29118 printf("Error: Out of memory.\n");
29119 terminatetetgen(this, 1);
29120 }
29121 if (b->order == 2) {
29122 out->o2facelist = new int[faces * 3];
29123 }
29124 // Allocate memory for 'trifacemarkerlist' if necessary.
29125 if (!b->nobound) {
29126 out->trifacemarkerlist = new int[faces];
29127 if (out->trifacemarkerlist == (int *) NULL) {
29128 printf("Error: Out of memory.\n");
29129 terminatetetgen(this, 1);
29130 }
29131 }
29132 if (b->neighout > 1) {
29133 // '-nn' switch.
29134 out->adjtetlist = new int[faces * 2];
29135 if (out->adjtetlist == (int *) NULL) {
29136 printf("Error: Out of memory.\n");
29137 terminatetetgen(this, 1);
29138 }
29139 }
29140 out->numberoftrifaces = faces;
29141 elist = out->trifacelist;
29142 emlist = out->trifacemarkerlist;
29143 }
29144
29145 // Determine the first index (0 or 1).
29146 firstindex = b->zeroindex ? 0 : in->firstnumber;
29147 shift = 0; // Default no shiftment.
29148 if ((in->firstnumber == 1) && (firstindex == 0)) {
29149 shift = 1; // Shift the output indices by 1.
29150 }
29151
29152 tetrahedrons->traversalinit();
29153 tface.tet = tetrahedrontraverse();
29154 facenumber = firstindex; // in->firstnumber;
29155 // To loop over the set of faces, loop over all tetrahedra, and look at
29156 // the four faces of each one. If its adjacent tet is a hull tet,
29157 // operate on the face, otherwise, operate on the face only if the
29158 // current tet has a smaller index than its neighbor.
29159 while (tface.tet != (tetrahedron *) NULL) {
29160 for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
29161 fsym(tface, tsymface);
29162 if (ishulltet(tsymface) ||
29163 (elemindex(tface.tet) < elemindex(tsymface.tet))) {
29164 torg = org(tface);
29165 tdest = dest(tface);
29166 tapex = apex(tface);
29167 if (b->order == 2) { // -o2
29168 // Get the three extra vertices on edges.
29169 extralist = (point *) (tface.tet[highorderindex]);
29170 // The extra vertices are on edges opposite the corners.
29171 enext(tface, workface);
29172 for (i = 0; i < 3; i++) {
29173 pp[i] = extralist[ver2edge[workface.ver]];
29174 enextself(workface);
29175 }
29176 }
29177 if (!b->nobound) {
29178 // Get the boundary marker of this face.
29179 if (b->plc || b->refine) {
29180 // Shell face is used.
29181 tspivot(tface, checkmark);
29182 if (checkmark.sh == NULL) {
29183 marker = 0; // It is an inner face. It's marker is 0.
29184 } else {
29185 if (in->facetmarkerlist) {
29186 // The facet marker is given, get it.
29187 faceid = shellmark(checkmark) - 1;
29188 marker = in->facetmarkerlist[faceid];
29189 } else {
29190 marker = 1; // The default marker for subface is 1.
29191 }
29192 }
29193 } else {
29194 // Shell face is not used, only distinguish outer and inner face.
29195 marker = (int) ishulltet(tsymface);
29196 }
29197 }
29198 if (b->neighout > 1) {
29199 // '-nn' switch. Output adjacent tets indices.
29200 neigh1 = elemindex(tface.tet);
29201 if (!ishulltet(tsymface)) {
29202 neigh2 = elemindex(tsymface.tet);
29203 } else {
29204 neigh2 = -1;
29205 }
29206 }
29207 if (out == (tetgenio *) NULL) {
29208 // Face number, indices of three vertices.
29209 fprintf(outfile, "%5d %4d %4d %4d", facenumber,
29210 pointmark(torg) - shift, pointmark(tdest) - shift,
29211 pointmark(tapex) - shift);
29212 if (b->order == 2) { // -o2
29213 fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
29214 pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
29215 }
29216 if (!b->nobound) {
29217 // Output a boundary marker.
29218 fprintf(outfile, " %d", marker);
29219 }
29220 if (b->neighout > 1) {
29221 fprintf(outfile, " %5d %5d", neigh1, neigh2);
29222 }
29223 fprintf(outfile, "\n");
29224 } else {
29225 // Output indices of three vertices.
29226 elist[index++] = pointmark(torg) - shift;
29227 elist[index++] = pointmark(tdest) - shift;
29228 elist[index++] = pointmark(tapex) - shift;
29229 if (b->order == 2) { // -o2
29230 out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
29231 out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
29232 out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
29233 }
29234 if (!b->nobound) {
29235 emlist[facenumber - in->firstnumber] = marker;
29236 }
29237 if (b->neighout > 1) {
29238 out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1;
29239 out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
29240 }
29241 }
29242 facenumber++;
29243 }
29244 }
29245 tface.tet = tetrahedrontraverse();
29246 }
29247
29248 if (out == (tetgenio *) NULL) {
29249 fprintf(outfile, "# Generated by %s\n", b->commandline);
29250 fclose(outfile);
29251 }
29252}
29253
29254///////////////////////////////////////////////////////////////////////////////
29255// //
29256// outhullfaces() Output hull faces to a .face file or a tetgenio object. //
29257// //
29258// The normal of each face is pointing to the outside of the domain. //
29259// //
29260///////////////////////////////////////////////////////////////////////////////
29261
29262void tetgenmesh::outhullfaces(tetgenio* out)
29263{
29264 FILE *outfile = NULL;
29265 char facefilename[FILENAMESIZE];
29266 triface hulltet;
29267 point torg, tdest, tapex;
29268 int *elist = NULL;
29269 int firstindex, shift;
29270 int facenumber;
29271 int index;
29272
29273 if (out == (tetgenio *) NULL) {
29274 strcpy(facefilename, b->outfilename);
29275 strcat(facefilename, ".face");
29276 }
29277
29278 if (!b->quiet) {
29279 if (out == (tetgenio *) NULL) {
29280 printf("Writing %s.\n", facefilename);
29281 } else {
29282 printf("Writing faces.\n");
29283 }
29284 }
29285
29286 if (out == (tetgenio *) NULL) {
29287 outfile = fopen(facefilename, "w");
29288 if (outfile == (FILE *) NULL) {
29289 printf("File I/O Error: Cannot create file %s.\n", facefilename);
29290 terminatetetgen(this, 1);
29291 }
29292 fprintf(outfile, "%ld 0\n", hullsize);
29293 } else {
29294 // Allocate memory for 'trifacelist'.
29295 out->trifacelist = new int[hullsize * 3];
29296 if (out->trifacelist == (int *) NULL) {
29297 printf("Error: Out of memory.\n");
29298 terminatetetgen(this, 1);
29299 }
29300 out->numberoftrifaces = hullsize;
29301 elist = out->trifacelist;
29302 index = 0;
29303 }
29304
29305 // Determine the first index (0 or 1).
29306 firstindex = b->zeroindex ? 0 : in->firstnumber;
29307 shift = 0; // Default no shiftment.
29308 if ((in->firstnumber == 1) && (firstindex == 0)) {
29309 shift = 1; // Shift the output indices by 1.
29310 }
29311
29312 tetrahedrons->traversalinit();
29313 hulltet.tet = alltetrahedrontraverse();
29314 facenumber = firstindex;
29315 while (hulltet.tet != (tetrahedron *) NULL) {
29316 if (ishulltet(hulltet)) {
29317 torg = (point) hulltet.tet[4];
29318 tdest = (point) hulltet.tet[5];
29319 tapex = (point) hulltet.tet[6];
29320 if (out == (tetgenio *) NULL) {
29321 // Face number, indices of three vertices.
29322 fprintf(outfile, "%5d %4d %4d %4d", facenumber,
29323 pointmark(torg) - shift, pointmark(tdest) - shift,
29324 pointmark(tapex) - shift);
29325 fprintf(outfile, "\n");
29326 } else {
29327 // Output indices of three vertices.
29328 elist[index++] = pointmark(torg) - shift;
29329 elist[index++] = pointmark(tdest) - shift;
29330 elist[index++] = pointmark(tapex) - shift;
29331 }
29332 facenumber++;
29333 }
29334 hulltet.tet = alltetrahedrontraverse();
29335 }
29336
29337 if (out == (tetgenio *) NULL) {
29338 fprintf(outfile, "# Generated by %s\n", b->commandline);
29339 fclose(outfile);
29340 }
29341}
29342
29343///////////////////////////////////////////////////////////////////////////////
29344// //
29345// outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or //
29346// a tetgenio structure. //
29347// //
29348// The boundary faces are found in 'subfaces'. For listing triangle vertices //
29349// in the same sense for all triangles in the mesh, the direction determined //
29350// by right-hand rule is pointer to the inside of the volume. //
29351// //
29352///////////////////////////////////////////////////////////////////////////////
29353
29354void tetgenmesh::outsubfaces(tetgenio* out)
29355{
29356 FILE *outfile = NULL;
29357 char facefilename[FILENAMESIZE];
29358 int *elist = NULL;
29359 int *emlist = NULL;
29360 int index = 0, index1 = 0, index2 = 0;
29361 triface abuttingtet;
29362 face faceloop;
29363 point torg, tdest, tapex;
29364 int faceid = 0, marker = 0;
29365 int firstindex, shift;
29366 int neigh1 = 0, neigh2 = 0;
29367 int facenumber;
29368
29369 // For -o2 option.
29370 triface workface;
29371 point *extralist, pp[3] = {0,0,0};
29372 int highorderindex = 11;
29373 int o2index = 0, i;
29374
29375 int t1ver; // used by fsymself()
29376
29377 if (out == (tetgenio *) NULL) {
29378 strcpy(facefilename, b->outfilename);
29379 strcat(facefilename, ".face");
29380 }
29381
29382 if (!b->quiet) {
29383 if (out == (tetgenio *) NULL) {
29384 printf("Writing %s.\n", facefilename);
29385 } else {
29386 printf("Writing faces.\n");
29387 }
29388 }
29389
29390 if (out == (tetgenio *) NULL) {
29391 outfile = fopen(facefilename, "w");
29392 if (outfile == (FILE *) NULL) {
29393 printf("File I/O Error: Cannot create file %s.\n", facefilename);
29394 terminatetetgen(this, 3);
29395 }
29396 // Number of subfaces.
29397 fprintf(outfile, "%ld %d\n", subfaces->items, !b->nobound);
29398 } else {
29399 // Allocate memory for 'trifacelist'.
29400 out->trifacelist = new int[subfaces->items * 3];
29401 if (out->trifacelist == (int *) NULL) {
29402 terminatetetgen(this, 1);
29403 }
29404 if (b->order == 2) {
29405 out->o2facelist = new int[subfaces->items * 3];
29406 }
29407 if (!b->nobound) {
29408 // Allocate memory for 'trifacemarkerlist'.
29409 out->trifacemarkerlist = new int[subfaces->items];
29410 if (out->trifacemarkerlist == (int *) NULL) {
29411 terminatetetgen(this, 1);
29412 }
29413 }
29414 if (b->neighout > 1) {
29415 // '-nn' switch.
29416 out->adjtetlist = new int[subfaces->items * 2];
29417 if (out->adjtetlist == (int *) NULL) {
29418 terminatetetgen(this, 1);
29419 }
29420 }
29421 out->numberoftrifaces = subfaces->items;
29422 elist = out->trifacelist;
29423 emlist = out->trifacemarkerlist;
29424 }
29425
29426 // Determine the first index (0 or 1).
29427 firstindex = b->zeroindex ? 0 : in->firstnumber;
29428 shift = 0; // Default no shiftment.
29429 if ((in->firstnumber == 1) && (firstindex == 0)) {
29430 shift = 1; // Shift the output indices by 1.
29431 }
29432
29433 subfaces->traversalinit();
29434 faceloop.sh = shellfacetraverse(subfaces);
29435 facenumber = firstindex; // in->firstnumber;
29436 while (faceloop.sh != (shellface *) NULL) {
29437 stpivot(faceloop, abuttingtet);
29438 // If there is a tetrahedron containing this subface, orient it so
29439 // that the normal of this face points to inside of the volume by
29440 // right-hand rule.
29441 if (abuttingtet.tet != NULL) {
29442 if (ishulltet(abuttingtet)) {
29443 fsymself(abuttingtet);
29444 assert(!ishulltet(abuttingtet));
29445 }
29446 }
29447 if (abuttingtet.tet != NULL) {
29448 torg = org(abuttingtet);
29449 tdest = dest(abuttingtet);
29450 tapex = apex(abuttingtet);
29451 if (b->order == 2) { // -o2
29452 // Get the three extra vertices on edges.
29453 extralist = (point *) (abuttingtet.tet[highorderindex]);
29454 workface = abuttingtet;
29455 for (i = 0; i < 3; i++) {
29456 pp[i] = extralist[ver2edge[workface.ver]];
29457 enextself(workface);
29458 }
29459 }
29460 } else {
29461 // This may happen when only a surface mesh be generated.
29462 torg = sorg(faceloop);
29463 tdest = sdest(faceloop);
29464 tapex = sapex(faceloop);
29465 if (b->order == 2) { // -o2
29466 // There is no extra node list available.
29467 pp[0] = torg;
29468 pp[1] = tdest;
29469 pp[2] = tapex;
29470 }
29471 }
29472 if (!b->nobound) {
29473 if (b->refine) { // -r option.
29474 if (in->trifacemarkerlist) {
29475 marker = shellmark(faceloop);
29476 } else {
29477 marker = 1; // Default marker for a subface is 1.
29478 }
29479 } else {
29480 if (in->facetmarkerlist) {
29481 faceid = shellmark(faceloop) - 1;
29482 marker = in->facetmarkerlist[faceid];
29483 } else {
29484 marker = 1; // Default marker for a subface is 1.
29485 }
29486 }
29487 }
29488 if (b->neighout > 1) {
29489 // '-nn' switch. Output adjacent tets indices.
29490 neigh1 = -1;
29491 neigh2 = -1;
29492 stpivot(faceloop, abuttingtet);
29493 if (abuttingtet.tet != NULL) {
29494 neigh1 = elemindex(abuttingtet.tet);
29495 fsymself(abuttingtet);
29496 if (!ishulltet(abuttingtet)) {
29497 neigh2 = elemindex(abuttingtet.tet);
29498 }
29499 }
29500 }
29501 if (out == (tetgenio *) NULL) {
29502 fprintf(outfile, "%5d %4d %4d %4d", facenumber,
29503 pointmark(torg) - shift, pointmark(tdest) - shift,
29504 pointmark(tapex) - shift);
29505 if (b->order == 2) { // -o2
29506 fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
29507 pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
29508 }
29509 if (!b->nobound) {
29510 fprintf(outfile, " %d", marker);
29511 }
29512 if (b->neighout > 1) {
29513 fprintf(outfile, " %5d %5d", neigh1, neigh2);
29514 }
29515 fprintf(outfile, "\n");
29516 } else {
29517 // Output three vertices of this face;
29518 elist[index++] = pointmark(torg) - shift;
29519 elist[index++] = pointmark(tdest) - shift;
29520 elist[index++] = pointmark(tapex) - shift;
29521 if (b->order == 2) { // -o2
29522 out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
29523 out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
29524 out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
29525 }
29526 if (!b->nobound) {
29527 emlist[index1++] = marker;
29528 }
29529 if (b->neighout > 1) {
29530 out->adjtetlist[index2++] = neigh1;
29531 out->adjtetlist[index2++] = neigh2;
29532 }
29533 }
29534 facenumber++;
29535 faceloop.sh = shellfacetraverse(subfaces);
29536 }
29537
29538 if (out == (tetgenio *) NULL) {
29539 fprintf(outfile, "# Generated by %s\n", b->commandline);
29540 fclose(outfile);
29541 }
29542}
29543
29544///////////////////////////////////////////////////////////////////////////////
29545// //
29546// outedges() Output all edges to a .edge file or a tetgenio object. //
29547// //
29548// Note: This routine must be called after outelements(), so that the total //
29549// number of edges 'meshedges' has been counted. //
29550// //
29551///////////////////////////////////////////////////////////////////////////////
29552
29553void tetgenmesh::outedges(tetgenio* out)
29554{
29555 FILE *outfile = NULL;
29556 char edgefilename[FILENAMESIZE];
29557 triface tetloop, worktet, spintet;
29558 face checkseg;
29559 point torg, tdest;
29560 int *elist = NULL, *emlist = NULL;
29561 int ishulledge;
29562 int firstindex, shift;
29563 int edgenumber, marker;
29564 int index = 0, index1 = 0, index2 = 0;
29565 int t1ver;
29566 int i;
29567
29568 // For -o2 option.
29569 point *extralist, pp = NULL;
29570 int highorderindex = 11;
29571 int o2index = 0;
29572
29573 if (out == (tetgenio *) NULL) {
29574 strcpy(edgefilename, b->outfilename);
29575 strcat(edgefilename, ".edge");
29576 }
29577
29578 if (!b->quiet) {
29579 if (out == (tetgenio *) NULL) {
29580 printf("Writing %s.\n", edgefilename);
29581 } else {
29582 printf("Writing edges.\n");
29583 }
29584 }
29585
29586 if (meshedges == 0l) {
29587 if (nonconvex) {
29588 numberedges(); // Count the edges.
29589 } else {
29590 // Use Euler's characteristic to get the numbe of edges.
29591 // It states V - E + F - C = 1, hence E = V + F - C - 1.
29592 long tsize = tetrahedrons->items - hullsize;
29593 long fsize = (tsize * 4l + hullsize) / 2l;
29594 long vsize = points->items - dupverts - unuverts;
29595 if (b->weighted) vsize -= nonregularcount;
29596 meshedges = vsize + fsize - tsize - 1;
29597 }
29598 }
29599
29600 if (out == (tetgenio *) NULL) {
29601 outfile = fopen(edgefilename, "w");
29602 if (outfile == (FILE *) NULL) {
29603 printf("File I/O Error: Cannot create file %s.\n", edgefilename);
29604 terminatetetgen(this, 1);
29605 }
29606 // Write the number of edges, boundary markers (0 or 1).
29607 fprintf(outfile, "%ld %d\n", meshedges, !b->nobound);
29608 } else {
29609 // Allocate memory for 'edgelist'.
29610 out->edgelist = new int[meshedges * 2];
29611 if (out->edgelist == (int *) NULL) {
29612 printf("Error: Out of memory.\n");
29613 terminatetetgen(this, 1);
29614 }
29615 if (b->order == 2) { // -o2 switch
29616 out->o2edgelist = new int[meshedges];
29617 }
29618 if (!b->nobound) {
29619 out->edgemarkerlist = new int[meshedges];
29620 }
29621 if (b->neighout > 1) { // '-nn' switch.
29622 out->edgeadjtetlist = new int[meshedges];
29623 }
29624 out->numberofedges = meshedges;
29625 elist = out->edgelist;
29626 emlist = out->edgemarkerlist;
29627 }
29628
29629 // Determine the first index (0 or 1).
29630 firstindex = b->zeroindex ? 0 : in->firstnumber;
29631 shift = 0; // Default no shiftment.
29632 if ((in->firstnumber == 1) && (firstindex == 0)) {
29633 shift = 1; // Shift (reduce) the output indices by 1.
29634 }
29635
29636 tetrahedrons->traversalinit();
29637 tetloop.tet = tetrahedrontraverse();
29638 edgenumber = firstindex; // in->firstnumber;
29639 while (tetloop.tet != (tetrahedron *) NULL) {
29640 // Count the number of Voronoi faces.
29641 worktet.tet = tetloop.tet;
29642 for (i = 0; i < 6; i++) {
29643 worktet.ver = edge2ver[i];
29644 ishulledge = 0;
29645 fnext(worktet, spintet);
29646 do {
29647 if (!ishulltet(spintet)) {
29648 if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
29649 } else {
29650 ishulledge = 1;
29651 }
29652 fnextself(spintet);
29653 } while (spintet.tet != worktet.tet);
29654 // Count this edge if no adjacent tets are smaller than this tet.
29655 if (spintet.tet == worktet.tet) {
29656 torg = org(worktet);
29657 tdest = dest(worktet);
29658 if (b->order == 2) { // -o2
29659 // Get the extra vertex on this edge.
29660 extralist = (point *) worktet.tet[highorderindex];
29661 pp = extralist[ver2edge[worktet.ver]];
29662 }
29663 if (out == (tetgenio *) NULL) {
29664 fprintf(outfile, "%5d %4d %4d", edgenumber,
29665 pointmark(torg) - shift, pointmark(tdest) - shift);
29666 if (b->order == 2) { // -o2
29667 fprintf(outfile, " %4d", pointmark(pp) - shift);
29668 }
29669 } else {
29670 // Output three vertices of this face;
29671 elist[index++] = pointmark(torg) - shift;
29672 elist[index++] = pointmark(tdest) - shift;
29673 if (b->order == 2) { // -o2
29674 out->o2edgelist[o2index++] = pointmark(pp) - shift;
29675 }
29676 }
29677 if (!b->nobound) {
29678 if (b->plc || b->refine) {
29679 // Check if the edge is a segment.
29680 tsspivot1(worktet, checkseg);
29681 if (checkseg.sh != NULL) {
29682 marker = shellmark(checkseg);
29683 if (marker == 0) { // Does it have no marker?
29684 marker = 1; // Set the default marker for this segment.
29685 }
29686 } else {
29687 marker = 0; // It's not a segment.
29688 }
29689 } else {
29690 // Mark it if it is a hull edge.
29691 marker = ishulledge ? 1 : 0;
29692 }
29693 if (out == (tetgenio *) NULL) {
29694 fprintf(outfile, " %d", marker);
29695 } else {
29696 emlist[index1++] = marker;
29697 }
29698 }
29699 if (b->neighout > 1) { // '-nn' switch.
29700 if (out == (tetgenio *) NULL) {
29701 fprintf(outfile, " %d", elemindex(tetloop.tet));
29702 } else {
29703 out->edgeadjtetlist[index2++] = elemindex(tetloop.tet);
29704 }
29705 }
29706 if (out == (tetgenio *) NULL) {
29707 fprintf(outfile, "\n");
29708 }
29709 edgenumber++;
29710 }
29711 }
29712 tetloop.tet = tetrahedrontraverse();
29713 }
29714
29715 if (out == (tetgenio *) NULL) {
29716 fprintf(outfile, "# Generated by %s\n", b->commandline);
29717 fclose(outfile);
29718 }
29719}
29720
29721///////////////////////////////////////////////////////////////////////////////
29722// //
29723// outsubsegments() Output segments to a .edge file or a structure. //
29724// //
29725///////////////////////////////////////////////////////////////////////////////
29726
29727void tetgenmesh::outsubsegments(tetgenio* out)
29728{
29729 FILE *outfile = NULL;
29730 char edgefilename[FILENAMESIZE];
29731 int *elist = NULL;
29732 int index, i;
29733 face edgeloop;
29734 point torg, tdest;
29735 int firstindex, shift;
29736 int marker;
29737 int edgenumber;
29738
29739 // For -o2 option.
29740 triface workface, spintet;
29741 point *extralist, pp = NULL;
29742 int highorderindex = 11;
29743 int o2index = 0;
29744
29745 // For -nn option.
29746 int neigh = -1;
29747 int index2 = 0;
29748
29749 int t1ver; // used by fsymself()
29750
29751 if (out == (tetgenio *) NULL) {
29752 strcpy(edgefilename, b->outfilename);
29753 strcat(edgefilename, ".edge");
29754 }
29755
29756 if (!b->quiet) {
29757 if (out == (tetgenio *) NULL) {
29758 printf("Writing %s.\n", edgefilename);
29759 } else {
29760 printf("Writing edges.\n");
29761 }
29762 }
29763
29764 if (out == (tetgenio *) NULL) {
29765 outfile = fopen(edgefilename, "w");
29766 if (outfile == (FILE *) NULL) {
29767 printf("File I/O Error: Cannot create file %s.\n", edgefilename);
29768 terminatetetgen(this, 3);
29769 }
29770 // Number of subsegments.
29771 fprintf(outfile, "%ld 1\n", subsegs->items);
29772 } else {
29773 // Allocate memory for 'edgelist'.
29774 out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
29775 if (out->edgelist == (int *) NULL) {
29776 terminatetetgen(this, 1);
29777 }
29778 if (b->order == 2) {
29779 out->o2edgelist = new int[subsegs->items];
29780 }
29781 out->edgemarkerlist = new int[subsegs->items];
29782 if (out->edgemarkerlist == (int *) NULL) {
29783 terminatetetgen(this, 1);
29784 }
29785 if (b->neighout > 1) {
29786 out->edgeadjtetlist = new int[subsegs->items];
29787 }
29788 out->numberofedges = subsegs->items;
29789 elist = out->edgelist;
29790 }
29791
29792 // Determine the first index (0 or 1).
29793 firstindex = b->zeroindex ? 0 : in->firstnumber;
29794 shift = 0; // Default no shiftment.
29795 if ((in->firstnumber == 1) && (firstindex == 0)) {
29796 shift = 1; // Shift the output indices by 1.
29797 }
29798 index = 0;
29799 i = 0;
29800
29801 subsegs->traversalinit();
29802 edgeloop.sh = shellfacetraverse(subsegs);
29803 edgenumber = firstindex; // in->firstnumber;
29804 while (edgeloop.sh != (shellface *) NULL) {
29805 torg = sorg(edgeloop);
29806 tdest = sdest(edgeloop);
29807 if ((b->order == 2) || (b->neighout > 1)) {
29808 sstpivot1(edgeloop, workface);
29809 if (workface.tet != NULL) {
29810 // We must find a non-hull tet.
29811 if (ishulltet(workface)) {
29812 spintet = workface;
29813 while (1) {
29814 fnextself(spintet);
29815 if (!ishulltet(spintet)) break;
29816 if (spintet.tet == workface.tet) break;
29817 }
29818 assert(!ishulltet(spintet));
29819 workface = spintet;
29820 }
29821 }
29822 }
29823 if (b->order == 2) { // -o2
29824 // Get the extra vertex on this edge.
29825 if (workface.tet != NULL) {
29826 extralist = (point *) workface.tet[highorderindex];
29827 pp = extralist[ver2edge[workface.ver]];
29828 } else {
29829 pp = torg; // There is no extra node available.
29830 }
29831 }
29832 if (b->neighout > 1) { // -nn
29833 if (workface.tet != NULL) {
29834 neigh = elemindex(workface.tet);
29835 } else {
29836 neigh = -1;
29837 }
29838 }
29839 marker = shellmark(edgeloop);
29840 if (marker == 0) {
29841 marker = 1; // Default marker of a boundary edge is 1.
29842 }
29843 if (out == (tetgenio *) NULL) {
29844 fprintf(outfile, "%5d %4d %4d", edgenumber,
29845 pointmark(torg) - shift, pointmark(tdest) - shift);
29846 if (b->order == 2) { // -o2
29847 fprintf(outfile, " %4d", pointmark(pp) - shift);
29848 }
29849 fprintf(outfile, " %d", marker);
29850 if (b->neighout > 1) { // -nn
29851 fprintf(outfile, " %4d", neigh);
29852 }
29853 fprintf(outfile, "\n");
29854 } else {
29855 // Output three vertices of this face;
29856 elist[index++] = pointmark(torg) - shift;
29857 elist[index++] = pointmark(tdest) - shift;
29858 if (b->order == 2) { // -o2
29859 out->o2edgelist[o2index++] = pointmark(pp) - shift;
29860 }
29861 out->edgemarkerlist[i++] = marker;
29862 if (b->neighout > 1) { // -nn
29863 out->edgeadjtetlist[index2++] = neigh;
29864 }
29865 }
29866 edgenumber++;
29867 edgeloop.sh = shellfacetraverse(subsegs);
29868 }
29869
29870 if (out == (tetgenio *) NULL) {
29871 fprintf(outfile, "# Generated by %s\n", b->commandline);
29872 fclose(outfile);
29873 }
29874}
29875
29876///////////////////////////////////////////////////////////////////////////////
29877// //
29878// outneighbors() Output tet neighbors to a .neigh file or a structure. //
29879// //
29880///////////////////////////////////////////////////////////////////////////////
29881
29882void tetgenmesh::outneighbors(tetgenio* out)
29883{
29884 FILE *outfile = NULL;
29885 char neighborfilename[FILENAMESIZE];
29886 int *nlist = NULL;
29887 int index = 0;
29888 triface tetloop, tetsym;
29889 int neighbori[4];
29890 int firstindex;
29891 int elementnumber;
29892 long ntets;
29893
29894 if (out == (tetgenio *) NULL) {
29895 strcpy(neighborfilename, b->outfilename);
29896 strcat(neighborfilename, ".neigh");
29897 }
29898
29899 if (!b->quiet) {
29900 if (out == (tetgenio *) NULL) {
29901 printf("Writing %s.\n", neighborfilename);
29902 } else {
29903 printf("Writing neighbors.\n");
29904 }
29905 }
29906
29907 ntets = tetrahedrons->items - hullsize;
29908
29909 if (out == (tetgenio *) NULL) {
29910 outfile = fopen(neighborfilename, "w");
29911 if (outfile == (FILE *) NULL) {
29912 printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
29913 terminatetetgen(this, 1);
29914 }
29915 // Number of tetrahedra, four faces per tetrahedron.
29916 fprintf(outfile, "%ld %d\n", ntets, 4);
29917 } else {
29918 // Allocate memory for 'neighborlist'.
29919 out->neighborlist = new int[ntets * 4];
29920 if (out->neighborlist == (int *) NULL) {
29921 printf("Error: Out of memory.\n");
29922 terminatetetgen(this, 1);
29923 }
29924 nlist = out->neighborlist;
29925 }
29926
29927 // Determine the first index (0 or 1).
29928 firstindex = b->zeroindex ? 0 : in->firstnumber;
29929
29930 tetrahedrons->traversalinit();
29931 tetloop.tet = tetrahedrontraverse();
29932 elementnumber = firstindex; // in->firstnumber;
29933 while (tetloop.tet != (tetrahedron *) NULL) {
29934 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
29935 fsym(tetloop, tetsym);
29936 if (!ishulltet(tetsym)) {
29937 neighbori[tetloop.ver] = elemindex(tetsym.tet);
29938 } else {
29939 neighbori[tetloop.ver] = -1;
29940 }
29941 }
29942 if (out == (tetgenio *) NULL) {
29943 // Tetrahedra number, neighboring tetrahedron numbers.
29944 fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
29945 neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
29946 } else {
29947 nlist[index++] = neighbori[0];
29948 nlist[index++] = neighbori[1];
29949 nlist[index++] = neighbori[2];
29950 nlist[index++] = neighbori[3];
29951 }
29952 tetloop.tet = tetrahedrontraverse();
29953 elementnumber++;
29954 }
29955
29956 if (out == (tetgenio *) NULL) {
29957 fprintf(outfile, "# Generated by %s\n", b->commandline);
29958 fclose(outfile);
29959 }
29960}
29961
29962///////////////////////////////////////////////////////////////////////////////
29963// //
29964// outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
29965// and .v.cell. //
29966// //
29967// The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
29968// The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
29969// Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
29970// unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
29971// A Voronoi face is the convex hull of all Voronoi vertices around a common //
29972// Delaunay edge. It is a closed polygon for any internal Delaunay edge. At a//
29973// ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
29974// onoi vertices around a common Delaunay vertex. It is a polytope for any //
29975// internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
29976// vertex belonging to the convex hull. //
29977// //
29978// NOTE: This routine is only used when the input is only a set of point. //
29979// Comment: Special thanks to Victor Liu for finding and fixing few bugs. //
29980// //
29981///////////////////////////////////////////////////////////////////////////////
29982
29983void tetgenmesh::outvoronoi(tetgenio* out)
29984{
29985 FILE *outfile = NULL;
29986 char outfilename[FILENAMESIZE];
29987 tetgenio::voroedge *vedge = NULL;
29988 tetgenio::vorofacet *vfacet = NULL;
29989 arraypool *tetlist, *ptlist;
29990 triface tetloop, worktet, spintet, firsttet;
29991 point pt[4], ploop, neipt;
29992 REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
29993 long ntets, faces, edges;
29994 int *indexarray, *fidxs, *eidxs;
29995 int arraysize, *vertarray = NULL;
29996 int vpointcount, vedgecount, vfacecount, tcount;
29997 int ishullvert, ishullface;
29998 int index, shift, end1, end2;
29999 int i, j;
30000
30001 int t1ver; // used by fsymself()
30002
30003 // Output Voronoi vertices to .v.node file.
30004 if (out == (tetgenio *) NULL) {
30005 strcpy(outfilename, b->outfilename);
30006 strcat(outfilename, ".v.node");
30007 }
30008
30009 if (!b->quiet) {
30010 if (out == (tetgenio *) NULL) {
30011 printf("Writing %s.\n", outfilename);
30012 } else {
30013 printf("Writing Voronoi vertices.\n");
30014 }
30015 }
30016
30017 // Determine the first index (0 or 1).
30018 shift = (b->zeroindex ? 0 : in->firstnumber);
30019
30020 // Each face and edge of the tetrahedral mesh will be indexed for indexing
30021 // the Voronoi edges and facets. Indices of faces and edges are saved in
30022 // each tetrahedron (including hull tets).
30023
30024 // Allocate the total space once.
30025 indexarray = new int[tetrahedrons->items * 10];
30026
30027 // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
30028 // for element markers, flags.
30029 i = 0;
30030 tetrahedrons->traversalinit();
30031 tetloop.tet = alltetrahedrontraverse();
30032 while (tetloop.tet != NULL) {
30033 tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
30034 i++;
30035 tetloop.tet = alltetrahedrontraverse();
30036 }
30037
30038 // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
30039 ntets = tetrahedrons->items - hullsize;
30040 // The number of Delaunay faces (Voronoi edges).
30041 faces = (4l * ntets + hullsize) / 2l;
30042 // The number of Delaunay edges (Voronoi faces).
30043 long vsize = points->items - dupverts - unuverts;
30044 if (b->weighted) vsize -= nonregularcount;
30045 edges = vsize + faces - ntets - 1;
30046
30047 if (out == (tetgenio *) NULL) {
30048 outfile = fopen(outfilename, "w");
30049 if (outfile == (FILE *) NULL) {
30050 printf("File I/O Error: Cannot create file %s.\n", outfilename);
30051 terminatetetgen(this, 3);
30052 }
30053 // Number of voronoi points, 3 dim, no attributes, no marker.
30054 fprintf(outfile, "%ld 3 0 0\n", ntets);
30055 } else {
30056 // Allocate space for 'vpointlist'.
30057 out->numberofvpoints = (int) ntets;
30058 out->vpointlist = new REAL[out->numberofvpoints * 3];
30059 if (out->vpointlist == (REAL *) NULL) {
30060 terminatetetgen(this, 1);
30061 }
30062 }
30063
30064 // Output Voronoi vertices (the circumcenters of tetrahedra).
30065 tetrahedrons->traversalinit();
30066 tetloop.tet = tetrahedrontraverse();
30067 vpointcount = 0; // The (internal) v-index always starts from 0.
30068 index = 0;
30069 while (tetloop.tet != (tetrahedron *) NULL) {
30070 for (i = 0; i < 4; i++) {
30071 pt[i] = (point) tetloop.tet[4 + i];
30072 setpoint2tet(pt[i], encode(tetloop));
30073 }
30074 if (b->weighted) {
30075 orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3],
30076 pt[3][3], ccent, NULL);
30077 } else {
30078 circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
30079 }
30080 if (out == (tetgenio *) NULL) {
30081 fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
30082 ccent[0], ccent[1], ccent[2]);
30083 } else {
30084 out->vpointlist[index++] = ccent[0];
30085 out->vpointlist[index++] = ccent[1];
30086 out->vpointlist[index++] = ccent[2];
30087 }
30088 setelemindex(tetloop.tet, vpointcount);
30089 vpointcount++;
30090 tetloop.tet = tetrahedrontraverse();
30091 }
30092
30093 if (out == (tetgenio *) NULL) {
30094 fprintf(outfile, "# Generated by %s\n", b->commandline);
30095 fclose(outfile);
30096 }
30097
30098 // Output Voronoi edges to .v.edge file.
30099 if (out == (tetgenio *) NULL) {
30100 strcpy(outfilename, b->outfilename);
30101 strcat(outfilename, ".v.edge");
30102 }
30103
30104 if (!b->quiet) {
30105 if (out == (tetgenio *) NULL) {
30106 printf("Writing %s.\n", outfilename);
30107 } else {
30108 printf("Writing Voronoi edges.\n");
30109 }
30110 }
30111
30112 if (out == (tetgenio *) NULL) {
30113 outfile = fopen(outfilename, "w");
30114 if (outfile == (FILE *) NULL) {
30115 printf("File I/O Error: Cannot create file %s.\n", outfilename);
30116 terminatetetgen(this, 3);
30117 }
30118 // Number of Voronoi edges, no marker.
30119 fprintf(outfile, "%ld 0\n", faces);
30120 } else {
30121 // Allocate space for 'vpointlist'.
30122 out->numberofvedges = (int) faces;
30123 out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
30124 }
30125
30126 // Output the Voronoi edges.
30127 tetrahedrons->traversalinit();
30128 tetloop.tet = tetrahedrontraverse();
30129 vedgecount = 0; // D-Face (V-edge) index (from zero).
30130 index = 0; // The Delaunay-face index.
30131 while (tetloop.tet != (tetrahedron *) NULL) {
30132 // Count the number of Voronoi edges. Look at the four faces of each
30133 // tetrahedron. Count the face if the tetrahedron's index is
30134 // smaller than its neighbor's or the neighbor is outside.
30135 end1 = elemindex(tetloop.tet);
30136 for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
30137 fsym(tetloop, worktet);
30138 if (ishulltet(worktet) ||
30139 (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
30140 // Found a Voronoi edge. Operate on it.
30141 if (out == (tetgenio *) NULL) {
30142 fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
30143 } else {
30144 vedge = &(out->vedgelist[index++]);
30145 vedge->v1 = end1 + shift;
30146 }
30147 if (!ishulltet(worktet)) {
30148 end2 = elemindex(worktet.tet);
30149 } else {
30150 end2 = -1;
30151 }
30152 // Note that end2 may be -1 (worktet.tet is outside).
30153 if (end2 == -1) {
30154 // Calculate the out normal of this hull face.
30155 pt[0] = dest(worktet);
30156 pt[1] = org(worktet);
30157 pt[2] = apex(worktet);
30158 for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
30159 for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
30160 cross(vec1, vec2, infvec);
30161 // Normalize it.
30162 L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
30163 + infvec[2] * infvec[2]);
30164 if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
30165 if (out == (tetgenio *) NULL) {
30166 fprintf(outfile, " -1");
30167 fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
30168 } else {
30169 vedge->v2 = -1;
30170 vedge->vnormal[0] = infvec[0];
30171 vedge->vnormal[1] = infvec[1];
30172 vedge->vnormal[2] = infvec[2];
30173 }
30174 } else {
30175 if (out == (tetgenio *) NULL) {
30176 fprintf(outfile, " %4d\n", end2 + shift);
30177 } else {
30178 vedge->v2 = end2 + shift;
30179 vedge->vnormal[0] = 0.0;
30180 vedge->vnormal[1] = 0.0;
30181 vedge->vnormal[2] = 0.0;
30182 }
30183 }
30184 // Save the V-edge index in this tet and its neighbor.
30185 fidxs = (int *) (tetloop.tet[11]);
30186 fidxs[tetloop.ver] = vedgecount;
30187 fidxs = (int *) (worktet.tet[11]);
30188 fidxs[worktet.ver & 3] = vedgecount;
30189 vedgecount++;
30190 }
30191 } // tetloop.ver
30192 tetloop.tet = tetrahedrontraverse();
30193 }
30194
30195 if (out == (tetgenio *) NULL) {
30196 fprintf(outfile, "# Generated by %s\n", b->commandline);
30197 fclose(outfile);
30198 }
30199
30200 // Output Voronoi faces to .v.face file.
30201 if (out == (tetgenio *) NULL) {
30202 strcpy(outfilename, b->outfilename);
30203 strcat(outfilename, ".v.face");
30204 }
30205
30206 if (!b->quiet) {
30207 if (out == (tetgenio *) NULL) {
30208 printf("Writing %s.\n", outfilename);
30209 } else {
30210 printf("Writing Voronoi faces.\n");
30211 }
30212 }
30213
30214 if (out == (tetgenio *) NULL) {
30215 outfile = fopen(outfilename, "w");
30216 if (outfile == (FILE *) NULL) {
30217 printf("File I/O Error: Cannot create file %s.\n", outfilename);
30218 terminatetetgen(this, 3);
30219 }
30220 // Number of Voronoi faces.
30221 fprintf(outfile, "%ld 0\n", edges);
30222 } else {
30223 out->numberofvfacets = edges;
30224 out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
30225 if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
30226 terminatetetgen(this, 1);
30227 }
30228 }
30229
30230 // Output the Voronoi facets.
30231 tetrahedrons->traversalinit();
30232 tetloop.tet = tetrahedrontraverse();
30233 vfacecount = 0; // D-edge (V-facet) index (from zero).
30234 while (tetloop.tet != (tetrahedron *) NULL) {
30235 // Count the number of Voronoi faces. Look at the six edges of each
30236 // tetrahedron. Count the edge only if the tetrahedron's index is
30237 // smaller than those of all other tetrahedra that share the edge.
30238 worktet.tet = tetloop.tet;
30239 for (i = 0; i < 6; i++) {
30240 worktet.ver = edge2ver[i];
30241 // Count the number of faces at this edge. If the edge is a hull edge,
30242 // the face containing dummypoint is also counted.
30243 //ishulledge = 0; // Is it a hull edge.
30244 tcount = 0;
30245 firsttet = worktet;
30246 spintet = worktet;
30247 while (1) {
30248 tcount++;
30249 fnextself(spintet);
30250 if (spintet.tet == worktet.tet) break;
30251 if (!ishulltet(spintet)) {
30252 if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
30253 } else {
30254 //ishulledge = 1;
30255 if (apex(spintet) == dummypoint) {
30256 // We make this V-edge appear in the end of the edge list.
30257 fnext(spintet, firsttet);
30258 }
30259 }
30260 } // while (1)
30261 if (spintet.tet == worktet.tet) {
30262 // Found a Voronoi facet. Operate on it.
30263 pt[0] = org(worktet);
30264 pt[1] = dest(worktet);
30265 end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
30266 end2 = pointmark(pt[1]) - in->firstnumber;
30267 if (out == (tetgenio *) NULL) {
30268 fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
30269 end1 + shift, end2 + shift, tcount);
30270 } else {
30271 vfacet = &(out->vfacetlist[vfacecount]);
30272 vfacet->c1 = end1 + shift;
30273 vfacet->c2 = end2 + shift;
30274 vfacet->elist = new int[tcount + 1];
30275 vfacet->elist[0] = tcount;
30276 index = 1;
30277 }
30278 // Output V-edges of this V-facet.
30279 spintet = firsttet; //worktet;
30280 while (1) {
30281 fidxs = (int *) (spintet.tet[11]);
30282 if (apex(spintet) != dummypoint) {
30283 vedgecount = fidxs[spintet.ver & 3];
30284 ishullface = 0;
30285 } else {
30286 ishullface = 1; // It's not a real face.
30287 }
30288 if (out == (tetgenio *) NULL) {
30289 fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1);
30290 } else {
30291 vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
30292 }
30293 // Save the V-facet index in this tet at this edge.
30294 eidxs = &(fidxs[4]);
30295 eidxs[ver2edge[spintet.ver]] = vfacecount;
30296 // Go to the next face.
30297 fnextself(spintet);
30298 if (spintet.tet == firsttet.tet) break;
30299 } // while (1)
30300 if (out == (tetgenio *) NULL) {
30301 fprintf(outfile, "\n");
30302 }
30303 vfacecount++;
30304 } // if (spintet.tet == worktet.tet)
30305 } // if (i = 0; i < 6; i++)
30306 tetloop.tet = tetrahedrontraverse();
30307 }
30308
30309 if (out == (tetgenio *) NULL) {
30310 fprintf(outfile, "# Generated by %s\n", b->commandline);
30311 fclose(outfile);
30312 }
30313
30314 // Output Voronoi cells to .v.cell file.
30315 if (out == (tetgenio *) NULL) {
30316 strcpy(outfilename, b->outfilename);
30317 strcat(outfilename, ".v.cell");
30318 }
30319
30320 if (!b->quiet) {
30321 if (out == (tetgenio *) NULL) {
30322 printf("Writing %s.\n", outfilename);
30323 } else {
30324 printf("Writing Voronoi cells.\n");
30325 }
30326 }
30327
30328 if (out == (tetgenio *) NULL) {
30329 outfile = fopen(outfilename, "w");
30330 if (outfile == (FILE *) NULL) {
30331 printf("File I/O Error: Cannot create file %s.\n", outfilename);
30332 terminatetetgen(this, 3);
30333 }
30334 // Number of Voronoi cells.
30335 fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
30336 } else {
30337 out->numberofvcells = points->items - unuverts - dupverts;
30338 out->vcelllist = new int*[out->numberofvcells];
30339 if (out->vcelllist == (int **) NULL) {
30340 terminatetetgen(this, 1);
30341 }
30342 }
30343
30344 // Output Voronoi cells.
30345 tetlist = cavetetlist;
30346 ptlist = cavetetvertlist;
30347 points->traversalinit();
30348 ploop = pointtraverse();
30349 vpointcount = 0;
30350 while (ploop != (point) NULL) {
30351 if ((pointtype(ploop) != UNUSEDVERTEX) &&
30352 (pointtype(ploop) != DUPLICATEDVERTEX) &&
30353 (pointtype(ploop) != NREGULARVERTEX)) {
30354 getvertexstar(1, ploop, tetlist, ptlist, NULL);
30355 // Mark all vertices. Check if it is a hull vertex.
30356 ishullvert = 0;
30357 for (i = 0; i < ptlist->objects; i++) {
30358 neipt = * (point *) fastlookup(ptlist, i);
30359 if (neipt != dummypoint) {
30360 pinfect(neipt);
30361 } else {
30362 ishullvert = 1;
30363 }
30364 }
30365 tcount = (int) ptlist->objects;
30366 if (out == (tetgenio *) NULL) {
30367 fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
30368 } else {
30369 arraysize = tcount;
30370 vertarray = new int[arraysize + 1];
30371 out->vcelllist[vpointcount] = vertarray;
30372 vertarray[0] = tcount;
30373 index = 1;
30374 }
30375 // List Voronoi facets bounding this cell.
30376 for (i = 0; i < tetlist->objects; i++) {
30377 worktet = * (triface *) fastlookup(tetlist, i);
30378 // Let 'worktet' be [a,b,c,d] where d = ploop.
30379 for (j = 0; j < 3; j++) {
30380 neipt = org(worktet); // neipt is a, or b, or c
30381 // Skip the dummypoint.
30382 if (neipt != dummypoint) {
30383 if (pinfected(neipt)) {
30384 // It's not processed yet.
30385 puninfect(neipt);
30386 // Go to the DT edge [a,d], or [b,d], or [c,d].
30387 esym(worktet, spintet);
30388 enextself(spintet);
30389 // Get the V-face dual to this edge.
30390 eidxs = (int *) spintet.tet[11];
30391 vfacecount = eidxs[4 + ver2edge[spintet.ver]];
30392 if (out == (tetgenio *) NULL) {
30393 fprintf(outfile, " %d", vfacecount + shift);
30394 } else {
30395 vertarray[index++] = vfacecount + shift;
30396 }
30397 }
30398 }
30399 enextself(worktet);
30400 } // j
30401 } // i
30402 if (ishullvert) {
30403 // Add a hull facet (-1) to the facet list.
30404 if (out == (tetgenio *) NULL) {
30405 fprintf(outfile, " -1");
30406 } else {
30407 vertarray[index++] = -1;
30408 }
30409 }
30410 if (out == (tetgenio *) NULL) {
30411 fprintf(outfile, "\n");
30412 }
30413 tetlist->restart();
30414 ptlist->restart();
30415 vpointcount++;
30416 }
30417 ploop = pointtraverse();
30418 }
30419
30420 // Delete the space for face/edge indices.
30421 delete [] indexarray;
30422
30423 if (out == (tetgenio *) NULL) {
30424 fprintf(outfile, "# Generated by %s\n", b->commandline);
30425 fclose(outfile);
30426 }
30427}
30428
30429///////////////////////////////////////////////////////////////////////////////
30430// //
30431// outsmesh() Write surface mesh to a .smesh file, which can be read and //
30432// tetrahedralized by TetGen. //
30433// //
30434// You can specify a filename (without suffix) in 'smfilename'. If you don't //
30435// supply a filename (let smfilename be NULL), the default name stored in //
30436// 'tetgenbehavior' will be used. //
30437// //
30438///////////////////////////////////////////////////////////////////////////////
30439
30440void tetgenmesh::outsmesh(char* smfilename)
30441{
30442 FILE *outfile;
30443 char nodfilename[FILENAMESIZE];
30444 char smefilename[FILENAMESIZE];
30445 face faceloop;
30446 point p1, p2, p3;
30447 int firstindex, shift;
30448 int bmark;
30449 int faceid, marker;
30450 int i;
30451
30452 if (smfilename != (char *) NULL && smfilename[0] != '\0') {
30453 strcpy(smefilename, smfilename);
30454 } else if (b->outfilename[0] != '\0') {
30455 strcpy(smefilename, b->outfilename);
30456 } else {
30457 strcpy(smefilename, "unnamed");
30458 }
30459 strcpy(nodfilename, smefilename);
30460 strcat(smefilename, ".smesh");
30461 strcat(nodfilename, ".node");
30462
30463 if (!b->quiet) {
30464 printf("Writing %s.\n", smefilename);
30465 }
30466 outfile = fopen(smefilename, "w");
30467 if (outfile == (FILE *) NULL) {
30468 printf("File I/O Error: Cannot create file %s.\n", smefilename);
30469 return;
30470 }
30471
30472 // Determine the first index (0 or 1).
30473 firstindex = b->zeroindex ? 0 : in->firstnumber;
30474 shift = 0; // Default no shiftment.
30475 if ((in->firstnumber == 1) && (firstindex == 0)) {
30476 shift = 1; // Shift the output indices by 1.
30477 }
30478
30479 fprintf(outfile, "# %s. TetGen's input file.\n", smefilename);
30480 fprintf(outfile, "\n# part 1: node list.\n");
30481 fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename);
30482
30483 marker = 0; // avoid compile warning.
30484 bmark = !b->nobound && in->facetmarkerlist;
30485
30486 fprintf(outfile, "\n# part 2: facet list.\n");
30487 // Number of facets, boundary marker.
30488 fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
30489
30490 subfaces->traversalinit();
30491 faceloop.sh = shellfacetraverse(subfaces);
30492 while (faceloop.sh != (shellface *) NULL) {
30493 p1 = sorg(faceloop);
30494 p2 = sdest(faceloop);
30495 p3 = sapex(faceloop);
30496 if (bmark) {
30497 faceid = shellmark(faceloop) - 1;
30498 if (faceid >= 0) {
30499 marker = in->facetmarkerlist[faceid];
30500 } else {
30501 marker = 0; // This subface must be added manually later.
30502 }
30503 }
30504 fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift,
30505 pointmark(p2) - shift, pointmark(p3) - shift);
30506 if (bmark) {
30507 fprintf(outfile, " %d", marker);
30508 }
30509 fprintf(outfile, "\n");
30510 faceloop.sh = shellfacetraverse(subfaces);
30511 }
30512
30513 // Copy input holelist.
30514 fprintf(outfile, "\n# part 3: hole list.\n");
30515 fprintf(outfile, "%d\n", in->numberofholes);
30516 for (i = 0; i < in->numberofholes; i++) {
30517 fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber,
30518 in->holelist[i * 3], in->holelist[i * 3 + 1],
30519 in->holelist[i * 3 + 2]);
30520 }
30521
30522 // Copy input regionlist.
30523 fprintf(outfile, "\n# part 4: region list.\n");
30524 fprintf(outfile, "%d\n", in->numberofregions);
30525 for (i = 0; i < in->numberofregions; i++) {
30526 fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber,
30527 in->regionlist[i * 5], in->regionlist[i * 5 + 1],
30528 in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
30529 in->regionlist[i * 5 + 4]);
30530 }
30531
30532 fprintf(outfile, "# Generated by %s\n", b->commandline);
30533 fclose(outfile);
30534}
30535
30536///////////////////////////////////////////////////////////////////////////////
30537// //
30538// outmesh2medit() Write mesh to a .mesh file, which can be read and //
30539// rendered by Medit (a free mesh viewer from INRIA). //
30540// //
30541// You can specify a filename (without suffix) in 'mfilename'. If you don't //
30542// supply a filename (let mfilename be NULL), the default name stored in //
30543// 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
30544// //
30545///////////////////////////////////////////////////////////////////////////////
30546
30547void tetgenmesh::outmesh2medit(char* mfilename)
30548{
30549 FILE *outfile;
30550 char mefilename[FILENAMESIZE];
30551 tetrahedron* tetptr;
30552 triface tface, tsymface;
30553 face segloop, checkmark;
30554 point ptloop, p1, p2, p3, p4;
30555 long ntets, faces;
30556 int pointnumber;
30557 int faceid, marker;
30558 int i;
30559
30560 if (mfilename != (char *) NULL && mfilename[0] != '\0') {
30561 strcpy(mefilename, mfilename);
30562 } else if (b->outfilename[0] != '\0') {
30563 strcpy(mefilename, b->outfilename);
30564 } else {
30565 strcpy(mefilename, "unnamed");
30566 }
30567 strcat(mefilename, ".mesh");
30568
30569 if (!b->quiet) {
30570 printf("Writing %s.\n", mefilename);
30571 }
30572 outfile = fopen(mefilename, "w");
30573 if (outfile == (FILE *) NULL) {
30574 printf("File I/O Error: Cannot create file %s.\n", mefilename);
30575 return;
30576 }
30577
30578 fprintf(outfile, "MeshVersionFormatted 1\n");
30579 fprintf(outfile, "\n");
30580 fprintf(outfile, "Dimension\n");
30581 fprintf(outfile, "3\n");
30582 fprintf(outfile, "\n");
30583
30584 fprintf(outfile, "\n# Set of mesh vertices\n");
30585 fprintf(outfile, "Vertices\n");
30586 fprintf(outfile, "%ld\n", points->items);
30587
30588 points->traversalinit();
30589 ptloop = pointtraverse();
30590 pointnumber = 1; // Medit need start number form 1.
30591 while (ptloop != (point) NULL) {
30592 // Point coordinates.
30593 fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
30594 if (in->numberofpointattributes > 0) {
30595 // Write an attribute, ignore others if more than one.
30596 fprintf(outfile, " %.17g\n", ptloop[3]);
30597 } else {
30598 fprintf(outfile, " 0\n");
30599 }
30600 setpointmark(ptloop, pointnumber);
30601 ptloop = pointtraverse();
30602 pointnumber++;
30603 }
30604
30605 // Compute the number of faces.
30606 ntets = tetrahedrons->items - hullsize;
30607 faces = (ntets * 4l + hullsize) / 2l;
30608
30609 fprintf(outfile, "\n# Set of Triangles\n");
30610 fprintf(outfile, "Triangles\n");
30611 fprintf(outfile, "%ld\n", faces);
30612
30613 tetrahedrons->traversalinit();
30614 tface.tet = tetrahedrontraverse();
30615 while (tface.tet != (tetrahedron *) NULL) {
30616 for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
30617 fsym(tface, tsymface);
30618 if (ishulltet(tsymface) ||
30619 (elemindex(tface.tet) < elemindex(tsymface.tet))) {
30620 p1 = org (tface);
30621 p2 = dest(tface);
30622 p3 = apex(tface);
30623 fprintf(outfile, "%5d %5d %5d",
30624 pointmark(p1), pointmark(p2), pointmark(p3));
30625 // Check if it is a subface.
30626 tspivot(tface, checkmark);
30627 if (checkmark.sh == NULL) {
30628 marker = 0; // It is an inner face. It's marker is 0.
30629 } else {
30630 if (in->facetmarkerlist) {
30631 // The facet marker is given, get it.
30632 faceid = shellmark(checkmark) - 1;
30633 marker = in->facetmarkerlist[faceid];
30634 } else {
30635 marker = 1; // The default marker for subface is 1.
30636 }
30637 }
30638 fprintf(outfile, " %d\n", marker);
30639 }
30640 }
30641 tface.tet = tetrahedrontraverse();
30642 }
30643
30644 fprintf(outfile, "\n# Set of Tetrahedra\n");
30645 fprintf(outfile, "Tetrahedra\n");
30646 fprintf(outfile, "%ld\n", ntets);
30647
30648 tetrahedrons->traversalinit();
30649 tetptr = tetrahedrontraverse();
30650 while (tetptr != (tetrahedron *) NULL) {
30651 if (!b->reversetetori) {
30652 p1 = (point) tetptr[4];
30653 p2 = (point) tetptr[5];
30654 } else {
30655 p1 = (point) tetptr[5];
30656 p2 = (point) tetptr[4];
30657 }
30658 p3 = (point) tetptr[6];
30659 p4 = (point) tetptr[7];
30660 fprintf(outfile, "%5d %5d %5d %5d",
30661 pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
30662 if (numelemattrib > 0) {
30663 fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
30664 } else {
30665 fprintf(outfile, " 0");
30666 }
30667 fprintf(outfile, "\n");
30668 tetptr = tetrahedrontraverse();
30669 }
30670
30671 fprintf(outfile, "\nCorners\n");
30672 fprintf(outfile, "%d\n", in->numberofpoints);
30673
30674 for (i = 0; i < in->numberofpoints; i++) {
30675 fprintf(outfile, "%4d\n", i + 1);
30676 }
30677
30678 if (b->plc || b->refine) {
30679 fprintf(outfile, "\nEdges\n");
30680 fprintf(outfile, "%ld\n", subsegs->items);
30681
30682 subsegs->traversalinit();
30683 segloop.sh = shellfacetraverse(subsegs);
30684 while (segloop.sh != (shellface *) NULL) {
30685 p1 = sorg(segloop);
30686 p2 = sdest(segloop);
30687 fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2));
30688 marker = shellmark(segloop);
30689 fprintf(outfile, " %d\n", marker);
30690 segloop.sh = shellfacetraverse(subsegs);
30691 }
30692 }
30693
30694 fprintf(outfile, "\nEnd\n");
30695 fclose(outfile);
30696}
30697
30698
30699
30700///////////////////////////////////////////////////////////////////////////////
30701// //
30702// outmesh2vtk() Save mesh to file in VTK Legacy format. //
30703// //
30704// This function was contributed by Bryn Llyod from ETH, 2007. //
30705// //
30706///////////////////////////////////////////////////////////////////////////////
30707
30708void tetgenmesh::outmesh2vtk(char* ofilename)
30709{
30710 FILE *outfile;
30711 char vtkfilename[FILENAMESIZE];
30712 point pointloop, p1, p2, p3, p4;
30713 tetrahedron* tptr;
30714 double x, y, z;
30715 int n1, n2, n3, n4;
30716 int nnodes = 4;
30717 int celltype = 10;
30718
30719 if (b->order == 2) {
30720 printf(" Write VTK not implemented for order 2 elements \n");
30721 return;
30722 }
30723
30724 int NEL = tetrahedrons->items - hullsize;
30725 int NN = points->items;
30726
30727 if (ofilename != (char *) NULL && ofilename[0] != '\0') {
30728 strcpy(vtkfilename, ofilename);
30729 } else if (b->outfilename[0] != '\0') {
30730 strcpy(vtkfilename, b->outfilename);
30731 } else {
30732 strcpy(vtkfilename, "unnamed");
30733 }
30734 strcat(vtkfilename, ".vtk");
30735
30736 if (!b->quiet) {
30737 printf("Writing %s.\n", vtkfilename);
30738 }
30739 outfile = fopen(vtkfilename, "w");
30740 if (outfile == (FILE *) NULL) {
30741 printf("File I/O Error: Cannot create file %s.\n", vtkfilename);
30742 return;
30743 }
30744
30745 //always write big endian
30746 //bool ImALittleEndian = !testIsBigEndian();
30747
30748 fprintf(outfile, "# vtk DataFile Version 2.0\n");
30749 fprintf(outfile, "Unstructured Grid\n");
30750 fprintf(outfile, "ASCII\n"); // BINARY
30751 fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
30752 fprintf(outfile, "POINTS %d double\n", NN);
30753
30754 points->traversalinit();
30755 pointloop = pointtraverse();
30756 for(int id=0; id<NN && pointloop != (point) NULL; id++){
30757 x = pointloop[0];
30758 y = pointloop[1];
30759 z = pointloop[2];
30760 fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
30761 pointloop = pointtraverse();
30762 }
30763 fprintf(outfile, "\n");
30764
30765 fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
30766 //NEL rows, each has 1 type id + 4 node id's
30767
30768 tetrahedrons->traversalinit();
30769 tptr = tetrahedrontraverse();
30770 //elementnumber = firstindex; // in->firstnumber;
30771 while (tptr != (tetrahedron *) NULL) {
30772 if (!b->reversetetori) {
30773 p1 = (point) tptr[4];
30774 p2 = (point) tptr[5];
30775 } else {
30776 p1 = (point) tptr[5];
30777 p2 = (point) tptr[4];
30778 }
30779 p3 = (point) tptr[6];
30780 p4 = (point) tptr[7];
30781 n1 = pointmark(p1) - in->firstnumber;
30782 n2 = pointmark(p2) - in->firstnumber;
30783 n3 = pointmark(p3) - in->firstnumber;
30784 n4 = pointmark(p4) - in->firstnumber;
30785 fprintf(outfile, "%d %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
30786 tptr = tetrahedrontraverse();
30787 }
30788 fprintf(outfile, "\n");
30789
30790 fprintf(outfile, "CELL_TYPES %d\n", NEL);
30791 for(int tid=0; tid<NEL; tid++){
30792 fprintf(outfile, "%d\n", celltype);
30793 }
30794 fprintf(outfile, "\n");
30795
30796 if (numelemattrib > 0) {
30797 // Output tetrahedra region attributes.
30798 fprintf(outfile, "CELL_DATA %d\n", NEL);
30799 fprintf(outfile, "SCALARS cell_scalars int 1\n");
30800 fprintf(outfile, "LOOKUP_TABLE default\n");
30801 tetrahedrons->traversalinit();
30802 tptr = tetrahedrontraverse();
30803 while (tptr != (tetrahedron *) NULL) {
30804 fprintf(outfile, "%d\n", (int) elemattribute(tptr, numelemattrib - 1));
30805 tptr = tetrahedrontraverse();
30806 }
30807 fprintf(outfile, "\n");
30808 }
30809
30810 fclose(outfile);
30811}
30812
30813//// ////
30814//// ////
30815//// output_cxx ///////////////////////////////////////////////////////////////
30816
30817//// main_cxx /////////////////////////////////////////////////////////////////
30818//// ////
30819//// ////
30820
30821///////////////////////////////////////////////////////////////////////////////
30822// //
30823// tetrahedralize() The interface for users using TetGen library to //
30824// generate tetrahedral meshes with all features. //
30825// //
30826// The sequence is roughly as follows. Many of these steps can be skipped, //
30827// depending on the command line switches. //
30828// //
30829// - Initialize constants and parse the command line. //
30830// - Read the vertices from a file and either //
30831// - tetrahedralize them (no -r), or //
30832// - read an old mesh from files and reconstruct it (-r). //
30833// - Insert the boundary segments and facets (-p or -Y). //
30834// - Read the holes (-p), regional attributes (-pA), and regional volume //
30835// constraints (-pa). Carve the holes and concavities, and spread the //
30836// regional attributes and volume constraints. //
30837// - Enforce the constraints on minimum quality bound (-q) and maximum //
30838// volume (-a), and a mesh size function (-m). //
30839// - Optimize the mesh wrt. specified quality measures (-O and -o). //
30840// - Write the output files and print the statistics. //
30841// - Check the consistency of the mesh (-C). //
30842// //
30843///////////////////////////////////////////////////////////////////////////////
30844
30845void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
30846 tetgenio *addin, tetgenio *bgmin)
30847{
30848 tetgenmesh m;
30849 clock_t tv[12], ts[5]; // Timing informations (defined in time.h)
30850 REAL cps = (REAL) CLOCKS_PER_SEC;
30851
30852 tv[0] = clock();
30853
30854 m.b = b;
30855 m.in = in;
30856 m.addin = addin;
30857
30858 if (b->metric && bgmin && (bgmin->numberofpoints > 0)) {
30859 m.bgm = new tetgenmesh(); // Create an empty background mesh.
30860 m.bgm->b = b;
30861 m.bgm->in = bgmin;
30862 }
30863
30864 m.initializepools();
30865 m.transfernodes();
30866
30867 exactinit(b->verbose, b->noexact, b->nostaticfilter,
30868 m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
30869
30870 tv[1] = clock();
30871
30872 if (b->refine) { // -r
30873 m.reconstructmesh();
30874 } else { // -p
30875 m.incrementaldelaunay(ts[0]);
30876 }
30877
30878 tv[2] = clock();
30879
30880 if (!b->quiet) {
30881 if (b->refine) {
30882 printf("Mesh reconstruction seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
30883 } else {
30884 printf("Delaunay seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
30885 if (b->verbose) {
30886 printf(" Point sorting seconds: %g\n", ((REAL)(ts[0]-tv[1])) / cps);
30887 }
30888 }
30889 }
30890
30891 if (b->plc && !b->refine) { // -p
30892 m.meshsurface();
30893
30894 ts[0] = clock();
30895
30896 if (!b->quiet) {
30897 printf("Surface mesh seconds: %g\n", ((REAL)(ts[0]-tv[2])) / cps);
30898 }
30899
30900 if (b->diagnose) { // -d
30901 m.detectinterfaces();
30902
30903 ts[1] = clock();
30904
30905 if (!b->quiet) {
30906 printf("Self-intersection seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
30907 }
30908
30909 // Only output when self-intersecting faces exist.
30910 if (m.subfaces->items > 0l) {
30911 m.outnodes(out);
30912 m.outsubfaces(out);
30913 }
30914
30915 return;
30916 }
30917 }
30918
30919 tv[3] = clock();
30920
30921 if ((b->metric) && (m.bgm != NULL)) { // -m
30922 m.bgm->initializepools();
30923 m.bgm->transfernodes();
30924 m.bgm->reconstructmesh();
30925
30926 ts[0] = clock();
30927
30928 if (!b->quiet) {
30929 printf("Background mesh reconstruct seconds: %g\n",
30930 ((REAL)(ts[0] - tv[3])) / cps);
30931 }
30932
30933 if (b->metric) { // -m
30934 m.interpolatemeshsize();
30935
30936 ts[1] = clock();
30937
30938 if (!b->quiet) {
30939 printf("Size interpolating seconds: %g\n",((REAL)(ts[1]-ts[0])) / cps);
30940 }
30941 }
30942 }
30943
30944 tv[4] = clock();
30945
30946 if (b->plc && !b->refine) { // -p
30947 if (b->nobisect) { // -Y
30948 m.recoverboundary(ts[0]);
30949 } else {
30950 m.constraineddelaunay(ts[0]);
30951 }
30952
30953 ts[1] = clock();
30954
30955 if (!b->quiet) {
30956 if (b->nobisect) {
30957 printf("Boundary recovery ");
30958 } else {
30959 printf("Constrained Delaunay ");
30960 }
30961 printf("seconds: %g\n", ((REAL)(ts[1] - tv[4])) / cps);
30962 if (b->verbose) {
30963 printf(" Segment recovery seconds: %g\n",((REAL)(ts[0]-tv[4]))/ cps);
30964 printf(" Facet recovery seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
30965 }
30966 }
30967
30968 m.carveholes();
30969
30970 ts[2] = clock();
30971
30972 if (!b->quiet) {
30973 printf("Exterior tets removal seconds: %g\n",((REAL)(ts[2]-ts[1]))/cps);
30974 }
30975
30976 if (b->nobisect) { // -Y
30977 if (m.subvertstack->objects > 0l) {
30978 m.suppresssteinerpoints();
30979
30980 ts[3] = clock();
30981
30982 if (!b->quiet) {
30983 printf("Steiner suppression seconds: %g\n",
30984 ((REAL)(ts[3]-ts[2]))/cps);
30985 }
30986 }
30987 }
30988 }
30989
30990 tv[5] = clock();
30991
30992 if (b->coarsen) { // -R
30993 m.meshcoarsening();
30994 }
30995
30996 tv[6] = clock();
30997
30998 if (!b->quiet) {
30999 if (b->coarsen) {
31000 printf("Mesh coarsening seconds: %g\n", ((REAL)(tv[6] - tv[5])) / cps);
31001 }
31002 }
31003
31004 if ((b->plc && b->nobisect) || b->coarsen) {
31005 m.recoverdelaunay();
31006 }
31007
31008 tv[7] = clock();
31009
31010 if (!b->quiet) {
31011 if ((b->plc && b->nobisect) || b->coarsen) {
31012 printf("Delaunay recovery seconds: %g\n", ((REAL)(tv[7] - tv[6]))/cps);
31013 }
31014 }
31015
31016 if ((b->plc || b->refine) && b->insertaddpoints) { // -i
31017 if ((addin != NULL) && (addin->numberofpoints > 0)) {
31018 m.insertconstrainedpoints(addin);
31019 }
31020 }
31021
31022 tv[8] = clock();
31023
31024 if (!b->quiet) {
31025 if ((b->plc || b->refine) && b->insertaddpoints) { // -i
31026 if ((addin != NULL) && (addin->numberofpoints > 0)) {
31027 printf("Constrained points seconds: %g\n", ((REAL)(tv[8]-tv[7]))/cps);
31028 }
31029 }
31030 }
31031
31032 if (b->quality) {
31033 m.delaunayrefinement();
31034 }
31035
31036 tv[9] = clock();
31037
31038 if (!b->quiet) {
31039 if (b->quality) {
31040 printf("Refinement seconds: %g\n", ((REAL)(tv[9] - tv[8])) / cps);
31041 }
31042 }
31043
31044 if ((b->plc || b->refine) && (b->optlevel > 0)) {
31045 m.optimizemesh();
31046 }
31047
31048 tv[10] = clock();
31049
31050 if (!b->quiet) {
31051 if ((b->plc || b->refine) && (b->optlevel > 0)) {
31052 printf("Optimization seconds: %g\n", ((REAL)(tv[10] - tv[9])) / cps);
31053 }
31054 }
31055
31056 if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
31057 || (b->refine && (in->numberofcorners == 10)))) {
31058 m.jettisonnodes();
31059 }
31060
31061 if ((b->order == 2) && !b->convex) {
31062 m.highorder();
31063 }
31064
31065 if (!b->quiet) {
31066 printf("\n");
31067 }
31068
31069 if (out != (tetgenio *) NULL) {
31070 out->firstnumber = in->firstnumber;
31071 out->mesh_dim = in->mesh_dim;
31072 }
31073
31074 if (b->nonodewritten || b->noiterationnum) {
31075 if (!b->quiet) {
31076 printf("NOT writing a .node file.\n");
31077 }
31078 } else {
31079 m.outnodes(out);
31080 }
31081
31082 if (b->noelewritten) {
31083 if (!b->quiet) {
31084 printf("NOT writing an .ele file.\n");
31085 }
31086 } else {
31087 if (m.tetrahedrons->items > 0l) {
31088 m.outelements(out);
31089 }
31090 }
31091
31092 if (b->nofacewritten) {
31093 if (!b->quiet) {
31094 printf("NOT writing an .face file.\n");
31095 }
31096 } else {
31097 if (b->facesout) {
31098 if (m.tetrahedrons->items > 0l) {
31099 m.outfaces(out); // Output all faces.
31100 }
31101 } else {
31102 if (b->plc || b->refine) {
31103 if (m.subfaces->items > 0l) {
31104 m.outsubfaces(out); // Output boundary faces.
31105 }
31106 } else {
31107 if (m.tetrahedrons->items > 0l) {
31108 m.outhullfaces(out); // Output convex hull faces.
31109 }
31110 }
31111 }
31112 }
31113
31114
31115 if (b->nofacewritten) {
31116 if (!b->quiet) {
31117 printf("NOT writing an .edge file.\n");
31118 }
31119 } else {
31120 if (b->edgesout) { // -e
31121 m.outedges(out); // output all mesh edges.
31122 } else {
31123 if (b->plc || b->refine) {
31124 m.outsubsegments(out); // output subsegments.
31125 }
31126 }
31127 }
31128
31129 if ((b->plc || b->refine) && b->metric) { // -m
31130 m.outmetrics(out);
31131 }
31132
31133 if (!out && b->plc &&
31134 ((b->object == tetgenbehavior::OFF) ||
31135 (b->object == tetgenbehavior::PLY) ||
31136 (b->object == tetgenbehavior::STL))) {
31137 m.outsmesh(b->outfilename);
31138 }
31139
31140 if (!out && b->meditview) {
31141 m.outmesh2medit(b->outfilename);
31142 }
31143
31144
31145 if (!out && b->vtkview) {
31146 m.outmesh2vtk(b->outfilename);
31147 }
31148
31149 if (b->neighout) {
31150 m.outneighbors(out);
31151 }
31152
31153 if ((!(b->plc || b->refine)) && b->voroout) {
31154 m.outvoronoi(out);
31155 }
31156
31157
31158 tv[11] = clock();
31159
31160 if (!b->quiet) {
31161 printf("\nOutput seconds: %g\n", ((REAL)(tv[11] - tv[10])) / cps);
31162 printf("Total running seconds: %g\n", ((REAL)(tv[11] - tv[0])) / cps);
31163 }
31164
31165 if (b->docheck) {
31166 m.checkmesh(0);
31167 if (b->plc || b->refine) {
31168 m.checkshells();
31169 m.checksegments();
31170 }
31171 if (b->docheck > 1) {
31172 m.checkdelaunay();
31173 }
31174 }
31175
31176 if (!b->quiet) {
31177 m.statistics();
31178 }
31179}
31180
31181#ifndef TETLIBRARY
31182
31183///////////////////////////////////////////////////////////////////////////////
31184// //
31185// main() The command line interface of TetGen. //
31186// //
31187///////////////////////////////////////////////////////////////////////////////
31188
31189int main(int argc, char *argv[])
31190
31191#else // with TETLIBRARY
31192
31193///////////////////////////////////////////////////////////////////////////////
31194// //
31195// tetrahedralize() The library interface of TetGen. //
31196// //
31197///////////////////////////////////////////////////////////////////////////////
31198
31199void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
31200 tetgenio *addin, tetgenio *bgmin)
31201
31202#endif // not TETLIBRARY
31203
31204{
31205 tetgenbehavior b;
31206
31207#ifndef TETLIBRARY
31208
31209 tetgenio in, addin, bgmin;
31210
31211 if (!b.parse_commandline(argc, argv)) {
31212 terminatetetgen(NULL, 10);
31213 }
31214
31215 // Read input files.
31216 if (b.refine) { // -r
31217 if (!in.load_tetmesh(b.infilename, (int) b.object)) {
31218 terminatetetgen(NULL, 10);
31219 }
31220 } else { // -p
31221 if (!in.load_plc(b.infilename, (int) b.object)) {
31222 terminatetetgen(NULL, 10);
31223 }
31224 }
31225 if (b.insertaddpoints) { // -i
31226 // Try to read a .a.node file.
31227 addin.load_node(b.addinfilename);
31228 }
31229 if (b.metric) { // -m
31230 // Try to read a background mesh in files .b.node, .b.ele.
31231 bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
31232 }
31233
31234 tetrahedralize(&b, &in, NULL, &addin, &bgmin);
31235
31236 return 0;
31237
31238#else // with TETLIBRARY
31239
31240 if (!b.parse_commandline(switches)) {
31241 terminatetetgen(NULL, 10);
31242 }
31243 tetrahedralize(&b, in, out, addin, bgmin);
31244
31245#endif // not TETLIBRARY
31246}
31247
31248//// ////
31249//// ////
31250//// main_cxx /////////////////////////////////////////////////////////////////
31251
31252#ifdef _MSC_VER
31253# pragma warning(pop)
31254#endif
31255