gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
tetgenBR.cxx
Go to the documentation of this file.
1 // This file is part of Tetgen/BR, the Boundary Recovery code of TetGen
2 //
3 // Copyright 2015-2016 Weierstrass Institute for Applied Analysis and
4 // Stochastics
5 //
6 // This file is relicensed under the terms of LICENSE.txt for use in Gmsh thanks
7 // to a Software License Agreement between Weierstrass Institute for Applied
8 // Analysis and Stochastics and GMESH SPRL.
9 
11 // //
12 // TetGen //
13 // //
14 // A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator //
15 // //
16 // Version 1.5 //
17 // May 31, 2014 //
18 // //
19 // Copyright (C) 2002--2016 //
20 // //
21 // TetGen is freely available through the website: http://www.tetgen.org. //
22 // It may be copied, modified, and redistributed for non-commercial use. //
23 // Please consult the file LICENSE for the detailed copyright notices. //
24 // //
26 
27 // The following code of this file was automatically generated. Do not edit!
28 // TetGenBR -- The Boundary Recovery code of TetGen.
29 
31 // //
32 // parse_commandline() Read the command line, identify switches, and set //
33 // up options and file names. //
34 // //
35 // 'argc' and 'argv' are the same parameters passed to the function main() //
36 // of a C/C++ program. They together represent the command line user invoked //
37 // from an environment in which TetGen is running. //
38 // //
40 
41 bool tetgenbehavior::parse_commandline(int argc, char **argv)
42 {
43  int startindex;
44  int increment;
45  int meshnumber;
46  int i, j, k;
47  char workstring[1024];
48 
49  // First determine the input style of the switches.
50  if (argc == 0) {
51  startindex = 0; // Switches are given without a dash.
52  argc = 1; // For running the following for-loop once.
53  commandline[0] = '\0';
54  } else {
55  startindex = 1;
56  strcpy(commandline, argv[0]);
57  strcat(commandline, " ");
58  }
59 
60  for (i = startindex; i < argc; i++) {
61  // Remember the command line for output.
62  strcat(commandline, argv[i]);
63  strcat(commandline, " ");
64  if (startindex == 1) {
65  // Is this string a filename?
66  if (argv[i][0] != '-') {
67  strncpy(infilename, argv[i], 1024 - 1);
68  infilename[1024 - 1] = '\0';
69  continue;
70  }
71  }
72  // Parse the individual switch from the string.
73  for (j = startindex; argv[i][j] != '\0'; j++) {
74  if (argv[i][j] == 'p') {
75  plc = 1;
76  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
77  (argv[i][j + 1] == '.')) {
78  k = 0;
79  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
80  (argv[i][j + 1] == '.')) {
81  j++;
82  workstring[k] = argv[i][j];
83  k++;
84  }
85  workstring[k] = '\0';
86  facet_separate_ang_tol = (REAL) strtod(workstring, (char **) NULL);
87  }
88  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
89  j++;
90  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
91  (argv[i][j + 1] == '.')) {
92  k = 0;
93  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
94  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
95  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
96  j++;
97  workstring[k] = argv[i][j];
98  k++;
99  }
100  workstring[k] = '\0';
101  facet_overlap_ang_tol = (REAL) strtod(workstring, (char **) NULL);
102  }
103  }
104  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
105  j++;
106  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
107  (argv[i][j + 1] == '.')) {
108  k = 0;
109  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
110  (argv[i][j + 1] == '.')) {
111  j++;
112  workstring[k] = argv[i][j];
113  k++;
114  }
115  workstring[k] = '\0';
116  facet_small_ang_tol = (REAL) strtod(workstring, (char **) NULL);
117  }
118  }
119  } else if (argv[i][j] == 's') {
120  psc = 1;
121  } else if (argv[i][j] == 'Y') {
122  nobisect = 1;
123  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
124  nobisect_nomerge = (argv[i][j + 1] - '0');
125  j++;
126  }
127  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
128  j++;
129  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
130  supsteiner_level = (argv[i][j + 1] - '0');
131  j++;
132  }
133  }
134  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
135  j++;
136  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
137  addsteiner_algo = (argv[i][j + 1] - '0');
138  j++;
139  }
140  }
141  } else if (argv[i][j] == 'r') {
142  refine = 1;
143  } else if (argv[i][j] == 'q') {
144  quality = 1;
145  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
146  (argv[i][j + 1] == '.')) {
147  k = 0;
148  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
149  (argv[i][j + 1] == '.')) {
150  j++;
151  workstring[k] = argv[i][j];
152  k++;
153  }
154  workstring[k] = '\0';
155  minratio = (REAL) strtod(workstring, (char **) NULL);
156  }
157  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
158  j++;
159  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
160  (argv[i][j + 1] == '.')) {
161  k = 0;
162  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
163  (argv[i][j + 1] == '.')) {
164  j++;
165  workstring[k] = argv[i][j];
166  k++;
167  }
168  workstring[k] = '\0';
169  mindihedral = (REAL) strtod(workstring, (char **) NULL);
170  }
171  }
172  } else if (argv[i][j] == 'R') {
173  coarsen = 1;
174  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
175  coarsen_param = (argv[i][j + 1] - '0');
176  j++;
177  }
178  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
179  j++;
180  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
181  (argv[i][j + 1] == '.')) {
182  k = 0;
183  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
184  (argv[i][j + 1] == '.')) {
185  j++;
186  workstring[k] = argv[i][j];
187  k++;
188  }
189  workstring[k] = '\0';
190  coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
191  }
192  }
193  } else if (argv[i][j] == 'w') {
194  weighted = 1;
195  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
196  weighted_param = (argv[i][j + 1] - '0');
197  j++;
198  }
199  } else if (argv[i][j] == 'b') {
200  // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
201  brio_hilbert = 1;
202  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
203  (argv[i][j + 1] == '.')) {
204  k = 0;
205  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
206  (argv[i][j + 1] == '.')) {
207  j++;
208  workstring[k] = argv[i][j];
209  k++;
210  }
211  workstring[k] = '\0';
212  brio_threshold = (int) strtol(workstring, (char **) NULL, 0);
213  }
214  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
215  j++;
216  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
217  (argv[i][j + 1] == '.')) {
218  k = 0;
219  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
220  (argv[i][j + 1] == '.')) {
221  j++;
222  workstring[k] = argv[i][j];
223  k++;
224  }
225  workstring[k] = '\0';
226  brio_ratio = (REAL) strtod(workstring, (char **) NULL);
227  }
228  }
229  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
230  j++;
231  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
232  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
233  k = 0;
234  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
235  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
236  j++;
237  workstring[k] = argv[i][j];
238  k++;
239  }
240  workstring[k] = '\0';
241  hilbert_limit = (int) strtol(workstring, (char **) NULL, 0);
242  }
243  }
244  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
245  j++;
246  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
247  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
248  k = 0;
249  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
250  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
251  j++;
252  workstring[k] = argv[i][j];
253  k++;
254  }
255  workstring[k] = '\0';
256  hilbert_order = (REAL) strtod(workstring, (char **) NULL);
257  }
258  }
259  if (brio_threshold == 0) { // -b0
260  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
261  }
262  if (brio_ratio >= 1.0) { // -b/1
263  no_sort = 1;
264  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
265  }
266  } else if (argv[i][j] == 'l') {
267  incrflip = 1;
268  } else if (argv[i][j] == 'L') {
269  flipinsert = 1;
270  } else if (argv[i][j] == 'm') {
271  metric = 1;
272  } else if (argv[i][j] == 'a') {
273  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
274  (argv[i][j + 1] == '.')) {
275  fixedvolume = 1;
276  k = 0;
277  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
278  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
279  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
280  j++;
281  workstring[k] = argv[i][j];
282  k++;
283  }
284  workstring[k] = '\0';
285  maxvolume = (REAL) strtod(workstring, (char **) NULL);
286  } else {
287  varvolume = 1;
288  }
289  } else if (argv[i][j] == 'A') {
290  regionattrib = 1;
291  } else if (argv[i][j] == 'D') {
292  cdtrefine = 1;
293  if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
294  reflevel = (argv[i][j + 1] - '1') + 1;
295  j++;
296  }
297  } else if (argv[i][j] == 'i') {
298  insertaddpoints = 1;
299  } else if (argv[i][j] == 'd') {
300  diagnose = 1;
301  } else if (argv[i][j] == 'c') {
302  convex = 1;
303  } else if (argv[i][j] == 'M') {
304  nomergefacet = 1;
305  nomergevertex = 1;
306  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
307  nomergefacet = (argv[i][j + 1] - '0');
308  j++;
309  }
310  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
311  j++;
312  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
313  nomergevertex = (argv[i][j + 1] - '0');
314  j++;
315  }
316  }
317  } else if (argv[i][j] == 'X') {
318  if (argv[i][j + 1] == '1') {
319  nostaticfilter = 1;
320  j++;
321  } else {
322  noexact = 1;
323  }
324  } else if (argv[i][j] == 'z') {
325  if (argv[i][j + 1] == '1') { // -z1
326  reversetetori = 1;
327  j++;
328  } else {
329  zeroindex = 1; // -z
330  }
331  } else if (argv[i][j] == 'f') {
332  facesout++;
333  } else if (argv[i][j] == 'e') {
334  edgesout++;
335  } else if (argv[i][j] == 'n') {
336  neighout++;
337  } else if (argv[i][j] == 'v') {
338  voroout = 1;
339  } else if (argv[i][j] == 'g') {
340  meditview = 1;
341  } else if (argv[i][j] == 'k') {
342  vtkview = 1;
343  } else if (argv[i][j] == 'J') {
344  nojettison = 1;
345  } else if (argv[i][j] == 'B') {
346  nobound = 1;
347  } else if (argv[i][j] == 'N') {
348  nonodewritten = 1;
349  } else if (argv[i][j] == 'E') {
350  noelewritten = 1;
351  } else if (argv[i][j] == 'F') {
352  nofacewritten = 1;
353  } else if (argv[i][j] == 'I') {
354  noiterationnum = 1;
355  } else if (argv[i][j] == 'S') {
356  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
357  (argv[i][j + 1] == '.')) {
358  k = 0;
359  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
360  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
361  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
362  j++;
363  workstring[k] = argv[i][j];
364  k++;
365  }
366  workstring[k] = '\0';
367  steinerleft = (int) strtol(workstring, (char **) NULL, 0);
368  }
369  } else if (argv[i][j] == 'o') {
370  if (argv[i][j + 1] == '2') {
371  order = 2;
372  j++;
373  }
374  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
375  j++;
376  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
377  (argv[i][j + 1] == '.')) {
378  k = 0;
379  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
380  (argv[i][j + 1] == '.')) {
381  j++;
382  workstring[k] = argv[i][j];
383  k++;
384  }
385  workstring[k] = '\0';
386  optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
387  }
388  }
389  } else if (argv[i][j] == 'O') {
390  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
391  optlevel = (argv[i][j + 1] - '0');
392  j++;
393  }
394  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
395  j++;
396  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
397  optscheme = (argv[i][j + 1] - '0');
398  j++;
399  }
400  }
401  } else if (argv[i][j] == 'T') {
402  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
403  (argv[i][j + 1] == '.')) {
404  k = 0;
405  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
406  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
407  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
408  j++;
409  workstring[k] = argv[i][j];
410  k++;
411  }
412  workstring[k] = '\0';
413  epsilon = (REAL) strtod(workstring, (char **) NULL);
414  }
415  } else if (argv[i][j] == 'C') {
416  docheck++;
417  } else if (argv[i][j] == 'Q') {
418  quiet = 1;
419  } else if (argv[i][j] == 'V') {
420  verbose++;
421  } else if (argv[i][j] == 'x') {
422  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
423  (argv[i][j + 1] == '.')) {
424  k = 0;
425  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
426  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
427  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
428  j++;
429  workstring[k] = argv[i][j];
430  k++;
431  }
432  workstring[k] = '\0';
433  tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
434  if (tetrahedraperblock > 8188) {
437  } else {
438  tetrahedraperblock = 8188;
439  }
440  }
441  } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
442  (argv[i][j] == '?')) {
443  } else {
444  printf("Warning: Unknown switch -%c.\n", argv[i][j]);
445  }
446  }
447  }
448 
449  if (startindex == 0) {
450  // Set a temporary filename for debugging output.
451  strcpy(infilename, "tetgen-tmpfile");
452  } else {
453  if (infilename[0] == '\0') {
454  }
455  // Recognize the object from file extension if it is available.
456  if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
457  infilename[strlen(infilename) - 5] = '\0';
458  object = NODES;
459  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
460  infilename[strlen(infilename) - 5] = '\0';
461  object = POLY;
462  plc = 1;
463  } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
464  infilename[strlen(infilename) - 6] = '\0';
465  object = POLY;
466  plc = 1;
467  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
468  infilename[strlen(infilename) - 4] = '\0';
469  object = OFF;
470  plc = 1;
471  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
472  infilename[strlen(infilename) - 4] = '\0';
473  object = PLY;
474  plc = 1;
475  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
476  infilename[strlen(infilename) - 4] = '\0';
477  object = STL;
478  plc = 1;
479  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
480  infilename[strlen(infilename) - 5] = '\0';
481  object = MEDIT;
482  if (!refine) plc = 1;
483  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
484  infilename[strlen(infilename) - 4] = '\0';
485  object = VTK;
486  plc = 1;
487  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
488  infilename[strlen(infilename) - 4] = '\0';
489  object = MESH;
490  refine = 1;
491  }
492  }
493 
494  if (nobisect && (!plc && !refine)) { // -Y
495  plc = 1; // Default -p option.
496  }
497  if (quality && (!plc && !refine)) { // -q
498  plc = 1; // Default -p option.
499  }
500  if (diagnose && !plc) { // -d
501  plc = 1;
502  }
503  if (refine && !quality) { // -r only
504  // Reconstruct a mesh, no mesh optimization.
505  optlevel = 0;
506  }
507  if (insertaddpoints && (optlevel == 0)) { // with -i option
508  optlevel = 2;
509  }
510  if (coarsen && (optlevel == 0)) { // with -R option
511  optlevel = 2;
512  }
513 
514  // Detect improper combinations of switches.
515  if ((refine || plc) && weighted) {
516  printf("Error: Switches -w cannot use together with -p or -r.\n");
517  return false;
518  }
519 
520  if (convex) { // -c
521  if (plc && !regionattrib) {
522  // -A (region attribute) is needed for marking exterior tets (-1).
523  regionattrib = 1;
524  }
525  }
526 
527  // Note: -A must not used together with -r option.
528  // Be careful not to add an extra attribute to each element unless the
529  // input supports it (PLC in, but not refining a preexisting mesh).
530  if (refine || !plc) {
531  regionattrib = 0;
532  }
533  // Be careful not to allocate space for element area constraints that
534  // will never be assigned any value (other than the default -1.0).
535  if (!refine && !plc) {
536  varvolume = 0;
537  }
538  // If '-a' or '-aa' is in use, enable '-q' option too.
539  if (fixedvolume || varvolume) {
540  if (quality == 0) {
541  quality = 1;
542  if (!plc && !refine) {
543  plc = 1; // enable -p.
544  }
545  }
546  }
547  // No user-specified dihedral angle bound. Use default ones.
548  if (!quality) {
549  if (optmaxdihedral < 179.0) {
550  if (nobisect) { // with -Y option
551  optmaxdihedral = 179.0;
552  } else { // -p only
553  optmaxdihedral = 179.999;
554  }
555  }
556  if (optminsmtdihed < 179.999) {
557  optminsmtdihed = 179.999;
558  }
559  if (optminslidihed < 179.999) {
560  optminslidihed = 179.999;
561  }
562  }
563 
564  increment = 0;
565  strcpy(workstring, infilename);
566  j = 1;
567  while (workstring[j] != '\0') {
568  if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
569  increment = j + 1;
570  }
571  j++;
572  }
573  meshnumber = 0;
574  if (increment > 0) {
575  j = increment;
576  do {
577  if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
578  meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
579  } else {
580  increment = 0;
581  }
582  j++;
583  } while (workstring[j] != '\0');
584  }
585  if (noiterationnum) {
586  strcpy(outfilename, infilename);
587  } else if (increment == 0) {
588  strcpy(outfilename, infilename);
589  strcat(outfilename, ".1");
590  } else {
591  workstring[increment] = '%';
592  workstring[increment + 1] = 'd';
593  workstring[increment + 2] = '\0';
594  sprintf(outfilename, workstring, meshnumber + 1);
595  }
596  // Additional input file name has the end ".a".
597  strcpy(addinfilename, infilename);
598  strcat(addinfilename, ".a");
599  // Background filename has the form "*.b.ele", "*.b.node", ...
600  strcpy(bgmeshfilename, infilename);
601  strcat(bgmeshfilename, ".b");
602 
603  return true;
604 }
605 
609 
613 
614 // Initialize fast lookup tables for mesh maniplulation primitives.
615 
616 int tetgenmesh::bondtbl[12][12] = {{0,},};
617 int tetgenmesh::enexttbl[12] = {0,};
618 int tetgenmesh::eprevtbl[12] = {0,};
619 int tetgenmesh::enextesymtbl[12] = {0,};
620 int tetgenmesh::eprevesymtbl[12] = {0,};
621 int tetgenmesh::eorgoppotbl[12] = {0,};
622 int tetgenmesh::edestoppotbl[12] = {0,};
623 int tetgenmesh::fsymtbl[12][12] = {{0,},};
624 int tetgenmesh::facepivot1[12] = {0,};
625 int tetgenmesh::facepivot2[12][12] = {{0,},};
626 int tetgenmesh::tsbondtbl[12][6] = {{0,},};
627 int tetgenmesh::stbondtbl[12][6] = {{0,},};
628 int tetgenmesh::tspivottbl[12][6] = {{0,},};
629 int tetgenmesh::stpivottbl[12][6] = {{0,},};
630 
631 // Table 'esymtbl' takes an directed edge (version) as input, returns the
632 // inversed edge (version) of it.
633 
634 int tetgenmesh::esymtbl[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
635 
636 // The following four tables give the 12 permutations of the set {0,1,2,3}.
637 // An offset 4 is added to each element for a direct access of the points
638 // in the tetrahedron data structure.
639 
640 int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
641 int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
642 int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
643 int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
644 
645 // The twelve versions correspond to six undirected edges. The following two
646 // tables map a version to an undirected edge and vice versa.
647 
648 int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
649 int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
650 
651 // Edge versions whose apex or opposite may be dummypoint.
652 
653 int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
654 
655 
656 // Table 'snextpivot' takes an edge version as input, returns the next edge
657 // version in the same edge ring.
658 
659 int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
660 
661 // The following three tables give the 6 permutations of the set {0,1,2}.
662 // An offset 3 is added to each element for a direct access of the points
663 // in the triangle data structure.
664 
665 int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
666 int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
667 int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
668 
670 // //
671 // inittable() Initialize the look-up tables. //
672 // //
674 
676 {
677  int soffset, toffset;
678  int i, j;
679 
680 
681  // i = t1.ver; j = t2.ver;
682  for (i = 0; i < 12; i++) {
683  for (j = 0; j < 12; j++) {
684  bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
685  }
686  }
687 
688 
689  // i = t1.ver; j = t2.ver
690  for (i = 0; i < 12; i++) {
691  for (j = 0; j < 12; j++) {
692  fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
693  }
694  }
695 
696 
697  for (i = 0; i < 12; i++) {
698  facepivot1[i] = (esymtbl[i] & 3);
699  }
700 
701  for (i = 0; i < 12; i++) {
702  for (j = 0; j < 12; j++) {
703  facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
704  }
705  }
706 
707  for (i = 0; i < 12; i++) {
708  enexttbl[i] = (i + 4) % 12;
709  eprevtbl[i] = (i + 8) % 12;
710  }
711 
712  for (i = 0; i < 12; i++) {
713  enextesymtbl[i] = esymtbl[enexttbl[i]];
714  eprevesymtbl[i] = esymtbl[eprevtbl[i]];
715  }
716 
717  for (i = 0; i < 12; i++) {
720  }
721 
722  // i = t.ver, j = s.shver
723  for (i = 0; i < 12; i++) {
724  for (j = 0; j < 6; j++) {
725  if ((j & 1) == 0) {
726  soffset = (6 - ((i & 12) >> 1)) % 6;
727  toffset = (12 - ((j & 6) << 1)) % 12;
728  } else {
729  soffset = (i & 12) >> 1;
730  toffset = (j & 6) << 1;
731  }
732  tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
733  stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
734  }
735  }
736 
737 
738  // i = t.ver, j = s.shver
739  for (i = 0; i < 12; i++) {
740  for (j = 0; j < 6; j++) {
741  if ((j & 1) == 0) {
742  soffset = (i & 12) >> 1;
743  toffset = (j & 6) << 1;
744  } else {
745  soffset = (6 - ((i & 12) >> 1)) % 6;
746  toffset = (12 - ((j & 6) << 1)) % 12;
747  }
748  tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
749  stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
750  }
751  }
752 }
753 
754 
756 // //
757 // restart() Deallocate all objects in this pool. //
758 // //
759 // The pool returns to a fresh state, like after it was initialized, except //
760 // that no memory is freed to the operating system. Rather, the previously //
761 // allocated blocks are ready to be used. //
762 // //
764 
766 {
767  objects = 0l;
768 }
769 
771 // //
772 // poolinit() Initialize an arraypool for allocation of objects. //
773 // //
774 // Before the pool may be used, it must be initialized by this procedure. //
775 // After initialization, memory can be allocated and freed in this pool. //
776 // //
778 
779 void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
780 {
781  // Each object must be at least one byte long.
782  objectbytes = sizeofobject > 1 ? sizeofobject : 1;
783 
784  log2objectsperblock = log2objperblk;
785  // Compute the number of objects in each block.
786  objectsperblock = ((int) 1) << log2objectsperblock;
787  objectsperblockmark = objectsperblock - 1;
788 
789  // No memory has been allocated.
790  totalmemory = 0l;
791  // The top array has not been allocated yet.
792  toparray = (char **) NULL;
793  toparraylen = 0;
794 
795  // Ready all indices to be allocated.
796  restart();
797 }
798 
800 // //
801 // arraypool() The constructor and destructor. //
802 // //
804 
805 tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
806 {
807  poolinit(sizeofobject, log2objperblk);
808 }
809 
811 {
812  int i;
813 
814  // Has anything been allocated at all?
815  if (toparray != (char **) NULL) {
816  // Walk through the top array.
817  for (i = 0; i < toparraylen; i++) {
818  // Check every pointer; NULLs may be scattered randomly.
819  if (toparray[i] != (char *) NULL) {
820  // Free an allocated block.
821  free((void *) toparray[i]);
822  }
823  }
824  // Free the top array.
825  free((void *) toparray);
826  }
827 
828  // The top array is no longer allocated.
829  toparray = (char **) NULL;
830  toparraylen = 0;
831  objects = 0;
832  totalmemory = 0;
833 }
834 
836 // //
837 // getblock() Return (and perhaps create) the block containing the object //
838 // with a given index. //
839 // //
840 // This function takes care of allocating or resizing the top array if nece- //
841 // ssary, and of allocating the block if it hasn't yet been allocated. //
842 // //
843 // Return a pointer to the beginning of the block (NOT the object). //
844 // //
846 
847 char* tetgenmesh::arraypool::getblock(int objectindex)
848 {
849  char **newarray;
850  char *block;
851  int newsize;
852  int topindex;
853  int i;
854 
855  // Compute the index in the top array (upper bits).
856  topindex = objectindex >> log2objectsperblock;
857  // Does the top array need to be allocated or resized?
858  if (toparray == (char **) NULL) {
859  // Allocate the top array big enough to hold 'topindex', and NULL out
860  // its contents.
861  newsize = topindex + 128;
862  toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
863  toparraylen = newsize;
864  for (i = 0; i < newsize; i++) {
865  toparray[i] = (char *) NULL;
866  }
867  // Account for the memory.
868  totalmemory = newsize * (uintptr_t) sizeof(char *);
869  } else if (topindex >= toparraylen) {
870  // Resize the top array, making sure it holds 'topindex'.
871  newsize = 3 * toparraylen;
872  if (topindex >= newsize) {
873  newsize = topindex + 128;
874  }
875  // Allocate the new array, copy the contents, NULL out the rest, and
876  // free the old array.
877  newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
878  for (i = 0; i < toparraylen; i++) {
879  newarray[i] = toparray[i];
880  }
881  for (i = toparraylen; i < newsize; i++) {
882  newarray[i] = (char *) NULL;
883  }
884  free(toparray);
885  // Account for the memory.
886  totalmemory += (newsize - toparraylen) * sizeof(char *);
887  toparray = newarray;
888  toparraylen = newsize;
889  }
890 
891  // Find the block, or learn that it hasn't been allocated yet.
892  block = toparray[topindex];
893  if (block == (char *) NULL) {
894  // Allocate a block at this index.
895  block = (char *) malloc((size_t) (objectsperblock * objectbytes));
896  toparray[topindex] = block;
897  // Account for the memory.
898  totalmemory += objectsperblock * objectbytes;
899  }
900 
901  // Return a pointer to the block.
902  return block;
903 }
904 
906 // //
907 // lookup() Return the pointer to the object with a given index, or NULL //
908 // if the object's block doesn't exist yet. //
909 // //
911 
912 void* tetgenmesh::arraypool::lookup(int objectindex)
913 {
914  char *block;
915  int topindex;
916 
917  // Has the top array been allocated yet?
918  if (toparray == (char **) NULL) {
919  return (void *) NULL;
920  }
921 
922  // Compute the index in the top array (upper bits).
923  topindex = objectindex >> log2objectsperblock;
924  // Does the top index fit in the top array?
925  if (topindex >= toparraylen) {
926  return (void *) NULL;
927  }
928 
929  // Find the block, or learn that it hasn't been allocated yet.
930  block = toparray[topindex];
931  if (block == (char *) NULL) {
932  return (void *) NULL;
933  }
934 
935  // Compute a pointer to the object with the given index. Note that
936  // 'objectsperblock' is a power of two, so the & operation is a bit mask
937  // that preserves the lower bits.
938  return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
939 }
940 
942 // //
943 // newindex() Allocate space for a fresh object from the pool. //
944 // //
945 // 'newptr' returns a pointer to the new object (it must not be a NULL). //
946 // //
948 
950 {
951  // Allocate an object at index 'firstvirgin'.
952  int newindex = objects;
953  *newptr = (void *) (getblock(objects) +
954  (objects & (objectsperblock - 1)) * objectbytes);
955  objects++;
956 
957  return newindex;
958 }
959 
960 
962 // //
963 // memorypool() The constructors of memorypool. //
964 // //
966 
968 {
969  firstblock = nowblock = (void **) NULL;
970  nextitem = (void *) NULL;
971  deaditemstack = (void *) NULL;
972  pathblock = (void **) NULL;
973  pathitem = (void *) NULL;
974  alignbytes = 0;
975  itembytes = itemwords = 0;
976  itemsperblock = 0;
977  items = maxitems = 0l;
978  unallocateditems = 0;
979  pathitemsleft = 0;
980 }
981 
982 tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize,
983  int alignment)
984 {
985  poolinit(bytecount, itemcount, wsize, alignment);
986 }
987 
989 // //
990 // ~memorypool() Free to the operating system all memory taken by a pool. //
991 // //
993 
995 {
996  while (firstblock != (void **) NULL) {
997  nowblock = (void **) *(firstblock);
998  free(firstblock);
999  firstblock = nowblock;
1000  }
1001 }
1002 
1004 // //
1005 // poolinit() Initialize a pool of memory for allocation of items. //
1006 // //
1007 // A `pool' is created whose records have size at least `bytecount'. Items //
1008 // will be allocated in `itemcount'-item blocks. Each item is assumed to be //
1009 // a collection of words, and either pointers or floating-point values are //
1010 // assumed to be the "primary" word type. (The "primary" word type is used //
1011 // to determine alignment of items.) If `alignment' isn't zero, all items //
1012 // will be `alignment'-byte aligned in memory. `alignment' must be either a //
1013 // multiple or a factor of the primary word size; powers of two are safe. //
1014 // `alignment' is normally used to create a few unused bits at the bottom of //
1015 // each item's pointer, in which information may be stored. //
1016 // //
1018 
1019 void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
1020  int alignment)
1021 {
1022  // Find the proper alignment, which must be at least as large as:
1023  // - The parameter `alignment'.
1024  // - The primary word type, to avoid unaligned accesses.
1025  // - sizeof(void *), so the stack of dead items can be maintained
1026  // without unaligned accesses.
1027  if (alignment > wordsize) {
1028  alignbytes = alignment;
1029  } else {
1030  alignbytes = wordsize;
1031  }
1032  if ((int) sizeof(void *) > alignbytes) {
1033  alignbytes = (int) sizeof(void *);
1034  }
1035  itemwords = ((bytecount + alignbytes - 1) / alignbytes)
1036  * (alignbytes / wordsize);
1037  itembytes = itemwords * wordsize;
1038  itemsperblock = itemcount;
1039 
1040  // Allocate a block of items. Space for `itemsperblock' items and one
1041  // pointer (to point to the next block) are allocated, as well as space
1042  // to ensure alignment of the items.
1043  firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
1044  + alignbytes);
1045  if (firstblock == (void **) NULL) {
1046  terminatetetgen(NULL, 1);
1047  }
1048  // Set the next block pointer to NULL.
1049  *(firstblock) = (void *) NULL;
1050  restart();
1051 }
1052 
1054 // //
1055 // restart() Deallocate all items in this pool. //
1056 // //
1057 // The pool is returned to its starting state, except that no memory is //
1058 // freed to the operating system. Rather, the previously allocated blocks //
1059 // are ready to be reused. //
1060 // //
1062 
1064 {
1065  uintptr_t alignptr;
1066 
1067  items = 0;
1068  maxitems = 0;
1069 
1070  // Set the currently active block.
1071  nowblock = firstblock;
1072  // Find the first item in the pool. Increment by the size of (void *).
1073  alignptr = (uintptr_t) (nowblock + 1);
1074  // Align the item on an `alignbytes'-byte boundary.
1075  nextitem = (void *)
1076  (alignptr + (uintptr_t) alignbytes -
1077  (alignptr % (uintptr_t) alignbytes));
1078  // There are lots of unallocated items left in this block.
1079  unallocateditems = itemsperblock;
1080  // The stack of deallocated items is empty.
1081  deaditemstack = (void *) NULL;
1082 }
1083 
1085 // //
1086 // alloc() Allocate space for an item. //
1087 // //
1089 
1091 {
1092  void *newitem;
1093  void **newblock;
1094  uintptr_t alignptr;
1095 
1096  // First check the linked list of dead items. If the list is not
1097  // empty, allocate an item from the list rather than a fresh one.
1098  if (deaditemstack != (void *) NULL) {
1099  newitem = deaditemstack; // Take first item in list.
1100  deaditemstack = * (void **) deaditemstack;
1101  } else {
1102  // Check if there are any free items left in the current block.
1103  if (unallocateditems == 0) {
1104  // Check if another block must be allocated.
1105  if (*nowblock == (void *) NULL) {
1106  // Allocate a new block of items, pointed to by the previous block.
1107  newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
1108  + alignbytes);
1109  if (newblock == (void **) NULL) {
1110  terminatetetgen(NULL, 1);
1111  }
1112  *nowblock = (void *) newblock;
1113  // The next block pointer is NULL.
1114  *newblock = (void *) NULL;
1115  }
1116  // Move to the new block.
1117  nowblock = (void **) *nowblock;
1118  // Find the first item in the block.
1119  // Increment by the size of (void *).
1120  alignptr = (uintptr_t) (nowblock + 1);
1121  // Align the item on an `alignbytes'-byte boundary.
1122  nextitem = (void *)
1123  (alignptr + (uintptr_t) alignbytes -
1124  (alignptr % (uintptr_t) alignbytes));
1125  // There are lots of unallocated items left in this block.
1126  unallocateditems = itemsperblock;
1127  }
1128  // Allocate a new item.
1129  newitem = nextitem;
1130  // Advance `nextitem' pointer to next free item in block.
1131  nextitem = (void *) ((uintptr_t) nextitem + itembytes);
1132  unallocateditems--;
1133  maxitems++;
1134  }
1135  items++;
1136  return newitem;
1137 }
1138 
1140 // //
1141 // dealloc() Deallocate space for an item. //
1142 // //
1143 // The deallocated space is stored in a queue for later reuse. //
1144 // //
1146 
1147 void tetgenmesh::memorypool::dealloc(void *dyingitem)
1148 {
1149  // Push freshly killed item onto stack.
1150  *((void **) dyingitem) = deaditemstack;
1151  deaditemstack = dyingitem;
1152  items--;
1153 }
1154 
1156 // //
1157 // traversalinit() Prepare to traverse the entire list of items. //
1158 // //
1159 // This routine is used in conjunction with traverse(). //
1160 // //
1162 
1164 {
1165  uintptr_t alignptr;
1166 
1167  // Begin the traversal in the first block.
1168  pathblock = firstblock;
1169  // Find the first item in the block. Increment by the size of (void *).
1170  alignptr = (uintptr_t) (pathblock + 1);
1171  // Align with item on an `alignbytes'-byte boundary.
1172  pathitem = (void *)
1173  (alignptr + (uintptr_t) alignbytes -
1174  (alignptr % (uintptr_t) alignbytes));
1175  // Set the number of items left in the current block.
1176  pathitemsleft = itemsperblock;
1177 }
1178 
1180 // //
1181 // traverse() Find the next item in the list. //
1182 // //
1183 // This routine is used in conjunction with traversalinit(). Be forewarned //
1184 // that this routine successively returns all items in the list, including //
1185 // deallocated ones on the deaditemqueue. It's up to you to figure out which //
1186 // ones are actually dead. It can usually be done more space-efficiently by //
1187 // a routine that knows something about the structure of the item. //
1188 // //
1190 
1192 {
1193  void *newitem;
1194  uintptr_t alignptr;
1195 
1196  // Stop upon exhausting the list of items.
1197  if (pathitem == nextitem) {
1198  return (void *) NULL;
1199  }
1200  // Check whether any untraversed items remain in the current block.
1201  if (pathitemsleft == 0) {
1202  // Find the next block.
1203  pathblock = (void **) *pathblock;
1204  // Find the first item in the block. Increment by the size of (void *).
1205  alignptr = (uintptr_t) (pathblock + 1);
1206  // Align with item on an `alignbytes'-byte boundary.
1207  pathitem = (void *)
1208  (alignptr + (uintptr_t) alignbytes -
1209  (alignptr % (uintptr_t) alignbytes));
1210  // Set the number of items left in the current block.
1211  pathitemsleft = itemsperblock;
1212  }
1213  newitem = pathitem;
1214  // Find the next item in the block.
1215  pathitem = (void *) ((uintptr_t) pathitem + itembytes);
1216  pathitemsleft--;
1217  return newitem;
1218 }
1219 
1221 // //
1222 // makeindex2pointmap() Create a map from index to vertices. //
1223 // //
1224 // 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
1225 // to each vertex is set into the array. The pointer to the first vertex is //
1226 // saved in 'idx2verlist[in->firstnumber]'. //
1227 // //
1229 
1231 {
1232  point pointloop;
1233  int idx;
1234 
1235  if (b->verbose > 1) {
1236  printf(" Constructing mapping from indices to points.\n");
1237  }
1238 
1239  idx2verlist = new point[points->items + 1];
1240 
1241  points->traversalinit();
1242  pointloop = pointtraverse();
1243  idx = in->firstnumber;
1244  while (pointloop != (point) NULL) {
1245  idx2verlist[idx++] = pointloop;
1246  pointloop = pointtraverse();
1247  }
1248 }
1249 
1251 // //
1252 // makesubfacemap() Create a map from vertex to subfaces incident at it. //
1253 // //
1254 // The map is returned in two arrays 'idx2faclist' and 'facperverlist'. All //
1255 // subfaces incident at i-th vertex (i is counted from 0) are found in the //
1256 // array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1]. //
1257 // Each entry in facperverlist[j] is a subface whose origin is the vertex. //
1258 // //
1259 // NOTE: These two arrays will be created inside this routine, don't forget //
1260 // to free them after using. //
1261 // //
1263 
1264 void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
1265  face*& facperverlist)
1266 {
1267  face shloop;
1268  int i, j, k;
1269 
1270  if (b->verbose > 1) {
1271  printf(" Making a map from points to subfaces.\n");
1272  }
1273 
1274  // Initialize 'idx2faclist'.
1275  idx2faclist = new int[points->items + 1];
1276  for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
1277 
1278  // Loop all subfaces, counter the number of subfaces incident at a vertex.
1279  pool->traversalinit();
1280  shloop.sh = shellfacetraverse(pool);
1281  while (shloop.sh != (shellface *) NULL) {
1282  // Increment the number of incident subfaces for each vertex.
1283  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
1284  idx2faclist[j]++;
1285  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
1286  idx2faclist[j]++;
1287  // Skip the third corner if it is a segment.
1288  if (shloop.sh[5] != NULL) {
1289  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
1290  idx2faclist[j]++;
1291  }
1292  shloop.sh = shellfacetraverse(pool);
1293  }
1294 
1295  // Calculate the total length of array 'facperverlist'.
1296  j = idx2faclist[0];
1297  idx2faclist[0] = 0; // Array starts from 0 element.
1298  for (i = 0; i < points->items; i++) {
1299  k = idx2faclist[i + 1];
1300  idx2faclist[i + 1] = idx2faclist[i] + j;
1301  j = k;
1302  }
1303 
1304  // The total length is in the last unit of idx2faclist.
1305  facperverlist = new face[idx2faclist[i]];
1306 
1307  // Loop all subfaces again, remember the subfaces at each vertex.
1308  pool->traversalinit();
1309  shloop.sh = shellfacetraverse(pool);
1310  while (shloop.sh != (shellface *) NULL) {
1311  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
1312  shloop.shver = 0; // save the origin.
1313  facperverlist[idx2faclist[j]] = shloop;
1314  idx2faclist[j]++;
1315  // Is it a subface or a subsegment?
1316  if (shloop.sh[5] != NULL) {
1317  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
1318  shloop.shver = 2; // save the origin.
1319  facperverlist[idx2faclist[j]] = shloop;
1320  idx2faclist[j]++;
1321  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
1322  shloop.shver = 4; // save the origin.
1323  facperverlist[idx2faclist[j]] = shloop;
1324  idx2faclist[j]++;
1325  } else {
1326  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
1327  shloop.shver = 1; // save the origin.
1328  facperverlist[idx2faclist[j]] = shloop;
1329  idx2faclist[j]++;
1330  }
1331  shloop.sh = shellfacetraverse(pool);
1332  }
1333 
1334  // Contents in 'idx2faclist' are shifted, now shift them back.
1335  for (i = points->items - 1; i >= 0; i--) {
1336  idx2faclist[i + 1] = idx2faclist[i];
1337  }
1338  idx2faclist[0] = 0;
1339 }
1340 
1342 // //
1343 // tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
1344 // //
1346 
1348 {
1349  // Set tetrahedron's vertices to NULL. This makes it possible to detect
1350  // dead tetrahedra when traversing the list of all tetrahedra.
1351  dyingtetrahedron[4] = (tetrahedron) NULL;
1352 
1353  // Dealloc the space to subfaces/subsegments.
1354  if (dyingtetrahedron[8] != NULL) {
1355  tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
1356  }
1357  if (dyingtetrahedron[9] != NULL) {
1358  tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
1359  }
1360 
1361  tetrahedrons->dealloc((void *) dyingtetrahedron);
1362 }
1363 
1365 // //
1366 // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
1367 // //
1369 
1371 {
1372  tetrahedron *newtetrahedron;
1373 
1374  do {
1375  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
1376  if (newtetrahedron == (tetrahedron *) NULL) {
1377  return (tetrahedron *) NULL;
1378  }
1379  } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
1380  ((point) newtetrahedron[7] == dummypoint));
1381  return newtetrahedron;
1382 }
1383 
1385 {
1386  tetrahedron *newtetrahedron;
1387 
1388  do {
1389  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
1390  if (newtetrahedron == (tetrahedron *) NULL) {
1391  return (tetrahedron *) NULL;
1392  }
1393  } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
1394  return newtetrahedron;
1395 }
1396 
1398 // //
1399 // shellfacedealloc() Deallocate space for a shellface, marking it dead. //
1400 // Used both for dealloc a subface and subsegment. //
1401 // //
1403 
1405 {
1406  // Set shellface's vertices to NULL. This makes it possible to detect dead
1407  // shellfaces when traversing the list of all shellfaces.
1408  dyingsh[3] = (shellface) NULL;
1409  pool->dealloc((void *) dyingsh);
1410 }
1411 
1413 // //
1414 // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
1415 // for both subfaces and subsegments pool traverse. //
1416 // //
1418 
1420 {
1421  shellface *newshellface;
1422 
1423  do {
1424  newshellface = (shellface *) pool->traverse();
1425  if (newshellface == (shellface *) NULL) {
1426  return (shellface *) NULL;
1427  }
1428  } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
1429  return newshellface;
1430 }
1431 
1432 
1434 // //
1435 // pointdealloc() Deallocate space for a point, marking it dead. //
1436 // //
1438 
1440 {
1441  // Mark the point as dead. This makes it possible to detect dead points
1442  // when traversing the list of all points.
1443  setpointtype(dyingpoint, DEADVERTEX);
1444  points->dealloc((void *) dyingpoint);
1445 }
1446 
1448 // //
1449 // pointtraverse() Traverse the points, skipping dead ones. //
1450 // //
1452 
1454 {
1455  point newpoint;
1456 
1457  do {
1458  newpoint = (point) points->traverse();
1459  if (newpoint == (point) NULL) {
1460  return (point) NULL;
1461  }
1462  } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
1463  return newpoint;
1464 }
1465 
1467 // //
1468 // maketetrahedron() Create a new tetrahedron. //
1469 // //
1471 
1473 {
1474  newtet->tet = (tetrahedron *) tetrahedrons->alloc();
1475 
1476  // Initialize the four adjoining tetrahedra to be "outer space".
1477  newtet->tet[0] = NULL;
1478  newtet->tet[1] = NULL;
1479  newtet->tet[2] = NULL;
1480  newtet->tet[3] = NULL;
1481  // Four NULL vertices.
1482  newtet->tet[4] = NULL;
1483  newtet->tet[5] = NULL;
1484  newtet->tet[6] = NULL;
1485  newtet->tet[7] = NULL;
1486  // No attached segments and subfaces yet.
1487  newtet->tet[8] = NULL;
1488  newtet->tet[9] = NULL;
1489  // Initialize the marker (clear all flags).
1490  setelemmarker(newtet->tet, 0);
1491  for (int i = 0; i < numelemattrib; i++) {
1492  setelemattribute(newtet->tet, i, 0.0);
1493  }
1494  if (b->varvolume) {
1495  setvolumebound(newtet->tet, -1.0);
1496  }
1497 
1498  // Initialize the version to be Zero.
1499  newtet->ver = 11;
1500 }
1501 
1503 // //
1504 // makeshellface() Create a new shellface with version zero. Used for //
1505 // both subfaces and subsegments. //
1506 // //
1508 
1510 {
1511  newface->sh = (shellface *) pool->alloc();
1512 
1513  // No adjointing subfaces.
1514  newface->sh[0] = NULL;
1515  newface->sh[1] = NULL;
1516  newface->sh[2] = NULL;
1517  // Three NULL vertices.
1518  newface->sh[3] = NULL;
1519  newface->sh[4] = NULL;
1520  newface->sh[5] = NULL;
1521  // No adjoining subsegments.
1522  newface->sh[6] = NULL;
1523  newface->sh[7] = NULL;
1524  newface->sh[8] = NULL;
1525  // No adjoining tetrahedra.
1526  newface->sh[9] = NULL;
1527  newface->sh[10] = NULL;
1528  if (checkconstraints) {
1529  // Initialize the maximum area bound.
1530  setareabound(*newface, 0.0);
1531  }
1532  // Set the boundary marker to zero.
1533  setshellmark(*newface, 0);
1534  // Clear the infection and marktest bits.
1535  ((int *) (newface->sh))[shmarkindex + 1] = 0;
1536  if (useinsertradius) {
1537  setfacetindex(*newface, 0);
1538  }
1539 
1540  newface->shver = 0;
1541 }
1542 
1544 // //
1545 // makepoint() Create a new point. //
1546 // //
1548 
1549 void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
1550 {
1551  int i;
1552 
1553  *pnewpoint = (point) points->alloc();
1554 
1555  // Initialize the point attributes.
1556  for (i = 0; i < numpointattrib; i++) {
1557  (*pnewpoint)[3 + i] = 0.0;
1558  }
1559  // Initialize the metric tensor.
1560  for (i = 0; i < sizeoftensor; i++) {
1561  (*pnewpoint)[pointmtrindex + i] = 0.0;
1562  }
1563  setpoint2tet(*pnewpoint, NULL);
1564  setpoint2ppt(*pnewpoint, NULL);
1565  if (b->plc || b->refine) {
1566  // Initialize the point-to-simplex field.
1567  setpoint2sh(*pnewpoint, NULL);
1568  if (b->metric && (bgm != NULL)) {
1569  setpoint2bgmtet(*pnewpoint, NULL);
1570  }
1571  }
1572  // Initialize the point marker (starting from in->firstnumber).
1573  setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
1574  // Clear all flags.
1575  ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
1576  // Initialize (set) the point type.
1577  setpointtype(*pnewpoint, vtype);
1578 }
1579 
1581 // //
1582 // initializepools() Calculate the sizes of the point, tetrahedron, and //
1583 // subface. Initialize their memory pools. //
1584 // //
1585 // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
1586 // 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'. They are //
1587 // used to find values within each point and tetrahedron, respectively. //
1588 // //
1590 
1592 {
1593  int pointsize = 0, elesize = 0, shsize = 0;
1594  int i;
1595 
1596  if (b->verbose) {
1597  printf(" Initializing memorypools.\n");
1598  printf(" tetrahedron per block: %d.\n", b->tetrahedraperblock);
1599  }
1600 
1601  inittables();
1602 
1603  // There are three input point lists available, which are in, addin,
1604  // and bgm->in. These point lists may have different number of
1605  // attributes. Decide the maximum number.
1606  numpointattrib = in->numberofpointattributes;
1607  if (bgm != NULL) {
1608  if (bgm->in->numberofpointattributes > numpointattrib) {
1609  numpointattrib = bgm->in->numberofpointattributes;
1610  }
1611  }
1612  if (addin != NULL) {
1613  if (addin->numberofpointattributes > numpointattrib) {
1614  numpointattrib = addin->numberofpointattributes;
1615  }
1616  }
1617  if (b->weighted || b->flipinsert) { // -w or -L.
1618  // The internal number of point attribute needs to be at least 1
1619  // (for storing point weights).
1620  if (numpointattrib == 0) {
1621  numpointattrib = 1;
1622  }
1623  }
1624 
1625  // Default varconstraint = 0;
1626  if (in->segmentconstraintlist || in->facetconstraintlist) {
1627  checkconstraints = 1;
1628  }
1629  if (b->plc || b->refine) {
1630  // Save the insertion radius for Steiner points if boundaries
1631  // are allowed be split.
1632  if (!b->nobisect || checkconstraints) {
1633  useinsertradius = 1;
1634  }
1635  }
1636 
1637  // The index within each point at which its metric tensor is found.
1638  // Each vertex has three coordinates.
1639  if (b->psc) {
1640  // '-s' option (PSC), the u,v coordinates are provided.
1642  // The index within each point at which its u, v coordinates are found.
1643  // Comment: They are saved after the list of point attributes.
1645  } else {
1647  }
1648  // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
1649  if (b->metric) {
1650  // Decide the size (1, 3, or 6) of the metric tensor.
1651  if (bgm != (tetgenmesh *) NULL) {
1652  // A background mesh is allocated. It may not exist though.
1653  sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
1654  bgm->in->numberofpointmtrs : in->numberofpointmtrs;
1655  } else {
1656  // No given background mesh - Itself is a background mesh.
1657  sizeoftensor = in->numberofpointmtrs;
1658  }
1659  // Make sure sizeoftensor is at least 1.
1660  sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
1661  } else {
1662  // For '-q' option. Make sure to have space for saving a scalar value.
1663  sizeoftensor = b->quality ? 1 : 0;
1664  }
1665  if (useinsertradius) {
1666  // Increase a space (REAL) for saving point insertion radius, it is
1667  // saved directly after the metric.
1668  sizeoftensor++;
1669  }
1671  // The index within each point at which an element pointer is found, where
1672  // the index is measured in pointers. Ensure the index is aligned to a
1673  // sizeof(tetrahedron)-byte address.
1675  + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
1676  if (b->plc || b->refine || b->voroout) {
1677  // Increase the point size by three pointers, which are:
1678  // - a pointer to a tet, read by point2tet();
1679  // - a pointer to a parent point, read by point2ppt()).
1680  // - a pointer to a subface or segment, read by point2sh();
1681  if (b->metric && (bgm != (tetgenmesh *) NULL)) {
1682  // Increase one pointer into the background mesh, point2bgmtet().
1683  pointsize = (point2simindex + 4) * sizeof(tetrahedron);
1684  } else {
1685  pointsize = (point2simindex + 3) * sizeof(tetrahedron);
1686  }
1687  } else {
1688  // Increase the point size by two pointer, which are:
1689  // - a pointer to a tet, read by point2tet();
1690  // - a pointer to a parent point, read by point2ppt()). -- Used by btree.
1691  pointsize = (point2simindex + 2) * sizeof(tetrahedron);
1692  }
1693  // The index within each point at which the boundary marker is found,
1694  // Ensure the point marker is aligned to a sizeof(int)-byte address.
1695  pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
1696  // Now point size is the ints (indicated by pointmarkindex) plus:
1697  // - an integer for boundary marker;
1698  // - an integer for vertex type;
1699  // - an integer for geometry tag (optional, -s option).
1700  pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
1701 
1702  // Initialize the pool of vertices.
1703  points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
1704 
1705  if (b->verbose) {
1706  printf(" Size of a point: %d bytes.\n", points->itembytes);
1707  }
1708 
1709  // Initialize the infinite vertex.
1710  dummypoint = (point) new char[pointsize];
1711  // Initialize all fields of this point.
1712  dummypoint[0] = 0.0;
1713  dummypoint[1] = 0.0;
1714  dummypoint[2] = 0.0;
1715  for (i = 0; i < numpointattrib; i++) {
1716  dummypoint[3 + i] = 0.0;
1717  }
1718  // Initialize the metric tensor.
1719  for (i = 0; i < sizeoftensor; i++) {
1720  dummypoint[pointmtrindex + i] = 0.0;
1721  }
1722  setpoint2tet(dummypoint, NULL);
1723  setpoint2ppt(dummypoint, NULL);
1724  if (b->plc || b->psc || b->refine) {
1725  // Initialize the point-to-simplex field.
1726  setpoint2sh(dummypoint, NULL);
1727  if (b->metric && (bgm != NULL)) {
1728  setpoint2bgmtet(dummypoint, NULL);
1729  }
1730  }
1731  // Initialize the point marker (starting from in->firstnumber).
1732  setpointmark(dummypoint, -1); // The unique marker for dummypoint.
1733  // Clear all flags.
1734  ((int *) (dummypoint))[pointmarkindex + 1] = 0;
1735  // Initialize (set) the point type.
1736  setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
1737 
1738  // The number of bytes occupied by a tetrahedron is varying by the user-
1739  // specified options. The contents of the first 12 pointers are listed
1740  // in the following table:
1741  // [0] |__ neighbor at f0 __|
1742  // [1] |__ neighbor at f1 __|
1743  // [2] |__ neighbor at f2 __|
1744  // [3] |__ neighbor at f3 __|
1745  // [4] |_____ vertex p0 ____|
1746  // [5] |_____ vertex p1 ____|
1747  // [6] |_____ vertex p2 ____|
1748  // [7] |_____ vertex p3 ____|
1749  // [8] |__ segments array __| (used by -p)
1750  // [9] |__ subfaces array __| (used by -p)
1751  // [10] |_____ reserved _____|
1752  // [11] |___ elem marker ____| (used as an integer)
1753 
1754  elesize = 12 * sizeof(tetrahedron);
1755 
1756  // The index to find the element markers. An integer containing varies
1757  // flags and element counter.
1758  if (!(sizeof(int) <= sizeof(tetrahedron)) ||
1759  ((sizeof(tetrahedron) % sizeof(int)))) {
1760  terminatetetgen(this, 2);
1761  }
1762  elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
1763 
1764  // The actual number of element attributes. Note that if the
1765  // `b->regionattrib' flag is set, an additional attribute will be added.
1766  numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
1767 
1768  // The index within each element at which its attributes are found, where
1769  // the index is measured in REALs.
1770  elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
1771  // The index within each element at which the maximum volume bound is
1772  // found, where the index is measured in REALs.
1774  // If element attributes or an constraint are needed, increase the number
1775  // of bytes occupied by an element.
1776  if (b->varvolume) {
1777  elesize = (volumeboundindex + 1) * sizeof(REAL);
1778  } else if (numelemattrib > 0) {
1779  elesize = volumeboundindex * sizeof(REAL);
1780  }
1781 
1782 
1783  // Having determined the memory size of an element, initialize the pool.
1784  tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
1785  16);
1786 
1787  if (b->verbose) {
1788  printf(" Size of a tetrahedron: %d (%d) bytes.\n", elesize,
1790  }
1791 
1792  if (b->plc || b->refine) { // if (b->useshelles) {
1793  // The number of bytes occupied by a subface. The list of pointers
1794  // stored in a subface are: three to other subfaces, three to corners,
1795  // three to subsegments, two to tetrahedra.
1796  shsize = 11 * sizeof(shellface);
1797  // The index within each subface at which the maximum area bound is
1798  // found, where the index is measured in REALs.
1799  areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
1800  // If -q switch is in use, increase the number of bytes occupied by
1801  // a subface for saving maximum area bound.
1802  if (checkconstraints) {
1803  shsize = (areaboundindex + 1) * sizeof(REAL);
1804  } else {
1805  shsize = areaboundindex * sizeof(REAL);
1806  }
1807  // The index within subface at which the facet marker is found. Ensure
1808  // the marker is aligned to a sizeof(int)-byte address.
1809  shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
1810  // Increase the number of bytes by two or three integers, one for facet
1811  // marker, one for shellface type and flags, and optionally one
1812  // for storing facet index (for mesh refinement).
1813  shsize = (shmarkindex + 2 + useinsertradius) * sizeof(shellface);
1814 
1815  // Initialize the pool of subfaces. Each subface record is eight-byte
1816  // aligned so it has room to store an edge version (from 0 to 5) in
1817  // the least three bits.
1818  subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
1819 
1820  if (b->verbose) {
1821  printf(" Size of a shellface: %d (%d) bytes.\n", shsize,
1822  subfaces->itembytes);
1823  }
1824 
1825  // Initialize the pool of subsegments. The subsegment's record is same
1826  // with subface.
1827  subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
1828 
1829  // Initialize the pool for tet-subseg connections.
1830  tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock,
1831  sizeof(void *), 0);
1832  // Initialize the pool for tet-subface connections.
1833  tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock,
1834  sizeof(void *), 0);
1835 
1836  // Initialize arraypools for segment & facet recovery.
1837  subsegstack = new arraypool(sizeof(face), 10);
1838  subfacstack = new arraypool(sizeof(face), 10);
1839  subvertstack = new arraypool(sizeof(point), 8);
1840 
1841  // Initialize arraypools for surface point insertion/deletion.
1842  caveshlist = new arraypool(sizeof(face), 8);
1843  caveshbdlist = new arraypool(sizeof(face), 8);
1844  cavesegshlist = new arraypool(sizeof(face), 4);
1845 
1846  cavetetshlist = new arraypool(sizeof(face), 8);
1847  cavetetseglist = new arraypool(sizeof(face), 8);
1848  caveencshlist = new arraypool(sizeof(face), 8);
1849  caveencseglist = new arraypool(sizeof(face), 8);
1850  }
1851 
1852  // Initialize the pools for flips.
1853  flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
1854  unflipqueue = new arraypool(sizeof(badface), 10);
1855 
1856  // Initialize the arraypools for point insertion.
1857  cavetetlist = new arraypool(sizeof(triface), 10);
1858  cavebdrylist = new arraypool(sizeof(triface), 10);
1859  caveoldtetlist = new arraypool(sizeof(triface), 10);
1860  cavetetvertlist = new arraypool(sizeof(point), 10);
1861 }
1862 
1866 
1870 
1871 // PI is the ratio of a circle's circumference to its diameter.
1872 REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
1873 
1875 // //
1876 // insphere_s() Insphere test with symbolic perturbation. //
1877 // //
1878 // Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
1879 // outside the circumscribed sphere of the four points. //
1880 // //
1881 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
1882 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
1883 // points pa, pb, and pc. Otherwise, the returned sign is flipped. //
1884 // //
1885 // Return a positive value (> 0) if pe lies inside, a negative value (< 0) //
1886 // if pe lies outside the sphere, the returned value will not be zero. //
1887 // //
1889 
1891 {
1892  REAL sign;
1893 
1894  sign = insphere(pa, pb, pc, pd, pe);
1895  if (sign != 0.0) {
1896  return sign;
1897  }
1898 
1899  // Symbolic perturbation.
1900  point pt[5], swappt;
1901  REAL oriA, oriB;
1902  int swaps, count;
1903  int n, i;
1904 
1905  pt[0] = pa;
1906  pt[1] = pb;
1907  pt[2] = pc;
1908  pt[3] = pd;
1909  pt[4] = pe;
1910 
1911  // Sort the five points such that their indices are in the increasing
1912  // order. An optimized bubble sort algorithm is used, i.e., it has
1913  // the worst case O(n^2) runtime, but it is usually much faster.
1914  swaps = 0; // Record the total number of swaps.
1915  n = 5;
1916  do {
1917  count = 0;
1918  n = n - 1;
1919  for (i = 0; i < n; i++) {
1920  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
1921  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
1922  count++;
1923  }
1924  }
1925  swaps += count;
1926  } while (count > 0); // Continue if some points are swapped.
1927 
1928  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
1929  if (oriA != 0.0) {
1930  // Flip the sign if there are odd number of swaps.
1931  if ((swaps % 2) != 0) oriA = -oriA;
1932  return oriA;
1933  }
1934 
1935  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
1936  if (oriB == 0.0) {
1937  terminatetetgen(this, 2);
1938  }
1939  // Flip the sign if there are odd number of swaps.
1940  if ((swaps % 2) != 0) oriB = -oriB;
1941  return oriB;
1942 }
1943 
1945 // //
1946 // orient4d_s() 4d orientation test with symbolic perturbation. //
1947 // //
1948 // Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
1949 // point pe' in R^4 lies below or above the hyperplane passing through the //
1950 // four points pa', pb', pc', and pd'. //
1951 // //
1952 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
1953 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
1954 // the points pa, pb, and pc. Otherwise, the returned sign is flipped. //
1955 // //
1956 // Return a positive value (> 0) if pe' lies below, a negative value (< 0) //
1957 // if pe' lies above the hyperplane, the returned value should not be zero. //
1958 // //
1960 
1962  REAL aheight, REAL bheight, REAL cheight,
1963  REAL dheight, REAL eheight)
1964 {
1965  REAL sign;
1966 
1967  sign = orient4d(pa, pb, pc, pd, pe,
1968  aheight, bheight, cheight, dheight, eheight);
1969  if (sign != 0.0) {
1970  return sign;
1971  }
1972 
1973  // Symbolic perturbation.
1974  point pt[5], swappt;
1975  REAL oriA, oriB;
1976  int swaps, count;
1977  int n, i;
1978 
1979  pt[0] = pa;
1980  pt[1] = pb;
1981  pt[2] = pc;
1982  pt[3] = pd;
1983  pt[4] = pe;
1984 
1985  // Sort the five points such that their indices are in the increasing
1986  // order. An optimized bubble sort algorithm is used, i.e., it has
1987  // the worst case O(n^2) runtime, but it is usually much faster.
1988  swaps = 0; // Record the total number of swaps.
1989  n = 5;
1990  do {
1991  count = 0;
1992  n = n - 1;
1993  for (i = 0; i < n; i++) {
1994  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
1995  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
1996  count++;
1997  }
1998  }
1999  swaps += count;
2000  } while (count > 0); // Continue if some points are swapped.
2001 
2002  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
2003  if (oriA != 0.0) {
2004  // Flip the sign if there are odd number of swaps.
2005  if ((swaps % 2) != 0) oriA = -oriA;
2006  return oriA;
2007  }
2008 
2009  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
2010  if (oriB == 0.0) {
2011  terminatetetgen(this, 2);
2012  }
2013  // Flip the sign if there are odd number of swaps.
2014  if ((swaps % 2) != 0) oriB = -oriB;
2015  return oriB;
2016 }
2017 
2019 // //
2020 // tri_edge_test() Triangle-edge intersection test. //
2021 // //
2022 // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
2023 // Q) in 3D, and tests if they intersect each other. //
2024 // //
2025 // If the point 'R' is not NULL, it lies strictly above the plane defined by //
2026 // A, B, C. It is used in test when T and E are coplanar. //
2027 // //
2028 // If T and E intersect each other, they may intersect in different ways. If //
2029 // 'level' > 0, their intersection type will be reported 'types' and 'pos'. //
2030 // //
2031 // The return value indicates one of the following cases: //
2032 // - 0, T and E are disjoint. //
2033 // - 1, T and E intersect each other. //
2034 // - 2, T and E are not coplanar. They intersect at a single point. //
2035 // - 4, T and E are coplanar. They intersect at a single point or a line //
2036 // segment (if types[1] != DISJOINT). //
2037 // //
2039 
2040 #define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
2042 #define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
2045  point R, int level, int *types, int *pos)
2046 {
2047  point U[3], V[3]; // The permuted vectors of points.
2048  int pu[3], pv[3]; // The original positions of points.
2049  REAL abovept[3];
2050  REAL sA, sB, sC;
2051  REAL s1, s2, s3, s4;
2052  int z1;
2053 
2054  if (R == NULL) {
2055  // Calculate a lift point.
2056  if (1) {
2057  REAL n[3], len;
2058  // Calculate a lift point, saved in dummypoint.
2059  facenormal(A, B, C, n, 1, NULL);
2060  len = sqrt(dot(n, n));
2061  if (len != 0) {
2062  n[0] /= len;
2063  n[1] /= len;
2064  n[2] /= len;
2065  len = distance(A, B);
2066  len += distance(B, C);
2067  len += distance(C, A);
2068  len /= 3.0;
2069  R = abovept; //dummypoint;
2070  R[0] = A[0] + len * n[0];
2071  R[1] = A[1] + len * n[1];
2072  R[2] = A[2] + len * n[2];
2073  } else {
2074  // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
2075  // to a line. We need a line-line intersection test.
2076  // !!! A non-save return value.!!!
2077  return 0; // DISJOINT
2078  }
2079  }
2080  }
2081 
2082  // Test A's, B's, and C's orientations wrt plane PQR.
2083  sA = orient3d(P, Q, R, A);
2084  sB = orient3d(P, Q, R, B);
2085  sC = orient3d(P, Q, R, C);
2086 
2087 
2088  if (sA < 0) {
2089  if (sB < 0) {
2090  if (sC < 0) { // (---).
2091  return 0;
2092  } else {
2093  if (sC > 0) { // (--+).
2094  // All points are in the right positions.
2095  SETVECTOR3(U, A, B, C); // I3
2096  SETVECTOR3(V, P, Q, R); // I2
2097  SETVECTOR3(pu, 0, 1, 2);
2098  SETVECTOR3(pv, 0, 1, 2);
2099  z1 = 0;
2100  } else { // (--0).
2101  SETVECTOR3(U, A, B, C); // I3
2102  SETVECTOR3(V, P, Q, R); // I2
2103  SETVECTOR3(pu, 0, 1, 2);
2104  SETVECTOR3(pv, 0, 1, 2);
2105  z1 = 1;
2106  }
2107  }
2108  } else {
2109  if (sB > 0) {
2110  if (sC < 0) { // (-+-).
2111  SETVECTOR3(U, C, A, B); // PT = ST
2112  SETVECTOR3(V, P, Q, R); // I2
2113  SETVECTOR3(pu, 2, 0, 1);
2114  SETVECTOR3(pv, 0, 1, 2);
2115  z1 = 0;
2116  } else {
2117  if (sC > 0) { // (-++).
2118  SETVECTOR3(U, B, C, A); // PT = ST x ST
2119  SETVECTOR3(V, Q, P, R); // PL = SL
2120  SETVECTOR3(pu, 1, 2, 0);
2121  SETVECTOR3(pv, 1, 0, 2);
2122  z1 = 0;
2123  } else { // (-+0).
2124  SETVECTOR3(U, C, A, B); // PT = ST
2125  SETVECTOR3(V, P, Q, R); // I2
2126  SETVECTOR3(pu, 2, 0, 1);
2127  SETVECTOR3(pv, 0, 1, 2);
2128  z1 = 2;
2129  }
2130  }
2131  } else {
2132  if (sC < 0) { // (-0-).
2133  SETVECTOR3(U, C, A, B); // PT = ST
2134  SETVECTOR3(V, P, Q, R); // I2
2135  SETVECTOR3(pu, 2, 0, 1);
2136  SETVECTOR3(pv, 0, 1, 2);
2137  z1 = 1;
2138  } else {
2139  if (sC > 0) { // (-0+).
2140  SETVECTOR3(U, B, C, A); // PT = ST x ST
2141  SETVECTOR3(V, Q, P, R); // PL = SL
2142  SETVECTOR3(pu, 1, 2, 0);
2143  SETVECTOR3(pv, 1, 0, 2);
2144  z1 = 2;
2145  } else { // (-00).
2146  SETVECTOR3(U, B, C, A); // PT = ST x ST
2147  SETVECTOR3(V, Q, P, R); // PL = SL
2148  SETVECTOR3(pu, 1, 2, 0);
2149  SETVECTOR3(pv, 1, 0, 2);
2150  z1 = 3;
2151  }
2152  }
2153  }
2154  }
2155  } else {
2156  if (sA > 0) {
2157  if (sB < 0) {
2158  if (sC < 0) { // (+--).
2159  SETVECTOR3(U, B, C, A); // PT = ST x ST
2160  SETVECTOR3(V, P, Q, R); // I2
2161  SETVECTOR3(pu, 1, 2, 0);
2162  SETVECTOR3(pv, 0, 1, 2);
2163  z1 = 0;
2164  } else {
2165  if (sC > 0) { // (+-+).
2166  SETVECTOR3(U, C, A, B); // PT = ST
2167  SETVECTOR3(V, Q, P, R); // PL = SL
2168  SETVECTOR3(pu, 2, 0, 1);
2169  SETVECTOR3(pv, 1, 0, 2);
2170  z1 = 0;
2171  } else { // (+-0).
2172  SETVECTOR3(U, C, A, B); // PT = ST
2173  SETVECTOR3(V, Q, P, R); // PL = SL
2174  SETVECTOR3(pu, 2, 0, 1);
2175  SETVECTOR3(pv, 1, 0, 2);
2176  z1 = 2;
2177  }
2178  }
2179  } else {
2180  if (sB > 0) {
2181  if (sC < 0) { // (++-).
2182  SETVECTOR3(U, A, B, C); // I3
2183  SETVECTOR3(V, Q, P, R); // PL = SL
2184  SETVECTOR3(pu, 0, 1, 2);
2185  SETVECTOR3(pv, 1, 0, 2);
2186  z1 = 0;
2187  } else {
2188  if (sC > 0) { // (+++).
2189  return 0;
2190  } else { // (++0).
2191  SETVECTOR3(U, A, B, C); // I3
2192  SETVECTOR3(V, Q, P, R); // PL = SL
2193  SETVECTOR3(pu, 0, 1, 2);
2194  SETVECTOR3(pv, 1, 0, 2);
2195  z1 = 1;
2196  }
2197  }
2198  } else { // (+0#)
2199  if (sC < 0) { // (+0-).
2200  SETVECTOR3(U, B, C, A); // PT = ST x ST
2201  SETVECTOR3(V, P, Q, R); // I2
2202  SETVECTOR3(pu, 1, 2, 0);
2203  SETVECTOR3(pv, 0, 1, 2);
2204  z1 = 2;
2205  } else {
2206  if (sC > 0) { // (+0+).
2207  SETVECTOR3(U, C, A, B); // PT = ST
2208  SETVECTOR3(V, Q, P, R); // PL = SL
2209  SETVECTOR3(pu, 2, 0, 1);
2210  SETVECTOR3(pv, 1, 0, 2);
2211  z1 = 1;
2212  } else { // (+00).
2213  SETVECTOR3(U, B, C, A); // PT = ST x ST
2214  SETVECTOR3(V, P, Q, R); // I2
2215  SETVECTOR3(pu, 1, 2, 0);
2216  SETVECTOR3(pv, 0, 1, 2);
2217  z1 = 3;
2218  }
2219  }
2220  }
2221  }
2222  } else {
2223  if (sB < 0) {
2224  if (sC < 0) { // (0--).
2225  SETVECTOR3(U, B, C, A); // PT = ST x ST
2226  SETVECTOR3(V, P, Q, R); // I2
2227  SETVECTOR3(pu, 1, 2, 0);
2228  SETVECTOR3(pv, 0, 1, 2);
2229  z1 = 1;
2230  } else {
2231  if (sC > 0) { // (0-+).
2232  SETVECTOR3(U, A, B, C); // I3
2233  SETVECTOR3(V, P, Q, R); // I2
2234  SETVECTOR3(pu, 0, 1, 2);
2235  SETVECTOR3(pv, 0, 1, 2);
2236  z1 = 2;
2237  } else { // (0-0).
2238  SETVECTOR3(U, C, A, B); // PT = ST
2239  SETVECTOR3(V, Q, P, R); // PL = SL
2240  SETVECTOR3(pu, 2, 0, 1);
2241  SETVECTOR3(pv, 1, 0, 2);
2242  z1 = 3;
2243  }
2244  }
2245  } else {
2246  if (sB > 0) {
2247  if (sC < 0) { // (0+-).
2248  SETVECTOR3(U, A, B, C); // I3
2249  SETVECTOR3(V, Q, P, R); // PL = SL
2250  SETVECTOR3(pu, 0, 1, 2);
2251  SETVECTOR3(pv, 1, 0, 2);
2252  z1 = 2;
2253  } else {
2254  if (sC > 0) { // (0++).
2255  SETVECTOR3(U, B, C, A); // PT = ST x ST
2256  SETVECTOR3(V, Q, P, R); // PL = SL
2257  SETVECTOR3(pu, 1, 2, 0);
2258  SETVECTOR3(pv, 1, 0, 2);
2259  z1 = 1;
2260  } else { // (0+0).
2261  SETVECTOR3(U, C, A, B); // PT = ST
2262  SETVECTOR3(V, P, Q, R); // I2
2263  SETVECTOR3(pu, 2, 0, 1);
2264  SETVECTOR3(pv, 0, 1, 2);
2265  z1 = 3;
2266  }
2267  }
2268  } else { // (00#)
2269  if (sC < 0) { // (00-).
2270  SETVECTOR3(U, A, B, C); // I3
2271  SETVECTOR3(V, Q, P, R); // PL = SL
2272  SETVECTOR3(pu, 0, 1, 2);
2273  SETVECTOR3(pv, 1, 0, 2);
2274  z1 = 3;
2275  } else {
2276  if (sC > 0) { // (00+).
2277  SETVECTOR3(U, A, B, C); // I3
2278  SETVECTOR3(V, P, Q, R); // I2
2279  SETVECTOR3(pu, 0, 1, 2);
2280  SETVECTOR3(pv, 0, 1, 2);
2281  z1 = 3;
2282  } else { // (000)
2283  // Not possible unless ABC is degenerate.
2284  // Avoiding compiler warnings.
2285  SETVECTOR3(U, A, B, C); // I3
2286  SETVECTOR3(V, P, Q, R); // I2
2287  SETVECTOR3(pu, 0, 1, 2);
2288  SETVECTOR3(pv, 0, 1, 2);
2289  z1 = 4;
2290  }
2291  }
2292  }
2293  }
2294  }
2295  }
2296 
2297  s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q
2298  s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P
2299 
2300  if (s1 > 0) {
2301  return 0;
2302  }
2303  if (s2 < 0) {
2304  return 0;
2305  }
2306 
2307  if (level == 0) {
2308  return 1; // They are intersected.
2309  }
2310 
2311 
2312  if (z1 == 1) {
2313  if (s1 == 0) { // (0###)
2314  // C = Q.
2315  types[0] = (int) SHAREVERT;
2316  pos[0] = pu[2]; // C
2317  pos[1] = pv[1]; // Q
2318  types[1] = (int) DISJOINT;
2319  } else {
2320  if (s2 == 0) { // (#0##)
2321  // C = P.
2322  types[0] = (int) SHAREVERT;
2323  pos[0] = pu[2]; // C
2324  pos[1] = pv[0]; // P
2325  types[1] = (int) DISJOINT;
2326  } else { // (-+##)
2327  // C in [P, Q].
2328  types[0] = (int) ACROSSVERT;
2329  pos[0] = pu[2]; // C
2330  pos[1] = pv[0]; // [P, Q]
2331  types[1] = (int) DISJOINT;
2332  }
2333  }
2334  return 4;
2335  }
2336 
2337  s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P
2338  s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q
2339 
2340  if (z1 == 0) { // (tritri-03)
2341  if (s1 < 0) {
2342  if (s3 > 0) {
2343  if (s4 > 0) {
2344  // [P, Q] overlaps [k, l] (-+++).
2345  types[0] = (int) ACROSSEDGE;
2346  pos[0] = pu[2]; // [C, A]
2347  pos[1] = pv[0]; // [P, Q]
2348  types[1] = (int) TOUCHFACE;
2349  pos[2] = 3; // [A, B, C]
2350  pos[3] = pv[1]; // Q
2351  } else {
2352  if (s4 == 0) {
2353  // Q = l, [P, Q] contains [k, l] (-++0).
2354  types[0] = (int) ACROSSEDGE;
2355  pos[0] = pu[2]; // [C, A]
2356  pos[1] = pv[0]; // [P, Q]
2357  types[1] = (int) TOUCHEDGE;
2358  pos[2] = pu[1]; // [B, C]
2359  pos[3] = pv[1]; // Q
2360  } else { // s4 < 0
2361  // [P, Q] contains [k, l] (-++-).
2362  types[0] = (int) ACROSSEDGE;
2363  pos[0] = pu[2]; // [C, A]
2364  pos[1] = pv[0]; // [P, Q]
2365  types[1] = (int) ACROSSEDGE;
2366  pos[2] = pu[1]; // [B, C]
2367  pos[3] = pv[0]; // [P, Q]
2368  }
2369  }
2370  } else {
2371  if (s3 == 0) {
2372  if (s4 > 0) {
2373  // P = k, [P, Q] in [k, l] (-+0+).
2374  types[0] = (int) TOUCHEDGE;
2375  pos[0] = pu[2]; // [C, A]
2376  pos[1] = pv[0]; // P
2377  types[1] = (int) TOUCHFACE;
2378  pos[2] = 3; // [A, B, C]
2379  pos[3] = pv[1]; // Q
2380  } else {
2381  if (s4 == 0) {
2382  // [P, Q] = [k, l] (-+00).
2383  types[0] = (int) TOUCHEDGE;
2384  pos[0] = pu[2]; // [C, A]
2385  pos[1] = pv[0]; // P
2386  types[1] = (int) TOUCHEDGE;
2387  pos[2] = pu[1]; // [B, C]
2388  pos[3] = pv[1]; // Q
2389  } else {
2390  // P = k, [P, Q] contains [k, l] (-+0-).
2391  types[0] = (int) TOUCHEDGE;
2392  pos[0] = pu[2]; // [C, A]
2393  pos[1] = pv[0]; // P
2394  types[1] = (int) ACROSSEDGE;
2395  pos[2] = pu[1]; // [B, C]
2396  pos[3] = pv[0]; // [P, Q]
2397  }
2398  }
2399  } else { // s3 < 0
2400  if (s2 > 0) {
2401  if (s4 > 0) {
2402  // [P, Q] in [k, l] (-+-+).
2403  types[0] = (int) TOUCHFACE;
2404  pos[0] = 3; // [A, B, C]
2405  pos[1] = pv[0]; // P
2406  types[1] = (int) TOUCHFACE;
2407  pos[2] = 3; // [A, B, C]
2408  pos[3] = pv[1]; // Q
2409  } else {
2410  if (s4 == 0) {
2411  // Q = l, [P, Q] in [k, l] (-+-0).
2412  types[0] = (int) TOUCHFACE;
2413  pos[0] = 3; // [A, B, C]
2414  pos[1] = pv[0]; // P
2415  types[1] = (int) TOUCHEDGE;
2416  pos[2] = pu[1]; // [B, C]
2417  pos[3] = pv[1]; // Q
2418  } else { // s4 < 0
2419  // [P, Q] overlaps [k, l] (-+--).
2420  types[0] = (int) TOUCHFACE;
2421  pos[0] = 3; // [A, B, C]
2422  pos[1] = pv[0]; // P
2423  types[1] = (int) ACROSSEDGE;
2424  pos[2] = pu[1]; // [B, C]
2425  pos[3] = pv[0]; // [P, Q]
2426  }
2427  }
2428  } else { // s2 == 0
2429  // P = l (#0##).
2430  types[0] = (int) TOUCHEDGE;
2431  pos[0] = pu[1]; // [B, C]
2432  pos[1] = pv[0]; // P
2433  types[1] = (int) DISJOINT;
2434  }
2435  }
2436  }
2437  } else { // s1 == 0
2438  // Q = k (0####)
2439  types[0] = (int) TOUCHEDGE;
2440  pos[0] = pu[2]; // [C, A]
2441  pos[1] = pv[1]; // Q
2442  types[1] = (int) DISJOINT;
2443  }
2444  } else if (z1 == 2) { // (tritri-23)
2445  if (s1 < 0) {
2446  if (s3 > 0) {
2447  if (s4 > 0) {
2448  // [P, Q] overlaps [A, l] (-+++).
2449  types[0] = (int) ACROSSVERT;
2450  pos[0] = pu[0]; // A
2451  pos[1] = pv[0]; // [P, Q]
2452  types[1] = (int) TOUCHFACE;
2453  pos[2] = 3; // [A, B, C]
2454  pos[3] = pv[1]; // Q
2455  } else {
2456  if (s4 == 0) {
2457  // Q = l, [P, Q] contains [A, l] (-++0).
2458  types[0] = (int) ACROSSVERT;
2459  pos[0] = pu[0]; // A
2460  pos[1] = pv[0]; // [P, Q]
2461  types[1] = (int) TOUCHEDGE;
2462  pos[2] = pu[1]; // [B, C]
2463  pos[3] = pv[1]; // Q
2464  } else { // s4 < 0
2465  // [P, Q] contains [A, l] (-++-).
2466  types[0] = (int) ACROSSVERT;
2467  pos[0] = pu[0]; // A
2468  pos[1] = pv[0]; // [P, Q]
2469  types[1] = (int) ACROSSEDGE;
2470  pos[2] = pu[1]; // [B, C]
2471  pos[3] = pv[0]; // [P, Q]
2472  }
2473  }
2474  } else {
2475  if (s3 == 0) {
2476  if (s4 > 0) {
2477  // P = A, [P, Q] in [A, l] (-+0+).
2478  types[0] = (int) SHAREVERT;
2479  pos[0] = pu[0]; // A
2480  pos[1] = pv[0]; // P
2481  types[1] = (int) TOUCHFACE;
2482  pos[2] = 3; // [A, B, C]
2483  pos[3] = pv[1]; // Q
2484  } else {
2485  if (s4 == 0) {
2486  // [P, Q] = [A, l] (-+00).
2487  types[0] = (int) SHAREVERT;
2488  pos[0] = pu[0]; // A
2489  pos[1] = pv[0]; // P
2490  types[1] = (int) TOUCHEDGE;
2491  pos[2] = pu[1]; // [B, C]
2492  pos[3] = pv[1]; // Q
2493  } else { // s4 < 0
2494  // Q = l, [P, Q] in [A, l] (-+0-).
2495  types[0] = (int) SHAREVERT;
2496  pos[0] = pu[0]; // A
2497  pos[1] = pv[0]; // P
2498  types[1] = (int) ACROSSEDGE;
2499  pos[2] = pu[1]; // [B, C]
2500  pos[3] = pv[0]; // [P, Q]
2501  }
2502  }
2503  } else { // s3 < 0
2504  if (s2 > 0) {
2505  if (s4 > 0) {
2506  // [P, Q] in [A, l] (-+-+).
2507  types[0] = (int) TOUCHFACE;
2508  pos[0] = 3; // [A, B, C]
2509  pos[1] = pv[0]; // P
2510  types[0] = (int) TOUCHFACE;
2511  pos[0] = 3; // [A, B, C]
2512  pos[1] = pv[1]; // Q
2513  } else {
2514  if (s4 == 0) {
2515  // Q = l, [P, Q] in [A, l] (-+-0).
2516  types[0] = (int) TOUCHFACE;
2517  pos[0] = 3; // [A, B, C]
2518  pos[1] = pv[0]; // P
2519  types[0] = (int) TOUCHEDGE;
2520  pos[0] = pu[1]; // [B, C]
2521  pos[1] = pv[1]; // Q
2522  } else { // s4 < 0
2523  // [P, Q] overlaps [A, l] (-+--).
2524  types[0] = (int) TOUCHFACE;
2525  pos[0] = 3; // [A, B, C]
2526  pos[1] = pv[0]; // P
2527  types[0] = (int) ACROSSEDGE;
2528  pos[0] = pu[1]; // [B, C]
2529  pos[1] = pv[0]; // [P, Q]
2530  }
2531  }
2532  } else { // s2 == 0
2533  // P = l (#0##).
2534  types[0] = (int) TOUCHEDGE;
2535  pos[0] = pu[1]; // [B, C]
2536  pos[1] = pv[0]; // P
2537  types[1] = (int) DISJOINT;
2538  }
2539  }
2540  }
2541  } else { // s1 == 0
2542  // Q = A (0###).
2543  types[0] = (int) SHAREVERT;
2544  pos[0] = pu[0]; // A
2545  pos[1] = pv[1]; // Q
2546  types[1] = (int) DISJOINT;
2547  }
2548  } else if (z1 == 3) { // (tritri-33)
2549  if (s1 < 0) {
2550  if (s3 > 0) {
2551  if (s4 > 0) {
2552  // [P, Q] overlaps [A, B] (-+++).
2553  types[0] = (int) ACROSSVERT;
2554  pos[0] = pu[0]; // A
2555  pos[1] = pv[0]; // [P, Q]
2556  types[1] = (int) TOUCHEDGE;
2557  pos[2] = pu[0]; // [A, B]
2558  pos[3] = pv[1]; // Q
2559  } else {
2560  if (s4 == 0) {
2561  // Q = B, [P, Q] contains [A, B] (-++0).
2562  types[0] = (int) ACROSSVERT;
2563  pos[0] = pu[0]; // A
2564  pos[1] = pv[0]; // [P, Q]
2565  types[1] = (int) SHAREVERT;
2566  pos[2] = pu[1]; // B
2567  pos[3] = pv[1]; // Q
2568  } else { // s4 < 0
2569  // [P, Q] contains [A, B] (-++-).
2570  types[0] = (int) ACROSSVERT;
2571  pos[0] = pu[0]; // A
2572  pos[1] = pv[0]; // [P, Q]
2573  types[1] = (int) ACROSSVERT;
2574  pos[2] = pu[1]; // B
2575  pos[3] = pv[0]; // [P, Q]
2576  }
2577  }
2578  } else {
2579  if (s3 == 0) {
2580  if (s4 > 0) {
2581  // P = A, [P, Q] in [A, B] (-+0+).
2582  types[0] = (int) SHAREVERT;
2583  pos[0] = pu[0]; // A
2584  pos[1] = pv[0]; // P
2585  types[1] = (int) TOUCHEDGE;
2586  pos[2] = pu[0]; // [A, B]
2587  pos[3] = pv[1]; // Q
2588  } else {
2589  if (s4 == 0) {
2590  // [P, Q] = [A, B] (-+00).
2591  types[0] = (int) SHAREEDGE;
2592  pos[0] = pu[0]; // [A, B]
2593  pos[1] = pv[0]; // [P, Q]
2594  types[1] = (int) DISJOINT;
2595  } else { // s4 < 0
2596  // P= A, [P, Q] in [A, B] (-+0-).
2597  types[0] = (int) SHAREVERT;
2598  pos[0] = pu[0]; // A
2599  pos[1] = pv[0]; // P
2600  types[1] = (int) ACROSSVERT;
2601  pos[2] = pu[1]; // B
2602  pos[3] = pv[0]; // [P, Q]
2603  }
2604  }
2605  } else { // s3 < 0
2606  if (s2 > 0) {
2607  if (s4 > 0) {
2608  // [P, Q] in [A, B] (-+-+).
2609  types[0] = (int) TOUCHEDGE;
2610  pos[0] = pu[0]; // [A, B]
2611  pos[1] = pv[0]; // P
2612  types[1] = (int) TOUCHEDGE;
2613  pos[2] = pu[0]; // [A, B]
2614  pos[3] = pv[1]; // Q
2615  } else {
2616  if (s4 == 0) {
2617  // Q = B, [P, Q] in [A, B] (-+-0).
2618  types[0] = (int) TOUCHEDGE;
2619  pos[0] = pu[0]; // [A, B]
2620  pos[1] = pv[0]; // P
2621  types[1] = (int) SHAREVERT;
2622  pos[2] = pu[1]; // B
2623  pos[3] = pv[1]; // Q
2624  } else { // s4 < 0
2625  // [P, Q] overlaps [A, B] (-+--).
2626  types[0] = (int) TOUCHEDGE;
2627  pos[0] = pu[0]; // [A, B]
2628  pos[1] = pv[0]; // P
2629  types[1] = (int) ACROSSVERT;
2630  pos[2] = pu[1]; // B
2631  pos[3] = pv[0]; // [P, Q]
2632  }
2633  }
2634  } else { // s2 == 0
2635  // P = B (#0##).
2636  types[0] = (int) SHAREVERT;
2637  pos[0] = pu[1]; // B
2638  pos[1] = pv[0]; // P
2639  types[1] = (int) DISJOINT;
2640  }
2641  }
2642  }
2643  } else { // s1 == 0
2644  // Q = A (0###).
2645  types[0] = (int) SHAREVERT;
2646  pos[0] = pu[0]; // A
2647  pos[1] = pv[1]; // Q
2648  types[1] = (int) DISJOINT;
2649  }
2650  }
2651 
2652  return 4;
2653 }
2654 
2656  REAL sP,REAL sQ,int level,int *types,int *pos)
2657 {
2658  point U[3], V[3]; //, Ptmp;
2659  int pu[3], pv[3]; //, itmp;
2660  REAL s1, s2, s3;
2661  int z1;
2662 
2663 
2664  if (sP < 0) {
2665  if (sQ < 0) { // (--) disjoint
2666  return 0;
2667  } else {
2668  if (sQ > 0) { // (-+)
2669  SETVECTOR3(U, A, B, C);
2670  SETVECTOR3(V, P, Q, R);
2671  SETVECTOR3(pu, 0, 1, 2);
2672  SETVECTOR3(pv, 0, 1, 2);
2673  z1 = 0;
2674  } else { // (-0)
2675  SETVECTOR3(U, A, B, C);
2676  SETVECTOR3(V, P, Q, R);
2677  SETVECTOR3(pu, 0, 1, 2);
2678  SETVECTOR3(pv, 0, 1, 2);
2679  z1 = 1;
2680  }
2681  }
2682  } else {
2683  if (sP > 0) { // (+-)
2684  if (sQ < 0) {
2685  SETVECTOR3(U, A, B, C);
2686  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
2687  SETVECTOR3(pu, 0, 1, 2);
2688  SETVECTOR3(pv, 1, 0, 2);
2689  z1 = 0;
2690  } else {
2691  if (sQ > 0) { // (++) disjoint
2692  return 0;
2693  } else { // (+0)
2694  SETVECTOR3(U, B, A, C); // A and B are flipped.
2695  SETVECTOR3(V, P, Q, R);
2696  SETVECTOR3(pu, 1, 0, 2);
2697  SETVECTOR3(pv, 0, 1, 2);
2698  z1 = 1;
2699  }
2700  }
2701  } else { // sP == 0
2702  if (sQ < 0) { // (0-)
2703  SETVECTOR3(U, A, B, C);
2704  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
2705  SETVECTOR3(pu, 0, 1, 2);
2706  SETVECTOR3(pv, 1, 0, 2);
2707  z1 = 1;
2708  } else {
2709  if (sQ > 0) { // (0+)
2710  SETVECTOR3(U, B, A, C); // A and B are flipped.
2711  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
2712  SETVECTOR3(pu, 1, 0, 2);
2713  SETVECTOR3(pv, 1, 0, 2);
2714  z1 = 1;
2715  } else { // (00)
2716  // A, B, C, P, and Q are coplanar.
2717  z1 = 2;
2718  }
2719  }
2720  }
2721  }
2722 
2723  if (z1 == 2) {
2724  // The triangle and the edge are coplanar.
2725  return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
2726  }
2727 
2728  s1 = orient3d(U[0], U[1], V[0], V[1]);
2729  if (s1 < 0) {
2730  return 0;
2731  }
2732 
2733  s2 = orient3d(U[1], U[2], V[0], V[1]);
2734  if (s2 < 0) {
2735  return 0;
2736  }
2737 
2738  s3 = orient3d(U[2], U[0], V[0], V[1]);
2739  if (s3 < 0) {
2740  return 0;
2741  }
2742 
2743  if (level == 0) {
2744  return 1; // The are intersected.
2745  }
2746 
2747  types[1] = (int) DISJOINT; // No second intersection point.
2748 
2749  if (z1 == 0) {
2750  if (s1 > 0) {
2751  if (s2 > 0) {
2752  if (s3 > 0) { // (+++)
2753  // [P, Q] passes interior of [A, B, C].
2754  types[0] = (int) ACROSSFACE;
2755  pos[0] = 3; // interior of [A, B, C]
2756  pos[1] = 0; // [P, Q]
2757  } else { // s3 == 0 (++0)
2758  // [P, Q] intersects [C, A].
2759  types[0] = (int) ACROSSEDGE;
2760  pos[0] = pu[2]; // [C, A]
2761  pos[1] = 0; // [P, Q]
2762  }
2763  } else { // s2 == 0
2764  if (s3 > 0) { // (+0+)
2765  // [P, Q] intersects [B, C].
2766  types[0] = (int) ACROSSEDGE;
2767  pos[0] = pu[1]; // [B, C]
2768  pos[1] = 0; // [P, Q]
2769  } else { // s3 == 0 (+00)
2770  // [P, Q] passes C.
2771  types[0] = (int) ACROSSVERT;
2772  pos[0] = pu[2]; // C
2773  pos[1] = 0; // [P, Q]
2774  }
2775  }
2776  } else { // s1 == 0
2777  if (s2 > 0) {
2778  if (s3 > 0) { // (0++)
2779  // [P, Q] intersects [A, B].
2780  types[0] = (int) ACROSSEDGE;
2781  pos[0] = pu[0]; // [A, B]
2782  pos[1] = 0; // [P, Q]
2783  } else { // s3 == 0 (0+0)
2784  // [P, Q] passes A.
2785  types[0] = (int) ACROSSVERT;
2786  pos[0] = pu[0]; // A
2787  pos[1] = 0; // [P, Q]
2788  }
2789  } else { // s2 == 0
2790  if (s3 > 0) { // (00+)
2791  // [P, Q] passes B.
2792  types[0] = (int) ACROSSVERT;
2793  pos[0] = pu[1]; // B
2794  pos[1] = 0; // [P, Q]
2795  }
2796  }
2797  }
2798  } else { // z1 == 1
2799  if (s1 > 0) {
2800  if (s2 > 0) {
2801  if (s3 > 0) { // (+++)
2802  // Q lies in [A, B, C].
2803  types[0] = (int) TOUCHFACE;
2804  pos[0] = 0; // [A, B, C]
2805  pos[1] = pv[1]; // Q
2806  } else { // s3 == 0 (++0)
2807  // Q lies on [C, A].
2808  types[0] = (int) TOUCHEDGE;
2809  pos[0] = pu[2]; // [C, A]
2810  pos[1] = pv[1]; // Q
2811  }
2812  } else { // s2 == 0
2813  if (s3 > 0) { // (+0+)
2814  // Q lies on [B, C].
2815  types[0] = (int) TOUCHEDGE;
2816  pos[0] = pu[1]; // [B, C]
2817  pos[1] = pv[1]; // Q
2818  } else { // s3 == 0 (+00)
2819  // Q = C.
2820  types[0] = (int) SHAREVERT;
2821  pos[0] = pu[2]; // C
2822  pos[1] = pv[1]; // Q
2823  }
2824  }
2825  } else { // s1 == 0
2826  if (s2 > 0) {
2827  if (s3 > 0) { // (0++)
2828  // Q lies on [A, B].
2829  types[0] = (int) TOUCHEDGE;
2830  pos[0] = pu[0]; // [A, B]
2831  pos[1] = pv[1]; // Q
2832  } else { // s3 == 0 (0+0)
2833  // Q = A.
2834  types[0] = (int) SHAREVERT;
2835  pos[0] = pu[0]; // A
2836  pos[1] = pv[1]; // Q
2837  }
2838  } else { // s2 == 0
2839  if (s3 > 0) { // (00+)
2840  // Q = B.
2841  types[0] = (int) SHAREVERT;
2842  pos[0] = pu[1]; // B
2843  pos[1] = pv[1]; // Q
2844  }
2845  }
2846  }
2847  }
2848 
2849  // T and E intersect in a single point.
2850  return 2;
2851 }
2852 
2854  point R, int level, int *types, int *pos)
2855 {
2856  REAL sP, sQ;
2857 
2858  // Test the locations of P and Q with respect to ABC.
2859  sP = orient3d(A, B, C, P);
2860  sQ = orient3d(A, B, C, Q);
2861 
2862  return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
2863 }
2864 
2866 // //
2867 // tri_tri_inter() Test whether two triangle (abc) and (opq) are //
2868 // intersecting or not. //
2869 // //
2870 // Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
2871 // the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT. //
2872 // //
2874 
2876  REAL* Q, REAL s_p, REAL s_q)
2877 {
2878  int types[2], pos[4];
2879  int ni; // =0, 2, 4
2880 
2881  ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
2882 
2883  if (ni > 0) {
2884  if (ni == 2) {
2885  // Get the intersection type.
2886  if (types[0] == (int) SHAREVERT) {
2887  return (int) SHAREVERT;
2888  } else {
2889  return (int) INTERSECT;
2890  }
2891  } else if (ni == 4) {
2892  // There may be two intersections.
2893  if (types[0] == (int) SHAREVERT) {
2894  if (types[1] == (int) DISJOINT) {
2895  return (int) SHAREVERT;
2896  } else {
2897  return (int) INTERSECT;
2898  }
2899  } else {
2900  if (types[0] == (int) SHAREEDGE) {
2901  return (int) SHAREEDGE;
2902  } else {
2903  return (int) INTERSECT;
2904  }
2905  }
2906  }
2907  }
2908 
2909  return (int) DISJOINT;
2910 }
2911 
2913 {
2914  REAL s_o, s_p, s_q;
2915  REAL s_a, s_b, s_c;
2916 
2917  s_o = orient3d(A, B, C, O);
2918  s_p = orient3d(A, B, C, P);
2919  s_q = orient3d(A, B, C, Q);
2920  if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
2921  // o, p, q are all in the same halfspace of ABC.
2922  return 0; // DISJOINT;
2923  }
2924 
2925  s_a = orient3d(O, P, Q, A);
2926  s_b = orient3d(O, P, Q, B);
2927  s_c = orient3d(O, P, Q, C);
2928  if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
2929  // a, b, c are all in the same halfspace of OPQ.
2930  return 0; // DISJOINT;
2931  }
2932 
2933  int abcop, abcpq, abcqo;
2934  int shareedge = 0;
2935 
2936  abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
2937  if (abcop == (int) INTERSECT) {
2938  return (int) INTERSECT;
2939  } else if (abcop == (int) SHAREEDGE) {
2940  shareedge++;
2941  }
2942  abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
2943  if (abcpq == (int) INTERSECT) {
2944  return (int) INTERSECT;
2945  } else if (abcpq == (int) SHAREEDGE) {
2946  shareedge++;
2947  }
2948  abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
2949  if (abcqo == (int) INTERSECT) {
2950  return (int) INTERSECT;
2951  } else if (abcqo == (int) SHAREEDGE) {
2952  shareedge++;
2953  }
2954  if (shareedge == 3) {
2955  // opq are coincident with abc.
2956  return (int) SHAREFACE;
2957  }
2958 
2959  // Continue to detect whether opq and abc are intersecting or not.
2960  int opqab, opqbc, opqca;
2961 
2962  opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
2963  if (opqab == (int) INTERSECT) {
2964  return (int) INTERSECT;
2965  }
2966  opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
2967  if (opqbc == (int) INTERSECT) {
2968  return (int) INTERSECT;
2969  }
2970  opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
2971  if (opqca == (int) INTERSECT) {
2972  return (int) INTERSECT;
2973  }
2974 
2975  // At this point, two triangles are not intersecting and not coincident.
2976  // They may be share an edge, or share a vertex, or disjoint.
2977  if (abcop == (int) SHAREEDGE) {
2978  // op is coincident with an edge of abc.
2979  return (int) SHAREEDGE;
2980  }
2981  if (abcpq == (int) SHAREEDGE) {
2982  // pq is coincident with an edge of abc.
2983  return (int) SHAREEDGE;
2984  }
2985  if (abcqo == (int) SHAREEDGE) {
2986  // qo is coincident with an edge of abc.
2987  return (int) SHAREEDGE;
2988  }
2989 
2990  // They may share a vertex or disjoint.
2991  if (abcop == (int) SHAREVERT) {
2992  return (int) SHAREVERT;
2993  }
2994  if (abcpq == (int) SHAREVERT) {
2995  // q is the coincident vertex.
2996  return (int) SHAREVERT;
2997  }
2998 
2999  // They are disjoint.
3000  return (int) DISJOINT;
3001 }
3002 
3004 // //
3005 // lu_decmp() Compute the LU decomposition of a matrix. //
3006 // //
3007 // Compute the LU decomposition of a (non-singular) square matrix A using //
3008 // partial pivoting and implicit row exchanges. The result is: //
3009 // A = P * L * U, //
3010 // where P is a permutation matrix, L is unit lower triangular, and U is //
3011 // upper triangular. The factored form of A is used in combination with //
3012 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
3013 // //
3014 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
3015 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
3016 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
3017 // permutation effected by the partial pivoting, effectively, 'ps' array //
3018 // tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
3019 // depending on whether the number of row interchanges was even or odd, //
3020 // respectively. //
3021 // //
3022 // Return true if the LU decomposition is successfully computed, otherwise, //
3023 // return false in case that A is a singular matrix. //
3024 // //
3026 
3027 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
3028 {
3029  REAL scales[4];
3030  REAL pivot, biggest, mult, tempf;
3031  int pivotindex = 0;
3032  int i, j, k;
3033 
3034  *d = 1.0; // No row interchanges yet.
3035 
3036  for (i = N; i < n + N; i++) { // For each row.
3037  // Find the largest element in each row for row equilibration
3038  biggest = 0.0;
3039  for (j = N; j < n + N; j++)
3040  if (biggest < (tempf = fabs(lu[i][j])))
3041  biggest = tempf;
3042  if (biggest != 0.0)
3043  scales[i] = 1.0 / biggest;
3044  else {
3045  scales[i] = 0.0;
3046  return false; // Zero row: singular matrix.
3047  }
3048  ps[i] = i; // Initialize pivot sequence.
3049  }
3050 
3051  for (k = N; k < n + N - 1; k++) { // For each column.
3052  // Find the largest element in each column to pivot around.
3053  biggest = 0.0;
3054  for (i = k; i < n + N; i++) {
3055  if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
3056  biggest = tempf;
3057  pivotindex = i;
3058  }
3059  }
3060  if (biggest == 0.0) {
3061  return false; // Zero column: singular matrix.
3062  }
3063  if (pivotindex != k) { // Update pivot sequence.
3064  j = ps[k];
3065  ps[k] = ps[pivotindex];
3066  ps[pivotindex] = j;
3067  *d = -(*d); // ...and change the parity of d.
3068  }
3069 
3070  // Pivot, eliminating an extra variable each time
3071  pivot = lu[ps[k]][k];
3072  for (i = k + 1; i < n + N; i++) {
3073  lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
3074  if (mult != 0.0) {
3075  for (j = k + 1; j < n + N; j++)
3076  lu[ps[i]][j] -= mult * lu[ps[k]][j];
3077  }
3078  }
3079  }
3080 
3081  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
3082  return lu[ps[n + N - 1]][n + N - 1] != 0.0;
3083 }
3084 
3086 // //
3087 // lu_solve() Solves the linear equation: Ax = b, after the matrix A //
3088 // has been decomposed into the lower and upper triangular //
3089 // matrices L and U, where A = LU. //
3090 // //
3091 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
3092 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
3093 // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
3094 // is input as the right-hand side vector, and returns with the solution //
3095 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
3096 // left in place for successive calls with different right-hand sides 'b'. //
3097 // //
3099 
3100 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
3101 {
3102  int i, j;
3103  REAL X[4], dot;
3104 
3105  for (i = N; i < n + N; i++) X[i] = 0.0;
3106 
3107  // Vector reduction using U triangular matrix.
3108  for (i = N; i < n + N; i++) {
3109  dot = 0.0;
3110  for (j = N; j < i + N; j++)
3111  dot += lu[ps[i]][j] * X[j];
3112  X[i] = b[ps[i]] - dot;
3113  }
3114 
3115  // Back substitution, in L triangular matrix.
3116  for (i = n + N - 1; i >= N; i--) {
3117  dot = 0.0;
3118  for (j = i + 1; j < n + N; j++)
3119  dot += lu[ps[i]][j] * X[j];
3120  X[i] = (X[i] - dot) / lu[ps[i]][i];
3121  }
3122 
3123  for (i = N; i < n + N; i++) b[i] = X[i];
3124 }
3125 
3127 // //
3128 // incircle3d() 3D in-circle test. //
3129 // //
3130 // Return a negative value if pd is inside the circumcircle of the triangle //
3131 // pa, pb, and pc. //
3132 // //
3133 // IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input //
3134 // triangles are [a,b,c] and [b,a,d]. //
3135 // //
3137 
3139 {
3140  REAL area2[2], n1[3], n2[3], c[3];
3141  REAL sign, r, d;
3142 
3143  // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
3144  facenormal(pa, pb, pc, n1, 1, NULL);
3145  area2[0] = dot(n1, n1);
3146  facenormal(pb, pa, pd, n2, 1, NULL);
3147  area2[1] = dot(n2, n2);
3148 
3149  if (area2[0] > area2[1]) {
3150  // Choose [a, b, c] as the base triangle.
3151  circumsphere(pa, pb, pc, NULL, c, &r);
3152  d = distance(c, pd);
3153  } else {
3154  // Choose [b, a, d] as the base triangle.
3155  if (area2[1] > 0) {
3156  circumsphere(pb, pa, pd, NULL, c, &r);
3157  d = distance(c, pc);
3158  } else {
3159  // The four points are collinear. This case only happens on the boundary.
3160  return 0; // Return "not inside".
3161  }
3162  }
3163 
3164  sign = d - r;
3165  if (fabs(sign) / r < b->epsilon) {
3166  sign = 0;
3167  }
3168 
3169  return sign;
3170 }
3171 
3173 // //
3174 // facenormal() Calculate the normal of the face. //
3175 // //
3176 // The normal of the face abc can be calculated by the cross product of 2 of //
3177 // its 3 edge vectors. A better choice of two edge vectors will reduce the //
3178 // numerical error during the calculation. Burdakov proved that the optimal //
3179 // basis problem is equivalent to the minimum spanning tree problem with the //
3180 // edge length be the functional, see Burdakov, "A greedy algorithm for the //
3181 // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
3182 // short edges in abc are chosen for the calculation. //
3183 // //
3184 // If 'lav' is not NULL and if 'pivot' is set, the average edge length of //
3185 // the edges of the face [a,b,c] is returned. //
3186 // //
3188 
3189 void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
3190  REAL* lav)
3191 {
3192  REAL v1[3], v2[3], v3[3], *pv1, *pv2;
3193  REAL L1, L2, L3;
3194 
3195  v1[0] = pb[0] - pa[0]; // edge vector v1: a->b
3196  v1[1] = pb[1] - pa[1];
3197  v1[2] = pb[2] - pa[2];
3198  v2[0] = pa[0] - pc[0]; // edge vector v2: c->a
3199  v2[1] = pa[1] - pc[1];
3200  v2[2] = pa[2] - pc[2];
3201 
3202  // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
3203  if (pivot > 0) {
3204  // Choose edge vectors by Burdakov's algorithm.
3205  v3[0] = pc[0] - pb[0]; // edge vector v3: b->c
3206  v3[1] = pc[1] - pb[1];
3207  v3[2] = pc[2] - pb[2];
3208  L1 = dot(v1, v1);
3209  L2 = dot(v2, v2);
3210  L3 = dot(v3, v3);
3211  // Sort the three edge lengths.
3212  if (L1 < L2) {
3213  if (L2 < L3) {
3214  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
3215  } else {
3216  pv1 = v3; pv2 = v1; // n = v3 x (-v1).
3217  }
3218  } else {
3219  if (L1 < L3) {
3220  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
3221  } else {
3222  pv1 = v2; pv2 = v3; // n = v2 x (-v3).
3223  }
3224  }
3225  if (lav) {
3226  // return the average edge length.
3227  *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
3228  }
3229  } else {
3230  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
3231  }
3232 
3233  // Calculate the face normal.
3234  cross(pv1, pv2, n);
3235  // Inverse the direction;
3236  n[0] = -n[0];
3237  n[1] = -n[1];
3238  n[2] = -n[2];
3239 }
3240 
3242 // //
3243 // shortdistance() Returns the shortest distance from point p to a line //
3244 // defined by two points e1 and e2. //
3245 // //
3246 // First compute the projection length l_p of the vector v1 = p - e1 along //
3247 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
3248 // shortest distance. //
3249 // //
3250 // This routine allows that p is collinear with the line. In this case, the //
3251 // return value is zero. The two points e1 and e2 should not be identical. //
3252 // //
3254 
3256 {
3257  REAL v1[3], v2[3];
3258  REAL len, l_p;
3259 
3260  v1[0] = e2[0] - e1[0];
3261  v1[1] = e2[1] - e1[1];
3262  v1[2] = e2[2] - e1[2];
3263  v2[0] = p[0] - e1[0];
3264  v2[1] = p[1] - e1[1];
3265  v2[2] = p[2] - e1[2];
3266 
3267  len = sqrt(dot(v1, v1));
3268 
3269  v1[0] /= len;
3270  v1[1] /= len;
3271  v1[2] /= len;
3272  l_p = dot(v1, v2);
3273 
3274  return sqrt(dot(v2, v2) - l_p * l_p);
3275 }
3276 
3278 // //
3279 // triarea() Return the area of a triangle. //
3280 // //
3282 
3284 {
3285  REAL A[4][4];
3286 
3287  // Compute the coefficient matrix A (3x3).
3288  A[0][0] = pb[0] - pa[0];
3289  A[0][1] = pb[1] - pa[1];
3290  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
3291  A[1][0] = pc[0] - pa[0];
3292  A[1][1] = pc[1] - pa[1];
3293  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
3294 
3295  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
3296 
3297  return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
3298 }
3299 
3301 {
3302  REAL adx, bdx, cdx;
3303  REAL ady, bdy, cdy;
3304  REAL adz, bdz, cdz;
3305 
3306  adx = pa[0] - pd[0];
3307  bdx = pb[0] - pd[0];
3308  cdx = pc[0] - pd[0];
3309  ady = pa[1] - pd[1];
3310  bdy = pb[1] - pd[1];
3311  cdy = pc[1] - pd[1];
3312  adz = pa[2] - pd[2];
3313  bdz = pb[2] - pd[2];
3314  cdz = pc[2] - pd[2];
3315 
3316  return adx * (bdy * cdz - bdz * cdy)
3317  + bdx * (cdy * adz - cdz * ady)
3318  + cdx * (ady * bdz - adz * bdy);
3319 }
3320 
3322 // //
3323 // interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
3324 // o->p1 and o->p2. //
3325 // //
3326 // 'n' is the normal of the plane containing face (o, p1, p2). The interior //
3327 // angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
3328 // the position of p1 and p2 will get the complement angle of the other one. //
3329 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
3330 // 'n' be NULL if you only want the interior angle between 0 - PI. //
3331 // //
3333 
3335 {
3336  REAL v1[3], v2[3], np[3];
3337  REAL theta, costheta, lenlen;
3338  REAL ori, len1, len2;
3339 
3340  // Get the interior angle (0 - PI) between o->p1, and o->p2.
3341  v1[0] = p1[0] - o[0];
3342  v1[1] = p1[1] - o[1];
3343  v1[2] = p1[2] - o[2];
3344  v2[0] = p2[0] - o[0];
3345  v2[1] = p2[1] - o[1];
3346  v2[2] = p2[2] - o[2];
3347  len1 = sqrt(dot(v1, v1));
3348  len2 = sqrt(dot(v2, v2));
3349  lenlen = len1 * len2;
3350 
3351  costheta = dot(v1, v2) / lenlen;
3352  if (costheta > 1.0) {
3353  costheta = 1.0; // Roundoff.
3354  } else if (costheta < -1.0) {
3355  costheta = -1.0; // Roundoff.
3356  }
3357  theta = acos(costheta);
3358  if (n != NULL) {
3359  // Get a point above the face (o, p1, p2);
3360  np[0] = o[0] + n[0];
3361  np[1] = o[1] + n[1];
3362  np[2] = o[2] + n[2];
3363  // Adjust theta (0 - 2 * PI).
3364  ori = orient3d(p1, o, np, p2);
3365  if (ori > 0.0) {
3366  theta = 2 * PI - theta;
3367  }
3368  }
3369 
3370  return theta;
3371 }
3372 
3374 // //
3375 // projpt2edge() Return the projection point from a point to an edge. //
3376 // //
3378 
3379 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
3380 {
3381  REAL v1[3], v2[3];
3382  REAL len, l_p;
3383 
3384  v1[0] = e2[0] - e1[0];
3385  v1[1] = e2[1] - e1[1];
3386  v1[2] = e2[2] - e1[2];
3387  v2[0] = p[0] - e1[0];
3388  v2[1] = p[1] - e1[1];
3389  v2[2] = p[2] - e1[2];
3390 
3391  len = sqrt(dot(v1, v1));
3392  v1[0] /= len;
3393  v1[1] /= len;
3394  v1[2] /= len;
3395  l_p = dot(v1, v2);
3396 
3397  prj[0] = e1[0] + l_p * v1[0];
3398  prj[1] = e1[1] + l_p * v1[1];
3399  prj[2] = e1[2] + l_p * v1[2];
3400 }
3401 
3403 // //
3404 // projpt2face() Return the projection point from a point to a face. //
3405 // //
3407 
3408 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
3409 {
3410  REAL fnormal[3], v1[3];
3411  REAL len, dist;
3412 
3413  // Get the unit face normal.
3414  facenormal(f1, f2, f3, fnormal, 1, NULL);
3415  len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] +
3416  fnormal[2]*fnormal[2]);
3417  fnormal[0] /= len;
3418  fnormal[1] /= len;
3419  fnormal[2] /= len;
3420  // Get the vector v1 = |p - f1|.
3421  v1[0] = p[0] - f1[0];
3422  v1[1] = p[1] - f1[1];
3423  v1[2] = p[2] - f1[2];
3424  // Get the project distance.
3425  dist = dot(fnormal, v1);
3426 
3427  // Get the project point.
3428  prj[0] = p[0] - dist * fnormal[0];
3429  prj[1] = p[1] - dist * fnormal[1];
3430  prj[2] = p[2] - dist * fnormal[2];
3431 }
3432 
3434 // //
3435 // tetalldihedral() Get all (six) dihedral angles of a tet. //
3436 // //
3437 // If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles, //
3438 // the edge indices are given in the global array 'edge2ver'. If 'cosmaxd' //
3439 // (or 'cosmind') is not NULL, it returns the cosine of the maximal (or //
3440 // minimal) dihedral angle. //
3441 // //
3443 
3445  REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
3446 {
3447  REAL N[4][3], vol, cosd, len;
3448  int f1 = 0, f2 = 0, i, j;
3449 
3450  vol = 0; // Check if the tet is valid or not.
3451 
3452  // Get four normals of faces of the tet.
3453  tetallnormal(pa, pb, pc, pd, N, &vol);
3454 
3455  if (vol > 0) {
3456  // Normalize the normals.
3457  for (i = 0; i < 4; i++) {
3458  len = sqrt(dot(N[i], N[i]));
3459  if (len != 0.0) {
3460  for (j = 0; j < 3; j++) N[i][j] /= len;
3461  } else {
3462  // There are degeneracies, such as duplicated vertices.
3463  vol = 0; //assert(0);
3464  }
3465  }
3466  }
3467 
3468  if (vol <= 0) { // if (vol == 0.0) {
3469  // A degenerated tet or an inverted tet.
3470  facenormal(pc, pb, pd, N[0], 1, NULL);
3471  facenormal(pa, pc, pd, N[1], 1, NULL);
3472  facenormal(pb, pa, pd, N[2], 1, NULL);
3473  facenormal(pa, pb, pc, N[3], 1, NULL);
3474  // Normalize the normals.
3475  for (i = 0; i < 4; i++) {
3476  len = sqrt(dot(N[i], N[i]));
3477  if (len != 0.0) {
3478  for (j = 0; j < 3; j++) N[i][j] /= len;
3479  } else {
3480  // There are degeneracies, such as duplicated vertices.
3481  break; // Not a valid normal.
3482  }
3483  }
3484  if (i < 4) {
3485  // Do not calculate dihedral angles.
3486  // Set all angles be 0 degree. There will be no quality optimization for
3487  // this tet! Use volume optimization to correct it.
3488  if (cosdd != NULL) {
3489  for (i = 0; i < 6; i++) {
3490  cosdd[i] = -1.0; // 180 degree.
3491  }
3492  }
3493  // This tet has zero volume.
3494  if (cosmaxd != NULL) {
3495  *cosmaxd = -1.0; // 180 degree.
3496  }
3497  if (cosmind != NULL) {
3498  *cosmind = -1.0; // 180 degree.
3499  }
3500  return false;
3501  }
3502  }
3503 
3504  // Calculate the cosine of the dihedral angles of the edges.
3505  for (i = 0; i < 6; i++) {
3506  switch (i) {
3507  case 0: f1 = 0; f2 = 1; break; // [c,d].
3508  case 1: f1 = 1; f2 = 2; break; // [a,d].
3509  case 2: f1 = 2; f2 = 3; break; // [a,b].
3510  case 3: f1 = 0; f2 = 3; break; // [b,c].
3511  case 4: f1 = 2; f2 = 0; break; // [b,d].
3512  case 5: f1 = 1; f2 = 3; break; // [a,c].
3513  }
3514  cosd = -dot(N[f1], N[f2]);
3515  if (cosd < -1.0) cosd = -1.0; // Rounding.
3516  if (cosd > 1.0) cosd = 1.0; // Rounding.
3517  if (cosdd) cosdd[i] = cosd;
3518  if (cosmaxd || cosmind) {
3519  if (i == 0) {
3520  if (cosmaxd) *cosmaxd = cosd;
3521  if (cosmind) *cosmind = cosd;
3522  } else {
3523  if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
3524  if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
3525  }
3526  }
3527  }
3528 
3529  return true;
3530 }
3531 
3533 // //
3534 // tetallnormal() Get the in-normals of the four faces of a given tet. //
3535 // //
3536 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
3537 // N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices //
3538 // of the mesh data structure). These normals are unnormalized. //
3539 // //
3541 
3543  REAL N[4][3], REAL* volume)
3544 {
3545  REAL A[4][4], rhs[4], D;
3546  int indx[4];
3547  int i, j;
3548 
3549  // get the entries of A[3][3].
3550  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
3551  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
3552  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
3553 
3554  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
3555  if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
3556  if (volume != NULL) {
3557  // Get the volume of the tet.
3558  *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
3559  }
3560  for (j = 0; j < 3; j++) {
3561  for (i = 0; i < 3; i++) rhs[i] = 0.0;
3562  rhs[j] = 1.0; // Positive means the inside direction
3563  lu_solve(A, 3, indx, rhs, 0);
3564  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
3565  }
3566  // Get the fourth normal by summing up the first three.
3567  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
3568  } else {
3569  // The tet is degenerated.
3570  if (volume != NULL) {
3571  *volume = 0;
3572  }
3573  }
3574 }
3575 
3577 // //
3578 // tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
3579 // //
3580 // The aspect ratio of a tet is L/h, where L is the longest edge length, and //
3581 // h is the shortest height of the tet. //
3582 // //
3584 
3586 {
3587  REAL V[6][3], edgelength[6], longlen;
3588  REAL vda[3], vdb[3], vdc[3];
3589  REAL N[4][3], A[4][4], rhs[4], D;
3590  REAL H[4], volume, minheightinv;
3591  int indx[4];
3592  int i, j;
3593 
3594  // Set the edge vectors: V[0], ..., V[5]
3595  for (i = 0; i < 3; i++) V[0][i] = pa[i] - pd[i];
3596  for (i = 0; i < 3; i++) V[1][i] = pb[i] - pd[i];
3597  for (i = 0; i < 3; i++) V[2][i] = pc[i] - pd[i];
3598  for (i = 0; i < 3; i++) V[3][i] = pb[i] - pa[i];
3599  for (i = 0; i < 3; i++) V[4][i] = pc[i] - pb[i];
3600  for (i = 0; i < 3; i++) V[5][i] = pa[i] - pc[i];
3601 
3602  // Get the squares of the edge lengths.
3603  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
3604 
3605  // Calculate the longest and shortest edge length.
3606  longlen = edgelength[0];
3607  for (i = 1; i < 6; i++) {
3608  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
3609  }
3610 
3611  // Set the matrix A = [vda, vdb, vdc]^T.
3612  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
3613  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
3614  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
3615  // Lu-decompose the matrix A.
3616  lu_decmp(A, 3, indx, &D, 0);
3617  // Get the volume of abcd.
3618  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
3619  // Check if it is zero.
3620  if (volume == 0.0) return 1.0e+200; // A degenerate tet.
3621 
3622  // Compute the 4 face normals (N[0], ..., N[3]).
3623  for (j = 0; j < 3; j++) {
3624  for (i = 0; i < 3; i++) rhs[i] = 0.0;
3625  rhs[j] = 1.0; // Positive means the inside direction
3626  lu_solve(A, 3, indx, rhs, 0);
3627  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
3628  }
3629  // Get the fourth normal by summing up the first three.
3630  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
3631  // Normalized the normals.
3632  for (i = 0; i < 4; i++) {
3633  // H[i] is the inverse of the height of its corresponding face.
3634  H[i] = sqrt(dot(N[i], N[i]));
3635  // if (H[i] > 0.0) {
3636  // for (j = 0; j < 3; j++) N[i][j] /= H[i];
3637  // }
3638  }
3639  // Get the radius of the inscribed sphere.
3640  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
3641  // Get the biggest H[i] (corresponding to the smallest height).
3642  minheightinv = H[0];
3643  for (i = 1; i < 4; i++) {
3644  if (H[i] > minheightinv) minheightinv = H[i];
3645  }
3646 
3647  return sqrt(longlen) * minheightinv;
3648 }
3649 
3651 // //
3652 // circumsphere() Calculate the smallest circumsphere (center and radius) //
3653 // of the given three or four points. //
3654 // //
3655 // The circumsphere of four points (a tetrahedron) is unique if they are not //
3656 // degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
3657 // the diametral sphere of the triangle if they are not degenerate. //
3658 // //
3659 // Return TRUE if the input points are not degenerate and the circumcenter //
3660 // and circumradius are returned in 'cent' and 'radius' respectively if they //
3661 // are not NULLs. Otherwise, return FALSE, the four points are co-planar. //
3662 // //
3664 
3665 bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
3666  REAL* cent, REAL* radius)
3667 {
3668  REAL A[4][4], rhs[4], D;
3669  int indx[4];
3670 
3671  // Compute the coefficient matrix A (3x3).
3672  A[0][0] = pb[0] - pa[0];
3673  A[0][1] = pb[1] - pa[1];
3674  A[0][2] = pb[2] - pa[2];
3675  A[1][0] = pc[0] - pa[0];
3676  A[1][1] = pc[1] - pa[1];
3677  A[1][2] = pc[2] - pa[2];
3678  if (pd != NULL) {
3679  A[2][0] = pd[0] - pa[0];
3680  A[2][1] = pd[1] - pa[1];
3681  A[2][2] = pd[2] - pa[2];
3682  } else {
3683  cross(A[0], A[1], A[2]);
3684  }
3685 
3686  // Compute the right hand side vector b (3x1).
3687  rhs[0] = 0.5 * dot(A[0], A[0]);
3688  rhs[1] = 0.5 * dot(A[1], A[1]);
3689  if (pd != NULL) {
3690  rhs[2] = 0.5 * dot(A[2], A[2]);
3691  } else {
3692  rhs[2] = 0.0;
3693  }
3694 
3695  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
3696  // and backward and forward substitute..
3697  if (!lu_decmp(A, 3, indx, &D, 0)) {
3698  if (radius != (REAL *) NULL) *radius = 0.0;
3699  return false;
3700  }
3701  lu_solve(A, 3, indx, rhs, 0);
3702  if (cent != (REAL *) NULL) {
3703  cent[0] = pa[0] + rhs[0];
3704  cent[1] = pa[1] + rhs[1];
3705  cent[2] = pa[2] + rhs[2];
3706  }
3707  if (radius != (REAL *) NULL) {
3708  *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
3709  }
3710  return true;
3711 }
3712 
3714 // //
3715 // orthosphere() Calulcate the orthosphere of four weighted points. //
3716 // //
3717 // A weighted point (p, P^2) can be interpreted as a sphere centered at the //
3718 // point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 + //
3719 // p[1]^2 + p[2]^2 - P^2. //
3720 // //
3722 
3723 bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
3724  REAL aheight, REAL bheight, REAL cheight,
3725  REAL dheight, REAL* orthocent, REAL* radius)
3726 {
3727  REAL A[4][4], rhs[4], D;
3728  int indx[4];
3729 
3730  // Set the coefficient matrix A (4 x 4).
3731  A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
3732  A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
3733  A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
3734  A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
3735 
3736  // Set the right hand side vector (4 x 1).
3737  rhs[0] = 0.5 * aheight;
3738  rhs[1] = 0.5 * bheight;
3739  rhs[2] = 0.5 * cheight;
3740  rhs[3] = 0.5 * dheight;
3741 
3742  // Solve the 4 by 4 equations use LU decomposition with partial pivoting
3743  // and backward and forward substitute..
3744  if (!lu_decmp(A, 4, indx, &D, 0)) {
3745  if (radius != (REAL *) NULL) *radius = 0.0;
3746  return false;
3747  }
3748  lu_solve(A, 4, indx, rhs, 0);
3749 
3750  if (orthocent != (REAL *) NULL) {
3751  orthocent[0] = rhs[1];
3752  orthocent[1] = rhs[2];
3753  orthocent[2] = rhs[3];
3754  }
3755  if (radius != (REAL *) NULL) {
3756  // rhs[0] = - rheight / 2;
3757  // rheight = - 2 * rhs[0];
3758  // = r[0]^2 + r[1]^2 + r[2]^2 - radius^2
3759  // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
3760  // = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
3761  *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
3762  + 2.0 * rhs[0]);
3763  }
3764  return true;
3765 }
3766 
3768 // //
3769 // planelineint() Calculate the intersection of a line and a plane. //
3770 // //
3771 // The equation of a plane (points P are on the plane with normal N and P3 //
3772 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
3773 // line (points P on the line passing through P1 and P2) can be written as: //
3774 // P = P1 + u (P2 - P1). The intersection of these two occurs when: //
3775 // N dot (P1 + u (P2 - P1)) = N dot P3. //
3776 // Solving for u gives: //
3777 // N dot (P3 - P1) //
3778 // u = ------------------. //
3779 // N dot (P2 - P1) //
3780 // If the denominator is 0 then N (the normal to the plane) is perpendicular //
3781 // to the line. Thus the line is either parallel to the plane and there are //
3782 // no solutions or the line is on the plane in which case there are an infi- //
3783 // nite number of solutions. //
3784 // //
3785 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
3786 // line. If u is non-zero, The intersection point (if exists) returns in ip. //
3787 // //
3789 
3790 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
3791  REAL* ip, REAL* u)
3792 {
3793  REAL n[3], det, det1;
3794 
3795  // Calculate N.
3796  facenormal(pa, pb, pc, n, 1, NULL);
3797  // Calculate N dot (e2 - e1).
3798  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
3799  + n[2] * (e2[2] - e1[2]);
3800  if (det != 0.0) {
3801  // Calculate N dot (pa - e1)
3802  det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
3803  + n[2] * (pa[2] - e1[2]);
3804  *u = det1 / det;
3805  ip[0] = e1[0] + *u * (e2[0] - e1[0]);
3806  ip[1] = e1[1] + *u * (e2[1] - e1[1]);
3807  ip[2] = e1[2] + *u * (e2[2] - e1[2]);
3808  } else {
3809  *u = 0.0;
3810  }
3811 }
3812 
3814 // //
3815 // linelineint() Calculate the intersection(s) of two line segments. //
3816 // //
3817 // Calculate the line segment [P, Q] that is the shortest route between two //
3818 // lines from A to B and C to D. Calculate also the values of tp and tq //
3819 // where: P = A + tp (B - A), and Q = C + tq (D - C). //
3820 // //
3821 // Return 1 if the line segment exists. Otherwise, return 0. //
3822 // //
3824 
3826  REAL* Q, REAL* tp, REAL* tq)
3827 {
3828  REAL vab[3], vcd[3], vca[3];
3829  REAL vab_vab, vcd_vcd, vab_vcd;
3830  REAL vca_vab, vca_vcd;
3831  REAL det, eps;
3832  int i;
3833 
3834  for (i = 0; i < 3; i++) {
3835  vab[i] = B[i] - A[i];
3836  vcd[i] = D[i] - C[i];
3837  vca[i] = A[i] - C[i];
3838  }
3839 
3840  vab_vab = dot(vab, vab);
3841  vcd_vcd = dot(vcd, vcd);
3842  vab_vcd = dot(vab, vcd);
3843 
3844  det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
3845  // Round the result.
3846  eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
3847  if (eps < b->epsilon) {
3848  return 0;
3849  }
3850 
3851  vca_vab = dot(vca, vab);
3852  vca_vcd = dot(vca, vcd);
3853 
3854  *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
3855  *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
3856 
3857  for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
3858  for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
3859 
3860  return 1;
3861 }
3862 
3864 // //
3865 // tetprismvol() Calculate the volume of a tetrahedral prism in 4D. //
3866 // //
3867 // A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
3868 // tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular //
3869 // prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
3870 // vertices. (Wikipedia). //
3871 // //
3872 // Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
3873 // the lower tetrahedral facet of the prism. The top tetrahedral facet is //
3874 // formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by //
3875 // lifting each vertex of the lower facet into R^4 by a weight (height). A //
3876 // canonical choice of the weights is the square of Euclidean norm of of the //
3877 // points (vectors). //
3878 // //
3879 // //
3880 // The return value is (4!) 24 times of the volume of the tetrahedral prism. //
3881 // //
3883 
3885 {
3886  REAL *p4, *p5, *p6, *p7;
3887  REAL w4, w5, w6, w7;
3888  REAL vol[4];
3889 
3890  p4 = p0;
3891  p5 = p1;
3892  p6 = p2;
3893  p7 = p3;
3894 
3895  // TO DO: these weights can be pre-calculated!
3896  w4 = dot(p0, p0);
3897  w5 = dot(p1, p1);
3898  w6 = dot(p2, p2);
3899  w7 = dot(p3, p3);
3900 
3901  // Calculate the volume of the tet-prism.
3902  vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
3903  vol[1] = orient4d(p3, p6, p2, p0, p1, 0, w6, 0, 0, 0);
3904  vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6, 0, 0, 0);
3905  vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0, 0);
3906 
3907  return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
3908 }
3909 
3911 // //
3912 // calculateabovepoint() Calculate a point above a facet in 'dummypoint'. //
3913 // //
3915 
3917  point *ppb, point *ppc)
3918 {
3919  point *ppt, pa, pb, pc;
3920  REAL v1[3], v2[3], n[3];
3921  REAL lab, len, A, area;
3922  REAL x, y, z;
3923  int i;
3924 
3925  ppt = (point *) fastlookup(facpoints, 0);
3926  pa = *ppt; // a is the first point.
3927  pb = pc = NULL; // Avoid compiler warnings.
3928 
3929  // Get a point b s.t. the length of [a, b] is maximal.
3930  lab = 0;
3931  for (i = 1; i < facpoints->objects; i++) {
3932  ppt = (point *) fastlookup(facpoints, i);
3933  x = (*ppt)[0] - pa[0];
3934  y = (*ppt)[1] - pa[1];
3935  z = (*ppt)[2] - pa[2];
3936  len = x * x + y * y + z * z;
3937  if (len > lab) {
3938  lab = len;
3939  pb = *ppt;
3940  }
3941  }
3942  lab = sqrt(lab);
3943  if (lab == 0) {
3944  if (!b->quiet) {
3945  printf("Warning: All points of a facet are coincident with %d.\n",
3946  pointmark(pa));
3947  }
3948  return false;
3949  }
3950 
3951  // Get a point c s.t. the area of [a, b, c] is maximal.
3952  v1[0] = pb[0] - pa[0];
3953  v1[1] = pb[1] - pa[1];
3954  v1[2] = pb[2] - pa[2];
3955  A = 0;
3956  for (i = 1; i < facpoints->objects; i++) {
3957  ppt = (point *) fastlookup(facpoints, i);
3958  v2[0] = (*ppt)[0] - pa[0];
3959  v2[1] = (*ppt)[1] - pa[1];
3960  v2[2] = (*ppt)[2] - pa[2];
3961  cross(v1, v2, n);
3962  area = dot(n, n);
3963  if (area > A) {
3964  A = area;
3965  pc = *ppt;
3966  }
3967  }
3968  if (A == 0) {
3969  // All points are collinear. No above point.
3970  if (!b->quiet) {
3971  printf("Warning: All points of a facet are collinaer with [%d, %d].\n",
3972  pointmark(pa), pointmark(pb));
3973  }
3974  return false;
3975  }
3976 
3977  // Calculate an above point of this facet.
3978  facenormal(pa, pb, pc, n, 1, NULL);
3979  len = sqrt(dot(n, n));
3980  n[0] /= len;
3981  n[1] /= len;
3982  n[2] /= len;
3983  lab /= 2.0; // Half the maximal length.
3984  dummypoint[0] = pa[0] + lab * n[0];
3985  dummypoint[1] = pa[1] + lab * n[1];
3986  dummypoint[2] = pa[2] + lab * n[2];
3987 
3988  if (ppa != NULL) {
3989  // Return the three points.
3990  *ppa = pa;
3991  *ppb = pb;
3992  *ppc = pc;
3993  }
3994 
3995  return true;
3996 }
3997 
3999 // //
4000 // Calculate an above point. It lies above the plane containing the subface //
4001 // [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
4002 // is the normal of the plane. //
4003 // //
4005 
4007 {
4008  REAL n1[3], n2[3], *norm;
4009  REAL len, len1, len2;
4010 
4011  // Select a base.
4012  facenormal(pa, pb, pc, n1, 1, NULL);
4013  len1 = sqrt(dot(n1, n1));
4014  facenormal(pa, pb, pd, n2, 1, NULL);
4015  len2 = sqrt(dot(n2, n2));
4016  if (len1 > len2) {
4017  norm = n1;
4018  len = len1;
4019  } else {
4020  norm = n2;
4021  len = len2;
4022  }
4023  norm[0] /= len;
4024  norm[1] /= len;
4025  norm[2] /= len;
4026  len = distance(pa, pb);
4027  dummypoint[0] = pa[0] + len * norm[0];
4028  dummypoint[1] = pa[1] + len * norm[1];
4029  dummypoint[2] = pa[2] + len * norm[2];
4030 }
4031 
4033 // //
4034 // report_overlapping_facets() Report two overlapping facets. //
4035 // //
4036 // Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b]. //
4037 // 'dihedang' is the dihedral angle between these two facets. It must less //
4038 // than the variable 'b->facet_overlap_angle_tol'. //
4039 // //
4041 
4043 {
4044  point pa, pb, pc, pd;
4045 
4046  pa = sorg(*f1);
4047  pb = sdest(*f1);
4048  pc = sapex(*f1);
4049  pd = sapex(*f2);
4050 
4051  if (pc != pd) {
4052  printf("Found two %s self-intersecting facets (dihedral angle %12.5E).\n",
4053  dihedang > 0 ? "nearly" : "exactly",dihedang);
4054  printf(" 1st: [%d, %d, %d] #%d\n",
4055  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
4056  printf(" 2nd: [%d, %d, %d] #%d\n",
4057  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
4058  if (dihedang > 0) {
4059  printf("The dihedral angle between them is %g degree.\n",
4060  dihedang / PI * 180.0);
4061  //printf("Hint: You may use -p/# to decrease the dihedral angle");
4062  //printf(" tolerance %g (degree).\n", b->facet_overlap_ang_tol);
4063  printf("Hint: You may use Mesh.AngleToleranceFacetOverlap to decrease the dihedral angle tolerance %g (degree)",
4065  }
4066  } else {
4067  if (shellmark(*f1) != shellmark(*f2)) {
4068  // Two identical faces from two different facet.
4069  printf("Found two overlapping facets.\n");
4070  } else {
4071  printf("Found two duplicated facets.\n");
4072  }
4073  printf(" 1st: [%d, %d, %d] #%d\n",
4074  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
4075  printf(" 2nd: [%d, %d, %d] #%d\n",
4076  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
4077  }
4078 
4079  // Return the information
4080  sevent.e_type = 6;
4081  sevent.f_marker1 = shellmark(*f1);
4082  sevent.f_vertices1[0] = pointmark(pa);
4083  sevent.f_vertices1[1] = pointmark(pb);
4084  sevent.f_vertices1[2] = pointmark(pc);
4085  sevent.f_marker2 = shellmark(*f2);
4086  sevent.f_vertices2[0] = pointmark(pa);
4087  sevent.f_vertices2[1] = pointmark(pb);
4088  sevent.f_vertices2[2] = pointmark(pd);
4089 
4090  terminatetetgen(this, 3);
4091 }
4092 
4094 // //
4095 // report_selfint_edge() Report a self-intersection at an edge. //
4096 // //
4097 // The edge 'e1'->'e2' and the tetrahedron 'itet' intersect. 'dir' indicates //
4098 // that the edge intersects the tet at its origin vertex (ACROSSVERTEX), or //
4099 // its current face (ACROSSFACE), or its current edge (ACROSSEDGE). //
4100 // If 'iedge' is not NULL, it is either a segment or a subface that contains //
4101 // the edge 'e1'->'e2'. It is used to report the geometry entity. //
4102 // //
4103 // Since it is a self-intersection, the vertex, edge or face of 'itet' that //
4104 // is intersecting with this edge must be an input vertex, a segment, or a //
4105 // subface, respectively. //
4106 // //
4108 
4110  triface* itet, enum interresult dir)
4111 {
4112  point forg = NULL, fdest = NULL, fapex = NULL;
4113  int etype = 0, geomtag = 0, facemark = 0;
4114 
4115  if (iedge != NULL) {
4116  if (iedge->sh[5] != NULL) {
4117  etype = 2; // A subface
4118  forg = e1;
4119  fdest = e2;
4120  fapex = sapex(*iedge);
4121  facemark = shellmark(*iedge);
4122  } else {
4123  etype = 1; // A segment
4124  forg = farsorg(*iedge);
4125  fdest = farsdest(*iedge);
4126  // Get a facet containing this segment.
4127  face parentsh;
4128  spivot(*iedge, parentsh);
4129  if (parentsh.sh != NULL) {
4130  facemark = shellmark(parentsh);
4131  }
4132  }
4133  geomtag = shellmark(*iedge);
4134  }
4135 
4136  if (dir == SHAREEDGE) {
4137  // Two edges (segments) are coincide.
4138  face colseg;
4139  tsspivot1(*itet, colseg);
4140  if (etype == 1) {
4141  if (colseg.sh != iedge->sh) {
4142  face parentsh;
4143  spivot(colseg, parentsh);
4144  printf("PLC Error: Two segments are overlapping.\n");
4145  printf(" Segment 1: [%d, %d] #%d (%d)\n", pointmark(sorg(colseg)),
4146  pointmark(sdest(colseg)), shellmark(colseg),
4147  parentsh.sh ? shellmark(parentsh) : 0);
4148  printf(" Segment 2: [%d, %d] #%d (%d)\n", pointmark(forg),
4149  pointmark(fdest), geomtag, facemark);
4150  sevent.e_type = 4;
4151  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
4152  sevent.s_marker1 = shellmark(colseg);
4153  sevent.f_vertices1[0] = pointmark( sorg(colseg));
4154  sevent.f_vertices1[1] = pointmark(sdest(colseg));
4155  sevent.f_vertices1[2] = 0;
4156  sevent.f_marker2 = facemark;
4157  sevent.s_marker2 = geomtag;
4158  sevent.f_vertices2[0] = pointmark(forg);
4159  sevent.f_vertices2[1] = pointmark(fdest);
4160  sevent.f_vertices2[2] = 0;
4161  } else {
4162  // Two identical segments. Why report it?
4163  terminatetetgen(this, 2);
4164  }
4165  } else if (etype == 2) {
4166  printf("PLC Error: A segment lies in a facet.\n");
4167  printf(" Segment: [%d, %d] #%d\n", pointmark(sorg(colseg)),
4168  pointmark(sdest(colseg)), shellmark(colseg));
4169  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg),
4170  pointmark(fdest), pointmark(fapex), geomtag);
4171  sevent.e_type = 5;
4172  sevent.f_marker1 = 0;
4173  sevent.s_marker1 = shellmark(colseg);
4174  sevent.f_vertices1[0] = pointmark( sorg(colseg));
4175  sevent.f_vertices1[1] = pointmark(sdest(colseg));
4176  sevent.f_vertices1[2] = 0;
4177  sevent.f_marker2 = geomtag;
4178  sevent.s_marker2 = 0;
4179  sevent.f_vertices2[0] = pointmark(forg);
4180  sevent.f_vertices2[1] = pointmark(fdest);
4181  sevent.f_vertices2[2] = pointmark(fapex);
4182  }
4183  } else if (dir == SHAREFACE) {
4184  // Two triangles (subfaces) are coincide.
4185  face colface;
4186  tspivot(*itet, colface);
4187  if (etype == 2) {
4188  if (colface.sh != iedge->sh) {
4189  printf("PLC Error: Two facets are overlapping.\n");
4190  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(forg),
4191  pointmark(fdest), pointmark(fapex), geomtag);
4192  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(sorg(colface)),
4193  pointmark(sdest(colface)), pointmark(sapex(colface)),
4194  shellmark(colface));
4195  sevent.e_type = 6;
4196  sevent.f_marker1 = geomtag;
4197  sevent.s_marker1 = 0;
4198  sevent.f_vertices1[0] = pointmark(forg);
4199  sevent.f_vertices1[1] = pointmark(fdest);
4200  sevent.f_vertices1[2] = pointmark(fapex);
4201  sevent.f_marker2 = shellmark(colface);
4202  sevent.s_marker2 = 0;
4203  sevent.f_vertices2[0] = pointmark(sorg(colface));
4204  sevent.f_vertices2[1] = pointmark(sdest(colface));
4205  sevent.f_vertices2[2] = pointmark(sapex(colface));
4206  } else {
4207  // Two identical subfaces. Why report it?
4208  terminatetetgen(this, 2);
4209  }
4210  } else {
4211  terminatetetgen(this, 2);
4212  }
4213  } else if (dir == ACROSSVERT) {
4214  point pp = dest(*itet);
4215  if ((pointtype(pp) == RIDGEVERTEX) || (pointtype(pp) == FACETVERTEX)
4216  || (pointtype(pp) == VOLVERTEX)) {
4217  if (etype == 1) {
4218  printf("PLC Error: A vertex lies in a segment.\n");
4219  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
4220  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(forg),
4221  pointmark(fdest), geomtag, facemark);
4222  sevent.e_type = 7;
4223  sevent.f_marker1 = 0;
4224  sevent.s_marker1 = 0;
4225  sevent.f_vertices1[0] = pointmark(pp);
4226  sevent.f_vertices1[1] = 0;
4227  sevent.f_vertices1[2] = 0;
4228  sevent.f_marker2 = facemark;
4229  sevent.s_marker2 = geomtag;
4230  sevent.f_vertices2[0] = pointmark(forg);
4231  sevent.f_vertices2[1] = pointmark(fdest);
4232  sevent.f_vertices2[2] = 0;
4233  sevent.int_point[0] = pp[0];
4234  sevent.int_point[1] = pp[1];
4235  sevent.int_point[2] = pp[2];
4236  } else if (etype == 2) {
4237  printf("PLC Error: A vertex lies in a facet.\n");
4238  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
4239  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg), pointmark(fdest),
4240  pointmark(fapex), geomtag);
4241  sevent.e_type = 8;
4242  sevent.f_marker1 = 0;
4243  sevent.s_marker1 = 0;
4244  sevent.f_vertices1[0] = pointmark(pp);
4245  sevent.f_vertices1[1] = 0;
4246  sevent.f_vertices1[2] = 0;
4247  sevent.f_marker2 = geomtag;
4248  sevent.s_marker2 = 0;
4249  sevent.f_vertices2[0] = pointmark(forg);
4250  sevent.f_vertices2[1] = pointmark(fdest);
4251  sevent.f_vertices2[2] = pointmark(fapex);
4252  sevent.int_point[0] = pp[0];
4253  sevent.int_point[1] = pp[1];
4254  sevent.int_point[2] = pp[2];
4255  }
4256  } else if (pointtype(pp) == FREESEGVERTEX) {
4257  face parentseg, parentsh;
4258  sdecode(point2sh(pp), parentseg);
4259  spivot(parentseg, parentsh);
4260  if (parentseg.sh != NULL) {
4261  point p1 = farsorg(parentseg);
4262  point p2 = farsdest(parentseg);
4263  if (etype == 1) {
4264  printf("PLC Error: Two segments intersect at point (%g,%g,%g).\n",
4265  pp[0], pp[1], pp[2]);
4266  printf(" Segment 1: [%d, %d], #%d (%d)\n", pointmark(forg),
4267  pointmark(fdest), geomtag, facemark);
4268  printf(" Segment 2: [%d, %d], #%d (%d)\n", pointmark(p1),
4269  pointmark(p2), shellmark(parentseg),
4270  parentsh.sh ? shellmark(parentsh) : 0);
4271  sevent.e_type = 1;
4272  sevent.f_marker1 = facemark;
4273  sevent.s_marker1 = geomtag;
4274  sevent.f_vertices1[0] = pointmark(forg);
4275  sevent.f_vertices1[1] = pointmark(fdest);
4276  sevent.f_vertices1[2] = 0;
4277  sevent.f_marker2 = (parentsh.sh ? shellmark(parentsh) : 0);
4278  sevent.s_marker2 = shellmark(parentseg);
4279  sevent.f_vertices2[0] = pointmark(p1);
4280  sevent.f_vertices2[1] = pointmark(p2);
4281  sevent.f_vertices2[2] = 0;
4282  sevent.int_point[0] = pp[0];
4283  sevent.int_point[1] = pp[1];
4284  sevent.int_point[2] = pp[2];
4285  } else if (etype == 2) {
4286  printf("PLC Error: A segment and a facet intersect at point");
4287  printf(" (%g,%g,%g).\n", pp[0], pp[1], pp[2]);
4288  printf(" Segment: [%d, %d], #%d (%d)\n", pointmark(p1),
4289  pointmark(p2), shellmark(parentseg),
4290  parentsh.sh ? shellmark(parentsh) : 0);
4291  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg),
4292  pointmark(fdest), pointmark(fapex), geomtag);
4293  sevent.e_type = 2;
4294  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
4295  sevent.s_marker1 = shellmark(parentseg);
4296  sevent.f_vertices1[0] = pointmark(p1);
4297  sevent.f_vertices1[1] = pointmark(p2);
4298  sevent.f_vertices1[2] = 0;
4299  sevent.f_marker2 = geomtag;
4300  sevent.s_marker2 = 0;
4301  sevent.f_vertices2[0] = pointmark(forg);
4302  sevent.f_vertices2[1] = pointmark(fdest);
4303  sevent.f_vertices2[2] = pointmark(fapex);
4304  sevent.int_point[0] = pp[0];
4305  sevent.int_point[1] = pp[1];
4306  sevent.int_point[2] = pp[2];
4307  }
4308  } else {
4309  terminatetetgen(this, 2); // Report a bug.
4310  }
4311  } else if (pointtype(pp) == FREEFACETVERTEX) {
4312  face parentsh;
4313  sdecode(point2sh(pp), parentsh);
4314  if (parentsh.sh != NULL) {
4315  point p1 = sorg(parentsh);
4316  point p2 = sdest(parentsh);
4317  point p3 = sapex(parentsh);
4318  if (etype == 1) {
4319  printf("PLC Error: A segment and a facet intersect at point");
4320  printf(" (%g,%g,%g).\n", pp[0], pp[1], pp[2]);
4321  printf(" Segment : [%d, %d], #%d (%d)\n", pointmark(forg),
4322  pointmark(fdest), geomtag, facemark);
4323  printf(" Facet : [%d, %d, %d] #%d.\n", pointmark(p1),
4324  pointmark(p2), pointmark(p3), shellmark(parentsh));
4325  sevent.e_type = 2;
4326  sevent.f_marker1 = facemark;
4327  sevent.s_marker1 = geomtag;
4328  sevent.f_vertices1[0] = pointmark(forg);
4329  sevent.f_vertices1[1] = pointmark(fdest);
4330  sevent.f_vertices1[2] = 0;
4331  sevent.f_marker2 = shellmark(parentsh);
4332  sevent.s_marker2 = 0;
4333  sevent.f_vertices2[0] = pointmark(p1);
4334  sevent.f_vertices2[1] = pointmark(p2);
4335  sevent.f_vertices2[2] = pointmark(p3);
4336  sevent.int_point[0] = pp[0];
4337  sevent.int_point[1] = pp[1];
4338  sevent.int_point[2] = pp[2];
4339  } else if (etype == 2) {
4340  printf("PLC Error: Two facets intersect at point (%g,%g,%g).\n",
4341  pp[0], pp[1], pp[2]);
4342  printf(" Facet 1: [%d, %d, %d] #%d.\n", pointmark(forg),
4343  pointmark(fdest), pointmark(fapex), geomtag);
4344  printf(" Facet 2: [%d, %d, %d] #%d.\n", pointmark(p1),
4345  pointmark(p2), pointmark(p3), shellmark(parentsh));
4346  sevent.e_type = 3;
4347  sevent.f_marker1 = geomtag;
4348  sevent.s_marker1 = 0;
4349  sevent.f_vertices1[0] = pointmark(forg);
4350  sevent.f_vertices1[1] = pointmark(fdest);
4351  sevent.f_vertices1[2] = pointmark(fapex);
4352  sevent.f_marker2 = shellmark(parentsh);
4353  sevent.s_marker2 = 0;
4354  sevent.f_vertices2[0] = pointmark(p1);
4355  sevent.f_vertices2[1] = pointmark(p2);
4356  sevent.f_vertices2[2] = pointmark(p3);
4357  sevent.int_point[0] = pp[0];
4358  sevent.int_point[1] = pp[1];
4359  sevent.int_point[2] = pp[2];
4360  }
4361  } else {
4362  terminatetetgen(this, 2); // Report a bug.
4363  }
4364  } else if (pointtype(pp) == FREEVOLVERTEX) {
4365  // This is not a PLC error.
4366  // We should shift the vertex.
4367  // not down yet.
4368  terminatetetgen(this, 2); // Report a bug.
4369  } else {
4370  terminatetetgen(this, 2); // Report a bug.
4371  }
4372  terminatetetgen(this, 3);
4373  } else if (dir == ACROSSEDGE) {
4374  if (issubseg(*itet)) {
4375  face checkseg;
4376  tsspivot1(*itet, checkseg);
4377  face parentsh;
4378  spivot(checkseg, parentsh);
4379  // Calulcate the intersecting point.
4380  point p1 = sorg(checkseg);
4381  point p2 = sdest(checkseg);
4382  REAL P[3], Q[3], tp = 0, tq = 0;
4383  linelineint(e1, e2, p1, p2, P, Q, &tp, &tq);
4384  if (etype == 1) {
4385  printf("PLC Error: Two segments intersect at point (%g,%g,%g).\n",
4386  P[0], P[1], P[2]);
4387  printf(" Segment 1: [%d, %d] #%d (%d)\n", pointmark(forg),
4388  pointmark(fdest), geomtag, facemark);
4389  printf(" Segment 2: [%d, %d] #%d (%d)\n", pointmark(p1),
4390  pointmark(p2), shellmark(checkseg),
4391  parentsh.sh ? shellmark(parentsh) : 0);
4392  sevent.e_type = 1;
4393  sevent.f_marker1 = facemark;
4394  sevent.s_marker1 = geomtag;
4395  sevent.f_vertices1[0] = pointmark(forg);
4396  sevent.f_vertices1[1] = pointmark(fdest);
4397  sevent.f_vertices1[2] = 0;
4398  sevent.f_marker2 = (parentsh.sh ? shellmark(parentsh) : 0);
4399  sevent.s_marker2 = shellmark(checkseg);
4400  sevent.f_vertices2[0] = pointmark(p1);
4401  sevent.f_vertices2[1] = pointmark(p2);
4402  sevent.f_vertices2[2] = 0;
4403  sevent.int_point[0] = P[0];
4404  sevent.int_point[1] = P[1];
4405  sevent.int_point[2] = P[2];
4406  } else if (etype == 2) {
4407  printf("PLC Error: A segment and a facet intersect at point");
4408  printf(" (%g,%g,%g).\n", P[0], P[1], P[2]);
4409  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(p1),
4410  pointmark(p2), shellmark(checkseg),
4411  parentsh.sh ? shellmark(parentsh) : 0);
4412  printf(" Facet: [%d, %d, %d] #%d.\n", pointmark(forg),
4413  pointmark(fdest), pointmark(fapex), geomtag);
4414  sevent.e_type = 2;
4415  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
4416  sevent.s_marker1 = shellmark(checkseg);
4417  sevent.f_vertices1[0] = pointmark(p1);
4418  sevent.f_vertices1[1] = pointmark(p2);
4419  sevent.f_vertices1[2] = 0;
4420  sevent.f_marker2 = geomtag;
4421  sevent.s_marker2 = 0;
4422  sevent.f_vertices2[0] = pointmark(forg);
4423  sevent.f_vertices2[1] = pointmark(fdest);
4424  sevent.f_vertices2[2] = pointmark(fapex);
4425  sevent.int_point[0] = P[0];
4426  sevent.int_point[1] = P[1];
4427  sevent.int_point[2] = P[2];
4428  }
4429  terminatetetgen(this, 3);
4430  }
4431  } else if (dir == ACROSSFACE) {
4432  if (issubface(*itet)) {
4433  face checksh;
4434  tspivot(*itet, checksh);
4435  point p1 = sorg(checksh);
4436  point p2 = sdest(checksh);
4437  point p3 = sapex(checksh);
4438  REAL ip[3], u = 0;
4439  planelineint(p1, p2, p3, e1, e2, ip, &u);
4440  if (etype == 1) {
4441  printf("PLC Error: A segment and a facet intersect at point");
4442  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
4443  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(forg),
4444  pointmark(fdest), geomtag, facemark);
4445  printf(" Facet: [%d, %d, %d] #%d.\n", pointmark(p1),
4446  pointmark(p2), pointmark(p3), shellmark(checksh));
4447  sevent.e_type = 2;
4448  sevent.f_marker1 = facemark;
4449  sevent.s_marker1 = geomtag;
4450  sevent.f_vertices1[0] = pointmark(forg);
4451  sevent.f_vertices1[1] = pointmark(fdest);
4452  sevent.f_vertices1[2] = 0;
4453  sevent.f_marker2 = shellmark(checksh);
4454  sevent.s_marker2 = 0;
4455  sevent.f_vertices2[0] = pointmark(p1);
4456  sevent.f_vertices2[1] = pointmark(p2);
4457  sevent.f_vertices2[2] = pointmark(p3);
4458  sevent.int_point[0] = ip[0];
4459  sevent.int_point[1] = ip[1];
4460  sevent.int_point[2] = ip[2];
4461  } else if (etype == 2) {
4462  printf("PLC Error: Two facets intersect at point (%g,%g,%g).\n",
4463  ip[0], ip[1], ip[2]);
4464  printf(" Facet 1: [%d, %d, %d] #%d.\n", pointmark(forg),
4465  pointmark(fdest), pointmark(fapex), geomtag);
4466  printf(" Facet 2: [%d, %d, %d] #%d.\n", pointmark(p1),
4467  pointmark(p2), pointmark(p3), shellmark(checksh));
4468  sevent.e_type = 3;
4469  sevent.f_marker1 = geomtag;
4470  sevent.s_marker1 = 0;
4471  sevent.f_vertices1[0] = pointmark(forg);
4472  sevent.f_vertices1[1] = pointmark(fdest);
4473  sevent.f_vertices1[2] = pointmark(fapex);
4474  sevent.f_marker2 = shellmark(checksh);
4475  sevent.s_marker2 = 0;
4476  sevent.f_vertices2[0] = pointmark(p1);
4477  sevent.f_vertices2[1] = pointmark(p2);
4478  sevent.f_vertices2[2] = pointmark(p3);
4479  sevent.int_point[0] = ip[0];
4480  sevent.int_point[1] = ip[1];
4481  sevent.int_point[2] = ip[2];
4482  }
4483  terminatetetgen(this, 3);
4484  }
4485  } else {
4486  // An unknown 'dir'.
4487  terminatetetgen(this, 2);
4488  }
4489  return 0;
4490 }
4491 
4493 // //
4494 // report_selfint_face() Report a self-intersection at a facet. //
4495 // //
4496 // The triangle with vertices 'p1', 'p2', and 'p3' intersects with the edge //
4497 // of the tetrahedra 'iedge'. The intersection type is reported by 'intflag',//
4498 // 'types', and 'poss'. //
4499 // //
4500 // This routine ASSUMES (1) the triangle (p1,p2,p3) must belong to a facet, //
4501 // 'sface' is a subface of the same facet; and (2) 'iedge' must be either a //
4502 // segment or an edge of another facet. //
4503 // //
4505 
4507  triface* iedge, int intflag, int* types, int* poss)
4508 {
4509  face iface;
4510  point e1 = NULL, e2 = NULL, e3 = NULL;
4511  int etype = 0, geomtag = 0, facemark = 0;
4512 
4513  geomtag = shellmark(*sface);
4514 
4515  if (issubface(*iedge)) {
4516  tspivot(*iedge, iface);
4517  e1 = sorg(iface);
4518  e2 = sdest(iface);
4519  e3 = sapex(iface);
4520  etype = 2;
4521  facemark = geomtag;
4522  } else if (issubseg(*iedge)) {
4523  tsspivot1(*iedge, iface);
4524  e1 = farsorg(iface);
4525  e2 = farsdest(iface);
4526  etype = 1;
4527  face parentsh;
4528  spivot(iface, parentsh);
4529  //facemark = shellmark(parentsh); // Gmsh commented out, as leads to crashes
4530  } else {
4531  terminatetetgen(this, 2);
4532  }
4533 
4534  if (intflag == 2) {
4535  // The triangle and the edge intersect only at one point.
4536  REAL ip[3], u = 0;
4537  planelineint(p1, p2, p3, e1, e2, ip, &u);
4538  if ((types[0] == (int) ACROSSFACE) ||
4539  (types[0] == (int) ACROSSEDGE)) {
4540  // The triangle and the edge intersect in their interiors.
4541  if (etype == 1) {
4542  printf("PLC Error: A segment and a facet intersect at point");
4543  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
4544  printf(" Segment: [%d,%d] #%d (%d)\n", pointmark(e1), pointmark(e2),
4545  shellmark(iface), facemark);
4546  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
4547  pointmark(p2), pointmark(p3), geomtag);
4548  sevent.e_type = 2;
4549  sevent.f_marker1 = facemark;
4550  sevent.s_marker1 = shellmark(iface);
4551  sevent.f_vertices1[0] = pointmark(e1);
4552  sevent.f_vertices1[1] = pointmark(e2);
4553  sevent.f_vertices1[2] = 0;
4554  sevent.f_marker2 = geomtag;
4555  sevent.s_marker2 = 0;
4556  sevent.f_vertices2[0] = pointmark(p1);
4557  sevent.f_vertices2[1] = pointmark(p2);
4558  sevent.f_vertices2[2] = pointmark(p3);
4559  sevent.int_point[0] = ip[0];
4560  sevent.int_point[1] = ip[1];
4561  sevent.int_point[2] = ip[2];
4562  } else {
4563  printf("PLC Error: Two facets intersect at point");
4564  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
4565  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(e1), pointmark(e2),
4566  pointmark(sorg(iface)), shellmark(iface));
4567  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(p1),
4568  pointmark(p2), pointmark(p3), geomtag);
4569  sevent.e_type = 3;
4570  sevent.f_marker1 = shellmark(iface);
4571  sevent.s_marker1 = 0;
4572  sevent.f_vertices1[0] = pointmark(e1);
4573  sevent.f_vertices1[1] = pointmark(e2);
4574  sevent.f_vertices1[2] = pointmark(sorg(iface));
4575  sevent.f_marker2 = geomtag;
4576  sevent.s_marker2 = 0;
4577  sevent.f_vertices2[0] = pointmark(p1);
4578  sevent.f_vertices2[1] = pointmark(p2);
4579  sevent.f_vertices2[2] = pointmark(p3);
4580  sevent.int_point[0] = ip[0];
4581  sevent.int_point[1] = ip[1];
4582  sevent.int_point[2] = ip[2];
4583  }
4584  } else if (types[0] == (int) ACROSSVERT) {
4585  // A vertex of the triangle and the edge intersect.
4586  point crosspt = NULL;
4587  if (poss[0] == 0) {
4588  crosspt = p1;
4589  } else if (poss[0] == 1) {
4590  crosspt = p2;
4591  } else if (poss[0] == 2) {
4592  crosspt = p3;
4593  } else {
4594  terminatetetgen(this, 2);
4595  }
4596  if (!issteinerpoint(crosspt)) {
4597  if (etype == 1) {
4598  printf("PLC Error: A vertex and a segment intersect at (%g,%g,%g)\n",
4599  crosspt[0], crosspt[1], crosspt[2]);
4600  printf(" Vertex: #%d\n", pointmark(crosspt));
4601  printf(" Segment: [%d,%d] #%d (%d)\n", pointmark(e1), pointmark(e2),
4602  shellmark(iface), facemark);
4603  sevent.e_type = 7;
4604  sevent.f_marker1 = 0;
4605  sevent.s_marker1 = 0;
4606  sevent.f_vertices1[0] = pointmark(crosspt);
4607  sevent.f_vertices1[1] = 0;
4608  sevent.f_vertices1[2] = 0;
4609  sevent.f_marker2 = facemark;
4610  sevent.s_marker2 = shellmark(iface);
4611  sevent.f_vertices2[0] = pointmark(e1);
4612  sevent.f_vertices2[1] = pointmark(e2);
4613  sevent.f_vertices2[2] = 0;
4614  sevent.int_point[0] = crosspt[0];
4615  sevent.int_point[1] = crosspt[1];
4616  sevent.int_point[2] = crosspt[2];
4617  } else {
4618  printf("PLC Error: A vertex and a facet intersect at (%g,%g,%g)\n",
4619  crosspt[0], crosspt[1], crosspt[2]);
4620  printf(" Vertex: #%d\n", pointmark(crosspt));
4621  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
4622  pointmark(p2), pointmark(p3), geomtag);
4623  sevent.e_type = 8;
4624  sevent.f_marker1 = 0;
4625  sevent.s_marker1 = 0;
4626  sevent.f_vertices1[0] = pointmark(crosspt);
4627  sevent.f_vertices1[1] = 0;
4628  sevent.f_vertices1[2] = 0;
4629  sevent.f_marker2 = geomtag;
4630  sevent.s_marker2 = 0;
4631  sevent.f_vertices2[0] = pointmark(p1);
4632  sevent.f_vertices2[1] = pointmark(p2);
4633  sevent.f_vertices2[2] = pointmark(p3);
4634  sevent.int_point[0] = crosspt[0];
4635  sevent.int_point[1] = crosspt[1];
4636  sevent.int_point[2] = crosspt[2];
4637  }
4638  } else {
4639  // It is a Steiner point. To be processed.
4640  terminatetetgen(this, 2);
4641  }
4642  } else if ((types[0] == (int) TOUCHFACE) ||
4643  (types[0] == (int) TOUCHEDGE)) {
4644  // The triangle and a vertex of the edge intersect.
4645  point touchpt = NULL;
4646  if (poss[1] == 0) {
4647  touchpt = org(*iedge);
4648  } else if (poss[1] == 1) {
4649  touchpt = dest(*iedge);
4650  } else {
4651  terminatetetgen(this, 2);
4652  }
4653  if (!issteinerpoint(touchpt)) {
4654  printf("PLC Error: A vertex and a facet intersect at (%g,%g,%g)\n",
4655  touchpt[0], touchpt[1], touchpt[2]);
4656  printf(" Vertex: #%d\n", pointmark(touchpt));
4657  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
4658  pointmark(p2), pointmark(p3), geomtag);
4659  sevent.e_type = 8;
4660  sevent.f_marker1 = 0;
4661  sevent.s_marker1 = 0;
4662  sevent.f_vertices1[0] = pointmark(touchpt);
4663  sevent.f_vertices1[1] = 0;
4664  sevent.f_vertices1[2] = 0;
4665  sevent.f_marker2 = geomtag;
4666  sevent.s_marker2 = 0;
4667  sevent.f_vertices2[0] = pointmark(p1);
4668  sevent.f_vertices2[1] = pointmark(p2);
4669  sevent.f_vertices2[2] = pointmark(p3);
4670  sevent.int_point[0] = touchpt[0];
4671  sevent.int_point[1] = touchpt[1];
4672  sevent.int_point[2] = touchpt[2];
4673  } else {
4674  // It is a Steiner point. To be processed.
4675  terminatetetgen(this, 2);
4676  }
4677  } else if (types[0] == (int) SHAREVERT) {
4678  terminatetetgen(this, 2);
4679  } else {
4680  terminatetetgen(this, 2);
4681  }
4682  } else if (intflag == 4) {
4683  if (types[0] == (int) SHAREFACE) {
4684  printf("PLC Error: Two facets are overlapping.\n");
4685  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(e1),
4686  pointmark(e2), pointmark(e3), facemark);
4687  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(p1),
4688  pointmark(p2), pointmark(p3), geomtag);
4689  sevent.e_type = 6;
4690  sevent.f_marker1 = facemark;
4691  sevent.s_marker1 = 0;
4692  sevent.f_vertices1[0] = pointmark(e1);
4693  sevent.f_vertices1[1] = pointmark(e2);
4694  sevent.f_vertices1[2] = pointmark(e3);
4695  sevent.f_marker2 = geomtag;
4696  sevent.s_marker2 = 0;
4697  sevent.f_vertices2[0] = pointmark(p1);
4698  sevent.f_vertices2[1] = pointmark(p2);
4699  sevent.f_vertices2[2] = pointmark(p3);
4700  } else {
4701  terminatetetgen(this, 2);
4702  }
4703  } else {
4704  terminatetetgen(this, 2);
4705  }
4706 
4707  terminatetetgen(this, 3);
4708  return 0;
4709 }
4710 
4714 
4718 
4720 // //
4721 // flip23() Perform a 2-to-3 flip (face-to-edge flip). //
4722 // //
4723 // 'fliptets' is an array of three tets (handles), where the [0] and [1] are //
4724 // [a,b,c,d] and [b,a,c,e]. The three new tets: [e,d,a,b], [e,d,b,c], and //
4725 // [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'. As a result, //
4726 // The face [a,b,c] is removed, and the edge [d,e] is created. //
4727 // //
4728 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
4729 // the five vertices may be 'dummypoint'. There are two canonical cases: //
4730 // (1) d is 'dummypoint', then all three new tets are hull tets. If e is //
4731 // 'dummypoint', we reconfigure e to d, i.e., turn it up-side down. //
4732 // (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are //
4733 // hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
4734 // rotate the three input tets counterclockwisely (right-hand rule) //
4735 // until a or b is in c's position. //
4736 // //
4737 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
4738 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
4739 // after the insertion of a new point. It is assumed that 'd' is the new //
4740 // point. IN this case, only link faces of 'd' are queued. //
4741 // //
4743 
4744 void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
4745 {
4746  triface topcastets[3], botcastets[3];
4747  triface newface, casface;
4748  point pa, pb, pc, pd, pe;
4749  REAL attrib, volume;
4750  int dummyflag = 0; // range = {-1, 0, 1, 2}.
4751  int i;
4752 
4753  if (hullflag > 0) {
4754  // Check if e is dummypoint.
4755  if (oppo(fliptets[1]) == dummypoint) {
4756  // Swap the two old tets.
4757  newface = fliptets[0];
4758  fliptets[0] = fliptets[1];
4759  fliptets[1] = newface;
4760  dummyflag = -1; // d is dummypoint.
4761  } else {
4762  // Check if either a or b is dummypoint.
4763  if (org(fliptets[0]) == dummypoint) {
4764  dummyflag = 1; // a is dummypoint.
4765  enextself(fliptets[0]);
4766  eprevself(fliptets[1]);
4767  } else if (dest(fliptets[0]) == dummypoint) {
4768  dummyflag = 2; // b is dummypoint.
4769  eprevself(fliptets[0]);
4770  enextself(fliptets[1]);
4771  } else {
4772  dummyflag = 0; // either c or d may be dummypoint.
4773  }
4774  }
4775  }
4776 
4777  pa = org(fliptets[0]);
4778  pb = dest(fliptets[0]);
4779  pc = apex(fliptets[0]);
4780  pd = oppo(fliptets[0]);
4781  pe = oppo(fliptets[1]);
4782 
4783  flip23count++;
4784 
4785  // Get the outer boundary faces.
4786  for (i = 0; i < 3; i++) {
4787  fnext(fliptets[0], topcastets[i]);
4788  enextself(fliptets[0]);
4789  }
4790  for (i = 0; i < 3; i++) {
4791  fnext(fliptets[1], botcastets[i]);
4792  eprevself(fliptets[1]);
4793  }
4794 
4795  // Re-use fliptets[0] and fliptets[1].
4796  fliptets[0].ver = 11;
4797  fliptets[1].ver = 11;
4798  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
4799  setelemmarker(fliptets[1].tet, 0);
4800  // NOTE: the element attributes and volume constraint remain unchanged.
4801  if (checksubsegflag) {
4802  // Dealloc the space to subsegments.
4803  if (fliptets[0].tet[8] != NULL) {
4804  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
4805  fliptets[0].tet[8] = NULL;
4806  }
4807  if (fliptets[1].tet[8] != NULL) {
4808  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
4809  fliptets[1].tet[8] = NULL;
4810  }
4811  }
4812  if (checksubfaceflag) {
4813  // Dealloc the space to subfaces.
4814  if (fliptets[0].tet[9] != NULL) {
4815  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
4816  fliptets[0].tet[9] = NULL;
4817  }
4818  if (fliptets[1].tet[9] != NULL) {
4819  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
4820  fliptets[1].tet[9] = NULL;
4821  }
4822  }
4823  // Create a new tet.
4824  maketetrahedron(&(fliptets[2]));
4825  // The new tet have the same attributes from the old tet.
4826  for (i = 0; i < numelemattrib; i++) {
4827  attrib = elemattribute(fliptets[0].tet, i);
4828  setelemattribute(fliptets[2].tet, i, attrib);
4829  }
4830  if (b->varvolume) {
4831  volume = volumebound(fliptets[0].tet);
4832  setvolumebound(fliptets[2].tet, volume);
4833  }
4834 
4835  if (hullflag > 0) {
4836  // Check if d is dummytet.
4837  if (pd != dummypoint) {
4838  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
4839  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
4840  // Check if c is dummypoint.
4841  if (pc != dummypoint) {
4842  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
4843  } else {
4844  setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
4845  esymself(fliptets[2]); // [e,d,c,a] *
4846  }
4847  // The hullsize does not change.
4848  } else {
4849  // d is dummypoint.
4850  setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
4851  setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
4852  setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
4853  // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
4854  for (i = 0; i < 3; i++) {
4855  eprevesymself(fliptets[i]);
4856  enextself(fliptets[i]);
4857  }
4858  // We deleted one hull tet, and created three hull tets.
4859  hullsize += 2;
4860  }
4861  } else {
4862  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
4863  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
4864  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
4865  }
4866 
4867  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
4868  REAL volneg[2], volpos[3], vol_diff;
4869  if (pd != dummypoint) {
4870  if (pc != dummypoint) {
4871  volpos[0] = tetprismvol(pe, pd, pa, pb);
4872  volpos[1] = tetprismvol(pe, pd, pb, pc);
4873  volpos[2] = tetprismvol(pe, pd, pc, pa);
4874  volneg[0] = tetprismvol(pa, pb, pc, pd);
4875  volneg[1] = tetprismvol(pb, pa, pc, pe);
4876  } else { // pc == dummypoint
4877  volpos[0] = tetprismvol(pe, pd, pa, pb);
4878  volpos[1] = 0.;
4879  volpos[2] = 0.;
4880  volneg[0] = 0.;
4881  volneg[1] = 0.;
4882  }
4883  } else { // pd == dummypoint.
4884  volpos[0] = 0.;
4885  volpos[1] = 0.;
4886  volpos[2] = 0.;
4887  volneg[0] = 0.;
4888  volneg[1] = tetprismvol(pb, pa, pc, pe);
4889  }
4890  vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
4891  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
4892  }
4893 
4894  // Bond three new tets together.
4895  for (i = 0; i < 3; i++) {
4896  esym(fliptets[i], newface);
4897  bond(newface, fliptets[(i + 1) % 3]);
4898  }
4899  // Bond to top outer boundary faces (at [a,b,c,d]).
4900  for (i = 0; i < 3; i++) {
4901  eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
4902  bond(newface, topcastets[i]);
4903  }
4904  // Bond bottom outer boundary faces (at [b,a,c,e]).
4905  for (i = 0; i < 3; i++) {
4906  edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
4907  bond(newface, botcastets[i]);
4908  }
4909 
4910  if (checksubsegflag) {
4911  // Bond subsegments if there are.
4912  // Each new tet has 5 edges to be checked (except the edge [e,d]).
4913  face checkseg;
4914  // The middle three: [a,b], [b,c], [c,a].
4915  for (i = 0; i < 3; i++) {
4916  if (issubseg(topcastets[i])) {
4917  tsspivot1(topcastets[i], checkseg);
4918  eorgoppo(fliptets[i], newface);
4919  tssbond1(newface, checkseg);
4920  sstbond1(checkseg, newface);
4921  if (fc->chkencflag & 1) {
4922  enqueuesubface(badsubsegs, &checkseg);
4923  }
4924  }
4925  }
4926  // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
4927  for (i = 0; i < 3; i++) {
4928  eprev(topcastets[i], casface);
4929  if (issubseg(casface)) {
4930  tsspivot1(casface, checkseg);
4931  enext(fliptets[i], newface);
4932  tssbond1(newface, checkseg);
4933  sstbond1(checkseg, newface);
4934  esym(fliptets[(i + 2) % 3], newface);
4935  eprevself(newface);
4936  tssbond1(newface, checkseg);
4937  sstbond1(checkseg, newface);
4938  if (fc->chkencflag & 1) {
4939  enqueuesubface(badsubsegs, &checkseg);
4940  }
4941  }
4942  }
4943  // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
4944  for (i = 0; i < 3; i++) {
4945  enext(botcastets[i], casface);
4946  if (issubseg(casface)) {
4947  tsspivot1(casface, checkseg);
4948  eprev(fliptets[i], newface);
4949  tssbond1(newface, checkseg);
4950  sstbond1(checkseg, newface);
4951  esym(fliptets[(i + 2) % 3], newface);
4952  enextself(newface);
4953  tssbond1(newface, checkseg);
4954  sstbond1(checkseg, newface);
4955  if (fc->chkencflag & 1) {
4956  enqueuesubface(badsubsegs, &checkseg);
4957  }
4958  }
4959  }
4960  } // if (checksubsegflag)
4961 
4962  if (checksubfaceflag) {
4963  // Bond 6 subfaces if there are.
4964  face checksh;
4965  for (i = 0; i < 3; i++) {
4966  if (issubface(topcastets[i])) {
4967  tspivot(topcastets[i], checksh);
4968  eorgoppo(fliptets[i], newface);
4969  sesymself(checksh);
4970  tsbond(newface, checksh);
4971  if (fc->chkencflag & 2) {
4972  enqueuesubface(badsubfacs, &checksh);
4973  }
4974  }
4975  }
4976  for (i = 0; i < 3; i++) {
4977  if (issubface(botcastets[i])) {
4978  tspivot(botcastets[i], checksh);
4979  edestoppo(fliptets[i], newface);
4980  sesymself(checksh);
4981  tsbond(newface, checksh);
4982  if (fc->chkencflag & 2) {
4983  enqueuesubface(badsubfacs, &checksh);
4984  }
4985  }
4986  }
4987  } // if (checksubfaceflag)
4988 
4989  if (fc->chkencflag & 4) {
4990  // Put three new tets into check list.
4991  for (i = 0; i < 3; i++) {
4992  enqueuetetrahedron(&(fliptets[i]));
4993  }
4994  }
4995 
4996  // Update the point-to-tet map.
4997  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
4998  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
4999  setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
5000  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
5001  setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
5002 
5003  if (hullflag > 0) {
5004  if (dummyflag != 0) {
5005  // Restore the original position of the points (for flipnm()).
5006  if (dummyflag == -1) {
5007  // Reverse the edge.
5008  for (i = 0; i < 3; i++) {
5009  esymself(fliptets[i]);
5010  }
5011  // Swap the last two new tets.
5012  newface = fliptets[1];
5013  fliptets[1] = fliptets[2];
5014  fliptets[2] = newface;
5015  } else {
5016  // either a or b were swapped.
5017  if (dummyflag == 1) {
5018  // a is dummypoint.
5019  newface = fliptets[0];
5020  fliptets[0] = fliptets[2];
5021  fliptets[2] = fliptets[1];
5022  fliptets[1] = newface;
5023  } else { // dummyflag == 2
5024  // b is dummypoint.
5025  newface = fliptets[0];
5026  fliptets[0] = fliptets[1];
5027  fliptets[1] = fliptets[2];
5028  fliptets[2] = newface;
5029  }
5030  }
5031  }
5032  }
5033 
5034  if (fc->enqflag > 0) {
5035  // Queue faces which may be locally non-Delaunay.
5036  for (i = 0; i < 3; i++) {
5037  eprevesym(fliptets[i], newface);
5038  flippush(flipstack, &newface);
5039  }
5040  if (fc->enqflag > 1) {
5041  for (i = 0; i < 3; i++) {
5042  enextesym(fliptets[i], newface);
5043  flippush(flipstack, &newface);
5044  }
5045  }
5046  }
5047 
5048  recenttet = fliptets[0];
5049 }
5050 
5052 // //
5053 // flip32() Perform a 3-to-2 flip (edge-to-face flip). //
5054 // //
5055 // 'fliptets' is an array of three tets (handles), which are [e,d,a,b], //
5056 // [e,d,b,c], and [e,d,c,a]. The two new tets: [a,b,c,d] and [b,a,c,e] are //
5057 // returned in [0] and [1] of 'fliptets'. As a result, the edge [e,d] is //
5058 // replaced by the face [a,b,c]. //
5059 // //
5060 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
5061 // the five vertices may be 'dummypoint'. There are two canonical cases: //
5062 // (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
5063 // we reconfigure e to d, i.e., turnover it. //
5064 // (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets. //
5065 // If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
5066 // three old tets counterclockwisely (right-hand rule) until a or b //
5067 // is in c's position. //
5068 // //
5069 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
5070 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
5071 // after the insertion of a new point. It is assumed that 'a' is the new //
5072 // point. In this case, only link faces of 'a' are queued. //
5073 // //
5074 // If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a //
5075 // segment. There may be two (interior) subfaces sharing at [e,d], which are //
5076 // [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c), //
5077 // or (c,a) In such case, a 2-to-2 flip is performed on these two subfaces //
5078 // and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted //
5079 // back into the tetrahedralization. //
5080 // //
5082 
5083 void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
5084 {
5085  triface topcastets[3], botcastets[3];
5086  triface newface, casface;
5087  face flipshs[3];
5088  face checkseg;
5089  point pa, pb, pc, pd, pe;
5090  REAL attrib, volume;
5091  int dummyflag = 0; // Rangle = {-1, 0, 1, 2}
5092  int spivot = -1, scount = 0; // for flip22()
5093  int t1ver;
5094  int i, j;
5095 
5096  if (hullflag > 0) {
5097  // Check if e is 'dummypoint'.
5098  if (org(fliptets[0]) == dummypoint) {
5099  // Reverse the edge.
5100  for (i = 0; i < 3; i++) {
5101  esymself(fliptets[i]);
5102  }
5103  // Swap the last two tets.
5104  newface = fliptets[1];
5105  fliptets[1] = fliptets[2];
5106  fliptets[2] = newface;
5107  dummyflag = -1; // e is dummypoint.
5108  } else {
5109  // Check if a or b is the 'dummypoint'.
5110  if (apex(fliptets[0]) == dummypoint) {
5111  dummyflag = 1; // a is dummypoint.
5112  newface = fliptets[0];
5113  fliptets[0] = fliptets[1];
5114  fliptets[1] = fliptets[2];
5115  fliptets[2] = newface;
5116  } else if (apex(fliptets[1]) == dummypoint) {
5117  dummyflag = 2; // b is dummypoint.
5118  newface = fliptets[0];
5119  fliptets[0] = fliptets[2];
5120  fliptets[2] = fliptets[1];
5121  fliptets[1] = newface;
5122  } else {
5123  dummyflag = 0; // either c or d may be dummypoint.
5124  }
5125  }
5126  }
5127 
5128  pa = apex(fliptets[0]);
5129  pb = apex(fliptets[1]);
5130  pc = apex(fliptets[2]);
5131  pd = dest(fliptets[0]);
5132  pe = org(fliptets[0]);
5133 
5134  flip32count++;
5135 
5136  // Get the outer boundary faces.
5137  for (i = 0; i < 3; i++) {
5138  eorgoppo(fliptets[i], casface);
5139  fsym(casface, topcastets[i]);
5140  }
5141  for (i = 0; i < 3; i++) {
5142  edestoppo(fliptets[i], casface);
5143  fsym(casface, botcastets[i]);
5144  }
5145 
5146  if (checksubfaceflag) {
5147  // Check if there are interior subfaces at the edge [e,d].
5148  for (i = 0; i < 3; i++) {
5149  tspivot(fliptets[i], flipshs[i]);
5150  if (flipshs[i].sh != NULL) {
5151  // Found an interior subface.
5152  stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
5153  scount++;
5154  } else {
5155  spivot = i;
5156  }
5157  }
5158  }
5159 
5160  // Re-use fliptets[0] and fliptets[1].
5161  fliptets[0].ver = 11;
5162  fliptets[1].ver = 11;
5163  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
5164  setelemmarker(fliptets[1].tet, 0);
5165  if (checksubsegflag) {
5166  // Dealloc the space to subsegments.
5167  if (fliptets[0].tet[8] != NULL) {
5168  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
5169  fliptets[0].tet[8] = NULL;
5170  }
5171  if (fliptets[1].tet[8] != NULL) {
5172  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
5173  fliptets[1].tet[8] = NULL;
5174  }
5175  }
5176  if (checksubfaceflag) {
5177  // Dealloc the space to subfaces.
5178  if (fliptets[0].tet[9] != NULL) {
5179  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
5180  fliptets[0].tet[9] = NULL;
5181  }
5182  if (fliptets[1].tet[9] != NULL) {
5183  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
5184  fliptets[1].tet[9] = NULL;
5185  }
5186  }
5187  if (checksubfaceflag) {
5188  if (scount > 0) {
5189  // The element attributes and volume constraint must be set correctly.
5190  // There are two subfaces involved in this flip. The three tets are
5191  // separated into two different regions, one may be exterior. The
5192  // first region has two tets, and the second region has only one.
5193  // The two created tets must be in the same region as the first region.
5194  // The element attributes and volume constraint must be set correctly.
5195  //assert(spivot != -1);
5196  // The tet fliptets[spivot] is in the first region.
5197  for (j = 0; j < 2; j++) {
5198  for (i = 0; i < numelemattrib; i++) {
5199  attrib = elemattribute(fliptets[spivot].tet, i);
5200  setelemattribute(fliptets[j].tet, i, attrib);
5201  }
5202  if (b->varvolume) {
5203  volume = volumebound(fliptets[spivot].tet);
5204  setvolumebound(fliptets[j].tet, volume);
5205  }
5206  }
5207  }
5208  }
5209  // Delete an old tet.
5210  tetrahedrondealloc(fliptets[2].tet);
5211 
5212  if (hullflag > 0) {
5213  // Check if c is dummypointc.
5214  if (pc != dummypoint) {
5215  // Check if d is dummypoint.
5216  if (pd != dummypoint) {
5217  // No hull tet is involved.
5218  } else {
5219  // We deleted three hull tets, and created one hull tet.
5220  hullsize -= 2;
5221  }
5222  setvertices(fliptets[0], pa, pb, pc, pd);
5223  setvertices(fliptets[1], pb, pa, pc, pe);
5224  } else {
5225  // c is dummypoint. The two new tets are hull tets.
5226  setvertices(fliptets[0], pb, pa, pd, pc);
5227  setvertices(fliptets[1], pa, pb, pe, pc);
5228  // Adjust badc -> abcd.
5229  esymself(fliptets[0]);
5230  // Adjust abec -> bace.
5231  esymself(fliptets[1]);
5232  // The hullsize does not change.
5233  }
5234  } else {
5235  setvertices(fliptets[0], pa, pb, pc, pd);
5236  setvertices(fliptets[1], pb, pa, pc, pe);
5237  }
5238 
5239  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
5240  REAL volneg[3], volpos[2], vol_diff;
5241  if (pc != dummypoint) {
5242  if (pd != dummypoint) {
5243  volneg[0] = tetprismvol(pe, pd, pa, pb);
5244  volneg[1] = tetprismvol(pe, pd, pb, pc);
5245  volneg[2] = tetprismvol(pe, pd, pc, pa);
5246  volpos[0] = tetprismvol(pa, pb, pc, pd);
5247  volpos[1] = tetprismvol(pb, pa, pc, pe);
5248  } else { // pd == dummypoint
5249  volneg[0] = 0.;
5250  volneg[1] = 0.;
5251  volneg[2] = 0.;
5252  volpos[0] = 0.;
5253  volpos[1] = tetprismvol(pb, pa, pc, pe);
5254  }
5255  } else { // pc == dummypoint.
5256  volneg[0] = tetprismvol(pe, pd, pa, pb);
5257  volneg[1] = 0.;
5258  volneg[2] = 0.;
5259  volpos[0] = 0.;
5260  volpos[1] = 0.;
5261  }
5262  vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
5263  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
5264  }
5265 
5266  // Bond abcd <==> bace.
5267  bond(fliptets[0], fliptets[1]);
5268  // Bond new faces to top outer boundary faces (at abcd).
5269  for (i = 0; i < 3; i++) {
5270  esym(fliptets[0], newface);
5271  bond(newface, topcastets[i]);
5272  enextself(fliptets[0]);
5273  }
5274  // Bond new faces to bottom outer boundary faces (at bace).
5275  for (i = 0; i < 3; i++) {
5276  esym(fliptets[1], newface);
5277  bond(newface, botcastets[i]);
5278  eprevself(fliptets[1]);
5279  }
5280 
5281  if (checksubsegflag) {
5282  // Bond 9 segments to new (flipped) tets.
5283  for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.
5284  if (issubseg(topcastets[i])) {
5285  tsspivot1(topcastets[i], checkseg);
5286  tssbond1(fliptets[0], checkseg);
5287  sstbond1(checkseg, fliptets[0]);
5288  tssbond1(fliptets[1], checkseg);
5289  sstbond1(checkseg, fliptets[1]);
5290  if (fc->chkencflag & 1) {
5291  enqueuesubface(badsubsegs, &checkseg);
5292  }
5293  }
5294  enextself(fliptets[0]);
5295  eprevself(fliptets[1]);
5296  }
5297  // The three top edges.
5298  for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
5299  esym(fliptets[0], newface);
5300  eprevself(newface);
5301  enext(topcastets[i], casface);
5302  if (issubseg(casface)) {
5303  tsspivot1(casface, checkseg);
5304  tssbond1(newface, checkseg);
5305  sstbond1(checkseg, newface);
5306  if (fc->chkencflag & 1) {
5307  enqueuesubface(badsubsegs, &checkseg);
5308  }
5309  }
5310  enextself(fliptets[0]);
5311  }
5312  // The three bot edges.
5313  for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
5314  esym(fliptets[1], newface);
5315  enextself(newface);
5316  eprev(botcastets[i], casface);
5317  if (issubseg(casface)) {
5318  tsspivot1(casface, checkseg);
5319  tssbond1(newface, checkseg);
5320  sstbond1(checkseg, newface);
5321  if (fc->chkencflag & 1) {
5322  enqueuesubface(badsubsegs, &checkseg);
5323  }
5324  }
5325  eprevself(fliptets[1]);
5326  }
5327  } // if (checksubsegflag)
5328 
5329  if (checksubfaceflag) {
5330  face checksh;
5331  // Bond the top three casing subfaces.
5332  for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
5333  if (issubface(topcastets[i])) {
5334  tspivot(topcastets[i], checksh);
5335  esym(fliptets[0], newface);
5336  sesymself(checksh);
5337  tsbond(newface, checksh);
5338  if (fc->chkencflag & 2) {
5339  enqueuesubface(badsubfacs, &checksh);
5340  }
5341  }
5342  enextself(fliptets[0]);
5343  }
5344  // Bond the bottom three casing subfaces.
5345  for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
5346  if (issubface(botcastets[i])) {
5347  tspivot(botcastets[i], checksh);
5348  esym(fliptets[1], newface);
5349  sesymself(checksh);
5350  tsbond(newface, checksh);
5351  if (fc->chkencflag & 2) {
5352  enqueuesubface(badsubfacs, &checksh);
5353  }
5354  }
5355  eprevself(fliptets[1]);
5356  }
5357 
5358  if (scount > 0) {
5359  face flipfaces[2];
5360  // Perform a 2-to-2 flip in subfaces.
5361  flipfaces[0] = flipshs[(spivot + 1) % 3];
5362  flipfaces[1] = flipshs[(spivot + 2) % 3];
5363  sesymself(flipfaces[1]);
5364  flip22(flipfaces, 0, fc->chkencflag);
5365  // Connect the flipped subfaces to flipped tets.
5366  // First go to the corresponding flipping edge.
5367  // Re-use top- and botcastets[0].
5368  topcastets[0] = fliptets[0];
5369  botcastets[0] = fliptets[1];
5370  for (i = 0; i < ((spivot + 1) % 3); i++) {
5371  enextself(topcastets[0]);
5372  eprevself(botcastets[0]);
5373  }
5374  // Connect the top subface to the top tets.
5375  esymself(topcastets[0]);
5376  sesymself(flipfaces[0]);
5377  // Check if there already exists a subface.
5378  tspivot(topcastets[0], checksh);
5379  if (checksh.sh == NULL) {
5380  tsbond(topcastets[0], flipfaces[0]);
5381  fsymself(topcastets[0]);
5382  sesymself(flipfaces[0]);
5383  tsbond(topcastets[0], flipfaces[0]);
5384  } else {
5385  // An invalid 2-to-2 flip. Report a bug.
5386  terminatetetgen(this, 2);
5387  }
5388  // Connect the bot subface to the bottom tets.
5389  esymself(botcastets[0]);
5390  sesymself(flipfaces[1]);
5391  // Check if there already exists a subface.
5392  tspivot(botcastets[0], checksh);
5393  if (checksh.sh == NULL) {
5394  tsbond(botcastets[0], flipfaces[1]);
5395  fsymself(botcastets[0]);
5396  sesymself(flipfaces[1]);
5397  tsbond(botcastets[0], flipfaces[1]);
5398  } else {
5399  // An invalid 2-to-2 flip. Report a bug.
5400  terminatetetgen(this, 2);
5401  }
5402  } // if (scount > 0)
5403  } // if (checksubfaceflag)
5404 
5405  if (fc->chkencflag & 4) {
5406  // Put two new tets into check list.
5407  for (i = 0; i < 2; i++) {
5408  enqueuetetrahedron(&(fliptets[i]));
5409  }
5410  }
5411 
5412  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
5413  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
5414  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
5415  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
5416  setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
5417 
5418  if (hullflag > 0) {
5419  if (dummyflag != 0) {
5420  // Restore the original position of the points (for flipnm()).
5421  if (dummyflag == -1) {
5422  // e were dummypoint. Swap the two new tets.
5423  newface = fliptets[0];
5424  fliptets[0] = fliptets[1];
5425  fliptets[1] = newface;
5426  } else {
5427  // a or b was dummypoint.
5428  if (dummyflag == 1) {
5429  eprevself(fliptets[0]);
5430  enextself(fliptets[1]);
5431  } else { // dummyflag == 2
5432  enextself(fliptets[0]);
5433  eprevself(fliptets[1]);
5434  }
5435  }
5436  }
5437  }
5438 
5439  if (fc->enqflag > 0) {
5440  // Queue faces which may be locally non-Delaunay.
5441  // pa = org(fliptets[0]); // 'a' may be a new vertex.
5442  enextesym(fliptets[0], newface);
5443  flippush(flipstack, &newface);
5444  eprevesym(fliptets[1], newface);
5445  flippush(flipstack, &newface);
5446  if (fc->enqflag > 1) {
5447  //pb = dest(fliptets[0]);
5448  eprevesym(fliptets[0], newface);
5449  flippush(flipstack, &newface);
5450  enextesym(fliptets[1], newface);
5451  flippush(flipstack, &newface);
5452  //pc = apex(fliptets[0]);
5453  esym(fliptets[0], newface);
5454  flippush(flipstack, &newface);
5455  esym(fliptets[1], newface);
5456  flippush(flipstack, &newface);
5457  }
5458  }
5459 
5460  recenttet = fliptets[0];
5461 }
5462 
5464 // //
5465 // flip41() Perform a 4-to-1 flip (Remove a vertex). //
5466 // //
5467 // 'fliptets' is an array of four tetrahedra in the star of the removing //
5468 // vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
5469 // four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
5470 // p]. On return, 'fliptets[0]' is the new tet [a,b,c,d]. //
5471 // //
5472 // If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
5473 // The 'hullsize' may be changed. Note that p may be dummypoint. In this //
5474 // case, four hull tets are replaced by one real tet. //
5475 // //
5476 // If 'checksubface' flag is set (>0), it is possible that there are three //
5477 // interior subfaces connecting at p. If so, a 3-to-1 flip is performed to //
5478 // to remove p from the surface triangulation. //
5479 // //
5480 // If it is called by the routine incrementalflip(), we assume that d is the //
5481 // newly inserted vertex. //
5482 // //
5484 
5485 void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
5486 {
5487  triface topcastets[3], botcastet;
5488  triface newface, neightet;
5489  face flipshs[4];
5490  point pa, pb, pc, pd, pp;
5491  int dummyflag = 0; // in {0, 1, 2, 3, 4}
5492  int spivot = -1, scount = 0;
5493  int t1ver;
5494  int i;
5495 
5496  pa = org(fliptets[3]);
5497  pb = dest(fliptets[3]);
5498  pc = apex(fliptets[3]);
5499  pd = dest(fliptets[0]);
5500  pp = org(fliptets[0]); // The removing vertex.
5501 
5502  flip41count++;
5503 
5504  // Get the outer boundary faces.
5505  for (i = 0; i < 3; i++) {
5506  enext(fliptets[i], topcastets[i]);
5507  fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
5508  enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
5509  }
5510  fsym(fliptets[3], botcastet); // [b,a,c,#]
5511 
5512  if (checksubfaceflag) {
5513  // Check if there are three subfaces at 'p'.
5514  // Re-use 'newface'.
5515  for (i = 0; i < 3; i++) {
5516  fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
5517  tspivot(newface, flipshs[i]);
5518  if (flipshs[i].sh != NULL) {
5519  spivot = i; // Remember this subface.
5520  scount++;
5521  }
5522  enextself(fliptets[3]);
5523  }
5524  if (scount > 0) {
5525  // There are three subfaces connecting at p.
5526  if (scount < 3) {
5527  // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
5528  // Go to the tet containing the three subfaces.
5529  fsym(topcastets[spivot], neightet);
5530  // Get the three subfaces connecting at p.
5531  for (i = 0; i < 3; i++) {
5532  esym(neightet, newface);
5533  tspivot(newface, flipshs[i]);
5534  eprevself(neightet);
5535  }
5536  } else {
5537  spivot = 3; // The new subface is [a,b,c].
5538  }
5539  }
5540  } // if (checksubfaceflag)
5541 
5542 
5543  // Re-use fliptets[0] for [a,b,c,d].
5544  fliptets[0].ver = 11;
5545  setelemmarker(fliptets[0].tet, 0); // Clean all flags.
5546  // NOTE: the element attributes and volume constraint remain unchanged.
5547  if (checksubsegflag) {
5548  // Dealloc the space to subsegments.
5549  if (fliptets[0].tet[8] != NULL) {
5550  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
5551  fliptets[0].tet[8] = NULL;
5552  }
5553  }
5554  if (checksubfaceflag) {
5555  // Dealloc the space to subfaces.
5556  if (fliptets[0].tet[9] != NULL) {
5557  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
5558  fliptets[0].tet[9] = NULL;
5559  }
5560  }
5561  // Delete the other three tets.
5562  for (i = 1; i < 4; i++) {
5563  tetrahedrondealloc(fliptets[i].tet);
5564  }
5565 
5566  if (pp != dummypoint) {
5567  // Mark the point pp as unused.
5569  unuverts++;
5570  }
5571 
5572  // Create the new tet [a,b,c,d].
5573  if (hullflag > 0) {
5574  // One of the five vertices may be 'dummypoint'.
5575  if (pa == dummypoint) {
5576  // pa is dummypoint.
5577  setvertices(fliptets[0], pc, pb, pd, pa);
5578  esymself(fliptets[0]); // [b,c,a,d]
5579  eprevself(fliptets[0]); // [a,b,c,d]
5580  dummyflag = 1;
5581  } else if (pb == dummypoint) {
5582  setvertices(fliptets[0], pa, pc, pd, pb);
5583  esymself(fliptets[0]); // [c,a,b,d]
5584  enextself(fliptets[0]); // [a,b,c,d]
5585  dummyflag = 2;
5586  } else if (pc == dummypoint) {
5587  setvertices(fliptets[0], pb, pa, pd, pc);
5588  esymself(fliptets[0]); // [a,b,c,d]
5589  dummyflag = 3;
5590  } else if (pd == dummypoint) {
5591  setvertices(fliptets[0], pa, pb, pc, pd);
5592  dummyflag = 4;
5593  } else {
5594  setvertices(fliptets[0], pa, pb, pc, pd);
5595  if (pp == dummypoint) {
5596  dummyflag = -1;
5597  } else {
5598  dummyflag = 0;
5599  }
5600  }
5601  if (dummyflag > 0) {
5602  // We deleted 3 hull tets, and create 1 hull tet.
5603  hullsize -= 2;
5604  } else if (dummyflag < 0) {
5605  // We deleted 4 hull tets.
5606  hullsize -= 4;
5607  // meshedges does not change.
5608  }
5609  } else {
5610  setvertices(fliptets[0], pa, pb, pc, pd);
5611  }
5612 
5613  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
5614  REAL volneg[4], volpos[1], vol_diff;
5615  if (dummyflag > 0) {
5616  if (pa == dummypoint) {
5617  volneg[0] = 0.;
5618  volneg[1] = tetprismvol(pp, pd, pb, pc);
5619  volneg[2] = 0.;
5620  volneg[3] = 0.;
5621  } else if (pb == dummypoint) {
5622  volneg[0] = 0.;
5623  volneg[1] = 0.;
5624  volneg[2] = tetprismvol(pp, pd, pc, pa);
5625  volneg[3] = 0.;
5626  } else if (pc == dummypoint) {
5627  volneg[0] = tetprismvol(pp, pd, pa, pb);
5628  volneg[1] = 0.;
5629  volneg[2] = 0.;
5630  volneg[3] = 0.;
5631  } else { // pd == dummypoint
5632  volneg[0] = 0.;
5633  volneg[1] = 0.;
5634  volneg[2] = 0.;
5635  volneg[3] = tetprismvol(pa, pb, pc, pp);
5636  }
5637  volpos[0] = 0.;
5638  } else if (dummyflag < 0) {
5639  volneg[0] = 0.;
5640  volneg[1] = 0.;
5641  volneg[2] = 0.;
5642  volneg[3] = 0.;
5643  volpos[0] = tetprismvol(pa, pb, pc, pd);
5644  } else {
5645  volneg[0] = tetprismvol(pp, pd, pa, pb);
5646  volneg[1] = tetprismvol(pp, pd, pb, pc);
5647  volneg[2] = tetprismvol(pp, pd, pc, pa);
5648  volneg[3] = tetprismvol(pa, pb, pc, pp);
5649  volpos[0] = tetprismvol(pa, pb, pc, pd);
5650  }
5651  vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
5652  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
5653  }
5654 
5655  // Bond the new tet to adjacent tets.
5656  for (i = 0; i < 3; i++) {
5657  esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
5658  bond(newface, topcastets[i]);
5659  enextself(fliptets[0]);
5660  }
5661  bond(fliptets[0], botcastet);
5662 
5663  if (checksubsegflag) {
5664  face checkseg;
5665  // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
5666  for (i = 0; i < 3; i++) {
5667  eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
5668  if (issubseg(newface)) {
5669  tsspivot1(newface, checkseg);
5670  esym(fliptets[0], newface);
5671  enextself(newface); // At edges [a,d], [b,d], [c,d].
5672  tssbond1(newface, checkseg);
5673  sstbond1(checkseg, newface);
5674  if (fc->chkencflag & 1) {
5675  enqueuesubface(badsubsegs, &checkseg);
5676  }
5677  }
5678  enextself(fliptets[0]);
5679  }
5680  for (i = 0; i < 3; i++) {
5681  if (issubseg(topcastets[i])) {
5682  tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
5683  tssbond1(fliptets[0], checkseg);
5684  sstbond1(checkseg, fliptets[0]);
5685  if (fc->chkencflag & 1) {
5686  enqueuesubface(badsubsegs, &checkseg);
5687  }
5688  }
5689  enextself(fliptets[0]);
5690  }
5691  }
5692 
5693  if (checksubfaceflag) {
5694  face checksh;
5695  // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
5696  for (i = 0; i < 3; i++) {
5697  if (issubface(topcastets[i])) {
5698  tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
5699  esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
5700  sesymself(checksh);
5701  tsbond(newface, checksh);
5702  if (fc->chkencflag & 2) {
5703  enqueuesubface(badsubfacs, &checksh);
5704  }
5705  }
5706  enextself(fliptets[0]);
5707  }
5708  if (issubface(botcastet)) {
5709  tspivot(botcastet, checksh); // At face [b,a,c]
5710  sesymself(checksh);
5711  tsbond(fliptets[0], checksh);
5712  if (fc->chkencflag & 2) {
5713  enqueuesubface(badsubfacs, &checksh);
5714  }
5715  }
5716 
5717  if (spivot >= 0) {
5718  // Perform a 3-to-1 flip in surface triangulation.
5719  // Depending on the value of 'spivot', the three subfaces are:
5720  // - 0: [a,b,p], [b,d,p], [d,a,p]
5721  // - 1: [b,c,p], [c,d,p], [d,b,p]
5722  // - 2: [c,a,p], [a,d,p], [d,c,p]
5723  // - 3: [a,b,p], [b,c,p], [c,a,p]
5724  // Adjust the three subfaces such that their origins are p, i.e.,
5725  // - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
5726  for (i = 0; i < 3; i++) {
5727  senext2self(flipshs[i]);
5728  }
5729  flip31(flipshs, 0);
5730  // Delete the three old subfaces.
5731  for (i = 0; i < 3; i++) {
5732  shellfacedealloc(subfaces, flipshs[i].sh);
5733  }
5734  if (spivot < 3) {
5735  // // Bond the new subface to the new tet [a,b,c,d].
5736  tsbond(topcastets[spivot], flipshs[3]);
5737  fsym(topcastets[spivot], newface);
5738  sesym(flipshs[3], checksh);
5739  tsbond(newface, checksh);
5740  } else {
5741  // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
5742  tsbond(fliptets[0], flipshs[3]);
5743  fsym(fliptets[0], newface);
5744  sesym(flipshs[3], checksh);
5745  tsbond(newface, checksh);
5746  }
5747  } // if (spivot > 0)
5748  } // if (checksubfaceflag)
5749 
5750  if (fc->chkencflag & 4) {
5751  enqueuetetrahedron(&(fliptets[0]));
5752  }
5753 
5754  // Update the point-to-tet map.
5755  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
5756  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
5757  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
5758  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
5759 
5760  if (fc->enqflag > 0) {
5761  // Queue faces which may be locally non-Delaunay.
5762  flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
5763  if (fc->enqflag > 1) {
5764  for (i = 0; i < 3; i++) {
5765  esym(fliptets[0], newface);
5766  flippush(flipstack, &newface);
5767  enextself(fliptets[0]);
5768  }
5769  }
5770  }
5771 
5772  recenttet = fliptets[0];
5773 }
5774 
5776 // //
5777 // flipnm() Flip an edge through a sequence of elementary flips. //
5778 // //
5779 // 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
5780 // ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
5781 // use the right-hand rule. //
5782 // //
5783 // 'level' (>= 0) indicates the current link level. If 'level > 0', we are //
5784 // flipping a link edge of an edge [a',b'], and 'abedgepivot' indicates //
5785 // which link edge, i.e., [c',b'] or [a',c'], is [a,b] These two parameters //
5786 // allow us to determine the new tets after a 3-to-2 flip, i.e., tets that //
5787 // do not inside the reduced star of edge [a',b']. //
5788 // //
5789 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
5790 // in flipnm([a,b]) so that the mesh is returned to its original state //
5791 // before doing the flipnm([a,b]) operation. //
5792 // //
5793 // The return value is an integer nn, where nn <= n. If nn is 2, then the //
5794 // edge is flipped. The first and the second tets in 'abtets' are new tets. //
5795 // Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets //
5796 // in the current star of [a,b]. //
5797 // //
5798 // ASSUMPTIONS: //
5799 // - Neither a nor b is 'dummypoint'. //
5800 // - [a,b] must not be a segment. //
5801 // //
5803 
5804 int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
5806 {
5807  triface fliptets[3], spintet, flipedge;
5808  triface *tmpabtets, *parytet;
5809  point pa, pb, pc, pd, pe, pf;
5810  REAL ori;
5811  int hullflag, hulledgeflag;
5812  int reducflag, rejflag;
5813  int reflexlinkedgecount;
5814  int edgepivot;
5815  int n1, nn;
5816  int t1ver;
5817  int i, j;
5818 
5819  pa = org(abtets[0]);
5820  pb = dest(abtets[0]);
5821 
5822  if (n > 3) {
5823  // Try to reduce the size of the Star(ab) by flipping a face in it.
5824  reflexlinkedgecount = 0;
5825 
5826  for (i = 0; i < n; i++) {
5827  // Let the face of 'abtets[i]' be [a,b,c].
5828  if (checksubfaceflag) {
5829  if (issubface(abtets[i])) {
5830  continue; // Skip a subface.
5831  }
5832  }
5833  // Do not flip this face if it is involved in two Stars.
5834  if ((elemcounter(abtets[i]) > 1) ||
5835  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
5836  continue;
5837  }
5838 
5839  pc = apex(abtets[i]);
5840  pd = apex(abtets[(i + 1) % n]);
5841  pe = apex(abtets[(i - 1 + n) % n]);
5842  if ((pd == dummypoint) || (pe == dummypoint)) {
5843  continue; // [a,b,c] is a hull face.
5844  }
5845 
5846 
5847  // Decide whether [a,b,c] is flippable or not.
5848  reducflag = 0;
5849 
5850  hullflag = (pc == dummypoint); // pc may be dummypoint.
5851  hulledgeflag = 0;
5852  if (hullflag == 0) {
5853  ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
5854  if (ori > 0) {
5855  ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
5856  if (ori > 0) {
5857  // Test if [a,b] is locally convex OR flat.
5858  ori = orient3d(pa, pb, pd, pe);
5859  if (ori > 0) {
5860  // Found a 2-to-3 flip: [a,b,c] => [e,d]
5861  reducflag = 1;
5862  } else if (ori == 0) {
5863  // [a,b] is flat.
5864  if (n == 4) {
5865  // The "flat" tet can be removed immediately by a 3-to-2 flip.
5866  reducflag = 1;
5867  // Check if [e,d] is a hull edge.
5868  pf = apex(abtets[(i + 2) % n]);
5869  hulledgeflag = (pf == dummypoint);
5870  }
5871  }
5872  }
5873  }
5874  if (!reducflag) {
5875  reflexlinkedgecount++;
5876  }
5877  } else {
5878  // 'c' is dummypoint.
5879  if (n == 4) {
5880  // Let the vertex opposite to 'c' is 'f'.
5881  // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
5882  // are valid tets.
5883  // Note: When the mesh is not convex, it is possible that [a,b] is
5884  // locally non-convex (at hull faces [a,b,e] and [b,a,d]).
5885  // In this case, an edge flip [a,b] to [e,d] is still possible.
5886  pf = apex(abtets[(i + 2) % n]);
5887  ori = orient3d(pd, pe, pf, pa);
5888  if (ori < 0) {
5889  ori = orient3d(pe, pd, pf, pb);
5890  if (ori < 0) {
5891  // Found a 4-to-4 flip: [a,b] => [e,d]
5892  reducflag = 1;
5893  ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
5894  hulledgeflag = 1; // [e,d] is a hull edge.
5895  }
5896  }
5897  }
5898  } // if (hullflag)
5899 
5900  if (reducflag) {
5901  if (nonconvex && hulledgeflag) {
5902  // We will create a hull edge [e,d]. Make sure it does not exist.
5903  if (getedge(pe, pd, &spintet)) {
5904  // The 2-to-3 flip is not a topological valid flip.
5905  reducflag = 0;
5906  }
5907  }
5908  }
5909 
5910  if (reducflag) {
5911  // [a,b,c] could be removed by a 2-to-3 flip.
5912  rejflag = 0;
5913  if (fc->checkflipeligibility) {
5914  // Check if the flip can be performed.
5915  rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
5916  abedgepivot, fc);
5917  }
5918  if (!rejflag) {
5919  // Do flip: [a,b,c] => [e,d].
5920  fliptets[0] = abtets[i];
5921  fsym(fliptets[0], fliptets[1]); // abtets[i-1].
5922  flip23(fliptets, hullflag, fc);
5923 
5924  // Shrink the array 'abtets', maintain the original order.
5925  // Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
5926  // are flipped, i.e., they do not in Star(ab) anymore.
5927  // 'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
5928  // 'abtets[i-1]' (adjust it to be [a,b,e,d]), see below:
5929  //
5930  // before after
5931  // [0] |___________| [0] |___________|
5932  // ... |___________| ... |___________|
5933  // [i-1] |_[a,b,e,c]_| [i-1] |_[a,b,e,d]_|
5934  // [i] |_[a,b,c,d]_| --> [i] |_[a,b,d,#]_|
5935  // [i+1] |_[a,b,d,#]_| [i+1] |_[a,b,#,*]_|
5936  // ... |___________| ... |___________|
5937  // [n-2] |___________| [n-2] |___________|
5938  // [n-1] |___________| [n-1] |_[i]_2-t-3_|
5939  //
5940  edestoppoself(fliptets[0]); // [a,b,e,d]
5941  // Increase the counter of this new tet (it is in Star(ab)).
5942  increaseelemcounter(fliptets[0]);
5943  abtets[(i - 1 + n) % n] = fliptets[0];
5944  for (j = i; j < n - 1; j++) {
5945  abtets[j] = abtets[j + 1]; // Upshift
5946  }
5947  // The last entry 'abtets[n-1]' is empty. It is used in two ways:
5948  // (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
5949  // (ii) it remembers the position [i] where this flip took place.
5950  // These information let us to either undo this flip or recover
5951  // the original edge link (for collecting new created tets).
5952  abtets[n - 1].tet = (tetrahedron *) pc;
5953  abtets[n - 1].ver = 0; // Clear it.
5954  // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
5955  // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
5956  abtets[n - 1].ver |= (1 << 4);
5957  // The poisition [i] of this flip is saved above the 7th bit.
5958  abtets[n - 1].ver |= (i << 6);
5959 
5960  if (fc->collectnewtets) {
5961  // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
5962  // Re-use the global array 'cavetetlist'.
5963  for (j = 1; j < 3; j++) {
5964  cavetetlist->newindex((void **) &parytet);
5965  *parytet = fliptets[j]; // fliptets[1], fliptets[2].
5966  }
5967  }
5968 
5969  // Star(ab) is reduced. Try to flip the edge [a,b].
5970  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
5971 
5972  if (nn == 2) {
5973  // The edge has been flipped.
5974  return nn;
5975  } else { // if (nn > 2)
5976  // The edge is not flipped.
5977  if (fc->unflip || (ori == 0)) {
5978  // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to
5979  // transform [e,d] => [a,b,c].
5980  // 'ori == 0' means that the previous flip created a degenerated
5981  // tet. It must be removed.
5982  // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to
5983  // find another two tets [e,d,b,c] and [e,d,c,a].
5984  fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
5985  edestoppoself(fliptets[0]); // [e,d,a,b]
5986  fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
5987  fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
5988  // Restore the two original tets in Star(ab).
5989  flip32(fliptets, hullflag, fc);
5990  // Marktest the two restored tets in Star(ab).
5991  for (j = 0; j < 2; j++) {
5992  increaseelemcounter(fliptets[j]);
5993  }
5994  // Expand the array 'abtets', maintain the original order.
5995  for (j = n - 2; j>= i; j--) {
5996  abtets[j + 1] = abtets[j]; // Downshift
5997  }
5998  // Insert the two new tets 'fliptets[0]' [a,b,c,d] and
5999  // 'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries,
6000  // respectively.
6001  esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
6002  abtets[i] = fliptets[0]; // [a,b,c,d]
6003  nn++;
6004  if (fc->collectnewtets) {
6005  // Pop two (flipped) tets from the stack.
6006  cavetetlist->objects -= 2;
6007  }
6008  } // if (unflip || (ori == 0))
6009  } // if (nn > 2)
6010 
6011  if (!fc->unflip) {
6012  // The flips are not reversed. The current Star(ab) can not be
6013  // further reduced. Return its current size (# of tets).
6014  return nn;
6015  }
6016  // unflip is set.
6017  // Continue the search for flips.
6018  }
6019  } // if (reducflag)
6020  } // i
6021 
6022  // The Star(ab) is not reduced.
6023  if (reflexlinkedgecount > 0) {
6024  // There are reflex edges in the Link(ab).
6025  if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) ||
6026  ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
6027  // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
6028  for (i = 0; i < n; i++) {
6029  // Do not flip this face [a,b,c] if there are two Stars involved.
6030  if ((elemcounter(abtets[i]) > 1) ||
6031  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
6032  continue;
6033  }
6034  pc = apex(abtets[i]);
6035  if (pc == dummypoint) {
6036  continue; // [a,b] is a hull edge.
6037  }
6038  pd = apex(abtets[(i + 1) % n]);
6039  pe = apex(abtets[(i - 1 + n) % n]);
6040  if ((pd == dummypoint) || (pe == dummypoint)) {
6041  continue; // [a,b,c] is a hull face.
6042  }
6043 
6044 
6045  edgepivot = 0; // No edge is selected yet.
6046 
6047  // Test if [b,c] is locally convex or flat.
6048  ori = orient3d(pb, pc, pd, pe);
6049  if (ori <= 0) {
6050  // Select the edge [c,b].
6051  enext(abtets[i], flipedge); // [b,c,a,d]
6052  edgepivot = 1;
6053  }
6054  if (!edgepivot) {
6055  // Test if [c,a] is locally convex or flat.
6056  ori = orient3d(pc, pa, pd, pe);
6057  if (ori <= 0) {
6058  // Select the edge [a,c].
6059  eprev(abtets[i], flipedge); // [c,a,b,d].
6060  edgepivot = 2;
6061  }
6062  }
6063 
6064  if (!edgepivot) continue;
6065 
6066  // An edge is selected.
6067  if (checksubsegflag) {
6068  // Do not flip it if it is a segment.
6069  if (issubseg(flipedge)) {
6070  if (fc->collectencsegflag) {
6071  face checkseg, *paryseg;
6072  tsspivot1(flipedge, checkseg);
6073  if (!sinfected(checkseg)) {
6074  // Queue this segment in list.
6075  sinfect(checkseg);
6076  caveencseglist->newindex((void **) &paryseg);
6077  *paryseg = checkseg;
6078  }
6079  }
6080  continue;
6081  }
6082  }
6083 
6084  // Try to flip the selected edge ([c,b] or [a,c]).
6085  esymself(flipedge);
6086  // Count the number of tets at the edge.
6087  n1 = 0;
6088  j = 0; // Sum of the star counters.
6089  spintet = flipedge;
6090  while (1) {
6091  n1++;
6092  j += (elemcounter(spintet));
6093  fnextself(spintet);
6094  if (spintet.tet == flipedge.tet) break;
6095  }
6096  if (n1 < 3) {
6097  // This is only possible when the mesh contains inverted
6098  // elements. Reprot a bug.
6099  terminatetetgen(this, 2);
6100  }
6101  if (j > 2) {
6102  // The Star(flipedge) overlaps other Stars.
6103  continue; // Do not flip this edge.
6104  }
6105 
6106  if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
6107  // The star size exceeds the given limit.
6108  continue; // Do not flip it.
6109  }
6110 
6111  // Allocate spaces for Star(flipedge).
6112  tmpabtets = new triface[n1];
6113  // Form the Star(flipedge).
6114  j = 0;
6115  spintet = flipedge;
6116  while (1) {
6117  tmpabtets[j] = spintet;
6118  // Increase the star counter of this tet.
6119  increaseelemcounter(tmpabtets[j]);
6120  j++;
6121  fnextself(spintet);
6122  if (spintet.tet == flipedge.tet) break;
6123  }
6124 
6125  // Try to flip the selected edge away.
6126  nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
6127 
6128  if (nn == 2) {
6129  // The edge is flipped. Star(ab) is reduced.
6130  // Shrink the array 'abtets', maintain the original order.
6131  if (edgepivot == 1) {
6132  // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
6133  spintet = tmpabtets[0]; // [d,a,e,b]
6134  enextself(spintet);
6135  esymself(spintet);
6136  enextself(spintet); // [a,b,e,d]
6137  } else {
6138  // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
6139  spintet = tmpabtets[1]; // [b,d,e,a]
6140  eprevself(spintet);
6141  esymself(spintet);
6142  eprevself(spintet); // [a,b,e,d]
6143  } // edgepivot == 2
6144  increaseelemcounter(spintet); // It is in Star(ab).
6145  // Put the new tet at [i-1]-th entry.
6146  abtets[(i - 1 + n) % n] = spintet;
6147  for (j = i; j < n - 1; j++) {
6148  abtets[j] = abtets[j + 1]; // Upshift
6149  }
6150  // Remember the flips in the last entry of the array 'abtets'.
6151  // They can be used to recover the flipped edge.
6152  abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
6153  abtets[n - 1].ver = 0; // Clear it.
6154  // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
6155  abtets[n - 1].ver |= edgepivot;
6156  // Use the 6th bit to signal this n1-to-m1 flip.
6157  abtets[n - 1].ver |= (1 << 5);
6158  // The poisition [i] of this flip is saved from 7th to 19th bit.
6159  abtets[n - 1].ver |= (i << 6);
6160  // The size of the star 'n1' is saved from 20th bit.
6161  abtets[n - 1].ver |= (n1 << 19);
6162 
6163  // Remember the flipped link vertex 'c'. It can be used to recover
6164  // the original edge link of [a,b], and to collect new tets.
6165  tmpabtets[0].tet = (tetrahedron *) pc;
6166  tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
6167 
6168  // Continue to flip the edge [a,b].
6169  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
6170 
6171  if (nn == 2) {
6172  // The edge has been flipped.
6173  return nn;
6174  } else { // if (nn > 2) {
6175  // The edge is not flipped.
6176  if (fc->unflip) {
6177  // Recover the flipped edge ([c,b] or [a,c]).
6178  // The sequence of flips are saved in 'tmpabtets'.
6179  // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
6180  // the flipping of edge [c,b] or [a,c].It must still exist in
6181  // Star(ab). It is the start tet to recover the flipped edge.
6182  if (edgepivot == 1) {
6183  // The flip edge is [c,b].
6184  tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
6185  eprevself(tmpabtets[0]);
6186  esymself(tmpabtets[0]);
6187  eprevself(tmpabtets[0]); // [d,a,e,b]
6188  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
6189  } else {
6190  // The flip edge is [a,c].
6191  tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
6192  enextself(tmpabtets[1]);
6193  esymself(tmpabtets[1]);
6194  enextself(tmpabtets[1]); // [b,d,e,a]
6195  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
6196  } // if (edgepivot == 2)
6197 
6198  // Recover the flipped edge ([c,b] or [a,c]).
6199  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
6200 
6201  // Insert the two recovered tets into Star(ab).
6202  for (j = n - 2; j >= i; j--) {
6203  abtets[j + 1] = abtets[j]; // Downshift
6204  }
6205  if (edgepivot == 1) {
6206  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
6207  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
6208  // tmpabtets[2] is [c,b,e,d]
6209  fliptets[0] = tmpabtets[1];
6210  enextself(fliptets[0]);
6211  esymself(fliptets[0]); // [a,b,e,c]
6212  fliptets[1] = tmpabtets[0];
6213  esymself(fliptets[1]);
6214  eprevself(fliptets[1]); // [a,b,c,d]
6215  } else {
6216  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
6217  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
6218  // tmpabtets[2] is [a,c,e,d]
6219  fliptets[0] = tmpabtets[1];
6220  eprevself(fliptets[0]);
6221  esymself(fliptets[0]); // [a,b,e,c]
6222  fliptets[1] = tmpabtets[0];
6223  esymself(fliptets[1]);
6224  enextself(fliptets[1]); // [a,b,c,d]
6225  } // edgepivot == 2
6226  for (j = 0; j < 2; j++) {
6227  increaseelemcounter(fliptets[j]);
6228  }
6229  // Insert the two recovered tets into Star(ab).
6230  abtets[(i - 1 + n) % n] = fliptets[0];
6231  abtets[i] = fliptets[1];
6232  nn++;
6233  // Release the allocated spaces.
6234  delete [] tmpabtets;
6235  } // if (unflip)
6236  } // if (nn > 2)
6237 
6238  if (!fc->unflip) {
6239  // The flips are not reversed. The current Star(ab) can not be
6240  // further reduced. Return its size (# of tets).
6241  return nn;
6242  }
6243  // unflip is set.
6244  // Continue the search for flips.
6245  } else {
6246  // The selected edge is not flipped.
6247  if (!fc->unflip) {
6248  // Release the memory used in this attempted flip.
6249  flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
6250  }
6251  // Decrease the star counters of tets in Star(flipedge).
6252  for (j = 0; j < nn; j++) {
6253  decreaseelemcounter(tmpabtets[j]);
6254  }
6255  // Release the allocated spaces.
6256  delete [] tmpabtets;
6257  }
6258  } // i
6259  } // if (level...)
6260  } // if (reflexlinkedgecount > 0)
6261  } else {
6262  // Check if a 3-to-2 flip is possible.
6263  // Let the three apexes be c, d,and e. Hull tets may be involved. If so,
6264  // we rearrange them such that the vertex e is dummypoint.
6265  hullflag = 0;
6266 
6267  if (apex(abtets[0]) == dummypoint) {
6268  pc = apex(abtets[1]);
6269  pd = apex(abtets[2]);
6270  pe = apex(abtets[0]);
6271  hullflag = 1;
6272  } else if (apex(abtets[1]) == dummypoint) {
6273  pc = apex(abtets[2]);
6274  pd = apex(abtets[0]);
6275  pe = apex(abtets[1]);
6276  hullflag = 2;
6277  } else {
6278  pc = apex(abtets[0]);
6279  pd = apex(abtets[1]);
6280  pe = apex(abtets[2]);
6281  hullflag = (pe == dummypoint) ? 3 : 0;
6282  }
6283 
6284  reducflag = 0;
6285  rejflag = 0;
6286 
6287 
6288  if (hullflag == 0) {
6289  // Make sure that no inverted tet will be created, i.e. the new tets
6290  // [d,c,e,a] and [c,d,e,b] must be valid tets.
6291  ori = orient3d(pd, pc, pe, pa);
6292  if (ori < 0) {
6293  ori = orient3d(pc, pd, pe, pb);
6294  if (ori < 0) {
6295  reducflag = 1;
6296  }
6297  }
6298  } else {
6299  // [a,b] is a hull edge.
6300  // Note: This can happen when it is in the middle of a 4-to-4 flip.
6301  // Note: [a,b] may even be a non-convex hull edge.
6302  if (!nonconvex) {
6303  // The mesh is convex, only do flip if it is a coplanar hull edge.
6304  ori = orient3d(pa, pb, pc, pd);
6305  if (ori == 0) {
6306  reducflag = 1;
6307  }
6308  } else { // nonconvex
6309  reducflag = 1;
6310  }
6311  if (reducflag == 1) {
6312  // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
6313  // Make sure that no inverted tet will be created.
6314  point searchpt = NULL, chkpt;
6315  REAL bigvol = 0.0, ori1, ori2;
6316  // Search an interior vertex which is an apex of edge [c,d].
6317  // In principle, it can be arbitrary interior vertex. To avoid
6318  // numerical issue, we choose the vertex which belongs to a tet
6319  // 't' at edge [c,d] and 't' has the biggest volume.
6320  fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
6321  eorgoppoself(fliptets[0]); // [d,c,b,a]
6322  spintet = fliptets[0];
6323  while (1) {
6324  fnextself(spintet);
6325  chkpt = oppo(spintet);
6326  if (chkpt == pb) break;
6327  if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
6328  ori = -orient3d(pd, pc, apex(spintet), chkpt);
6329  if (ori > bigvol) {
6330  bigvol = ori;
6331  searchpt = chkpt;
6332  }
6333  }
6334  }
6335  if (searchpt != NULL) {
6336  // Now valid the configuration.
6337  ori1 = orient3d(pd, pc, searchpt, pa);
6338  ori2 = orient3d(pd, pc, searchpt, pb);
6339  if (ori1 * ori2 >= 0.0) {
6340  reducflag = 0; // Not valid.
6341  } else {
6342  ori1 = orient3d(pa, pb, searchpt, pc);
6343  ori2 = orient3d(pa, pb, searchpt, pd);
6344  if (ori1 * ori2 >= 0.0) {
6345  reducflag = 0; // Not valid.
6346  }
6347  }
6348  } else {
6349  // No valid searchpt is found.
6350  reducflag = 0; // Do not flip it.
6351  }
6352  } // if (reducflag == 1)
6353  } // if (hullflag == 1)
6354 
6355  if (reducflag) {
6356  // A 3-to-2 flip is possible.
6357  if (checksubfaceflag) {
6358  // This edge (must not be a segment) can be flipped ONLY IF it belongs
6359  // to either 0 or 2 subfaces. In the latter case, a 2-to-2 flip in
6360  // the surface mesh will be automatically performed within the
6361  // 3-to-2 flip.
6362  nn = 0;
6363  edgepivot = -1; // Re-use it.
6364  for (j = 0; j < 3; j++) {
6365  if (issubface(abtets[j])) {
6366  nn++; // Found a subface.
6367  } else {
6368  edgepivot = j;
6369  }
6370  }
6371  if (nn == 1) {
6372  // Found only 1 subface containing this edge. This can happen in
6373  // the boundary recovery phase. The neighbor subface is not yet
6374  // recovered. This edge should not be flipped at this moment.
6375  rejflag = 1;
6376  } else if (nn == 2) {
6377  // Found two subfaces. A 2-to-2 flip is possible. Validate it.
6378  // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
6379  eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
6380  if (issubface(spintet)) {
6381  rejflag = 1; // Conflict to a 2-to-2 flip.
6382  } else {
6383  esymself(spintet);
6384  if (issubface(spintet)) {
6385  rejflag = 1; // Conflict to a 2-to-2 flip.
6386  }
6387  }
6388  } else if (nn == 3) {
6389  // Report a bug.
6390  terminatetetgen(this, 2);
6391  }
6392  }
6393  if (!rejflag && fc->checkflipeligibility) {
6394  // Here we must exchange 'a' and 'b'. Since in the check... function,
6395  // we assume the following point sequence, 'a,b,c,d,e', where
6396  // the face [a,b,c] will be flipped and the edge [e,d] will be
6397  // created. The two new tets are [a,b,c,d] and [b,a,c,e].
6398  rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level,
6399  abedgepivot, fc);
6400  }
6401  if (!rejflag) {
6402  // Do flip: [a,b] => [c,d,e]
6403  flip32(abtets, hullflag, fc);
6404  if (fc->remove_ndelaunay_edge) {
6405  if (level == 0) {
6406  // It is the desired removing edge. Check if we have improved
6407  // the objective function.
6408  if ((fc->tetprism_vol_sum >= 0.0) ||
6409  (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
6410  // No improvement! flip back: [c,d,e] => [a,b].
6411  flip23(abtets, hullflag, fc);
6412  // Increase the element counter -- They are in cavity.
6413  for (j = 0; j < 3; j++) {
6414  increaseelemcounter(abtets[j]);
6415  }
6416  return 3;
6417  }
6418  } // if (level == 0)
6419  }
6420  if (fc->collectnewtets) {
6421  // Collect new tets.
6422  if (level == 0) {
6423  // Push the two new tets into stack.
6424  for (j = 0; j < 2; j++) {
6425  cavetetlist->newindex((void **) &parytet);
6426  *parytet = abtets[j];
6427  }
6428  } else {
6429  // Only one of the new tets is collected. The other one is inside
6430  // the reduced edge star. 'abedgepivot' is either '1' or '2'.
6431  cavetetlist->newindex((void **) &parytet);
6432  if (abedgepivot == 1) { // [c,b]
6433  *parytet = abtets[1];
6434  } else {
6435  *parytet = abtets[0];
6436  }
6437  }
6438  } // if (fc->collectnewtets)
6439  return 2;
6440  }
6441  } // if (reducflag)
6442  } // if (n == 3)
6443 
6444  // The current (reduced) Star size.
6445  return n;
6446 }
6447 
6449 // //
6450 // flipnm_post() Post process a n-to-m flip. //
6451 // //
6452 // IMPORTANT: This routine only works when there is no other flip operation //
6453 // is done after flipnm([a,b]) which attempts to remove an edge [a,b]. //
6454 // //
6455 // 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
6456 // [a,b] before flipnm([a,b]). 'nn' (< n) is the value returned by flipnm. //
6457 // If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
6458 // are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
6459 // b] and its initial Star([a,b]). If 'nn >= 3' edge [a,b] still exists in //
6460 // current mesh and 'nn' is the current number of tets in Star([a,b]). //
6461 // //
6462 // Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a //
6463 // flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet //
6464 // 'abtets[t-1]', where '0 <= t <= i'. These information can be used to //
6465 // undo the flips performed in flipnm([a,b]) or to collect new tets created //
6466 // by the flipnm([a,b]) operation. //
6467 // //
6468 // Default, this routine only walks through the flips and frees the spaces //
6469 // allocated during the flipnm([a,b]) operation. //
6470 // //
6471 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
6472 // in flipnm([a,b]) so that the mesh is returned to its original state //
6473 // before doing the flipnm([a,b]) operation. //
6474 // //
6475 // //
6477 
6478 int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
6480 {
6481  triface fliptets[3], flipface;
6482  triface *tmpabtets;
6483  int fliptype;
6484  int edgepivot;
6485  int t, n1;
6486  int i, j;
6487 
6488 
6489  if (nn == 2) {
6490  // The edge [a,b] has been flipped.
6491  // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
6492  // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
6493  if (fc->unflip) {
6494  // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
6495  flip23(abtets, 1, fc);
6496  if (fc->collectnewtets) {
6497  // Pop up new (flipped) tets from the stack.
6498  if (abedgepivot == 0) {
6499  // Two new tets were collected.
6500  cavetetlist->objects -= 2;
6501  } else {
6502  // Only one of the two new tets was collected.
6503  cavetetlist->objects -= 1;
6504  }
6505  }
6506  }
6507  // The initial size of Star(ab) is 3.
6508  nn++;
6509  }
6510 
6511  // Walk through the performed flips.
6512  for (i = nn; i < n; i++) {
6513  // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
6514  // At the end of this step, the size of the Star([a,b]) is 'i+1'.
6515  // The sizes of the Link([a,b]) are the same.
6516  fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
6517  if (fliptype == 1) {
6518  // It was a 2-to-3 flip: [a,b,c]->[e,d].
6519  t = (abtets[i].ver >> 6);
6520  if (fc->unflip) {
6521  if (b->verbose > 2) {
6522  printf(" Recover a 2-to-3 flip at f[%d].\n", t);
6523  }
6524  // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
6525  // it is created by a 2-to-3 flip [a,b,c] => [e,d].
6526  fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
6527  eprevself(fliptets[0]);
6528  esymself(fliptets[0]);
6529  enextself(fliptets[0]); // [e,d,a,b]
6530  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
6531  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
6532  // Do a 3-to-2 flip: [e,d] => [a,b,c].
6533  // NOTE: hull tets may be invloved.
6534  flip32(fliptets, 1, fc);
6535  // Expand the array 'abtets', maintain the original order.
6536  // The new array length is (i+1).
6537  for (j = i - 1; j >= t; j--) {
6538  abtets[j + 1] = abtets[j]; // Downshift
6539  }
6540  // The tet abtets[(t-1)%i] is deleted. Insert the two new tets
6541  // 'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
6542  // the (t-1)-th and t-th entries, respectively.
6543  esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
6544  abtets[t] = fliptets[0]; // [a,b,c,d]
6545  if (fc->collectnewtets) {
6546  // Pop up two (flipped) tets from the stack.
6547  cavetetlist->objects -= 2;
6548  }
6549  }
6550  } else if (fliptype == 2) {
6551  tmpabtets = (triface *) (abtets[i].tet);
6552  n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
6553  edgepivot = (abtets[i].ver & 3);
6554  t = ((abtets[i].ver >> 6) & 8191);
6555  if (fc->unflip) {
6556  if (b->verbose > 2) {
6557  printf(" Recover a %d-to-m flip at e[%d] of f[%d].\n", n1,
6558  edgepivot, t);
6559  }
6560  // Recover the flipped edge ([c,b] or [a,c]).
6561  // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
6562  // the flipping of edge [c,b] or [a,c]. It must still exist in
6563  // Star(ab). Use it to recover the flipped edge.
6564  if (edgepivot == 1) {
6565  // The flip edge is [c,b].
6566  tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
6567  eprevself(tmpabtets[0]);
6568  esymself(tmpabtets[0]);
6569  eprevself(tmpabtets[0]); // [d,a,e,b]
6570  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
6571  } else {
6572  // The flip edge is [a,c].
6573  tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
6574  enextself(tmpabtets[1]);
6575  esymself(tmpabtets[1]);
6576  enextself(tmpabtets[1]); // [b,d,e,a]
6577  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
6578  } // if (edgepivot == 2)
6579 
6580  // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
6581  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
6582 
6583  // Insert the two recovered tets into the original Star(ab).
6584  for (j = i - 1; j >= t; j--) {
6585  abtets[j + 1] = abtets[j]; // Downshift
6586  }
6587  if (edgepivot == 1) {
6588  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
6589  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
6590  // tmpabtets[2] is [c,b,e,d]
6591  fliptets[0] = tmpabtets[1];
6592  enextself(fliptets[0]);
6593  esymself(fliptets[0]); // [a,b,e,c]
6594  fliptets[1] = tmpabtets[0];
6595  esymself(fliptets[1]);
6596  eprevself(fliptets[1]); // [a,b,c,d]
6597  } else {
6598  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
6599  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
6600  // tmpabtets[2] is [a,c,e,d]
6601  fliptets[0] = tmpabtets[1];
6602  eprevself(fliptets[0]);
6603  esymself(fliptets[0]); // [a,b,e,c]
6604  fliptets[1] = tmpabtets[0];
6605  esymself(fliptets[1]);
6606  enextself(fliptets[1]); // [a,b,c,d]
6607  } // edgepivot == 2
6608  // Insert the two recovered tets into Star(ab).
6609  abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
6610  abtets[t] = fliptets[1];
6611  }
6612  else {
6613  // Only free the spaces.
6614  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
6615  } // if (!unflip)
6616  if (b->verbose > 2) {
6617  printf(" Release %d spaces at f[%d].\n", n1, i);
6618  }
6619  delete [] tmpabtets;
6620  }
6621  } // i
6622 
6623  return 1;
6624 }
6625 
6627 // //
6628 // insertpoint() Insert a point into current tetrahedralization. //
6629 // //
6630 // The Bowyer-Watson (B-W) algorithm is used to add a new point p into the //
6631 // tetrahedralization T. It first finds a "cavity", denoted as C, in T, C //
6632 // consists of tetrahedra in T that "conflict" with p. If T is a Delaunay //
6633 // tetrahedralization, then all boundary faces (triangles) of C are visible //
6634 // by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
6635 // tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
6636 // C and p. If T is not a DT, then C may be not star-shaped. It must be //
6637 // modified so that it becomes star-shaped. //
6638 // //
6640 
6641 int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
6642  face *splitseg, insertvertexflags *ivf)
6643 {
6644  arraypool *swaplist;
6645  triface *cavetet, spintet, neightet, neineitet, *parytet;
6646  triface oldtet, newtet, newneitet;
6647  face checksh, neighsh, *parysh;
6648  face checkseg, *paryseg;
6649  point *pts, pa, pb, pc, *parypt;
6650  enum locateresult loc = OUTSIDE;
6651  REAL sign, ori;
6652  REAL attrib, volume;
6653  bool enqflag;
6654  int t1ver;
6655  int i, j, k, s;
6656 
6657  if (b->verbose > 2) {
6658  printf(" Insert point %d\n", pointmark(insertpt));
6659  }
6660 
6661  // Locate the point.
6662  if (searchtet->tet != NULL) {
6663  loc = (enum locateresult) ivf->iloc;
6664  }
6665 
6666  if (loc == OUTSIDE) {
6667  if (searchtet->tet == NULL) {
6668  if (!b->weighted) {
6669  randomsample(insertpt, searchtet);
6670  } else {
6671  // Weighted DT. There may exist dangling vertex.
6672  *searchtet = recenttet;
6673  }
6674  }
6675  // Locate the point.
6676  loc = locate(insertpt, searchtet);
6677  }
6678 
6679  ivf->iloc = (int) loc; // The return value.
6680 
6681  if (b->weighted) {
6682  if (loc != OUTSIDE) {
6683  // Check if this vertex is regular.
6684  pts = (point *) searchtet->tet;
6685  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
6686  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
6687  insertpt[3]);
6688  if (sign > 0) {
6689  // This new vertex lies above the lower hull. Do not insert it.
6690  ivf->iloc = (int) NONREGULAR;
6691  return 0;
6692  }
6693  }
6694  }
6695 
6696  // Create the initial cavity C(p) which contains all tetrahedra that
6697  // intersect p. It may include 1, 2, or n tetrahedra.
6698  // If p lies on a segment or subface, also create the initial sub-cavity
6699  // sC(p) which contains all subfaces (and segment) which intersect p.
6700 
6701  if (loc == OUTSIDE) {
6702  flip14count++;
6703  // The current hull will be enlarged.
6704  // Add four adjacent boundary tets into list.
6705  for (i = 0; i < 4; i++) {
6706  decode(searchtet->tet[i], neightet);
6707  neightet.ver = epivot[neightet.ver];
6708  cavebdrylist->newindex((void **) &parytet);
6709  *parytet = neightet;
6710  }
6711  infect(*searchtet);
6712  caveoldtetlist->newindex((void **) &parytet);
6713  *parytet = *searchtet;
6714  } else if (loc == INTETRAHEDRON) {
6715  flip14count++;
6716  // Add four adjacent boundary tets into list.
6717  for (i = 0; i < 4; i++) {
6718  decode(searchtet->tet[i], neightet);
6719  neightet.ver = epivot[neightet.ver];
6720  cavebdrylist->newindex((void **) &parytet);
6721  *parytet = neightet;
6722  }
6723  infect(*searchtet);
6724  caveoldtetlist->newindex((void **) &parytet);
6725  *parytet = *searchtet;
6726  } else if (loc == ONFACE) {
6727  flip26count++;
6728  // Add six adjacent boundary tets into list.
6729  j = (searchtet->ver & 3); // The current face number.
6730  for (i = 1; i < 4; i++) {
6731  decode(searchtet->tet[(j + i) % 4], neightet);
6732  neightet.ver = epivot[neightet.ver];
6733  cavebdrylist->newindex((void **) &parytet);
6734  *parytet = neightet;
6735  }
6736  decode(searchtet->tet[j], spintet);
6737  j = (spintet.ver & 3); // The current face number.
6738  for (i = 1; i < 4; i++) {
6739  decode(spintet.tet[(j + i) % 4], neightet);
6740  neightet.ver = epivot[neightet.ver];
6741  cavebdrylist->newindex((void **) &parytet);
6742  *parytet = neightet;
6743  }
6744  infect(spintet);
6745  caveoldtetlist->newindex((void **) &parytet);
6746  *parytet = spintet;
6747  infect(*searchtet);
6748  caveoldtetlist->newindex((void **) &parytet);
6749  *parytet = *searchtet;
6750 
6751  if (ivf->splitbdflag) {
6752  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
6753  // Create the initial sub-cavity sC(p).
6754  smarktest(*splitsh);
6755  caveshlist->newindex((void **) &parysh);
6756  *parysh = *splitsh;
6757  }
6758  } // if (splitbdflag)
6759  } else if (loc == ONEDGE) {
6760  flipn2ncount++;
6761  // Add all adjacent boundary tets into list.
6762  spintet = *searchtet;
6763  while (1) {
6764  eorgoppo(spintet, neightet);
6765  decode(neightet.tet[neightet.ver & 3], neightet);
6766  neightet.ver = epivot[neightet.ver];
6767  cavebdrylist->newindex((void **) &parytet);
6768  *parytet = neightet;
6769  edestoppo(spintet, neightet);
6770  decode(neightet.tet[neightet.ver & 3], neightet);
6771  neightet.ver = epivot[neightet.ver];
6772  cavebdrylist->newindex((void **) &parytet);
6773  *parytet = neightet;
6774  infect(spintet);
6775  caveoldtetlist->newindex((void **) &parytet);
6776  *parytet = spintet;
6777  fnextself(spintet);
6778  if (spintet.tet == searchtet->tet) break;
6779  } // while (1)
6780 
6781  if (ivf->splitbdflag) {
6782  // Create the initial sub-cavity sC(p).
6783  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
6784  smarktest(*splitseg);
6785  splitseg->shver = 0;
6786  spivot(*splitseg, *splitsh);
6787  }
6788  if (splitsh != NULL) {
6789  if (splitsh->sh != NULL) {
6790  // Collect all subfaces share at this edge.
6791  pa = sorg(*splitsh);
6792  neighsh = *splitsh;
6793  while (1) {
6794  // Adjust the origin of its edge to be 'pa'.
6795  if (sorg(neighsh) != pa) {
6796  sesymself(neighsh);
6797  }
6798  // Add this face into list (in B-W cavity).
6799  smarktest(neighsh);
6800  caveshlist->newindex((void **) &parysh);
6801  *parysh = neighsh;
6802  // Add this face into face-at-splitedge list.
6803  cavesegshlist->newindex((void **) &parysh);
6804  *parysh = neighsh;
6805  // Go to the next face at the edge.
6806  spivotself(neighsh);
6807  // Stop if all faces at the edge have been visited.
6808  if (neighsh.sh == splitsh->sh) break;
6809  if (neighsh.sh == NULL) break;
6810  } // while (1)
6811  } // if (not a dangling segment)
6812  }
6813  } // if (splitbdflag)
6814  } else if (loc == INSTAR) {
6815  // We assume that all tets in the star are given in 'caveoldtetlist',
6816  // and they are all infected.
6817  // Collect the boundary faces of the star.
6818  for (i = 0; i < caveoldtetlist->objects; i++) {
6819  cavetet = (triface *) fastlookup(caveoldtetlist, i);
6820  // Check its 4 neighbor tets.
6821  for (j = 0; j < 4; j++) {
6822  decode(cavetet->tet[j], neightet);
6823  if (!infected(neightet)) {
6824  // It's a boundary face.
6825  neightet.ver = epivot[neightet.ver];
6826  cavebdrylist->newindex((void **) &parytet);
6827  *parytet = neightet;
6828  }
6829  }
6830  }
6831  } else if (loc == ONVERTEX) {
6832  // The point already exist. Do nothing and return.
6833  return 0;
6834  }
6835 
6836 
6837  if (ivf->bowywat) {
6838  // Update the cavity C(p) using the Bowyer-Watson algorithm.
6839  swaplist = cavetetlist;
6841  cavebdrylist = swaplist;
6842  for (i = 0; i < cavetetlist->objects; i++) {
6843  // 'cavetet' is an adjacent tet at outside of the cavity.
6844  cavetet = (triface *) fastlookup(cavetetlist, i);
6845  // The tet may be tested and included in the (enlarged) cavity.
6846  if (!infected(*cavetet)) {
6847  // Check for two possible cases for this tet:
6848  // (1) It is a cavity tet, or
6849  // (2) it is a cavity boundary face.
6850  enqflag = false;
6851  if (!marktested(*cavetet)) {
6852  // Do Delaunay (in-sphere) test.
6853  pts = (point *) cavetet->tet;
6854  if (pts[7] != dummypoint) {
6855  // A volume tet. Operate on it.
6856  if (b->weighted) {
6857  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
6858  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
6859  insertpt[3]);
6860  } else {
6861  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
6862  }
6863  enqflag = (sign < 0.0);
6864  } else {
6865  if (!nonconvex) {
6866  // Test if this hull face is visible by the new point.
6867  ori = orient3d(pts[4], pts[5], pts[6], insertpt);
6868  if (ori < 0) {
6869  // A visible hull face.
6870  // Include it in the cavity. The convex hull will be enlarged.
6871  enqflag = true;
6872  } else if (ori == 0.0) {
6873  // A coplanar hull face. We need to test if this hull face is
6874  // Delaunay or not. We test if the adjacent tet (not faked)
6875  // of this hull face is Delaunay or not.
6876  decode(cavetet->tet[3], neineitet);
6877  if (!infected(neineitet)) {
6878  if (!marktested(neineitet)) {
6879  // Do Delaunay test on this tet.
6880  pts = (point *) neineitet.tet;
6881  if (b->weighted) {
6882  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
6883  pts[4][3], pts[5][3], pts[6][3],
6884  pts[7][3], insertpt[3]);
6885  } else {
6886  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
6887  }
6888  enqflag = (sign < 0.0);
6889  }
6890  } else {
6891  // The adjacent tet is non-Delaunay. The hull face is non-
6892  // Delaunay as well. Include it in the cavity.
6893  enqflag = true;
6894  } // if (!infected(neineitet))
6895  } // if (ori == 0.0)
6896  } else {
6897  // A hull face (must be a subface).
6898  // We FIRST include it in the initial cavity if the adjacent tet
6899  // (not faked) of this hull face is not Delaunay wrt p.
6900  // Whether it belongs to the final cavity will be determined
6901  // during the validation process. 'validflag'.
6902  decode(cavetet->tet[3], neineitet);
6903  if (!infected(neineitet)) {
6904  if (!marktested(neineitet)) {
6905  // Do Delaunay test on this tet.
6906  pts = (point *) neineitet.tet;
6907  if (b->weighted) {
6908  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
6909  pts[4][3], pts[5][3], pts[6][3],
6910  pts[7][3], insertpt[3]);
6911  } else {
6912  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
6913  }
6914  enqflag = (sign < 0.0);
6915  }
6916  } else {
6917  // The adjacent tet is non-Delaunay. The hull face is non-
6918  // Delaunay as well. Include it in the cavity.
6919  enqflag = true;
6920  } // if (infected(neineitet))
6921  } // if (nonconvex)
6922  } // if (pts[7] != dummypoint)
6923  marktest(*cavetet); // Only test it once.
6924  } // if (!marktested(*cavetet))
6925 
6926  if (enqflag) {
6927  // Found a tet in the cavity. Put other three faces in check list.
6928  k = (cavetet->ver & 3); // The current face number
6929  for (j = 1; j < 4; j++) {
6930  decode(cavetet->tet[(j + k) % 4], neightet);
6931  cavetetlist->newindex((void **) &parytet);
6932  *parytet = neightet;
6933  }
6934  infect(*cavetet);
6935  caveoldtetlist->newindex((void **) &parytet);
6936  *parytet = *cavetet;
6937  } else {
6938  // Found a boundary face of the cavity.
6939  cavetet->ver = epivot[cavetet->ver];
6940  cavebdrylist->newindex((void **) &parytet);
6941  *parytet = *cavetet;
6942  }
6943  } // if (!infected(*cavetet))
6944  } // i
6945 
6946  cavetetlist->restart(); // Clear the working list.
6947  } // if (ivf->bowywat)
6948 
6949  if (checksubsegflag) {
6950  // Collect all segments of C(p).
6951  shellface *ssptr;
6952  for (i = 0; i < caveoldtetlist->objects; i++) {
6953  cavetet = (triface *) fastlookup(caveoldtetlist, i);
6954  if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
6955  for (j = 0; j < 6; j++) {
6956  if (ssptr[j]) {
6957  sdecode(ssptr[j], checkseg);
6958  if (!sinfected(checkseg)) {
6959  sinfect(checkseg);
6960  cavetetseglist->newindex((void **) &paryseg);
6961  *paryseg = checkseg;
6962  }
6963  }
6964  } // j
6965  }
6966  } // i
6967  // Uninfect collected segments.
6968  for (i = 0; i < cavetetseglist->objects; i++) {
6969  paryseg = (face *) fastlookup(cavetetseglist, i);
6970  suninfect(*paryseg);
6971  }
6972 
6973  } // if (checksubsegflag)
6974 
6975  if (checksubfaceflag) {
6976  // Collect all subfaces of C(p).
6977  shellface *sptr;
6978  for (i = 0; i < caveoldtetlist->objects; i++) {
6979  cavetet = (triface *) fastlookup(caveoldtetlist, i);
6980  if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
6981  for (j = 0; j < 4; j++) {
6982  if (sptr[j]) {
6983  sdecode(sptr[j], checksh);
6984  if (!sinfected(checksh)) {
6985  sinfect(checksh);
6986  cavetetshlist->newindex((void **) &parysh);
6987  *parysh = checksh;
6988  }
6989  }
6990  } // j
6991  }
6992  } // i
6993  // Uninfect collected subfaces.
6994  for (i = 0; i < cavetetshlist->objects; i++) {
6995  parysh = (face *) fastlookup(cavetetshlist, i);
6996  suninfect(*parysh);
6997  }
6998 
6999  } // if (checksubfaceflag)
7000 
7001  if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
7002  // The vertex lies outside of the domain. And it does not encroach
7003  // upon any boundary segment or subface. Do not insert it.
7004  insertpoint_abort(splitseg, ivf);
7005  return 0;
7006  }
7007 
7008  if (ivf->splitbdflag) {
7009  // The new point locates in surface mesh. Update the sC(p).
7010  // We have already 'smarktested' the subfaces which directly intersect
7011  // with p in 'caveshlist'. From them, we 'smarktest' their neighboring
7012  // subfaces which are included in C(p). Do not across a segment.
7013  for (i = 0; i < caveshlist->objects; i++) {
7014  parysh = (face *) fastlookup(caveshlist, i);
7015  checksh = *parysh;
7016  for (j = 0; j < 3; j++) {
7017  if (!isshsubseg(checksh)) {
7018  spivot(checksh, neighsh);
7019  if (!smarktested(neighsh)) {
7020  stpivot(neighsh, neightet);
7021  if (infected(neightet)) {
7022  fsymself(neightet);
7023  if (infected(neightet)) {
7024  // This subface is inside C(p).
7025  // Check if its diametrical circumsphere encloses 'p'.
7026  // The purpose of this check is to avoid forming invalid
7027  // subcavity in surface mesh.
7028  sign = incircle3d(sorg(neighsh), sdest(neighsh),
7029  sapex(neighsh), insertpt);
7030  if (sign < 0) {
7031  smarktest(neighsh);
7032  caveshlist->newindex((void **) &parysh);
7033  *parysh = neighsh;
7034  }
7035  }
7036  }
7037  }
7038  }
7039  senextself(checksh);
7040  } // j
7041  } // i
7042  } // if (ivf->splitbdflag)
7043 
7044  if (ivf->validflag) {
7045  // Validate C(p) and update it if it is not star-shaped.
7046  int cutcount = 0;
7047 
7048  if (ivf->respectbdflag) {
7049  // The initial cavity may include subfaces which are not on the facets
7050  // being splitting. Find them and make them as boundary of C(p).
7051  // Comment: We have already 'smarktested' the subfaces in sC(p). They
7052  // are completely inside C(p).
7053  for (i = 0; i < cavetetshlist->objects; i++) {
7054  parysh = (face *) fastlookup(cavetetshlist, i);
7055  stpivot(*parysh, neightet);
7056  if (infected(neightet)) {
7057  fsymself(neightet);
7058  if (infected(neightet)) {
7059  // Found a subface inside C(p).
7060  if (!smarktested(*parysh)) {
7061  // It is possible that this face is a boundary subface.
7062  // Check if it is a hull face.
7063  //assert(apex(neightet) != dummypoint);
7064  if (oppo(neightet) != dummypoint) {
7065  fsymself(neightet);
7066  }
7067  if (oppo(neightet) != dummypoint) {
7068  ori = orient3d(org(neightet), dest(neightet), apex(neightet),
7069  insertpt);
7070  if (ori < 0) {
7071  // A visible face, get its neighbor face.
7072  fsymself(neightet);
7073  ori = -ori; // It must be invisible by p.
7074  }
7075  } else {
7076  // A hull tet. It needs to be cut.
7077  ori = 1;
7078  }
7079  // Cut this tet if it is either invisible by or coplanar with p.
7080  if (ori >= 0) {
7081  uninfect(neightet);
7082  unmarktest(neightet);
7083  cutcount++;
7084  neightet.ver = epivot[neightet.ver];
7085  cavebdrylist->newindex((void **) &parytet);
7086  *parytet = neightet;
7087  // Add three new faces to find new boundaries.
7088  for (j = 0; j < 3; j++) {
7089  esym(neightet, neineitet);
7090  neineitet.ver = epivot[neineitet.ver];
7091  cavebdrylist->newindex((void **) &parytet);
7092  *parytet = neineitet;
7093  enextself(neightet);
7094  }
7095  } // if (ori >= 0)
7096  }
7097  }
7098  }
7099  } // i
7100 
7101  // The initial cavity may include segments in its interior. We need to
7102  // Update the cavity so that these segments are on the boundary of
7103  // the cavity.
7104  for (i = 0; i < cavetetseglist->objects; i++) {
7105  paryseg = (face *) fastlookup(cavetetseglist, i);
7106  // Check this segment if it is not a splitting segment.
7107  if (!smarktested(*paryseg)) {
7108  sstpivot1(*paryseg, neightet);
7109  spintet = neightet;
7110  while (1) {
7111  if (!infected(spintet)) break;
7112  fnextself(spintet);
7113  if (spintet.tet == neightet.tet) break;
7114  }
7115  if (infected(spintet)) {
7116  // Find an adjacent tet at this segment such that both faces
7117  // at this segment are not visible by p.
7118  pa = org(neightet);
7119  pb = dest(neightet);
7120  spintet = neightet;
7121  j = 0;
7122  while (1) {
7123  // Check if this face is visible by p.
7124  pc = apex(spintet);
7125  if (pc != dummypoint) {
7126  ori = orient3d(pa, pb, pc, insertpt);
7127  if (ori >= 0) {
7128  // Not visible. Check another face in this tet.
7129  esym(spintet, neineitet);
7130  pc = apex(neineitet);
7131  if (pc != dummypoint) {
7132  ori = orient3d(pb, pa, pc, insertpt);
7133  if (ori >= 0) {
7134  // Not visible. Found this face.
7135  j = 1; // Flag that it is found.
7136  break;
7137  }
7138  }
7139  }
7140  }
7141  fnextself(spintet);
7142  if (spintet.tet == neightet.tet) break;
7143  }
7144  if (j == 0) {
7145  // Not found such a face.
7146  terminatetetgen(this, 2);
7147  }
7148  neightet = spintet;
7149  if (b->verbose > 3) {
7150  printf(" Cut tet (%d, %d, %d, %d)\n",
7151  pointmark(org(neightet)), pointmark(dest(neightet)),
7152  pointmark(apex(neightet)), pointmark(oppo(neightet)));
7153  }
7154  uninfect(neightet);
7155  unmarktest(neightet);
7156  cutcount++;
7157  neightet.ver = epivot[neightet.ver];
7158  cavebdrylist->newindex((void **) &parytet);
7159  *parytet = neightet;
7160  // Add three new faces to find new boundaries.
7161  for (j = 0; j < 3; j++) {
7162  esym(neightet, neineitet);
7163  neineitet.ver = epivot[neineitet.ver];
7164  cavebdrylist->newindex((void **) &parytet);
7165  *parytet = neineitet;
7166  enextself(neightet);
7167  }
7168  }
7169  }
7170  } // i
7171  } // if (ivf->respectbdflag)
7172 
7173  // Update the cavity by removing invisible faces until it is star-shaped.
7174  for (i = 0; i < cavebdrylist->objects; i++) {
7175  cavetet = (triface *) fastlookup(cavebdrylist, i);
7176  // 'cavetet' is an exterior tet adjacent to the cavity.
7177  // Check if its neighbor is inside C(p).
7178  fsym(*cavetet, neightet);
7179  if (infected(neightet)) {
7180  if (apex(*cavetet) != dummypoint) {
7181  // It is a cavity boundary face. Check its visibility.
7182  if (oppo(neightet) != dummypoint) {
7183  // Check if this face is visible by the new point.
7184  if (issubface(neightet)) {
7185  // We should only create a new tet that has a reasonable volume.
7186  // Re-use 'volume' and 'attrib'.
7187  pa = org(*cavetet);
7188  pb = dest(*cavetet);
7189  pc = apex(*cavetet);
7190  volume = orient3dfast(pa, pb, pc, insertpt);
7191  attrib = distance(pa, pb) * distance(pb, pc) * distance(pc, pa);
7192  if ((fabs(volume) / attrib) < b->epsilon) {
7193  ori = 0.0;
7194  } else {
7195  ori = orient3d(pa, pb, pc, insertpt);
7196  }
7197  } else {
7198  ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
7199  insertpt);
7200  }
7201  enqflag = (ori > 0);
7202  // Comment: if ori == 0 (coplanar case), we also cut the tet.
7203  } else {
7204  // It is a hull face. And its adjacent tet (at inside of the
7205  // domain) has been cut from the cavity. Cut it as well.
7206  //assert(nonconvex);
7207  enqflag = false;
7208  }
7209  } else {
7210  enqflag = true; // A hull edge.
7211  }
7212  if (enqflag) {
7213  // This face is valid, save it.
7214  cavetetlist->newindex((void **) &parytet);
7215  *parytet = *cavetet;
7216  } else {
7217  uninfect(neightet);
7218  unmarktest(neightet);
7219  cutcount++;
7220  // Add three new faces to find new boundaries.
7221  for (j = 0; j < 3; j++) {
7222  esym(neightet, neineitet);
7223  neineitet.ver = epivot[neineitet.ver];
7224  cavebdrylist->newindex((void **) &parytet);
7225  *parytet = neineitet;
7226  enextself(neightet);
7227  }
7228  // 'cavetet' is not on the cavity boundary anymore.
7229  unmarktest(*cavetet);
7230  }
7231  } else {
7232  // 'cavetet' is not on the cavity boundary anymore.
7233  unmarktest(*cavetet);
7234  }
7235  } // i
7236 
7237  if (cutcount > 0) {
7238  // The cavity has been updated.
7239  // Update the cavity boundary faces.
7240  cavebdrylist->restart();
7241  for (i = 0; i < cavetetlist->objects; i++) {
7242  cavetet = (triface *) fastlookup(cavetetlist, i);
7243  // 'cavetet' was an exterior tet adjacent to the cavity.
7244  fsym(*cavetet, neightet);
7245  if (infected(neightet)) {
7246  // It is a cavity boundary face.
7247  cavebdrylist->newindex((void **) &parytet);
7248  *parytet = *cavetet;
7249  } else {
7250  // Not a cavity boundary face.
7251  unmarktest(*cavetet);
7252  }
7253  }
7254 
7255  // Update the list of old tets.
7256  cavetetlist->restart();
7257  for (i = 0; i < caveoldtetlist->objects; i++) {
7258  cavetet = (triface *) fastlookup(caveoldtetlist, i);
7259  if (infected(*cavetet)) {
7260  cavetetlist->newindex((void **) &parytet);
7261  *parytet = *cavetet;
7262  }
7263  }
7264  // Swap 'cavetetlist' and 'caveoldtetlist'.
7265  swaplist = caveoldtetlist;
7267  cavetetlist = swaplist;
7268 
7269  // The cavity should contain at least one tet.
7270  if (caveoldtetlist->objects == 0l) {
7271  insertpoint_abort(splitseg, ivf);
7272  ivf->iloc = (int) BADELEMENT;
7273  return 0;
7274  }
7275 
7276  if (ivf->splitbdflag) {
7277  int cutshcount = 0;
7278  // Update the sub-cavity sC(p).
7279  for (i = 0; i < caveshlist->objects; i++) {
7280  parysh = (face *) fastlookup(caveshlist, i);
7281  if (smarktested(*parysh)) {
7282  enqflag = false;
7283  stpivot(*parysh, neightet);
7284  if (infected(neightet)) {
7285  fsymself(neightet);
7286  if (infected(neightet)) {
7287  enqflag = true;
7288  }
7289  }
7290  if (!enqflag) {
7291  sunmarktest(*parysh);
7292  // Use the last entry of this array to fill this entry.
7293  j = caveshlist->objects - 1;
7294  checksh = * (face *) fastlookup(caveshlist, j);
7295  *parysh = checksh;
7296  cutshcount++;
7297  caveshlist->objects--; // The list is shrinked.
7298  i--;
7299  }
7300  }
7301  }
7302 
7303  if (cutshcount > 0) {
7304  i = 0; // Count the number of invalid subfaces/segments.
7305  // Valid the updated sub-cavity sC(p).
7306  if (loc == ONFACE) {
7307  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
7308  // The to-be split subface should be in sC(p).
7309  if (!smarktested(*splitsh)) i++;
7310  }
7311  } else if (loc == ONEDGE) {
7312  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
7313  // The to-be split segment should be in sC(p).
7314  if (!smarktested(*splitseg)) i++;
7315  }
7316  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
7317  // All subfaces at this edge should be in sC(p).
7318  pa = sorg(*splitsh);
7319  neighsh = *splitsh;
7320  while (1) {
7321  // Adjust the origin of its edge to be 'pa'.
7322  if (sorg(neighsh) != pa) {
7323  sesymself(neighsh);
7324  }
7325  // Add this face into list (in B-W cavity).
7326  if (!smarktested(neighsh)) i++;
7327  // Go to the next face at the edge.
7328  spivotself(neighsh);
7329  // Stop if all faces at the edge have been visited.
7330  if (neighsh.sh == splitsh->sh) break;
7331  if (neighsh.sh == NULL) break;
7332  } // while (1)
7333  }
7334  }
7335 
7336  if (i > 0) {
7337  // The updated sC(p) is invalid. Do not insert this vertex.
7338  insertpoint_abort(splitseg, ivf);
7339  ivf->iloc = (int) BADELEMENT;
7340  return 0;
7341  }
7342  } // if (cutshcount > 0)
7343  } // if (ivf->splitbdflag)
7344  } // if (cutcount > 0)
7345 
7346  } // if (ivf->validflag)
7347 
7348  if (ivf->refineflag) {
7349  // The new point is inserted by Delaunay refinement, i.e., it is the
7350  // circumcenter of a tetrahedron, or a subface, or a segment.
7351  // Do not insert this point if the tetrahedron, or subface, or segment
7352  // is not inside the final cavity.
7353  if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
7354  ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
7355  insertpoint_abort(splitseg, ivf);
7356  ivf->iloc = (int) BADELEMENT;
7357  return 0;
7358  }
7359  } // if (ivf->refineflag)
7360 
7361  if (b->plc && (loc != INSTAR)) {
7362  // Reject the new point if it lies too close to an existing point (b->plc),
7363  // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
7364  // Collect the list of vertices of the initial cavity.
7365  if (loc == OUTSIDE) {
7366  pts = (point *) &(searchtet->tet[4]);
7367  for (i = 0; i < 3; i++) {
7368  cavetetvertlist->newindex((void **) &parypt);
7369  *parypt = pts[i];
7370  }
7371  } else if (loc == INTETRAHEDRON) {
7372  pts = (point *) &(searchtet->tet[4]);
7373  for (i = 0; i < 4; i++) {
7374  cavetetvertlist->newindex((void **) &parypt);
7375  *parypt = pts[i];
7376  }
7377  } else if (loc == ONFACE) {
7378  pts = (point *) &(searchtet->tet[4]);
7379  for (i = 0; i < 3; i++) {
7380  cavetetvertlist->newindex((void **) &parypt);
7381  *parypt = pts[i];
7382  }
7383  if (pts[3] != dummypoint) {
7384  cavetetvertlist->newindex((void **) &parypt);
7385  *parypt = pts[3];
7386  }
7387  fsym(*searchtet, spintet);
7388  if (oppo(spintet) != dummypoint) {
7389  cavetetvertlist->newindex((void **) &parypt);
7390  *parypt = oppo(spintet);
7391  }
7392  } else if (loc == ONEDGE) {
7393  spintet = *searchtet;
7394  cavetetvertlist->newindex((void **) &parypt);
7395  *parypt = org(spintet);
7396  cavetetvertlist->newindex((void **) &parypt);
7397  *parypt = dest(spintet);
7398  while (1) {
7399  if (apex(spintet) != dummypoint) {
7400  cavetetvertlist->newindex((void **) &parypt);
7401  *parypt = apex(spintet);
7402  }
7403  fnextself(spintet);
7404  if (spintet.tet == searchtet->tet) break;
7405  }
7406  }
7407 
7408  int rejptflag = (ivf->rejflag & 4);
7409  REAL rd;
7410  pts = NULL;
7411 
7412  for (i = 0; i < cavetetvertlist->objects; i++) {
7413  parypt = (point *) fastlookup(cavetetvertlist, i);
7414  rd = distance(*parypt, insertpt);
7415  // Is the point very close to an existing point?
7416  if (rd < minedgelength) {
7417  pts = parypt;
7418  loc = NEARVERTEX;
7419  break;
7420  }
7421  if (rejptflag) {
7422  // Is the point encroaches upon an existing point?
7423  if (rd < (0.5 * (*parypt)[pointmtrindex])) {
7424  pts = parypt;
7425  loc = ENCVERTEX;
7426  break;
7427  }
7428  }
7429  }
7430  cavetetvertlist->restart(); // Clear the work list.
7431 
7432  if (pts != NULL) {
7433  // The point is either too close to an existing vertex (NEARVERTEX)
7434  // or encroaches upon (inside the protecting ball) of that vertex.
7435  if (loc == NEARVERTEX) {
7436  if (!issteinerpoint(insertpt) && b->nomergevertex) { // -M0/1 option.
7437  // 'insertpt' is an input vertex.
7438  // In this case, we still insert this vertex. Issue a warning.
7439  if (!b->quiet) {
7440  printf("Warning: Two points, %d and %d, are very close.\n",
7441  pointmark(insertpt), pointmark(*pts));
7442  printf(" Creating a very short edge (len = %g) (< %g).\n",
7443  rd, minedgelength);
7444  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
7445  b->epsilon);
7446  printf(" to avoid this warning.\n");
7447  }
7448  } else {
7449  point2tetorg(*pts, *searchtet);
7450  insertpoint_abort(splitseg, ivf);
7451  ivf->iloc = (int) loc;
7452  return 0;
7453  }
7454  } else { // loc == ENCVERTEX
7455  // The point lies inside the protection ball.
7456  point2tetorg(*pts, *searchtet);
7457  insertpoint_abort(splitseg, ivf);
7458  ivf->iloc = (int) loc;
7459  return 0;
7460  }
7461  }
7462  } // if (b->plc && (loc != INSTAR))
7463 
7464  if (b->weighted || ivf->cdtflag || ivf->smlenflag
7465  ) {
7466  // There may be other vertices inside C(p). We need to find them.
7467  // Collect all vertices of C(p).
7468  for (i = 0; i < caveoldtetlist->objects; i++) {
7469  cavetet = (triface *) fastlookup(caveoldtetlist, i);
7470  //assert(infected(*cavetet));
7471  pts = (point *) &(cavetet->tet[4]);
7472  for (j = 0; j < 4; j++) {
7473  if (pts[j] != dummypoint) {
7474  if (!pinfected(pts[j])) {
7475  pinfect(pts[j]);
7476  cavetetvertlist->newindex((void **) &parypt);
7477  *parypt = pts[j];
7478  }
7479  }
7480  } // j
7481  } // i
7482  // Uninfect all collected (cavity) vertices.
7483  for (i = 0; i < cavetetvertlist->objects; i++) {
7484  parypt = (point *) fastlookup(cavetetvertlist, i);
7485  puninfect(*parypt);
7486  }
7487  if (ivf->smlenflag) {
7488  REAL len;
7489  // Get the length of the shortest edge connecting to 'newpt'.
7490  parypt = (point *) fastlookup(cavetetvertlist, 0);
7491  ivf->smlen = distance(*parypt, insertpt);
7492  ivf->parentpt = *parypt;
7493  for (i = 1; i < cavetetvertlist->objects; i++) {
7494  parypt = (point *) fastlookup(cavetetvertlist, i);
7495  len = distance(*parypt, insertpt);
7496  if (len < ivf->smlen) {
7497  ivf->smlen = len;
7498  ivf->parentpt = *parypt;
7499  }
7500  }
7501  }
7502  }
7503 
7504 
7505  if (ivf->cdtflag) {
7506  // Unmark tets.
7507  for (i = 0; i < caveoldtetlist->objects; i++) {
7508  cavetet = (triface *) fastlookup(caveoldtetlist, i);
7509  unmarktest(*cavetet);
7510  }
7511  for (i = 0; i < cavebdrylist->objects; i++) {
7512  cavetet = (triface *) fastlookup(cavebdrylist, i);
7513  unmarktest(*cavetet);
7514  }
7515  // Clean up arrays which are not needed.
7516  cavetetlist->restart();
7517  if (checksubsegflag) {
7519  }
7520  if (checksubfaceflag) {
7522  }
7523  return 1;
7524  }
7525 
7526  // Before re-mesh C(p). Process the segments and subfaces which are on the
7527  // boundary of C(p). Make sure that each such segment or subface is
7528  // connecting to a tet outside C(p). So we can re-connect them to the
7529  // new tets inside the C(p) later.
7530 
7531  if (checksubsegflag) {
7532  for (i = 0; i < cavetetseglist->objects; i++) {
7533  paryseg = (face *) fastlookup(cavetetseglist, i);
7534  // Operate on it if it is not the splitting segment, i.e., in sC(p).
7535  if (!smarktested(*paryseg)) {
7536  // Check if the segment is inside the cavity.
7537  // 'j' counts the num of adjacent tets of this seg.
7538  // 'k' counts the num of adjacent tets which are 'sinfected'.
7539  j = k = 0;
7540  sstpivot1(*paryseg, neightet);
7541  spintet = neightet;
7542  while (1) {
7543  j++;
7544  if (!infected(spintet)) {
7545  neineitet = spintet; // An outer tet. Remember it.
7546  } else {
7547  k++; // An in tet.
7548  }
7549  fnextself(spintet);
7550  if (spintet.tet == neightet.tet) break;
7551  }
7552  // assert(j > 0);
7553  if (k == 0) {
7554  // The segment is not connect to C(p) anymore. Remove it by
7555  // Replacing it by the last entry of this list.
7556  s = cavetetseglist->objects - 1;
7557  checkseg = * (face *) fastlookup(cavetetseglist, s);
7558  *paryseg = checkseg;
7560  i--;
7561  } else if (k < j) {
7562  // The segment is on the boundary of C(p).
7563  sstbond1(*paryseg, neineitet);
7564  } else { // k == j
7565  // The segment is inside C(p).
7566  if (!ivf->splitbdflag) {
7567  checkseg = *paryseg;
7568  sinfect(checkseg); // Flag it as an interior segment.
7569  caveencseglist->newindex((void **) &paryseg);
7570  *paryseg = checkseg;
7571  } else {
7572  //assert(0); // Not possible.
7573  terminatetetgen(this, 2);
7574  }
7575  }
7576  } else {
7577  // assert(smarktested(*paryseg));
7578  // Flag it as an interior segment. Do not queue it, since it will
7579  // be deleted after the segment splitting.
7580  sinfect(*paryseg);
7581  }
7582  } // i
7583  } // if (checksubsegflag)
7584 
7585  if (checksubfaceflag) {
7586  for (i = 0; i < cavetetshlist->objects; i++) {
7587  parysh = (face *) fastlookup(cavetetshlist, i);
7588  // Operate on it if it is not inside the sub-cavity sC(p).
7589  if (!smarktested(*parysh)) {
7590  // Check if this subface is inside the cavity.
7591  k = 0;
7592  for (j = 0; j < 2; j++) {
7593  stpivot(*parysh, neightet);
7594  if (!infected(neightet)) {
7595  checksh = *parysh; // Remember this side.
7596  } else {
7597  k++;
7598  }
7599  sesymself(*parysh);
7600  }
7601  if (k == 0) {
7602  // The subface is not connected to C(p). Remove it.
7603  s = cavetetshlist->objects - 1;
7604  checksh = * (face *) fastlookup(cavetetshlist, s);
7605  *parysh = checksh;
7607  i--;
7608  } else if (k == 1) {
7609  // This side is the outer boundary of C(p).
7610  *parysh = checksh;
7611  } else { // k == 2
7612  if (!ivf->splitbdflag) {
7613  checksh = *parysh;
7614  sinfect(checksh); // Flag it.
7615  caveencshlist->newindex((void **) &parysh);
7616  *parysh = checksh;
7617  } else {
7618  //assert(0); // Not possible.
7619  terminatetetgen(this, 2);
7620  }
7621  }
7622  } else {
7623  // assert(smarktested(*parysh));
7624  // Flag it as an interior subface. Do not queue it. It will be
7625  // deleted after the facet point insertion.
7626  sinfect(*parysh);
7627  }
7628  } // i
7629  } // if (checksubfaceflag)
7630 
7631  // Create new tetrahedra to fill the cavity.
7632 
7633  for (i = 0; i < cavebdrylist->objects; i++) {
7634  cavetet = (triface *) fastlookup(cavebdrylist, i);
7635  neightet = *cavetet;
7636  unmarktest(neightet); // Unmark it.
7637  // Get the oldtet (inside the cavity).
7638  fsym(neightet, oldtet);
7639  if (apex(neightet) != dummypoint) {
7640  // Create a new tet in the cavity.
7641  maketetrahedron(&newtet);
7642  setorg(newtet, dest(neightet));
7643  setdest(newtet, org(neightet));
7644  setapex(newtet, apex(neightet));
7645  setoppo(newtet, insertpt);
7646  } else {
7647  // Create a new hull tet.
7648  hullsize++;
7649  maketetrahedron(&newtet);
7650  setorg(newtet, org(neightet));
7651  setdest(newtet, dest(neightet));
7652  setapex(newtet, insertpt);
7653  setoppo(newtet, dummypoint); // It must opposite to face 3.
7654  // Adjust back to the cavity bounday face.
7655  esymself(newtet);
7656  }
7657  // The new tet inherits attribtes from the old tet.
7658  for (j = 0; j < numelemattrib; j++) {
7659  attrib = elemattribute(oldtet.tet, j);
7660  setelemattribute(newtet.tet, j, attrib);
7661  }
7662  if (b->varvolume) {
7663  volume = volumebound(oldtet.tet);
7664  setvolumebound(newtet.tet, volume);
7665  }
7666  // Connect newtet <==> neightet, this also disconnect the old bond.
7667  bond(newtet, neightet);
7668  // oldtet still connects to neightet.
7669  *cavetet = oldtet; // *cavetet = newtet;
7670  } // i
7671 
7672  // Set a handle for speeding point location.
7673  recenttet = newtet;
7674  //setpoint2tet(insertpt, encode(newtet));
7675  setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
7676 
7677  // Re-use this list to save new interior cavity faces.
7678  cavetetlist->restart();
7679 
7680  // Connect adjacent new tetrahedra together.
7681  for (i = 0; i < cavebdrylist->objects; i++) {
7682  cavetet = (triface *) fastlookup(cavebdrylist, i);
7683  // cavtet is an oldtet, get the newtet at this face.
7684  oldtet = *cavetet;
7685  fsym(oldtet, neightet);
7686  fsym(neightet, newtet);
7687  // Comment: oldtet and newtet must be at the same directed edge.
7688  // Connect the three other faces of this newtet.
7689  for (j = 0; j < 3; j++) {
7690  esym(newtet, neightet); // Go to the face.
7691  if (neightet.tet[neightet.ver & 3] == NULL) {
7692  // Find the adjacent face of this newtet.
7693  spintet = oldtet;
7694  while (1) {
7695  fnextself(spintet);
7696  if (!infected(spintet)) break;
7697  }
7698  fsym(spintet, newneitet);
7699  esymself(newneitet);
7700  bond(neightet, newneitet);
7701  if (ivf->lawson > 1) {
7702  cavetetlist->newindex((void **) &parytet);
7703  *parytet = neightet;
7704  }
7705  }
7706  //setpoint2tet(org(newtet), encode(newtet));
7707  setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
7708  enextself(newtet);
7709  enextself(oldtet);
7710  }
7711  *cavetet = newtet; // Save the new tet.
7712  } // i
7713 
7714  if (checksubfaceflag) {
7715  // Connect subfaces on the boundary of the cavity to the new tets.
7716  for (i = 0; i < cavetetshlist->objects; i++) {
7717  parysh = (face *) fastlookup(cavetetshlist, i);
7718  // Connect it if it is not a missing subface.
7719  if (!sinfected(*parysh)) {
7720  stpivot(*parysh, neightet);
7721  fsym(neightet, spintet);
7722  sesymself(*parysh);
7723  tsbond(spintet, *parysh);
7724  }
7725  }
7726  }
7727 
7728  if (checksubsegflag) {
7729  // Connect segments on the boundary of the cavity to the new tets.
7730  for (i = 0; i < cavetetseglist->objects; i++) {
7731  paryseg = (face *) fastlookup(cavetetseglist, i);
7732  // Connect it if it is not a missing segment.
7733  if (!sinfected(*paryseg)) {
7734  sstpivot1(*paryseg, neightet);
7735  spintet = neightet;
7736  while (1) {
7737  tssbond1(spintet, *paryseg);
7738  fnextself(spintet);
7739  if (spintet.tet == neightet.tet) break;
7740  }
7741  }
7742  }
7743  }
7744 
7745  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
7746  ((splitseg != NULL) && (splitseg->sh != NULL))) {
7747  // Split a subface or a segment.
7748  sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
7749  }
7750 
7751  if (checksubfaceflag) {
7752  if (ivf->splitbdflag) {
7753  // Recover new subfaces in C(p).
7754  for (i = 0; i < caveshbdlist->objects; i++) {
7755  // Get an old subface at edge [a, b].
7756  parysh = (face *) fastlookup(caveshbdlist, i);
7757  spivot(*parysh, checksh); // The new subface [a, b, p].
7758  // Do not recover a deleted new face (degenerated).
7759  if (checksh.sh[3] != NULL) {
7760  // Note that the old subface still connects to adjacent old tets
7761  // of C(p), which still connect to the tets outside C(p).
7762  stpivot(*parysh, neightet);
7763  // Find the adjacent tet containing the edge [a,b] outside C(p).
7764  spintet = neightet;
7765  while (1) {
7766  fnextself(spintet);
7767  if (!infected(spintet)) break;
7768  }
7769  // The adjacent tet connects to a new tet in C(p).
7770  fsym(spintet, neightet);
7771  // Find the tet containing the face [a, b, p].
7772  spintet = neightet;
7773  while (1) {
7774  fnextself(spintet);
7775  if (apex(spintet) == insertpt) break;
7776  }
7777  // Adjust the edge direction in spintet and checksh.
7778  if (sorg(checksh) != org(spintet)) {
7779  sesymself(checksh);
7780  }
7781  // Connect the subface to two adjacent tets.
7782  tsbond(spintet, checksh);
7783  fsymself(spintet);
7784  sesymself(checksh);
7785  tsbond(spintet, checksh);
7786  } // if (checksh.sh[3] != NULL)
7787  }
7788  } else {
7789  // The Boundary recovery phase.
7790  // Put all new subfaces into stack for recovery.
7791  for (i = 0; i < caveshbdlist->objects; i++) {
7792  // Get an old subface at edge [a, b].
7793  parysh = (face *) fastlookup(caveshbdlist, i);
7794  spivot(*parysh, checksh); // The new subface [a, b, p].
7795  // Do not recover a deleted new face (degenerated).
7796  if (checksh.sh[3] != NULL) {
7797  subfacstack->newindex((void **) &parysh);
7798  *parysh = checksh;
7799  }
7800  }
7801  // Put all interior subfaces into stack for recovery.
7802  for (i = 0; i < caveencshlist->objects; i++) {
7803  parysh = (face *) fastlookup(caveencshlist, i);
7804  // Some subfaces inside C(p) might be split in sinsertvertex().
7805  // Only queue those faces which are not split.
7806  if (!smarktested(*parysh)) {
7807  checksh = *parysh;
7808  suninfect(checksh);
7809  stdissolve(checksh); // Detach connections to old tets.
7810  subfacstack->newindex((void **) &parysh);
7811  *parysh = checksh;
7812  }
7813  }
7814  }
7815  } // if (checksubfaceflag)
7816 
7817  if (checksubsegflag) {
7818  if (ivf->splitbdflag) {
7819  if (splitseg != NULL) {
7820  // Recover the two new subsegments in C(p).
7821  for (i = 0; i < cavesegshlist->objects; i++) {
7822  paryseg = (face *) fastlookup(cavesegshlist, i);
7823  // Insert this subsegment into C(p).
7824  checkseg = *paryseg;
7825  // Get the adjacent new subface.
7826  checkseg.shver = 0;
7827  spivot(checkseg, checksh);
7828  if (checksh.sh != NULL) {
7829  // Get the adjacent new tetrahedron.
7830  stpivot(checksh, neightet);
7831  } else {
7832  // It's a dangling segment.
7833  point2tetorg(sorg(checkseg), neightet);
7834  finddirection(&neightet, sdest(checkseg));
7835  }
7836  sstbond1(checkseg, neightet);
7837  spintet = neightet;
7838  while (1) {
7839  tssbond1(spintet, checkseg);
7840  fnextself(spintet);
7841  if (spintet.tet == neightet.tet) break;
7842  }
7843  }
7844  } // if (splitseg != NULL)
7845  } else {
7846  // The Boundary Recovery Phase.
7847  // Queue missing segments in C(p) for recovery.
7848  if (splitseg != NULL) {
7849  // Queue two new subsegments in C(p) for recovery.
7850  for (i = 0; i < cavesegshlist->objects; i++) {
7851  paryseg = (face *) fastlookup(cavesegshlist, i);
7852  checkseg = *paryseg;
7853  //sstdissolve1(checkseg); // It has not been connected yet.
7854  s = randomnation(subsegstack->objects + 1);
7855  subsegstack->newindex((void **) &paryseg);
7856  *paryseg = * (face *) fastlookup(subsegstack, s);
7857  paryseg = (face *) fastlookup(subsegstack, s);
7858  *paryseg = checkseg;
7859  }
7860  } // if (splitseg != NULL)
7861  for (i = 0; i < caveencseglist->objects; i++) {
7862  paryseg = (face *) fastlookup(caveencseglist, i);
7863  if (!smarktested(*paryseg)) { // It may be split.
7864  checkseg = *paryseg;
7865  suninfect(checkseg);
7866  sstdissolve1(checkseg); // Detach connections to old tets.
7867  s = randomnation(subsegstack->objects + 1);
7868  subsegstack->newindex((void **) &paryseg);
7869  *paryseg = * (face *) fastlookup(subsegstack, s);
7870  paryseg = (face *) fastlookup(subsegstack, s);
7871  *paryseg = checkseg;
7872  }
7873  }
7874  }
7875  } // if (checksubsegflag)
7876 
7877  if (b->weighted
7878  ) {
7879  // Some vertices may be completed inside the cavity. They must be
7880  // detected and added to recovering list.
7881  // Since every "live" vertex must contain a pointer to a non-dead
7882  // tetrahedron, we can check for each vertex this pointer.
7883  for (i = 0; i < cavetetvertlist->objects; i++) {
7884  pts = (point *) fastlookup(cavetetvertlist, i);
7885  decode(point2tet(*pts), *searchtet);
7886  if (infected(*searchtet)) {
7887  if (b->weighted) {
7888  if (b->verbose > 1) {
7889  printf(" Point #%d is non-regular after the insertion of #%d.\n",
7890  pointmark(*pts), pointmark(insertpt));
7891  }
7893  nonregularcount++;
7894  }
7895  }
7896  }
7897  }
7898 
7899  if (ivf->chkencflag & 1) {
7900  // Queue all segment outside C(p).
7901  for (i = 0; i < cavetetseglist->objects; i++) {
7902  paryseg = (face *) fastlookup(cavetetseglist, i);
7903  // Skip if it is the split segment.
7904  if (!sinfected(*paryseg)) {
7905  enqueuesubface(badsubsegs, paryseg);
7906  }
7907  }
7908  if (splitseg != NULL) {
7909  // Queue the two new subsegments inside C(p).
7910  for (i = 0; i < cavesegshlist->objects; i++) {
7911  paryseg = (face *) fastlookup(cavesegshlist, i);
7912  enqueuesubface(badsubsegs, paryseg);
7913  }
7914  }
7915  } // if (chkencflag & 1)
7916 
7917  if (ivf->chkencflag & 2) {
7918  // Queue all subfaces outside C(p).
7919  for (i = 0; i < cavetetshlist->objects; i++) {
7920  parysh = (face *) fastlookup(cavetetshlist, i);
7921  // Skip if it is a split subface.
7922  if (!sinfected(*parysh)) {
7923  enqueuesubface(badsubfacs, parysh);
7924  }
7925  }
7926  // Queue all new subfaces inside C(p).
7927  for (i = 0; i < caveshbdlist->objects; i++) {
7928  // Get an old subface at edge [a, b].
7929  parysh = (face *) fastlookup(caveshbdlist, i);
7930  spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
7931  // Do not recover a deleted new face (degenerated).
7932  if (checksh.sh[3] != NULL) {
7933  enqueuesubface(badsubfacs, &checksh);
7934  }
7935  }
7936  } // if (chkencflag & 2)
7937 
7938  if (ivf->chkencflag & 4) {
7939  // Queue all new tetrahedra in C(p).
7940  for (i = 0; i < cavebdrylist->objects; i++) {
7941  cavetet = (triface *) fastlookup(cavebdrylist, i);
7942  enqueuetetrahedron(cavetet);
7943  }
7944  }
7945 
7946  // C(p) is re-meshed successfully.
7947 
7948  // Delete the old tets in C(p).
7949  for (i = 0; i < caveoldtetlist->objects; i++) {
7950  searchtet = (triface *) fastlookup(caveoldtetlist, i);
7951  if (ishulltet(*searchtet)) {
7952  hullsize--;
7953  }
7954  tetrahedrondealloc(searchtet->tet);
7955  }
7956 
7957  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
7958  ((splitseg != NULL) && (splitseg->sh != NULL))) {
7959  // Delete the old subfaces in sC(p).
7960  for (i = 0; i < caveshlist->objects; i++) {
7961  parysh = (face *) fastlookup(caveshlist, i);
7962  if (checksubfaceflag) {//if (bowywat == 2) {
7963  // It is possible that this subface still connects to adjacent
7964  // tets which are not in C(p). If so, clear connections in the
7965  // adjacent tets at this subface.
7966  stpivot(*parysh, neightet);
7967  if (neightet.tet != NULL) {
7968  if (neightet.tet[4] != NULL) {
7969  // Found an adjacent tet. It must be not in C(p).
7970  tsdissolve(neightet);
7971  fsymself(neightet);
7972  tsdissolve(neightet);
7973  }
7974  }
7975  }
7976  shellfacedealloc(subfaces, parysh->sh);
7977  }
7978  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
7979  // Delete the old segment in sC(p).
7980  shellfacedealloc(subsegs, splitseg->sh);
7981  }
7982  }
7983 
7984  if (ivf->lawson) {
7985  for (i = 0; i < cavebdrylist->objects; i++) {
7986  searchtet = (triface *) fastlookup(cavebdrylist, i);
7987  flippush(flipstack, searchtet);
7988  }
7989  if (ivf->lawson > 1) {
7990  for (i = 0; i < cavetetlist->objects; i++) {
7991  searchtet = (triface *) fastlookup(cavetetlist, i);
7992  flippush(flipstack, searchtet);
7993  }
7994  }
7995  }
7996 
7997 
7998  // Clean the working lists.
7999 
8001  cavebdrylist->restart();
8002  cavetetlist->restart();
8003 
8004  if (checksubsegflag) {
8007  }
8008 
8009  if (checksubfaceflag) {
8012  }
8013 
8014  if (b->weighted || ivf->smlenflag
8015  ) {
8017  }
8018 
8019  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
8020  ((splitseg != NULL) && (splitseg->sh != NULL))) {
8021  caveshlist->restart();
8022  caveshbdlist->restart();
8024  }
8025 
8026  return 1; // Point is inserted.
8027 }
8028 
8030 // //
8031 // insertpoint_abort() Abort the insertion of a new vertex. //
8032 // //
8033 // The cavity will be restored. All working lists are cleared. //
8034 // //
8036 
8038 {
8039  triface *cavetet;
8040  face *parysh;
8041  int i;
8042 
8043  for (i = 0; i < caveoldtetlist->objects; i++) {
8044  cavetet = (triface *) fastlookup(caveoldtetlist, i);
8045  uninfect(*cavetet);
8046  unmarktest(*cavetet);
8047  }
8048  for (i = 0; i < cavebdrylist->objects; i++) {
8049  cavetet = (triface *) fastlookup(cavebdrylist, i);
8050  unmarktest(*cavetet);
8051  }
8052  cavetetlist->restart();
8053  cavebdrylist->restart();
8057  if (ivf->splitbdflag) {
8058  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
8059  sunmarktest(*splitseg);
8060  }
8061  for (i = 0; i < caveshlist->objects; i++) {
8062  parysh = (face *) fastlookup(caveshlist, i);
8063  sunmarktest(*parysh);
8064  }
8065  caveshlist->restart();
8067  }
8068 }
8069 
8073 
8077 
8078 
8080 // //
8081 // hilbert_init() Initialize the Gray code permutation table. //
8082 // //
8083 // The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray //
8084 // code sequences traveled by the 1st order Hilbert curve in 3 dimensions. //
8085 // The first column is the Gray code of the entry point of the curve, and //
8086 // the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
8087 // the exit point of curve lies. //
8088 // //
8089 // The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
8090 // indices from 0 to 7, modulo by '3'. The code for generating this table is //
8091 // from: http://graphics.stanford.edu/~seander/bithacks.html. //
8092 // //
8094 
8096 {
8097  int gc[8], N, mask, travel_bit;
8098  int e, d, f, k, g;
8099  int v, c;
8100  int i;
8101 
8102  N = (n == 2) ? 4 : 8;
8103  mask = (n == 2) ? 3 : 7;
8104 
8105  // Generate the Gray code sequence.
8106  for (i = 0; i < N; i++) {
8107  gc[i] = i ^ (i >> 1);
8108  }
8109 
8110  for (e = 0; e < N; e++) {
8111  for (d = 0; d < n; d++) {
8112  // Calculate the end point (f).
8113  f = e ^ (1 << d); // Toggle the d-th bit of 'e'.
8114  // travel_bit = 2**p, the bit we want to travel.
8115  travel_bit = e ^ f;
8116  for (i = 0; i < N; i++) {
8117  // // Rotate gc[i] left by (p + 1) % n bits.
8118  k = gc[i] * (travel_bit * 2);
8119  g = ((k | (k / N)) & mask);
8120  // Calculate the permuted Gray code by xor with the start point (e).
8121  transgc[e][d][i] = (g ^ e);
8122  }
8123  } // d
8124  } // e
8125 
8126  // Count the consecutive '1' bits (trailing) on the right.
8127  tsb1mod3[0] = 0;
8128  for (i = 1; i < N; i++) {
8129  v = ~i; // Count the 0s.
8130  v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
8131  for (c = 0; v; c++) {
8132  v >>= 1;
8133  }
8134  tsb1mod3[i] = c % n;
8135  }
8136 }
8137 
8139 // //
8140 // hilbert_sort3() Sort points using the 3d Hilbert curve. //
8141 // //
8143 
8144 int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
8145  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
8146  REAL bzmin, REAL bzmax)
8147 {
8148  point swapvert;
8149  int axis, d;
8150  REAL split;
8151  int i, j;
8152 
8153 
8154  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
8155  // correspoding to x-, or y- or z-axis.
8156  axis = (gc0 ^ gc1) >> 1;
8157 
8158  // Calulate the split position along the axis.
8159  if (axis == 0) {
8160  split = 0.5 * (bxmin + bxmax);
8161  } else if (axis == 1) {
8162  split = 0.5 * (bymin + bymax);
8163  } else { // == 2
8164  split = 0.5 * (bzmin + bzmax);
8165  }
8166 
8167  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
8168  // of the axis is to the positive of the axis, otherwise, it is -1.
8169  d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
8170 
8171 
8172  // Partition the vertices into left- and right-arrays such that left points
8173  // have Hilbert indices lower than the right points.
8174  i = 0;
8175  j = arraysize - 1;
8176 
8177  // Partition the vertices into left- and right-arrays.
8178  if (d > 0) {
8179  do {
8180  for (; i < arraysize; i++) {
8181  if (vertexarray[i][axis] >= split) break;
8182  }
8183  for (; j >= 0; j--) {
8184  if (vertexarray[j][axis] < split) break;
8185  }
8186  // Is the partition finished?
8187  if (i == (j + 1)) break;
8188  // Swap i-th and j-th vertices.
8189  swapvert = vertexarray[i];
8190  vertexarray[i] = vertexarray[j];
8191  vertexarray[j] = swapvert;
8192  // Continue patitioning the array;
8193  } while (true);
8194  } else {
8195  do {
8196  for (; i < arraysize; i++) {
8197  if (vertexarray[i][axis] <= split) break;
8198  }
8199  for (; j >= 0; j--) {
8200  if (vertexarray[j][axis] > split) break;
8201  }
8202  // Is the partition finished?
8203  if (i == (j + 1)) break;
8204  // Swap i-th and j-th vertices.
8205  swapvert = vertexarray[i];
8206  vertexarray[i] = vertexarray[j];
8207  vertexarray[j] = swapvert;
8208  // Continue patitioning the array;
8209  } while (true);
8210  }
8211 
8212  return i;
8213 }
8214 
8215 void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
8216  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
8217  REAL bzmin, REAL bzmax, int depth)
8218 {
8219  REAL x1, x2, y1, y2, z1, z2;
8220  int p[9], w, e_w, d_w, k, ei, di;
8221  int n = 3, mask = 7;
8222 
8223  p[0] = 0;
8224  p[8] = arraysize;
8225 
8226  // Sort the points according to the 1st order Hilbert curve in 3d.
8227  p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4],
8228  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
8229  p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2],
8230  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
8231  p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1],
8232  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
8233  p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2],
8234  transgc[e][d][2], transgc[e][d][3],
8235  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
8236  p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4],
8237  transgc[e][d][5], transgc[e][d][6],
8238  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
8239  p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4],
8240  transgc[e][d][4], transgc[e][d][5],
8241  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
8242  p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6],
8243  transgc[e][d][6], transgc[e][d][7],
8244  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
8245 
8246  if (b->hilbert_order > 0) {
8247  // A maximum order is prescribed.
8248  if ((depth + 1) == b->hilbert_order) {
8249  // The maximum prescribed order is reached.
8250  return;
8251  }
8252  }
8253 
8254  // Recursively sort the points in sub-boxes.
8255  for (w = 0; w < 8; w++) {
8256  // w is the local Hilbert index (NOT Gray code).
8257  // Sort into the sub-box either there are more than 2 points in it, or
8258  // the prescribed order of the curve is not reached yet.
8259  //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
8260  if ((p[w+1] - p[w]) > b->hilbert_limit) {
8261  // Calculcate the start point (ei) of the curve in this sub-box.
8262  // update e = e ^ (e(w) left_rotate (d+1)).
8263  if (w == 0) {
8264  e_w = 0;
8265  } else {
8266  // calculate e(w) = gc(2 * floor((w - 1) / 2)).
8267  k = 2 * ((w - 1) / 2);
8268  e_w = k ^ (k >> 1); // = gc(k).
8269  }
8270  k = e_w;
8271  e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
8272  ei = e ^ e_w;
8273  // Calulcate the direction (di) of the curve in this sub-box.
8274  // update d = (d + d(w) + 1) % n
8275  if (w == 0) {
8276  d_w = 0;
8277  } else {
8278  d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
8279  }
8280  di = (d + d_w + 1) % n;
8281  // Calculate the bounding box of the sub-box.
8282  if (transgc[e][d][w] & 1) { // x-axis
8283  x1 = 0.5 * (bxmin + bxmax);
8284  x2 = bxmax;
8285  } else {
8286  x1 = bxmin;
8287  x2 = 0.5 * (bxmin + bxmax);
8288  }
8289  if (transgc[e][d][w] & 2) { // y-axis
8290  y1 = 0.5 * (bymin + bymax);
8291  y2 = bymax;
8292  } else {
8293  y1 = bymin;
8294  y2 = 0.5 * (bymin + bymax);
8295  }
8296  if (transgc[e][d][w] & 4) { // z-axis
8297  z1 = 0.5 * (bzmin + bzmax);
8298  z2 = bzmax;
8299  } else {
8300  z1 = bzmin;
8301  z2 = 0.5 * (bzmin + bzmax);
8302  }
8303  hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di,
8304  x1, x2, y1, y2, z1, z2, depth+1);
8305  } // if (p[w+1] - p[w] > 1)
8306  } // w
8307 }
8308 
8310 // //
8311 // brio_multiscale_sort() Sort the points using BRIO and Hilbert curve. //
8312 // //
8314 
8315 void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize,
8316  int threshold, REAL ratio, int *depth)
8317 {
8318  int middle;
8319 
8320  middle = 0;
8321  if (arraysize >= threshold) {
8322  (*depth)++;
8323  middle = arraysize * ratio;
8324  brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
8325  }
8326  // Sort the right-array (rnd-th round) using the Hilbert curve.
8327  hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
8328  xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
8329 }
8330 
8332 // //
8333 // randomnation() Generate a random number between 0 and 'choices' - 1. //
8334 // //
8336 
8337 unsigned long tetgenmesh::randomnation(unsigned int choices)
8338 {
8339  unsigned long newrandom;
8340 
8341  if (choices >= 714025l) {
8342  newrandom = (randomseed * 1366l + 150889l) % 714025l;
8343  randomseed = (newrandom * 1366l + 150889l) % 714025l;
8344  newrandom = newrandom * (choices / 714025l) + randomseed;
8345  if (newrandom >= choices) {
8346  return newrandom - choices;
8347  } else {
8348  return newrandom;
8349  }
8350  } else {
8351  randomseed = (randomseed * 1366l + 150889l) % 714025l;
8352  return randomseed % choices;
8353  }
8354 }
8355 
8357 // //
8358 // randomsample() Randomly sample the tetrahedra for point loation. //
8359 // //
8360 // Searching begins from one of handles: the input 'searchtet', a recently //
8361 // encountered tetrahedron 'recenttet', or from one chosen from a random //
8362 // sample. The choice is made by determining which one's origin is closest //
8363 // to the point we are searching for. //
8364 // //
8366 
8367 void tetgenmesh::randomsample(point searchpt,triface *searchtet)
8368 {
8369  tetrahedron *firsttet, *tetptr;
8370  point torg;
8371  void **sampleblock;
8372  uintptr_t alignptr;
8373  long sampleblocks, samplesperblock, samplenum;
8374  long tetblocks, i, j;
8375  REAL searchdist, dist;
8376 
8377  if (b->verbose > 2) {
8378  printf(" Random sampling tetrahedra for searching point %d.\n",
8379  pointmark(searchpt));
8380  }
8381 
8382  if (!nonconvex) {
8383  if (searchtet->tet == NULL) {
8384  // A null tet. Choose the recenttet as the starting tet.
8385  *searchtet = recenttet;
8386  }
8387 
8388  // 'searchtet' should be a valid tetrahedron. Choose the base face
8389  // whose vertices must not be 'dummypoint'.
8390  searchtet->ver = 3;
8391  // Record the distance from its origin to the searching point.
8392  torg = org(*searchtet);
8393  searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
8394  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
8395  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
8396 
8397  // If a recently encountered tetrahedron has been recorded and has not
8398  // been deallocated, test it as a good starting point.
8399  if (recenttet.tet != searchtet->tet) {
8400  recenttet.ver = 3;
8401  torg = org(recenttet);
8402  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
8403  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
8404  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
8405  if (dist < searchdist) {
8406  *searchtet = recenttet;
8407  searchdist = dist;
8408  }
8409  }
8410  } else {
8411  // The mesh is non-convex. Do not use 'recenttet'.
8412  searchdist = longest;
8413  }
8414 
8415  // Select "good" candidate using k random samples, taking the closest one.
8416  // The number of random samples taken is proportional to the fourth root
8417  // of the number of tetrahedra in the mesh.
8418  while (samples * samples * samples * samples < tetrahedrons->items) {
8419  samples++;
8420  }
8421  // Find how much blocks in current tet pool.
8422  tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1)
8423  / b->tetrahedraperblock;
8424  // Find the average samples per block. Each block at least have 1 sample.
8425  samplesperblock = 1 + (samples / tetblocks);
8426  sampleblocks = samples / samplesperblock;
8427  sampleblock = tetrahedrons->firstblock;
8428  for (i = 0; i < sampleblocks; i++) {
8429  alignptr = (uintptr_t) (sampleblock + 1);
8430  firsttet = (tetrahedron *)
8431  (alignptr + (uintptr_t) tetrahedrons->alignbytes
8432  - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
8433  for (j = 0; j < samplesperblock; j++) {
8434  if (i == tetblocks - 1) {
8435  // This is the last block.
8436  samplenum = randomnation((int)
8438  } else {
8439  samplenum = randomnation(b->tetrahedraperblock);
8440  }
8441  tetptr = (tetrahedron *)
8442  (firsttet + (samplenum * tetrahedrons->itemwords));
8443  torg = (point) tetptr[4];
8444  if (torg != (point) NULL) {
8445  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
8446  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
8447  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
8448  if (dist < searchdist) {
8449  searchtet->tet = tetptr;
8450  searchtet->ver = 11; // torg = org(t);
8451  searchdist = dist;
8452  }
8453  } else {
8454  // A dead tet. Re-sample it.
8455  if (i != tetblocks - 1) j--;
8456  }
8457  }
8458  sampleblock = (void **) *sampleblock;
8459  }
8460 }
8461 
8463 // //
8464 // locate() Find a tetrahedron containing a given point. //
8465 // //
8466 // Begins its search from 'searchtet', assume there is a line segment L from //
8467 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
8468 // towards 'searchpt' by traversing all faces intersected by L. //
8469 // //
8470 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
8471 // returned value indicates one of the following cases: //
8472 // - ONVERTEX, the search point lies on the origin of 'searchtet'. //
8473 // - ONEDGE, the search point lies on an edge of 'searchtet'. //
8474 // - ONFACE, the search point lies on a face of 'searchtet'. //
8475 // - INTET, the search point lies in the interior of 'searchtet'. //
8476 // - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a //
8477 // hull face which is visible by the search point. //
8478 // //
8479 // WARNING: This routine is designed for convex triangulations, and will not //
8480 // generally work after the holes and concavities have been carved. //
8481 // //
8483 
8485  tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag)
8486 {
8487  point torg, tdest, tapex, toppo;
8488  enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
8489  REAL ori, oriorg, oridest, oriapex;
8490  enum locateresult loc = OUTSIDE;
8491  int t1ver;
8492  int s;
8493 
8494  if (searchtet->tet == NULL) {
8495  // A null tet. Choose the recenttet as the starting tet.
8496  searchtet->tet = recenttet.tet;
8497  }
8498 
8499  // Check if we are in the outside of the convex hull.
8500  if (ishulltet(*searchtet)) {
8501  // Get its adjacent tet (inside the hull).
8502  searchtet->ver = 3;
8503  fsymself(*searchtet);
8504  }
8505 
8506  // Let searchtet be the face such that 'searchpt' lies above to it.
8507  for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
8508  torg = org(*searchtet);
8509  tdest = dest(*searchtet);
8510  tapex = apex(*searchtet);
8511  ori = orient3d(torg, tdest, tapex, searchpt);
8512  if (ori < 0.0) break;
8513  }
8514  if (searchtet->ver == 4) {
8515  terminatetetgen(this, 2);
8516  }
8517 
8518  // Walk through tetrahedra to locate the point.
8519  while (true) {
8520 
8521  toppo = oppo(*searchtet);
8522 
8523  // Check if the vertex is we seek.
8524  if (toppo == searchpt) {
8525  // Adjust the origin of searchtet to be searchpt.
8526  esymself(*searchtet);
8527  eprevself(*searchtet);
8528  loc = ONVERTEX; // return ONVERTEX;
8529  break;
8530  }
8531 
8532  // We enter from one of serarchtet's faces, which face do we exit?
8533  oriorg = orient3d(tdest, tapex, toppo, searchpt);
8534  oridest = orient3d(tapex, torg, toppo, searchpt);
8535  oriapex = orient3d(torg, tdest, toppo, searchpt);
8536 
8537  // Now decide which face to move. It is possible there are more than one
8538  // faces are viable moves. If so, randomly choose one.
8539  if (oriorg < 0) {
8540  if (oridest < 0) {
8541  if (oriapex < 0) {
8542  // All three faces are possible.
8543  s = randomnation(3); // 's' is in {0,1,2}.
8544  if (s == 0) {
8545  nextmove = ORGMOVE;
8546  } else if (s == 1) {
8547  nextmove = DESTMOVE;
8548  } else {
8549  nextmove = APEXMOVE;
8550  }
8551  } else {
8552  // Two faces, opposite to origin and destination, are viable.
8553  //s = randomnation(2); // 's' is in {0,1}.
8554  if (randomnation(2)) {
8555  nextmove = ORGMOVE;
8556  } else {
8557  nextmove = DESTMOVE;
8558  }
8559  }
8560  } else {
8561  if (oriapex < 0) {
8562  // Two faces, opposite to origin and apex, are viable.
8563  //s = randomnation(2); // 's' is in {0,1}.
8564  if (randomnation(2)) {
8565  nextmove = ORGMOVE;
8566  } else {
8567  nextmove = APEXMOVE;
8568  }
8569  } else {
8570  // Only the face opposite to origin is viable.
8571  nextmove = ORGMOVE;
8572  }
8573  }
8574  } else {
8575  if (oridest < 0) {
8576  if (oriapex < 0) {
8577  // Two faces, opposite to destination and apex, are viable.
8578  //s = randomnation(2); // 's' is in {0,1}.
8579  if (randomnation(2)) {
8580  nextmove = DESTMOVE;
8581  } else {
8582  nextmove = APEXMOVE;
8583  }
8584  } else {
8585  // Only the face opposite to destination is viable.
8586  nextmove = DESTMOVE;
8587  }
8588  } else {
8589  if (oriapex < 0) {
8590  // Only the face opposite to apex is viable.
8591  nextmove = APEXMOVE;
8592  } else {
8593  // The point we seek must be on the boundary of or inside this
8594  // tetrahedron. Check for boundary cases.
8595  if (oriorg == 0) {
8596  // Go to the face opposite to origin.
8597  enextesymself(*searchtet);
8598  if (oridest == 0) {
8599  eprevself(*searchtet); // edge oppo->apex
8600  if (oriapex == 0) {
8601  // oppo is duplicated with p.
8602  loc = ONVERTEX; // return ONVERTEX;
8603  break;
8604  }
8605  loc = ONEDGE; // return ONEDGE;
8606  break;
8607  }
8608  if (oriapex == 0) {
8609  enextself(*searchtet); // edge dest->oppo
8610  loc = ONEDGE; // return ONEDGE;
8611  break;
8612  }
8613  loc = ONFACE; // return ONFACE;
8614  break;
8615  }
8616  if (oridest == 0) {
8617  // Go to the face opposite to destination.
8618  eprevesymself(*searchtet);
8619  if (oriapex == 0) {
8620  eprevself(*searchtet); // edge oppo->org
8621  loc = ONEDGE; // return ONEDGE;
8622  break;
8623  }
8624  loc = ONFACE; // return ONFACE;
8625  break;
8626  }
8627  if (oriapex == 0) {
8628  // Go to the face opposite to apex
8629  esymself(*searchtet);
8630  loc = ONFACE; // return ONFACE;
8631  break;
8632  }
8633  loc = INTETRAHEDRON; // return INTETRAHEDRON;
8634  break;
8635  }
8636  }
8637  }
8638 
8639  // Move to the selected face.
8640  if (nextmove == ORGMOVE) {
8641  enextesymself(*searchtet);
8642  } else if (nextmove == DESTMOVE) {
8643  eprevesymself(*searchtet);
8644  } else {
8645  esymself(*searchtet);
8646  }
8647  if (chkencflag) {
8648  // Check if we are walking across a subface.
8649  if (issubface(*searchtet)) {
8650  loc = ENCSUBFACE;
8651  break;
8652  }
8653  }
8654  // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
8655  fsymself(*searchtet);
8656  if (oppo(*searchtet) == dummypoint) {
8657  loc = OUTSIDE; // return OUTSIDE;
8658  break;
8659  }
8660 
8661  // Retreat the three vertices of the base face.
8662  torg = org(*searchtet);
8663  tdest = dest(*searchtet);
8664  tapex = apex(*searchtet);
8665 
8666  } // while (true)
8667 
8668  return loc;
8669 }
8670 
8672 // //
8673 // flippush() Push a face (possibly will be flipped) into flipstack. //
8674 // //
8675 // The face is marked. The flag is used to check the validity of the face on //
8676 // its popup. Some other flips may change it already. //
8677 // //
8679 
8680 void tetgenmesh::flippush(badface*& fstack, triface* flipface)
8681 {
8682  if (!facemarked(*flipface)) {
8683  badface *newflipface = (badface *) flippool->alloc();
8684  newflipface->tt = *flipface;
8685  markface(newflipface->tt);
8686  // Push this face into stack.
8687  newflipface->nextitem = fstack;
8688  fstack = newflipface;
8689  }
8690 }
8691 
8693 // //
8694 // incrementalflip() Incrementally flipping to construct DT. //
8695 // //
8696 // Faces need to be checked for flipping are already queued in 'flipstack'. //
8697 // Return the total number of performed flips. //
8698 // //
8699 // Comment: This routine should be only used in the incremental Delaunay //
8700 // construction. In other cases, lawsonflip3d() should be used. //
8701 // //
8702 // If the new point lies outside of the convex hull ('hullflag' is set). The //
8703 // incremental flip algorithm still works as usual. However, we must ensure //
8704 // that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
8705 // edge or face. Otherwise, the underlying space of the triangulation becomes//
8706 // non-manifold and it is not possible to flip further. //
8707 // Thanks to Joerg Rambau and Frank Lutz for helping in this issue. //
8708 // //
8710 
8712 {
8713  badface *popface;
8714  triface fliptets[5], *parytet;
8715  point *pts, *parypt, pe;
8716  REAL sign, ori;
8717  int flipcount = 0;
8718  int t1ver;
8719  int i;
8720 
8721  if (b->verbose > 2) {
8722  printf(" Lawson flip (%ld faces).\n", flippool->items);
8723  }
8724 
8725  if (hullflag) {
8726  // 'newpt' lies in the outside of the convex hull.
8727  // Mark all hull vertices which are connecting to it.
8728  popface = flipstack;
8729  while (popface != NULL) {
8730  pts = (point *) popface->tt.tet;
8731  for (i = 4; i < 8; i++) {
8732  if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
8733  if (!pinfected(pts[i])) {
8734  pinfect(pts[i]);
8735  cavetetvertlist->newindex((void **) &parypt);
8736  *parypt = pts[i];
8737  }
8738  }
8739  }
8740  popface = popface->nextitem;
8741  }
8742  }
8743 
8744  // Loop until the queue is empty.
8745  while (flipstack != NULL) {
8746 
8747  // Pop a face from the stack.
8748  popface = flipstack;
8749  fliptets[0] = popface->tt;
8750  flipstack = flipstack->nextitem; // The next top item in stack.
8751  flippool->dealloc((void *) popface);
8752 
8753  // Skip it if it is a dead tet (destroyed by previous flips).
8754  if (isdeadtet(fliptets[0])) continue;
8755  // Skip it if it is not the same tet as we saved.
8756  if (!facemarked(fliptets[0])) continue;
8757 
8758  unmarkface(fliptets[0]);
8759 
8760  if ((point) fliptets[0].tet[7] == dummypoint) {
8761  // It must be a hull edge.
8762  fliptets[0].ver = epivot[fliptets[0].ver];
8763  // A hull edge. The current convex hull may be enlarged.
8764  fsym(fliptets[0], fliptets[1]);
8765  pts = (point *) fliptets[1].tet;
8766  ori = orient3d(pts[4], pts[5], pts[6], newpt);
8767  if (ori < 0) {
8768  // Visible. The convex hull will be enlarged.
8769  // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
8770  // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
8771  enext(fliptets[1], fliptets[2]);
8772  eprev(fliptets[1], fliptets[3]);
8773  fnextself(fliptets[2]); // [a,c,e,*]
8774  fnextself(fliptets[3]); // [c,b,e,*]
8775  if (oppo(fliptets[2]) == newpt) {
8776  if (oppo(fliptets[3]) == newpt) {
8777  // Both tets exist! A 4-to-1 flip is found.
8778  terminatetetgen(this, 2); // Report a bug.
8779  } else {
8780  esym(fliptets[2], fliptets[0]);
8781  fnext(fliptets[0], fliptets[1]);
8782  fnext(fliptets[1], fliptets[2]);
8783  // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
8784  // This corresponds to my standard labels, where edge [e,d] is
8785  // repalced by face [a,b,c], and a is the new vertex.
8786  // [0] [c,a,d,e] (d = newpt)
8787  // [1] [c,a,e,b] (c = dummypoint)
8788  // [2] [c,a,b,d]
8789  flip32(fliptets, 1, fc);
8790  }
8791  } else {
8792  if (oppo(fliptets[3]) == newpt) {
8793  fnext(fliptets[3], fliptets[0]);
8794  fnext(fliptets[0], fliptets[1]);
8795  fnext(fliptets[1], fliptets[2]);
8796  // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
8797  // [0] [c,b,d,a] (d = newpt)
8798  // [1] [c,b,a,e] (c = dummypoint)
8799  // [2] [c,b,e,d]
8800  flip32(fliptets, 1, fc);
8801  } else {
8802  if (hullflag) {
8803  // Reject this flip if pe is already marked.
8804  pe = oppo(fliptets[1]);
8805  if (!pinfected(pe)) {
8806  pinfect(pe);
8807  cavetetvertlist->newindex((void **) &parypt);
8808  *parypt = pe;
8809  // Perform a 2-to-3 flip.
8810  flip23(fliptets, 1, fc);
8811  } else {
8812  // Reject this flip.
8813  flipcount--;
8814  }
8815  } else {
8816  // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
8817  // [0] [a,b,c,d], d = newpt.
8818  // [1] [b,a,c,e], c = dummypoint.
8819  flip23(fliptets, 1, fc);
8820  }
8821  }
8822  }
8823  flipcount++;
8824  }
8825  continue;
8826  } // if (dummypoint)
8827 
8828  fsym(fliptets[0], fliptets[1]);
8829  if ((point) fliptets[1].tet[7] == dummypoint) {
8830  // A hull face is locally Delaunay.
8831  continue;
8832  }
8833  // Check if the adjacent tet has already been tested.
8834  if (marktested(fliptets[1])) {
8835  // It has been tested and it is Delaunay.
8836  continue;
8837  }
8838 
8839  // Test whether the face is locally Delaunay or not.
8840  pts = (point *) fliptets[1].tet;
8841  if (b->weighted) {
8842  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
8843  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
8844  newpt[3]);
8845  } else {
8846  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
8847  }
8848 
8849 
8850  if (sign < 0) {
8851  point pd = newpt;
8852  point pe = oppo(fliptets[1]);
8853  // Check the convexity of its three edges. Stop checking either a
8854  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
8855  // encountered, and 'fliptet' represents that edge.
8856  for (i = 0; i < 3; i++) {
8857  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
8858  if (ori <= 0) break;
8859  enextself(fliptets[0]);
8860  }
8861  if (ori > 0) {
8862  // A 2-to-3 flip is found.
8863  // [0] [a,b,c,d],
8864  // [1] [b,a,c,e]. no dummypoint.
8865  flip23(fliptets, 0, fc);
8866  flipcount++;
8867  } else { // ori <= 0
8868  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
8869  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
8870  // Check if there are three or four tets sharing at this edge.
8871  esymself(fliptets[0]); // [b,a,d,c]
8872  for (i = 0; i < 3; i++) {
8873  fnext(fliptets[i], fliptets[i+1]);
8874  }
8875  if (fliptets[3].tet == fliptets[0].tet) {
8876  // A 3-to-2 flip is found. (No hull tet.)
8877  flip32(fliptets, 0, fc);
8878  flipcount++;
8879  } else {
8880  // There are more than 3 tets at this edge.
8881  fnext(fliptets[3], fliptets[4]);
8882  if (fliptets[4].tet == fliptets[0].tet) {
8883  if (ori == 0) {
8884  // A 4-to-4 flip is found. (Two hull tets may be involved.)
8885  // Current tets in 'fliptets':
8886  // [0] [b,a,d,c] (d may be newpt)
8887  // [1] [b,a,c,e]
8888  // [2] [b,a,e,f] (f may be dummypoint)
8889  // [3] [b,a,f,d]
8890  esymself(fliptets[0]); // [a,b,c,d]
8891  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
8892  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
8893  // It will be removed by the followed 3-to-2 flip.
8894  flip23(fliptets, 0, fc); // No hull tet.
8895  fnext(fliptets[3], fliptets[1]);
8896  fnext(fliptets[1], fliptets[2]);
8897  // Current tets in 'fliptets':
8898  // [0] [...]
8899  // [1] [b,a,d,e] (degenerated, d may be new point).
8900  // [2] [b,a,e,f] (f may be dummypoint)
8901  // [3] [b,a,f,d]
8902  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
8903  // Hull tets may be involved (f may be dummypoint).
8904  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
8905  flipcount++;
8906  }
8907  }
8908  }
8909  } // ori
8910  } else {
8911  // The adjacent tet is Delaunay. Mark it to avoid testing it again.
8912  marktest(fliptets[1]);
8913  // Save it for unmarking it later.
8914  cavebdrylist->newindex((void **) &parytet);
8915  *parytet = fliptets[1];
8916  }
8917 
8918  } // while (flipstack)
8919 
8920  // Unmark saved tetrahedra.
8921  for (i = 0; i < cavebdrylist->objects; i++) {
8922  parytet = (triface *) fastlookup(cavebdrylist, i);
8923  unmarktest(*parytet);
8924  }
8925  cavebdrylist->restart();
8926 
8927  if (hullflag) {
8928  // Unmark infected vertices.
8929  for (i = 0; i < cavetetvertlist->objects; i++) {
8930  parypt = (point *) fastlookup(cavetetvertlist, i);
8931  puninfect(*parypt);
8932  }
8934  }
8935 
8936 
8937  return flipcount;
8938 }
8939 
8941 // //
8942 // initialdelaunay() Create an initial Delaunay tetrahedralization. //
8943 // //
8944 // The tetrahedralization contains only one tetrahedron abcd, and four hull //
8945 // tetrahedra. The points pa, pb, pc, and pd must be linearly independent. //
8946 // //
8948 
8950 {
8951  triface firsttet, tetopa, tetopb, tetopc, tetopd;
8952  triface worktet, worktet1;
8953 
8954  if (b->verbose > 2) {
8955  printf(" Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
8956  pointmark(pb), pointmark(pc), pointmark(pd));
8957  }
8958 
8959  // Create the first tetrahedron.
8960  maketetrahedron(&firsttet);
8961  setvertices(firsttet, pa, pb, pc, pd);
8962  // Create four hull tetrahedra.
8963  maketetrahedron(&tetopa);
8964  setvertices(tetopa, pb, pc, pd, dummypoint);
8965  maketetrahedron(&tetopb);
8966  setvertices(tetopb, pc, pa, pd, dummypoint);
8967  maketetrahedron(&tetopc);
8968  setvertices(tetopc, pa, pb, pd, dummypoint);
8969  maketetrahedron(&tetopd);
8970  setvertices(tetopd, pb, pa, pc, dummypoint);
8971  hullsize += 4;
8972 
8973  // Connect hull tetrahedra to firsttet (at four faces of firsttet).
8974  bond(firsttet, tetopd);
8975  esym(firsttet, worktet);
8976  bond(worktet, tetopc); // ab
8977  enextesym(firsttet, worktet);
8978  bond(worktet, tetopa); // bc
8979  eprevesym(firsttet, worktet);
8980  bond(worktet, tetopb); // ca
8981 
8982  // Connect hull tetrahedra together (at six edges of firsttet).
8983  esym(tetopc, worktet);
8984  esym(tetopd, worktet1);
8985  bond(worktet, worktet1); // ab
8986  esym(tetopa, worktet);
8987  eprevesym(tetopd, worktet1);
8988  bond(worktet, worktet1); // bc
8989  esym(tetopb, worktet);
8990  enextesym(tetopd, worktet1);
8991  bond(worktet, worktet1); // ca
8992  eprevesym(tetopc, worktet);
8993  enextesym(tetopb, worktet1);
8994  bond(worktet, worktet1); // da
8995  eprevesym(tetopa, worktet);
8996  enextesym(tetopc, worktet1);
8997  bond(worktet, worktet1); // db
8998  eprevesym(tetopb, worktet);
8999  enextesym(tetopa, worktet1);
9000  bond(worktet, worktet1); // dc
9001 
9002  // Set the vertex type.
9003  if (pointtype(pa) == UNUSEDVERTEX) {
9004  setpointtype(pa, VOLVERTEX);
9005  }
9006  if (pointtype(pb) == UNUSEDVERTEX) {
9007  setpointtype(pb, VOLVERTEX);
9008  }
9009  if (pointtype(pc) == UNUSEDVERTEX) {
9010  setpointtype(pc, VOLVERTEX);
9011  }
9012  if (pointtype(pd) == UNUSEDVERTEX) {
9013  setpointtype(pd, VOLVERTEX);
9014  }
9015 
9016  setpoint2tet(pa, encode(firsttet));
9017  setpoint2tet(pb, encode(firsttet));
9018  setpoint2tet(pc, encode(firsttet));
9019  setpoint2tet(pd, encode(firsttet));
9020 
9021  // Remember the first tetrahedron.
9022  recenttet = firsttet;
9023 }
9024 
9026 // //
9027 // incrementaldelaunay() Create a Delaunay tetrahedralization by //
9028 // the incremental approach. //
9029 // //
9031 
9032 
9034 {
9035  triface searchtet;
9036  point *permutarray, swapvertex;
9037  REAL v1[3], v2[3], n[3];
9038  REAL bboxsize, bboxsize2, bboxsize3, ori;
9039  int randindex;
9040  int ngroup = 0;
9041  int i, j;
9042 
9043  if (!b->quiet) {
9044  printf("Delaunizing vertices...\n");
9045  }
9046 
9047  // Form a random permuation (uniformly at random) of the set of vertices.
9048  permutarray = new point[in->numberofpoints];
9049  points->traversalinit();
9050 
9051  if (b->no_sort) {
9052  if (b->verbose) {
9053  printf(" Using the input order.\n");
9054  }
9055  for (i = 0; i < in->numberofpoints; i++) {
9056  permutarray[i] = (point) points->traverse();
9057  }
9058  } else {
9059  if (b->verbose) {
9060  printf(" Permuting vertices.\n");
9061  }
9062  srand(in->numberofpoints);
9063  for (i = 0; i < in->numberofpoints; i++) {
9064  randindex = rand() % (i + 1); // randomnation(i + 1);
9065  permutarray[i] = permutarray[randindex];
9066  permutarray[randindex] = (point) points->traverse();
9067  }
9068  if (b->brio_hilbert) { // -b option
9069  if (b->verbose) {
9070  printf(" Sorting vertices.\n");
9071  }
9072  hilbert_init(in->mesh_dim);
9073  brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold,
9074  b->brio_ratio, &ngroup);
9075  }
9076  }
9077 
9078  tv = clock(); // Remember the time for sorting points.
9079 
9080  // Calculate the diagonal size of its bounding box.
9081  bboxsize = sqrt(norm2(xmax - xmin, ymax - ymin, zmax - zmin));
9082  bboxsize2 = bboxsize * bboxsize;
9083  bboxsize3 = bboxsize2 * bboxsize;
9084 
9085  // Make sure the second vertex is not identical with the first one.
9086  i = 1;
9087  while ((distance(permutarray[0],permutarray[i])/bboxsize)<b->epsilon) {
9088  i++;
9089  if (i == in->numberofpoints - 1) {
9090  printf("Exception: All vertices are (nearly) identical (Tol = %g).\n",
9091  b->epsilon);
9092  terminatetetgen(this, 10);
9093  }
9094  }
9095  if (i > 1) {
9096  // Swap to move the non-identical vertex from index i to index 1.
9097  swapvertex = permutarray[i];
9098  permutarray[i] = permutarray[1];
9099  permutarray[1] = swapvertex;
9100  }
9101 
9102  // Make sure the third vertex is not collinear with the first two.
9103  // Acknowledgement: Thanks Jan Pomplun for his correction by using
9104  // epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
9105  i = 2;
9106  for (j = 0; j < 3; j++) {
9107  v1[j] = permutarray[1][j] - permutarray[0][j];
9108  v2[j] = permutarray[i][j] - permutarray[0][j];
9109  }
9110  cross(v1, v2, n);
9111  while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) <
9112  (b->epsilon * b->epsilon)) {
9113  i++;
9114  if (i == in->numberofpoints - 1) {
9115  printf("Exception: All vertices are (nearly) collinear (Tol = %g).\n",
9116  b->epsilon);
9117  terminatetetgen(this, 10);
9118  }
9119  for (j = 0; j < 3; j++) {
9120  v2[j] = permutarray[i][j] - permutarray[0][j];
9121  }
9122  cross(v1, v2, n);
9123  }
9124  if (i > 2) {
9125  // Swap to move the non-identical vertex from index i to index 1.
9126  swapvertex = permutarray[i];
9127  permutarray[i] = permutarray[2];
9128  permutarray[2] = swapvertex;
9129  }
9130 
9131  // Make sure the fourth vertex is not coplanar with the first three.
9132  i = 3;
9133  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
9134  permutarray[i]);
9135  while ((fabs(ori) / bboxsize3) < (b->epsilon * b->epsilon * b->epsilon)) {
9136  i++;
9137  if (i == in->numberofpoints) {
9138  printf("Exception: All vertices are coplanar (Tol = %g).\n",
9139  b->epsilon);
9140  terminatetetgen(this, 10);
9141  }
9142  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
9143  permutarray[i]);
9144  }
9145  if (i > 3) {
9146  // Swap to move the non-identical vertex from index i to index 1.
9147  swapvertex = permutarray[i];
9148  permutarray[i] = permutarray[3];
9149  permutarray[3] = swapvertex;
9150  }
9151 
9152  // Orient the first four vertices in permutarray so that they follow the
9153  // right-hand rule.
9154  if (ori > 0.0) {
9155  // Swap the first two vertices.
9156  swapvertex = permutarray[0];
9157  permutarray[0] = permutarray[1];
9158  permutarray[1] = swapvertex;
9159  }
9160 
9161  // Create the initial Delaunay tetrahedralization.
9162  initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
9163  permutarray[3]);
9164 
9165  if (b->verbose) {
9166  printf(" Incrementally inserting vertices.\n");
9167  }
9168  insertvertexflags ivf;
9170 
9171  // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
9172  if (b->incrflip) {
9173  ivf.bowywat = 0;
9174  ivf.lawson = 1;
9175  fc.enqflag = 1;
9176  } else {
9177  ivf.bowywat = 1;
9178  ivf.lawson = 0;
9179  }
9180 
9181 
9182  for (i = 4; i < in->numberofpoints; i++) {
9183  if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
9184  setpointtype(permutarray[i], VOLVERTEX);
9185  }
9186  if (b->brio_hilbert || b->no_sort) { // -b or -b/1
9187  // Start the last updated tet.
9188  searchtet.tet = recenttet.tet;
9189  } else { // -b0
9190  // Randomly choose the starting tet for point location.
9191  searchtet.tet = NULL;
9192  }
9193  ivf.iloc = (int) OUTSIDE;
9194  // Insert the vertex.
9195  if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
9196  if (flipstack != NULL) {
9197  // Perform flip to recover Delaunayness.
9198  incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
9199  }
9200  } else {
9201  if (ivf.iloc == (int) ONVERTEX) {
9202  // The point already exists. Mark it and do nothing on it.
9203  swapvertex = org(searchtet);
9204  if (b->object != tetgenbehavior::STL) {
9205  if (!b->quiet) {
9206  printf("Warning: Point #%d is coincident with #%d. Ignored!\n",
9207  pointmark(permutarray[i]), pointmark(swapvertex));
9208  }
9209  }
9210  setpoint2ppt(permutarray[i], swapvertex);
9211  setpointtype(permutarray[i], DUPLICATEDVERTEX);
9212  dupverts++;
9213  } else if (ivf.iloc == (int) NEARVERTEX) {
9214  swapvertex = org(searchtet);
9215  if (!b->quiet) {
9216  printf("Warning: Point %d is replaced by point %d.\n",
9217  pointmark(permutarray[i]), pointmark(swapvertex));
9218  printf(" Avoid creating a very short edge (len = %g) (< %g).\n",
9219  permutarray[i][3], minedgelength);
9220  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
9221  b->epsilon);
9222  printf(" or use the option -M0/1 to avoid such replacement.\n");
9223  }
9224  // Remember it is a duplicated point.
9225  setpoint2ppt(permutarray[i], swapvertex);
9226  setpointtype(permutarray[i], DUPLICATEDVERTEX);
9227  dupverts++;
9228  } else if (ivf.iloc == (int) NONREGULAR) {
9229  // The point is non-regular. Skipped.
9230  if (b->verbose) {
9231  printf(" Point #%d is non-regular, skipped.\n",
9232  pointmark(permutarray[i]));
9233  }
9234  setpointtype(permutarray[i], NREGULARVERTEX);
9235  nonregularcount++;
9236  }
9237  }
9238  }
9239 
9240 
9241 
9242  delete [] permutarray;
9243 }
9244 
9248 
9252 
9254 // //
9255 // flipshpush() Push a facet edge into flip stack. //
9256 // //
9258 
9260 {
9261  badface *newflipface;
9262 
9263  newflipface = (badface *) flippool->alloc();
9264  newflipface->ss = *flipedge;
9265  newflipface->forg = sorg(*flipedge);
9266  newflipface->fdest = sdest(*flipedge);
9267  newflipface->nextitem = flipstack;
9268  flipstack = newflipface;
9269 }
9270 
9272 // //
9273 // flip22() Perform a 2-to-2 flip in surface mesh. //
9274 // //
9275 // 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and //
9276 // [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
9277 // is replaced by edge [c,d]. //
9278 // //
9280 
9281 void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
9282 {
9283  face bdedges[4], outfaces[4], infaces[4];
9284  face bdsegs[4];
9285  face checkface;
9286  point pa, pb, pc, pd;
9287  int i;
9288 
9289  pa = sorg(flipfaces[0]);
9290  pb = sdest(flipfaces[0]);
9291  pc = sapex(flipfaces[0]);
9292  pd = sapex(flipfaces[1]);
9293 
9294  if (sorg(flipfaces[1]) != pb) {
9295  sesymself(flipfaces[1]);
9296  }
9297 
9298  flip22count++;
9299 
9300  // Collect the four boundary edges.
9301  senext(flipfaces[0], bdedges[0]);
9302  senext2(flipfaces[0], bdedges[1]);
9303  senext(flipfaces[1], bdedges[2]);
9304  senext2(flipfaces[1], bdedges[3]);
9305 
9306  // Collect outer boundary faces.
9307  for (i = 0; i < 4; i++) {
9308  spivot(bdedges[i], outfaces[i]);
9309  infaces[i] = outfaces[i];
9310  sspivot(bdedges[i], bdsegs[i]);
9311  if (outfaces[i].sh != NULL) {
9312  if (isshsubseg(bdedges[i])) {
9313  spivot(infaces[i], checkface);
9314  while (checkface.sh != bdedges[i].sh) {
9315  infaces[i] = checkface;
9316  spivot(infaces[i], checkface);
9317  }
9318  }
9319  }
9320  }
9321 
9322  // The flags set in these two subfaces do not change.
9323  // Shellmark does not change.
9324  // area constraint does not change.
9325 
9326  // Transform [a,b,c] -> [c,d,b].
9327  setshvertices(flipfaces[0], pc, pd, pb);
9328  // Transform [b,a,d] -> [d,c,a].
9329  setshvertices(flipfaces[1], pd, pc, pa);
9330 
9331  // Update the point-to-subface map.
9332  if (pointtype(pa) == FREEFACETVERTEX) {
9333  setpoint2sh(pa, sencode(flipfaces[1]));
9334  }
9335  if (pointtype(pb) == FREEFACETVERTEX) {
9336  setpoint2sh(pb, sencode(flipfaces[0]));
9337  }
9338  if (pointtype(pc) == FREEFACETVERTEX) {
9339  setpoint2sh(pc, sencode(flipfaces[0]));
9340  }
9341  if (pointtype(pd) == FREEFACETVERTEX) {
9342  setpoint2sh(pd, sencode(flipfaces[0]));
9343  }
9344 
9345  // Reconnect boundary edges to outer boundary faces.
9346  for (i = 0; i < 4; i++) {
9347  if (outfaces[(3 + i) % 4].sh != NULL) {
9348  // Make sure that the subface has the ori as the segment.
9349  if (bdsegs[(3 + i) % 4].sh != NULL) {
9350  bdsegs[(3 + i) % 4].shver = 0;
9351  if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
9352  sesymself(bdedges[i]);
9353  }
9354  }
9355  sbond1(bdedges[i], outfaces[(3 + i) % 4]);
9356  sbond1(infaces[(3 + i) % 4], bdedges[i]);
9357  } else {
9358  sdissolve(bdedges[i]);
9359  }
9360  if (bdsegs[(3 + i) % 4].sh != NULL) {
9361  ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
9362  if (chkencflag & 1) {
9363  // Queue this segment for encroaching check.
9364  enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
9365  }
9366  } else {
9367  ssdissolve(bdedges[i]);
9368  }
9369  }
9370 
9371  if (chkencflag & 2) {
9372  // Queue the flipped subfaces for quality/encroaching checks.
9373  for (i = 0; i < 2; i++) {
9374  enqueuesubface(badsubfacs, &(flipfaces[i]));
9375  }
9376  }
9377 
9378  recentsh = flipfaces[0];
9379 
9380  if (flipflag) {
9381  // Put the boundary edges into flip stack.
9382  for (i = 0; i < 4; i++) {
9383  flipshpush(&(bdedges[i]));
9384  }
9385  }
9386 }
9387 
9389 // //
9390 // flip31() Remove a vertex by transforming 3-to-1 subfaces. //
9391 // //
9392 // 'flipfaces' is an array of subfaces. Its length is at least 4. On input, //
9393 // the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine //
9394 // replaces them by one face [a,b,c], it is returned in flipfaces[3]. //
9395 // //
9396 // NOTE: The three old subfaces are not deleted within this routine. They //
9397 // still hold pointers to their adjacent subfaces. These informations are //
9398 // needed by the routine 'sremovevertex()' for recovering a segment. //
9399 // The caller of this routine must delete the old subfaces after their uses. //
9400 // //
9402 
9403 void tetgenmesh::flip31(face* flipfaces, int flipflag)
9404 {
9405  face bdedges[3], outfaces[3], infaces[3];
9406  face bdsegs[3];
9407  face checkface;
9408  point pa, pb, pc;
9409  int i;
9410 
9411  pa = sdest(flipfaces[0]);
9412  pb = sdest(flipfaces[1]);
9413  pc = sdest(flipfaces[2]);
9414 
9415  flip31count++;
9416 
9417  // Collect all infos at the three boundary edges.
9418  for (i = 0; i < 3; i++) {
9419  senext(flipfaces[i], bdedges[i]);
9420  spivot(bdedges[i], outfaces[i]);
9421  infaces[i] = outfaces[i];
9422  sspivot(bdedges[i], bdsegs[i]);
9423  if (outfaces[i].sh != NULL) {
9424  if (isshsubseg(bdedges[i])) {
9425  spivot(infaces[i], checkface);
9426  while (checkface.sh != bdedges[i].sh) {
9427  infaces[i] = checkface;
9428  spivot(infaces[i], checkface);
9429  }
9430  }
9431  }
9432  } // i
9433 
9434  // Create a new subface.
9435  makeshellface(subfaces, &(flipfaces[3]));
9436  setshvertices(flipfaces[3], pa, pb,pc);
9437  setshellmark(flipfaces[3], shellmark(flipfaces[0]));
9438  if (checkconstraints) {
9439  //area = areabound(flipfaces[0]);
9440  setareabound(flipfaces[3], areabound(flipfaces[0]));
9441  }
9442  if (useinsertradius) {
9443  setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
9444  }
9445 
9446  // Update the point-to-subface map.
9447  if (pointtype(pa) == FREEFACETVERTEX) {
9448  setpoint2sh(pa, sencode(flipfaces[3]));
9449  }
9450  if (pointtype(pb) == FREEFACETVERTEX) {
9451  setpoint2sh(pb, sencode(flipfaces[3]));
9452  }
9453  if (pointtype(pc) == FREEFACETVERTEX) {
9454  setpoint2sh(pc, sencode(flipfaces[3]));
9455  }
9456 
9457  // Update the three new boundary edges.
9458  bdedges[0] = flipfaces[3]; // [a,b]
9459  senext(flipfaces[3], bdedges[1]); // [b,c]
9460  senext2(flipfaces[3], bdedges[2]); // [c,a]
9461 
9462  // Reconnect boundary edges to outer boundary faces.
9463  for (i = 0; i < 3; i++) {
9464  if (outfaces[i].sh != NULL) {
9465  // Make sure that the subface has the ori as the segment.
9466  if (bdsegs[i].sh != NULL) {
9467  bdsegs[i].shver = 0;
9468  if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
9469  sesymself(bdedges[i]);
9470  }
9471  }
9472  sbond1(bdedges[i], outfaces[i]);
9473  sbond1(infaces[i], bdedges[i]);
9474  }
9475  if (bdsegs[i].sh != NULL) {
9476  ssbond(bdedges[i], bdsegs[i]);
9477  }
9478  }
9479 
9480  recentsh = flipfaces[3];
9481 
9482  if (flipflag) {
9483  // Put the boundary edges into flip stack.
9484  for (i = 0; i < 3; i++) {
9485  flipshpush(&(bdedges[i]));
9486  }
9487  }
9488 }
9489 
9491 // //
9492 // lawsonflip() Flip non-locally Delaunay edges. //
9493 // //
9495 
9497 {
9498  badface *popface;
9499  face flipfaces[2];
9500  point pa, pb, pc, pd;
9501  REAL sign;
9502  long flipcount = 0;
9503 
9504  if (b->verbose > 2) {
9505  printf(" Lawson flip %ld edges.\n", flippool->items);
9506  }
9507 
9508  while (flipstack != (badface *) NULL) {
9509 
9510  // Pop an edge from the stack.
9511  popface = flipstack;
9512  flipfaces[0] = popface->ss;
9513  pa = popface->forg;
9514  pb = popface->fdest;
9515  flipstack = popface->nextitem; // The next top item in stack.
9516  flippool->dealloc((void *) popface);
9517 
9518  // Skip it if it is dead.
9519  if (flipfaces[0].sh[3] == NULL) continue;
9520  // Skip it if it is not the same edge as we saved.
9521  if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
9522  // Skip it if it is a subsegment.
9523  if (isshsubseg(flipfaces[0])) continue;
9524 
9525  // Get the adjacent face.
9526  spivot(flipfaces[0], flipfaces[1]);
9527  if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
9528  pc = sapex(flipfaces[0]);
9529  pd = sapex(flipfaces[1]);
9530 
9531  sign = incircle3d(pa, pb, pc, pd);
9532 
9533  if (sign < 0) {
9534  // It is non-locally Delaunay. Flip it.
9535  flip22(flipfaces, 1, 0);
9536  flipcount++;
9537  }
9538  }
9539 
9540  if (b->verbose > 2) {
9541  printf(" Performed %ld flips.\n", flipcount);
9542  }
9543 
9544  return flipcount;
9545 }
9546 
9548 // //
9549 // sinsertvertex() Insert a vertex into a triangulation of a facet. //
9550 // //
9551 // This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
9552 // 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p), //
9553 // 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a //
9554 // segment, 'cavesegshlist' returns the two new subsegments. //
9555 // //
9556 // 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
9557 // will first locate the point. It starts searching from 'searchsh' or 'rec- //
9558 // entsh' if 'searchsh' is NULL. //
9559 // //
9560 // If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert //
9561 // the vertex. Otherwise, only insert the vertex in the initial cavity. //
9562 // //
9563 // If 'iloc' is 'INSTAR', this means the cavity of this vertex was already //
9564 // provided in the list 'caveshlist'. //
9565 // //
9566 // If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
9567 // be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'. //
9568 // //
9569 // 'rflag' (rounding) is a parameter passed to slocate() function. If it is //
9570 // set, after the location of the point is found, either ONEDGE or ONFACE, //
9571 // round the result using an epsilon. //
9572 // //
9573 // NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
9574 // want to remove the new point immediately. //
9575 // //
9577 
9578 int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
9579  int iloc, int bowywat, int rflag)
9580 {
9581  face cavesh, neighsh, *parysh;
9582  face newsh, casout, casin;
9583  face checkseg;
9584  point pa, pb;
9585  enum locateresult loc = OUTSIDE;
9586  REAL sign, ori;
9587  int i, j;
9588 
9589  if (b->verbose > 2) {
9590  printf(" Insert facet point %d.\n", pointmark(insertpt));
9591  }
9592 
9593  if (bowywat == 3) {
9594  loc = INSTAR;
9595  }
9596 
9597  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9598  // A segment is going to be split, no point location.
9599  spivot(*splitseg, *searchsh);
9600  if (loc != INSTAR) loc = ONEDGE;
9601  } else {
9602  if (loc != INSTAR) loc = (enum locateresult) iloc;
9603  if (loc == OUTSIDE) {
9604  // Do point location in surface mesh.
9605  if (searchsh->sh == NULL) {
9606  *searchsh = recentsh;
9607  }
9608  // Search the vertex. An above point must be provided ('aflag' = 1).
9609  loc = slocate(insertpt, searchsh, 1, 1, rflag);
9610  }
9611  }
9612 
9613 
9614  // Form the initial sC(p).
9615  if (loc == ONFACE) {
9616  // Add the face into list (in B-W cavity).
9617  smarktest(*searchsh);
9618  caveshlist->newindex((void **) &parysh);
9619  *parysh = *searchsh;
9620  } else if (loc == ONEDGE) {
9621  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9622  splitseg->shver = 0;
9623  pa = sorg(*splitseg);
9624  } else {
9625  pa = sorg(*searchsh);
9626  }
9627  if (searchsh->sh != NULL) {
9628  // Collect all subfaces share at this edge.
9629  neighsh = *searchsh;
9630  while (1) {
9631  // Adjust the origin of its edge to be 'pa'.
9632  if (sorg(neighsh) != pa) sesymself(neighsh);
9633  // Add this face into list (in B-W cavity).
9634  smarktest(neighsh);
9635  caveshlist->newindex((void **) &parysh);
9636  *parysh = neighsh;
9637  // Add this face into face-at-splitedge list.
9638  cavesegshlist->newindex((void **) &parysh);
9639  *parysh = neighsh;
9640  // Go to the next face at the edge.
9641  spivotself(neighsh);
9642  // Stop if all faces at the edge have been visited.
9643  if (neighsh.sh == searchsh->sh) break;
9644  if (neighsh.sh == NULL) break;
9645  }
9646  } // If (not a non-dangling segment).
9647  } else if (loc == ONVERTEX) {
9648  return (int) loc;
9649  } else if (loc == OUTSIDE) {
9650  // Comment: This should only happen during the surface meshing step.
9651  // Enlarge the convex hull of the triangulation by including p.
9652  // An above point of the facet is set in 'dummypoint' to replace
9653  // orient2d tests by orient3d tests.
9654  // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
9655  // plane, and a->b is directed from left to right, p lies above a->b.
9656  // Find the right-most edge of the triangulation which is visible by p.
9657  neighsh = *searchsh;
9658  while (1) {
9659  senext2self(neighsh);
9660  spivot(neighsh, casout);
9661  if (casout.sh == NULL) {
9662  // A convex hull edge. Is it visible by p.
9663  ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
9664  if (ori < 0) {
9665  *searchsh = neighsh; // Visible, update 'searchsh'.
9666  } else {
9667  break; // 'searchsh' is the right-most visible edge.
9668  }
9669  } else {
9670  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
9671  neighsh = casout;
9672  }
9673  }
9674  // Create new triangles for all visible edges of p (from right to left).
9675  casin.sh = NULL; // No adjacent face at right.
9676  pa = sorg(*searchsh);
9677  pb = sdest(*searchsh);
9678  while (1) {
9679  // Create a new subface on top of the (visible) edge.
9680  makeshellface(subfaces, &newsh);
9681  setshvertices(newsh, pb, pa, insertpt);
9682  setshellmark(newsh, shellmark(*searchsh));
9683  if (checkconstraints) {
9684  //area = areabound(*searchsh);
9685  setareabound(newsh, areabound(*searchsh));
9686  }
9687  if (useinsertradius) {
9688  setfacetindex(newsh, getfacetindex(*searchsh));
9689  }
9690  // Connect the new subface to the bottom subfaces.
9691  sbond1(newsh, *searchsh);
9692  sbond1(*searchsh, newsh);
9693  // Connect the new subface to its right-adjacent subface.
9694  if (casin.sh != NULL) {
9695  senext(newsh, casout);
9696  sbond1(casout, casin);
9697  sbond1(casin, casout);
9698  }
9699  // The left-adjacent subface has not been created yet.
9700  senext2(newsh, casin);
9701  // Add the new face into list (inside the B-W cavity).
9702  smarktest(newsh);
9703  caveshlist->newindex((void **) &parysh);
9704  *parysh = newsh;
9705  // Move to the convex hull edge at the left of 'searchsh'.
9706  neighsh = *searchsh;
9707  while (1) {
9708  senextself(neighsh);
9709  spivot(neighsh, casout);
9710  if (casout.sh == NULL) {
9711  *searchsh = neighsh;
9712  break;
9713  }
9714  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
9715  neighsh = casout;
9716  }
9717  // A convex hull edge. Is it visible by p.
9718  pa = sorg(*searchsh);
9719  pb = sdest(*searchsh);
9720  ori = orient3d(pa, pb, dummypoint, insertpt);
9721  // Finish the process if p is not visible by the hull edge.
9722  if (ori >= 0) break;
9723  }
9724  } else if (loc == INSTAR) {
9725  // Under this case, the sub-cavity sC(p) has already been formed in
9726  // insertvertex().
9727  }
9728 
9729  // Form the Bowyer-Watson cavity sC(p).
9730  for (i = 0; i < caveshlist->objects; i++) {
9731  cavesh = * (face *) fastlookup(caveshlist, i);
9732  for (j = 0; j < 3; j++) {
9733  if (!isshsubseg(cavesh)) {
9734  spivot(cavesh, neighsh);
9735  if (neighsh.sh != NULL) {
9736  // The adjacent face exists.
9737  if (!smarktested(neighsh)) {
9738  if (bowywat) {
9739  if (loc == INSTAR) { // if (bowywat > 2) {
9740  // It must be a boundary edge.
9741  sign = 1;
9742  } else {
9743  // Check if this subface is connected to adjacent tet(s).
9744  if (!isshtet(neighsh)) {
9745  // Check if the subface is non-Delaunay wrt. the new pt.
9746  sign = incircle3d(sorg(neighsh), sdest(neighsh),
9747  sapex(neighsh), insertpt);
9748  } else {
9749  // It is connected to an adjacent tet. A boundary edge.
9750  sign = 1;
9751  }
9752  }
9753  if (sign < 0) {
9754  // Add the adjacent face in list (in B-W cavity).
9755  smarktest(neighsh);
9756  caveshlist->newindex((void **) &parysh);
9757  *parysh = neighsh;
9758  }
9759  } else {
9760  sign = 1; // A boundary edge.
9761  }
9762  } else {
9763  sign = -1; // Not a boundary edge.
9764  }
9765  } else {
9766  // No adjacent face. It is a hull edge.
9767  if (loc == OUTSIDE) {
9768  // It is a boundary edge if it does not contain p.
9769  if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
9770  sign = -1; // Not a boundary edge.
9771  } else {
9772  sign = 1; // A boundary edge.
9773  }
9774  } else {
9775  sign = 1; // A boundary edge.
9776  }
9777  }
9778  } else {
9779  // Do not across a segment. It is a boundary edge.
9780  sign = 1;
9781  }
9782  if (sign >= 0) {
9783  // Add a boundary edge.
9784  caveshbdlist->newindex((void **) &parysh);
9785  *parysh = cavesh;
9786  }
9787  senextself(cavesh);
9788  } // j
9789  } // i
9790 
9791 
9792  // Creating new subfaces.
9793  for (i = 0; i < caveshbdlist->objects; i++) {
9794  parysh = (face *) fastlookup(caveshbdlist, i);
9795  sspivot(*parysh, checkseg);
9796  if ((parysh->shver & 01) != 0) sesymself(*parysh);
9797  pa = sorg(*parysh);
9798  pb = sdest(*parysh);
9799  // Create a new subface.
9800  makeshellface(subfaces, &newsh);
9801  setshvertices(newsh, pa, pb, insertpt);
9802  setshellmark(newsh, shellmark(*parysh));
9803  if (checkconstraints) {
9804  //area = areabound(*parysh);
9805  setareabound(newsh, areabound(*parysh));
9806  }
9807  if (useinsertradius) {
9808  setfacetindex(newsh, getfacetindex(*parysh));
9809  }
9810  // Update the point-to-subface map.
9811  if (pointtype(pa) == FREEFACETVERTEX) {
9812  setpoint2sh(pa, sencode(newsh));
9813  }
9814  if (pointtype(pb) == FREEFACETVERTEX) {
9815  setpoint2sh(pb, sencode(newsh));
9816  }
9817  // Connect newsh to outer subfaces.
9818  spivot(*parysh, casout);
9819  if (casout.sh != NULL) {
9820  casin = casout;
9821  if (checkseg.sh != NULL) {
9822  // Make sure that newsh has the right ori at this segment.
9823  checkseg.shver = 0;
9824  if (sorg(newsh) != sorg(checkseg)) {
9825  sesymself(newsh);
9826  sesymself(*parysh); // This side should also be inverse.
9827  }
9828  spivot(casin, neighsh);
9829  while (neighsh.sh != parysh->sh) {
9830  casin = neighsh;
9831  spivot(casin, neighsh);
9832  }
9833  }
9834  sbond1(newsh, casout);
9835  sbond1(casin, newsh);
9836  }
9837  if (checkseg.sh != NULL) {
9838  ssbond(newsh, checkseg);
9839  }
9840  // Connect oldsh <== newsh (for connecting adjacent new subfaces).
9841  // *parysh and newsh point to the same edge and the same ori.
9842  sbond1(*parysh, newsh);
9843  }
9844 
9845  if (newsh.sh != NULL) {
9846  // Set a handle for searching.
9847  recentsh = newsh;
9848  }
9849 
9850  // Update the point-to-subface map.
9851  if (pointtype(insertpt) == FREEFACETVERTEX) {
9852  setpoint2sh(insertpt, sencode(newsh));
9853  }
9854 
9855  // Connect adjacent new subfaces together.
9856  for (i = 0; i < caveshbdlist->objects; i++) {
9857  // Get an old subface at edge [a, b].
9858  parysh = (face *) fastlookup(caveshbdlist, i);
9859  spivot(*parysh, newsh); // The new subface [a, b, p].
9860  senextself(newsh); // At edge [b, p].
9861  spivot(newsh, neighsh);
9862  if (neighsh.sh == NULL) {
9863  // Find the adjacent new subface at edge [b, p].
9864  pb = sdest(*parysh);
9865  neighsh = *parysh;
9866  while (1) {
9867  senextself(neighsh);
9868  spivotself(neighsh);
9869  if (neighsh.sh == NULL) break;
9870  if (!smarktested(neighsh)) break;
9871  if (sdest(neighsh) != pb) sesymself(neighsh);
9872  }
9873  if (neighsh.sh != NULL) {
9874  // Now 'neighsh' is a new subface at edge [b, #].
9875  if (sorg(neighsh) != pb) sesymself(neighsh);
9876  senext2self(neighsh); // Go to the open edge [p, b].
9877  sbond(newsh, neighsh);
9878  }
9879  }
9880  spivot(*parysh, newsh); // The new subface [a, b, p].
9881  senext2self(newsh); // At edge [p, a].
9882  spivot(newsh, neighsh);
9883  if (neighsh.sh == NULL) {
9884  // Find the adjacent new subface at edge [p, a].
9885  pa = sorg(*parysh);
9886  neighsh = *parysh;
9887  while (1) {
9888  senext2self(neighsh);
9889  spivotself(neighsh);
9890  if (neighsh.sh == NULL) break;
9891  if (!smarktested(neighsh)) break;
9892  if (sorg(neighsh) != pa) sesymself(neighsh);
9893  }
9894  if (neighsh.sh != NULL) {
9895  // Now 'neighsh' is a new subface at edge [#, a].
9896  if (sdest(neighsh) != pa) sesymself(neighsh);
9897  senextself(neighsh); // Go to the open edge [a, p].
9898  sbond(newsh, neighsh);
9899  }
9900  }
9901  }
9902 
9903  if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
9904  || (cavesegshlist->objects > 0l)) {
9905  // An edge is being split. We distinguish two cases:
9906  // (1) the edge is not on the boundary of the cavity;
9907  // (2) the edge is on the boundary of the cavity.
9908  // In case (2), the edge is either a segment or a hull edge. There are
9909  // degenerated new faces in the cavity. They must be removed.
9910  face aseg, bseg, aoutseg, boutseg;
9911 
9912  for (i = 0; i < cavesegshlist->objects; i++) {
9913  // Get the saved old subface.
9914  parysh = (face *) fastlookup(cavesegshlist, i);
9915  // Get a possible new degenerated subface.
9916  spivot(*parysh, cavesh);
9917  if (sapex(cavesh) == insertpt) {
9918  // Found a degenerated new subface, i.e., case (2).
9919  if (cavesegshlist->objects > 1) {
9920  // There are more than one subface share at this edge.
9921  j = (i + 1) % (int) cavesegshlist->objects;
9922  parysh = (face *) fastlookup(cavesegshlist, j);
9923  spivot(*parysh, neighsh);
9924  // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
9925  if (sorg(neighsh) != sorg(cavesh)) {
9926  sesymself(neighsh);
9927  }
9928  // Connect adjacent faces at two other edges of cavesh and neighsh.
9929  // As a result, the two degenerated new faces are squeezed from the
9930  // new triangulation of the cavity. Note that the squeezed faces
9931  // still hold the adjacent informations which will be used in
9932  // re-connecting subsegments (if they exist).
9933  for (j = 0; j < 2; j++) {
9934  senextself(cavesh);
9935  senextself(neighsh);
9936  spivot(cavesh, newsh);
9937  spivot(neighsh, casout);
9938  sbond1(newsh, casout); // newsh <- casout.
9939  }
9940  } else {
9941  // There is only one subface containing this edge [a,b]. Squeeze the
9942  // degenerated new face [a,b,c] by disconnecting it from its two
9943  // adjacent subfaces at edges [b,c] and [c,a]. Note that the face
9944  // [a,b,c] still hold the connection to them.
9945  for (j = 0; j < 2; j++) {
9946  senextself(cavesh);
9947  spivot(cavesh, newsh);
9948  sdissolve(newsh);
9949  }
9950  }
9951  //recentsh = newsh;
9952  // Update the point-to-subface map.
9953  if (pointtype(insertpt) == FREEFACETVERTEX) {
9954  setpoint2sh(insertpt, sencode(newsh));
9955  }
9956  }
9957  }
9958 
9959  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9960  if (loc != INSTAR) { // if (bowywat < 3) {
9961  smarktest(*splitseg); // Mark it as being processed.
9962  }
9963 
9964  aseg = *splitseg;
9965  pa = sorg(*splitseg);
9966  pb = sdest(*splitseg);
9967 
9968  // Insert the new point p.
9969  makeshellface(subsegs, &aseg);
9970  makeshellface(subsegs, &bseg);
9971 
9972  setshvertices(aseg, pa, insertpt, NULL);
9973  setshvertices(bseg, insertpt, pb, NULL);
9974  setshellmark(aseg, shellmark(*splitseg));
9975  setshellmark(bseg, shellmark(*splitseg));
9976  if (checkconstraints) {
9977  setareabound(aseg, areabound(*splitseg));
9978  setareabound(bseg, areabound(*splitseg));
9979  }
9980  if (useinsertradius) {
9981  setfacetindex(aseg, getfacetindex(*splitseg));
9982  setfacetindex(bseg, getfacetindex(*splitseg));
9983  }
9984 
9985  // Connect [#, a]<->[a, p].
9986  senext2(*splitseg, boutseg); // Temporarily use boutseg.
9987  spivotself(boutseg);
9988  if (boutseg.sh != NULL) {
9989  senext2(aseg, aoutseg);
9990  sbond(boutseg, aoutseg);
9991  }
9992  // Connect [p, b]<->[b, #].
9993  senext(*splitseg, aoutseg);
9994  spivotself(aoutseg);
9995  if (aoutseg.sh != NULL) {
9996  senext(bseg, boutseg);
9997  sbond(boutseg, aoutseg);
9998  }
9999  // Connect [a, p] <-> [p, b].
10000  senext(aseg, aoutseg);
10001  senext2(bseg, boutseg);
10002  sbond(aoutseg, boutseg);
10003 
10004  // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
10005  // Although the degenerated new faces have been squeezed. They still
10006  // hold the connections to the actual new faces.
10007  for (i = 0; i < cavesegshlist->objects; i++) {
10008  parysh = (face *) fastlookup(cavesegshlist, i);
10009  spivot(*parysh, neighsh);
10010  // neighsh is a degenerated new face.
10011  if (sorg(neighsh) != pa) {
10012  sesymself(neighsh);
10013  }
10014  senext2(neighsh, newsh);
10015  spivotself(newsh); // The edge [p, a] in newsh
10016  ssbond(newsh, aseg);
10017  senext(neighsh, newsh);
10018  spivotself(newsh); // The edge [b, p] in newsh
10019  ssbond(newsh, bseg);
10020  }
10021 
10022 
10023  // Let the point remember the segment it lies on.
10024  if (pointtype(insertpt) == FREESEGVERTEX) {
10025  setpoint2sh(insertpt, sencode(aseg));
10026  }
10027  // Update the point-to-seg map.
10028  if (pointtype(pa) == FREESEGVERTEX) {
10029  setpoint2sh(pa, sencode(aseg));
10030  }
10031  if (pointtype(pb) == FREESEGVERTEX) {
10032  setpoint2sh(pb, sencode(bseg));
10033  }
10034  } // if ((splitseg != NULL) && (splitseg->sh != NULL))
10035 
10036  // Delete all degenerated new faces.
10037  for (i = 0; i < cavesegshlist->objects; i++) {
10038  parysh = (face *) fastlookup(cavesegshlist, i);
10039  spivotself(*parysh);
10040  if (sapex(*parysh) == insertpt) {
10041  shellfacedealloc(subfaces, parysh->sh);
10042  }
10043  }
10045 
10046  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10047  // Return the two new subsegments (for further process).
10048  // Re-use 'cavesegshlist'.
10049  cavesegshlist->newindex((void **) &parysh);
10050  *parysh = aseg;
10051  cavesegshlist->newindex((void **) &parysh);
10052  *parysh = bseg;
10053  }
10054  } // if (loc == ONEDGE)
10055 
10056 
10057  return (int) loc;
10058 }
10059 
10061 // //
10062 // sremovevertex() Remove a vertex from the surface mesh. //
10063 // //
10064 // 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
10065 // a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a //
10066 // facet vertex, and the origin of 'parentsh' is p. //
10067 // //
10068 // Within each facet, we first use a sequence of 2-to-2 flips to flip any //
10069 // edge at p, finally use a 3-to-1 flip to remove p. //
10070 // //
10071 // All new created subfaces are returned in the global array 'caveshbdlist'. //
10072 // The new segment (when p is on segment) is returned in 'parentseg'. //
10073 // //
10074 // If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay- //
10075 // ness after p is removed. //
10076 // //
10078 
10079 int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
10080  int lawson)
10081 {
10082  face flipfaces[4], spinsh, *parysh;
10083  point pa, pb, pc, pd;
10084  REAL ori1, ori2;
10085  int it, i, j;
10086 
10087  if (parentseg != NULL) {
10088  // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
10089  // where 'parentseg' should be [p,b]. Find the segment [a,p].
10090  face startsh, neighsh, nextsh;
10091  face abseg, prevseg, checkseg;
10092  face adjseg1, adjseg2;
10093  face fakesh;
10094  senext2(*parentseg, prevseg);
10095  spivotself(prevseg);
10096  prevseg.shver = 0;
10097  // Restore the original segment [a,b].
10098  pa = sorg(prevseg);
10099  pb = sdest(*parentseg);
10100  if (b->verbose > 2) {
10101  printf(" Remove vertex %d from segment [%d, %d].\n",
10102  pointmark(delpt), pointmark(pa), pointmark(pb));
10103  }
10104  makeshellface(subsegs, &abseg);
10105  setshvertices(abseg, pa, pb, NULL);
10106  setshellmark(abseg, shellmark(*parentseg));
10107  if (checkconstraints) {
10108  setareabound(abseg, areabound(*parentseg));
10109  }
10110  if (useinsertradius) {
10111  setfacetindex(abseg, getfacetindex(*parentseg));
10112  }
10113  // Connect [#, a]<->[a, b].
10114  senext2(prevseg, adjseg1);
10115  spivotself(adjseg1);
10116  if (adjseg1.sh != NULL) {
10117  adjseg1.shver = 0;
10118  senextself(adjseg1);
10119  senext2(abseg, adjseg2);
10120  sbond(adjseg1, adjseg2);
10121  }
10122  // Connect [a, b]<->[b, #].
10123  senext(*parentseg, adjseg1);
10124  spivotself(adjseg1);
10125  if (adjseg1.sh != NULL) {
10126  adjseg1.shver = 0;
10127  senext2self(adjseg1);
10128  senext(abseg, adjseg2);
10129  sbond(adjseg1, adjseg2);
10130  }
10131  // Update the point-to-segment map.
10132  setpoint2sh(pa, sencode(abseg));
10133  setpoint2sh(pb, sencode(abseg));
10134 
10135  // Get the faces in face ring at segment [p, b].
10136  // Re-use array 'caveshlist'.
10137  spivot(*parentseg, *parentsh);
10138  if (parentsh->sh != NULL) {
10139  spinsh = *parentsh;
10140  while (1) {
10141  // Save this face in list.
10142  caveshlist->newindex((void **) &parysh);
10143  *parysh = spinsh;
10144  // Go to the next face in the ring.
10145  spivotself(spinsh);
10146  if (spinsh.sh == NULL) {
10147  break; // It is possible there is only one facet.
10148  }
10149  if (spinsh.sh == parentsh->sh) break;
10150  }
10151  }
10152 
10153  // Create the face ring of the new segment [a,b]. Each face in the ring
10154  // is [a,b,p] (degenerated!). It will be removed (automatically).
10155  for (i = 0; i < caveshlist->objects; i++) {
10156  parysh = (face *) fastlookup(caveshlist, i);
10157  startsh = *parysh;
10158  if (sorg(startsh) != delpt) {
10159  sesymself(startsh);
10160  }
10161  // startsh is [p, b, #1], find the subface [a, p, #2].
10162  neighsh = startsh;
10163  while (1) {
10164  senext2self(neighsh);
10165  sspivot(neighsh, checkseg);
10166  if (checkseg.sh != NULL) {
10167  // It must be the segment [a, p].
10168  break;
10169  }
10170  spivotself(neighsh);
10171  if (sorg(neighsh) != delpt) sesymself(neighsh);
10172  }
10173  // Now neighsh is [a, p, #2].
10174  if (neighsh.sh != startsh.sh) {
10175  // Detach the two subsegments [a,p] and [p,b] from subfaces.
10176  ssdissolve(startsh);
10177  ssdissolve(neighsh);
10178  // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
10179  // new segment [a,b]; (2) connect to the two adjacent subfaces
10180  // [p,b,#] and [a,p,#].
10181  makeshellface(subfaces, &fakesh);
10182  setshvertices(fakesh, pa, pb, delpt);
10183  setshellmark(fakesh, shellmark(startsh));
10184  // Connect fakesh to the segment [a,b].
10185  ssbond(fakesh, abseg);
10186  // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
10187  senext(fakesh, nextsh);
10188  sbond(nextsh, startsh);
10189  senext2(fakesh, nextsh);
10190  sbond(nextsh, neighsh);
10191  smarktest(fakesh); // Mark it as faked.
10192  } else {
10193  // Special case. There exists already a degenerated face [a,b,p]!
10194  // There is no need to create a faked subface here.
10195  senext2self(neighsh); // [a,b,p]
10196  // Since we will re-connect the face ring using the faked subfaces.
10197  // We put the adjacent face of [a,b,p] to the list.
10198  spivot(neighsh, startsh); // The original adjacent subface.
10199  if (sorg(startsh) != pa) sesymself(startsh);
10200  sdissolve(startsh);
10201  // Connect fakesh to the segment [a,b].
10202  ssbond(startsh, abseg);
10203  fakesh = startsh; // Do not mark it!
10204  // Delete the degenerated subface.
10205  shellfacedealloc(subfaces, neighsh.sh);
10206  }
10207  // Save the fakesh in list (for re-creating the face ring).
10208  cavesegshlist->newindex((void **) &parysh);
10209  *parysh = fakesh;
10210  } // i
10211  caveshlist->restart();
10212 
10213  // Re-create the face ring.
10214  if (cavesegshlist->objects > 1) {
10215  for (i = 0; i < cavesegshlist->objects; i++) {
10216  parysh = (face *) fastlookup(cavesegshlist, i);
10217  fakesh = *parysh;
10218  // Get the next face in the ring.
10219  j = (i + 1) % cavesegshlist->objects;
10220  parysh = (face *) fastlookup(cavesegshlist, j);
10221  nextsh = *parysh;
10222  sbond1(fakesh, nextsh);
10223  }
10224  }
10225 
10226  // Delete the two subsegments containing p.
10227  shellfacedealloc(subsegs, parentseg->sh);
10228  shellfacedealloc(subsegs, prevseg.sh);
10229  // Return the new segment.
10230  *parentseg = abseg;
10231  } else {
10232  // p is inside the surface.
10233  if (b->verbose > 2) {
10234  printf(" Remove vertex %d from surface.\n", pointmark(delpt));
10235  }
10236  // Let 'delpt' be its apex.
10237  senextself(*parentsh);
10238  // For unifying the code, we add parentsh to list.
10239  cavesegshlist->newindex((void **) &parysh);
10240  *parysh = *parentsh;
10241  }
10242 
10243  // Remove the point (p).
10244 
10245  for (it = 0; it < cavesegshlist->objects; it++) {
10246  parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
10247  senextself(*parentsh); // [b,p,a].
10248  spivotself(*parentsh);
10249  if (sorg(*parentsh) != delpt) sesymself(*parentsh);
10250  // now parentsh is [p,b,#].
10251  if (sorg(*parentsh) != delpt) {
10252  // The vertex has already been removed in above special case.
10253  continue;
10254  }
10255 
10256  while (1) {
10257  // Initialize the flip edge list. Re-use 'caveshlist'.
10258  spinsh = *parentsh; // [p, b, #]
10259  while (1) {
10260  caveshlist->newindex((void **) &parysh);
10261  *parysh = spinsh;
10262  senext2self(spinsh);
10263  spivotself(spinsh);
10264  if (spinsh.sh == parentsh->sh) break;
10265  if (sorg(spinsh) != delpt) sesymself(spinsh);
10266  } // while (1)
10267 
10268  if (caveshlist->objects == 3) {
10269  // Delete the point by a 3-to-1 flip.
10270  for (i = 0; i < 3; i++) {
10271  parysh = (face *) fastlookup(caveshlist, i);
10272  flipfaces[i] = *parysh;
10273  }
10274  flip31(flipfaces, lawson);
10275  for (i = 0; i < 3; i++) {
10276  shellfacedealloc(subfaces, flipfaces[i].sh);
10277  }
10278  caveshlist->restart();
10279  // Save the new subface.
10280  caveshbdlist->newindex((void **) &parysh);
10281  *parysh = flipfaces[3];
10282  // The vertex is removed.
10283  break;
10284  }
10285 
10286  // Search an edge to flip.
10287  for (i = 0; i < caveshlist->objects; i++) {
10288  parysh = (face *) fastlookup(caveshlist, i);
10289  flipfaces[0] = *parysh;
10290  spivot(flipfaces[0], flipfaces[1]);
10291  if (sorg(flipfaces[0]) != sdest(flipfaces[1]))
10292  sesymself(flipfaces[1]);
10293  // Skip this edge if it belongs to a faked subface.
10294  if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
10295  pa = sorg(flipfaces[0]);
10296  pb = sdest(flipfaces[0]);
10297  pc = sapex(flipfaces[0]);
10298  pd = sapex(flipfaces[1]);
10299  calculateabovepoint4(pa, pb, pc, pd);
10300  // Check if a 2-to-2 flip is possible.
10301  ori1 = orient3d(pc, pd, dummypoint, pa);
10302  ori2 = orient3d(pc, pd, dummypoint, pb);
10303  if (ori1 * ori2 < 0) {
10304  // A 2-to-2 flip is found.
10305  flip22(flipfaces, lawson, 0);
10306  // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
10307  // changed. The 'flipfaces[1]' contains p as its apex.
10308  senext2(flipfaces[1], *parentsh);
10309  // Save the new subface.
10310  caveshbdlist->newindex((void **) &parysh);
10311  *parysh = flipfaces[0];
10312  break;
10313  }
10314  } //
10315  } // i
10316 
10317  if (i == caveshlist->objects) {
10318  // Do a flip22 and a flip31 to remove p.
10319  parysh = (face *) fastlookup(caveshlist, 0);
10320  flipfaces[0] = *parysh;
10321  spivot(flipfaces[0], flipfaces[1]);
10322  if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
10323  sesymself(flipfaces[1]);
10324  }
10325  flip22(flipfaces, lawson, 0);
10326  senext2(flipfaces[1], *parentsh);
10327  // Save the new subface.
10328  caveshbdlist->newindex((void **) &parysh);
10329  *parysh = flipfaces[0];
10330  }
10331 
10332  // The edge list at p are changed.
10333  caveshlist->restart();
10334  } // while (1)
10335 
10336  } // it
10337 
10339 
10340  if (b->verbose > 2) {
10341  printf(" Created %ld new subfaces.\n", caveshbdlist->objects);
10342  }
10343 
10344 
10345  if (lawson) {
10346  lawsonflip();
10347  }
10348 
10349  return 0;
10350 }
10351 
10353 // //
10354 // slocate() Locate a point in a surface triangulation. //
10355 // //
10356 // Staring the search from 'searchsh'(it should not be NULL). Perform a line //
10357 // walk search for a subface containing the point (p). //
10358 // //
10359 // If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies //
10360 // above the 'searchsh' in its current orientation. The test if c is CCW to //
10361 // the line a->b can be done by the test if c is below the oriented plane //
10362 // a->b->dummypoint. //
10363 // //
10364 // If 'cflag' is not TRUE, the triangulation may not be convex. Stop search //
10365 // when a segment is met and return OUTSIDE. //
10366 // //
10367 // If 'rflag' (rounding) is set, after the location of the point is found, //
10368 // either ONEDGE or ONFACE, round the result using an epsilon. //
10369 // //
10370 // The returned value indicates the following cases: //
10371 // - ONVERTEX, p is the origin of 'searchsh'. //
10372 // - ONEDGE, p lies on the edge of 'searchsh'. //
10373 // - ONFACE, p lies in the interior of 'searchsh'. //
10374 // - OUTSIDE, p lies outside of the triangulation, p is on the left-hand //
10375 // side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW. //
10376 // //
10378 
10380  face* searchsh, int aflag, int cflag, int rflag)
10381 {
10382  face neighsh;
10383  point pa, pb, pc;
10384  enum locateresult loc;
10385  enum {MOVE_BC, MOVE_CA} nextmove;
10386  REAL ori, ori_bc, ori_ca;
10387  int i;
10388 
10389  pa = sorg(*searchsh);
10390  pb = sdest(*searchsh);
10391  pc = sapex(*searchsh);
10392 
10393  if (!aflag) {
10394  // No above point is given. Calculate an above point for this facet.
10395  calculateabovepoint4(pa, pb, pc, searchpt);
10396  }
10397 
10398  // 'dummypoint' is given. Make sure it is above [a,b,c]
10399  ori = orient3d(pa, pb, pc, dummypoint);
10400  if (ori > 0) {
10401  sesymself(*searchsh); // Reverse the face orientation.
10402  } else if (ori == 0.0) {
10403  // This case should not happen theoretically. But...
10404  return UNKNOWN;
10405  }
10406 
10407  // Find an edge of the face s.t. p lies on its right-hand side (CCW).
10408  for (i = 0; i < 3; i++) {
10409  pa = sorg(*searchsh);
10410  pb = sdest(*searchsh);
10411  ori = orient3d(pa, pb, dummypoint, searchpt);
10412  if (ori > 0) break;
10413  senextself(*searchsh);
10414  }
10415  if (i == 3) {
10416  return UNKNOWN;
10417  }
10418 
10419  pc = sapex(*searchsh);
10420 
10421  if (pc == searchpt) {
10422  senext2self(*searchsh);
10423  return ONVERTEX;
10424  }
10425 
10426  while (1) {
10427 
10428  ori_bc = orient3d(pb, pc, dummypoint, searchpt);
10429  ori_ca = orient3d(pc, pa, dummypoint, searchpt);
10430 
10431  if (ori_bc < 0) {
10432  if (ori_ca < 0) { // (--)
10433  // Any of the edges is a viable move.
10434  if (randomnation(2)) {
10435  nextmove = MOVE_CA;
10436  } else {
10437  nextmove = MOVE_BC;
10438  }
10439  } else { // (-#)
10440  // Edge [b, c] is viable.
10441  nextmove = MOVE_BC;
10442  }
10443  } else {
10444  if (ori_ca < 0) { // (#-)
10445  // Edge [c, a] is viable.
10446  nextmove = MOVE_CA;
10447  } else {
10448  if (ori_bc > 0) {
10449  if (ori_ca > 0) { // (++)
10450  loc = ONFACE; // Inside [a, b, c].
10451  break;
10452  } else { // (+0)
10453  senext2self(*searchsh); // On edge [c, a].
10454  loc = ONEDGE;
10455  break;
10456  }
10457  } else { // ori_bc == 0
10458  if (ori_ca > 0) { // (0+)
10459  senextself(*searchsh); // On edge [b, c].
10460  loc = ONEDGE;
10461  break;
10462  } else { // (00)
10463  // p is coincident with vertex c.
10464  senext2self(*searchsh);
10465  return ONVERTEX;
10466  }
10467  }
10468  }
10469  }
10470 
10471  // Move to the next face.
10472  if (nextmove == MOVE_BC) {
10473  senextself(*searchsh);
10474  } else {
10475  senext2self(*searchsh);
10476  }
10477  if (!cflag) {
10478  // NON-convex case. Check if we will cross a boundary.
10479  if (isshsubseg(*searchsh)) {
10480  return ENCSEGMENT;
10481  }
10482  }
10483  spivot(*searchsh, neighsh);
10484  if (neighsh.sh == NULL) {
10485  return OUTSIDE; // A hull edge.
10486  }
10487  // Adjust the edge orientation.
10488  if (sorg(neighsh) != sdest(*searchsh)) {
10489  sesymself(neighsh);
10490  }
10491 
10492  // Update the newly discovered face and its endpoints.
10493  *searchsh = neighsh;
10494  pa = sorg(*searchsh);
10495  pb = sdest(*searchsh);
10496  pc = sapex(*searchsh);
10497 
10498  if (pc == searchpt) {
10499  senext2self(*searchsh);
10500  return ONVERTEX;
10501  }
10502 
10503  } // while (1)
10504 
10505  // assert(loc == ONFACE || loc == ONEDGE);
10506 
10507 
10508  if (rflag) {
10509  // Round the locate result before return.
10510  REAL n[3], area_abc, area_abp, area_bcp, area_cap;
10511 
10512  pa = sorg(*searchsh);
10513  pb = sdest(*searchsh);
10514  pc = sapex(*searchsh);
10515 
10516  facenormal(pa, pb, pc, n, 1, NULL);
10517  area_abc = sqrt(dot(n, n));
10518 
10519  facenormal(pb, pc, searchpt, n, 1, NULL);
10520  area_bcp = sqrt(dot(n, n));
10521  if ((area_bcp / area_abc) < b->epsilon) {
10522  area_bcp = 0; // Rounding.
10523  }
10524 
10525  facenormal(pc, pa, searchpt, n, 1, NULL);
10526  area_cap = sqrt(dot(n, n));
10527  if ((area_cap / area_abc) < b->epsilon) {
10528  area_cap = 0; // Rounding
10529  }
10530 
10531  if ((loc == ONFACE) || (loc == OUTSIDE)) {
10532  facenormal(pa, pb, searchpt, n, 1, NULL);
10533  area_abp = sqrt(dot(n, n));
10534  if ((area_abp / area_abc) < b->epsilon) {
10535  area_abp = 0; // Rounding
10536  }
10537  } else { // loc == ONEDGE
10538  area_abp = 0;
10539  }
10540 
10541  if (area_abp == 0) {
10542  if (area_bcp == 0) {
10543  senextself(*searchsh);
10544  loc = ONVERTEX; // p is close to b.
10545  } else {
10546  if (area_cap == 0) {
10547  loc = ONVERTEX; // p is close to a.
10548  } else {
10549  loc = ONEDGE; // p is on edge [a,b].
10550  }
10551  }
10552  } else if (area_bcp == 0) {
10553  if (area_cap == 0) {
10554  senext2self(*searchsh);
10555  loc = ONVERTEX; // p is close to c.
10556  } else {
10557  senextself(*searchsh);
10558  loc = ONEDGE; // p is on edge [b,c].
10559  }
10560  } else if (area_cap == 0) {
10561  senext2self(*searchsh);
10562  loc = ONEDGE; // p is on edge [c,a].
10563  } else {
10564  loc = ONFACE; // p is on face [a,b,c].
10565  }
10566  } // if (rflag)
10567 
10568  return loc;
10569 }
10570 
10572 // //
10573 // sscoutsegment() Look for a segment in the surface triangulation. //
10574 // //
10575 // The segment is given by the origin of 'searchsh' and 'endpt'. //
10576 // //
10577 // If an edge in T is found matching this segment, the segment is "locked" //
10578 // in T at the edge. Otherwise, flip the first edge in T that the segment //
10579 // crosses. Continue the search from the flipped face. //
10580 // //
10581 // This routine uses 'orisent3d' to determine the search direction. It uses //
10582 // 'dummypoint' as the 'lifted point' in 3d, and it assumes that it (dummy- //
10583 // point) lies above the 'searchsh' (w.r.t the Right-hand rule). //
10584 // //
10586 
10588  point endpt, int insertsegflag, int reporterrorflag, int chkencflag)
10589 {
10590  face flipshs[2], neighsh;
10591  point startpt, pa, pb, pc, pd;
10592  enum interresult dir;
10593  enum {MOVE_AB, MOVE_CA} nextmove;
10594  REAL ori_ab, ori_ca, len;
10595 
10596  // The origin of 'searchsh' is fixed.
10597  startpt = sorg(*searchsh);
10598  nextmove = MOVE_AB; // Avoid compiler warning.
10599 
10600  if (b->verbose > 2) {
10601  printf(" Scout segment (%d, %d).\n", pointmark(startpt),
10602  pointmark(endpt));
10603  }
10604  len = distance(startpt, endpt);
10605 
10606  // Search an edge in 'searchsh' on the path of this segment.
10607  while (1) {
10608 
10609  pb = sdest(*searchsh);
10610  if (pb == endpt) {
10611  dir = SHAREEDGE; // Found!
10612  break;
10613  }
10614 
10615  pc = sapex(*searchsh);
10616  if (pc == endpt) {
10617  senext2self(*searchsh);
10618  sesymself(*searchsh);
10619  dir = SHAREEDGE; // Found!
10620  break;
10621  }
10622 
10623 
10624  // Round the results.
10625  if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
10626  ori_ab = 0.0;
10627  } else {
10628  ori_ab = orient3d(startpt, pb, dummypoint, endpt);
10629  }
10630  if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
10631  ori_ca = 0.0;
10632  } else {
10633  ori_ca = orient3d(pc, startpt, dummypoint, endpt);
10634  }
10635 
10636  if (ori_ab < 0) {
10637  if (ori_ca < 0) { // (--)
10638  // Both sides are viable moves.
10639  if (randomnation(2)) {
10640  nextmove = MOVE_CA;
10641  } else {
10642  nextmove = MOVE_AB;
10643  }
10644  } else { // (-#)
10645  nextmove = MOVE_AB;
10646  }
10647  } else {
10648  if (ori_ca < 0) { // (#-)
10649  nextmove = MOVE_CA;
10650  } else {
10651  if (ori_ab > 0) {
10652  if (ori_ca > 0) { // (++)
10653  // The segment intersects with edge [b, c].
10654  dir = ACROSSEDGE;
10655  break;
10656  } else { // (+0)
10657  // The segment collinear with edge [c, a].
10658  senext2self(*searchsh);
10659  sesymself(*searchsh);
10660  dir = ACROSSVERT;
10661  break;
10662  }
10663  } else {
10664  if (ori_ca > 0) { // (0+)
10665  // The segment is collinear with edge [a, b].
10666  dir = ACROSSVERT;
10667  break;
10668  } else { // (00)
10669  // startpt == endpt. Not possible.
10670  terminatetetgen(this, 2);
10671  }
10672  }
10673  }
10674  }
10675 
10676  // Move 'searchsh' to the next face, keep the origin unchanged.
10677  if (nextmove == MOVE_AB) {
10678  if (chkencflag) {
10679  // Do not cross boundary.
10680  if (isshsubseg(*searchsh)) {
10681  return ACROSSEDGE; // ACROSS_SEG
10682  }
10683  }
10684  spivot(*searchsh, neighsh);
10685  if (neighsh.sh != NULL) {
10686  if (sorg(neighsh) != pb) sesymself(neighsh);
10687  senext(neighsh, *searchsh);
10688  } else {
10689  // This side (startpt->pb) is outside. It is caused by rounding error.
10690  // Try the next side, i.e., (pc->startpt).
10691  senext2(*searchsh, neighsh);
10692  if (chkencflag) {
10693  // Do not cross boundary.
10694  if (isshsubseg(neighsh)) {
10695  *searchsh = neighsh;
10696  return ACROSSEDGE; // ACROSS_SEG
10697  }
10698  }
10699  spivotself(neighsh);
10700  if (sdest(neighsh) != pc) sesymself(neighsh);
10701  *searchsh = neighsh;
10702  }
10703  } else { // MOVE_CA
10704  senext2(*searchsh, neighsh);
10705  if (chkencflag) {
10706  // Do not cross boundary.
10707  if (isshsubseg(neighsh)) {
10708  *searchsh = neighsh;
10709  return ACROSSEDGE; // ACROSS_SEG
10710  }
10711  }
10712  spivotself(neighsh);
10713  if (neighsh.sh != NULL) {
10714  if (sdest(neighsh) != pc) sesymself(neighsh);
10715  *searchsh = neighsh;
10716  } else {
10717  // The same reason as above.
10718  // Try the next side, i.e., (startpt->pb).
10719  if (chkencflag) {
10720  // Do not cross boundary.
10721  if (isshsubseg(*searchsh)) {
10722  return ACROSSEDGE; // ACROSS_SEG
10723  }
10724  }
10725  spivot(*searchsh, neighsh);
10726  if (sorg(neighsh) != pb) sesymself(neighsh);
10727  senext(neighsh, *searchsh);
10728  }
10729  }
10730  } // while
10731 
10732  if (dir == SHAREEDGE) {
10733  if (insertsegflag) {
10734  // Insert the segment into the triangulation.
10735  face newseg;
10736  makeshellface(subsegs, &newseg);
10737  setshvertices(newseg, startpt, endpt, NULL);
10738  // Set the default segment marker.
10739  setshellmark(newseg, -1);
10740  ssbond(*searchsh, newseg);
10741  spivot(*searchsh, neighsh);
10742  if (neighsh.sh != NULL) {
10743  ssbond(neighsh, newseg);
10744  }
10745  }
10746  return dir;
10747  }
10748 
10749  if (dir == ACROSSVERT) {
10750  // A point is found collinear with this segment.
10751  if (reporterrorflag) {
10752  point pp = sdest(*searchsh);
10753  printf("PLC Error: A vertex lies in a segment in facet #%d.\n",
10754  shellmark(*searchsh));
10755  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
10756  printf(" Segment: [%d, %d]\n", pointmark(startpt), pointmark(endpt));
10757  }
10758  return dir;
10759  }
10760 
10761  if (dir == ACROSSEDGE) {
10762  // Edge [b, c] intersects with the segment.
10763  senext(*searchsh, flipshs[0]);
10764  if (isshsubseg(flipshs[0])) {
10765  if (reporterrorflag) {
10766  REAL P[3], Q[3], tp = 0, tq = 0;
10767  linelineint(startpt, endpt, pb, pc, P, Q, &tp, &tq);
10768  printf("PLC Error: Two segments intersect at point (%g,%g,%g),",
10769  P[0], P[1], P[2]);
10770  printf(" in facet #%d.\n", shellmark(*searchsh));
10771  printf(" Segment 1: [%d, %d]\n", pointmark(pb), pointmark(pc));
10772  printf(" Segment 2: [%d, %d]\n", pointmark(startpt),pointmark(endpt));
10773  }
10774  return dir; // ACROSS_SEG
10775  }
10776  // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
10777  spivot(flipshs[0], flipshs[1]);
10778  if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
10779  flip22(flipshs, 1, 0);
10780  // The flip may create an inverted triangle, check it.
10781  pa = sapex(flipshs[1]);
10782  pb = sapex(flipshs[0]);
10783  pc = sorg(flipshs[0]);
10784  pd = sdest(flipshs[0]);
10785  // Check if pa and pb are on the different sides of [pc, pd].
10786  // Re-use ori_ab, ori_ca for the tests.
10787  ori_ab = orient3d(pc, pd, dummypoint, pb);
10788  ori_ca = orient3d(pd, pc, dummypoint, pa);
10789  if (ori_ab <= 0) {
10790  flipshpush(&(flipshs[0]));
10791  } else if (ori_ca <= 0) {
10792  flipshpush(&(flipshs[1]));
10793  }
10794  // Set 'searchsh' s.t. its origin is 'startpt'.
10795  *searchsh = flipshs[0];
10796  }
10797 
10798  return sscoutsegment(searchsh, endpt, insertsegflag, reporterrorflag,
10799  chkencflag);
10800 }
10801 
10803 // //
10804 // scarveholes() Remove triangles not in the facet. //
10805 // //
10806 // This routine re-uses the two global arrays: caveshlist and caveshbdlist. //
10807 // //
10809 
10810 void tetgenmesh::scarveholes(int holes, REAL* holelist)
10811 {
10812  face *parysh, searchsh, neighsh;
10813  enum locateresult loc;
10814  int i, j;
10815 
10816  // Get all triangles. Infect unprotected convex hull triangles.
10818  caveshlist->newindex((void **) &parysh);
10819  *parysh = recentsh;
10820  for (i = 0; i < caveshlist->objects; i++) {
10821  parysh = (face *) fastlookup(caveshlist, i);
10822  searchsh = *parysh;
10823  searchsh.shver = 0;
10824  for (j = 0; j < 3; j++) {
10825  spivot(searchsh, neighsh);
10826  // Is this side on the convex hull?
10827  if (neighsh.sh != NULL) {
10828  if (!smarktested(neighsh)) {
10829  smarktest(neighsh);
10830  caveshlist->newindex((void **) &parysh);
10831  *parysh = neighsh;
10832  }
10833  } else {
10834  // A hull side. Check if it is protected by a segment.
10835  if (!isshsubseg(searchsh)) {
10836  // Not protected. Save this face.
10837  if (!sinfected(searchsh)) {
10838  sinfect(searchsh);
10839  caveshbdlist->newindex((void **) &parysh);
10840  *parysh = searchsh;
10841  }
10842  }
10843  }
10844  senextself(searchsh);
10845  }
10846  }
10847 
10848  // Infect the triangles in the holes.
10849  for (i = 0; i < 3 * holes; i += 3) {
10850  searchsh = recentsh;
10851  loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
10852  if (loc != OUTSIDE) {
10853  sinfect(searchsh);
10854  caveshbdlist->newindex((void **) &parysh);
10855  *parysh = searchsh;
10856  }
10857  }
10858 
10859  // Find and infect all exterior triangles.
10860  for (i = 0; i < caveshbdlist->objects; i++) {
10861  parysh = (face *) fastlookup(caveshbdlist, i);
10862  searchsh = *parysh;
10863  searchsh.shver = 0;
10864  for (j = 0; j < 3; j++) {
10865  spivot(searchsh, neighsh);
10866  if (neighsh.sh != NULL) {
10867  if (!isshsubseg(searchsh)) {
10868  if (!sinfected(neighsh)) {
10869  sinfect(neighsh);
10870  caveshbdlist->newindex((void **) &parysh);
10871  *parysh = neighsh;
10872  }
10873  } else {
10874  sdissolve(neighsh); // Disconnect a protected face.
10875  }
10876  }
10877  senextself(searchsh);
10878  }
10879  }
10880 
10881  // Delete exterior triangles, unmark interior triangles.
10882  for (i = 0; i < caveshlist->objects; i++) {
10883  parysh = (face *) fastlookup(caveshlist, i);
10884  if (sinfected(*parysh)) {
10885  shellfacedealloc(subfaces, parysh->sh);
10886  } else {
10887  sunmarktest(*parysh);
10888  }
10889  }
10890 
10891  caveshlist->restart();
10892  caveshbdlist->restart();
10893 }
10894 
10895 
10897 // //
10898 // unifysegments() Remove redundant segments and create face links. //
10899 // //
10900 // After this routine, although segments are unique, but some of them may be //
10901 // removed later by mergefacet(). All vertices still have type FACETVERTEX. //
10902 // //
10904 
10906 {
10907  badface *facelink = NULL, *newlinkitem, *f1, *f2;
10908  face *facperverlist, sface;
10909  face subsegloop, testseg;
10910  point torg, tdest;
10911  REAL ori1, ori2, ori3;
10912  REAL n1[3], n2[3];
10913  REAL cosang, ang, ang_tol;
10914  int *idx2faclist;
10915  int idx, k, m;
10916 
10917  if (b->verbose > 1) {
10918  printf(" Unifying segments.\n");
10919  }
10920  // The limit dihedral angle that two facets are not overlapping.
10921  ang_tol = b->facet_overlap_ang_tol / 180.0 * PI;
10922  if (ang_tol < 0.0) ang_tol = 0.0;
10923 
10924  // Create a mapping from vertices to subfaces.
10925  makepoint2submap(subfaces, idx2faclist, facperverlist);
10926 
10927 
10928  subsegloop.shver = 0;
10930  subsegloop.sh = shellfacetraverse(subsegs);
10931  while (subsegloop.sh != (shellface *) NULL) {
10932  torg = sorg(subsegloop);
10933  tdest = sdest(subsegloop);
10934 
10935  idx = pointmark(torg) - in->firstnumber;
10936  // Loop through the set of subfaces containing 'torg'. Get all the
10937  // subfaces containing the edge (torg, tdest). Save and order them
10938  // in 'sfacelist', the ordering is defined by the right-hand rule
10939  // with thumb points from torg to tdest.
10940  for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
10941  sface = facperverlist[k];
10942  // The face may be deleted if it is a duplicated face.
10943  if (sface.sh[3] == NULL) continue;
10944  // Search the edge torg->tdest.
10945  if (sdest(sface) != tdest) {
10946  senext2self(sface);
10947  sesymself(sface);
10948  }
10949  if (sdest(sface) != tdest) continue;
10950 
10951  // Save the face f in facelink.
10952  if (flippool->items >= 2) {
10953  f1 = facelink;
10954  for (m = 0; m < flippool->items - 1; m++) {
10955  f2 = f1->nextitem;
10956  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
10957  ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
10958  if (ori1 > 0) {
10959  // apex(f2) is below f1.
10960  if (ori2 > 0) {
10961  // apex(f) is below f1 (see Fig.1).
10962  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
10963  if (ori3 > 0) {
10964  // apex(f) is below f2, insert it.
10965  break;
10966  } else if (ori3 < 0) {
10967  // apex(f) is above f2, continue.
10968  } else { // ori3 == 0;
10969  // f is coplanar and codirection with f2.
10970  report_overlapping_facets(&(f2->ss), &sface);
10971  break;
10972  }
10973  } else if (ori2 < 0) {
10974  // apex(f) is above f1 below f2, inset it (see Fig. 2).
10975  break;
10976  } else { // ori2 == 0;
10977  // apex(f) is coplanar with f1 (see Fig. 5).
10978  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
10979  if (ori3 > 0) {
10980  // apex(f) is below f2, insert it.
10981  break;
10982  } else {
10983  // f is coplanar and codirection with f1.
10984  report_overlapping_facets(&(f1->ss), &sface);
10985  break;
10986  }
10987  }
10988  } else if (ori1 < 0) {
10989  // apex(f2) is above f1.
10990  if (ori2 > 0) {
10991  // apex(f) is below f1, continue (see Fig. 3).
10992  } else if (ori2 < 0) {
10993  // apex(f) is above f1 (see Fig.4).
10994  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
10995  if (ori3 > 0) {
10996  // apex(f) is below f2, insert it.
10997  break;
10998  } else if (ori3 < 0) {
10999  // apex(f) is above f2, continue.
11000  } else { // ori3 == 0;
11001  // f is coplanar and codirection with f2.
11002  report_overlapping_facets(&(f2->ss), &sface);
11003  break;
11004  }
11005  } else { // ori2 == 0;
11006  // f is coplanar and with f1 (see Fig. 6).
11007  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
11008  if (ori3 > 0) {
11009  // f is also codirection with f1.
11010  report_overlapping_facets(&(f1->ss), &sface);
11011  break;
11012  } else {
11013  // f is above f2, continue.
11014  }
11015  }
11016  } else { // ori1 == 0;
11017  // apex(f2) is coplanar with f1. By assumption, f1 is not
11018  // coplanar and codirection with f2.
11019  if (ori2 > 0) {
11020  // apex(f) is below f1, continue (see Fig. 7).
11021  } else if (ori2 < 0) {
11022  // apex(f) is above f1, insert it (see Fig. 7).
11023  break;
11024  } else { // ori2 == 0.
11025  // apex(f) is coplanar with f1 (see Fig. 8).
11026  // f is either codirection with f1 or is codirection with f2.
11027  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
11028  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
11029  if (dot(n1, n2) > 0) {
11030  report_overlapping_facets(&(f1->ss), &sface);
11031  } else {
11032  printf("%12.5E %12.5E %12.5E\n",torg[0],torg[1],torg[2]);
11033  printf("%12.5E %12.5E %12.5E\n",tdest[0],tdest[1],tdest[2]);
11034  printf("%12.5E %12.5E %12.5E\n", sapex(f1->ss)[0], sapex(f1->ss)[1], sapex(f1->ss)[2]);
11035  printf("%d %d %d\n",pointmark(torg), pointmark(tdest), pointmark(sapex(f1->ss)));
11036  printf("%d %d %d\n",pointmark(torg), pointmark(tdest), pointmark(sapex(f2->ss)));
11037  printf("%12.5E %12.5E n1(%12.5E,%12.5E,%12.5E) n2(%12.5E,%12.5E,%12.5E)\n",
11038  ori1,ori2, n1[0], n1[1], n1[2], n2[0], n2[1], n2[2]);
11039  report_overlapping_facets(&(f2->ss), &sface);
11040  }
11041  break;
11042  }
11043  }
11044  // Go to the next item;
11045  f1 = f2;
11046  } // for (m = 0; ...)
11047  if (sface.sh[3] != NULL) {
11048  // Insert sface between f1 and f2.
11049  newlinkitem = (badface *) flippool->alloc();
11050  newlinkitem->ss = sface;
11051  newlinkitem->nextitem = f1->nextitem;
11052  f1->nextitem = newlinkitem;
11053  }
11054  } else if (flippool->items == 1) {
11055  f1 = facelink;
11056  // Make sure that f is not coplanar and codirection with f1.
11057  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
11058  if (ori1 == 0) {
11059  // f is coplanar with f1 (see Fig. 8).
11060  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
11061  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
11062  if (dot(n1, n2) > 0) {
11063  // The two faces are codirectional as well.
11064  report_overlapping_facets(&(f1->ss), &sface);
11065  }
11066  }
11067  // Add this face to link if it is not deleted.
11068  if (sface.sh[3] != NULL) {
11069  // Add this face into link.
11070  newlinkitem = (badface *) flippool->alloc();
11071  newlinkitem->ss = sface;
11072  newlinkitem->nextitem = NULL;
11073  f1->nextitem = newlinkitem;
11074  }
11075  } else {
11076  // The first face.
11077  newlinkitem = (badface *) flippool->alloc();
11078  newlinkitem->ss = sface;
11079  newlinkitem->nextitem = NULL;
11080  facelink = newlinkitem;
11081  }
11082  } // for (k = idx2faclist[idx]; ...)
11083 
11084 
11085  // Set the connection between this segment and faces containing it,
11086  // at the same time, remove redundant segments.
11087  f1 = facelink;
11088  for (k = 0; k < flippool->items; k++) {
11089  sspivot(f1->ss, testseg);
11090  // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
11091  if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
11092  shellfacedealloc(subsegs, testseg.sh);
11093  }
11094  // Bonds the subface and the segment together.
11095  ssbond(f1->ss, subsegloop);
11096  f1 = f1->nextitem;
11097  }
11098 
11099  // Create the face ring at the segment.
11100  if (flippool->items > 1) {
11101  f1 = facelink;
11102  for (k = 1; k <= flippool->items; k++) {
11103  k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
11104  // Calculate the dihedral angle between the two facet.
11105  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
11106  facenormal(torg, tdest, sapex(f2->ss), n2, 1, NULL);
11107  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
11108  // Rounding.
11109  if (cosang > 1.0) cosang = 1.0;
11110  else if (cosang < -1.0) cosang = -1.0;
11111  ang = acos(cosang);
11112  if (ang < ang_tol) {
11113  // Two facets are treated as overlapping each other.
11114  report_overlapping_facets(&(f1->ss), &(f2->ss), ang);
11115  } else {
11116  // Record the smallest input dihedral angle.
11117  if (ang < minfacetdihed) {
11118  minfacetdihed = ang;
11119  }
11120  sbond1(f1->ss, f2->ss);
11121  }
11122  f1 = f2;
11123  }
11124  }
11125 
11126  flippool->restart();
11127 
11128  // Are there length constraints?
11129  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
11130  int e1, e2;
11131  REAL len;
11132  for (k = 0; k < in->numberofsegmentconstraints; k++) {
11133  e1 = (int) in->segmentconstraintlist[k * 3];
11134  e2 = (int) in->segmentconstraintlist[k * 3 + 1];
11135  if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
11136  ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
11137  len = in->segmentconstraintlist[k * 3 + 2];
11138  setareabound(subsegloop, len);
11139  break;
11140  }
11141  }
11142  }
11143 
11144  subsegloop.sh = shellfacetraverse(subsegs);
11145  }
11146 
11147  delete [] idx2faclist;
11148  delete [] facperverlist;
11149 }
11150 
11152 // //
11153 // identifyinputedges() Identify input edges. //
11154 // //
11155 // A set of input edges is provided in the 'in->edgelist'. We find these //
11156 // edges in the surface mesh and make them segments of the mesh. //
11157 // //
11158 // It is possible that an input edge is not in any facet, i.e.,it is a float-//
11159 // segment inside the volume. //
11160 // //
11162 
11164 {
11165  face* shperverlist;
11166  int* idx2shlist;
11167  face searchsh, neighsh;
11168  face segloop, checkseg, newseg;
11169  point checkpt, pa = NULL, pb = NULL;
11170  int *endpts;
11171  int edgemarker;
11172  int idx, i, j;
11173 
11174  int e1, e2;
11175  REAL len;
11176 
11177  if (!b->quiet) {
11178  printf("Inserting edges ...\n");
11179  }
11180 
11181  // Construct a map from points to subfaces.
11182  makepoint2submap(subfaces, idx2shlist, shperverlist);
11183 
11184  // Process the set of input edges.
11185  for (i = 0; i < in->numberofedges; i++) {
11186  endpts = &(in->edgelist[(i << 1)]);
11187  if (endpts[0] == endpts[1]) {
11188  if (!b->quiet) {
11189  printf("Warning: Edge #%d is degenerated. Skipped.\n", i);
11190  }
11191  continue; // Skip a degenerated edge.
11192  }
11193  // Recall that all existing segments have a default marker '-1'.
11194  // We assign all identified segments a default marker '-2'.
11195  edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : -2;
11196 
11197  // Find a face contains the edge.
11198  newseg.sh = NULL;
11199  searchsh.sh = NULL;
11200  idx = endpts[0] - in->firstnumber;
11201  for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
11202  checkpt = sdest(shperverlist[j]);
11203  if (pointmark(checkpt) == endpts[1]) {
11204  searchsh = shperverlist[j];
11205  break; // Found.
11206  } else {
11207  checkpt = sapex(shperverlist[j]);
11208  if (pointmark(checkpt) == endpts[1]) {
11209  senext2(shperverlist[j], searchsh);
11210  sesymself(searchsh);
11211  break;
11212  }
11213  }
11214  } // j
11215 
11216  if (searchsh.sh != NULL) {
11217  // Check if this edge is already a segment of the mesh.
11218  sspivot(searchsh, checkseg);
11219  if (checkseg.sh != NULL) {
11220  // This segment already exist.
11221  newseg = checkseg;
11222  } else {
11223  // Create a new segment at this edge.
11224  pa = sorg(searchsh);
11225  pb = sdest(searchsh);
11226  makeshellface(subsegs, &newseg);
11227  setshvertices(newseg, pa, pb, NULL);
11228  ssbond(searchsh, newseg);
11229  spivot(searchsh, neighsh);
11230  if (neighsh.sh != NULL) {
11231  ssbond(neighsh, newseg);
11232  }
11233  }
11234  } else {
11235  // It is a dangling segment (not belong to any facets).
11236  // Get the two endpoints of this segment.
11237  pa = idx2verlist[endpts[0]];
11238  pb = idx2verlist[endpts[1]];
11239  if (pa == pb) {
11240  if (!b->quiet) {
11241  printf("Warning: Edge #%d is degenerated. Skipped.\n", i);
11242  }
11243  continue;
11244  }
11245  // Check if segment [a,b] already exists.
11246  // TODO: Change the brute-force search. Slow!
11247  point *ppt;
11249  segloop.sh = shellfacetraverse(subsegs);
11250  while (segloop.sh != NULL) {
11251  ppt = (point *) &(segloop.sh[3]);
11252  if (((ppt[0] == pa) && (ppt[1] == pb)) ||
11253  ((ppt[0] == pb) && (ppt[1] == pa))) {
11254  // Found!
11255  newseg = segloop;
11256  break;
11257  }
11258  segloop.sh = shellfacetraverse(subsegs);
11259  }
11260  if (newseg.sh == NULL) {
11261  makeshellface(subsegs, &newseg);
11262  setshvertices(newseg, pa, pb, NULL);
11263  }
11264  }
11265 
11266  setshellmark(newseg, edgemarker);
11267 
11268  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
11269  for (i = 0; i < in->numberofsegmentconstraints; i++) {
11270  e1 = (int) in->segmentconstraintlist[i * 3];
11271  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
11272  if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
11273  ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
11274  len = in->segmentconstraintlist[i * 3 + 2];
11275  setareabound(newseg, len);
11276  break;
11277  }
11278  }
11279  }
11280  } // i
11281 
11282  delete [] shperverlist;
11283  delete [] idx2shlist;
11284 }
11285 
11287 // //
11288 // mergefacets() Merge adjacent facets. //
11289 // //
11291 
11293 {
11294  face parentsh, neighsh, neineish;
11295  face segloop;
11296  point pa, pb, pc, pd;
11297  REAL n1[3], n2[3];
11298  REAL cosang, cosang_tol;
11299 
11300 
11301  // Allocate an array to save calcaulated dihedral angles at segments.
11302  arraypool *dihedangarray = new arraypool(sizeof(double), 10);
11303  REAL *paryang = NULL;
11304 
11305  // First, remove coplanar segments.
11306  // The dihedral angle bound for two different facets.
11307  cosang_tol = cos(b->facet_separate_ang_tol / 180.0 * PI);
11308 
11310  segloop.sh = shellfacetraverse(subsegs);
11311  while (segloop.sh != (shellface *) NULL) {
11312  // Only remove a segment if it has a marker '-1'.
11313  if (shellmark(segloop) != -1) {
11314  segloop.sh = shellfacetraverse(subsegs);
11315  continue;
11316  }
11317  spivot(segloop, parentsh);
11318  if (parentsh.sh != NULL) {
11319  spivot(parentsh, neighsh);
11320  if (neighsh.sh != NULL) {
11321  spivot(neighsh, neineish);
11322  if (neineish.sh == parentsh.sh) {
11323  // Exactly two subfaces at this segment.
11324  // Only merge them if they have the same boundary marker.
11325  if (shellmark(parentsh) == shellmark(neighsh)) {
11326  pa = sorg(segloop);
11327  pb = sdest(segloop);
11328  pc = sapex(parentsh);
11329  pd = sapex(neighsh);
11330  // Calculate the dihedral angle at the segment [a,b].
11331  facenormal(pa, pb, pc, n1, 1, NULL);
11332  facenormal(pa, pb, pd, n2, 1, NULL);
11333  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
11334  if (cosang < cosang_tol) {
11335  ssdissolve(parentsh);
11336  ssdissolve(neighsh);
11337  shellfacedealloc(subsegs, segloop.sh);
11338  // Add the edge to flip stack.
11339  flipshpush(&parentsh);
11340  } else {
11341  // Save 'cosang' to avoid re-calculate it.
11342  // Re-use the pointer at the first segment.
11343  dihedangarray->newindex((void **) &paryang);
11344  *paryang = cosang;
11345  segloop.sh[6] = (shellface) paryang;
11346  }
11347  }
11348  } // if (neineish.sh == parentsh.sh)
11349  }
11350  }
11351  segloop.sh = shellfacetraverse(subsegs);
11352  }
11353 
11354  // Second, remove ridge segments at small angles.
11355  // The dihedral angle bound for two different facets.
11356  cosang_tol = cos(b->facet_small_ang_tol / 180.0 * PI);
11357  REAL cosang_sep_tol = cos((b->facet_separate_ang_tol - 5.0) / 180.0 * PI);
11358  face shloop;
11359  face seg1, seg2;
11360  REAL cosang1, cosang2;
11361  int i, j;
11362 
11364  shloop.sh = shellfacetraverse(subfaces);
11365  while (shloop.sh != (shellface *) NULL) {
11366  for (i = 0; i < 3; i++) {
11367  if (isshsubseg(shloop)) {
11368  senext(shloop, neighsh);
11369  if (isshsubseg(neighsh)) {
11370  // Found two segments sharing at one vertex.
11371  // Check if they form a small angle.
11372  pa = sorg(shloop);
11373  pb = sdest(shloop);
11374  pc = sapex(shloop);
11375  for (j = 0; j < 3; j++) n1[j] = pa[j] - pb[j];
11376  for (j = 0; j < 3; j++) n2[j] = pc[j] - pb[j];
11377  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
11378  if (cosang > cosang_tol) {
11379  // Found a small angle.
11380  segloop.sh = NULL;
11381  sspivot(shloop, seg1);
11382  sspivot(neighsh, seg2);
11383  if (seg1.sh[6] != NULL) {
11384  paryang = (REAL *) (seg1.sh[6]);
11385  cosang1 = *paryang;
11386  } else {
11387  cosang1 = 1.0; // 0 degree;
11388  }
11389  if (seg2.sh[6] != NULL) {
11390  paryang = (REAL *) (seg2.sh[6]);
11391  cosang2 = *paryang;
11392  } else {
11393  cosang2 = 1.0; // 0 degree;
11394  }
11395  if (cosang1 < cosang_sep_tol) {
11396  if (cosang2 < cosang_sep_tol) {
11397  if (cosang1 < cosang2) {
11398  segloop = seg1;
11399  } else {
11400  segloop = seg2;
11401  }
11402  } else {
11403  segloop = seg1;
11404  }
11405  } else {
11406  if (cosang2 < cosang_sep_tol) {
11407  segloop = seg2;
11408  }
11409  }
11410  if (segloop.sh != NULL) {
11411  // Remove this segment.
11412  segloop.shver = 0;
11413  spivot(segloop, parentsh);
11414  spivot(parentsh, neighsh);
11415  ssdissolve(parentsh);
11416  ssdissolve(neighsh);
11417  shellfacedealloc(subsegs, segloop.sh);
11418  // Add the edge to flip stack.
11419  flipshpush(&parentsh);
11420  break;
11421  }
11422  }
11423  } // if (isshsubseg)
11424  } // if (isshsubseg)
11425  senextself(shloop);
11426  }
11427  shloop.sh = shellfacetraverse(subfaces);
11428  }
11429 
11430  delete dihedangarray;
11431 
11432  if (flipstack != NULL) {
11433  lawsonflip(); // Recover Delaunayness.
11434  }
11435 }
11436 
11437 
11439 // //
11440 // finddirection() Find the tet on the path from one point to another. //
11441 // //
11442 // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
11443 // 'searchtet' contains a tet on the path, its origin does not change. //
11444 // //
11445 // The return value indicates one of the following cases (let 'searchtet' be //
11446 // abcd, a is the origin of the path): //
11447 // - ACROSSVERT, edge ab is collinear with the path; //
11448 // - ACROSSEDGE, edge bc intersects with the path; //
11449 // - ACROSSFACE, face bcd intersects with the path. //
11450 // //
11451 // WARNING: This routine is designed for convex triangulations, and will not //
11452 // generally work after the holes and concavities have been carved. //
11453 // //
11455 
11457  tetgenmesh::finddirection(triface* searchtet, point endpt)
11458 {
11459  triface neightet;
11460  point pa, pb, pc, pd;
11461  enum {HMOVE, RMOVE, LMOVE} nextmove;
11462  REAL hori, rori, lori;
11463  int t1ver;
11464  int s;
11465 
11466  // The origin is fixed.
11467  pa = org(*searchtet);
11468  if ((point) searchtet->tet[7] == dummypoint) {
11469  // A hull tet. Choose the neighbor of its base face.
11470  decode(searchtet->tet[3], *searchtet);
11471  // Reset the origin to be pa.
11472  if ((point) searchtet->tet[4] == pa) {
11473  searchtet->ver = 11;
11474  } else if ((point) searchtet->tet[5] == pa) {
11475  searchtet->ver = 3;
11476  } else if ((point) searchtet->tet[6] == pa) {
11477  searchtet->ver = 7;
11478  } else {
11479  searchtet->ver = 0;
11480  }
11481  }
11482 
11483  pb = dest(*searchtet);
11484  // Check whether the destination or apex is 'endpt'.
11485  if (pb == endpt) {
11486  // pa->pb is the search edge.
11487  return ACROSSVERT;
11488  }
11489 
11490  pc = apex(*searchtet);
11491  if (pc == endpt) {
11492  // pa->pc is the search edge.
11493  eprevesymself(*searchtet);
11494  return ACROSSVERT;
11495  }
11496 
11497  // Walk through tets around pa until the right one is found.
11498  size_t loopCount = 0;
11499  while (1) {
11500 
11501  pd = oppo(*searchtet);
11502  // Check whether the opposite vertex is 'endpt'.
11503  if (pd == endpt) {
11504  // pa->pd is the search edge.
11505  esymself(*searchtet);
11506  enextself(*searchtet);
11507  return ACROSSVERT;
11508  }
11509  // Check if we have entered outside of the domain.
11510  if (pd == dummypoint) {
11511  // This is possible when the mesh is non-convex.
11512  if (nonconvex) {
11513  return ACROSSFACE; // return ACROSSSUB; // Hit a bounday.
11514  } else {
11515  terminatetetgen(this, 2);
11516  }
11517  }
11518 
11519  // Now assume that the base face abc coincides with the horizon plane,
11520  // and d lies above the horizon. The search point 'endpt' may lie
11521  // above or below the horizon. We test the orientations of 'endpt'
11522  // with respect to three planes: abc (horizon), bad (right plane),
11523  // and acd (left plane).
11524  hori = orient3d(pa, pb, pc, endpt);
11525  rori = orient3d(pb, pa, pd, endpt);
11526  lori = orient3d(pa, pc, pd, endpt);
11527 
11528  // Now decide the tet to move. It is possible there are more than one
11529  // tets are viable moves. Is so, randomly choose one.
11530  if (hori > 0) {
11531  if (rori > 0) {
11532  if (lori > 0) {
11533  // Any of the three neighbors is a viable move.
11534  s = randomnation(3);
11535  if (s == 0) {
11536  nextmove = HMOVE;
11537  } else if (s == 1) {
11538  nextmove = RMOVE;
11539  } else {
11540  nextmove = LMOVE;
11541  }
11542  } else {
11543  // Two tets, below horizon and below right, are viable.
11544  if (randomnation(2)) {
11545  nextmove = HMOVE;
11546  } else {
11547  nextmove = RMOVE;
11548  }
11549  }
11550  } else {
11551  if (lori > 0) {
11552  // Two tets, below horizon and below left, are viable.
11553  if (randomnation(2)) {
11554  nextmove = HMOVE;
11555  } else {
11556  nextmove = LMOVE;
11557  }
11558  } else {
11559  // The tet below horizon is chosen.
11560  nextmove = HMOVE;
11561  }
11562  }
11563  } else {
11564  if (rori > 0) {
11565  if (lori > 0) {
11566  // Two tets, below right and below left, are viable.
11567  if (randomnation(2)) {
11568  nextmove = RMOVE;
11569  } else {
11570  nextmove = LMOVE;
11571  }
11572  } else {
11573  // The tet below right is chosen.
11574  nextmove = RMOVE;
11575  }
11576  } else {
11577  if (lori > 0) {
11578  // The tet below left is chosen.
11579  nextmove = LMOVE;
11580  } else {
11581  // 'endpt' lies either on the plane(s) or across face bcd.
11582  if (hori == 0) {
11583  if (rori == 0) {
11584  // pa->'endpt' is COLLINEAR with pa->pb.
11585  return ACROSSVERT;
11586  }
11587  if (lori == 0) {
11588  // pa->'endpt' is COLLINEAR with pa->pc.
11589  eprevesymself(*searchtet); // [a,c,d]
11590  return ACROSSVERT;
11591  }
11592  // pa->'endpt' crosses the edge pb->pc.
11593  return ACROSSEDGE;
11594  }
11595  if (rori == 0) {
11596  if (lori == 0) {
11597  // pa->'endpt' is COLLINEAR with pa->pd.
11598  esymself(*searchtet); // face bad.
11599  enextself(*searchtet); // face [a,d,b]
11600  return ACROSSVERT;
11601  }
11602  // pa->'endpt' crosses the edge pb->pd.
11603  esymself(*searchtet); // face bad.
11604  enextself(*searchtet); // face adb
11605  return ACROSSEDGE;
11606  }
11607  if (lori == 0) {
11608  // pa->'endpt' crosses the edge pc->pd.
11609  eprevesymself(*searchtet); // [a,c,d]
11610  return ACROSSEDGE;
11611  }
11612  // pa->'endpt' crosses the face bcd.
11613  return ACROSSFACE;
11614  }
11615  }
11616  }
11617 
11618  // Move to the next tet, fix pa as its origin.
11619  if (nextmove == RMOVE) {
11620  fnextself(*searchtet);
11621  } else if (nextmove == LMOVE) {
11622  eprevself(*searchtet);
11623  fnextself(*searchtet);
11624  enextself(*searchtet);
11625  } else { // HMOVE
11626  fsymself(*searchtet);
11627  enextself(*searchtet);
11628  }
11629  pb = dest(*searchtet);
11630  pc = apex(*searchtet);
11631 
11632  // Highest loopCount encountered in a valid testcase is 124. For values
11633  // much higher than that, we are likely stuck in an infinite loop.
11634  const size_t surelyHangingLoopCountThreshold = 1000000;
11635  if (loopCount > surelyHangingLoopCountThreshold)
11636  {
11637  terminatetetgen(this, 1000);
11638  }
11639  loopCount++;
11640 
11641  } // while (1)
11642 
11643 }
11644 
11645 
11649 
11651 // //
11652 // checkflipeligibility() A call back function for boundary recovery. //
11653 // //
11654 // 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
11655 // and 2 : 3-to-2, respectively. //
11656 // //
11657 // 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is //
11658 // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
11659 // other points must not be 'dummypoint'. //
11660 // //
11662 
11664  point pc, point pd, point pe,
11665  int level, int edgepivot,
11667 {
11668  point tmppts[3];
11669  enum interresult dir;
11670  int types[2], poss[4];
11671  int intflag;
11672  int rejflag = 0;
11673  int i;
11674 
11675  if (fc->seg[0] != NULL) {
11676  // A constraining edge is given (e.g., for edge recovery).
11677  if (fliptype == 1) {
11678  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
11679  tmppts[0] = pa;
11680  tmppts[1] = pb;
11681  tmppts[2] = pc;
11682  for (i = 0; i < 3 && !rejflag; i++) {
11683  if (tmppts[i] != dummypoint) {
11684  // Test if the face [e,d,#] intersects the edge.
11685  intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1],
11686  NULL, 1, types, poss);
11687  if (intflag == 2) {
11688  // They intersect at a single point.
11689  dir = (enum interresult) types[0];
11690  if (dir == ACROSSFACE) {
11691  // The interior of [e,d,#] intersect the segment.
11692  rejflag = 1;
11693  } else if (dir == ACROSSEDGE) {
11694  if (poss[0] == 0) {
11695  // The interior of [e,d] intersect the segment.
11696  // Since [e,d] is the newly created edge. Reject this flip.
11697  rejflag = 1;
11698  }
11699  }
11700  } else if (intflag == 4) {
11701  // They may intersect at either a point or a line segment.
11702  dir = (enum interresult) types[0];
11703  if (dir == ACROSSEDGE) {
11704  if (poss[0] == 0) {
11705  // The interior of [e,d] intersect the segment.
11706  // Since [e,d] is the newly created edge. Reject this flip.
11707  rejflag = 1;
11708  }
11709  }
11710  }
11711  } // if (tmppts[0] != dummypoint)
11712  } // i
11713  } else if (fliptype == 2) {
11714  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
11715  if (pc != dummypoint) {
11716  // Check if the new face [a,b,c] intersect the edge in its interior.
11717  intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL,
11718  1, types, poss);
11719  if (intflag == 2) {
11720  // They intersect at a single point.
11721  dir = (enum interresult) types[0];
11722  if (dir == ACROSSFACE) {
11723  // The interior of [a,b,c] intersect the segment.
11724  rejflag = 1; // Do not flip.
11725  }
11726  } else if (intflag == 4) {
11727  // [a,b,c] is coplanar with the edge.
11728  dir = (enum interresult) types[0];
11729  if (dir == ACROSSEDGE) {
11730  // The boundary of [a,b,c] intersect the segment.
11731  rejflag = 1; // Do not flip.
11732  }
11733  }
11734  } // if (pc != dummypoint)
11735  }
11736  } // if (fc->seg[0] != NULL)
11737 
11738  if ((fc->fac[0] != NULL) && !rejflag) {
11739  // A constraining face is given (e.g., for face recovery).
11740  if (fliptype == 1) {
11741  // A 2-to-3 flip.
11742  // Test if the new edge [e,d] intersects the face.
11743  intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd,
11744  NULL, 1, types, poss);
11745  if (intflag == 2) {
11746  // They intersect at a single point.
11747  dir = (enum interresult) types[0];
11748  if (dir == ACROSSFACE) {
11749  rejflag = 1;
11750  } else if (dir == ACROSSEDGE) {
11751  rejflag = 1;
11752  }
11753  } else if (intflag == 4) {
11754  // The edge [e,d] is coplanar with the face.
11755  // There may be two intersections.
11756  for (i = 0; i < 2 && !rejflag; i++) {
11757  dir = (enum interresult) types[i];
11758  if (dir == ACROSSFACE) {
11759  rejflag = 1;
11760  } else if (dir == ACROSSEDGE) {
11761  rejflag = 1;
11762  }
11763  }
11764  }
11765  } // if (fliptype == 1)
11766  } // if (fc->fac[0] != NULL)
11767 
11768  if ((fc->remvert != NULL) && !rejflag) {
11769  // The vertex is going to be removed. Do not create a new edge which
11770  // contains this vertex.
11771  if (fliptype == 1) {
11772  // A 2-to-3 flip.
11773  if ((pd == fc->remvert) || (pe == fc->remvert)) {
11774  rejflag = 1;
11775  }
11776  }
11777  }
11778 
11779  if (fc->remove_large_angle && !rejflag) {
11780  // Remove a large dihedral angle. Do not create a new small angle.
11781  REAL cosmaxd = 0, diff;
11782  if (fliptype == 1) {
11783  // We assume that neither 'a' nor 'b' is dummypoint.
11784  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
11785  // The new tet [e,d,a,b] will be flipped later. Only two new tets:
11786  // [e,d,b,c] and [e,d,c,a] need to be checked.
11787  if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
11788  // Get the largest dihedral angle of [e,d,b,c].
11789  tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
11790  diff = cosmaxd - fc->cosdihed_in;
11791  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
11792  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
11793  rejflag = 1;
11794  } else {
11795  // Record the largest new angle.
11796  if (cosmaxd < fc->cosdihed_out) {
11797  fc->cosdihed_out = cosmaxd;
11798  }
11799  // Get the largest dihedral angle of [e,d,c,a].
11800  tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
11801  diff = cosmaxd - fc->cosdihed_in;
11802  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
11803  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
11804  rejflag = 1;
11805  } else {
11806  // Record the largest new angle.
11807  if (cosmaxd < fc->cosdihed_out) {
11808  fc->cosdihed_out = cosmaxd;
11809  }
11810  }
11811  }
11812  } // if (pc != dummypoint && ...)
11813  } else if (fliptype == 2) {
11814  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
11815  // We assume that neither 'e' nor 'd' is dummypoint.
11816  if (level == 0) {
11817  // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
11818  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
11819  // Get the largest dihedral angle of [a,b,c,d].
11820  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
11821  diff = cosmaxd - fc->cosdihed_in;
11822  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
11823  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
11824  rejflag = 1;
11825  } else {
11826  // Record the largest new angle.
11827  if (cosmaxd < fc->cosdihed_out) {
11828  fc->cosdihed_out = cosmaxd;
11829  }
11830  // Get the largest dihedral angle of [b,a,c,e].
11831  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
11832  diff = cosmaxd - fc->cosdihed_in;
11833  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
11834  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
11835  rejflag = 1;
11836  } else {
11837  // Record the largest new angle.
11838  if (cosmaxd < fc->cosdihed_out) {
11839  fc->cosdihed_out = cosmaxd;
11840  }
11841  }
11842  }
11843  }
11844  } else { // level > 0
11845  if (edgepivot == 1) {
11846  // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
11847  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
11848  // Get the largest dihedral angle of [b,a,c,e].
11849  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
11850  diff = cosmaxd - fc->cosdihed_in;
11851  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
11852  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
11853  rejflag = 1;
11854  } else {
11855  // Record the largest new angle.
11856  if (cosmaxd < fc->cosdihed_out) {
11857  fc->cosdihed_out = cosmaxd;
11858  }
11859  }
11860  }
11861  } else {
11862  // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
11863  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
11864  // Get the largest dihedral angle of [b,a,c,e].
11865  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
11866  diff = cosmaxd - fc->cosdihed_in;
11867  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
11868  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
11869  rejflag = 1;
11870  } else {
11871  // Record the largest new angle.
11872  if (cosmaxd < fc->cosdihed_out) {
11873  fc->cosdihed_out = cosmaxd;
11874  }
11875  }
11876  }
11877  } // edgepivot
11878  } // level
11879  }
11880  }
11881 
11882  return rejflag;
11883 }
11884 
11886 // //
11887 // removeedgebyflips() Attempt to remove an edge by flips. //
11888 // //
11889 // 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed. //
11890 // //
11891 // The return value is a positive integer, it indicates whether the edge is //
11892 // removed or not. A value "2" means the edge is removed, otherwise, the //
11893 // edge is not removed and the value (must >= 3) is the current number of //
11894 // tets in the edge star. //
11895 // //
11897 
11899 {
11900  triface *abtets, spintet;
11901  int t1ver;
11902  int n, nn, i;
11903 
11904 
11905  if (checksubsegflag) {
11906  // Do not flip a segment.
11907  if (issubseg(*flipedge)) {
11908  if (fc->collectencsegflag) {
11909  face checkseg, *paryseg;
11910  tsspivot1(*flipedge, checkseg);
11911  if (!sinfected(checkseg)) {
11912  // Queue this segment in list.
11913  sinfect(checkseg);
11914  caveencseglist->newindex((void **) &paryseg);
11915  *paryseg = checkseg;
11916  }
11917  }
11918  return 0;
11919  }
11920  }
11921 
11922  // Count the number of tets at edge [a,b].
11923  n = 0;
11924  spintet = *flipedge;
11925  while (1) {
11926  n++;
11927  fnextself(spintet);
11928  if (spintet.tet == flipedge->tet) break;
11929  }
11930  if (n < 3) {
11931  // It is only possible when the mesh contains inverted tetrahedra.
11932  terminatetetgen(this, 2); // Report a bug
11933  }
11934 
11935  if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
11936  // The star size exceeds the limit.
11937  return 0; // Do not flip it.
11938  }
11939 
11940  // Allocate spaces.
11941  abtets = new triface[n];
11942  // Collect the tets at edge [a,b].
11943  spintet = *flipedge;
11944  i = 0;
11945  while (1) {
11946  abtets[i] = spintet;
11947  setelemcounter(abtets[i], 1);
11948  i++;
11949  fnextself(spintet);
11950  if (spintet.tet == flipedge->tet) break;
11951  }
11952 
11953 
11954  // Try to flip the edge (level = 0, edgepivot = 0).
11955  nn = flipnm(abtets, n, 0, 0, fc);
11956 
11957 
11958  if (nn > 2) {
11959  // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
11960  for (i = 0; i < nn; i++) {
11961  setelemcounter(abtets[i], 0);
11962  }
11963  // Restore the input edge (needed by Lawson's flip).
11964  *flipedge = abtets[0];
11965  }
11966 
11967  // Release the temporary allocated spaces.
11968  // NOTE: fc->unflip must be 0.
11969  int bakunflip = fc->unflip;
11970  fc->unflip = 0;
11971  flipnm_post(abtets, n, nn, 0, fc);
11972  fc->unflip = bakunflip;
11973 
11974  delete [] abtets;
11975 
11976  return nn;
11977 }
11978 
11980 // //
11981 // removefacebyflips() Remove a face by flips. //
11982 // //
11983 // Return 1 if the face is removed. Otherwise, return 0. //
11984 // //
11985 // ASSUMPTIONS: //
11986 // - 'flipface' must not be a subface. //
11987 // - 'flipface' must not be a hull face. //
11988 // //
11990 
11992 {
11993  triface fliptets[3], flipedge;
11994  point pa, pb, pc, pd, pe;
11995  REAL ori;
11996  int reducflag = 0;
11997 
11998  fliptets[0] = *flipface;
11999  fsym(*flipface, fliptets[1]);
12000  pa = org(fliptets[0]);
12001  pb = dest(fliptets[0]);
12002  pc = apex(fliptets[0]);
12003  pd = oppo(fliptets[0]);
12004  pe = oppo(fliptets[1]);
12005 
12006  ori = orient3d(pa, pb, pd, pe);
12007  if (ori > 0) {
12008  ori = orient3d(pb, pc, pd, pe);
12009  if (ori > 0) {
12010  ori = orient3d(pc, pa, pd, pe);
12011  if (ori > 0) {
12012  // Found a 2-to-3 flip.
12013  reducflag = 1;
12014  } else {
12015  eprev(*flipface, flipedge); // [c,a]
12016  }
12017  } else {
12018  enext(*flipface, flipedge); // [b,c]
12019  }
12020  } else {
12021  flipedge = *flipface; // [a,b]
12022  }
12023 
12024  if (reducflag) {
12025  // A 2-to-3 flip is found.
12026  flip23(fliptets, 0, fc);
12027  return 1;
12028  } else {
12029  // Try to flip the selected edge of this face.
12030  if (removeedgebyflips(&flipedge, fc) == 2) {
12031  return 1;
12032  }
12033  }
12034 
12035  // Face is not removed.
12036  return 0;
12037 }
12038 
12040 // //
12041 // recoveredge() Recover an edge in current tetrahedralization. //
12042 // //
12043 // If the edge is recovered, 'searchtet' returns a tet containing the edge. //
12044 // //
12045 // This edge may intersect a set of faces and edges in the mesh. All these //
12046 // faces or edges are needed to be removed. //
12047 // //
12048 // If the parameter 'fullsearch' is set, it tries to flip any face or edge //
12049 // that intersects the recovering edge. Otherwise, only the face or edge //
12050 // which is visible by 'startpt' is tried. //
12051 // //
12052 // The parameter 'sedge' is used to report self-intersection. If it is not //
12053 // a NULL, it is EITHER a segment OR a subface that contains this edge. //
12054 // //
12055 // Note that this routine assumes that the tetrahedralization is convex. //
12056 // //
12058 
12059 int tetgenmesh::recoveredgebyflips(point startpt, point endpt, face *sedge,
12060  triface* searchtet, int fullsearch)
12061 {
12063  enum interresult dir;
12064 
12065  fc.seg[0] = startpt;
12066  fc.seg[1] = endpt;
12067  fc.checkflipeligibility = 1;
12068 
12069  // The mainloop of the edge reocvery.
12070  while (1) { // Loop I
12071 
12072  // Search the edge from 'startpt'.
12073  point2tetorg(startpt, *searchtet);
12074  dir = finddirection(searchtet, endpt);
12075  if (dir == ACROSSVERT) {
12076  if (dest(*searchtet) == endpt) {
12077  return 1; // Edge is recovered.
12078  } else {
12079  if (sedge) {
12080  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
12081  } else {
12082  return 0;
12083  }
12084  }
12085  }
12086 
12087  // The edge is missing.
12088 
12089  // Try to remove the first intersecting face/edge.
12090  enextesymself(*searchtet); // Go to the opposite face.
12091  if (dir == ACROSSFACE) {
12092  if (checksubfaceflag) {
12093  if (issubface(*searchtet)) {
12094  if (sedge) {
12095  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
12096  } else {
12097  return 0; // Cannot flip a subface.
12098  }
12099  }
12100  }
12101  // Try to flip a crossing face.
12102  if (removefacebyflips(searchtet, &fc)) {
12103  continue;
12104  }
12105  } else if (dir == ACROSSEDGE) {
12106  if (checksubsegflag) {
12107  if (issubseg(*searchtet)) {
12108  if (sedge) {
12109  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
12110  } else {
12111  return 0; // Cannot flip a segment.
12112  }
12113  }
12114  }
12115  // Try to flip an intersecting edge.
12116  if (removeedgebyflips(searchtet, &fc) == 2) {
12117  continue;
12118  }
12119  }
12120 
12121  // The edge is missing.
12122 
12123  if (fullsearch) {
12124  // Try to flip one of the faces/edges which intersects the edge.
12125  triface neightet, spintet;
12126  point pa, pb, pc, pd;
12127  badface bakface;
12128  enum interresult dir1;
12129  int types[2], poss[4], pos = 0;
12130  int success = 0;
12131  int t1ver;
12132  int i, j;
12133 
12134  // Loop through the sequence of intersecting faces/edges from
12135  // 'startpt' to 'endpt'.
12136  point2tetorg(startpt, *searchtet);
12137  dir = finddirection(searchtet, endpt);
12138 
12139  // Go to the face/edge intersecting the searching edge.
12140  enextesymself(*searchtet); // Go to the opposite face.
12141  // This face/edge has been tried in previous step.
12142 
12143  while (1) { // Loop I-I
12144 
12145  // Find the next intersecting face/edge.
12146  fsymself(*searchtet);
12147  if (dir == ACROSSFACE) {
12148  neightet = *searchtet;
12149  j = (neightet.ver & 3); // j is the current face number.
12150  for (i = j + 1; i < j + 4; i++) {
12151  neightet.ver = (i % 4);
12152  pa = org(neightet);
12153  pb = dest(neightet);
12154  pc = apex(neightet);
12155  pd = oppo(neightet); // The above point.
12156  if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
12157  dir = (enum interresult) types[0];
12158  pos = poss[0];
12159  break;
12160  } else {
12161  dir = DISJOINT;
12162  pos = 0;
12163  }
12164  } // i
12165  // There must be an intersection face/edge.
12166  if (dir == DISJOINT) {
12167  terminatetetgen(this, 2);
12168  }
12169  } else if (dir == ACROSSEDGE) {
12170  while (1) { // Loop I-I-I
12171  // Check the two opposite faces (of the edge) in 'searchtet'.
12172  for (i = 0; i < 2; i++) {
12173  if (i == 0) {
12174  enextesym(*searchtet, neightet);
12175  } else {
12176  eprevesym(*searchtet, neightet);
12177  }
12178  pa = org(neightet);
12179  pb = dest(neightet);
12180  pc = apex(neightet);
12181  pd = oppo(neightet); // The above point.
12182  if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
12183  dir = (enum interresult) types[0];
12184  pos = poss[0];
12185  break; // for loop
12186  } else {
12187  dir = DISJOINT;
12188  pos = 0;
12189  }
12190  } // i
12191  if (dir != DISJOINT) {
12192  // Find an intersection face/edge.
12193  break; // Loop I-I-I
12194  }
12195  // No intersection. Rotate to the next tet at the edge.
12196  fnextself(*searchtet);
12197  } // while (1) // Loop I-I-I
12198  } else {
12199  terminatetetgen(this, 2); // Report a bug
12200  }
12201 
12202  // Adjust to the intersecting edge/vertex.
12203  for (i = 0; i < pos; i++) {
12204  enextself(neightet);
12205  }
12206 
12207  if (dir == SHAREVERT) {
12208  // Check if we have reached the 'endpt'.
12209  pd = org(neightet);
12210  if (pd == endpt) {
12211  // Failed to recover the edge.
12212  break; // Loop I-I
12213  } else {
12214  terminatetetgen(this, 2); // Report a bug
12215  }
12216  }
12217 
12218  // The next to be flipped face/edge.
12219  *searchtet = neightet;
12220 
12221  // Bakup this face (tetrahedron).
12222  bakface.forg = org(*searchtet);
12223  bakface.fdest = dest(*searchtet);
12224  bakface.fapex = apex(*searchtet);
12225  bakface.foppo = oppo(*searchtet);
12226 
12227  // Try to flip this intersecting face/edge.
12228  if (dir == ACROSSFACE) {
12229  if (checksubfaceflag) {
12230  if (issubface(*searchtet)) {
12231  if (sedge) {
12232  return report_selfint_edge(startpt,endpt,sedge,searchtet,dir);
12233  } else {
12234  return 0; // Cannot flip a subface.
12235  }
12236  }
12237  }
12238  if (removefacebyflips(searchtet, &fc)) {
12239  success = 1;
12240  break; // Loop I-I
12241  }
12242  } else if (dir == ACROSSEDGE) {
12243  if (checksubsegflag) {
12244  if (issubseg(*searchtet)) {
12245  if (sedge) {
12246  return report_selfint_edge(startpt,endpt,sedge,searchtet,dir);
12247  } else {
12248  return 0; // Cannot flip a segment.
12249  }
12250  }
12251  }
12252  if (removeedgebyflips(searchtet, &fc) == 2) {
12253  success = 1;
12254  break; // Loop I-I
12255  }
12256  } else if (dir == ACROSSVERT) {
12257  if (sedge) {
12258  //return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
12259  terminatetetgen(this, 2);
12260  } else {
12261  return 0;
12262  }
12263  } else {
12264  terminatetetgen(this, 2);
12265  }
12266 
12267  // The face/edge is not flipped.
12268  if ((searchtet->tet == NULL) ||
12269  (org(*searchtet) != bakface.forg) ||
12270  (dest(*searchtet) != bakface.fdest) ||
12271  (apex(*searchtet) != bakface.fapex) ||
12272  (oppo(*searchtet) != bakface.foppo)) {
12273  // 'searchtet' was flipped. We must restore it.
12274  point2tetorg(bakface.forg, *searchtet);
12275  dir1 = finddirection(searchtet, bakface.fdest);
12276  if (dir1 == ACROSSVERT) {
12277  if (dest(*searchtet) == bakface.fdest) {
12278  spintet = *searchtet;
12279  while (1) {
12280  if (apex(spintet) == bakface.fapex) {
12281  // Found the face.
12282  *searchtet = spintet;
12283  break;
12284  }
12285  fnextself(spintet);
12286  if (spintet.tet == searchtet->tet) {
12287  searchtet->tet = NULL;
12288  break; // Not find.
12289  }
12290  } // while (1)
12291  if (searchtet->tet != NULL) {
12292  if (oppo(*searchtet) != bakface.foppo) {
12293  fsymself(*searchtet);
12294  if (oppo(*searchtet) != bakface.foppo) {
12295  // The original (intersecting) tet has been flipped.
12296  searchtet->tet = NULL;
12297  break; // Not find.
12298  }
12299  }
12300  }
12301  } else {
12302  searchtet->tet = NULL; // Not find.
12303  }
12304  } else {
12305  searchtet->tet = NULL; // Not find.
12306  }
12307  if (searchtet->tet == NULL) {
12308  success = 0; // This face/edge has been destroyed.
12309  break; // Loop I-I
12310  }
12311  }
12312  } // while (1) // Loop I-I
12313 
12314  if (success) {
12315  // One of intersecting faces/edges is flipped.
12316  continue;
12317  }
12318 
12319  } // if (fullsearch)
12320 
12321  // The edge is missing.
12322  break; // Loop I
12323 
12324  } // while (1) // Loop I
12325 
12326  return 0;
12327 }
12328 
12330 // //
12331 // add_steinerpt_in_schoenhardtpoly() Insert a Steiner point in a Schoen- //
12332 // hardt polyhedron. //
12333 // //
12334 // 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
12335 // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)]. Moreover, //
12336 // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'. A special //
12337 // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b]. //
12338 // Such set of tets arises when we want to recover an edge from 'p0' to 'p_ //
12339 // (n-1)', and the number of tets at [a,b] can not be reduced by any flip. //
12340 // //
12342 
12344  int chkencflag)
12345 {
12346  triface worktet, *parytet;
12347  triface faketet1, faketet2;
12348  point pc, pd, steinerpt;
12349  insertvertexflags ivf;
12350  optparameters opm;
12351  REAL vcd[3], sampt[3], smtpt[3];
12352  REAL maxminvol = 0.0, minvol = 0.0, ori;
12353  int success, maxidx = 0;
12354  int it, i;
12355 
12356 
12357  pc = apex(abtets[0]); // pc = p0
12358  pd = oppo(abtets[n-1]); // pd = p_(n-1)
12359 
12360 
12361  // Find an optimial point in edge [c,d]. It is visible by all outer faces
12362  // of 'abtets', and it maxmizes the min volume.
12363 
12364  // initialize the list of 2n boundary faces.
12365  for (i = 0; i < n; i++) {
12366  edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
12367  cavetetlist->newindex((void **) &parytet);
12368  *parytet = worktet;
12369  eorgoppo(abtets[i], worktet); // [p_i+1,p_i,b]
12370  cavetetlist->newindex((void **) &parytet);
12371  *parytet = worktet;
12372  }
12373 
12374  int N = 100;
12375  REAL stepi = 0.01;
12376 
12377  // Search the point along the edge [c,d].
12378  for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
12379 
12380  // Sample N points in edge [c,d].
12381  for (it = 1; it < N; it++) {
12382  for (i = 0; i < 3; i++) {
12383  sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
12384  }
12385  for (i = 0; i < cavetetlist->objects; i++) {
12386  parytet = (triface *) fastlookup(cavetetlist, i);
12387  ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
12388  if (i == 0) {
12389  minvol = ori;
12390  } else {
12391  if (minvol > ori) minvol = ori;
12392  }
12393  } // i
12394  if (it == 1) {
12395  maxminvol = minvol;
12396  maxidx = it;
12397  } else {
12398  if (maxminvol < minvol) {
12399  maxminvol = minvol;
12400  maxidx = it;
12401  }
12402  }
12403  } // it
12404 
12405  if (maxminvol <= 0) {
12406  cavetetlist->restart();
12407  return 0;
12408  }
12409 
12410  for (i = 0; i < 3; i++) {
12411  smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
12412  }
12413 
12414  // Create two faked tets to hold the two non-existing boundary faces:
12415  // [d,c,a] and [c,d,b].
12416  maketetrahedron(&faketet1);
12417  setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
12418  cavetetlist->newindex((void **) &parytet);
12419  *parytet = faketet1;
12420  maketetrahedron(&faketet2);
12421  setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
12422  cavetetlist->newindex((void **) &parytet);
12423  *parytet = faketet2;
12424 
12425  // Point smooth options.
12426  opm.max_min_volume = 1;
12427  opm.numofsearchdirs = 20;
12428  opm.searchstep = 0.001;
12429  opm.maxiter = 100; // Limit the maximum iterations.
12430  opm.initval = 0.0; // Initial volume is zero.
12431 
12432  // Try to relocate the point into the inside of the polyhedron.
12433  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
12434 
12435  if (success) {
12436  while (opm.smthiter == 100) {
12437  // It was relocated and the prescribed maximum iteration reached.
12438  // Try to increase the search stepsize.
12439  opm.searchstep *= 10.0;
12440  //opm.maxiter = 100; // Limit the maximum iterations.
12441  opm.initval = opm.imprval;
12442  opm.smthiter = 0; // Init.
12443  smoothpoint(smtpt, cavetetlist, 1, &opm);
12444  }
12445  } // if (success)
12446 
12447  // Delete the two faked tets.
12448  tetrahedrondealloc(faketet1.tet);
12449  tetrahedrondealloc(faketet2.tet);
12450 
12451  cavetetlist->restart();
12452 
12453  if (!success) {
12454  return 0;
12455  }
12456 
12457 
12458  // Insert the Steiner point.
12459  makepoint(&steinerpt, FREEVOLVERTEX);
12460  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
12461 
12462  // Insert the created Steiner point.
12463  for (i = 0; i < n; i++) {
12464  infect(abtets[i]);
12465  caveoldtetlist->newindex((void **) &parytet);
12466  *parytet = abtets[i];
12467  }
12468  worktet = abtets[0]; // No need point location.
12469  ivf.iloc = (int) INSTAR;
12470  ivf.chkencflag = chkencflag;
12471  ivf.assignmeshsize = b->metric;
12472  if (ivf.assignmeshsize) {
12473  // Search the tet containing 'steinerpt' for size interpolation.
12474  locate(steinerpt, &(abtets[0]));
12475  worktet = abtets[0];
12476  }
12477 
12478  // Insert the new point into the tetrahedralization T.
12479  // Note that T is convex (nonconvex = 0).
12480  if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
12481  // The vertex has been inserted.
12482  st_volref_count++;
12483  if (steinerleft > 0) steinerleft--;
12484  return 1;
12485  } else {
12486  // Not inserted.
12487  pointdealloc(steinerpt);
12488  return 0;
12489  }
12490 }
12491 
12493 // //
12494 // add_steinerpt_in_segment() Add a Steiner point inside a segment. //
12495 // //
12497 
12498 int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
12499 {
12500  triface searchtet;
12501  face *paryseg, candseg;
12502  point startpt, endpt, pc, pd;
12504  enum interresult dir;
12505  REAL P[3], Q[3], tp, tq;
12506  REAL len, smlen = 0, split = 0, split_q = 0;
12507  int success=0;
12508  int i;
12509 
12510  startpt = sorg(*misseg);
12511  endpt = sdest(*misseg);
12512 
12513  fc.seg[0] = startpt;
12514  fc.seg[1] = endpt;
12515  fc.checkflipeligibility = 1;
12516  fc.collectencsegflag = 1;
12517 
12518  point2tetorg(startpt, searchtet);
12519  dir = finddirection(&searchtet, endpt);
12520  // Try to flip the first intersecting face/edge.
12521  enextesymself(searchtet); // Go to the opposite face.
12522 
12523  int bak_fliplinklevel = b->fliplinklevel;
12524  b->fliplinklevel = searchlevel;
12525 
12526  if (dir == ACROSSFACE) {
12527  // A face is intersected with the segment. Try to flip it.
12528  success = removefacebyflips(&searchtet, &fc);
12529  } else if (dir == ACROSSEDGE) {
12530  // An edge is intersected with the segment. Try to flip it.
12531  success = removeedgebyflips(&searchtet, &fc);
12532  }
12533 
12534  split = 0;
12535  for (i = 0; i < caveencseglist->objects; i++) {
12536  paryseg = (face *) fastlookup(caveencseglist, i);
12537  suninfect(*paryseg);
12538  // Calculate the shortest edge between the two lines.
12539  pc = sorg(*paryseg);
12540  pd = sdest(*paryseg);
12541  tp = tq = 0;
12542  if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
12543  // Does the shortest edge lie between the two segments?
12544  // Round tp and tq.
12545  if ((tp > 0) && (tq < 1)) {
12546  if (tp < 0.5) {
12547  if (tp < (b->epsilon * 1e+3)) tp = 0.0;
12548  } else {
12549  if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
12550  }
12551  }
12552  if ((tp <= 0) || (tp >= 1)) continue;
12553  if ((tq > 0) && (tq < 1)) {
12554  if (tq < 0.5) {
12555  if (tq < (b->epsilon * 1e+3)) tq = 0.0;
12556  } else {
12557  if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
12558  }
12559  }
12560  if ((tq <= 0) || (tq >= 1)) continue;
12561  // It is a valid shortest edge. Calculate its length.
12562  len = distance(P, Q);
12563  if (split == 0) {
12564  smlen = len;
12565  split = tp;
12566  split_q = tq;
12567  candseg = *paryseg;
12568  } else {
12569  if (len < smlen) {
12570  smlen = len;
12571  split = tp;
12572  split_q = tq;
12573  candseg = *paryseg;
12574  }
12575  }
12576  }
12577  }
12578 
12580  b->fliplinklevel = bak_fliplinklevel;
12581 
12582  if (split == 0) {
12583  // Found no crossing segment.
12584  return 0;
12585  }
12586 
12587  face splitsh;
12588  face splitseg;
12589  point steinerpt, *parypt;
12590  insertvertexflags ivf;
12591 
12592  if (b->addsteiner_algo == 1) {
12593  // Split the segment at the closest point to a near segment.
12594  makepoint(&steinerpt, FREESEGVERTEX);
12595  for (i = 0; i < 3; i++) {
12596  steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
12597  }
12598  } else { // b->addsteiner_algo == 2
12599  for (i = 0; i < 3; i++) {
12600  P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
12601  }
12602  pc = sorg(candseg);
12603  pd = sdest(candseg);
12604  for (i = 0; i < 3; i++) {
12605  Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
12606  }
12607  makepoint(&steinerpt, FREEVOLVERTEX);
12608  for (i = 0; i < 3; i++) {
12609  steinerpt[i] = 0.5 * (P[i] + Q[i]);
12610  }
12611  }
12612 
12613  // We need to locate the point. Start searching from 'searchtet'.
12614  if (split < 0.5) {
12615  point2tetorg(startpt, searchtet);
12616  } else {
12617  point2tetorg(endpt, searchtet);
12618  }
12619  if (b->addsteiner_algo == 1) {
12620  splitseg = *misseg;
12621  spivot(*misseg, splitsh);
12622  } else {
12623  splitsh.sh = NULL;
12624  splitseg.sh = NULL;
12625  }
12626  ivf.iloc = (int) OUTSIDE;
12627  ivf.bowywat = 1;
12628  ivf.lawson = 0;
12629  ivf.rejflag = 0;
12630  ivf.chkencflag = 0;
12631  ivf.sloc = (int) ONEDGE;
12632  ivf.sbowywat = 1;
12633  ivf.splitbdflag = 0;
12634  ivf.validflag = 1;
12635  ivf.respectbdflag = 1;
12636  ivf.assignmeshsize = b->metric;
12637 
12638  if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
12639  pointdealloc(steinerpt);
12640  return 0;
12641  }
12642 
12643  if (b->addsteiner_algo == 1) {
12644  // Save this Steiner point (for removal).
12645  // Re-use the array 'subvertstack'.
12646  subvertstack->newindex((void **) &parypt);
12647  *parypt = steinerpt;
12648  st_segref_count++;
12649  } else { // b->addsteiner_algo == 2
12650  // Queue the segment for recovery.
12651  subsegstack->newindex((void **) &paryseg);
12652  *paryseg = *misseg;
12653  st_volref_count++;
12654  }
12655  if (steinerleft > 0) steinerleft--;
12656  if (!success){
12657  // error
12658  }
12659 
12660  return 1;
12661 }
12662 
12664 // //
12665 // addsteiner4recoversegment() Add a Steiner point for recovering a seg. //
12666 // //
12668 
12669 int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
12670 {
12671  triface *abtets, searchtet, spintet;
12672  face splitsh;
12673  face *paryseg;
12674  point startpt, endpt;
12675  point pa, pb, pd, steinerpt, *parypt;
12676  enum interresult dir;
12677  insertvertexflags ivf;
12678  int types[2], poss[4];
12679  int n, endi, success;
12680  int t1ver;
12681  int i;
12682 
12683  startpt = sorg(*misseg);
12684  if (pointtype(startpt) == FREESEGVERTEX) {
12685  sesymself(*misseg);
12686  startpt = sorg(*misseg);
12687  }
12688  endpt = sdest(*misseg);
12689 
12690  // Try to recover the edge by adding Steiner points.
12691  point2tetorg(startpt, searchtet);
12692  dir = finddirection(&searchtet, endpt);
12693  enextself(searchtet);
12694 
12695  if (dir == ACROSSFACE) {
12696  // The segment is crossing at least 3 faces. Find the common edge of
12697  // the first 3 crossing faces.
12698  esymself(searchtet);
12699  fsym(searchtet, spintet);
12700  pd = oppo(spintet);
12701  for (i = 0; i < 3; i++) {
12702  pa = org(spintet);
12703  pb = dest(spintet);
12704  if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
12705  break; // Found the edge.
12706  }
12707  enextself(spintet);
12708  eprevself(searchtet);
12709  }
12710  esymself(searchtet);
12711  }
12712 
12713  spintet = searchtet;
12714  n = 0; endi = -1;
12715  while (1) {
12716  // Check if the endpt appears in the star.
12717  if (apex(spintet) == endpt) {
12718  endi = n; // Remember the position of endpt.
12719  }
12720  n++; // Count a tet in the star.
12721  fnextself(spintet);
12722  if (spintet.tet == searchtet.tet) break;
12723  }
12724 
12725  if (endi > 0) {
12726  // endpt is also in the edge star
12727  // Get all tets in the edge star.
12728  abtets = new triface[n];
12729  spintet = searchtet;
12730  for (i = 0; i < n; i++) {
12731  abtets[i] = spintet;
12732  fnextself(spintet);
12733  }
12734 
12735  success = 0;
12736 
12737  if (dir == ACROSSFACE) {
12738  // Find a Steiner points inside the polyhedron.
12739  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
12740  success = 1;
12741  }
12742  } else if (dir == ACROSSEDGE) {
12743  // PLC check.
12744  if (issubseg(searchtet)) {
12745  terminatetetgen(this, 2);
12746  }
12747  if (n > 4) {
12748  // In this case, 'abtets' is separated by the plane (containing the
12749  // two intersecting edges) into two parts, P1 and P2, where P1
12750  // consists of 'endi' tets: abtets[0], abtets[1], ...,
12751  // abtets[endi-1], and P2 consists of 'n - endi' tets:
12752  // abtets[endi], abtets[endi+1], abtets[n-1].
12753  if (endi > 2) { // P1
12754  // There are at least 3 tets in the first part.
12755  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
12756  success++;
12757  }
12758  }
12759  if ((n - endi) > 2) { // P2
12760  // There are at least 3 tets in the first part.
12761  if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
12762  success++;
12763  }
12764  }
12765  } else {
12766  // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
12767  // However, there will be invalid tets (either zero or negtive
12768  // volume). Otherwise, [c,d] should already be recovered by the
12769  // recoveredge() function.
12770  terminatetetgen(this, 2);
12771  }
12772  } else {
12773  terminatetetgen(this, 2);
12774  }
12775 
12776  delete [] abtets;
12777 
12778  if (success) {
12779  // Add the missing segment back to the recovering list.
12780  subsegstack->newindex((void **) &paryseg);
12781  *paryseg = *misseg;
12782  return 1;
12783  }
12784  } // if (endi > 0)
12785 
12786  if (!splitsegflag) {
12787  return 0;
12788  }
12789 
12790  if (b->verbose > 2) {
12791  printf(" Splitting segment (%d, %d)\n", pointmark(startpt),
12792  pointmark(endpt));
12793  }
12794  steinerpt = NULL;
12795 
12796  if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
12797  if (add_steinerpt_in_segment(misseg, 3)) {
12798  return 1;
12799  }
12800  sesymself(*misseg);
12801  if (add_steinerpt_in_segment(misseg, 3)) {
12802  return 1;
12803  }
12804  sesymself(*misseg);
12805  }
12806 
12807 
12808 
12809 
12810  if (steinerpt == NULL) {
12811  // Split the segment at its midpoint.
12812  makepoint(&steinerpt, FREESEGVERTEX);
12813  for (i = 0; i < 3; i++) {
12814  steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
12815  }
12816 
12817  // We need to locate the point.
12818  spivot(*misseg, splitsh);
12819  ivf.iloc = (int) OUTSIDE;
12820  ivf.bowywat = 1;
12821  ivf.lawson = 0;
12822  ivf.rejflag = 0;
12823  ivf.chkencflag = 0;
12824  ivf.sloc = (int) ONEDGE;
12825  ivf.sbowywat = 1;
12826  ivf.splitbdflag = 0;
12827  ivf.validflag = 1;
12828  ivf.respectbdflag = 1;
12829  ivf.assignmeshsize = b->metric;
12830  if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
12831  terminatetetgen(this, 2);
12832  }
12833  } // if (endi > 0)
12834 
12835  // Save this Steiner point (for removal).
12836  // Re-use the array 'subvertstack'.
12837  subvertstack->newindex((void **) &parypt);
12838  *parypt = steinerpt;
12839 
12840  st_segref_count++;
12841  if (steinerleft > 0) steinerleft--;
12842 
12843  return 1;
12844 }
12845 
12847 // //
12848 // recoversegments() Recover all segments. //
12849 // //
12850 // All segments need to be recovered are in 'subsegstack'. //
12851 // //
12852 // This routine first tries to recover each segment by only using flips. If //
12853 // no flip is possible, and the flag 'steinerflag' is set, it then tries to //
12854 // insert Steiner points near or in the segment. //
12855 // //
12857 
12858 int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
12859  int steinerflag)
12860 {
12861  triface searchtet, spintet;
12862  face sseg, *paryseg;
12863  point startpt, endpt;
12864  int success;
12865  int t1ver;
12866 
12867  long bak_inpoly_count = st_volref_count;
12868  long bak_segref_count = st_segref_count;
12869 
12870  if (b->verbose > 1) {
12871  printf(" Recover segments [%s level = %2d] #: %ld.\n",
12872  (b->fliplinklevel > 0) ? "fixed" : "auto",
12874  subsegstack->objects);
12875  }
12876 
12877  // Loop until 'subsegstack' is empty.
12878  while (subsegstack->objects > 0l) {
12879  // seglist is used as a stack.
12880  subsegstack->objects--;
12881  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
12882  sseg = *paryseg;
12883 
12884  // Check if this segment has been recovered.
12885  sstpivot1(sseg, searchtet);
12886  if (searchtet.tet != NULL) {
12887  continue; // Not a missing segment.
12888  }
12889 
12890  startpt = sorg(sseg);
12891  endpt = sdest(sseg);
12892 
12893  if (b->verbose > 2) {
12894  printf(" Recover segment (%d, %d).\n", pointmark(startpt),
12895  pointmark(endpt));
12896  }
12897 
12898  success = 0;
12899 
12900  if (recoveredgebyflips(startpt, endpt, &sseg, &searchtet, 0)) {
12901  success = 1;
12902  } else {
12903  // Try to recover it from the other direction.
12904  if (recoveredgebyflips(endpt, startpt, &sseg, &searchtet, 0)) {
12905  success = 1;
12906  }
12907  }
12908 
12909  if (!success && fullsearch) {
12910  if (recoveredgebyflips(startpt, endpt, &sseg, &searchtet, fullsearch)) {
12911  success = 1;
12912  }
12913  }
12914 
12915  if (success) {
12916  // Segment is recovered. Insert it.
12917  // Let the segment remember an adjacent tet.
12918  sstbond1(sseg, searchtet);
12919  // Bond the segment to all tets containing it.
12920  spintet = searchtet;
12921  do {
12922  tssbond1(spintet, sseg);
12923  fnextself(spintet);
12924  } while (spintet.tet != searchtet.tet);
12925  } else {
12926  if (steinerflag > 0) {
12927  // Try to recover the segment but do not split it.
12928  if (addsteiner4recoversegment(&sseg, 0)) {
12929  success = 1;
12930  }
12931  if (!success && (steinerflag > 1)) {
12932  // Split the segment.
12933  addsteiner4recoversegment(&sseg, 1);
12934  success = 1;
12935  }
12936  }
12937  if (!success) {
12938  if (misseglist != NULL) {
12939  // Save this segment.
12940  misseglist->newindex((void **) &paryseg);
12941  *paryseg = sseg;
12942  }
12943  }
12944  }
12945 
12946  } // while (subsegstack->objects > 0l)
12947 
12948  if (steinerflag) {
12949  if (b->verbose > 1) {
12950  // Report the number of added Steiner points.
12951  if (st_volref_count > bak_inpoly_count) {
12952  printf(" Add %ld Steiner points in volume.\n",
12953  st_volref_count - bak_inpoly_count);
12954  }
12955  if (st_segref_count > bak_segref_count) {
12956  printf(" Add %ld Steiner points in segments.\n",
12957  st_segref_count - bak_segref_count);
12958  }
12959  }
12960  }
12961 
12962  return 0;
12963 }
12964 
12966 // //
12967 // recoverfacebyflips() Recover a face by flips. //
12968 // //
12969 // 'pa', 'pb', and 'pc' are the three vertices of this face. This routine //
12970 // tries to recover it in the tetrahedral mesh. It is assumed that the three //
12971 // edges, i.e., pa->pb, pb->pc, and pc->pa all exist. //
12972 // //
12973 // If the face is recovered, it is returned by 'searchtet'. //
12974 // //
12975 // If 'searchsh' is not NULL, it is a subface to be recovered. Its vertices //
12976 // must be pa, pb, and pc. It is mainly used to check self-intersections. //
12977 // Another use of this subface is to split it when a Steiner point is found //
12978 // inside this subface. //
12979 // //
12981 
12983  face *searchsh, triface* searchtet)
12984 {
12985  triface spintet, flipedge;
12986  point pd, pe;
12988  int types[2], poss[4], intflag;
12989  int success;
12990  int t1ver;
12991  int i, j;
12992 
12993 
12994  fc.fac[0] = pa;
12995  fc.fac[1] = pb;
12996  fc.fac[2] = pc;
12997  fc.checkflipeligibility = 1;
12998  success = 0;
12999 
13000  for (i = 0; i < 3 && !success; i++) {
13001  while (1) {
13002  // Get a tet containing the edge [a,b].
13003  point2tetorg(fc.fac[i], *searchtet);
13004  finddirection(searchtet, fc.fac[(i+1)%3]);
13005  // Search the face [a,b,c]
13006  spintet = *searchtet;
13007  while (1) {
13008  if (apex(spintet) == fc.fac[(i+2)%3]) {
13009  // Found the face.
13010  *searchtet = spintet;
13011  // Return the face [a,b,c].
13012  for (j = i; j > 0; j--) {
13013  eprevself(*searchtet);
13014  }
13015  success = 1;
13016  break;
13017  }
13018  fnextself(spintet);
13019  if (spintet.tet == searchtet->tet) break;
13020  } // while (1)
13021  if (success) break;
13022  // The face is missing. Try to recover it.
13023  flipedge.tet = NULL;
13024  // Find a crossing edge of this face.
13025  spintet = *searchtet;
13026  while (1) {
13027  pd = apex(spintet);
13028  pe = oppo(spintet);
13029  if ((pd != dummypoint) && (pe != dummypoint)) {
13030  // Check if [d,e] intersects [a,b,c]
13031  intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
13032  if (intflag > 0) {
13033  // By the assumption that all edges of the face exist, they can
13034  // only intersect at a single point.
13035  if (intflag == 2) {
13036  // Go to the edge [d,e].
13037  edestoppo(spintet, flipedge); // [d,e,a,b]
13038  if (searchsh != NULL) {
13039  // Check the intersection type.
13040  if ((types[0] == (int) ACROSSFACE) ||
13041  (types[0] == (int) ACROSSEDGE)) {
13042  // Check if [e,d] is a segment.
13043  if (issubseg(flipedge)) {
13044  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
13045  intflag, types, poss);
13046  } else {
13047  // Check if [e,d] is an edge of a subface.
13048  triface chkface = flipedge;
13049  while (1) {
13050  if (issubface(chkface)) break;
13051  fsymself(chkface);
13052  if (chkface.tet == flipedge.tet) break;
13053  }
13054  if (issubface(chkface)) {
13055  // Two subfaces are intersecting.
13056  return report_selfint_face(pa, pb, pc,searchsh,&chkface,
13057  intflag, types, poss);
13058  }
13059  }
13060  } else if (types[0] == TOUCHFACE) {
13061  // This is possible when a Steiner point was added on it.
13062  point touchpt, *parypt;
13063  if (poss[1] == 0) {
13064  touchpt = pd; // pd is a coplanar vertex.
13065  } else {
13066  touchpt = pe; // pe is a coplanar vertex.
13067  }
13068  if (pointtype(touchpt) == FREEVOLVERTEX) {
13069  // A volume Steiner point was added in this subface.
13070  // Split this subface by this point.
13071  face checksh, *parysh;
13072  int siloc = (int) ONFACE;
13073  int sbowat = 0; // Only split this subface. A 1-to-3 flip.
13074  setpointtype(touchpt, FREEFACETVERTEX);
13075  sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
13076  st_volref_count--;
13077  st_facref_count++;
13078  // Queue this vertex for removal.
13079  subvertstack->newindex((void **) &parypt);
13080  *parypt = touchpt;
13081  // Queue new subfaces for recovery.
13082  // Put all new subfaces into stack for recovery.
13083  for (i = 0; i < caveshbdlist->objects; i++) {
13084  // Get an old subface at edge [a, b].
13085  parysh = (face *) fastlookup(caveshbdlist, i);
13086  spivot(*parysh, checksh); // The new subface [a, b, p].
13087  // Do not recover a deleted new face (degenerated).
13088  if (checksh.sh[3] != NULL) {
13089  subfacstack->newindex((void **) &parysh);
13090  *parysh = checksh;
13091  }
13092  }
13093  // Delete the old subfaces in sC(p).
13094  for (i = 0; i < caveshlist->objects; i++) {
13095  parysh = (face *) fastlookup(caveshlist, i);
13096  shellfacedealloc(subfaces, parysh->sh);
13097  }
13098  // Clear working lists.
13099  caveshlist->restart();
13100  caveshbdlist->restart();
13102  // We can return this function.
13103  searchsh->sh = NULL; // It has been split.
13104  return 1;
13105  } else {
13106  // Other cases may be due to a bug or a PLC error.
13107  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
13108  intflag, types, poss);
13109  }
13110  } else {
13111  // The other intersection types: ACROSSVERT, TOUCHEDGE,
13112  // SHAREVERTEX should not be possible or due to a PLC error.
13113  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
13114  intflag, types, poss);
13115  }
13116  } // if (searchsh != NULL)
13117  } else { // intflag == 4. Coplanar case.
13118  terminatetetgen(this, 2);
13119  }
13120  break;
13121  } // if (intflag > 0)
13122  }
13123  fnextself(spintet);
13124  if (spintet.tet == searchtet->tet) {
13125  terminatetetgen(this, 2);
13126  }
13127  } // while (1)
13128  // Try to flip the edge [d,e].
13129  if (removeedgebyflips(&flipedge, &fc) == 2) {
13130  // A crossing edge is removed.
13131  continue;
13132  }
13133  break;
13134  } // while (1)
13135  } // i
13136 
13137  return success;
13138 }
13139 
13141 // //
13142 // recoversubfaces() Recover all subfaces. //
13143 // //
13145 
13146 int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
13147 {
13148  triface searchtet, neightet, spintet;
13149  face searchsh, neighsh, neineish, *parysh;
13150  face bdsegs[3];
13151  point startpt, endpt, apexpt, *parypt;
13152  point steinerpt;
13153  insertvertexflags ivf;
13154  int success;
13155  int t1ver;
13156  int i, j;
13157 
13158  if (b->verbose > 1) {
13159  printf(" Recover subfaces [%s level = %2d] #: %ld.\n",
13160  (b->fliplinklevel > 0) ? "fixed" : "auto",
13162  subfacstack->objects);
13163  }
13164 
13165  // Loop until 'subfacstack' is empty.
13166  while (subfacstack->objects > 0l) {
13167 
13168  subfacstack->objects--;
13169  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
13170  searchsh = *parysh;
13171 
13172  if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
13173 
13174  stpivot(searchsh, neightet);
13175  if (neightet.tet != NULL) continue; // Skip a recovered subface.
13176 
13177 
13178  if (b->verbose > 2) {
13179  printf(" Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
13180  pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
13181  }
13182 
13183  // The three edges of the face need to be existed first.
13184  for (i = 0; i < 3; i++) {
13185  sspivot(searchsh, bdsegs[i]);
13186  if (bdsegs[i].sh != NULL) {
13187  // The segment must exist.
13188  sstpivot1(bdsegs[i], searchtet);
13189  if (searchtet.tet == NULL) {
13190  terminatetetgen(this, 2);
13191  }
13192  } else {
13193  // This edge is not a segment (due to a Steiner point).
13194  // Check whether it exists or not.
13195  success = 0;
13196  startpt = sorg(searchsh);
13197  endpt = sdest(searchsh);
13198  point2tetorg(startpt, searchtet);
13199  finddirection(&searchtet, endpt);
13200  if (dest(searchtet) == endpt) {
13201  success = 1;
13202  } else {
13203  // The edge is missing. Try to recover it.
13204  if (recoveredgebyflips(startpt, endpt, &searchsh, &searchtet, 0)) {
13205  success = 1;
13206  } else {
13207  if (recoveredgebyflips(endpt, startpt, &searchsh, &searchtet, 0)) {
13208  success = 1;
13209  }
13210  }
13211  }
13212  if (success) {
13213  // Insert a temporary segment to protect this edge.
13214  makeshellface(subsegs, &(bdsegs[i]));
13215  setshvertices(bdsegs[i], startpt, endpt, NULL);
13216  smarktest2(bdsegs[i]); // It's a temporary segment.
13217  // Insert this segment into surface mesh.
13218  ssbond(searchsh, bdsegs[i]);
13219  spivot(searchsh, neighsh);
13220  if (neighsh.sh != NULL) {
13221  ssbond(neighsh, bdsegs[i]);
13222  }
13223  // Insert this segment into tetrahedralization.
13224  sstbond1(bdsegs[i], searchtet);
13225  // Bond the segment to all tets containing it.
13226  spintet = searchtet;
13227  do {
13228  tssbond1(spintet, bdsegs[i]);
13229  fnextself(spintet);
13230  } while (spintet.tet != searchtet.tet);
13231  } else {
13232  // An edge of this subface is missing. Can't recover this subface.
13233  // Delete any temporary segment that has been created.
13234  for (j = (i - 1); j >= 0; j--) {
13235  if (smarktest2ed(bdsegs[j])) {
13236  spivot(bdsegs[j], neineish);
13237  ssdissolve(neineish);
13238  spivot(neineish, neighsh);
13239  if (neighsh.sh != NULL) {
13240  ssdissolve(neighsh);
13241  }
13242  sstpivot1(bdsegs[j], searchtet);
13243  spintet = searchtet;
13244  while (1) {
13245  tssdissolve1(spintet);
13246  fnextself(spintet);
13247  if (spintet.tet == searchtet.tet) break;
13248  }
13249  shellfacedealloc(subsegs, bdsegs[j].sh);
13250  }
13251  } // j
13252  if (steinerflag) {
13253  // Add a Steiner point at the midpoint of this edge.
13254  if (b->verbose > 2) {
13255  printf(" Add a Steiner point in subedge (%d, %d).\n",
13256  pointmark(startpt), pointmark(endpt));
13257  }
13258  makepoint(&steinerpt, FREEFACETVERTEX);
13259  for (j = 0; j < 3; j++) {
13260  steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
13261  }
13262 
13263  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
13264  ivf.iloc = (int) OUTSIDE; // Need point location.
13265  ivf.bowywat = 1;
13266  ivf.lawson = 0;
13267  ivf.rejflag = 0;
13268  ivf.chkencflag = 0;
13269  ivf.sloc = (int) ONEDGE;
13270  ivf.sbowywat = 1; // Allow flips in facet.
13271  ivf.splitbdflag = 0;
13272  ivf.validflag = 1;
13273  ivf.respectbdflag = 1;
13274  ivf.assignmeshsize = b->metric;
13275  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
13276  terminatetetgen(this, 2);
13277  }
13278  // Save this Steiner point (for removal).
13279  // Re-use the array 'subvertstack'.
13280  subvertstack->newindex((void **) &parypt);
13281  *parypt = steinerpt;
13282 
13283  st_facref_count++;
13284  if (steinerleft > 0) steinerleft--;
13285  } // if (steinerflag)
13286  break;
13287  }
13288  }
13289  senextself(searchsh);
13290  } // i
13291 
13292  if (i == 3) {
13293  // Recover the subface.
13294  startpt = sorg(searchsh);
13295  endpt = sdest(searchsh);
13296  apexpt = sapex(searchsh);
13297 
13298  success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
13299 
13300  // Delete any temporary segment that has been created.
13301  for (j = 0; j < 3; j++) {
13302  if (smarktest2ed(bdsegs[j])) {
13303  spivot(bdsegs[j], neineish);
13304  ssdissolve(neineish);
13305  spivot(neineish, neighsh);
13306  if (neighsh.sh != NULL) {
13307  ssdissolve(neighsh);
13308  }
13309  sstpivot1(bdsegs[j], neightet);
13310  spintet = neightet;
13311  while (1) {
13312  tssdissolve1(spintet);
13313  fnextself(spintet);
13314  if (spintet.tet == neightet.tet) break;
13315  }
13316  shellfacedealloc(subsegs, bdsegs[j].sh);
13317  }
13318  } // j
13319 
13320  if (success) {
13321  if (searchsh.sh != NULL) {
13322  // Face is recovered. Insert it.
13323  tsbond(searchtet, searchsh);
13324  fsymself(searchtet);
13325  sesymself(searchsh);
13326  tsbond(searchtet, searchsh);
13327  }
13328  } else {
13329  if (steinerflag) {
13330  // Add a Steiner point at the barycenter of this subface.
13331  if (b->verbose > 2) {
13332  printf(" Add a Steiner point in subface (%d, %d, %d).\n",
13333  pointmark(startpt), pointmark(endpt), pointmark(apexpt));
13334  }
13335  makepoint(&steinerpt, FREEFACETVERTEX);
13336  for (j = 0; j < 3; j++) {
13337  steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
13338  }
13339 
13340  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
13341  ivf.iloc = (int) OUTSIDE; // Need point location.
13342  ivf.bowywat = 1;
13343  ivf.lawson = 0;
13344  ivf.rejflag = 0;
13345  ivf.chkencflag = 0;
13346  ivf.sloc = (int) ONFACE;
13347  ivf.sbowywat = 1; // Allow flips in facet.
13348  ivf.splitbdflag = 0;
13349  ivf.validflag = 1;
13350  ivf.respectbdflag = 1;
13351  ivf.assignmeshsize = b->metric;
13352  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
13353  terminatetetgen(this, 2);
13354  }
13355  // Save this Steiner point (for removal).
13356  // Re-use the array 'subvertstack'.
13357  subvertstack->newindex((void **) &parypt);
13358  *parypt = steinerpt;
13359 
13360  st_facref_count++;
13361  if (steinerleft > 0) steinerleft--;
13362  } // if (steinerflag)
13363  }
13364  } else {
13365  success = 0;
13366  }
13367 
13368  if (!success) {
13369  if (misshlist != NULL) {
13370  // Save this subface.
13371  misshlist->newindex((void **) &parysh);
13372  *parysh = searchsh;
13373  }
13374  }
13375 
13376  } // while (subfacstack->objects > 0l)
13377 
13378  return 0;
13379 }
13380 
13382 // //
13383 // getvertexstar() Return the star of a vertex. //
13384 // //
13385 // If the flag 'fullstar' is set, return the complete star of this vertex. //
13386 // Otherwise, only a part of the star which is bounded by facets is returned.//
13387 // //
13388 // 'tetlist' returns the list of tets in the star of the vertex 'searchpt'. //
13389 // Every tet in 'tetlist' is at the face opposing to 'searchpt'. //
13390 // //
13391 // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
13392 // //
13393 // 'shlist' returns the list of subfaces in the star. Each subface must face //
13394 // to the interior of this star. //
13395 // //
13397 
13398 int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
13399  arraypool* vertlist, arraypool* shlist)
13400 {
13401  triface searchtet, neightet, *parytet;
13402  face checksh, *parysh;
13403  point pt, *parypt;
13404  int collectflag;
13405  int t1ver;
13406  int i, j;
13407 
13408  point2tetorg(searchpt, searchtet);
13409 
13410  // Go to the opposite face (the link face) of the vertex.
13411  enextesymself(searchtet);
13412  //assert(oppo(searchtet) == searchpt);
13413  infect(searchtet); // Collect this tet (link face).
13414  tetlist->newindex((void **) &parytet);
13415  *parytet = searchtet;
13416  if (vertlist != NULL) {
13417  // Collect three (link) vertices.
13418  j = (searchtet.ver & 3); // The current vertex index.
13419  for (i = 1; i < 4; i++) {
13420  pt = (point) searchtet.tet[4 + ((j + i) % 4)];
13421  pinfect(pt);
13422  vertlist->newindex((void **) &parypt);
13423  *parypt = pt;
13424  }
13425  }
13426 
13427  collectflag = 1;
13428  esym(searchtet, neightet);
13429  if (issubface(neightet)) {
13430  if (shlist != NULL) {
13431  tspivot(neightet, checksh);
13432  if (!sinfected(checksh)) {
13433  // Collect this subface (link edge).
13434  sinfected(checksh);
13435  shlist->newindex((void **) &parysh);
13436  *parysh = checksh;
13437  }
13438  }
13439  if (!fullstar) {
13440  collectflag = 0;
13441  }
13442  }
13443  if (collectflag) {
13444  fsymself(neightet); // Goto the adj tet of this face.
13445  esymself(neightet); // Goto the oppo face of this vertex.
13446  // assert(oppo(neightet) == searchpt);
13447  infect(neightet); // Collect this tet (link face).
13448  tetlist->newindex((void **) &parytet);
13449  *parytet = neightet;
13450  if (vertlist != NULL) {
13451  // Collect its apex.
13452  pt = apex(neightet);
13453  pinfect(pt);
13454  vertlist->newindex((void **) &parypt);
13455  *parypt = pt;
13456  }
13457  } // if (collectflag)
13458 
13459  // Continue to collect all tets in the star.
13460  for (i = 0; i < tetlist->objects; i++) {
13461  searchtet = * (triface *) fastlookup(tetlist, i);
13462  // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
13463  // tet at the current edge is already collected.
13464  // Check the neighbors at the other two edges of this face.
13465  for (j = 0; j < 2; j++) {
13466  collectflag = 1;
13467  enextself(searchtet);
13468  esym(searchtet, neightet);
13469  if (issubface(neightet)) {
13470  if (shlist != NULL) {
13471  tspivot(neightet, checksh);
13472  if (!sinfected(checksh)) {
13473  // Collect this subface (link edge).
13474  sinfected(checksh);
13475  shlist->newindex((void **) &parysh);
13476  *parysh = checksh;
13477  }
13478  }
13479  if (!fullstar) {
13480  collectflag = 0;
13481  }
13482  }
13483  if (collectflag) {
13484  fsymself(neightet);
13485  if (!infected(neightet)) {
13486  esymself(neightet); // Go to the face opposite to 'searchpt'.
13487  infect(neightet);
13488  tetlist->newindex((void **) &parytet);
13489  *parytet = neightet;
13490  if (vertlist != NULL) {
13491  // Check if a vertex is collected.
13492  pt = apex(neightet);
13493  if (!pinfected(pt)) {
13494  pinfect(pt);
13495  vertlist->newindex((void **) &parypt);
13496  *parypt = pt;
13497  }
13498  }
13499  } // if (!infected(neightet))
13500  } // if (collectflag)
13501  } // j
13502  } // i
13503 
13504 
13505  // Uninfect the list of tets and vertices.
13506  for (i = 0; i < tetlist->objects; i++) {
13507  parytet = (triface *) fastlookup(tetlist, i);
13508  uninfect(*parytet);
13509  }
13510 
13511  if (vertlist != NULL) {
13512  for (i = 0; i < vertlist->objects; i++) {
13513  parypt = (point *) fastlookup(vertlist, i);
13514  puninfect(*parypt);
13515  }
13516  }
13517 
13518  if (shlist != NULL) {
13519  for (i = 0; i < shlist->objects; i++) {
13520  parysh = (face *) fastlookup(shlist, i);
13521  suninfect(*parysh);
13522  }
13523  }
13524 
13525  return (int) tetlist->objects;
13526 }
13527 
13529 // //
13530 // getedge() Get a tetrahedron having the two endpoints. //
13531 // //
13532 // The method here is to search the second vertex in the link faces of the //
13533 // first vertex. The global array 'cavetetlist' is re-used for searching. //
13534 // //
13535 // This function is used for the case when the mesh is non-convex. Otherwise,//
13536 // the function finddirection() should be faster than this. //
13537 // //
13539 
13541 {
13542  triface searchtet, neightet, *parytet;
13543  point pt;
13544  int done;
13545  int i, j;
13546 
13547  if (b->verbose > 2) {
13548  printf(" Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
13549  }
13550 
13551  // Quickly check if 'tedge' is just this edge.
13552  if (!isdeadtet(*tedge)) {
13553  if (org(*tedge) == e1) {
13554  if (dest(*tedge) == e2) {
13555  return 1;
13556  }
13557  } else if (org(*tedge) == e2) {
13558  if (dest(*tedge) == e1) {
13559  esymself(*tedge);
13560  return 1;
13561  }
13562  }
13563  }
13564 
13565  // Search for the edge [e1, e2].
13566  point2tetorg(e1, *tedge);
13567  finddirection(tedge, e2);
13568  if (dest(*tedge) == e2) {
13569  return 1;
13570  } else {
13571  // Search for the edge [e2, e1].
13572  point2tetorg(e2, *tedge);
13573  finddirection(tedge, e1);
13574  if (dest(*tedge) == e1) {
13575  esymself(*tedge);
13576  return 1;
13577  }
13578  }
13579 
13580 
13581  // Go to the link face of e1.
13582  point2tetorg(e1, searchtet);
13583  enextesymself(searchtet);
13584  arraypool *tetlist = cavebdrylist;
13585 
13586  // Search e2.
13587  for (i = 0; i < 3; i++) {
13588  pt = apex(searchtet);
13589  if (pt == e2) {
13590  // Found. 'searchtet' is [#,#,e2,e1].
13591  eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
13592  return 1;
13593  }
13594  enextself(searchtet);
13595  }
13596 
13597  // Get the adjacent link face at 'searchtet'.
13598  fnext(searchtet, neightet);
13599  esymself(neightet);
13600  // assert(oppo(neightet) == e1);
13601  pt = apex(neightet);
13602  if (pt == e2) {
13603  // Found. 'neightet' is [#,#,e2,e1].
13604  eorgoppo(neightet, *tedge); // [e1,e2,#,#].
13605  return 1;
13606  }
13607 
13608  // Continue searching in the link face of e1.
13609  infect(searchtet);
13610  tetlist->newindex((void **) &parytet);
13611  *parytet = searchtet;
13612  infect(neightet);
13613  tetlist->newindex((void **) &parytet);
13614  *parytet = neightet;
13615 
13616  done = 0;
13617 
13618  for (i = 0; (i < tetlist->objects) && !done; i++) {
13619  parytet = (triface *) fastlookup(tetlist, i);
13620  searchtet = *parytet;
13621  for (j = 0; (j < 2) && !done; j++) {
13622  enextself(searchtet);
13623  fnext(searchtet, neightet);
13624  if (!infected(neightet)) {
13625  esymself(neightet);
13626  pt = apex(neightet);
13627  if (pt == e2) {
13628  // Found. 'neightet' is [#,#,e2,e1].
13629  eorgoppo(neightet, *tedge);
13630  done = 1;
13631  } else {
13632  infect(neightet);
13633  tetlist->newindex((void **) &parytet);
13634  *parytet = neightet;
13635  }
13636  }
13637  } // j
13638  } // i
13639 
13640  // Uninfect the list of visited tets.
13641  for (i = 0; i < tetlist->objects; i++) {
13642  parytet = (triface *) fastlookup(tetlist, i);
13643  uninfect(*parytet);
13644  }
13645  tetlist->restart();
13646 
13647  return done;
13648 }
13649 
13651 // //
13652 // reduceedgesatvertex() Reduce the number of edges at a given vertex. //
13653 // //
13654 // 'endptlist' contains the endpoints of edges connecting at the vertex. //
13655 // //
13657 
13659 {
13660  triface searchtet;
13661  point *pendpt, *parypt;
13662  enum interresult dir;
13664  int reduceflag;
13665  int count;
13666  int n, i, j;
13667 
13668 
13669  fc.remvert = startpt;
13670  fc.checkflipeligibility = 1;
13671 
13672  while (1) {
13673 
13674  count = 0;
13675 
13676  for (i = 0; i < endptlist->objects; i++) {
13677  pendpt = (point *) fastlookup(endptlist, i);
13678  if (*pendpt == dummypoint) {
13679  continue; // Do not reduce a virtual edge.
13680  }
13681  reduceflag = 0;
13682  // Find the edge.
13683  if (nonconvex) {
13684  if (getedge(startpt, *pendpt, &searchtet)) {
13685  dir = ACROSSVERT;
13686  } else {
13687  // The edge does not exist (was flipped).
13688  dir = INTERSECT;
13689  }
13690  } else {
13691  point2tetorg(startpt, searchtet);
13692  dir = finddirection(&searchtet, *pendpt);
13693  }
13694  if (dir == ACROSSVERT) {
13695  if (dest(searchtet) == *pendpt) {
13696  // Do not flip a segment.
13697  if (!issubseg(searchtet)) {
13698  n = removeedgebyflips(&searchtet, &fc);
13699  if (n == 2) {
13700  reduceflag = 1;
13701  }
13702  }
13703  }
13704  } else {
13705  // The edge has been flipped.
13706  reduceflag = 1;
13707  }
13708  if (reduceflag) {
13709  count++;
13710  // Move the last vertex into this slot.
13711  j = endptlist->objects - 1;
13712  parypt = (point *) fastlookup(endptlist, j);
13713  *pendpt = *parypt;
13714  endptlist->objects--;
13715  i--;
13716  }
13717  } // i
13718 
13719  if (count == 0) {
13720  // No edge is reduced.
13721  break;
13722  }
13723 
13724  } // while (1)
13725 
13726  return (int) endptlist->objects;
13727 }
13728 
13730 // //
13731 // removevertexbyflips() Remove a vertex by flips. //
13732 // //
13733 // This routine attempts to remove the given vertex 'rempt' (p) from the //
13734 // tetrahedralization (T) by a sequence of flips. //
13735 // //
13736 // The algorithm used here is a simple edge reduce method. Suppose there are //
13737 // n edges connected at p. We try to reduce the number of edges by flipping //
13738 // any edge (not a segment) that is connecting at p. //
13739 // //
13740 // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
13741 // can be successfully removed. //
13742 // //
13744 
13746 {
13747  triface *fliptets = NULL, wrktets[4];
13748  triface searchtet, spintet, neightet;
13749  face parentsh, spinsh, checksh;
13750  face leftseg, rightseg, checkseg;
13751  point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
13753  enum verttype vt;
13754  enum locateresult loc;
13755  int valence, removeflag;
13756  int slawson;
13757  int t1ver;
13758  int n, i;
13759 
13760  vt = pointtype(steinerpt);
13761 
13762  if (vt == FREESEGVERTEX) {
13763  sdecode(point2sh(steinerpt), leftseg);
13764  leftseg.shver = 0;
13765  if (sdest(leftseg) == steinerpt) {
13766  senext(leftseg, rightseg);
13767  spivotself(rightseg);
13768  rightseg.shver = 0;
13769  } else {
13770  rightseg = leftseg;
13771  senext2(rightseg, leftseg);
13772  spivotself(leftseg);
13773  leftseg.shver = 0;
13774  }
13775  lpt = sorg(leftseg);
13776  rpt = sdest(rightseg);
13777  if (b->verbose > 2) {
13778  printf(" Removing Steiner point %d in segment (%d, %d).\n",
13779  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
13780 
13781  }
13782  } else if (vt == FREEFACETVERTEX) {
13783  if (b->verbose > 2) {
13784  printf(" Removing Steiner point %d in facet.\n",
13785  pointmark(steinerpt));
13786  }
13787  } else if (vt == FREEVOLVERTEX) {
13788  if (b->verbose > 2) {
13789  printf(" Removing Steiner point %d in volume.\n",
13790  pointmark(steinerpt));
13791  }
13792  } else if (vt == VOLVERTEX) {
13793  if (b->verbose > 2) {
13794  printf(" Removing a point %d in volume.\n",
13795  pointmark(steinerpt));
13796  }
13797  } else {
13798  // It is not a Steiner point.
13799  return 0;
13800  }
13801 
13802  // Try to reduce the number of edges at 'p' by flips.
13803  getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
13804  cavetetlist->restart(); // This list may be re-used.
13805  if (cavetetvertlist->objects > 3l) {
13806  valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
13807  } else {
13808  valence = cavetetvertlist->objects;
13809  }
13811 
13812  removeflag = 0;
13813 
13814  if (valence == 4) {
13815  // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
13816  // vertices. This case is due to that 'p' is not exactly on the segment.
13817  point2tetorg(steinerpt, searchtet);
13818  loc = INTETRAHEDRON;
13819  removeflag = 1;
13820  } else if (valence == 5) {
13821  // There are 5 edges.
13822  if (vt == FREESEGVERTEX) {
13823  sstpivot1(leftseg, searchtet);
13824  if (org(searchtet) != steinerpt) {
13825  esymself(searchtet);
13826  }
13827  i = 0; // Count the numbe of tet at the edge [p,lpt].
13828  neightet.tet = NULL; // Init the face.
13829  spintet = searchtet;
13830  while (1) {
13831  i++;
13832  if (apex(spintet) == rpt) {
13833  // Remember the face containing the edge [lpt, rpt].
13834  neightet = spintet;
13835  }
13836  fnextself(spintet);
13837  if (spintet.tet == searchtet.tet) break;
13838  }
13839  if (i == 3) {
13840  // This case has been checked below.
13841  } else if (i == 4) {
13842  // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
13843  // at [p,rpt]. There must be a face [p, lpt, rpt].
13844  if (apex(neightet) == rpt) {
13845  // The edge (segment) has been already recovered!
13846  // Check if a 6-to-2 flip is possible (to remove 'p').
13847  // Let 'searchtet' be [p,d,a,b]
13848  esym(neightet, searchtet);
13849  enextself(searchtet);
13850  // Check if there are exactly three tets at edge [p,d].
13851  wrktets[0] = searchtet; // [p,d,a,b]
13852  for (i = 0; i < 2; i++) {
13853  fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
13854  }
13855  if (apex(wrktets[0]) == oppo(wrktets[2])) {
13856  loc = ONFACE;
13857  removeflag = 1;
13858  }
13859  }
13860  }
13861  } else if (vt == FREEFACETVERTEX) {
13862  // It is possible to do a 6-to-2 flip to remove the vertex.
13863  point2tetorg(steinerpt, searchtet);
13864  // Get the three faces of 'searchtet' which share at p.
13865  // All faces has p as origin.
13866  wrktets[0] = searchtet;
13867  wrktets[1] = searchtet;
13868  esymself(wrktets[1]);
13869  enextself(wrktets[1]);
13870  wrktets[2] = searchtet;
13871  eprevself(wrktets[2]);
13872  esymself(wrktets[2]);
13873  // All internal edges of the six tets have valance either 3 or 4.
13874  // Get one edge which has valance 3.
13875  searchtet.tet = NULL;
13876  for (i = 0; i < 3; i++) {
13877  spintet = wrktets[i];
13878  valence = 0;
13879  while (1) {
13880  valence++;
13881  fnextself(spintet);
13882  if (spintet.tet == wrktets[i].tet) break;
13883  }
13884  if (valence == 3) {
13885  // Found the edge.
13886  searchtet = wrktets[i];
13887  break;
13888  }
13889  }
13890  // Note, we do not detach the three subfaces at p.
13891  // They will be removed within a 4-to-1 flip.
13892  loc = ONFACE;
13893  removeflag = 1;
13894  }
13895  //removeflag = 1;
13896  }
13897 
13898  if (!removeflag) {
13899  if (vt == FREESEGVERTEX) {
13900  // Check is it possible to recover the edge [lpt,rpt].
13901  // The condition to check is: Whether each tet containing 'leftseg' is
13902  // adjacent to a tet containing 'rightseg'.
13903  sstpivot1(leftseg, searchtet);
13904  if (org(searchtet) != steinerpt) {
13905  esymself(searchtet);
13906  }
13907  spintet = searchtet;
13908  while (1) {
13909  // Go to the bottom face of this tet.
13910  eprev(spintet, neightet);
13911  esymself(neightet); // [steinerpt, p1, p2, lpt]
13912  // Get the adjacent tet.
13913  fsymself(neightet); // [p1, steinerpt, p2, rpt]
13914  if (oppo(neightet) != rpt) {
13915  // Found a non-matching adjacent tet.
13916  break;
13917  }
13918  fnextself(spintet);
13919  if (spintet.tet == searchtet.tet) {
13920  // 'searchtet' is [p,d,p1,p2].
13921  loc = ONEDGE;
13922  removeflag = 1;
13923  break;
13924  }
13925  }
13926  } // if (vt == FREESEGVERTEX)
13927  }
13928 
13929  if (!removeflag) {
13930  if (vt == FREESEGVERTEX) {
13931  // Check if the edge [lpt, rpt] exists.
13932  if (getedge(lpt, rpt, &searchtet)) {
13933  // We have recovered this edge. Shift the vertex into the volume.
13934  // We can recover this edge if the subfaces are not recovered yet.
13935  if (!checksubfaceflag) {
13936  // Remove the vertex from the surface mesh.
13937  // This will re-create the segment [lpt, rpt] and re-triangulate
13938  // all the facets at the segment.
13939  // Detach the subsegments from their surrounding tets.
13940  for (i = 0; i < 2; i++) {
13941  checkseg = (i == 0) ? leftseg : rightseg;
13942  sstpivot1(checkseg, neightet);
13943  spintet = neightet;
13944  while (1) {
13945  tssdissolve1(spintet);
13946  fnextself(spintet);
13947  if (spintet.tet == neightet.tet) break;
13948  }
13949  sstdissolve1(checkseg);
13950  } // i
13951  slawson = 1; // Do lawson flip after removal.
13952  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
13953  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
13954  // Clear the list for new subfaces.
13955  caveshbdlist->restart();
13956  // Insert the new segment.
13957  sstbond1(rightseg, searchtet);
13958  spintet = searchtet;
13959  while (1) {
13960  tssbond1(spintet, rightseg);
13961  fnextself(spintet);
13962  if (spintet.tet == searchtet.tet) break;
13963  }
13964  // The Steiner point has been shifted into the volume.
13965  setpointtype(steinerpt, FREEVOLVERTEX);
13966  st_segref_count--;
13967  st_volref_count++;
13968  return 1;
13969  } // if (!checksubfaceflag)
13970  } // if (getedge(...))
13971  } // if (vt == FREESEGVERTEX)
13972  } // if (!removeflag)
13973 
13974  if (!removeflag) {
13975  return 0;
13976  }
13977 
13978  if (vt == FREESEGVERTEX) {
13979  // Detach the subsegments from their surronding tets.
13980  for (i = 0; i < 2; i++) {
13981  checkseg = (i == 0) ? leftseg : rightseg;
13982  sstpivot1(checkseg, neightet);
13983  spintet = neightet;
13984  while (1) {
13985  tssdissolve1(spintet);
13986  fnextself(spintet);
13987  if (spintet.tet == neightet.tet) break;
13988  }
13989  sstdissolve1(checkseg);
13990  } // i
13991  if (checksubfaceflag) {
13992  // Detach the subfaces at the subsegments from their attached tets.
13993  for (i = 0; i < 2; i++) {
13994  checkseg = (i == 0) ? leftseg : rightseg;
13995  spivot(checkseg, parentsh);
13996  if (parentsh.sh != NULL) {
13997  spinsh = parentsh;
13998  while (1) {
13999  stpivot(spinsh, neightet);
14000  if (neightet.tet != NULL) {
14001  tsdissolve(neightet);
14002  }
14003  sesymself(spinsh);
14004  stpivot(spinsh, neightet);
14005  if (neightet.tet != NULL) {
14006  tsdissolve(neightet);
14007  }
14008  stdissolve(spinsh);
14009  spivotself(spinsh); // Go to the next subface.
14010  if (spinsh.sh == parentsh.sh) break;
14011  }
14012  }
14013  } // i
14014  } // if (checksubfaceflag)
14015  }
14016 
14017  if (loc == INTETRAHEDRON) {
14018  // Collect the four tets containing 'p'.
14019  fliptets = new triface[4];
14020  fliptets[0] = searchtet; // [p,d,a,b]
14021  for (i = 0; i < 2; i++) {
14022  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
14023  }
14024  eprev(fliptets[0], fliptets[3]);
14025  fnextself(fliptets[3]); // it is [a,p,b,c]
14026  eprevself(fliptets[3]);
14027  esymself(fliptets[3]); // [a,b,c,p].
14028  // Remove p by a 4-to-1 flip.
14029  //flip41(fliptets, 1, 0, 0);
14030  flip41(fliptets, 1, &fc);
14031  //recenttet = fliptets[0];
14032  } else if (loc == ONFACE) {
14033  // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
14034  // face [a,b,c]. Let 'searchtet' be the tet [p,d,a,b].
14035  // Collect the six tets containing 'p'.
14036  fliptets = new triface[6];
14037  fliptets[0] = searchtet; // [p,d,a,b]
14038  for (i = 0; i < 2; i++) {
14039  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
14040  }
14041  eprev(fliptets[0], fliptets[3]);
14042  fnextself(fliptets[3]); // [a,p,b,e]
14043  esymself(fliptets[3]); // [p,a,e,b]
14044  eprevself(fliptets[3]); // [e,p,a,b]
14045  for (i = 3; i < 5; i++) {
14046  fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
14047  }
14048  if (vt == FREEFACETVERTEX) {
14049  // We need to determine the location of three subfaces at p.
14050  valence = 0; // Re-use it.
14051  // Check if subfaces are all located in the lower three tets.
14052  // i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a].
14053  for (i = 3; i < 6; i++) {
14054  if (issubface(fliptets[i])) valence++;
14055  }
14056  if (valence > 0) {
14057  // We must do 3-to-2 flip in the upper part. We simply re-arrange
14058  // the six tets.
14059  for (i = 0; i < 3; i++) {
14060  esym(fliptets[i+3], wrktets[i]);
14061  esym(fliptets[i], fliptets[i+3]);
14062  fliptets[i] = wrktets[i];
14063  }
14064  // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
14065  wrktets[1] = fliptets[1];
14066  fliptets[1] = fliptets[2];
14067  fliptets[2] = wrktets[1];
14068  wrktets[1] = fliptets[4];
14069  fliptets[4] = fliptets[5];
14070  fliptets[5] = wrktets[1];
14071  }
14072  }
14073  // Remove p by a 6-to-2 flip, which is a combination of two flips:
14074  // a 3-to-2 (deletes the edge [e,p]), and
14075  // a 4-to-1 (deletes the vertex p).
14076  // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
14077  // two new tets: [a,b,c,p] and [b,a,c,e]. The new tet [a,b,c,p] is
14078  // degenerate (has zero volume). It will be deleted in the followed
14079  // 4-to-1 flip.
14080  //flip32(&(fliptets[3]), 1, 0, 0);
14081  flip32(&(fliptets[3]), 1, &fc);
14082  // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
14083  // This creates a new tet [a,b,c,d].
14084  //flip41(fliptets, 1, 0, 0);
14085  flip41(fliptets, 1, &fc);
14086  //recenttet = fliptets[0];
14087  } else if (loc == ONEDGE) {
14088  // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
14089  // tets sharing at edge [e,d] originally. We number the link vertices
14090  // of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
14091  // Count the number of tets at edge [e,p] and [p,d] (this is n).
14092  n = 0;
14093  spintet = searchtet;
14094  while (1) {
14095  n++;
14096  fnextself(spintet);
14097  if (spintet.tet == searchtet.tet) break;
14098  }
14099  // Collect the 2n tets containing 'p'.
14100  fliptets = new triface[2 * n];
14101  fliptets[0] = searchtet; // [p,b,p_0,p_1]
14102  for (i = 0; i < (n - 1); i++) {
14103  fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
14104  }
14105  eprev(fliptets[0], fliptets[n]);
14106  fnextself(fliptets[n]); // [p_0,p,p_1,e]
14107  esymself(fliptets[n]); // [p,p_0,e,p_1]
14108  eprevself(fliptets[n]); // [e,p,p_0,p_1]
14109  for (i = n; i < (2 * n - 1); i++) {
14110  fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
14111  }
14112  // Remove p by a 2n-to-n flip, it is a sequence of n flips:
14113  // - Do a 2-to-3 flip on
14114  // [p_0,p_1,p,d] and
14115  // [p,p_1,p_0,e].
14116  // This produces:
14117  // [e,d,p_0,p_1],
14118  // [e,d,p_1,p] (degenerated), and
14119  // [e,d,p,p_0] (degenerated).
14120  wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
14121  eprevself(wrktets[0]); // [p_0,p,d,p_1]
14122  esymself(wrktets[0]); // [p,p_0,p_1,d]
14123  enextself(wrktets[0]); // [p_0,p_1,p,d] [0]
14124  wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
14125  enextself(wrktets[1]); // [p,p_0,e,p_1]
14126  esymself(wrktets[1]); // [p_0,p,p_1,e]
14127  eprevself(wrktets[1]); // [p_1,p_0,p,e] [1]
14128  //flip23(wrktets, 1, 0, 0);
14129  flip23(wrktets, 1, &fc);
14130  // Save the new tet [e,d,p,p_0] (degenerated).
14131  fliptets[n] = wrktets[2];
14132  // Save the new tet [e,d,p_0,p_1].
14133  fliptets[0] = wrktets[0];
14134  // - Repeat from i = 1 to n-2: (n - 2) flips
14135  // - Do a 3-to-2 flip on
14136  // [p,p_i,d,e],
14137  // [p,p_i,e,p_i+1], and
14138  // [p,p_i,p_i+1,d].
14139  // This produces:
14140  // [d,e,p_i+1,p_i], and
14141  // [e,d,p_i+1,p] (degenerated).
14142  for (i = 1; i < (n - 1); i++) {
14143  wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
14144  enextself(wrktets[0]); // [d,p_i,e,p] (...)
14145  esymself(wrktets[0]); // [p_i,d,p,e] (...)
14146  eprevself(wrktets[0]); // [p,p_i,d,e] (degenerated) [0].
14147  wrktets[1] = fliptets[n+i]; // [e,p,p_i,p_i+1]
14148  enextself(wrktets[1]); // [p,p_i,e,p_i+1] [1]
14149  wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
14150  eprevself(wrktets[2]); // [p_i,p,d,p_i+1]
14151  esymself(wrktets[2]); // [p,p_i,p_i+1,d] [2]
14152  //flip32(wrktets, 1, 0, 0);
14153  flip32(wrktets, 1, &fc);
14154  // Save the new tet [e,d,p_i,p_i+1]. // FOR DEBUG ONLY
14155  fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
14156  esymself(fliptets[i]); // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
14157  }
14158  // - Do a 4-to-1 flip on
14159  // [p,p_0,e,d], [d,e,p_0,p],
14160  // [p,p_0,d,p_n-1], [e,p_n-1,p_0,p],
14161  // [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
14162  // [e,d,p_n-1,p].
14163  // This produces
14164  // [e,d,p_n-1,p_0] and
14165  // deletes p.
14166  wrktets[3] = wrktets[1]; // [e,d,p_n-1,p] (degenerated) [3]
14167  wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
14168  eprevself(wrktets[0]); // [p,e,d,p_0] (...)
14169  esymself(wrktets[0]); // [e,p,p_0,d] (...)
14170  enextself(wrktets[0]); // [p,p_0,e,d] (degenerated) [0]
14171  wrktets[1] = fliptets[n-1]; // [p,d,p_n-1,p_0]
14172  esymself(wrktets[1]); // [d,p,p_0,p_n-1]
14173  enextself(wrktets[1]); // [p,p_0,d,p_n-1] [1]
14174  wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
14175  enextself(wrktets[2]); // [p_p_n-1,e,p_0]
14176  esymself(wrktets[2]); // [p_n-1,p,p_0,e]
14177  enextself(wrktets[2]); // [p,p_0,p_n-1,e] [2]
14178  //flip41(wrktets, 1, 0, 0);
14179  flip41(wrktets, 1, &fc);
14180  // Save the new tet [e,d,p_n-1,p_0] // FOR DEBUG ONLY
14181  fliptets[n-1] = wrktets[0]; // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
14182  //recenttet = fliptets[0];
14183  }
14184 
14185  delete [] fliptets;
14186 
14187  if (vt == FREESEGVERTEX) {
14188  // Remove the vertex from the surface mesh.
14189  // This will re-create the segment [lpt, rpt] and re-triangulate
14190  // all the facets at the segment.
14191  // Only do lawson flip when subfaces are not recovery yet.
14192  slawson = (checksubfaceflag ? 0 : 1);
14193  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
14194  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
14195 
14196  // The original segment is returned in 'rightseg'.
14197  rightseg.shver = 0;
14198  // Insert the new segment.
14199  point2tetorg(lpt, searchtet);
14200  finddirection(&searchtet, rpt);
14201  sstbond1(rightseg, searchtet);
14202  spintet = searchtet;
14203  while (1) {
14204  tssbond1(spintet, rightseg);
14205  fnextself(spintet);
14206  if (spintet.tet == searchtet.tet) break;
14207  }
14208 
14209  if (checksubfaceflag) {
14210  // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
14211  spivot(rightseg, parentsh);
14212  if (parentsh.sh != NULL) {
14213  spinsh = parentsh;
14214  while (1) {
14215  if (sorg(spinsh) != lpt) {
14216  sesymself(spinsh);
14217  }
14218  apexpt = sapex(spinsh);
14219  // Find the adjacent tet of [lpt,rpt,apexpt];
14220  spintet = searchtet;
14221  while (1) {
14222  if (apex(spintet) == apexpt) {
14223  tsbond(spintet, spinsh);
14224  sesymself(spinsh); // Get to another side of this face.
14225  fsym(spintet, neightet);
14226  tsbond(neightet, spinsh);
14227  sesymself(spinsh); // Get back to the original side.
14228  break;
14229  }
14230  fnextself(spintet);
14231  }
14232  spivotself(spinsh);
14233  if (spinsh.sh == parentsh.sh) break;
14234  }
14235  }
14236  } // if (checksubfaceflag)
14237 
14238  // Clear the set of new subfaces.
14239  caveshbdlist->restart();
14240  } // if (vt == FREESEGVERTEX)
14241 
14242  // The point has been removed.
14243  if (pointtype(steinerpt) != UNUSEDVERTEX) {
14244  setpointtype(steinerpt, UNUSEDVERTEX);
14245  unuverts++;
14246  }
14247  if (vt != VOLVERTEX) {
14248  // Update the correspinding counters.
14249  if (vt == FREESEGVERTEX) {
14250  st_segref_count--;
14251  } else if (vt == FREEFACETVERTEX) {
14252  st_facref_count--;
14253  } else if (vt == FREEVOLVERTEX) {
14254  st_volref_count--;
14255  }
14256  if (steinerleft > 0) steinerleft++;
14257  }
14258 
14259  return 1;
14260 }
14261 
14263 // //
14264 // suppressbdrysteinerpoint() Suppress a boundary Steiner point //
14265 // //
14267 
14269 {
14270  face parentsh, spinsh, *parysh;
14271  face leftseg, rightseg;
14272  point lpt = NULL, rpt = NULL;
14273  int i;
14274 
14275  verttype vt = pointtype(steinerpt);
14276 
14277  if (vt == FREESEGVERTEX) {
14278  sdecode(point2sh(steinerpt), leftseg);
14279  leftseg.shver = 0;
14280  if (sdest(leftseg) == steinerpt) {
14281  senext(leftseg, rightseg);
14282  spivotself(rightseg);
14283  rightseg.shver = 0;
14284  } else {
14285  rightseg = leftseg;
14286  senext2(rightseg, leftseg);
14287  spivotself(leftseg);
14288  leftseg.shver = 0;
14289  }
14290  lpt = sorg(leftseg);
14291  rpt = sdest(rightseg);
14292  if (b->verbose > 2) {
14293  printf(" Suppressing Steiner point %d in segment (%d, %d).\n",
14294  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
14295  }
14296  // Get all subfaces at the left segment [lpt, steinerpt].
14297  spivot(leftseg, parentsh);
14298  if (parentsh.sh != NULL) {
14299  // It is not a dangling segment.
14300  spinsh = parentsh;
14301  while (1) {
14302  cavesegshlist->newindex((void **) &parysh);
14303  *parysh = spinsh;
14304  // Orient the face consistently.
14305  if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
14306  spivotself(spinsh);
14307  if (spinsh.sh == NULL) break;
14308  if (spinsh.sh == parentsh.sh) break;
14309  }
14310  }
14311  if (cavesegshlist->objects < 2) {
14312  // It is a single segment. Not handle it yet.
14314  return 0;
14315  }
14316  } else if (vt == FREEFACETVERTEX) {
14317  if (b->verbose > 2) {
14318  printf(" Suppressing Steiner point %d from facet.\n",
14319  pointmark(steinerpt));
14320  }
14321  sdecode(point2sh(steinerpt), parentsh);
14322  // A facet Steiner point. There are exactly two sectors.
14323  for (i = 0; i < 2; i++) {
14324  cavesegshlist->newindex((void **) &parysh);
14325  *parysh = parentsh;
14326  sesymself(parentsh);
14327  }
14328  } else {
14329  return 0;
14330  }
14331 
14332  triface searchtet, neightet, *parytet;
14333  point pa, pb, pc, pd;
14334  REAL v1[3], v2[3], len, u;
14335 
14336  REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
14337  REAL ori, minvol, smallvol;
14338  int samplesize;
14339  int it, j, k;
14340 
14341  int n = (int) cavesegshlist->objects;
14342  point *newsteiners = new point[n];
14343  for (i = 0; i < n; i++) newsteiners[i] = NULL;
14344 
14345  // Search for each sector an interior vertex.
14346  for (i = 0; i < cavesegshlist->objects; i++) {
14347  parysh = (face *) fastlookup(cavesegshlist, i);
14348  stpivot(*parysh, searchtet);
14349  // Skip it if it is outside.
14350  if (ishulltet(searchtet)) continue;
14351  // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
14352  // opposite. Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
14353  // Moreover, subfaces are oriented towards the interior of the ball.
14354  setpoint2tet(steinerpt, encode(searchtet));
14355  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
14356  // Calculate the searching vector.
14357  pa = sorg(*parysh);
14358  pb = sdest(*parysh);
14359  pc = sapex(*parysh);
14360  facenormal(pa, pb, pc, v1, 1, NULL);
14361  len = sqrt(dot(v1, v1));
14362  v1[0] /= len;
14363  v1[1] /= len;
14364  v1[2] /= len;
14365  if (vt == FREESEGVERTEX) {
14366  parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
14367  pd = sapex(*parysh);
14368  facenormal(pb, pa, pd, v2, 1, NULL);
14369  len = sqrt(dot(v2, v2));
14370  v2[0] /= len;
14371  v2[1] /= len;
14372  v2[2] /= len;
14373  // Average the two vectors.
14374  v1[0] = 0.5 * (v1[0] + v2[0]);
14375  v1[1] = 0.5 * (v1[1] + v2[1]);
14376  v1[2] = 0.5 * (v1[2] + v2[2]);
14377  }
14378  // Search the intersection of the ray starting from 'steinerpt' to
14379  // the search direction 'v1' and the shell of the half-ball.
14380  // - Construct an endpoint.
14381  len = distance(pa, pb);
14382  v2[0] = steinerpt[0] + len * v1[0];
14383  v2[1] = steinerpt[1] + len * v1[1];
14384  v2[2] = steinerpt[2] + len * v1[2];
14385  for (j = 0; j < cavetetlist->objects; j++) {
14386  parytet = (triface *) fastlookup(cavetetlist, j);
14387  pa = org(*parytet);
14388  pb = dest(*parytet);
14389  pc = apex(*parytet);
14390  // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
14391  // is the apex, and three sides are defined by the triangle
14392  // [pa, pb, pc].
14393  ori = orient3d(steinerpt, pa, pb, v2);
14394  if (ori >= 0) {
14395  ori = orient3d(steinerpt, pb, pc, v2);
14396  if (ori >= 0) {
14397  ori = orient3d(steinerpt, pc, pa, v2);
14398  if (ori >= 0) {
14399  // Found! Calculate the intersection.
14400  planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
14401  break;
14402  }
14403  }
14404  }
14405  } // j
14406  // Close the ball by adding the subfaces.
14407  for (j = 0; j < caveshlist->objects; j++) {
14408  parysh = (face *) fastlookup(caveshlist, j);
14409  stpivot(*parysh, neightet);
14410  cavetetlist->newindex((void **) &parytet);
14411  *parytet = neightet;
14412  }
14413  // Search a best point inside the segment [startpt, steinerpt].
14414  it = 0;
14415  samplesize = 100;
14416  v1[0] = steinerpt[0] - startpt[0];
14417  v1[1] = steinerpt[1] - startpt[1];
14418  v1[2] = steinerpt[2] - startpt[2];
14419  minvol = -1.0;
14420  while (it < 3) {
14421  for (j = 1; j < samplesize - 1; j++) {
14422  samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
14423  samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
14424  samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
14425  // Find the minimum volume for 'samplept'.
14426  smallvol = -1;
14427  for (k = 0; k < cavetetlist->objects; k++) {
14428  parytet = (triface *) fastlookup(cavetetlist, k);
14429  pa = org(*parytet);
14430  pb = dest(*parytet);
14431  pc = apex(*parytet);
14432  ori = orient3d(pb, pa, pc, samplept);
14433  if (ori <= 0) {
14434  break; // An invalid tet.
14435  }
14436  if (smallvol == -1) {
14437  smallvol = ori;
14438  } else {
14439  if (ori < smallvol) smallvol = ori;
14440  }
14441  } // k
14442  if (k == cavetetlist->objects) {
14443  // Found a valid point. Remember it.
14444  if (minvol == -1.0) {
14445  candpt[0] = samplept[0];
14446  candpt[1] = samplept[1];
14447  candpt[2] = samplept[2];
14448  minvol = smallvol;
14449  } else {
14450  if (minvol < smallvol) {
14451  // It is a better location. Remember it.
14452  candpt[0] = samplept[0];
14453  candpt[1] = samplept[1];
14454  candpt[2] = samplept[2];
14455  minvol = smallvol;
14456  } else {
14457  // No improvement of smallest volume.
14458  // Since we are searching along the line [startpt, steinerpy],
14459  // The smallest volume can only be decreased later.
14460  break;
14461  }
14462  }
14463  }
14464  } // j
14465  if (minvol > 0) break;
14466  samplesize *= 10;
14467  it++;
14468  } // while (it < 3)
14469  if (minvol == -1.0) {
14470  // Failed to find a valid point.
14471  cavetetlist->restart();
14472  caveshlist->restart();
14473  break;
14474  }
14475  // Create a new Steiner point inside this section.
14476  makepoint(&(newsteiners[i]), FREEVOLVERTEX);
14477  newsteiners[i][0] = candpt[0];
14478  newsteiners[i][1] = candpt[1];
14479  newsteiners[i][2] = candpt[2];
14480  cavetetlist->restart();
14481  caveshlist->restart();
14482  } // i
14483 
14484  if (i < cavesegshlist->objects) {
14485  // Failed to suppress the vertex.
14486  for (; i > 0; i--) {
14487  if (newsteiners[i - 1] != NULL) {
14488  pointdealloc(newsteiners[i - 1]);
14489  }
14490  }
14491  delete [] newsteiners;
14493  return 0;
14494  }
14495 
14496  // Remove p from the segment or the facet.
14497  triface newtet, newface, spintet;
14498  face newsh, neighsh;
14499  face *splitseg, checkseg;
14500  int slawson = 0; // Do not do flip afterword.
14501  int t1ver;
14502 
14503  if (vt == FREESEGVERTEX) {
14504  // Detach 'leftseg' and 'rightseg' from their adjacent tets.
14505  // These two subsegments will be deleted.
14506  sstpivot1(leftseg, neightet);
14507  spintet = neightet;
14508  while (1) {
14509  tssdissolve1(spintet);
14510  fnextself(spintet);
14511  if (spintet.tet == neightet.tet) break;
14512  }
14513  sstpivot1(rightseg, neightet);
14514  spintet = neightet;
14515  while (1) {
14516  tssdissolve1(spintet);
14517  fnextself(spintet);
14518  if (spintet.tet == neightet.tet) break;
14519  }
14520  }
14521 
14522  // Loop through all sectors bounded by facets at this segment.
14523  // Within each sector, create a new Steiner point 'np', and replace 'p'
14524  // by 'np' for all tets in this sector.
14525  for (i = 0; i < cavesegshlist->objects; i++) {
14526  parysh = (face *) fastlookup(cavesegshlist, i);
14527  // 'parysh' is the face [lpt, steinerpt, #].
14528  stpivot(*parysh, neightet);
14529  // Get all tets in this sector.
14530  setpoint2tet(steinerpt, encode(neightet));
14531  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
14532  if (!ishulltet(neightet)) {
14533  // Within each tet in the ball, replace 'p' by 'np'.
14534  for (j = 0; j < cavetetlist->objects; j++) {
14535  parytet = (triface *) fastlookup(cavetetlist, j);
14536  setoppo(*parytet, newsteiners[i]);
14537  } // j
14538  // Point to a parent tet.
14539  parytet = (triface *) fastlookup(cavetetlist, 0);
14540  setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet));
14541  st_volref_count++;
14542  if (steinerleft > 0) steinerleft--;
14543  }
14544  // Disconnect the set of boundary faces. They're temporarily open faces.
14545  // They will be connected to the new tets after 'p' is removed.
14546  for (j = 0; j < caveshlist->objects; j++) {
14547  // Get a boundary face.
14548  parysh = (face *) fastlookup(caveshlist, j);
14549  stpivot(*parysh, neightet);
14550  //assert(apex(neightet) == newpt);
14551  // Clear the connection at this face.
14552  dissolve(neightet);
14553  tsdissolve(neightet);
14554  }
14555  // Clear the working lists.
14556  cavetetlist->restart();
14557  caveshlist->restart();
14558  } // i
14560 
14561  if (vt == FREESEGVERTEX) {
14562  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
14563  splitseg = &rightseg;
14564  } else {
14565  if (sdest(parentsh) == steinerpt) {
14566  senextself(parentsh);
14567  } else if (sapex(parentsh) == steinerpt) {
14568  senext2self(parentsh);
14569  }
14570  splitseg = NULL;
14571  }
14572  sremovevertex(steinerpt, &parentsh, splitseg, slawson);
14573 
14574  if (vt == FREESEGVERTEX) {
14575  // The original segment is returned in 'rightseg'.
14576  rightseg.shver = 0;
14577  }
14578 
14579  // For each new subface, create two new tets at each side of it.
14580  // Both of the two new tets have its opposite be dummypoint.
14581  for (i = 0; i < caveshbdlist->objects; i++) {
14582  parysh = (face *) fastlookup(caveshbdlist, i);
14583  sinfect(*parysh); // Mark it for connecting new tets.
14584  newsh = *parysh;
14585  pa = sorg(newsh);
14586  pb = sdest(newsh);
14587  pc = sapex(newsh);
14588  maketetrahedron(&newtet);
14589  maketetrahedron(&neightet);
14590  setvertices(newtet, pa, pb, pc, dummypoint);
14591  setvertices(neightet, pb, pa, pc, dummypoint);
14592  bond(newtet, neightet);
14593  tsbond(newtet, newsh);
14594  sesymself(newsh);
14595  tsbond(neightet, newsh);
14596  }
14597  // Temporarily increase the hullsize.
14598  hullsize += (caveshbdlist->objects * 2l);
14599 
14600  if (vt == FREESEGVERTEX) {
14601  // Connecting new tets at the recovered segment.
14602  spivot(rightseg, parentsh);
14603  spinsh = parentsh;
14604  while (1) {
14605  if (sorg(spinsh) != lpt) sesymself(spinsh);
14606  // Get the new tet at this subface.
14607  stpivot(spinsh, newtet);
14608  tssbond1(newtet, rightseg);
14609  // Go to the other face at this segment.
14610  spivot(spinsh, neighsh);
14611  if (sorg(neighsh) != lpt) sesymself(neighsh);
14612  sesymself(neighsh);
14613  stpivot(neighsh, neightet);
14614  tssbond1(neightet, rightseg);
14615  sstbond1(rightseg, neightet);
14616  // Connecting two adjacent tets at this segment.
14617  esymself(newtet);
14618  esymself(neightet);
14619  // Connect the two tets (at rightseg) together.
14620  bond(newtet, neightet);
14621  // Go to the next subface.
14622  spivotself(spinsh);
14623  if (spinsh.sh == parentsh.sh) break;
14624  }
14625  }
14626 
14627  // Connecting new tets at new subfaces together.
14628  for (i = 0; i < caveshbdlist->objects; i++) {
14629  parysh = (face *) fastlookup(caveshbdlist, i);
14630  newsh = *parysh;
14631  //assert(sinfected(newsh));
14632  // Each new subface contains two new tets.
14633  for (k = 0; k < 2; k++) {
14634  stpivot(newsh, newtet);
14635  for (j = 0; j < 3; j++) {
14636  // Check if this side is open.
14637  esym(newtet, newface);
14638  if (newface.tet[newface.ver & 3] == NULL) {
14639  // An open face. Connect it to its adjacent tet.
14640  sspivot(newsh, checkseg);
14641  if (checkseg.sh != NULL) {
14642  // A segment. It must not be the recovered segment.
14643  tssbond1(newtet, checkseg);
14644  sstbond1(checkseg, newtet);
14645  }
14646  spivot(newsh, neighsh);
14647  if (neighsh.sh != NULL) {
14648  // The adjacent subface exists. It's not a dangling segment.
14649  if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
14650  stpivot(neighsh, neightet);
14651  if (sinfected(neighsh)) {
14652  esymself(neightet);
14653  } else {
14654  // Search for an open face at this edge.
14655  spintet = neightet;
14656  while (1) {
14657  esym(spintet, searchtet);
14658  fsym(searchtet, spintet);
14659  if (spintet.tet == NULL) break;
14660  }
14661  // Found an open face at 'searchtet'.
14662  neightet = searchtet;
14663  }
14664  } else {
14665  // The edge (at 'newsh') is a dangling segment.
14666  // Get an adjacent tet at this segment.
14667  sstpivot1(checkseg, neightet);
14668  if (org(neightet) != sdest(newsh)) esymself(neightet);
14669  // Search for an open face at this edge.
14670  spintet = neightet;
14671  while (1) {
14672  esym(spintet, searchtet);
14673  fsym(searchtet, spintet);
14674  if (spintet.tet == NULL) break;
14675  }
14676  // Found an open face at 'searchtet'.
14677  neightet = searchtet;
14678  }
14679  pc = apex(newface);
14680  if (apex(neightet) == steinerpt) {
14681  // Exterior case. The 'neightet' is a hull tet which contain
14682  // 'steinerpt'. It will be deleted after 'steinerpt' is removed.
14683  caveoldtetlist->newindex((void **) &parytet);
14684  *parytet = neightet;
14685  // Connect newface to the adjacent hull tet of 'neightet', which
14686  // has the same edge as 'newface', and does not has 'steinerpt'.
14687  fnextself(neightet);
14688  } else {
14689  if (pc == dummypoint) {
14690  if (apex(neightet) != dummypoint) {
14691  setapex(newface, apex(neightet));
14692  // A hull tet has turned into an interior tet.
14693  hullsize--; // Must update the hullsize.
14694  }
14695  }
14696  }
14697  bond(newface, neightet);
14698  } // if (newface.tet[newface.ver & 3] == NULL)
14699  enextself(newtet);
14700  senextself(newsh);
14701  } // j
14702  sesymself(newsh);
14703  } // k
14704  } // i
14705 
14706  // Unmark all new subfaces.
14707  for (i = 0; i < caveshbdlist->objects; i++) {
14708  parysh = (face *) fastlookup(caveshbdlist, i);
14709  suninfect(*parysh);
14710  }
14711  caveshbdlist->restart();
14712 
14713  if (caveoldtetlist->objects > 0l) {
14714  // Delete hull tets which contain 'steinerpt'.
14715  for (i = 0; i < caveoldtetlist->objects; i++) {
14716  parytet = (triface *) fastlookup(caveoldtetlist, i);
14717  tetrahedrondealloc(parytet->tet);
14718  }
14719  // Must update the hullsize.
14722  }
14723 
14724  setpointtype(steinerpt, UNUSEDVERTEX);
14725  unuverts++;
14726  if (vt == FREESEGVERTEX) {
14727  st_segref_count--;
14728  } else { // vt == FREEFACETVERTEX
14729  st_facref_count--;
14730  }
14731  if (steinerleft > 0) steinerleft++; // We've removed a Steiner points.
14732 
14733 
14734  point *parypt;
14735  int steinercount = 0;
14736 
14737  int bak_fliplinklevel = b->fliplinklevel;
14738  b->fliplinklevel = 100000; // Unlimited flip level.
14739 
14740  // Try to remove newly added Steiner points.
14741  for (i = 0; i < n; i++) {
14742  if (newsteiners[i] != NULL) {
14743  if (!removevertexbyflips(newsteiners[i])) {
14744  if (b->supsteiner_level > 0) { // Not -Y/0
14745  // Save it in subvertstack for removal.
14746  subvertstack->newindex((void **) &parypt);
14747  *parypt = newsteiners[i];
14748  }
14749  steinercount++;
14750  }
14751  }
14752  }
14753 
14754  b->fliplinklevel = bak_fliplinklevel;
14755 
14756  if (steinercount > 0) {
14757  if (b->verbose > 2) {
14758  printf(" Added %d interior Steiner points.\n", steinercount);
14759  }
14760  }
14761 
14762  delete [] newsteiners;
14763 
14764  return 1;
14765 }
14766 
14767 
14769 // //
14770 // suppresssteinerpoints() Suppress Steiner points. //
14771 // //
14772 // All Steiner points have been saved in 'subvertstack' in the routines //
14773 // carveholes() and suppresssteinerpoint(). //
14774 // Each Steiner point is either removed or shifted into the interior. //
14775 // //
14777 
14779 {
14780 
14781  if (!b->quiet) {
14782  printf("Suppressing Steiner points ...\n");
14783  }
14784 
14785  point rempt, *parypt;
14786 
14787  int bak_fliplinklevel = b->fliplinklevel;
14788  b->fliplinklevel = 100000; // Unlimited flip level.
14789  int suppcount = 0, remcount = 0;
14790  int i;
14791 
14792  // Try to suppress boundary Steiner points.
14793  for (i = 0; i < subvertstack->objects; i++) {
14794  parypt = (point *) fastlookup(subvertstack, i);
14795  rempt = *parypt;
14796  if (pointtype(rempt) != UNUSEDVERTEX) {
14797  if ((pointtype(rempt) == FREESEGVERTEX) ||
14798  (pointtype(rempt) == FREEFACETVERTEX)) {
14799  if (suppressbdrysteinerpoint(rempt)) {
14800  suppcount++;
14801  }
14802  }
14803  }
14804  } // i
14805 
14806  if (suppcount > 0) {
14807  if (b->verbose) {
14808  printf(" Suppressed %d boundary Steiner points.\n", suppcount);
14809  }
14810  }
14811 
14812  if (b->supsteiner_level > 0) { // -Y/1
14813  for (i = 0; i < subvertstack->objects; i++) {
14814  parypt = (point *) fastlookup(subvertstack, i);
14815  rempt = *parypt;
14816  if (pointtype(rempt) != UNUSEDVERTEX) {
14817  if (pointtype(rempt) == FREEVOLVERTEX) {
14818  if (removevertexbyflips(rempt)) {
14819  remcount++;
14820  }
14821  }
14822  }
14823  }
14824  }
14825 
14826  if (remcount > 0) {
14827  if (b->verbose) {
14828  printf(" Removed %d interior Steiner points.\n", remcount);
14829  }
14830  }
14831 
14832  b->fliplinklevel = bak_fliplinklevel;
14833 
14834  if (b->supsteiner_level > 1) { // -Y/2
14835  // Smooth interior Steiner points.
14836  optparameters opm;
14837  triface *parytet;
14838  point *ppt;
14839  REAL ori;
14840  int smtcount, count, ivcount;
14841  int nt, j;
14842 
14843  // Point smooth options.
14844  opm.max_min_volume = 1;
14845  opm.numofsearchdirs = 20;
14846  opm.searchstep = 0.001;
14847  opm.maxiter = 30; // Limit the maximum iterations.
14848 
14849  smtcount = 0;
14850 
14851  do {
14852 
14853  nt = 0;
14854 
14855  while (1) {
14856  count = 0;
14857  ivcount = 0; // Clear the inverted count.
14858 
14859  for (i = 0; i < subvertstack->objects; i++) {
14860  parypt = (point *) fastlookup(subvertstack, i);
14861  rempt = *parypt;
14862  if (pointtype(rempt) == FREEVOLVERTEX) {
14863  getvertexstar(1, rempt, cavetetlist, NULL, NULL);
14864  // Calculate the initial smallest volume (maybe zero or negative).
14865  for (j = 0; j < cavetetlist->objects; j++) {
14866  parytet = (triface *) fastlookup(cavetetlist, j);
14867  ppt = (point *) &(parytet->tet[4]);
14868  ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
14869  if (j == 0) {
14870  opm.initval = ori;
14871  } else {
14872  if (opm.initval > ori) opm.initval = ori;
14873  }
14874  }
14875  if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
14876  count++;
14877  }
14878  if (opm.imprval <= 0.0) {
14879  ivcount++; // The mesh contains inverted elements.
14880  }
14881  cavetetlist->restart();
14882  }
14883  } // i
14884 
14885  smtcount += count;
14886 
14887  if (count == 0) {
14888  // No point has been smoothed.
14889  break;
14890  }
14891 
14892  nt++;
14893  if (nt > 2) {
14894  break; // Already three iterations.
14895  }
14896  } // while
14897 
14898  if (ivcount > 0) {
14899  // There are inverted elements!
14900  if (opm.maxiter > 0) {
14901  // Set unlimited smoothing steps. Try again.
14902  opm.numofsearchdirs = 30;
14903  opm.searchstep = 0.0001;
14904  opm.maxiter = -1;
14905  continue;
14906  }
14907  }
14908 
14909  break;
14910  } while (1); // Additional loop for (ivcount > 0)
14911 
14912  if (ivcount > 0) {
14913  printf("BUG Report! The mesh contain inverted elements.\n");
14914  }
14915 
14916  if (b->verbose) {
14917  if (smtcount > 0) {
14918  printf(" Smoothed %d Steiner points.\n", smtcount);
14919  }
14920  }
14921  } // -Y2
14922 
14923  subvertstack->restart();
14924 
14925  return 1;
14926 }
14927 
14929 // //
14930 // recoverboundary() Recover segments and facets. //
14931 // //
14933 
14935 {
14936  arraypool *misseglist, *misshlist;
14937  arraypool *bdrysteinerptlist;
14938  face searchsh, *parysh;
14939  face searchseg, *paryseg;
14940  point rempt, *parypt;
14941  long ms; // The number of missing segments/subfaces.
14942  int nit; // The number of iterations.
14943  int s, i;
14944 
14945  // Counters.
14946  long bak_segref_count, bak_facref_count, bak_volref_count;
14947 
14948  if (!b->quiet) {
14949  printf("Recovering boundaries...\n");
14950  }
14951 
14952 
14953  if (b->verbose) {
14954  printf(" Recovering segments.\n");
14955  }
14956 
14957  // Segments will be introduced.
14958  checksubsegflag = 1;
14959 
14960  misseglist = new arraypool(sizeof(face), 8);
14961  bdrysteinerptlist = new arraypool(sizeof(point), 8);
14962 
14963  // In random order.
14965  for (i = 0; i < subsegs->items; i++) {
14966  s = randomnation(i + 1);
14967  // Move the s-th seg to the i-th.
14968  subsegstack->newindex((void **) &paryseg);
14969  *paryseg = * (face *) fastlookup(subsegstack, s);
14970  // Put i-th seg to be the s-th.
14971  searchseg.sh = shellfacetraverse(subsegs);
14972  paryseg = (face *) fastlookup(subsegstack, s);
14973  *paryseg = searchseg;
14974  }
14975 
14976  // The init number of missing segments.
14977  ms = subsegs->items;
14978  nit = 0;
14979  if (b->fliplinklevel < 0) {
14980  autofliplinklevel = 1; // Init value.
14981  }
14982 
14983  // First, trying to recover segments by only doing flips.
14984  while (1) {
14985  recoversegments(misseglist, 0, 0);
14986 
14987  if (misseglist->objects > 0) {
14988  if (b->fliplinklevel >= 0) {
14989  break;
14990  } else {
14991  if (misseglist->objects >= ms) {
14992  nit++;
14993  if (nit >= 3) {
14994  //break;
14995  // Do the last round with unbounded flip link level.
14996  b->fliplinklevel = 100000;
14997  }
14998  } else {
14999  ms = misseglist->objects;
15000  if (nit > 0) {
15001  nit--;
15002  }
15003  }
15004  for (i = 0; i < misseglist->objects; i++) {
15005  subsegstack->newindex((void **) &paryseg);
15006  *paryseg = * (face *) fastlookup(misseglist, i);
15007  }
15008  misseglist->restart();
15010  }
15011  } else {
15012  // All segments are recovered.
15013  break;
15014  }
15015  } // while (1)
15016 
15017  if (b->verbose) {
15018  printf(" %ld (%ld) segments are recovered (missing).\n",
15019  subsegs->items - misseglist->objects, misseglist->objects);
15020  }
15021 
15022  if (misseglist->objects > 0) {
15023  // Second, trying to recover segments by doing more flips (fullsearch).
15024  while (misseglist->objects > 0) {
15025  ms = misseglist->objects;
15026  for (i = 0; i < misseglist->objects; i++) {
15027  subsegstack->newindex((void **) &paryseg);
15028  *paryseg = * (face *) fastlookup(misseglist, i);
15029  }
15030  misseglist->restart();
15031 
15032  recoversegments(misseglist, 1, 0);
15033 
15034  if (misseglist->objects < ms) {
15035  // The number of missing segments is reduced.
15036  continue;
15037  } else {
15038  break;
15039  }
15040  }
15041  if (b->verbose) {
15042  printf(" %ld (%ld) segments are recovered (missing).\n",
15043  subsegs->items - misseglist->objects, misseglist->objects);
15044  }
15045  }
15046 
15047  if (misseglist->objects > 0) {
15048  // Third, trying to recover segments by doing more flips (fullsearch)
15049  // and adding Steiner points in the volume.
15050  while (misseglist->objects > 0) {
15051  ms = misseglist->objects;
15052  for (i = 0; i < misseglist->objects; i++) {
15053  subsegstack->newindex((void **) &paryseg);
15054  *paryseg = * (face *) fastlookup(misseglist, i);
15055  }
15056  misseglist->restart();
15057 
15058  recoversegments(misseglist, 1, 1);
15059 
15060  if (misseglist->objects < ms) {
15061  // The number of missing segments is reduced.
15062  continue;
15063  } else {
15064  break;
15065  }
15066  }
15067  if (b->verbose) {
15068  printf(" Added %ld Steiner points in volume.\n", st_volref_count);
15069  }
15070  }
15071 
15072  if (misseglist->objects > 0) {
15073  // Last, trying to recover segments by doing more flips (fullsearch),
15074  // and adding Steiner points in the volume, and splitting segments.
15075  long bak_inpoly_count = st_volref_count; //st_inpoly_count;
15076  for (i = 0; i < misseglist->objects; i++) {
15077  subsegstack->newindex((void **) &paryseg);
15078  *paryseg = * (face *) fastlookup(misseglist, i);
15079  }
15080  misseglist->restart();
15081 
15082  recoversegments(misseglist, 1, 2);
15083 
15084  if (b->verbose) {
15085  printf(" Added %ld Steiner points in segments.\n", st_segref_count);
15086  if (st_volref_count > bak_inpoly_count) {
15087  printf(" Added another %ld Steiner points in volume.\n",
15088  st_volref_count - bak_inpoly_count);
15089  }
15090  }
15091  }
15092 
15093 
15094  if (st_segref_count > 0) {
15095  // Try to remove the Steiner points added in segments.
15096  bak_segref_count = st_segref_count;
15097  bak_volref_count = st_volref_count;
15098  for (i = 0; i < subvertstack->objects; i++) {
15099  // Get the Steiner point.
15100  parypt = (point *) fastlookup(subvertstack, i);
15101  rempt = *parypt;
15102  if (!removevertexbyflips(rempt)) {
15103  // Save it in list.
15104  bdrysteinerptlist->newindex((void **) &parypt);
15105  *parypt = rempt;
15106  }
15107  }
15108  if (b->verbose) {
15109  if (st_segref_count < bak_segref_count) {
15110  if (bak_volref_count < st_volref_count) {
15111  printf(" Suppressed %ld Steiner points in segments.\n",
15112  st_volref_count - bak_volref_count);
15113  }
15114  if ((st_segref_count + (st_volref_count - bak_volref_count)) <
15115  bak_segref_count) {
15116  printf(" Removed %ld Steiner points in segments.\n",
15117  bak_segref_count -
15118  (st_segref_count + (st_volref_count - bak_volref_count)));
15119  }
15120  }
15121  }
15122  subvertstack->restart();
15123  }
15124 
15125 
15126  tv = clock();
15127 
15128  if (b->verbose) {
15129  printf(" Recovering facets.\n");
15130  }
15131 
15132  // Subfaces will be introduced.
15133  checksubfaceflag = 1;
15134 
15135  misshlist = new arraypool(sizeof(face), 8);
15136 
15137  // Randomly order the subfaces.
15139  for (i = 0; i < subfaces->items; i++) {
15140  s = randomnation(i + 1);
15141  // Move the s-th subface to the i-th.
15142  subfacstack->newindex((void **) &parysh);
15143  *parysh = * (face *) fastlookup(subfacstack, s);
15144  // Put i-th subface to be the s-th.
15145  searchsh.sh = shellfacetraverse(subfaces);
15146  parysh = (face *) fastlookup(subfacstack, s);
15147  *parysh = searchsh;
15148  }
15149 
15150  ms = subfaces->items;
15151  nit = 0;
15152  b->fliplinklevel = -1; // Init.
15153  if (b->fliplinklevel < 0) {
15154  autofliplinklevel = 1; // Init value.
15155  }
15156 
15157  while (1) {
15158  recoversubfaces(misshlist, 0);
15159 
15160  if (misshlist->objects > 0) {
15161  if (b->fliplinklevel >= 0) {
15162  break;
15163  } else {
15164  if (misshlist->objects >= ms) {
15165  nit++;
15166  if (nit >= 3) {
15167  //break;
15168  // Do the last round with unbounded flip link level.
15169  b->fliplinklevel = 100000;
15170  }
15171  } else {
15172  ms = misshlist->objects;
15173  if (nit > 0) {
15174  nit--;
15175  }
15176  }
15177  for (i = 0; i < misshlist->objects; i++) {
15178  subfacstack->newindex((void **) &parysh);
15179  *parysh = * (face *) fastlookup(misshlist, i);
15180  }
15181  misshlist->restart();
15183  }
15184  } else {
15185  // All subfaces are recovered.
15186  break;
15187  }
15188  } // while (1)
15189 
15190  if (b->verbose) {
15191  printf(" %ld (%ld) subfaces are recovered (missing).\n",
15192  subfaces->items - misshlist->objects, misshlist->objects);
15193  }
15194 
15195  if (misshlist->objects > 0) {
15196  // There are missing subfaces. Add Steiner points.
15197  for (i = 0; i < misshlist->objects; i++) {
15198  subfacstack->newindex((void **) &parysh);
15199  *parysh = * (face *) fastlookup(misshlist, i);
15200  }
15201  misshlist->restart();
15202 
15203  recoversubfaces(NULL, 1);
15204 
15205  if (b->verbose) {
15206  printf(" Added %ld Steiner points in facets.\n", st_facref_count);
15207  }
15208  }
15209 
15210 
15211  if (st_facref_count > 0) {
15212  // Try to remove the Steiner points added in facets.
15213  bak_facref_count = st_facref_count;
15214  for (i = 0; i < subvertstack->objects; i++) {
15215  // Get the Steiner point.
15216  parypt = (point *) fastlookup(subvertstack, i);
15217  rempt = *parypt;
15218  if (!removevertexbyflips(*parypt)) {
15219  // Save it in list.
15220  bdrysteinerptlist->newindex((void **) &parypt);
15221  *parypt = rempt;
15222  }
15223  }
15224  if (b->verbose) {
15225  if (st_facref_count < bak_facref_count) {
15226  printf(" Removed %ld Steiner points in facets.\n",
15227  bak_facref_count - st_facref_count);
15228  }
15229  }
15230  subvertstack->restart();
15231  }
15232 
15233 
15234  if (bdrysteinerptlist->objects > 0) {
15235  if (b->verbose) {
15236  printf(" %ld Steiner points remained in boundary.\n",
15237  bdrysteinerptlist->objects);
15238  }
15239  } // if
15240 
15241 
15242  // Accumulate the dynamic memory.
15243  totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
15244  bdrysteinerptlist->totalmemory);
15245 
15246  delete bdrysteinerptlist;
15247  delete misseglist;
15248  delete misshlist;
15249 }
15250 
15254 
15255 
15259 
15261 // //
15262 // carveholes() Remove tetrahedra not in the mesh domain. //
15263 // //
15265 
15266 
15268 {
15269  arraypool *tetarray, *hullarray;
15270  triface tetloop, neightet, *parytet, *parytet1;
15271  triface *regiontets = NULL;
15272  face checksh, *parysh;
15273  face checkseg;
15274  point ptloop, *parypt;
15275  int t1ver;
15276  int i, j, k;
15277 
15278  if (!b->quiet) {
15279  if (b->convex) {
15280  printf("Marking exterior tetrahedra ...\n");
15281  } else {
15282  printf("Removing exterior tetrahedra ...\n");
15283  }
15284  }
15285 
15286  // Initialize the pool of exterior tets.
15287  tetarray = new arraypool(sizeof(triface), 10);
15288  hullarray = new arraypool(sizeof(triface), 10);
15289 
15290  // Collect unprotected tets and hull tets.
15292  tetloop.ver = 11; // The face opposite to dummypoint.
15293  tetloop.tet = alltetrahedrontraverse();
15294  while (tetloop.tet != (tetrahedron *) NULL) {
15295  if (ishulltet(tetloop)) {
15296  // Is this side protected by a subface?
15297  if (!issubface(tetloop)) {
15298  // Collect an unprotected hull tet and tet.
15299  infect(tetloop);
15300  hullarray->newindex((void **) &parytet);
15301  *parytet = tetloop;
15302  // tetloop's face number is 11 & 3 = 3.
15303  decode(tetloop.tet[3], neightet);
15304  if (!infected(neightet)) {
15305  infect(neightet);
15306  tetarray->newindex((void **) &parytet);
15307  *parytet = neightet;
15308  }
15309  }
15310  }
15311  tetloop.tet = alltetrahedrontraverse();
15312  }
15313 
15314  if (in->numberofholes > 0) {
15315  // Mark as infected any tets inside volume holes.
15316  for (i = 0; i < 3 * in->numberofholes; i += 3) {
15317  // Search a tet containing the i-th hole point.
15318  neightet.tet = NULL;
15319  randomsample(&(in->holelist[i]), &neightet);
15320  if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
15321  // The tet 'neightet' contain this point.
15322  if (!infected(neightet)) {
15323  infect(neightet);
15324  tetarray->newindex((void **) &parytet);
15325  *parytet = neightet;
15326  // Add its adjacent tet if it is not protected.
15327  if (!issubface(neightet)) {
15328  decode(neightet.tet[neightet.ver & 3], tetloop);
15329  if (!infected(tetloop)) {
15330  infect(tetloop);
15331  if (ishulltet(tetloop)) {
15332  hullarray->newindex((void **) &parytet);
15333  } else {
15334  tetarray->newindex((void **) &parytet);
15335  }
15336  *parytet = tetloop;
15337  }
15338  }
15339  else {
15340  // It is protected. Check if its adjacent tet is a hull tet.
15341  decode(neightet.tet[neightet.ver & 3], tetloop);
15342  if (ishulltet(tetloop)) {
15343  // It is hull tet, add it into the list. Moreover, the subface
15344  // is dead, i.e., both sides are in exterior.
15345  if (!infected(tetloop)) {
15346  infect(tetloop);
15347  hullarray->newindex((void **) &parytet);
15348  *parytet = tetloop;
15349  }
15350  }
15351  if (infected(tetloop)) {
15352  // Both sides of this subface are in exterior.
15353  tspivot(neightet, checksh);
15354  sinfect(checksh); // Only queue it once.
15355  subfacstack->newindex((void **) &parysh);
15356  *parysh = checksh;
15357  }
15358  }
15359  } // if (!infected(neightet))
15360  } else {
15361  // A hole point locates outside of the convex hull.
15362  if (!b->quiet) {
15363  printf("Warning: The %d-th hole point ", i/3 + 1);
15364  printf("lies outside the convex hull.\n");
15365  }
15366  }
15367  } // i
15368  } // if (in->numberofholes > 0)
15369 
15370  if (b->regionattrib && (in->numberofregions > 0)) { // -A option.
15371  // Record the tetrahedra that contains the region points for assigning
15372  // region attributes after the holes have been carved.
15373  regiontets = new triface[in->numberofregions];
15374  // Mark as marktested any tetrahedra inside volume regions.
15375  for (i = 0; i < 5 * in->numberofregions; i += 5) {
15376  // Search a tet containing the i-th region point.
15377  neightet.tet = NULL;
15378  randomsample(&(in->regionlist[i]), &neightet);
15379  if (locate(&(in->regionlist[i]), &neightet) != OUTSIDE) {
15380  regiontets[i/5] = neightet;
15381  } else {
15382  if (!b->quiet) {
15383  printf("Warning: The %d-th region point ", i/5+1);
15384  printf("lies outside the convex hull.\n");
15385  }
15386  regiontets[i/5].tet = NULL;
15387  }
15388  }
15389  }
15390 
15391  // Collect all exterior tets (in concave place and in holes).
15392  for (i = 0; i < tetarray->objects; i++) {
15393  parytet = (triface *) fastlookup(tetarray, i);
15394  j = (parytet->ver & 3); // j is the current face number.
15395  // Check the other three adjacent tets.
15396  for (k = 1; k < 4; k++) {
15397  decode(parytet->tet[(j + k) % 4], neightet);
15398  // neightet may be a hull tet.
15399  if (!infected(neightet)) {
15400  // Is neightet protected by a subface.
15401  if (!issubface(neightet)) {
15402  // Not proected. Collect it. (It must not be a hull tet).
15403  infect(neightet);
15404  tetarray->newindex((void **) &parytet1);
15405  *parytet1 = neightet;
15406  } else {
15407  // Protected. Check if it is a hull tet.
15408  if (ishulltet(neightet)) {
15409  // A hull tet. Collect it.
15410  infect(neightet);
15411  hullarray->newindex((void **) &parytet1);
15412  *parytet1 = neightet;
15413  // Both sides of this subface are exterior.
15414  tspivot(neightet, checksh);
15415  // Queue this subface (to be deleted later).
15416  sinfect(checksh); // Only queue it once.
15417  subfacstack->newindex((void **) &parysh);
15418  *parysh = checksh;
15419  }
15420  }
15421  } else {
15422  // Both sides of this face are in exterior.
15423  // If there is a subface. It should be collected.
15424  if (issubface(neightet)) {
15425  tspivot(neightet, checksh);
15426  if (!sinfected(checksh)) {
15427  sinfect(checksh);
15428  subfacstack->newindex((void **) &parysh);
15429  *parysh = checksh;
15430  }
15431  }
15432  }
15433  } // j, k
15434  } // i
15435 
15436  if (b->regionattrib && (in->numberofregions > 0)) {
15437  // Re-check saved region tets to see if they lie outside.
15438  for (i = 0; i < in->numberofregions; i++) {
15439  if (infected(regiontets[i])) {
15440  if (b->verbose) {
15441  printf("Warning: The %d-th region point ", i+1);
15442  printf("lies in the exterior of the domain.\n");
15443  }
15444  regiontets[i].tet = NULL;
15445  }
15446  }
15447  }
15448 
15449  // Collect vertices which point to infected tets. These vertices
15450  // may get deleted after the removal of exterior tets.
15451  // If -Y1 option is used, collect all Steiner points for removal.
15452  // The lists 'cavetetvertlist' and 'subvertstack' are re-used.
15453  points->traversalinit();
15454  ptloop = pointtraverse();
15455  while (ptloop != NULL) {
15456  if ((pointtype(ptloop) != UNUSEDVERTEX) &&
15457  (pointtype(ptloop) != DUPLICATEDVERTEX)) {
15458  decode(point2tet(ptloop), neightet);
15459  if (infected(neightet)) {
15460  cavetetvertlist->newindex((void **) &parypt);
15461  *parypt = ptloop;
15462  }
15463  if (b->nobisect && (b->supsteiner_level > 0)) { // -Y/1
15464  // Queue it if it is a Steiner point.
15465  if (pointmark(ptloop) >
15466  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
15467  subvertstack->newindex((void **) &parypt);
15468  *parypt = ptloop;
15469  }
15470  }
15471  }
15472  ptloop = pointtraverse();
15473  }
15474 
15475  if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
15476  // Remove exterior tets. Hull tets are updated.
15477  arraypool *newhullfacearray;
15478  triface hulltet, casface;
15479  face segloop, *paryseg;
15480  point pa, pb, pc;
15481  long delsegcount = 0l;
15482 
15483  // Collect segments which point to infected tets. Some segments
15484  // may get deleted after the removal of exterior tets.
15486  segloop.sh = shellfacetraverse(subsegs);
15487  while (segloop.sh != NULL) {
15488  sstpivot1(segloop, neightet);
15489  if (infected(neightet)) {
15490  subsegstack->newindex((void **) &paryseg);
15491  *paryseg = segloop;
15492  }
15493  segloop.sh = shellfacetraverse(subsegs);
15494  }
15495 
15496  newhullfacearray = new arraypool(sizeof(triface), 10);
15497 
15498  // Create and save new hull tets.
15499  for (i = 0; i < tetarray->objects; i++) {
15500  parytet = (triface *) fastlookup(tetarray, i);
15501  for (j = 0; j < 4; j++) {
15502  decode(parytet->tet[j], tetloop);
15503  if (!infected(tetloop)) {
15504  // Found a new hull face (must be a subface).
15505  tspivot(tetloop, checksh);
15506  maketetrahedron(&hulltet);
15507  pa = org(tetloop);
15508  pb = dest(tetloop);
15509  pc = apex(tetloop);
15510  setvertices(hulltet, pb, pa, pc, dummypoint);
15511  bond(tetloop, hulltet);
15512  // Update the subface-to-tet map.
15513  sesymself(checksh);
15514  tsbond(hulltet, checksh);
15515  // Update the segment-to-tet map.
15516  for (k = 0; k < 3; k++) {
15517  if (issubseg(tetloop)) {
15518  tsspivot1(tetloop, checkseg);
15519  tssbond1(hulltet, checkseg);
15520  sstbond1(checkseg, hulltet);
15521  }
15522  enextself(tetloop);
15523  eprevself(hulltet);
15524  }
15525  // Update the point-to-tet map.
15526  setpoint2tet(pa, (tetrahedron) tetloop.tet);
15527  setpoint2tet(pb, (tetrahedron) tetloop.tet);
15528  setpoint2tet(pc, (tetrahedron) tetloop.tet);
15529  // Save the exterior tet at this hull face. It still holds pointer
15530  // to the adjacent interior tet. Use it to connect new hull tets.
15531  newhullfacearray->newindex((void **) &parytet1);
15532  parytet1->tet = parytet->tet;
15533  parytet1->ver = j;
15534  } // if (!infected(tetloop))
15535  } // j
15536  } // i
15537 
15538  // Connect new hull tets.
15539  for (i = 0; i < newhullfacearray->objects; i++) {
15540  parytet = (triface *) fastlookup(newhullfacearray, i);
15541  fsym(*parytet, neightet);
15542  // Get the new hull tet.
15543  fsym(neightet, hulltet);
15544  for (j = 0; j < 3; j++) {
15545  esym(hulltet, casface);
15546  if (casface.tet[casface.ver & 3] == NULL) {
15547  // Since the boundary of the domain may not be a manifold, we
15548  // find the adjacent hull face by traversing the tets in the
15549  // exterior (which are all infected tets).
15550  neightet = *parytet;
15551  while (1) {
15552  fnextself(neightet);
15553  if (!infected(neightet)) break;
15554  }
15555  if (!ishulltet(neightet)) {
15556  // An interior tet. Get the new hull tet.
15557  fsymself(neightet);
15558  esymself(neightet);
15559  }
15560  // Bond them together.
15561  bond(casface, neightet);
15562  }
15563  enextself(hulltet);
15564  enextself(*parytet);
15565  } // j
15566  } // i
15567 
15568  if (subfacstack->objects > 0l) {
15569  // Remove all subfaces which do not attach to any tetrahedron.
15570  // Segments which are not attached to any subfaces and tets
15571  // are deleted too.
15572  face casingout, casingin;
15573 
15574  for (i = 0; i < subfacstack->objects; i++) {
15575  parysh = (face *) fastlookup(subfacstack, i);
15576  if (i == 0) {
15577  if (b->verbose) {
15578  printf("Warning: Removed an exterior face (%d, %d, %d) #%d\n",
15579  pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
15580  pointmark(sapex(*parysh)), shellmark(*parysh));
15581  }
15582  }
15583  // Dissolve this subface from face links.
15584  for (j = 0; j < 3; j++) {
15585  spivot(*parysh, casingout);
15586  sspivot(*parysh, checkseg);
15587  if (casingout.sh != NULL) {
15588  casingin = casingout;
15589  while (1) {
15590  spivot(casingin, checksh);
15591  if (checksh.sh == parysh->sh) break;
15592  casingin = checksh;
15593  }
15594  if (casingin.sh != casingout.sh) {
15595  // Update the link: ... -> casingin -> casingout ->...
15596  sbond1(casingin, casingout);
15597  } else {
15598  // Only one subface at this edge is left.
15599  sdissolve(casingout);
15600  }
15601  if (checkseg.sh != NULL) {
15602  // Make sure the segment does not connect to a dead one.
15603  ssbond(casingout, checkseg);
15604  }
15605  } else {
15606  if (checkseg.sh != NULL) {
15607  //if (checkseg.sh[3] != NULL) {
15608  if (delsegcount == 0) {
15609  if (b->verbose) {
15610  printf("Warning: Removed an exterior segment (%d, %d) #%d\n",
15611  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
15612  shellmark(checkseg));
15613  }
15614  }
15615  shellfacedealloc(subsegs, checkseg.sh);
15616  delsegcount++;
15617  }
15618  }
15619  senextself(*parysh);
15620  } // j
15621  // Delete this subface.
15622  shellfacedealloc(subfaces, parysh->sh);
15623  } // i
15624  if (b->verbose) {
15625  printf(" Deleted %ld subfaces.\n", subfacstack->objects);
15626  }
15627  subfacstack->restart();
15628  } // if (subfacstack->objects > 0l)
15629 
15630  if (subsegstack->objects > 0l) {
15631  for (i = 0; i < subsegstack->objects; i++) {
15632  paryseg = (face *) fastlookup(subsegstack, i);
15633  if (paryseg->sh && (paryseg->sh[3] != NULL)) {
15634  sstpivot1(*paryseg, neightet);
15635  if (infected(neightet)) {
15636  if (b->verbose) {
15637  printf("Warning: Removed an exterior segment (%d, %d) #%d\n",
15638  pointmark(sorg(*paryseg)), pointmark(sdest(*paryseg)),
15639  shellmark(*paryseg));
15640  }
15641  shellfacedealloc(subsegs, paryseg->sh);
15642  delsegcount++;
15643  }
15644  }
15645  }
15646  subsegstack->restart();
15647  } // if (subsegstack->objects > 0l)
15648 
15649  if (delsegcount > 0) {
15650  if (b->verbose) {
15651  printf(" Deleted %ld segments.\n", delsegcount);
15652  }
15653  }
15654 
15655  if (cavetetvertlist->objects > 0l) {
15656  // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
15657  long delvertcount = unuverts;
15658  long delsteinercount = 0l;
15659 
15660  for (i = 0; i < cavetetvertlist->objects; i++) {
15661  parypt = (point *) fastlookup(cavetetvertlist, i);
15662  decode(point2tet(*parypt), neightet);
15663  if (infected(neightet)) {
15664  // Found an exterior vertex.
15665  if (pointmark(*parypt) >
15666  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
15667  // A Steiner point.
15668  if (pointtype(*parypt) == FREESEGVERTEX) {
15669  st_segref_count--;
15670  } else if (pointtype(*parypt) == FREEFACETVERTEX) {
15671  st_facref_count--;
15672  } else {
15673  st_volref_count--;
15674  }
15675  delsteinercount++;
15676  if (steinerleft > 0) steinerleft++;
15677  }
15678  setpointtype(*parypt, UNUSEDVERTEX);
15679  unuverts++;
15680  }
15681  }
15682 
15683  if (b->verbose) {
15684  if (unuverts > delvertcount) {
15685  if (delsteinercount > 0l) {
15686  if (unuverts > (delvertcount + delsteinercount)) {
15687  printf(" Removed %ld exterior input vertices.\n",
15688  unuverts - delvertcount - delsteinercount);
15689  }
15690  printf(" Removed %ld exterior Steiner vertices.\n",
15691  delsteinercount);
15692  } else {
15693  printf(" Removed %ld exterior input vertices.\n",
15694  unuverts - delvertcount);
15695  }
15696  }
15697  }
15699  // Comment: 'subvertstack' will be cleaned in routine
15700  // suppresssteinerpoints().
15701  } // if (cavetetvertlist->objects > 0l)
15702 
15703  // Update the hull size.
15704  hullsize += (newhullfacearray->objects - hullarray->objects);
15705 
15706  // Delete all exterior tets and old hull tets.
15707  for (i = 0; i < tetarray->objects; i++) {
15708  parytet = (triface *) fastlookup(tetarray, i);
15709  tetrahedrondealloc(parytet->tet);
15710  }
15711  tetarray->restart();
15712 
15713  for (i = 0; i < hullarray->objects; i++) {
15714  parytet = (triface *) fastlookup(hullarray, i);
15715  tetrahedrondealloc(parytet->tet);
15716  }
15717  hullarray->restart();
15718 
15719  delete newhullfacearray;
15720  } // if (!b->convex && (tetarray->objects > 0l))
15721 
15722  if (b->convex && (tetarray->objects > 0l)) { // With -c option
15723  // In this case, all exterior tets get a region marker '-1'.
15724  int attrnum = numelemattrib - 1;
15725 
15726  for (i = 0; i < tetarray->objects; i++) {
15727  parytet = (triface *) fastlookup(tetarray, i);
15728  setelemattribute(parytet->tet, attrnum, -1);
15729  }
15730  tetarray->restart();
15731 
15732  for (i = 0; i < hullarray->objects; i++) {
15733  parytet = (triface *) fastlookup(hullarray, i);
15734  uninfect(*parytet);
15735  }
15736  hullarray->restart();
15737 
15738  if (subfacstack->objects > 0l) {
15739  for (i = 0; i < subfacstack->objects; i++) {
15740  parysh = (face *) fastlookup(subfacstack, i);
15741  suninfect(*parysh);
15742  }
15743  subfacstack->restart();
15744  }
15745 
15746  if (cavetetvertlist->objects > 0l) {
15748  }
15749  } // if (b->convex && (tetarray->objects > 0l))
15750 
15751  if (b->regionattrib) { // With -A option.
15752  if (!b->quiet) {
15753  printf("Spreading region attributes.\n");
15754  }
15755  REAL volume;
15756  int attr, maxattr = 0; // Choose a small number here.
15757  int attrnum = numelemattrib - 1;
15758  // Comment: The element region marker is at the end of the list of
15759  // the element attributes.
15760  int regioncount = 0;
15761 
15762  // If has user-defined region attributes.
15763  if (in->numberofregions > 0) {
15764  // Spread region attributes.
15765  for (i = 0; i < 5 * in->numberofregions; i += 5) {
15766  if (regiontets[i/5].tet != NULL) {
15767  attr = (int) in->regionlist[i + 3];
15768  if (attr > maxattr) {
15769  maxattr = attr;
15770  }
15771  volume = in->regionlist[i + 4];
15772  tetarray->restart(); // Re-use this array.
15773  infect(regiontets[i/5]);
15774  tetarray->newindex((void **) &parytet);
15775  *parytet = regiontets[i/5];
15776  // Collect and set attrs for all tets of this region.
15777  for (j = 0; j < tetarray->objects; j++) {
15778  parytet = (triface *) fastlookup(tetarray, j);
15779  tetloop = *parytet;
15780  setelemattribute(tetloop.tet, attrnum, attr);
15781  if (b->varvolume) { // If has -a option.
15782  setvolumebound(tetloop.tet, volume);
15783  }
15784  for (k = 0; k < 4; k++) {
15785  decode(tetloop.tet[k], neightet);
15786  // Is the adjacent already checked?
15787  if (!infected(neightet)) {
15788  // Is this side protected by a subface?
15789  if (!issubface(neightet)) {
15790  infect(neightet);
15791  tetarray->newindex((void **) &parytet);
15792  *parytet = neightet;
15793  }
15794  }
15795  } // k
15796  } // j
15797  regioncount++;
15798  } // if (regiontets[i/5].tet != NULL)
15799  } // i
15800  }
15801 
15802  // Set attributes for all tetrahedra.
15803  attr = maxattr + 1;
15805  tetloop.tet = tetrahedrontraverse();
15806  while (tetloop.tet != (tetrahedron *) NULL) {
15807  if (!infected(tetloop)) {
15808  // An unmarked region.
15809  tetarray->restart(); // Re-use this array.
15810  infect(tetloop);
15811  tetarray->newindex((void **) &parytet);
15812  *parytet = tetloop;
15813  // Find and mark all tets.
15814  for (j = 0; j < tetarray->objects; j++) {
15815  parytet = (triface *) fastlookup(tetarray, j);
15816  tetloop = *parytet;
15817  setelemattribute(tetloop.tet, attrnum, attr);
15818  for (k = 0; k < 4; k++) {
15819  decode(tetloop.tet[k], neightet);
15820  // Is the adjacent tet already checked?
15821  if (!infected(neightet)) {
15822  // Is this side protected by a subface?
15823  if (!issubface(neightet)) {
15824  infect(neightet);
15825  tetarray->newindex((void **) &parytet);
15826  *parytet = neightet;
15827  }
15828  }
15829  } // k
15830  } // j
15831  attr++; // Increase the attribute.
15832  regioncount++;
15833  }
15834  tetloop.tet = tetrahedrontraverse();
15835  }
15836  // Until here, every tet has a region attribute.
15837 
15838  // Uninfect processed tets.
15840  tetloop.tet = tetrahedrontraverse();
15841  while (tetloop.tet != (tetrahedron *) NULL) {
15842  uninfect(tetloop);
15843  tetloop.tet = tetrahedrontraverse();
15844  }
15845 
15846  if (b->verbose) {
15847  //assert(regioncount > 0);
15848  if (regioncount > 1) {
15849  printf(" Found %d subdomains.\n", regioncount);
15850  } else {
15851  printf(" Found %d domain.\n", regioncount);
15852  }
15853  }
15854  } // if (b->regionattrib)
15855 
15856  if (regiontets != NULL) {
15857  delete [] regiontets;
15858  }
15859  delete tetarray;
15860  delete hullarray;
15861 
15862  if (!b->convex) { // No -c option
15863  // The mesh is non-convex now.
15864  nonconvex = 1;
15865 
15866  // Push all hull tets into 'flipstack'.
15868  tetloop.ver = 11; // The face opposite to dummypoint.
15869  tetloop.tet = alltetrahedrontraverse();
15870  while (tetloop.tet != (tetrahedron *) NULL) {
15871  if ((point) tetloop.tet[7] == dummypoint) {
15872  fsym(tetloop, neightet);
15873  flippush(flipstack, &neightet);
15874  }
15875  tetloop.tet = alltetrahedrontraverse();
15876  }
15877 
15879  fc.enqflag = 2;
15880  long sliver_peel_count = lawsonflip3d(&fc);
15881 
15882  if (sliver_peel_count > 0l) {
15883  if (b->verbose) {
15884  printf(" Removed %ld hull slivers.\n", sliver_peel_count);
15885  }
15886  }
15887  unflipqueue->restart();
15888  } // if (!b->convex)
15889 }
15890 
15892 // //
15893 // enqueuesubface() Queue a subface or a subsegment for encroachment chk. //
15894 // //
15896 
15898 {
15899  if (!smarktest2ed(*chkface)) {
15900  smarktest2(*chkface); // Only queue it once.
15901  face *queface = (face *) pool->alloc();
15902  *queface = *chkface;
15903  }
15904 }
15905 
15907 // //
15908 // enqueuetetrahedron() Queue a tetrahedron for quality check. //
15909 // //
15911 
15913 {
15914  if (!marktest2ed(*chktet)) {
15915  marktest2(*chktet); // Only queue it once.
15916  triface *quetet = (triface *) badtetrahedrons->alloc();
15917  *quetet = *chktet;
15918  }
15919 }
15920 
15924 
15926 // //
15927 // lawsonflip3d() A three-dimensional Lawson's algorithm. //
15928 // //
15930 
15932 {
15933  triface fliptets[5], neightet, hulltet;
15934  face checksh, casingout;
15935  badface *popface, *bface;
15936  point pd, pe, *pts;
15937  REAL sign, ori;
15938  REAL vol, len3;
15939  long flipcount, totalcount = 0l;
15940  long sliver_peels = 0l;
15941  int t1ver;
15942  int i;
15943 
15944  size_t loopCount = 0;
15945  while (1) {
15946 
15947  if (b->verbose > 2) {
15948  printf(" Lawson flip %ld faces.\n", flippool->items);
15949  }
15950  flipcount = 0l;
15951 
15952  while (flipstack != (badface *) NULL) {
15953  // Pop a face from the stack.
15954  popface = flipstack;
15955  fliptets[0] = popface->tt;
15956  flipstack = flipstack->nextitem; // The next top item in stack.
15957  flippool->dealloc((void *) popface);
15958 
15959  // Skip it if it is a dead tet (destroyed by previous flips).
15960  if (isdeadtet(fliptets[0])) continue;
15961  // Skip it if it is not the same tet as we saved.
15962  if (!facemarked(fliptets[0])) continue;
15963 
15964  unmarkface(fliptets[0]);
15965 
15966  if (ishulltet(fliptets[0])) continue;
15967 
15968  fsym(fliptets[0], fliptets[1]);
15969  if (ishulltet(fliptets[1])) {
15970  if (nonconvex) {
15971  // Check if 'fliptets[0]' it is a hull sliver.
15972  tspivot(fliptets[0], checksh);
15973  for (i = 0; i < 3; i++) {
15974  if (!isshsubseg(checksh)) {
15975  spivot(checksh, casingout);
15976  //assert(casingout.sh != NULL);
15977  if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
15978  stpivot(casingout, neightet);
15979  if (neightet.tet == fliptets[0].tet) {
15980  // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where
15981  // [e,d,a] and [d,e,b] are hull faces.
15982  edestoppo(neightet, hulltet); // [a,b,e,d]
15983  fsymself(hulltet); // [b,a,e,#]
15984  if (oppo(hulltet) == dummypoint) {
15985  pe = org(neightet);
15986  if ((pointtype(pe) == FREEFACETVERTEX) ||
15987  (pointtype(pe) == FREESEGVERTEX)) {
15988  removevertexbyflips(pe);
15989  }
15990  } else {
15991  eorgoppo(neightet, hulltet); // [b,a,d,e]
15992  fsymself(hulltet); // [a,b,d,#]
15993  if (oppo(hulltet) == dummypoint) {
15994  pd = dest(neightet);
15995  if ((pointtype(pd) == FREEFACETVERTEX) ||
15996  (pointtype(pd) == FREESEGVERTEX)) {
15997  removevertexbyflips(pd);
15998  }
15999  } else {
16000  // Perform a 3-to-2 flip to remove the sliver.
16001  fliptets[0] = neightet; // [e,d,a,b]
16002  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
16003  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
16004  flip32(fliptets, 1, fc);
16005  // Update counters.
16006  flip32count--;
16007  flip22count--;
16008  sliver_peels++;
16009  if (fc->remove_ndelaunay_edge) {
16010  // Update the volume (must be decreased).
16011  //assert(fc->tetprism_vol_sum <= 0);
16012  tetprism_vol_sum += fc->tetprism_vol_sum;
16013  fc->tetprism_vol_sum = 0.0; // Clear it.
16014  }
16015  }
16016  }
16017  break;
16018  } // if (neightet.tet == fliptets[0].tet)
16019  } // if (!isshsubseg(checksh))
16020  senextself(checksh);
16021  } // i
16022  } // if (nonconvex)
16023  continue;
16024  }
16025 
16026  if (checksubfaceflag) {
16027  // Do not flip if it is a subface.
16028  if (issubface(fliptets[0])) continue;
16029  }
16030 
16031  // Test whether the face is locally Delaunay or not.
16032  pts = (point *) fliptets[1].tet;
16033  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
16034 
16035  if (sign < 0) {
16036  // A non-Delaunay face. Try to flip it.
16037  pd = oppo(fliptets[0]);
16038  pe = oppo(fliptets[1]);
16039 
16040  // Use the length of the edge [d,e] as a reference to determine
16041  // a nearly degenerated new tet.
16042  len3 = distance(pd, pe);
16043  len3 = (len3 * len3 * len3);
16044 
16045  // Check the convexity of its three edges. Stop checking either a
16046  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
16047  // encountered, and 'fliptet' represents that edge.
16048  for (i = 0; i < 3; i++) {
16049  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
16050  if (ori > 0) {
16051  // Avoid creating a nearly degenerated new tet at boundary.
16052  // Re-use fliptets[2], fliptets[3];
16053  esym(fliptets[0], fliptets[2]);
16054  esym(fliptets[1], fliptets[3]);
16055  if (issubface(fliptets[2]) || issubface(fliptets[3])) {
16056  vol = orient3dfast(org(fliptets[0]), dest(fliptets[0]), pd, pe);
16057  if ((fabs(vol) / len3) < b->epsilon) {
16058  ori = 0.0; // Do rounding.
16059  }
16060  }
16061  } // Rounding check
16062  if (ori <= 0) break;
16063  enextself(fliptets[0]);
16064  eprevself(fliptets[1]);
16065  }
16066 
16067  if (ori > 0) {
16068  // A 2-to-3 flip is found.
16069  // [0] [a,b,c,d],
16070  // [1] [b,a,c,e]. no dummypoint.
16071  flip23(fliptets, 0, fc);
16072  flipcount++;
16073  if (fc->remove_ndelaunay_edge) {
16074  // Update the volume (must be decreased).
16075  //assert(fc->tetprism_vol_sum <= 0);
16076  tetprism_vol_sum += fc->tetprism_vol_sum;
16077  fc->tetprism_vol_sum = 0.0; // Clear it.
16078  }
16079  continue;
16080  } else { // ori <= 0
16081  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
16082  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
16083  if (checksubsegflag) {
16084  // Do not flip if it is a segment.
16085  if (issubseg(fliptets[0])) continue;
16086  }
16087  // Check if there are three or four tets sharing at this edge.
16088  esymself(fliptets[0]); // [b,a,d,c]
16089  for (i = 0; i < 3; i++) {
16090  fnext(fliptets[i], fliptets[i+1]);
16091  }
16092  if (fliptets[3].tet == fliptets[0].tet) {
16093  // A 3-to-2 flip is found. (No hull tet.)
16094  flip32(fliptets, 0, fc);
16095  flipcount++;
16096  if (fc->remove_ndelaunay_edge) {
16097  // Update the volume (must be decreased).
16098  //assert(fc->tetprism_vol_sum <= 0);
16099  tetprism_vol_sum += fc->tetprism_vol_sum;
16100  fc->tetprism_vol_sum = 0.0; // Clear it.
16101  }
16102  continue;
16103  } else {
16104  // There are more than 3 tets at this edge.
16105  fnext(fliptets[3], fliptets[4]);
16106  if (fliptets[4].tet == fliptets[0].tet) {
16107  // There are exactly 4 tets at this edge.
16108  if (nonconvex) {
16109  if (apex(fliptets[3]) == dummypoint) {
16110  // This edge is locally non-convex on the hull.
16111  // It can be removed by a 4-to-4 flip.
16112  ori = 0;
16113  }
16114  } // if (nonconvex)
16115  if (ori == 0) {
16116  // A 4-to-4 flip is found. (Two hull tets may be involved.)
16117  // Current tets in 'fliptets':
16118  // [0] [b,a,d,c] (d may be newpt)
16119  // [1] [b,a,c,e]
16120  // [2] [b,a,e,f] (f may be dummypoint)
16121  // [3] [b,a,f,d]
16122  esymself(fliptets[0]); // [a,b,c,d]
16123  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
16124  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
16125  // It will be removed by the followed 3-to-2 flip.
16126  flip23(fliptets, 0, fc); // No hull tet.
16127  fnext(fliptets[3], fliptets[1]);
16128  fnext(fliptets[1], fliptets[2]);
16129  // Current tets in 'fliptets':
16130  // [0] [...]
16131  // [1] [b,a,d,e] (degenerated, d may be new point).
16132  // [2] [b,a,e,f] (f may be dummypoint)
16133  // [3] [b,a,f,d]
16134  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
16135  // Hull tets may be involved (f may be dummypoint).
16136  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
16137  flipcount++;
16138  flip23count--;
16139  flip32count--;
16140  flip44count++;
16141  if (fc->remove_ndelaunay_edge) {
16142  // Update the volume (must be decreased).
16143  //assert(fc->tetprism_vol_sum <= 0);
16144  tetprism_vol_sum += fc->tetprism_vol_sum;
16145  fc->tetprism_vol_sum = 0.0; // Clear it.
16146  }
16147  continue;
16148  } // if (ori == 0)
16149  }
16150  }
16151  } // if (ori <= 0)
16152 
16153  // This non-Delaunay face is unflippable. Save it.
16154  unflipqueue->newindex((void **) &bface);
16155  bface->tt = fliptets[0];
16156  bface->forg = org(fliptets[0]);
16157  bface->fdest = dest(fliptets[0]);
16158  bface->fapex = apex(fliptets[0]);
16159  } // if (sign < 0)
16160  } // while (flipstack)
16161 
16162  if (b->verbose > 2) {
16163  if (flipcount > 0) {
16164  printf(" Performed %ld flips.\n", flipcount);
16165  }
16166  }
16167  // Accumulate the counter of flips.
16168  totalcount += flipcount;
16169 
16170  // Return if no unflippable faces left.
16171  if (unflipqueue->objects == 0l) break;
16172  // Return if no flip has been performed.
16173  if (flipcount == 0l) break;
16174 
16175  // Try to flip the unflippable faces.
16176  for (i = 0; i < unflipqueue->objects; i++) {
16177  bface = (badface *) fastlookup(unflipqueue, i);
16178  if (!isdeadtet(bface->tt) &&
16179  (org(bface->tt) == bface->forg) &&
16180  (dest(bface->tt) == bface->fdest) &&
16181  (apex(bface->tt) == bface->fapex)) {
16182  flippush(flipstack, &(bface->tt));
16183  }
16184  }
16185  unflipqueue->restart();
16186 
16187  // Highest loopCount encountered in a valid testcase is 4. For values
16188  // much higher than that, we are likely stuck in an infinite loop.
16189  const size_t surelyHangingLoopCountThreshold = 10000;
16190  if (loopCount > surelyHangingLoopCountThreshold)
16191  {
16192  terminatetetgen(this, 1000);
16193  }
16194  loopCount++;
16195 
16196  } // while (1)
16197 
16198  if (b->verbose > 2) {
16199  if (totalcount > 0) {
16200  printf(" Performed %ld flips.\n", totalcount);
16201  }
16202  if (sliver_peels > 0) {
16203  printf(" Removed %ld hull slivers.\n", sliver_peels);
16204  }
16205  if (unflipqueue->objects > 0l) {
16206  printf(" %ld unflippable edges remained.\n", unflipqueue->objects);
16207  }
16208  }
16209 
16210  return totalcount + sliver_peels;
16211 }
16212 
16214 // //
16215 // recoverdelaunay() Recovery the locally Delaunay property. //
16216 // //
16218 
16220 {
16221  arraypool *flipqueue, *nextflipqueue, *swapqueue;
16222  triface tetloop, neightet, *parytet;
16223  badface *bface, *parybface;
16224  point *ppt;
16226  int i, j;
16227 
16228  if (!b->quiet) {
16229  printf("Recovering Delaunayness...\n");
16230  }
16231 
16232  tetprism_vol_sum = 0.0; // Initialize it.
16233 
16234  // Put all interior faces of the mesh into 'flipstack'.
16236  tetloop.tet = tetrahedrontraverse();
16237  while (tetloop.tet != NULL) {
16238  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
16239  decode(tetloop.tet[tetloop.ver], neightet);
16240  if (!facemarked(neightet)) {
16241  flippush(flipstack, &tetloop);
16242  }
16243  }
16244  ppt = (point *) &(tetloop.tet[4]);
16245  tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
16246  tetloop.tet = tetrahedrontraverse();
16247  }
16248 
16249  // Calulate a relatively lower bound for small improvement.
16250  // Used to avoid rounding error in volume calculation.
16251  fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
16252 
16253  if (b->verbose) {
16254  printf(" Initial obj = %.17g\n", tetprism_vol_sum);
16255  }
16256 
16257  if (b->verbose > 1) {
16258  printf(" Recover Delaunay [Lawson] : %ld\n", flippool->items);
16259  }
16260 
16261  // First only use the basic Lawson's flip.
16262  fc.remove_ndelaunay_edge = 1;
16263  fc.enqflag = 2;
16264 
16265  lawsonflip3d(&fc);
16266 
16267  if (b->verbose > 1) {
16268  printf(" obj (after Lawson) = %.17g\n", tetprism_vol_sum);
16269  }
16270 
16271  if (unflipqueue->objects == 0l) {
16272  return; // The mesh is Delaunay.
16273  }
16274 
16275  fc.unflip = 1; // Unflip if the edge is not flipped.
16276  fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
16277  fc.enqflag = 0;
16278 
16279  autofliplinklevel = 1; // Init level.
16280  b->fliplinklevel = -1; // No fixed level.
16281 
16282  // For efficiency reason, we limit the maximium size of the edge star.
16283  int bakmaxflipstarsize = b->flipstarsize;
16284  b->flipstarsize = 10; // default
16285 
16286  flipqueue = new arraypool(sizeof(badface), 10);
16287  nextflipqueue = new arraypool(sizeof(badface), 10);
16288 
16289  // Swap the two flip queues.
16290  swapqueue = flipqueue;
16291  flipqueue = unflipqueue;
16292  unflipqueue = swapqueue;
16293 
16294  while (flipqueue->objects > 0l) {
16295 
16296  if (b->verbose > 1) {
16297  printf(" Recover Delaunay [level = %2d] #: %ld.\n",
16298  autofliplinklevel, flipqueue->objects);
16299  }
16300 
16301  for (i = 0; i < flipqueue->objects; i++) {
16302  bface = (badface *) fastlookup(flipqueue, i);
16303  if (getedge(bface->forg, bface->fdest, &bface->tt)) {
16304  if (removeedgebyflips(&(bface->tt), &fc) == 2) {
16305  tetprism_vol_sum += fc.tetprism_vol_sum;
16306  fc.tetprism_vol_sum = 0.0; // Clear it.
16307  // Queue new faces for flips.
16308  for (j = 0; j < cavetetlist->objects; j++) {
16309  parytet = (triface *) fastlookup(cavetetlist, j);
16310  // A queued new tet may be dead.
16311  if (!isdeadtet(*parytet)) {
16312  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
16313  // Avoid queue a face twice.
16314  decode(parytet->tet[parytet->ver], neightet);
16315  if (!facemarked(neightet)) {
16316  flippush(flipstack, parytet);
16317  }
16318  } // parytet->ver
16319  }
16320  } // j
16321  cavetetlist->restart();
16322  // Remove locally non-Delaunay faces. New non-Delaunay edges
16323  // may be found. They are saved in 'unflipqueue'.
16324  fc.enqflag = 2;
16325  lawsonflip3d(&fc);
16326  fc.enqflag = 0;
16327  // There may be unflipable faces. Add them in flipqueue.
16328  for (j = 0; j < unflipqueue->objects; j++) {
16329  bface = (badface *) fastlookup(unflipqueue, j);
16330  flipqueue->newindex((void **) &parybface);
16331  *parybface = *bface;
16332  }
16333  unflipqueue->restart();
16334  } else {
16335  // Unable to remove this edge. Save it.
16336  nextflipqueue->newindex((void **) &parybface);
16337  *parybface = *bface;
16338  // Normally, it should be zero.
16339  //assert(fc.tetprism_vol_sum == 0.0);
16340  // However, due to rounding errors, a tiny value may appear.
16341  fc.tetprism_vol_sum = 0.0;
16342  }
16343  }
16344  } // i
16345 
16346  if (b->verbose > 1) {
16347  printf(" obj (after level %d) = %.17g.\n", autofliplinklevel,
16349  }
16350  flipqueue->restart();
16351 
16352  // Swap the two flip queues.
16353  swapqueue = flipqueue;
16354  flipqueue = nextflipqueue;
16355  nextflipqueue = swapqueue;
16356 
16357  if (flipqueue->objects > 0l) {
16358  // default 'b->delmaxfliplevel' is 1.
16360  // For efficiency reason, we do not search too far.
16361  break;
16362  }
16364  }
16365  } // while (flipqueue->objects > 0l)
16366 
16367  if (flipqueue->objects > 0l) {
16368  if (b->verbose > 1) {
16369  printf(" %ld non-Delaunay edges remained.\n", flipqueue->objects);
16370  }
16371  }
16372 
16373  if (b->verbose) {
16374  printf(" Final obj = %.17g\n", tetprism_vol_sum);
16375  }
16376 
16377  b->flipstarsize = bakmaxflipstarsize;
16378  delete flipqueue;
16379  delete nextflipqueue;
16380 }
16381 
16383 // //
16384 // gettetrahedron() Get a tetrahedron which have the given vertices. //
16385 // //
16387 
16389  triface *searchtet)
16390 {
16391  triface spintet;
16392  int t1ver;
16393 
16394  if (getedge(pa, pb, searchtet)) {
16395  spintet = *searchtet;
16396  while (1) {
16397  if (apex(spintet) == pc) {
16398  *searchtet = spintet;
16399  break;
16400  }
16401  fnextself(spintet);
16402  if (spintet.tet == searchtet->tet) break;
16403  }
16404  if (apex(*searchtet) == pc) {
16405  if (oppo(*searchtet) == pd) {
16406  return 1;
16407  } else {
16408  fsymself(*searchtet);
16409  if (oppo(*searchtet) == pd) {
16410  return 1;
16411  }
16412  }
16413  }
16414  }
16415 
16416  return 0;
16417 }
16418 
16420 // //
16421 // improvequalitybyflips() Improve the mesh quality by flips. //
16422 // //
16424 
16426 {
16427  arraypool *flipqueue, *nextflipqueue, *swapqueue;
16428  badface *bface, *parybface;
16429  triface *parytet;
16430  point *ppt;
16432  REAL *cosdd, ncosdd[6], maxdd;
16433  long totalremcount, remcount;
16434  int remflag;
16435  int n, i, j, k;
16436 
16437  //assert(unflipqueue->objects > 0l);
16438  flipqueue = new arraypool(sizeof(badface), 10);
16439  nextflipqueue = new arraypool(sizeof(badface), 10);
16440 
16441  // Backup flip edge options.
16442  int bakautofliplinklevel = autofliplinklevel;
16443  int bakfliplinklevel = b->fliplinklevel;
16444  int bakmaxflipstarsize = b->flipstarsize;
16445 
16446  // Set flip edge options.
16447  autofliplinklevel = 1;
16448  b->fliplinklevel = -1;
16449  b->flipstarsize = 10; // b->optmaxflipstarsize;
16450 
16451  fc.remove_large_angle = 1;
16452  fc.unflip = 1;
16453  fc.collectnewtets = 1;
16454  fc.checkflipeligibility = 1;
16455 
16456  totalremcount = 0l;
16457 
16458  // Swap the two flip queues.
16459  swapqueue = flipqueue;
16460  flipqueue = unflipqueue;
16461  unflipqueue = swapqueue;
16462 
16463  while (flipqueue->objects > 0l) {
16464 
16465  remcount = 0l;
16466 
16467  while (flipqueue->objects > 0l) {
16468  if (b->verbose > 1) {
16469  printf(" Improving mesh qualiy by flips [%d]#: %ld.\n",
16470  autofliplinklevel, flipqueue->objects);
16471  }
16472 
16473  for (k = 0; k < flipqueue->objects; k++) {
16474  bface = (badface *) fastlookup(flipqueue, k);
16475  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
16476  bface->foppo, &bface->tt)) {
16477  //assert(!ishulltet(bface->tt));
16478  // There are bad dihedral angles in this tet.
16479  if (bface->tt.ver != 11) {
16480  // The dihedral angles are permuted.
16481  // Here we simply re-compute them. Slow!!.
16482  ppt = (point *) & (bface->tt.tet[4]);
16483  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
16484  &bface->key, NULL);
16485  bface->forg = ppt[0];
16486  bface->fdest = ppt[1];
16487  bface->fapex = ppt[2];
16488  bface->foppo = ppt[3];
16489  bface->tt.ver = 11;
16490  }
16491  if (bface->key == 0) {
16492  // Re-comput the quality values. Due to smoothing operations.
16493  ppt = (point *) & (bface->tt.tet[4]);
16494  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
16495  &bface->key, NULL);
16496  }
16497  cosdd = bface->cent;
16498  remflag = 0;
16499  for (i = 0; (i < 6) && !remflag; i++) {
16500  if (cosdd[i] < cosmaxdihed) {
16501  // Found a large dihedral angle.
16502  bface->tt.ver = edge2ver[i]; // Go to the edge.
16503  fc.cosdihed_in = cosdd[i];
16504  fc.cosdihed_out = 0.0; // 90 degree.
16505  n = removeedgebyflips(&(bface->tt), &fc);
16506  if (n == 2) {
16507  // Edge is flipped.
16508  remflag = 1;
16509  if (fc.cosdihed_out < cosmaxdihed) {
16510  // Queue new bad tets for further improvements.
16511  for (j = 0; j < cavetetlist->objects; j++) {
16512  parytet = (triface *) fastlookup(cavetetlist, j);
16513  if (!isdeadtet(*parytet)) {
16514  ppt = (point *) & (parytet->tet[4]);
16515  // Do not test a hull tet.
16516  if (ppt[3] != dummypoint) {
16517  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd,
16518  &maxdd, NULL);
16519  if (maxdd < cosmaxdihed) {
16520  // There are bad dihedral angles in this tet.
16521  nextflipqueue->newindex((void **) &parybface);
16522  parybface->tt.tet = parytet->tet;
16523  parybface->tt.ver = 11;
16524  parybface->forg = ppt[0];
16525  parybface->fdest = ppt[1];
16526  parybface->fapex = ppt[2];
16527  parybface->foppo = ppt[3];
16528  parybface->key = maxdd;
16529  for (n = 0; n < 6; n++) {
16530  parybface->cent[n] = ncosdd[n];
16531  }
16532  }
16533  } // if (ppt[3] != dummypoint)
16534  }
16535  } // j
16536  } // if (fc.cosdihed_out < cosmaxdihed)
16537  cavetetlist->restart();
16538  remcount++;
16539  }
16540  }
16541  } // i
16542  if (!remflag) {
16543  // An unremoved bad tet. Queue it again.
16544  unflipqueue->newindex((void **) &parybface);
16545  *parybface = *bface;
16546  }
16547  } // if (gettetrahedron(...))
16548  } // k
16549 
16550  flipqueue->restart();
16551 
16552  // Swap the two flip queues.
16553  swapqueue = flipqueue;
16554  flipqueue = nextflipqueue;
16555  nextflipqueue = swapqueue;
16556  } // while (flipqueues->objects > 0)
16557 
16558  if (b->verbose > 1) {
16559  printf(" Removed %ld bad tets.\n", remcount);
16560  }
16561  totalremcount += remcount;
16562 
16563  if (unflipqueue->objects > 0l) {
16564  //if (autofliplinklevel >= b->optmaxfliplevel) {
16565  if (autofliplinklevel >= b->optlevel) {
16566  break;
16567  }
16569  //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
16570  }
16571 
16572  // Swap the two flip queues.
16573  swapqueue = flipqueue;
16574  flipqueue = unflipqueue;
16575  unflipqueue = swapqueue;
16576  } // while (flipqueues->objects > 0)
16577 
16578  // Restore original flip edge options.
16579  autofliplinklevel = bakautofliplinklevel;
16580  b->fliplinklevel = bakfliplinklevel;
16581  b->flipstarsize = bakmaxflipstarsize;
16582 
16583  delete flipqueue;
16584  delete nextflipqueue;
16585 
16586  return totalremcount;
16587 }
16588 
16590 // //
16591 // smoothpoint() Moving a vertex to improve the mesh quality. //
16592 // //
16593 // 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point. //
16594 // It may be not a vertex of the mesh. //
16595 // //
16596 // This routine tries to move 'p' inside its star until a selected objective //
16597 // function over all tetrahedra in the star is improved. The function may be //
16598 // the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
16599 // simply the volume of the tetrahedra. //
16600 // //
16601 // 'linkfacelist' contains the list of link faces of 'p'. Since a link face //
16602 // has two orientations, ccw or cw, with respect to 'p'. 'ccw' indicates //
16603 // the orientation is ccw (1) or not (0). //
16604 // //
16605 // 'opm' is a structure contains the parameters of the objective function. //
16606 // It is needed by the evaluation of the function value. //
16607 // //
16608 // The return value indicates weather the point is smoothed or not. //
16609 // //
16610 // ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
16611 // no face has 'dummypoint' as its vertex. //
16612 // //
16614 
16615 int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
16616  optparameters *opm)
16617 {
16618  triface *parytet, *parytet1, swaptet;
16619  point pa, pb, pc;
16620  REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
16621  REAL oldval, minval = 0.0, val;
16622  REAL maxcosd; // oldang, newang;
16623  REAL ori, diff;
16624  int numdirs, iter;
16625  int i, j, k;
16626 
16627  // Decide the number of moving directions.
16628  numdirs = (int) linkfacelist->objects;
16629  if (numdirs > opm->numofsearchdirs) {
16630  numdirs = opm->numofsearchdirs; // Maximum search directions.
16631  }
16632 
16633  // Set the initial value.
16634  opm->imprval = opm->initval;
16635  iter = 0;
16636 
16637  for (i = 0; i < 3; i++) {
16638  bestpt[i] = startpt[i] = smtpt[i];
16639  }
16640 
16641  // Iterate until the obj function is not improved.
16642  while (1) {
16643 
16644  // Find the best next location.
16645  oldval = opm->imprval;
16646 
16647  for (i = 0; i < numdirs; i++) {
16648  // Randomly pick a link face (0 <= k <= objects - i - 1).
16649  k = (int) randomnation(linkfacelist->objects - i);
16650  parytet = (triface *) fastlookup(linkfacelist, k);
16651  // Calculate a new position from 'p' to the center of this face.
16652  pa = org(*parytet);
16653  pb = dest(*parytet);
16654  pc = apex(*parytet);
16655  for (j = 0; j < 3; j++) {
16656  fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
16657  }
16658  for (j = 0; j < 3; j++) {
16659  nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]);
16660  }
16661  // Calculate the largest minimum function value for the new location.
16662  for (j = 0; j < linkfacelist->objects; j++) {
16663  parytet = (triface *) fastlookup(linkfacelist, j);
16664  if (ccw) {
16665  pa = org(*parytet);
16666  pb = dest(*parytet);
16667  } else {
16668  pb = org(*parytet);
16669  pa = dest(*parytet);
16670  }
16671  pc = apex(*parytet);
16672  ori = orient3d(pa, pb, pc, nextpt);
16673  if (ori < 0.0) {
16674  // Calcuate the objective function value.
16675  if (opm->max_min_volume) {
16676  //val = -ori;
16677  val = - orient3dfast(pa, pb, pc, nextpt);
16678  } else if (opm->min_max_aspectratio) {
16679  val = 1.0 / tetaspectratio(pa, pb, pc, nextpt);
16680  } else if (opm->min_max_dihedangle) {
16681  tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
16682  if (maxcosd < -1) maxcosd = -1.0; // Rounding.
16683  val = maxcosd + 1.0; // Make it be positive.
16684  } else {
16685  // Unknown objective function.
16686  val = 0.0;
16687  }
16688  } else { // ori >= 0.0;
16689  // An invalid new tet.
16690  // This may happen if the mesh contains inverted elements.
16691  if (opm->max_min_volume) {
16692  //val = -ori;
16693  val = - orient3dfast(pa, pb, pc, nextpt);
16694  } else {
16695  // Discard this point.
16696  break; // j
16697  }
16698  } // if (ori >= 0.0)
16699  // Stop looping when the object value is not improved.
16700  if (val <= opm->imprval) {
16701  break; // j
16702  } else {
16703  // Remember the smallest improved value.
16704  if (j == 0) {
16705  minval = val;
16706  } else {
16707  minval = (val < minval) ? val : minval;
16708  }
16709  }
16710  } // j
16711  if (j == linkfacelist->objects) {
16712  // The function value has been improved.
16713  opm->imprval = minval;
16714  // Save the new location of the point.
16715  for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
16716  }
16717  // Swap k-th and (object-i-1)-th entries.
16718  j = linkfacelist->objects - i - 1;
16719  parytet = (triface *) fastlookup(linkfacelist, k);
16720  parytet1 = (triface *) fastlookup(linkfacelist, j);
16721  swaptet = *parytet1;
16722  *parytet1 = *parytet;
16723  *parytet = swaptet;
16724  } // i
16725 
16726  diff = opm->imprval - oldval;
16727  if (diff > 0.0) {
16728  // Is the function value improved effectively?
16729  if (opm->max_min_volume) {
16730  //if ((diff / oldval) < b->epsilon) diff = 0.0;
16731  } else if (opm->min_max_aspectratio) {
16732  if ((diff / oldval) < 1e-3) diff = 0.0;
16733  } else if (opm->min_max_dihedangle) {
16734  //oldang = acos(oldval - 1.0);
16735  //newang = acos(opm->imprval - 1.0);
16736  //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
16737  } else {
16738  // Unknown objective function.
16739  terminatetetgen(this, 2);
16740  }
16741  }
16742 
16743  if (diff > 0.0) {
16744  // Yes, move p to the new location and continue.
16745  for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
16746  iter++;
16747  if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
16748  // Maximum smoothing iterations reached.
16749  break;
16750  }
16751  } else {
16752  break;
16753  }
16754 
16755  } // while (1)
16756 
16757  if (iter > 0) {
16758  // The point has been smoothed.
16759  opm->smthiter = iter; // Remember the number of iterations.
16760  // The point has been smoothed. Update it to its new position.
16761  for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
16762  }
16763 
16764  return iter;
16765 }
16766 
16767 
16769 // //
16770 // improvequalitysmoothing() Improve mesh quality by smoothing. //
16771 // //
16773 
16775 {
16776  arraypool *flipqueue, *swapqueue;
16777  triface *parytet;
16778  badface *bface, *parybface;
16779  point *ppt;
16780  long totalsmtcount, smtcount;
16781  int smtflag;
16782  int iter, i, j, k;
16783 
16784  //assert(unflipqueue->objects > 0l);
16785  flipqueue = new arraypool(sizeof(badface), 10);
16786 
16787  // Swap the two flip queues.
16788  swapqueue = flipqueue;
16789  flipqueue = unflipqueue;
16790  unflipqueue = swapqueue;
16791 
16792  totalsmtcount = 0l;
16793  iter = 0;
16794 
16795  while (flipqueue->objects > 0l) {
16796 
16797  smtcount = 0l;
16798 
16799  if (b->verbose > 1) {
16800  printf(" Improving mesh quality by smoothing [%d]#: %ld.\n",
16801  iter, flipqueue->objects);
16802  }
16803 
16804  for (k = 0; k < flipqueue->objects; k++) {
16805  bface = (badface *) fastlookup(flipqueue, k);
16806  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
16807  bface->foppo, &bface->tt)) {
16808  // Operate on it if it is not in 'unflipqueue'.
16809  if (!marktested(bface->tt)) {
16810  // Here we simply re-compute the quality. Since other smoothing
16811  // operation may have moved the vertices of this tet.
16812  ppt = (point *) & (bface->tt.tet[4]);
16813  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
16814  &bface->key, NULL);
16815  if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
16816  // It is a sliver. Try to smooth its vertices.
16817  smtflag = 0;
16818  opm->initval = bface->key + 1.0;
16819  for (i = 0; (i < 4) && !smtflag; i++) {
16820  if (pointtype(ppt[i]) == FREEVOLVERTEX) {
16821  getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
16822  opm->searchstep = 0.001; // Search step size
16823  smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
16824  if (smtflag) {
16825  while (opm->smthiter == opm->maxiter) {
16826  opm->searchstep *= 10.0; // Increase the step size.
16827  opm->initval = opm->imprval;
16828  opm->smthiter = 0; // reset
16829  smoothpoint(ppt[i], cavetetlist, 1, opm);
16830  }
16831  // This tet is modifed.
16832  smtcount++;
16833  if ((opm->imprval - 1.0) < cossmtdihed) {
16834  // There are slivers in new tets. Queue them.
16835  for (j = 0; j < cavetetlist->objects; j++) {
16836  parytet = (triface *) fastlookup(cavetetlist, j);
16837  // Operate it if it is not in 'unflipqueue'.
16838  if (!marktested(*parytet)) {
16839  // Evaluate its quality.
16840  // Re-use ppt, bface->key, bface->cent.
16841  ppt = (point *) & (parytet->tet[4]);
16842  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3],
16843  bface->cent, &bface->key, NULL);
16844  if (bface->key < cossmtdihed) {
16845  // A new sliver. Queue it.
16846  marktest(*parytet); // It is in unflipqueue.
16847  unflipqueue->newindex((void **) &parybface);
16848  parybface->tt = *parytet;
16849  parybface->forg = ppt[0];
16850  parybface->fdest = ppt[1];
16851  parybface->fapex = ppt[2];
16852  parybface->foppo = ppt[3];
16853  parybface->tt.ver = 11;
16854  parybface->key = 0.0;
16855  }
16856  }
16857  } // j
16858  } // if ((opm->imprval - 1.0) < cossmtdihed)
16859  } // if (smtflag)
16860  cavetetlist->restart();
16861  } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
16862  } // i
16863  if (!smtflag) {
16864  // Didn't smooth. Queue it again.
16865  marktest(bface->tt); // It is in unflipqueue.
16866  unflipqueue->newindex((void **) &parybface);
16867  parybface->tt = bface->tt;
16868  parybface->forg = ppt[0];
16869  parybface->fdest = ppt[1];
16870  parybface->fapex = ppt[2];
16871  parybface->foppo = ppt[3];
16872  parybface->tt.ver = 11;
16873  parybface->key = 0.0;
16874  }
16875  } // if (maxdd < cosslidihed)
16876  } // if (!marktested(...))
16877  } // if (gettetrahedron(...))
16878  } // k
16879 
16880  flipqueue->restart();
16881 
16882  // Unmark the tets in unflipqueue.
16883  for (i = 0; i < unflipqueue->objects; i++) {
16884  bface = (badface *) fastlookup(unflipqueue, i);
16885  unmarktest(bface->tt);
16886  }
16887 
16888  if (b->verbose > 1) {
16889  printf(" Smooth %ld points.\n", smtcount);
16890  }
16891  totalsmtcount += smtcount;
16892 
16893  if (smtcount == 0l) {
16894  // No point has been smoothed.
16895  break;
16896  } else {
16897  iter++;
16898  if (iter == 2) { //if (iter >= b->optpasses) {
16899  break;
16900  }
16901  }
16902 
16903  // Swap the two flip queues.
16904  swapqueue = flipqueue;
16905  flipqueue = unflipqueue;
16906  unflipqueue = swapqueue;
16907  } // while
16908 
16909  delete flipqueue;
16910 
16911  return totalsmtcount;
16912 }
16913 
16915 // //
16916 // splitsliver() Split a sliver. //
16917 // //
16919 
16920 int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
16921 {
16922  triface *abtets;
16923  triface searchtet, spintet, *parytet;
16924  point pa, pb, steinerpt;
16925  optparameters opm;
16926  insertvertexflags ivf;
16927  REAL smtpt[3], midpt[3];
16928  int success;
16929  int t1ver;
16930  int n, i;
16931 
16932  // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle.
16933  // Go to the opposite edge [a,b].
16934  edestoppo(*slitet, searchtet); // [a,b,c,d].
16935 
16936  // Do not split a segment.
16937  if (issubseg(searchtet)) {
16938  return 0;
16939  }
16940 
16941  // Count the number of tets shared at [a,b].
16942  // Do not split it if it is a hull edge.
16943  spintet = searchtet;
16944  n = 0;
16945  while (1) {
16946  if (ishulltet(spintet)) break;
16947  n++;
16948  fnextself(spintet);
16949  if (spintet.tet == searchtet.tet) break;
16950  }
16951  if (ishulltet(spintet)) {
16952  return 0; // It is a hull edge.
16953  }
16954 
16955  // Get all tets at edge [a,b].
16956  abtets = new triface[n];
16957  spintet = searchtet;
16958  for (i = 0; i < n; i++) {
16959  abtets[i] = spintet;
16960  fnextself(spintet);
16961  }
16962 
16963  // Initialize the list of 2n boundary faces.
16964  for (i = 0; i < n; i++) {
16965  eprev(abtets[i], searchtet);
16966  esymself(searchtet); // [a,p_i,p_i+1].
16967  cavetetlist->newindex((void **) &parytet);
16968  *parytet = searchtet;
16969  enext(abtets[i], searchtet);
16970  esymself(searchtet); // [p_i,b,p_i+1].
16971  cavetetlist->newindex((void **) &parytet);
16972  *parytet = searchtet;
16973  }
16974 
16975  // Init the Steiner point at the midpoint of edge [a,b].
16976  pa = org(abtets[0]);
16977  pb = dest(abtets[0]);
16978  for (i = 0; i < 3; i++) {
16979  smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
16980  }
16981 
16982  // Point smooth options.
16983  opm.min_max_dihedangle = 1;
16984  opm.initval = cosd + 1.0; // Initial volume is zero.
16985  opm.numofsearchdirs = 20;
16986  opm.searchstep = 0.001;
16987  opm.maxiter = 100; // Limit the maximum iterations.
16988 
16989  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
16990 
16991  if (success) {
16992  while (opm.smthiter == opm.maxiter) {
16993  // It was relocated and the prescribed maximum iteration reached.
16994  // Try to increase the search stepsize.
16995  opm.searchstep *= 10.0;
16996  //opm.maxiter = 100; // Limit the maximum iterations.
16997  opm.initval = opm.imprval;
16998  opm.smthiter = 0; // Init.
16999  smoothpoint(smtpt, cavetetlist, 1, &opm);
17000  }
17001  } // if (success)
17002 
17003  cavetetlist->restart();
17004 
17005  if (!success) {
17006  delete [] abtets;
17007  return 0;
17008  }
17009 
17010 
17011  // Insert the Steiner point.
17012  makepoint(&steinerpt, FREEVOLVERTEX);
17013  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
17014 
17015  // Insert the created Steiner point.
17016  for (i = 0; i < n; i++) {
17017  infect(abtets[i]);
17018  caveoldtetlist->newindex((void **) &parytet);
17019  *parytet = abtets[i];
17020  }
17021 
17022  searchtet = abtets[0]; // No need point location.
17023  if (b->metric) {
17024  locate(steinerpt, &searchtet); // For size interpolation.
17025  }
17026 
17027  delete [] abtets;
17028 
17029  ivf.iloc = (int) INSTAR;
17030  ivf.chkencflag = chkencflag;
17031  ivf.assignmeshsize = b->metric;
17032 
17033 
17034  if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
17035  // The vertex has been inserted.
17036  st_volref_count++;
17037  if (steinerleft > 0) steinerleft--;
17038  return 1;
17039  } else {
17040  // The Steiner point is too close to an existing vertex. Reject it.
17041  pointdealloc(steinerpt);
17042  return 0;
17043  }
17044 }
17045 
17047 // //
17048 // removeslivers() Remove slivers by adding Steiner points. //
17049 // //
17051 
17052 long tetgenmesh::removeslivers(int chkencflag)
17053 {
17054  arraypool *flipqueue, *swapqueue;
17055  badface *bface, *parybface;
17056  triface slitet, *parytet;
17057  point *ppt;
17058  REAL cosdd[6], maxcosd;
17059  long totalsptcount, sptcount;
17060  int iter, i, j, k;
17061 
17062  //assert(unflipqueue->objects > 0l);
17063  flipqueue = new arraypool(sizeof(badface), 10);
17064 
17065  // Swap the two flip queues.
17066  swapqueue = flipqueue;
17067  flipqueue = unflipqueue;
17068  unflipqueue = swapqueue;
17069 
17070  totalsptcount = 0l;
17071  iter = 0;
17072 
17073  while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
17074 
17075  sptcount = 0l;
17076 
17077  if (b->verbose > 1) {
17078  printf(" Splitting bad quality tets [%d]#: %ld.\n",
17079  iter, flipqueue->objects);
17080  }
17081 
17082  for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {
17083  bface = (badface *) fastlookup(flipqueue, k);
17084  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
17085  bface->foppo, &bface->tt)) {
17086  if ((bface->key == 0) || (bface->tt.ver != 11)) {
17087  // Here we need to re-compute the quality. Since other smoothing
17088  // operation may have moved the vertices of this tet.
17089  ppt = (point *) & (bface->tt.tet[4]);
17090  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
17091  &bface->key, NULL);
17092  }
17093  if (bface->key < cosslidihed) {
17094  // It is a sliver. Try to split it.
17095  slitet.tet = bface->tt.tet;
17096  //cosdd = bface->cent;
17097  for (j = 0; j < 6; j++) {
17098  if (bface->cent[j] < cosslidihed) {
17099  // Found a large dihedral angle.
17100  slitet.ver = edge2ver[j]; // Go to the edge.
17101  if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
17102  sptcount++;
17103  break;
17104  }
17105  }
17106  } // j
17107  if (j < 6) {
17108  // A sliver is split. Queue new slivers.
17110  parytet = (triface *) badtetrahedrons->traverse();
17111  while (parytet != NULL) {
17112  unmarktest2(*parytet);
17113  ppt = (point *) & (parytet->tet[4]);
17114  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd,
17115  &maxcosd, NULL);
17116  if (maxcosd < cosslidihed) {
17117  // A new sliver. Queue it.
17118  unflipqueue->newindex((void **) &parybface);
17119  parybface->forg = ppt[0];
17120  parybface->fdest = ppt[1];
17121  parybface->fapex = ppt[2];
17122  parybface->foppo = ppt[3];
17123  parybface->tt.tet = parytet->tet;
17124  parybface->tt.ver = 11;
17125  parybface->key = maxcosd;
17126  for (i = 0; i < 6; i++) {
17127  parybface->cent[i] = cosdd[i];
17128  }
17129  }
17130  parytet = (triface *) badtetrahedrons->traverse();
17131  }
17133  } else {
17134  // Didn't split. Queue it again.
17135  unflipqueue->newindex((void **) &parybface);
17136  *parybface = *bface;
17137  } // if (j == 6)
17138  } // if (bface->key < cosslidihed)
17139  } // if (gettetrahedron(...))
17140  } // k
17141 
17142  flipqueue->restart();
17143 
17144  if (b->verbose > 1) {
17145  printf(" Split %ld tets.\n", sptcount);
17146  }
17147  totalsptcount += sptcount;
17148 
17149  if (sptcount == 0l) {
17150  // No point has been smoothed.
17151  break;
17152  } else {
17153  iter++;
17154  if (iter == 2) { //if (iter >= b->optpasses) {
17155  break;
17156  }
17157  }
17158 
17159  // Swap the two flip queues.
17160  swapqueue = flipqueue;
17161  flipqueue = unflipqueue;
17162  unflipqueue = swapqueue;
17163  } // while
17164 
17165  delete flipqueue;
17166 
17167  return totalsptcount;
17168 }
17169 
17171 // //
17172 // optimizemesh() Optimize mesh for specified objective functions. //
17173 // //
17175 
17177 {
17178  badface *parybface;
17179  triface checktet;
17180  point *ppt;
17181  int optpasses;
17182  optparameters opm;
17183  REAL ncosdd[6], maxdd;
17184  long totalremcount, remcount;
17185  long totalsmtcount, smtcount;
17186  long totalsptcount, sptcount;
17187  int chkencflag;
17188  int iter;
17189  int n;
17190 
17191  if (!b->quiet) {
17192  printf("Optimizing mesh...\n");
17193  }
17194 
17195  optpasses = ((1 << b->optlevel) - 1);
17196 
17197  if (b->verbose) {
17198  printf(" Optimization level = %d.\n", b->optlevel);
17199  printf(" Optimization scheme = %d.\n", b->optscheme);
17200  printf(" Number of iteration = %d.\n", optpasses);
17201  printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral);
17202  }
17203 
17204  totalsmtcount = totalsptcount = totalremcount = 0l;
17205 
17206  cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
17207  cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
17208  cosslidihed = cos(b->optminslidihed / 180.0 * PI);
17209 
17210  int attrnum = numelemattrib - 1;
17211 
17212  // Put all bad tetrahedra into array.
17214  checktet.tet = tetrahedrontraverse();
17215  while (checktet.tet != NULL) {
17216  if (b->convex) { // -c
17217  // Skip this tet if it lies in the exterior.
17218  if (elemattribute(checktet.tet, attrnum) == -1.0) {
17219  checktet.tet = tetrahedrontraverse();
17220  continue;
17221  }
17222  }
17223  ppt = (point *) & (checktet.tet[4]);
17224  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
17225  if (maxdd < cosmaxdihed) {
17226  // There are bad dihedral angles in this tet.
17227  unflipqueue->newindex((void **) &parybface);
17228  parybface->tt.tet = checktet.tet;
17229  parybface->tt.ver = 11;
17230  parybface->forg = ppt[0];
17231  parybface->fdest = ppt[1];
17232  parybface->fapex = ppt[2];
17233  parybface->foppo = ppt[3];
17234  parybface->key = maxdd;
17235  for (n = 0; n < 6; n++) {
17236  parybface->cent[n] = ncosdd[n];
17237  }
17238  }
17239  checktet.tet = tetrahedrontraverse();
17240  }
17241 
17242  totalremcount = improvequalitybyflips();
17243 
17244  if ((unflipqueue->objects > 0l) &&
17245  ((b->optscheme & 2) || (b->optscheme & 4))) {
17246  // The pool is only used by removeslivers().
17248  sizeof(void *), 0);
17249 
17250  // Smoothing options.
17251  opm.min_max_dihedangle = 1;
17252  opm.numofsearchdirs = 10;
17253  // opm.searchstep = 0.001;
17254  opm.maxiter = 30; // Limit the maximum iterations.
17255  //opm.checkencflag = 4; // Queue affected tets after smoothing.
17256  chkencflag = 4; // Queue affected tets after splitting a sliver.
17257  iter = 0;
17258 
17259  while (iter < optpasses) {
17260  smtcount = sptcount = remcount = 0l;
17261  if (b->optscheme & 2) {
17262  smtcount += improvequalitybysmoothing(&opm);
17263  totalsmtcount += smtcount;
17264  if (smtcount > 0l) {
17265  remcount = improvequalitybyflips();
17266  totalremcount += remcount;
17267  }
17268  }
17269  if (unflipqueue->objects > 0l) {
17270  if (b->optscheme & 4) {
17271  sptcount += removeslivers(chkencflag);
17272  totalsptcount += sptcount;
17273  if (sptcount > 0l) {
17274  remcount = improvequalitybyflips();
17275  totalremcount += remcount;
17276  }
17277  }
17278  }
17279  if (unflipqueue->objects > 0l) {
17280  if (remcount > 0l) {
17281  iter++;
17282  } else {
17283  break;
17284  }
17285  } else {
17286  break;
17287  }
17288  } // while (iter)
17289 
17290  delete badtetrahedrons;
17291  badtetrahedrons = NULL;
17292  }
17293 
17294  if (unflipqueue->objects > 0l) {
17295  if (b->verbose > 1) {
17296  printf(" %ld bad tets remained.\n", unflipqueue->objects);
17297  }
17298  unflipqueue->restart();
17299  }
17300 
17301  if (b->verbose) {
17302  if (totalremcount > 0l) {
17303  printf(" Removed %ld edges.\n", totalremcount);
17304  }
17305  if (totalsmtcount > 0l) {
17306  printf(" Smoothed %ld points.\n", totalsmtcount);
17307  }
17308  if (totalsptcount > 0l) {
17309  printf(" Split %ld slivers.\n", totalsptcount);
17310  }
17311  }
17312 }
17313 
17317 
17318 
17320 // //
17321 // jettisonnodes() Jettison unused or duplicated vertices. //
17322 // //
17323 // Unused points are those input points which are outside the mesh domain or //
17324 // have no connection (isolated) to the mesh. Duplicated points exist for //
17325 // example if the input PLC is read from a .stl mesh file (marked during the //
17326 // Delaunay tetrahedralization step. This routine remove these points from //
17327 // points list. All existing points are reindexed. //
17328 // //
17330 
17332 {
17333  point pointloop;
17334  bool jetflag;
17335  int oldidx, newidx;
17336  int remcount;
17337 
17338  if (!b->quiet) {
17339  printf("Jettisoning redundant points.\n");
17340  }
17341 
17342  points->traversalinit();
17343  pointloop = pointtraverse();
17344  oldidx = newidx = 0; // in->firstnumber;
17345  remcount = 0;
17346  while (pointloop != (point) NULL) {
17347  jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
17348  (pointtype(pointloop) == UNUSEDVERTEX);
17349  if (jetflag) {
17350  // It is a duplicated or unused point, delete it.
17351  pointdealloc(pointloop);
17352  remcount++;
17353  } else {
17354  // Re-index it.
17355  setpointmark(pointloop, newidx + in->firstnumber);
17356  if (in->pointmarkerlist != (int *) NULL) {
17357  if (oldidx < in->numberofpoints) {
17358  // Re-index the point marker as well.
17359  in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
17360  }
17361  }
17362  newidx++;
17363  }
17364  oldidx++;
17365  pointloop = pointtraverse();
17366  }
17367  if (b->verbose) {
17368  printf(" %ld duplicated vertices are removed.\n", dupverts);
17369  printf(" %ld unused vertices are removed.\n", unuverts);
17370  }
17371  dupverts = 0l;
17372  unuverts = 0l;
17373 
17374  // The following line ensures that dead items in the pool of nodes cannot
17375  // be allocated for the new created nodes. This ensures that the input
17376  // nodes will occur earlier in the output files, and have lower indices.
17377  points->deaditemstack = (void *) NULL;
17378 }
tetgenmesh::setfacetindex
void setfacetindex(face &f, int value)
Definition: tetgenBR.h:2215
sevent
static selfint_event sevent
Definition: tetgenBR.h:1537
tetgenmesh::numelemattrib
int numelemattrib
Definition: tetgenBR.h:789
tetgenmesh::facemarked
bool facemarked(triface &t)
Definition: tetgenBR.h:1880
tetgenmesh::stbondtbl
static int stbondtbl[12][6]
Definition: tetgenBR.h:847
tetgenmesh::flip22count
long flip22count
Definition: tetgenBR.h:831
tetgenmesh::face::sh
shellface * sh
Definition: tetgenBR.h:402
tetgenmesh::tspivot
void tspivot(triface &t, face &s)
Definition: tetgenBR.h:2258
D
#define D
Definition: DefaultOptions.h:24
tetgenmesh::autofliplinklevel
int autofliplinklevel
Definition: tetgenBR.h:805
tetgenmesh::enextself
void enextself(triface &t)
Definition: tetgenBR.h:1624
tetgenbehavior::nonodewritten
int nonodewritten
Definition: tetgenBR.h:83
tetgenmesh::esym
void esym(triface &t1, triface &t2)
Definition: tetgenBR.h:1639
tetgenmesh::DUPLICATEDVERTEX
@ DUPLICATEDVERTEX
Definition: tetgenBR.h:684
tetgenbehavior::OFF
@ OFF
Definition: tetgenBR.h:147
tetgenmesh::flip26count
long flip26count
Definition: tetgenBR.h:829
tetgenbehavior::facet_overlap_ang_tol
REAL facet_overlap_ang_tol
Definition: tetgenBR.h:117
tetgenmesh::smarktested
bool smarktested(face &s)
Definition: tetgenBR.h:2168
tetgenmesh::zmax
REAL zmax
Definition: tetgenBR.h:816
tetgenmesh::cosslidihed
REAL cosslidihed
Definition: tetgenBR.h:811
tetgenmesh::cavesegshlist
arraypool * cavesegshlist
Definition: tetgenBR.h:759
tetgenmesh::shellmark
int shellmark(face &s)
Definition: tetgenBR.h:2121
tetgenmesh::sesym
void sesym(face &s1, face &s2)
Definition: tetgenBR.h:2076
tetgenmesh::incircle3d
REAL incircle3d(point pa, point pb, point pc, point pd)
Definition: tetgenBR.cxx:3138
tetgenbehavior::nobound
int nobound
Definition: tetgenBR.h:82
tetgenbehavior::MESH
@ MESH
Definition: tetgenBR.h:147
tetgenmesh
Definition: tetgenBR.h:254
tetgenmesh::insertvertexflags::sloc
int sloc
Definition: tetgenBR.h:554
tetgenmesh::enextesym
void enextesym(triface &t1, triface &t2)
Definition: tetgenBR.h:1650
tetgenmesh::flip44count
long flip44count
Definition: tetgenBR.h:830
tetgenmesh::in
tetgenio * in
Definition: tetgenBR.h:734
tetgenmesh::issteinerpoint
bool issteinerpoint(point pt)
Definition: tetgenBR.h:2563
tetgenmesh::shellfacetraverse
shellface * shellfacetraverse(memorypool *)
Definition: tetgenBR.cxx:1419
tetgenmesh::sdecode
void sdecode(shellface sptr, face &s)
Definition: tetgenBR.h:1982
SETVECTOR3
#define SETVECTOR3(V, a0, a1, a2)
Definition: tetgenBR.cxx:2040
tetgenmesh::projpt2edge
void projpt2edge(REAL *p, REAL *e1, REAL *e2, REAL *prj)
Definition: tetgenBR.cxx:3379
tetgenmesh::memorypool::dealloc
void dealloc(void *)
Definition: tetgenBR.cxx:1147
tetgenbehavior::fixedvolume
int fixedvolume
Definition: tetgenBR.h:65
tetgenmesh::edestoppoself
void edestoppoself(triface &t)
Definition: tetgenBR.h:1694
tetgenmesh::lu_decmp
bool lu_decmp(REAL lu[4][4], int n, int *ps, REAL *d, int N)
Definition: tetgenBR.cxx:3027
tetgenmesh::optparameters::min_max_aspectratio
int min_max_aspectratio
Definition: tetgenBR.h:649
tetgenmesh::randomsample
void randomsample(point searchpt, triface *searchtet)
Definition: tetgenBR.cxx:8367
tetgenmesh::interiorangle
REAL interiorangle(REAL *o, REAL *p1, REAL *p2, REAL *n)
Definition: tetgenBR.cxx:3334
tetgenmesh::unmarktest
void unmarktest(triface &t)
Definition: tetgenBR.h:1856
tetgenmesh::scarveholes
void scarveholes(int, REAL *)
Definition: tetgenBR.cxx:10810
selfint_event::f_marker2
int f_marker2
Definition: tetgenBR.h:1525
tetgenmesh::optparameters::smthiter
int smthiter
Definition: tetgenBR.h:658
tetgenmesh::cosmaxdihed
REAL cosmaxdihed
Definition: tetgenBR.h:809
tetgenmesh::makeindex2pointmap
void makeindex2pointmap(point *&)
Definition: tetgenBR.cxx:1230
tetgenmesh::fsymtbl
static int fsymtbl[12][12]
Definition: tetgenBR.h:841
tetgenmesh::badface::nextitem
badface * nextitem
Definition: tetgenBR.h:532
tetgenmesh::insertvertexflags::chkencflag
int chkencflag
Definition: tetgenBR.h:552
isshsubseg
#define isshsubseg(s)
Definition: tetgenBR.h:2335
tetgenbehavior::maxvolume
REAL maxvolume
Definition: tetgenBR.h:119
tetgenmesh::incrementalflip
int incrementalflip(point newpt, int, flipconstraints *fc)
Definition: tetgenBR.cxx:8711
tetgenbehavior::nojettison
int nojettison
Definition: tetgenBR.h:87
tetgenmesh::locate
enum locateresult locate(point searchpt, triface *searchtet, int chkencflag=0)
Definition: tetgenBR.cxx:8485
tetgenmesh::SHAREFACE
@ SHAREFACE
Definition: tetgenBR.h:702
tetgenmesh::INSTAR
@ INSTAR
Definition: tetgenBR.h:723
tetgenbehavior::bgmeshfilename
char bgmeshfilename[1024]
Definition: tetgenBR.h:133
tetgenmesh::volumebound
REAL volumebound(tetrahedron *ptr)
Definition: tetgenBR.h:1791
tetgenmesh::minfacetdihed
REAL minfacetdihed
Definition: tetgenBR.h:812
tetgenmesh::sencode
shellface sencode(face &s)
Definition: tetgenBR.h:1988
tetgenmesh::setorg
void setorg(triface &t, point p)
Definition: tetgenBR.h:1750
tetgenmesh::hilbert_split
int hilbert_split(point *vertexarray, int arraysize, int gc0, int gc1, REAL, REAL, REAL, REAL, REAL, REAL)
Definition: tetgenBR.cxx:8144
tetgenmesh::sspivot
void sspivot(face &s, face &edge)
Definition: tetgenBR.h:2328
tetgenmesh::pinfected
bool pinfected(point pt)
Definition: tetgenBR.h:2456
tetgenmesh::flipnm
int flipnm(triface *, int n, int level, int, flipconstraints *fc)
Definition: tetgenBR.cxx:5804
tetgenmesh::cavetetseglist
arraypool * cavetetseglist
Definition: tetgenBR.h:757
tetgenmesh::memorypool::poolinit
void poolinit(int, int, int, int)
Definition: tetgenBR.cxx:1019
tetgenbehavior::object
enum tetgenbehavior::objecttype object
tetgenmesh::transgc
int transgc[8][3][8]
Definition: tetgenBR.h:1239
tetgenmesh::fnextself
void fnextself(triface &t)
tetgenmesh::hilbert_sort3
void hilbert_sort3(point *vertexarray, int arraysize, int e, int d, REAL, REAL, REAL, REAL, REAL, REAL, int depth)
Definition: tetgenBR.cxx:8215
tetgenmesh::flip22
void flip22(face *, int, int)
Definition: tetgenBR.cxx:9281
tetgenmesh::SHAREEDGE
@ SHAREEDGE
Definition: tetgenBR.h:701
tetgenmesh::flip41
void flip41(triface *, int, flipconstraints *fc)
Definition: tetgenBR.cxx:5485
tetgenmesh::tri_edge_test
int tri_edge_test(point, point, point, point, point, point, int, int *, int *)
Definition: tetgenBR.cxx:2853
tetgenmesh::smarktest2ed
bool smarktest2ed(face &s)
Definition: tetgenBR.h:2188
tetgenmesh::edestoppotbl
static int edestoppotbl[12]
Definition: tetgenBR.h:844
selfint_event::int_point
REAL int_point[3]
Definition: tetgenBR.h:1528
tetgenmesh::point2sh
shellface point2sh(point pt)
Definition: tetgenBR.h:2532
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
tetgenmesh::orthosphere
bool orthosphere(REAL *, REAL *, REAL *, REAL *, REAL, REAL, REAL, REAL, REAL *, REAL *)
Definition: tetgenBR.cxx:3723
tetgenmesh::points
memorypool * points
Definition: tetgenBR.h:744
tetgenbehavior::nobisect
int nobisect
Definition: tetgenBR.h:57
tetgenmesh::makeshellface
void makeshellface(memorypool *, face *)
Definition: tetgenBR.cxx:1509
tetgenbehavior::convex
int convex
Definition: tetgenBR.h:70
tetgenmesh::badface::fdest
point fdest
Definition: tetgenBR.h:531
isshtet
#define isshtet(s)
Definition: tetgenBR.h:2285
tetgenmesh::badface::key
REAL key
Definition: tetgenBR.h:530
tetgenbehavior::VTK
@ VTK
Definition: tetgenBR.h:147
tetgenbehavior::outfilename
char outfilename[1024]
Definition: tetgenBR.h:131
tetgenmesh::incrementaldelaunay
void incrementaldelaunay(clock_t &)
Definition: tetgenBR.cxx:9033
tetgenmesh::recoveredgebyflips
int recoveredgebyflips(point, point, face *, triface *, int fullsearch)
Definition: tetgenBR.cxx:12059
tetgenmesh::tetrahedron
REAL ** tetrahedron
Definition: tetgenBR.h:302
tetgenmesh::flip41count
long flip41count
Definition: tetgenBR.h:830
tetgenmesh::tetrahedrondealloc
void tetrahedrondealloc(tetrahedron *)
Definition: tetgenBR.cxx:1347
tetgenmesh::pointmark
int pointmark(point pt)
Definition: tetgenBR.h:2396
tetgenmesh::unmarktest2
void unmarktest2(triface &t)
Definition: tetgenBR.h:1914
tetgenmesh::randomnation
unsigned long randomnation(unsigned int choices)
Definition: tetgenBR.cxx:8337
tetgenmesh::tssbond1
void tssbond1(triface &t, face &seg)
Definition: tetgenBR.h:2343
tetgenmesh::sorgpivot
static int sorgpivot[6]
Definition: tetgenBR.h:850
tetgenmesh::optimizemesh
void optimizemesh()
Definition: tetgenBR.cxx:17176
tetgenmesh::hilbert_init
void hilbert_init(int n)
Definition: tetgenBR.cxx:8095
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
tetgenmesh::snextpivot
static int snextpivot[6]
Definition: tetgenBR.h:851
tetgenmesh::badface
Definition: tetgenBR.h:526
tetgenmesh::subfaces
memorypool * subfaces
Definition: tetgenBR.h:744
tetgenmesh::optparameters::numofsearchdirs
int numofsearchdirs
Definition: tetgenBR.h:655
tetgenmesh::report_selfint_face
int report_selfint_face(point, point, point, face *sface, triface *iedge, int intflag, int *types, int *poss)
Definition: tetgenBR.cxx:4506
robustPredicates::epsilon
static REAL epsilon
Definition: robustPredicates.cpp:371
tetgenmesh::unifysegments
void unifysegments()
Definition: tetgenBR.cxx:10905
tetgenmesh::decreaseelemcounter
void decreaseelemcounter(triface &t)
Definition: tetgenBR.h:1948
tetgenbehavior::optlevel
int optlevel
Definition: tetgenBR.h:105
tetgenmesh::recoverfacebyflips
int recoverfacebyflips(point, point, point, face *, triface *)
Definition: tetgenBR.cxx:12982
tetgenmesh::tri_tri_inter
int tri_tri_inter(point, point, point, point, point, point)
Definition: tetgenBR.cxx:2912
tetgenmesh::arraypool::poolinit
void poolinit(int sizeofobject, int log2objperblk)
Definition: tetgenBR.cxx:779
tetgenbehavior::meditview
int meditview
Definition: tetgenBR.h:80
tetgenmesh::lu_solve
void lu_solve(REAL lu[4][4], int n, int *ps, REAL *b, int N)
Definition: tetgenBR.cxx:3100
tetgenmesh::tetallnormal
void tetallnormal(point, point, point, point, REAL N[4][3], REAL *volume)
Definition: tetgenBR.cxx:3542
tetgenmesh::calculateabovepoint
bool calculateabovepoint(arraypool *, point *, point *, point *)
Definition: tetgenBR.cxx:3916
tetgenmesh::sinfect
void sinfect(face &s)
Definition: tetgenBR.h:2134
tetgenmesh::flipnm_post
int flipnm_post(triface *, int n, int nn, int, flipconstraints *fc)
Definition: tetgenBR.cxx:6478
tetgenmesh::increaseelemcounter
void increaseelemcounter(triface &t)
Definition: tetgenBR.h:1942
tetgenmesh::calculateabovepoint4
void calculateabovepoint4(point, point, point, point)
Definition: tetgenBR.cxx:4006
tetgenbehavior::reflevel
int reflevel
Definition: tetgenBR.h:104
tetgenmesh::badface::ss
face ss
Definition: tetgenBR.h:529
tetgenmesh::sapexpivot
static int sapexpivot[6]
Definition: tetgenBR.h:850
tetgenbehavior::STL
@ STL
Definition: tetgenBR.h:147
tetgenmesh::marktest2
void marktest2(triface &t)
Definition: tetgenBR.h:1909
tetgenmesh::infect
void infect(triface &t)
Definition: tetgenBR.h:1833
REAL
#define REAL
Definition: robustPredicates.cpp:141
tetgenmesh::carveholes
void carveholes()
Definition: tetgenBR.cxx:15267
tetgenmesh::dest
point dest(triface &t)
Definition: tetgenBR.h:1735
tetgenbehavior::epsilon
REAL epsilon
Definition: tetgenBR.h:125
tetgenmesh::memorypool::firstblock
void ** firstblock
Definition: tetgenBR.h:488
tetgenmesh::arraypool::totalmemory
unsigned long totalmemory
Definition: tetgenBR.h:442
issubface
#define issubface(t)
Definition: tetgenBR.h:2270
tetgenmesh::linelineint
int linelineint(REAL *, REAL *, REAL *, REAL *, REAL *, REAL *, REAL *, REAL *)
Definition: tetgenBR.cxx:3825
tetgenmesh::arraypool::~arraypool
~arraypool()
Definition: tetgenBR.cxx:810
tetgenmesh::UNKNOWN
@ UNKNOWN
Definition: tetgenBR.h:712
tetgenmesh::caveshlist
arraypool * caveshlist
Definition: tetgenBR.h:759
tetgenmesh::longest
REAL longest
Definition: tetgenBR.h:814
tetgenbehavior::brio_threshold
int brio_threshold
Definition: tetgenBR.h:114
tetgenmesh::decode
void decode(tetrahedron ptr, triface &t)
Definition: tetgenBR.h:1597
tetgenmesh::edge2ver
static int edge2ver[6]
Definition: tetgenBR.h:849
tetgenmesh::badface::forg
point forg
Definition: tetgenBR.h:531
tetgenmesh::stdissolve
void stdissolve(face &s)
Definition: tetgenBR.h:2296
tetgenmesh::marktest
void marktest(triface &t)
Definition: tetgenBR.h:1851
tetgenmesh::puninfect
void puninfect(point pt)
Definition: tetgenBR.h:2451
tetgenmesh::ACROSSFACE
@ ACROSSFACE
Definition: tetgenBR.h:707
issubseg
#define issubseg(t)
Definition: tetgenBR.h:2383
tetgenmesh::pointmarkindex
int pointmarkindex
Definition: tetgenBR.h:794
tetgenbehavior::addsteiner_algo
int addsteiner_algo
Definition: tetgenBR.h:98
tetgenmesh::tspivottbl
static int tspivottbl[12][6]
Definition: tetgenBR.h:848
tetgenmesh::badtetrahedrons
memorypool * badtetrahedrons
Definition: tetgenBR.h:748
tetgenmesh::encode
tetrahedron encode(triface &t)
Definition: tetgenBR.h:1584
tetgenmesh::destpivot
static int destpivot[12]
Definition: tetgenBR.h:846
tetgenmesh::setpoint2sh
void setpoint2sh(point pt, shellface value)
Definition: tetgenBR.h:2537
tetgenmesh::tetrahedrontraverse
tetrahedron * tetrahedrontraverse()
Definition: tetgenBR.cxx:1370
tetgenmesh::mergefacets
void mergefacets()
Definition: tetgenBR.cxx:11292
tetgenmesh::b
tetgenbehavior * b
Definition: tetgenBR.h:737
tetgenmesh::setdest
void setdest(triface &t, point p)
Definition: tetgenBR.h:1755
tetgenmesh::dissolve
void dissolve(triface &t)
Definition: tetgenBR.h:1614
tetgenmesh::insertvertexflags::refineflag
int refineflag
Definition: tetgenBR.h:557
tetgenmesh::caveshbdlist
arraypool * caveshbdlist
Definition: tetgenBR.h:759
tetgenmesh::st_facref_count
long st_facref_count
Definition: tetgenBR.h:827
tetgenmesh::flipshpush
void flipshpush(face *)
Definition: tetgenBR.cxx:9259
tetgenbehavior::quiet
int quiet
Definition: tetgenBR.h:89
tetgenbehavior::MEDIT
@ MEDIT
Definition: tetgenBR.h:147
tetgenmesh::pointtraverse
point pointtraverse()
Definition: tetgenBR.cxx:1453
tetgenbehavior::infilename
char infilename[1024]
Definition: tetgenBR.h:130
tetgenbehavior::neighout
int neighout
Definition: tetgenBR.h:78
tetgenmesh::edestoppo
void edestoppo(triface &t1, triface &t2)
Definition: tetgenBR.h:1688
tetgenbehavior::docheck
int docheck
Definition: tetgenBR.h:88
tetgenmesh::sorg
point sorg(face &s)
Definition: tetgenBR.h:2039
tetgenbehavior::vtkview
int vtkview
Definition: tetgenBR.h:81
tetgenmesh::isdeadtet
bool isdeadtet(triface &t)
Definition: tetgenBR.h:1963
tetgenmesh::sdest
point sdest(face &s)
Definition: tetgenBR.h:2044
tetgenmesh::setapex
void setapex(triface &t, point p)
Definition: tetgenBR.h:1760
tetgenmesh::report_overlapping_facets
void report_overlapping_facets(face *, face *, REAL dihedang=0.0)
Definition: tetgenBR.cxx:4042
tetgenmesh::OUTSIDE
@ OUTSIDE
Definition: tetgenBR.h:713
tetgenmesh::st_volref_count
long st_volref_count
Definition: tetgenBR.h:827
tetgenmesh::sapex
point sapex(face &s)
Definition: tetgenBR.h:2049
tetgenmesh::badface::fapex
point fapex
Definition: tetgenBR.h:531
tetgenmesh::totalworkmemory
unsigned long totalworkmemory
Definition: tetgenBR.h:832
tetgenmesh::INTETRAHEDRON
@ INTETRAHEDRON
Definition: tetgenBR.h:714
tetgenmesh::esymself
void esymself(triface &t)
Definition: tetgenBR.h:1645
tetgenbehavior::shellfaceperblock
int shellfaceperblock
Definition: tetgenBR.h:95
tetgenmesh::insertvertexflags::smlen
REAL smlen
Definition: tetgenBR.h:561
tetgenmesh::memorypool::itembytes
int itembytes
Definition: tetgenBR.h:494
tetgenmesh::ENCSUBFACE
@ ENCSUBFACE
Definition: tetgenBR.h:720
tetgenmesh::caveencseglist
arraypool * caveencseglist
Definition: tetgenBR.h:758
tetgenmesh::flip32count
long flip32count
Definition: tetgenBR.h:830
tetgenmesh::eprevtbl
static int eprevtbl[12]
Definition: tetgenBR.h:842
tetgenmesh::tetaspectratio
REAL tetaspectratio(point, point, point, point)
Definition: tetgenBR.cxx:3585
tetgenmesh::orient3dfast
REAL orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
Definition: tetgenBR.cxx:3300
tetgenmesh::optparameters
Definition: tetgenBR.h:645
tetgenmesh::insertvertexflags::splitbdflag
int splitbdflag
Definition: tetgenBR.h:551
tetgenbehavior::verbose
int verbose
Definition: tetgenBR.h:90
tetgenmesh::interresult
interresult
Definition: tetgenBR.h:697
tetgenmesh::insertpoint
int insertpoint(point, triface *, face *, face *, insertvertexflags *)
Definition: tetgenBR.cxx:6641
tetgenmesh::insertvertexflags::iloc
int iloc
Definition: tetgenBR.h:549
tetgenmesh::suppresssteinerpoints
int suppresssteinerpoints()
Definition: tetgenBR.cxx:14778
tetgenmesh::sscoutsegment
enum interresult sscoutsegment(face *, point, int, int, int)
Definition: tetgenBR.cxx:10587
tetgenbehavior::optminsmtdihed
REAL optminsmtdihed
Definition: tetgenBR.h:123
tetgenmesh::insphere_s
REAL insphere_s(REAL *, REAL *, REAL *, REAL *, REAL *)
Definition: tetgenBR.cxx:1890
tetgenmesh::flipn2ncount
long flipn2ncount
Definition: tetgenBR.h:829
tetgenmesh::apexpivot
static int apexpivot[12]
Definition: tetgenBR.h:846
tetgenmesh::slocate
enum locateresult slocate(point, face *, int, int, int)
Definition: tetgenBR.cxx:10379
tetgenmesh::setpoint2bgmtet
void setpoint2bgmtet(point pt, tetrahedron value)
Definition: tetgenBR.h:2547
tetgenmesh::distance
REAL distance(REAL *p1, REAL *p2)
Definition: tetgenBR.h:2654
tetgenmesh::arraypool
Definition: tetgenBR.h:433
tetgenmesh::setvolumebound
void setvolumebound(tetrahedron *ptr, REAL value)
Definition: tetgenBR.h:1796
tetgenmesh::setpointmark
void setpointmark(point pt, int value)
Definition: tetgenBR.h:2401
tetgenmesh::suninfect
void suninfect(face &s)
Definition: tetgenBR.h:2140
tetgenmesh::insertvertexflags::validflag
int validflag
Definition: tetgenBR.h:551
tetgenbehavior::incrflip
int incrflip
Definition: tetgenBR.h:61
tetgenmesh::insertvertexflags::cdtflag
int cdtflag
Definition: tetgenBR.h:552
tetgenmesh::elemattribute
REAL elemattribute(tetrahedron *ptr, int attnum)
Definition: tetgenBR.h:1778
tetgenmesh::setelemattribute
void setelemattribute(tetrahedron *ptr, int attnum, REAL value)
Definition: tetgenBR.h:1783
LegendrePolynomials::fc
void fc(int n, double u, double *val)
Definition: orthogonalBasis.cpp:92
tetgenmesh::setpointtype
void setpointtype(point pt, enum verttype value)
Definition: tetgenBR.h:2413
tetgenmesh::NREGULARVERTEX
@ NREGULARVERTEX
Definition: tetgenBR.h:692
tetgenmesh::arraypool::getblock
char * getblock(int objectindex)
Definition: tetgenBR.cxx:847
tetgenmesh::setshellmark
void setshellmark(face &s, int value)
Definition: tetgenBR.h:2126
tetgenmesh::makepoint
void makepoint(point *, enum verttype)
Definition: tetgenBR.cxx:1549
tetgenmesh::ymax
REAL ymax
Definition: tetgenBR.h:816
tetgenmesh::eprevesymself
void eprevesymself(triface &t)
Definition: tetgenBR.h:1669
tetgenmesh::facepivot1
static int facepivot1[12]
Definition: tetgenBR.h:845
tetgenbehavior::quality
int quality
Definition: tetgenBR.h:56
tetgenmesh::sbond
void sbond(face &s1, face &s2)
Definition: tetgenBR.h:2001
tetgenmesh::DISJOINT
@ DISJOINT
Definition: tetgenBR.h:698
tetgenmesh::enqueuesubface
void enqueuesubface(memorypool *, face *)
Definition: tetgenBR.cxx:15897
tetgenbehavior::POLY
@ POLY
Definition: tetgenBR.h:147
tetgenmesh::marktested
bool marktested(triface &t)
Definition: tetgenBR.h:1861
tetgenmesh::insertvertexflags::rejflag
int rejflag
Definition: tetgenBR.h:552
tetgenbehavior::reversetetori
int reversetetori
Definition: tetgenBR.h:109
selfint_event::f_vertices1
int f_vertices1[3]
Definition: tetgenBR.h:1524
tetgenmesh::tsbond
void tsbond(triface &t, face &s)
Definition: tetgenBR.h:2237
tetgenmesh::suppressbdrysteinerpoint
int suppressbdrysteinerpoint(point steinerpt)
Definition: tetgenBR.cxx:14268
tetgenmesh::splitsliver
int splitsliver(triface *, REAL, int)
Definition: tetgenBR.cxx:16920
tetgenmesh::BADELEMENT
@ BADELEMENT
Definition: tetgenBR.h:724
tetgenmesh::recenttet
triface recenttet
Definition: tetgenBR.h:777
terminatetetgen
void terminatetetgen(tetgenmesh *m, int x)
Definition: tetgenBR.h:1539
tetgenmesh::insertvertexflags::lawson
int lawson
Definition: tetgenBR.h:550
tetgenbehavior::optscheme
int optscheme
Definition: tetgenBR.h:106
tetgenbehavior::coarsen_percent
REAL coarsen_percent
Definition: tetgenBR.h:126
tetgenbehavior::noelewritten
int noelewritten
Definition: tetgenBR.h:84
tetgenmesh::report_selfint_edge
int report_selfint_edge(point, point, face *sedge, triface *searchtet, enum interresult)
Definition: tetgenBR.cxx:4109
tetgenmesh::infected
bool infected(triface &t)
Definition: tetgenBR.h:1843
tetgenmesh::circumsphere
bool circumsphere(REAL *, REAL *, REAL *, REAL *, REAL *cent, REAL *radius)
Definition: tetgenBR.cxx:3665
tetgenbehavior::nostaticfilter
int nostaticfilter
Definition: tetgenBR.h:74
tetgenbehavior::addinfilename
char addinfilename[1024]
Definition: tetgenBR.h:132
tetgenmesh::pointtype
enum verttype pointtype(point pt)
Definition: tetgenBR.h:2408
tetgenmesh::orgpivot
static int orgpivot[12]
Definition: tetgenBR.h:846
tetgenmesh::setelemmarker
void setelemmarker(tetrahedron *ptr, int value)
Definition: tetgenBR.h:1824
tetgenmesh::uninfect
void uninfect(triface &t)
Definition: tetgenBR.h:1838
tetgenmesh::dupverts
long dupverts
Definition: tetgenBR.h:824
tetgenmesh::recoversegments
int recoversegments(arraypool *, int fullsearch, int steinerflag)
Definition: tetgenBR.cxx:12858
tetgenmesh::farsorg
point farsorg(face &seg)
Definition: tetgenBR.h:2603
tetgenmesh::tsspivot1
void tsspivot1(triface &t, face &s)
Definition: tetgenBR.h:2371
tetgenbehavior::commandline
char commandline[1024]
Definition: tetgenBR.h:129
tetgenmesh::stpivottbl
static int stpivottbl[12][6]
Definition: tetgenBR.h:848
tetgenmesh::spivotself
void spivotself(face &s)
Definition: tetgenBR.h:2030
tetgenmesh::sesymself
void sesymself(face &s)
Definition: tetgenBR.h:2082
tetgenmesh::DEADVERTEX
@ DEADVERTEX
Definition: tetgenBR.h:693
tetgenmesh::badface::tt
triface tt
Definition: tetgenBR.h:528
tetgenmesh::FREEFACETVERTEX
@ FREEFACETVERTEX
Definition: tetgenBR.h:690
tetgenmesh::bgm
tetgenmesh * bgm
Definition: tetgenBR.h:740
tetgenmesh::enqueuetetrahedron
void enqueuetetrahedron(triface *)
Definition: tetgenBR.cxx:15912
tetgenmesh::bondtbl
static int bondtbl[12][12]
Definition: tetgenBR.h:841
tetgenmesh::cavetetlist
arraypool * cavetetlist
Definition: tetgenBR.h:756
tetgenmesh::unflipqueue
arraypool * unflipqueue
Definition: tetgenBR.h:752
tetgenmesh::smarktest
void smarktest(face &s)
Definition: tetgenBR.h:2156
tetgenmesh::arraypool::newindex
int newindex(void **newptr)
Definition: tetgenBR.cxx:949
tetgenmesh::triface::ver
int ver
Definition: tetgenBR.h:390
tetgenmesh::hullsize
long hullsize
Definition: tetgenBR.h:820
tetgenmesh::improvequalitybysmoothing
long improvequalitybysmoothing(optparameters *opm)
Definition: tetgenBR.cxx:16774
tetgenmesh::flip23
void flip23(triface *, int, flipconstraints *fc)
Definition: tetgenBR.cxx:4744
tetgenmesh::pointdealloc
void pointdealloc(point)
Definition: tetgenBR.cxx:1439
tetgenbehavior::tetrahedraperblock
int tetrahedraperblock
Definition: tetgenBR.h:94
tetgenmesh::ssbond
void ssbond(face &s, face &edge)
Definition: tetgenBR.h:2310
tetgenmesh::volumeboundindex
int volumeboundindex
Definition: tetgenBR.h:797
tetgenmesh::facenormal
void facenormal(point pa, point pb, point pc, REAL *n, int pivot, REAL *lav)
Definition: tetgenBR.cxx:3189
tetgenmesh::esymtbl
static int esymtbl[12]
Definition: tetgenBR.h:842
tetgenbehavior::minratio
REAL minratio
Definition: tetgenBR.h:120
norm
void norm(const double *vec, double *norm)
Definition: gmshLevelset.cpp:202
tetgenmesh::initialdelaunay
void initialdelaunay(point pa, point pb, point pc, point pd)
Definition: tetgenBR.cxx:8949
tetgenmesh::senext2self
void senext2self(face &s)
Definition: tetgenBR.h:2101
tetgenmesh::insertvertexflags::assignmeshsize
int assignmeshsize
Definition: tetgenBR.h:553
tetgenmesh::ONFACE
@ ONFACE
Definition: tetgenBR.h:715
tetgenbehavior::insertaddpoints
int insertaddpoints
Definition: tetgenBR.h:68
tetgenmesh::eorgoppo
void eorgoppo(triface &t1, triface &t2)
Definition: tetgenBR.h:1677
tetgenbehavior::PLY
@ PLY
Definition: tetgenBR.h:147
tetgenmesh::removefacebyflips
int removefacebyflips(triface *, flipconstraints *)
Definition: tetgenBR.cxx:11991
tetgenmesh::subfacstack
arraypool * subfacstack
Definition: tetgenBR.h:762
tetgenbehavior::diagnose
int diagnose
Definition: tetgenBR.h:69
tetgenmesh::memorypool::traversalinit
void traversalinit()
Definition: tetgenBR.cxx:1163
tetgenmesh::optparameters::initval
REAL initval
Definition: tetgenBR.h:653
tetgenmesh::oppopivot
static int oppopivot[12]
Definition: tetgenBR.h:846
tetgenmesh::identifyinputedges
void identifyinputedges(point *)
Definition: tetgenBR.cxx:11163
tetgenmesh::setelemcounter
void setelemcounter(triface &t, int value)
Definition: tetgenBR.h:1933
tetgenmesh::oppo
point oppo(triface &t)
Definition: tetgenBR.h:1745
tetgenmesh::TOUCHEDGE
@ TOUCHEDGE
Definition: tetgenBR.h:703
tetgenmesh::locateresult
locateresult
Definition: tetgenBR.h:711
tetgenmesh::stpivot
void stpivot(face &s, triface &t)
Definition: tetgenBR.h:2276
robustPredicates::insphere
REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
Definition: robustPredicates.cpp:4200
tetgenmesh::orient4d_s
REAL orient4d_s(REAL *, REAL *, REAL *, REAL *, REAL *, REAL, REAL, REAL, REAL, REAL)
Definition: tetgenBR.cxx:1961
tetgenbehavior::zeroindex
int zeroindex
Definition: tetgenBR.h:75
tetgenbehavior::vertexperblock
int vertexperblock
Definition: tetgenBR.h:93
selfint_event::f_marker1
int f_marker1
Definition: tetgenBR.h:1522
tetgenbehavior::noexact
int noexact
Definition: tetgenBR.h:73
tetgenmesh::projpt2face
void projpt2face(REAL *p, REAL *f1, REAL *f2, REAL *f3, REAL *prj)
Definition: tetgenBR.cxx:3408
tetgenmesh::marktest2ed
bool marktest2ed(triface &t)
Definition: tetgenBR.h:1919
tetgenmesh::flip31count
long flip31count
Definition: tetgenBR.h:831
tetgenmesh::flippush
void flippush(badface *&, triface *)
Definition: tetgenBR.cxx:8680
tetgenmesh::apex
point apex(triface &t)
Definition: tetgenBR.h:1740
tetgenbehavior::no_sort
int no_sort
Definition: tetgenBR.h:111
tetgenmesh::sstpivot1
void sstpivot1(face &s, triface &t)
Definition: tetgenBR.h:2385
tetgenmesh::pointparamindex
int pointparamindex
Definition: tetgenBR.h:792
tetgenmesh::badsubsegs
memorypool * badsubsegs
Definition: tetgenBR.h:748
tetgenmesh::memorypool::deaditemstack
void * deaditemstack
Definition: tetgenBR.h:490
tetgenmesh::sinsertvertex
int sinsertvertex(point newpt, face *, face *, int iloc, int bowywat, int)
Definition: tetgenBR.cxx:9578
tetgenmesh::sremovevertex
int sremovevertex(point delpt, face *, face *, int lawson)
Definition: tetgenBR.cxx:10079
selfint_event::s_marker1
int s_marker1
Definition: tetgenBR.h:1523
tetgenmesh::unmarkface
void unmarkface(triface &t)
Definition: tetgenBR.h:1875
tetgenmesh::enext
void enext(triface &t1, triface &t2)
Definition: tetgenBR.h:1618
tetgenmesh::bond
void bond(triface &t1, triface &t2)
Definition: tetgenBR.h:1606
tetgenmesh::point
REAL * point
Definition: tetgenBR.h:330
tetgenmesh::memorypool
Definition: tetgenBR.h:486
tetgenmesh::improvequalitybyflips
long improvequalitybyflips()
Definition: tetgenBR.cxx:16425
tetgenbehavior::edgesout
int edgesout
Definition: tetgenBR.h:77
tetgenmesh::ssdissolve
void ssdissolve(face &s)
Definition: tetgenBR.h:2324
tetgenbehavior::refine
int refine
Definition: tetgenBR.h:55
tetgenmesh::tsbondtbl
static int tsbondtbl[12][6]
Definition: tetgenBR.h:847
tetgenmesh::sstdissolve1
void sstdissolve1(face &s)
Definition: tetgenBR.h:2366
tetgenmesh::dot
REAL dot(REAL *v1, REAL *v2)
Definition: tetgenBR.h:2640
tetgenmesh::shellfacedealloc
void shellfacedealloc(memorypool *, shellface *)
Definition: tetgenBR.cxx:1404
tetgenmesh::insertvertexflags::sbowywat
int sbowywat
Definition: tetgenBR.h:554
tetgenmesh::ENCVERTEX
@ ENCVERTEX
Definition: tetgenBR.h:718
mult
Quaternion mult(const Quaternion &A, const Quaternion &B)
Definition: Camera.cpp:459
tetgenmesh::lawsonflip
long lawsonflip()
Definition: tetgenBR.cxx:9496
tetgenbehavior::flipstarsize
int flipstarsize
Definition: tetgenBR.h:102
fastlookup
#define fastlookup(pool, index)
Definition: tetgenBR.h:458
tetgenmesh::triface
Definition: tetgenBR.h:387
tetgenmesh::areabound
REAL areabound(face &s)
Definition: tetgenBR.h:2108
tetgenbehavior::optminslidihed
REAL optminslidihed
Definition: tetgenBR.h:124
tetgenmesh::areaboundindex
int areaboundindex
Definition: tetgenBR.h:800
tetgenmesh::checksubfaceflag
int checksubfaceflag
Definition: tetgenBR.h:802
tetgenmesh::shmarkindex
int shmarkindex
Definition: tetgenBR.h:799
tetgenmesh::removevertexbyflips
int removevertexbyflips(point steinerpt)
Definition: tetgenBR.cxx:13745
tetgenmesh::flipconstraints
Definition: tetgenBR.h:589
tetgenmesh::dummypoint
point dummypoint
Definition: tetgenBR.h:775
tetgenmesh::senextself
void senextself(face &s)
Definition: tetgenBR.h:2093
if
if(!yymsg) yymsg
tetgenbehavior::hilbert_order
int hilbert_order
Definition: tetgenBR.h:112
tetgenmesh::ONVERTEX
@ ONVERTEX
Definition: tetgenBR.h:717
tetgenmesh::removeedgebyflips
int removeedgebyflips(triface *, flipconstraints *)
Definition: tetgenBR.cxx:11898
tetgenmesh::setoppo
void setoppo(triface &t, point p)
Definition: tetgenBR.h:1765
tetgenmesh::inittables
void inittables()
Definition: tetgenBR.cxx:675
tetgenbehavior::delmaxfliplevel
int delmaxfliplevel
Definition: tetgenBR.h:107
tetgenmesh::initializepools
void initializepools()
Definition: tetgenBR.cxx:1591
tetgenmesh::RIDGEVERTEX
@ RIDGEVERTEX
Definition: tetgenBR.h:685
tetgenmesh::subsegs
memorypool * subsegs
Definition: tetgenBR.h:744
tetgenmesh::badface::cent
REAL cent[6]
Definition: tetgenBR.h:530
tetgenmesh::tri_edge_inter_tail
int tri_edge_inter_tail(point, point, point, point, point, REAL, REAL)
Definition: tetgenBR.cxx:2875
tetgenmesh::SHAREVERT
@ SHAREVERT
Definition: tetgenBR.h:700
tetgenmesh::ACROSSVERT
@ ACROSSVERT
Definition: tetgenBR.h:705
tetgenmesh::pointmtrindex
int pointmtrindex
Definition: tetgenBR.h:791
tetgenmesh::tet2subpool
memorypool * tet2subpool
Definition: tetgenBR.h:745
tetgenmesh::memorypool::maxitems
long maxitems
Definition: tetgenBR.h:496
tetgenbehavior::metric
int metric
Definition: tetgenBR.h:63
tetgenbehavior::facet_small_ang_tol
REAL facet_small_ang_tol
Definition: tetgenBR.h:118
tetgenmesh::enexttbl
static int enexttbl[12]
Definition: tetgenBR.h:842
tetgenmesh::sinfected
bool sinfected(face &s)
Definition: tetgenBR.h:2148
tetgenbehavior::plc
int plc
Definition: tetgenBR.h:53
tetgenmesh::recoverdelaunay
void recoverdelaunay()
Definition: tetgenBR.cxx:16219
tetgenmesh::elemattribindex
int elemattribindex
Definition: tetgenBR.h:796
tetgenmesh::sdissolve
void sdissolve(face &s)
Definition: tetgenBR.h:2019
tetgenmesh::memorypool::restart
void restart()
Definition: tetgenBR.cxx:1063
selfint_event::e_type
int e_type
Definition: tetgenBR.h:1521
tetgenmesh::sdestpivot
static int sdestpivot[6]
Definition: tetgenBR.h:850
tetgenmesh::norm2
REAL norm2(REAL x, REAL y, REAL z)
Definition: tetgenBR.h:2661
tetgenmesh::tsdissolve
void tsdissolve(triface &t)
Definition: tetgenBR.h:2289
selfint_event::s_marker2
int s_marker2
Definition: tetgenBR.h:1526
tetgenmesh::add_steinerpt_in_segment
int add_steinerpt_in_segment(face *, int searchlevel)
Definition: tetgenBR.cxx:12498
tetgenmesh::fnext
void fnext(triface &t1, triface &t2)
Definition: tetgenBR.h:1716
tetgenmesh::tet2segpool
memorypool * tet2segpool
Definition: tetgenBR.h:745
tetgenmesh::FREEVOLVERTEX
@ FREEVOLVERTEX
Definition: tetgenBR.h:691
tetgenbehavior::supsteiner_level
int supsteiner_level
Definition: tetgenBR.h:97
tetgenmesh::ACROSSEDGE
@ ACROSSEDGE
Definition: tetgenBR.h:706
tetgenmesh::checkconstraints
int checkconstraints
Definition: tetgenBR.h:803
tetgenmesh::markface
void markface(triface &t)
Definition: tetgenBR.h:1870
tetgenmesh::triface::tet
tetrahedron * tet
Definition: tetgenBR.h:389
point
Definition: shapeFunctions.h:305
tetgenmesh::point2tetorg
void point2tetorg(point pt, triface &t)
Definition: tetgenBR.h:2571
selfint_event::f_vertices2
int f_vertices2[3]
Definition: tetgenBR.h:1527
tetgenmesh::senext
void senext(face &s1, face &s2)
Definition: tetgenBR.h:2087
tetgenmesh::recoversubfaces
int recoversubfaces(arraypool *, int steinerflag)
Definition: tetgenBR.cxx:13146
tetgenmesh::flip32
void flip32(triface *, int, flipconstraints *fc)
Definition: tetgenBR.cxx:5083
tetgenbehavior::voroout
int voroout
Definition: tetgenBR.h:79
tetgenmesh::eprevesymtbl
static int eprevesymtbl[12]
Definition: tetgenBR.h:843
tetgenmesh::finddirection
enum interresult finddirection(triface *searchtet, point endpt)
Definition: tetgenBR.cxx:11457
tetgenmesh::zmin
REAL zmin
Definition: tetgenBR.h:816
tetgenmesh::cossmtdihed
REAL cossmtdihed
Definition: tetgenBR.h:810
tetgenmesh::VOLVERTEX
@ VOLVERTEX
Definition: tetgenBR.h:688
tetgenmesh::fsym
void fsym(triface &t1, triface &t2)
Definition: tetgenBR.h:1701
tetgenmesh::arraypool::restart
void restart()
Definition: tetgenBR.cxx:765
tetgenmesh::removeslivers
long removeslivers(int)
Definition: tetgenBR.cxx:17052
tetgenbehavior::noiterationnum
int noiterationnum
Definition: tetgenBR.h:86
tetgenbehavior::NODES
@ NODES
Definition: tetgenBR.h:147
tetgenmesh::facepivot2
static int facepivot2[12][12]
Definition: tetgenBR.h:845
tetgenmesh::optparameters::min_max_dihedangle
int min_max_dihedangle
Definition: tetgenBR.h:650
tetgenmesh::getedge
int getedge(point, point, triface *)
Definition: tetgenBR.cxx:13540
tetgenmesh::getvertexstar
int getvertexstar(int, point searchpt, arraypool *, arraypool *, arraypool *)
Definition: tetgenBR.cxx:13398
tetgenbehavior::regionattrib
int regionattrib
Definition: tetgenBR.h:66
tetgenbehavior::order
int order
Definition: tetgenBR.h:108
tetgenmesh::sbond1
void sbond1(face &s1, face &s2)
Definition: tetgenBR.h:2011
tetgenmesh::FACETVERTEX
@ FACETVERTEX
Definition: tetgenBR.h:687
tetgenbehavior::optmaxdihedral
REAL optmaxdihedral
Definition: tetgenBR.h:122
tetgenmesh::unuverts
long unuverts
Definition: tetgenBR.h:825
tetgenmesh::nonregularcount
long nonregularcount
Definition: tetgenBR.h:826
tetgenmesh::PI
static REAL PI
Definition: tetgenBR.h:781
tetgenmesh::badsubfacs
memorypool * badsubfacs
Definition: tetgenBR.h:748
tetgenmesh::tetprism_vol_sum
REAL tetprism_vol_sum
Definition: tetgenBR.h:813
tetgenmesh::eprevself
void eprevself(triface &t)
Definition: tetgenBR.h:1634
tetgenmesh::sunmarktest
void sunmarktest(face &s)
Definition: tetgenBR.h:2162
setvertices
#define setvertices(t, torg, tdest, tapex, toppo)
Definition: tetgenBR.h:1770
tetgenbehavior::facesout
int facesout
Definition: tetgenBR.h:76
tetgenmesh::NEARVERTEX
@ NEARVERTEX
Definition: tetgenBR.h:721
tetgenmesh::eorgoppoself
void eorgoppoself(triface &t)
Definition: tetgenBR.h:1683
tetgenmesh::xmax
REAL xmax
Definition: tetgenBR.h:816
tetgenmesh::badface::foppo
point foppo
Definition: tetgenBR.h:531
tetgenmesh::insertvertexflags::bowywat
int bowywat
Definition: tetgenBR.h:550
tetgenmesh::senext2
void senext2(face &s1, face &s2)
Definition: tetgenBR.h:2095
z
const double z
Definition: GaussQuadratureQuad.cpp:56
tetgenmesh::sizeoftensor
int sizeoftensor
Definition: tetgenBR.h:790
tetgenmesh::addsteiner4recoversegment
int addsteiner4recoversegment(face *, int)
Definition: tetgenBR.cxx:12669
tetgenmesh::reduceedgesatvertex
int reduceedgesatvertex(point startpt, arraypool *endptlist)
Definition: tetgenBR.cxx:13658
tetgenmesh::tssdissolve1
void tssdissolve1(triface &t)
Definition: tetgenBR.h:2359
tetgenmesh::xmin
REAL xmin
Definition: tetgenBR.h:816
tetgenmesh::insertvertexflags::respectbdflag
int respectbdflag
Definition: tetgenBR.h:551
O
#define O
Definition: DefaultOptions.h:22
tetgenmesh::UNUSEDVERTEX
@ UNUSEDVERTEX
Definition: tetgenBR.h:683
tetgenmesh::arraypool::lookup
void * lookup(int objectindex)
Definition: tetgenBR.cxx:912
tetgenbehavior::nobisect_nomerge
int nobisect_nomerge
Definition: tetgenBR.h:96
tetgenbehavior::weighted_param
int weighted_param
Definition: tetgenBR.h:100
tetgenmesh::getfacetindex
int getfacetindex(face &f)
Definition: tetgenBR.h:2220
tetgenmesh::nonconvex
int nonconvex
Definition: tetgenBR.h:804
tetgenbehavior::steinerleft
int steinerleft
Definition: tetgenBR.h:110
tetgenmesh::pinfect
void pinfect(point pt)
Definition: tetgenBR.h:2446
tetgenmesh::memorypool::itemwords
int itemwords
Definition: tetgenBR.h:494
tetgenbehavior::nomergevertex
int nomergevertex
Definition: tetgenBR.h:72
tetrahedron
Definition: shapeFunctions.h:682
tetgenmesh::ENCSEGMENT
@ ENCSEGMENT
Definition: tetgenBR.h:719
tetgenmesh::subvertstack
arraypool * subvertstack
Definition: tetgenBR.h:762
tetgenbehavior::brio_hilbert
int brio_hilbert
Definition: tetgenBR.h:60
tetgenmesh::epivot
static int epivot[12]
Definition: tetgenBR.h:849
tetgenmesh::eorgoppotbl
static int eorgoppotbl[12]
Definition: tetgenBR.h:844
tetgenmesh::randomseed
unsigned long randomseed
Definition: tetgenBR.h:808
tetgenmesh::add_steinerpt_in_schoenhardtpoly
int add_steinerpt_in_schoenhardtpoly(triface *, int, int chkencflag)
Definition: tetgenBR.cxx:12343
tetgenmesh::setareabound
void setareabound(face &s, REAL value)
Definition: tetgenBR.h:2113
tetgenmesh::caveencshlist
arraypool * caveencshlist
Definition: tetgenBR.h:758
tetgenmesh::elemmarkerindex
int elemmarkerindex
Definition: tetgenBR.h:798
tetgenmesh::verttype
verttype
Definition: tetgenBR.h:682
tetgenbehavior::parse_commandline
bool parse_commandline(int argc, char **argv)
Definition: tetgenBR.cxx:41
tetgenmesh::steinerleft
long steinerleft
Definition: tetgenBR.h:823
tetgenmesh::subsegstack
arraypool * subsegstack
Definition: tetgenBR.h:762
tetgenmesh::jettisonnodes
void jettisonnodes()
Definition: tetgenBR.cxx:17331
tetgenmesh::enextesymself
void enextesymself(triface &t)
Definition: tetgenBR.h:1656
tetgenmesh::memorypool::alloc
void * alloc()
Definition: tetgenBR.cxx:1090
tetgenmesh::ONEDGE
@ ONEDGE
Definition: tetgenBR.h:716
tetgenmesh::tsb1mod3
int tsb1mod3[8]
Definition: tetgenBR.h:1239
tetgenmesh::point2tet
tetrahedron point2tet(point pt)
Definition: tetgenBR.h:2512
tetgenmesh::cavetetshlist
arraypool * cavetetshlist
Definition: tetgenBR.h:757
tetgenmesh::optparameters::imprval
REAL imprval
Definition: tetgenBR.h:653
tetgenmesh::triarea
REAL triarea(REAL *pa, REAL *pb, REAL *pc)
Definition: tetgenBR.cxx:3283
tetgenmesh::memorypool::items
long items
Definition: tetgenBR.h:496
tetgenbehavior::varvolume
int varvolume
Definition: tetgenBR.h:64
tetgenmesh::enextesymtbl
static int enextesymtbl[12]
Definition: tetgenBR.h:843
tetgenbehavior::coarsen_param
int coarsen_param
Definition: tetgenBR.h:99
robustPredicates::orient3d
REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
Definition: robustPredicates.cpp:2321
tetgenmesh::flippool
memorypool * flippool
Definition: tetgenBR.h:751
tetgenmesh::setpoint2ppt
void setpoint2ppt(point pt, point value)
Definition: tetgenBR.h:2527
tetgenmesh::shortdistance
REAL shortdistance(REAL *p, REAL *e1, REAL *e2)
Definition: tetgenBR.cxx:3255
tetgenmesh::tri_edge_tail
int tri_edge_tail(point, point, point, point, point, point, REAL, REAL, int, int *, int *)
Definition: tetgenBR.cxx:2655
setshvertices
#define setshvertices(s, pa, pb, pc)
Definition: tetgenBR.h:2069
tetgenmesh::fsymself
void fsymself(triface &t)
tetgenmesh::optparameters::searchstep
REAL searchstep
Definition: tetgenBR.h:656
tetgenmesh::memorypool::~memorypool
~memorypool()
Definition: tetgenBR.cxx:994
tetgenmesh::setpoint2tet
void setpoint2tet(point pt, tetrahedron value)
Definition: tetgenBR.h:2517
tetgenmesh::addin
tetgenio * addin
Definition: tetgenBR.h:734
tetgenbehavior::mindihedral
REAL mindihedral
Definition: tetgenBR.h:121
tetgenmesh::ishulltet
bool ishulltet(triface &t)
Definition: tetgenBR.h:1956
tetgenmesh::flip14count
long flip14count
Definition: tetgenBR.h:829
tetgenmesh::flip23count
long flip23count
Definition: tetgenBR.h:830
tetgenmesh::samples
long samples
Definition: tetgenBR.h:807
tetgenbehavior::nomergefacet
int nomergefacet
Definition: tetgenBR.h:71
tetgenmesh::point2simindex
int point2simindex
Definition: tetgenBR.h:793
tetgenmesh::cavetetvertlist
arraypool * cavetetvertlist
Definition: tetgenBR.h:757
tetgenbehavior::flipinsert
int flipinsert
Definition: tetgenBR.h:62
tetgenbehavior::fliplinklevel
int fliplinklevel
Definition: tetgenBR.h:101
tetgenmesh::tetprismvol
REAL tetprismvol(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
Definition: tetgenBR.cxx:3884
tetgenmesh::cross
void cross(REAL *v1, REAL *v2, REAL *n)
Definition: tetgenBR.h:2646
tetgenmesh::optparameters::max_min_volume
int max_min_volume
Definition: tetgenBR.h:648
tetgenmesh::tri_edge_2d
int tri_edge_2d(point, point, point, point, point, point, int, int *, int *)
Definition: tetgenBR.cxx:2044
tetgenbehavior::brio_ratio
REAL brio_ratio
Definition: tetgenBR.h:115
tetgenmesh::TOUCHFACE
@ TOUCHFACE
Definition: tetgenBR.h:704
tetgenmesh::arraypool::arraypool
arraypool(int sizeofobject, int log2objperblk)
Definition: tetgenBR.cxx:805
tetgenmesh::ymin
REAL ymin
Definition: tetgenBR.h:816
tetgenmesh::insertvertexflags::refinetet
triface refinetet
Definition: tetgenBR.h:558
tetgenmesh::NONREGULAR
@ NONREGULAR
Definition: tetgenBR.h:722
tetgenmesh::numpointattrib
int numpointattrib
Definition: tetgenBR.h:788
tetgenmesh::tetalldihedral
bool tetalldihedral(point, point, point, point, REAL *, REAL *, REAL *)
Definition: tetgenBR.cxx:3444
tetgenbehavior::cdtrefine
int cdtrefine
Definition: tetgenBR.h:67
tetgenmesh::memorypool::memorypool
memorypool()
Definition: tetgenBR.cxx:967
tetgenmesh::insertvertexflags::smlenflag
int smlenflag
Definition: tetgenBR.h:560
tetgenmesh::INTERSECT
@ INTERSECT
Definition: tetgenBR.h:699
tetgenmesh::checksubsegflag
int checksubsegflag
Definition: tetgenBR.h:801
tetgenmesh::lawsonflip3d
long lawsonflip3d(flipconstraints *fc)
Definition: tetgenBR.cxx:15931
tetgenmesh::useinsertradius
int useinsertradius
Definition: tetgenBR.h:806
tetgenmesh::arraypool::objects
long objects
Definition: tetgenBR.h:441
tetgenmesh::insertvertexflags
Definition: tetgenBR.h:547
tetgenmesh::tetrahedrons
memorypool * tetrahedrons
Definition: tetgenBR.h:744
tetgenmesh::eprev
void eprev(triface &t1, triface &t2)
Definition: tetgenBR.h:1628
tetgenmesh::recoverboundary
void recoverboundary(clock_t &)
Definition: tetgenBR.cxx:14934
tetgenmesh::cavebdrylist
arraypool * cavebdrylist
Definition: tetgenBR.h:756
tetgenbehavior::fliplinklevelinc
int fliplinklevelinc
Definition: tetgenBR.h:103
tetgenmesh::ver2edge
static int ver2edge[12]
Definition: tetgenBR.h:849
tetgenmesh::insertvertexflags::parentpt
point parentpt
Definition: tetgenBR.h:562
tetgenbehavior::hilbert_limit
int hilbert_limit
Definition: tetgenBR.h:113
tetgenmesh::memorypool::traverse
void * traverse()
Definition: tetgenBR.cxx:1191
tetgenmesh::brio_multiscale_sort
void brio_multiscale_sort(point *, int, int threshold, REAL ratio, int *depth)
Definition: tetgenBR.cxx:8315
robustPredicates::orient4d
REAL orient4d(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, REAL aheight, REAL bheight, REAL cheight, REAL dheight, REAL eheight)
Definition: robustPredicates.cpp:4739
tetgenmesh::minedgelength
REAL minedgelength
Definition: tetgenBR.h:815
tetgenbehavior::psc
int psc
Definition: tetgenBR.h:54
tetgenbehavior::facet_separate_ang_tol
REAL facet_separate_ang_tol
Definition: tetgenBR.h:116
tetgenmesh::optparameters::maxiter
int maxiter
Definition: tetgenBR.h:657
tetgenbehavior::coarsen
int coarsen
Definition: tetgenBR.h:58
tetgenmesh::elemcounter
int elemcounter(triface &t)
Definition: tetgenBR.h:1928
tetgenmesh::makepoint2submap
void makepoint2submap(memorypool *, int *&, face *&)
Definition: tetgenBR.cxx:1264
tetgenmesh::face::shver
int shver
Definition: tetgenBR.h:403
tetgenmesh::sstbond1
void sstbond1(face &s, triface &t)
Definition: tetgenBR.h:2354
tetgenmesh::smoothpoint
int smoothpoint(point smtpt, arraypool *, int ccw, optparameters *opm)
Definition: tetgenBR.cxx:16615
tetgenbehavior::weighted
int weighted
Definition: tetgenBR.h:59
tetgenmesh::alltetrahedrontraverse
tetrahedron * alltetrahedrontraverse()
Definition: tetgenBR.cxx:1384
tetgenmesh::flipstack
badface * flipstack
Definition: tetgenBR.h:753
tetgenmesh::caveoldtetlist
arraypool * caveoldtetlist
Definition: tetgenBR.h:756
tetgenmesh::org
point org(triface &t)
Definition: tetgenBR.h:1730
tetgenbehavior::nofacewritten
int nofacewritten
Definition: tetgenBR.h:85
tetgenmesh::smarktest2
void smarktest2(face &s)
Definition: tetgenBR.h:2176
tetgenmesh::insertvertexflags::refinesh
face refinesh
Definition: tetgenBR.h:559
tetgenmesh::farsdest
point farsdest(face &seg)
Definition: tetgenBR.h:2618
tetgenmesh::spivot
void spivot(face &s1, face &s2)
Definition: tetgenBR.h:2024
tetgenmesh::eprevesym
void eprevesym(triface &t1, triface &t2)
Definition: tetgenBR.h:1663
tetgenmesh::gettetrahedron
int gettetrahedron(point, point, point, point, triface *)
Definition: tetgenBR.cxx:16388
tetgenmesh::maketetrahedron
void maketetrahedron(triface *)
Definition: tetgenBR.cxx:1472
tetgenmesh::planelineint
void planelineint(REAL *, REAL *, REAL *, REAL *, REAL *, REAL *, REAL *)
Definition: tetgenBR.cxx:3790
tetgenmesh::insertpoint_abort
void insertpoint_abort(face *, insertvertexflags *)
Definition: tetgenBR.cxx:8037
tetgenmesh::recentsh
face recentsh
Definition: tetgenBR.h:778
tetgenmesh::FREESEGVERTEX
@ FREESEGVERTEX
Definition: tetgenBR.h:689
tetgenmesh::pointinsradiusindex
int pointinsradiusindex
Definition: tetgenBR.h:795
tetgenmesh::flip31
void flip31(face *, int)
Definition: tetgenBR.cxx:9403
tetgenmesh::shellface
REAL ** shellface
Definition: tetgenBR.h:313
tetgenmesh::checkflipeligibility
int checkflipeligibility(int fliptype, point, point, point, point, point, int level, int edgepivot, flipconstraints *fc)
Definition: tetgenBR.cxx:11663
tetgenmesh::face
Definition: tetgenBR.h:400
tetgenmesh::memorypool::alignbytes
int alignbytes
Definition: tetgenBR.h:493
tetgenmesh::st_segref_count
long st_segref_count
Definition: tetgenBR.h:827