Skip to content
Snippets Groups Projects
Select Git revision
  • 7b260816785a9f6e87f84005f7925d5e57caed80
  • master default
  • cgnsUnstructured
  • partitioning
  • poppler
  • HighOrderBLCurving
  • gmsh_3_0_4
  • gmsh_3_0_3
  • gmsh_3_0_2
  • gmsh_3_0_1
  • gmsh_3_0_0
  • gmsh_2_16_0
  • gmsh_2_15_0
  • gmsh_2_14_1
  • gmsh_2_14_0
  • gmsh_2_13_2
  • gmsh_2_13_1
  • gmsh_2_12_0
  • gmsh_2_11_0
  • gmsh_2_10_1
  • gmsh_2_10_0
  • gmsh_2_9_3
  • gmsh_2_9_2
  • gmsh_2_9_1
  • gmsh_2_9_0
  • gmsh_2_8_6
26 results

tetgen.cxx

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    tetgen.cxx 1.09 MiB
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // TetGen                                                                    //
    //                                                                           //
    // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
    //                                                                           //
    // Version 1.5                                                               //
    // February 21, 2012                                                         //
    //                                                                           //
    // PRE-RELEASE TEST CODE.                                                    //
    // PLEASE DO NOT DISTRIBUTE !!                                               //
    // PLEASE HELP ME TO IMPROVE IT !!                                           //
    //                                                                           //
    // Copyright (C) 2002--2012                                                  //
    // Hang Si                                                                   //
    // Research Group: Numerical Mathematics and Scientific Computing            //
    // Weierstrass Institute for Applied Analysis and Stochastics (WIAS)         //
    // Mohrenstr. 39, 10117 Berlin, Germany                                      //
    // Hang.Si@wias-berlin.de                                                    //
    //                                                                           //
    // TetGen is freely available through the website: http://www.tetgen.org.    //
    //   It may be copied, modified, and redistributed for non-commercial use.   //
    //   Please consult the file LICENSE for the detailed copyright notices.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    #include "tetgen.h"
    
    //// io_cxx ///////////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_node_call()    Read a list of points from a file.                    //
    //                                                                           //
    // 'infile' is the file handle contains the node list.  It may point to a    //
    // .node, or .poly or .smesh file. 'markers' indicates each node contains an //
    // additional marker (integer) or not. 'uvflag' indicates each node contains //
    // u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
    // of the file being read,  it is only used in error messages.               //
    //                                                                           //
    // The 'firstnumber' (0 or 1) is automatically determined by the number of   //
    // the first index of the first point.                                       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag, 
                                  char* infilename)
    {
      char inputline[INPUTLINESIZE];
      char *stringptr;
      REAL x, y, z, attrib;
      int firstnode, currentmarker;
      int index, attribindex;
      int i, j;
    
      // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
      pointlist = new REAL[numberofpoints * 3];
      if (pointlist == (REAL *) NULL) {
        terminatetetgen(1);
      }
      if (numberofpointattributes > 0) {
        pointattributelist = new REAL[numberofpoints * numberofpointattributes];
        if (pointattributelist == (REAL *) NULL) {
          terminatetetgen(1);
        }
      }
      if (markers) {
        pointmarkerlist = new int[numberofpoints];
        if (pointmarkerlist == (int *) NULL) {
          terminatetetgen(1);
        }
      }
      if (uvflag) {
        pointparamlist = new pointparam[numberofpoints];
        if (pointparamlist == NULL) {
          terminatetetgen(1);
        }
      }
    
      // Read the point section.
      index = 0;
      attribindex = 0;
      for (i = 0; i < numberofpoints; i++) {
        stringptr = readnumberline(inputline, infile, infilename);
        if (useindex) {
          if (i == 0) {
            firstnode = (int) strtol (stringptr, &stringptr, 0);
            if ((firstnode == 0) || (firstnode == 1)) {
              firstnumber = firstnode;
            }
          }
          stringptr = findnextnumber(stringptr);
        } // if (useindex)
        if (*stringptr == '\0') {
          printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
          break;
        }
        x = (REAL) strtod(stringptr, &stringptr);
        stringptr = findnextnumber(stringptr);
        if (*stringptr == '\0') {
          printf("Error:  Point %d has no y coordinate.\n", firstnumber + i);
          break;
        }
        y = (REAL) strtod(stringptr, &stringptr);
        if (mesh_dim == 3) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
            break;
          }
          z = (REAL) strtod(stringptr, &stringptr);
        } else {
          z = 0.0; // mesh_dim == 2;
        }
        pointlist[index++] = x;
        pointlist[index++] = y;
        pointlist[index++] = z;
        // Read the point attributes.
        for (j = 0; j < numberofpointattributes; j++) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            attrib = 0.0;
          } else {
            attrib = (REAL) strtod(stringptr, &stringptr);
          }
          pointattributelist[attribindex++] = attrib;
        }
        if (markers) {
          // Read a point marker.
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            currentmarker = 0;
          } else {
            currentmarker = (int) strtol (stringptr, &stringptr, 0);
          }
          pointmarkerlist[i] = currentmarker;
        }
        if (uvflag) {
          // Read point paramteters.
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Point %d has no uv[0].\n", firstnumber + i);
            break;
          }
          pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Point %d has no uv[1].\n", firstnumber + i);
            break;
          }
          pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Point %d has no tag.\n", firstnumber + i);
            break;
          }
          pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Point %d has no type.\n", firstnumber + i);
            break;
          }
          pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
          if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
            printf("Error:  Point %d has an invalid type.\n", firstnumber + i);
            break;
          }
        }
      }
      if (i < numberofpoints) {
        // Failed to read points due to some error.
        delete [] pointlist;
        pointlist = (REAL *) NULL;
        if (markers) {
          delete [] pointmarkerlist;
          pointmarkerlist = (int *) NULL;
        }
        if (numberofpointattributes > 0) {
          delete [] pointattributelist;
          pointattributelist = (REAL *) NULL;
        }
        if (uvflag) {
          delete [] pointparamlist;
          pointparamlist = NULL;
        }
        numberofpoints = 0;
        return false;
      }
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_node()    Load a list of points from a .node file.                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_node(char* filebasename)
    {
      FILE *infile;
      char innodefilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr;
      bool okflag;
      int markers;
      int uvflag; // for psc input.
    
      // Assembling the actual file names we want to open.
      strcpy(innodefilename, filebasename);
      strcat(innodefilename, ".node");
    
      // Try to open a .node file.
      infile = fopen(innodefilename, "r");
      if (infile == (FILE *) NULL) {
        printf("  Cannot access file %s.\n", innodefilename);
        return false;
      }
      printf("Opening %s.\n", innodefilename); 
    
      // Set initial flags.
      mesh_dim = 3;
      numberofpointattributes = 0;  // no point attribute.
      markers = 0;  // no boundary marker.
      uvflag = 0; // no uv parameters (reuqired by a PSC). 
    
      // Read the first line of the file.
      stringptr = readnumberline(inputline, infile, innodefilename);
      // Does this file contain an index colume?
      stringptr = strstr(inputline, "rbox");
      if (stringptr == NULL) {
        // Read number of points, number of dimensions, number of point
        //   attributes, and number of boundary markers. 
        stringptr = inputline;
        numberofpoints = (int) strtol (stringptr, &stringptr, 0);
        stringptr = findnextnumber(stringptr);
        if (*stringptr != '\0') {
          mesh_dim = (int) strtol (stringptr, &stringptr, 0);
        }
        stringptr = findnextnumber(stringptr);
        if (*stringptr != '\0') {
          numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
        }
        stringptr = findnextnumber(stringptr);
        if (*stringptr != '\0') {
          markers = (int) strtol (stringptr, &stringptr, 0);
        }
        stringptr = findnextnumber(stringptr);
        if (*stringptr != '\0') {
          uvflag = (int) strtol (stringptr, &stringptr, 0);
        }
      } else {
        // It is a rbox (qhull) input file.
        stringptr = inputline;
        // Get the dimension.
        mesh_dim = (int) strtol (stringptr, &stringptr, 0);
        // Get the number of points.
        stringptr = readnumberline(inputline, infile, innodefilename);
        numberofpoints = (int) strtol (stringptr, &stringptr, 0);
        // There is no index column.
        useindex = 0;
      }
    
      // Load the list of nodes.
      okflag = load_node_call(infile, markers, uvflag, innodefilename);
    
      fclose(infile);
      return okflag;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_edge()    Load a list of edges from a .edge file.                    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_edge(char* filebasename)
    {
      FILE *infile;
      char inedgefilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr;
      int markers, corner;
      int index;
      int i, j;
    
      strcpy(inedgefilename, filebasename);
      strcat(inedgefilename, ".edge");
    
      infile = fopen(inedgefilename, "r");
      if (infile != (FILE *) NULL) {
        printf("Opening %s.\n", inedgefilename);
      } else {
        //printf("  Cannot access file %s.\n", inedgefilename);
        return false;
      }
    
      // Read number of boundary edges.
      stringptr = readnumberline(inputline, infile, inedgefilename);
      numberofedges = (int) strtol (stringptr, &stringptr, 0);
      if (numberofedges > 0) {
        edgelist = new int[numberofedges * 2];
        if (edgelist == (int *) NULL) {
          terminatetetgen(1);
        }
        stringptr = findnextnumber(stringptr);
        if (*stringptr == '\0') {
          markers = 0;  // Default value.
        } else {
          markers = (int) strtol (stringptr, &stringptr, 0);
        }
        if (markers > 0) {
          edgemarkerlist = new int[numberofedges];
        }
      }
    
      // Read the list of edges.
      index = 0;
      for (i = 0; i < numberofedges; i++) {
        // Read edge index and the edge's two endpoints.
        stringptr = readnumberline(inputline, infile, inedgefilename);
        for (j = 0; j < 2; j++) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Edge %d is missing vertex %d in %s.\n",
                   i + firstnumber, j + 1, inedgefilename);
            terminatetetgen(1);
          }
          corner = (int) strtol(stringptr, &stringptr, 0);
          if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
            printf("Error:  Edge %d has an invalid vertex index.\n",
                   i + firstnumber);
            terminatetetgen(1);
          }
          edgelist[index++] = corner;
        }
        // Read the edge marker if it has.
        if (markers) {
          stringptr = findnextnumber(stringptr);
          edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
        }
      }
    
      fclose(infile);
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_face()    Load a list of faces (triangles) from a .face file.        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_face(char* filebasename)
    {
      FILE *infile;
      char infilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr;
      REAL attrib;
      int markers, corner;
      int index;
      int i, j;
    
      strcpy(infilename, filebasename);
      strcat(infilename, ".face");
    
      infile = fopen(infilename, "r");
      if (infile != (FILE *) NULL) {
        printf("Opening %s.\n", infilename);
      } else {
        return false;
      }
    
      // Read number of faces, boundary markers.
      stringptr = readnumberline(inputline, infile, infilename);
      numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
      stringptr = findnextnumber(stringptr);
      if (mesh_dim == 2) {
        // Skip a number.
        stringptr = findnextnumber(stringptr);
      }
      if (*stringptr == '\0') {
        markers = 0;  // Default there is no marker per face.
      } else {
        markers = (int) strtol (stringptr, &stringptr, 0);
      }
      if (numberoftrifaces > 0) {
        trifacelist = new int[numberoftrifaces * 3];
        if (trifacelist == (int *) NULL) {
          terminatetetgen(1);
        }
        if (markers) {
          trifacemarkerlist = new int[numberoftrifaces];
          if (trifacemarkerlist == (int *) NULL) {
            terminatetetgen(1);
          }
        }
      }
    
      // Read the list of faces.
      index = 0;
      for (i = 0; i < numberoftrifaces; i++) {
        // Read face index and the face's three corners.
        stringptr = readnumberline(inputline, infile, infilename);
        for (j = 0; j < 3; j++) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Face %d is missing vertex %d in %s.\n",
                   i + firstnumber, j + 1, infilename);
            terminatetetgen(1);
          }
          corner = (int) strtol(stringptr, &stringptr, 0);
          if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
            printf("Error:  Face %d has an invalid vertex index.\n",
                   i + firstnumber);
            terminatetetgen(1);
          }
          trifacelist[index++] = corner;
        }
        // Read the boundary marker if it exists.
        if (markers) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            attrib = 0.0;
          } else {
            attrib = (REAL) strtod(stringptr, &stringptr);
          }
          trifacemarkerlist[i] = (int) attrib;
        }
      }
    
      fclose(infile);
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_tet()    Load a list of tetrahedra from a .ele file.                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_tet(char* filebasename)
    {
      FILE *infile;
      char infilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr;
      REAL attrib;
      int corner;
      int index, attribindex;
      int i, j;
    
      strcpy(infilename, filebasename);
      strcat(infilename, ".ele");
    
      infile = fopen(infilename, "r");
      if (infile != (FILE *) NULL) {
        printf("Opening %s.\n", infilename);
      } else {
        return false;
      }
    
      // Read number of elements, number of corners (4 or 10), number of
      //   element attributes.
      stringptr = readnumberline(inputline, infile, infilename);
      numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
      if (numberoftetrahedra <= 0) {
        printf("Error:  Invalid number of tetrahedra.\n");
        fclose(infile);
        return false;
      }
      stringptr = findnextnumber(stringptr);
      if (*stringptr == '\0') {
        numberofcorners = 4;  // Default read 4 nodes per element.
      } else {
        numberofcorners = (int) strtol(stringptr, &stringptr, 0);
      }
      stringptr = findnextnumber(stringptr);
      if (*stringptr == '\0') {
        numberoftetrahedronattributes = 0; // Default no attribute.
      } else {
        numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
      }
      if (numberofcorners != 4 && numberofcorners != 10) {
        printf("Error:  Wrong number of corners %d (should be 4 or 10).\n", 
               numberofcorners);
        fclose(infile);
        return false;
      }
    
      // Allocate memory for tetrahedra.
      tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; 
      if (tetrahedronlist == (int *) NULL) {
        terminatetetgen(1);
      }
      // Allocate memory for output tetrahedron attributes if necessary.
      if (numberoftetrahedronattributes > 0) {
        tetrahedronattributelist = new REAL[numberoftetrahedra *
                                            numberoftetrahedronattributes];
        if (tetrahedronattributelist == (REAL *) NULL) {
          terminatetetgen(1);
        }
      }
    
      // Read the list of tetrahedra.
      index = 0;
      attribindex = 0;
      for (i = 0; i < numberoftetrahedra; i++) {
        // Read tetrahedron index and the tetrahedron's corners.
        stringptr = readnumberline(inputline, infile, infilename);
        for (j = 0; j < numberofcorners; j++) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  Tetrahedron %d is missing vertex %d in %s.\n",
                   i + firstnumber, j + 1, infilename);
            terminatetetgen(1);
          }
          corner = (int) strtol(stringptr, &stringptr, 0);
          if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
            printf("Error:  Tetrahedron %d has an invalid vertex index.\n",
                   i + firstnumber);
            terminatetetgen(1);
          }
          tetrahedronlist[index++] = corner;
        }
        // Read the tetrahedron's attributes.
        for (j = 0; j < numberoftetrahedronattributes; j++) {
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            attrib = 0.0;
          } else {
            attrib = (REAL) strtod(stringptr, &stringptr);
          }
          tetrahedronattributelist[attribindex++] = attrib;
        }
      }
    
      fclose(infile);
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_vol()    Load a list of volume constraints from a .vol file.         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_vol(char* filebasename)
    {
      FILE *infile;
      char inelefilename[FILENAMESIZE];
      char infilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr; 
      REAL volume;
      int volelements;
      int i;
    
      strcpy(infilename, filebasename);
      strcat(infilename, ".vol");
    
      infile = fopen(infilename, "r");
      if (infile != (FILE *) NULL) {
        printf("Opening %s.\n", infilename);
      } else {
        return false;
      }
    
      // Read number of tetrahedra.
      stringptr = readnumberline(inputline, infile, infilename);
      volelements = (int) strtol (stringptr, &stringptr, 0);
      if (volelements != numberoftetrahedra) {
        strcpy(inelefilename, filebasename);
        strcat(infilename, ".ele");
        printf("Warning:  %s and %s disagree on number of tetrahedra.\n",
               inelefilename, infilename);
        fclose(infile);
        return false;
      }
    
      tetrahedronvolumelist = new REAL[volelements];
      if (tetrahedronvolumelist == (REAL *) NULL) {
        terminatetetgen(1);
      }
    
      // Read the list of volume constraints.
      for (i = 0; i < volelements; i++) {
        stringptr = readnumberline(inputline, infile, infilename);
        stringptr = findnextnumber(stringptr);
        if (*stringptr == '\0') {
          volume = -1.0; // No constraint on this tetrahedron.
        } else {
          volume = (REAL) strtod(stringptr, &stringptr);
        }
        tetrahedronvolumelist[i] = volume;
      }
    
      fclose(infile);
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_var()    Load constraints applied on facets, segments, and nodes     //
    //               from a .var file.                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_var(char* filebasename)
    {
      FILE *infile;
      char varfilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr;
      int index;
      int i;
    
      // Variant constraints are saved in file "filename.var".
      strcpy(varfilename, filebasename);
      strcat(varfilename, ".var");
      infile = fopen(varfilename, "r");
      if (infile != (FILE *) NULL) {
        printf("Opening %s.\n", varfilename);
      } else {
        // No such file. Ignore it without a message.
        return false;
      }
    
      // Read the facet constraint section.
      stringptr = readnumberline(inputline, infile, varfilename);
      if (*stringptr != '\0') {
        numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
      } else {
        numberoffacetconstraints = 0;
      }
      if (numberoffacetconstraints > 0) {
        // Initialize 'facetconstraintlist'.
        facetconstraintlist = new REAL[numberoffacetconstraints * 2];
        index = 0;
        for (i = 0; i < numberoffacetconstraints; i++) {
          stringptr = readnumberline(inputline, infile, varfilename);
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  facet constraint %d has no facet marker.\n",
                   firstnumber + i);
            break;
          } else {
            facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
          }
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  facet constraint %d has no maximum area bound.\n",
                   firstnumber + i);
            break;
          } else {
            facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
          }
        }
        if (i < numberoffacetconstraints) {
          // This must be caused by an error.
          fclose(infile);
          return false;
        }
      }
    
      // Read the segment constraint section.
      stringptr = readnumberline(inputline, infile, varfilename);
      if (*stringptr != '\0') {
        numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
      } else {
        numberofsegmentconstraints = 0;
      }
      if (numberofsegmentconstraints > 0) {
        // Initialize 'segmentconstraintlist'.
        segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
        index = 0;
        for (i = 0; i < numberofsegmentconstraints; i++) {
          stringptr = readnumberline(inputline, infile, varfilename);
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  segment constraint %d has no frist endpoint.\n",
                   firstnumber + i);
            break;
          } else {
            segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
          }
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  segment constraint %d has no second endpoint.\n",
                   firstnumber + i);
            break;
          } else {
            segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
          }
          stringptr = findnextnumber(stringptr);
          if (*stringptr == '\0') {
            printf("Error:  segment constraint %d has no maximum length bound.\n",
                   firstnumber + i);
            break;
          } else {
            segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
          }
        }
        if (i < numberofsegmentconstraints) {
          // This must be caused by an error.
          fclose(infile);
          return false;
        }
      }
    
      fclose(infile);
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_mtr()    Load a size specification map from a .mtr file.             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_mtr(char* filebasename)
    {
      FILE *infile;
      char mtrfilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr;
      REAL mtr;
      int ptnum;
      int mtrindex;
      int i, j;
    
      strcpy(mtrfilename, filebasename);
      strcat(mtrfilename, ".mtr");
      infile = fopen(mtrfilename, "r");
      if (infile != (FILE *) NULL) {
        printf("Opening %s.\n", mtrfilename);
      } else {
        // No such file. Return.
        return false;
      }
    
      // Read the number of points.
      stringptr = readnumberline(inputline, infile, mtrfilename);
      ptnum = (int) strtol (stringptr, &stringptr, 0);
      if (ptnum != numberofpoints) {
        printf("  !! Point numbers are not equal. Ignored.\n");
        fclose(infile);
        return false;
      }
      // Read the number of columns (1, 3, or 6).
      stringptr = findnextnumber(stringptr); // Skip number of points.
      if (*stringptr != '\0') {
        numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
      }
      if (numberofpointmtrs == 0) {
        // Column number doesn't match. Set a default number (1).
        numberofpointmtrs = 1;
      }
    
      // Allocate space for pointmtrlist.
      pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
      if (pointmtrlist == (REAL *) NULL) {
        terminatetetgen(1);
      }
      mtrindex = 0;
      for (i = 0; i < numberofpoints; i++) {
        // Read metrics.
        stringptr = readnumberline(inputline, infile, mtrfilename);
        for (j = 0; j < numberofpointmtrs; j++) {
          if (*stringptr == '\0') {
            printf("Error:  Metric %d is missing value #%d in %s.\n",
                   i + firstnumber, j + 1, mtrfilename);
            terminatetetgen(1);
          }
          mtr = (REAL) strtod(stringptr, &stringptr);
          pointmtrlist[mtrindex++] = mtr;
          stringptr = findnextnumber(stringptr);
        }
      }
    
      fclose(infile);
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_poly()    Load a PL complex from a .poly or a .smesh file.           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_poly(char* filebasename)
    {
      FILE *infile;
      char inpolyfilename[FILENAMESIZE];
      char insmeshfilename[FILENAMESIZE];
      char inputline[INPUTLINESIZE];
      char *stringptr, *infilename;
      int smesh, markers, uvflag, currentmarker;
      int index;
      int i, j, k;
    
      // Assembling the actual file names we want to open.
      strcpy(inpolyfilename, filebasename);
      strcpy(insmeshfilename, filebasename);
      strcat(inpolyfilename, ".poly");
      strcat(insmeshfilename, ".smesh");
    
      // First assume it is a .poly file.
      smesh = 0;
      // Try to open a .poly file.
      infile = fopen(inpolyfilename, "r");
      if (infile == (FILE *) NULL) {
        // .poly doesn't exist! Try to open a .smesh file.
        infile = fopen(insmeshfilename, "r");
        if (infile == (FILE *) NULL) {
          printf("  Cannot access file %s and %s.\n",
                 inpolyfilename, insmeshfilename);
          return false;
        } else {
          printf("Opening %s.\n", insmeshfilename);
          infilename = insmeshfilename;
        }
        smesh = 1;
      } else {
        printf("Opening %s.\n", inpolyfilename);
        infilename = inpolyfilename;
      }
    
      // Initialize the default values.
      mesh_dim = 3;  // Three-dimemsional accoordinates.
      numberofpointattributes = 0;  // no point attribute.
      markers = 0;  // no boundary marker.
      uvflag = 0; // no uv parameters (reuqired by a PSC).
    
      // Read number of points, number of dimensions, number of point
      //   attributes, and number of boundary markers.
      stringptr = readnumberline(inputline, infile, infilename);
      numberofpoints = (int) strtol (stringptr, &stringptr, 0);
      stringptr = findnextnumber(stringptr);
      if (*stringptr != '\0') {
        mesh_dim = (int) strtol (stringptr, &stringptr, 0);      
      }
      stringptr = findnextnumber(stringptr);
      if (*stringptr != '\0') {
        numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
      }
      stringptr = findnextnumber(stringptr);
      if (*stringptr != '\0') {
        markers = (int) strtol (stringptr, &stringptr, 0);
      }
      if (*stringptr != '\0') {
        uvflag = (int) strtol (stringptr, &stringptr, 0);
      }
    
      if (numberofpoints > 0) {
        // Load the list of nodes.
        if (!load_node_call(infile, markers, uvflag, infilename)) {
          fclose(infile);
          return false;
        }
      } else {
        // If the .poly or .smesh file claims there are zero points, that
        //   means the points should be read from a separate .node file.
        if (!load_node(filebasename)) {
          fclose(infile);
          return false;
        }
      }
    
      if ((mesh_dim != 3) && (mesh_dim != 2)) {
        printf("Input error:  TetGen only works for 2D & 3D point sets.\n");
        fclose(infile);
        return false;
      }
      if (numberofpoints < (mesh_dim + 1)) {
        printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
        fclose(infile);
        return false;
      }
    
      facet *f;
      polygon *p;
    
      if (mesh_dim == 3) {
    
        // Read number of facets and number of boundary markers.
        stringptr = readnumberline(inputline, infile, infilename);
        if (stringptr == NULL) {
          // No facet list, return.
          fclose(infile);
          return true;
        }
        numberoffacets = (int) strtol (stringptr, &stringptr, 0);
        if (numberoffacets <= 0) {
          // No facet list, return.
          fclose(infile);
          return true;
        }
        stringptr = findnextnumber(stringptr);
        if (*stringptr == '\0') {
          markers = 0;  // no boundary marker.
        } else {
          markers = (int) strtol (stringptr, &stringptr, 0);
        }
    
        // Initialize the 'facetlist', 'facetmarkerlist'.
        facetlist = new facet[numberoffacets];
        if (markers == 1) {
          facetmarkerlist = new int[numberoffacets];
        }
    
        // Read data into 'facetlist', 'facetmarkerlist'.
        if (smesh == 0) {
          // Facets are in .poly file format.
          for (i = 1; i <= numberoffacets; i++) {
            f = &(facetlist[i - 1]);
            init(f);
            f->numberofholes = 0;
            currentmarker = 0;
            // Read number of polygons, number of holes, and a boundary marker.
            stringptr = readnumberline(inputline, infile, infilename);
            f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
            stringptr = findnextnumber(stringptr);
            if (*stringptr != '\0') {
              f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
              if (markers == 1) {
                stringptr = findnextnumber(stringptr);
                if (*stringptr != '\0') {
                  currentmarker = (int) strtol(stringptr, &stringptr, 0);
                }
              }
            }
            // Initialize facetmarker if it needs.
            if (markers == 1) {
              facetmarkerlist[i - 1] = currentmarker; 
            }
            // Each facet should has at least one polygon.
            if (f->numberofpolygons <= 0) {
              printf("Error:  Wrong number of polygon in %d facet.\n", i);
              break; 
            }
            // Initialize the 'f->polygonlist'.
            f->polygonlist = new polygon[f->numberofpolygons];
            // Go through all polygons, read in their vertices.
            for (j = 1; j <= f->numberofpolygons; j++) {
              p = &(f->polygonlist[j - 1]);
              init(p);
              // Read number of vertices of this polygon.
              stringptr = readnumberline(inputline, infile, infilename);
              p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
              if (p->numberofvertices < 1) {
                printf("Error:  Wrong polygon %d in facet %d\n", j, i);
                break;
              }
              // Initialize 'p->vertexlist'.
              p->vertexlist = new int[p->numberofvertices];
              // Read all vertices of this polygon.
              for (k = 1; k <= p->numberofvertices; k++) {
                stringptr = findnextnumber(stringptr);
                if (*stringptr == '\0') {
                  // Try to load another non-empty line and continue to read the
                  //   rest of vertices.
                  stringptr = readnumberline(inputline, infile, infilename);
                  if (*stringptr == '\0') {
                    printf("Error: Missing %d endpoints of polygon %d in facet %d",
                           p->numberofvertices - k, j, i);
                    break;
                  }
                }
                p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
              }
            } 
            if (j <= f->numberofpolygons) {
              // This must be caused by an error. However, there're j - 1
              //   polygons have been read. Reset the 'f->numberofpolygon'.
              if (j == 1) {
                // This is the first polygon.
                delete [] f->polygonlist;
              }
              f->numberofpolygons = j - 1;
              // No hole will be read even it exists.
              f->numberofholes = 0;
              break;
            }
            // If this facet has hole pints defined, read them.
            if (f->numberofholes > 0) {
              // Initialize 'f->holelist'.
              f->holelist = new REAL[f->numberofholes * 3];
              // Read the holes' coordinates.
              index = 0;
              for (j = 1; j <= f->numberofholes; j++) {
                stringptr = readnumberline(inputline, infile, infilename);
                for (k = 1; k <= 3; k++) {
                  stringptr = findnextnumber(stringptr);
                  if (*stringptr == '\0') {
                    printf("Error:  Hole %d in facet %d has no coordinates", j, i);
                    break;
                  }
                  f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
                }
                if (k <= 3) {
                  // This must be caused by an error.
                  break;
                }
              }
              if (j <= f->numberofholes) {
                // This must be caused by an error.
                break;
              }
            }
          }
          if (i <= numberoffacets) {
            // This must be caused by an error.
            numberoffacets = i - 1;
            fclose(infile);
            return false;
          }
        } else { // poly == 0
          // Read the facets from a .smesh file.
          for (i = 1; i <= numberoffacets; i++) {
            f = &(facetlist[i - 1]);
            init(f);
            // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
            //   contains exactly one polygon, no hole.
            f->numberofpolygons = 1;
            f->polygonlist = new polygon[f->numberofpolygons];
            p = &(f->polygonlist[0]);
            init(p);
            // Read number of vertices of this polygon.
            stringptr = readnumberline(inputline, infile, insmeshfilename);
            p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
            if (p->numberofvertices < 1) {
              printf("Error:  Wrong number of vertex in facet %d\n", i);
              break;
            }
            // Initialize 'p->vertexlist'.
            p->vertexlist = new int[p->numberofvertices];
            for (k = 1; k <= p->numberofvertices; k++) {
              stringptr = findnextnumber(stringptr);
              if (*stringptr == '\0') {
                // Try to load another non-empty line and continue to read the
                //   rest of vertices.
                stringptr = readnumberline(inputline, infile, infilename);
                if (*stringptr == '\0') {
                  printf("Error:  Missing %d endpoints in facet %d",
                         p->numberofvertices - k, i);
                  break;
                }
              }
              p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
            }
            if (k <= p->numberofvertices) {
              // This must be caused by an error.
              break;
            }
            // Read facet's boundary marker at last.
            if (markers == 1) {
              stringptr = findnextnumber(stringptr);
              if (*stringptr == '\0') {
                currentmarker = 0;
              } else {
                currentmarker = (int) strtol(stringptr, &stringptr, 0);
              }
              facetmarkerlist[i - 1] = currentmarker;
            }
          }
          if (i <= numberoffacets) {
            // This must be caused by an error.
            numberoffacets = i - 1;
            fclose(infile);
            return false;
          }
        }
    
        // Read the hole section.
        stringptr = readnumberline(inputline, infile, infilename);
        if (stringptr == NULL) {
          // No hole list, return.
          fclose(infile);
          return true;
        }
        if (*stringptr != '\0') {
          numberofholes = (int) strtol (stringptr, &stringptr, 0);
        } else {
          numberofholes = 0;
        }
        if (numberofholes > 0) {
          // Initialize 'holelist'.
          holelist = new REAL[numberofholes * 3];
          for (i = 0; i < 3 * numberofholes; i += 3) {
            stringptr = readnumberline(inputline, infile, infilename);
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Hole %d has no x coord.\n", firstnumber + (i / 3));
              break;
            } else {
              holelist[i] = (REAL) strtod(stringptr, &stringptr);
            }
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Hole %d has no y coord.\n", firstnumber + (i / 3));
              break;
            } else {
              holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
            }
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Hole %d has no z coord.\n", firstnumber + (i / 3));
              break;
            } else {
              holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
            }
          }
          if (i < 3 * numberofholes) {
            // This must be caused by an error.
            fclose(infile);
            return false;
          }
        }
    
        // Read the region section.  The 'region' section is optional, if we
        //   don't reach the end-of-file, try read it in.
        stringptr = readnumberline(inputline, infile, NULL);
        if (stringptr != (char *) NULL && *stringptr != '\0') {
          numberofregions = (int) strtol (stringptr, &stringptr, 0);
        } else {
          numberofregions = 0;
        }
        if (numberofregions > 0) {
          // Initialize 'regionlist'.
          regionlist = new REAL[numberofregions * 5];
          index = 0;
          for (i = 0; i < numberofregions; i++) {
            stringptr = readnumberline(inputline, infile, infilename);
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Region %d has no x coordinate.\n", firstnumber + i);
              break;
            } else {
              regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
            }
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Region %d has no y coordinate.\n", firstnumber + i);
              break;
            } else {
              regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
            }
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Region %d has no z coordinate.\n", firstnumber + i);
              break;
            } else {
              regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
            }
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              printf("Error:  Region %d has no region attrib.\n", firstnumber + i);
              break;
            } else {
              regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
            }
            stringptr = findnextnumber(stringptr);
            if (*stringptr == '\0') {
              regionlist[index] = regionlist[index - 1];
            } else {
              regionlist[index] = (REAL) strtod(stringptr, &stringptr);
            }
            index++;
          }
          if (i < numberofregions) {
            // This must be caused by an error.
            fclose(infile);
            return false;
          }
        }
    
      } else {
    
        // Read a PSLG from Triangle's poly file.
        assert(mesh_dim == 2);
        // A PSLG is a facet of a PLC.
        numberoffacets = 1;
        // Initialize the 'facetlist'.
        facetlist = new facet[numberoffacets];
        facetmarkerlist = (int *) NULL; // No facet markers.
        f = &(facetlist[0]);
        init(f);
        // Read number of segments.
        stringptr = readnumberline(inputline, infile, infilename);
        // Segments are degenerate polygons.
        f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
        if (f->numberofpolygons > 0) {
          f->polygonlist = new polygon[f->numberofpolygons];
        }
        // Go through all segments, read in their vertices.
        for (j = 0; j < f->numberofpolygons; j++) {
          p = &(f->polygonlist[j]);
          init(p);
          // Read in a segment.
          stringptr = readnumberline(inputline, infile, infilename);
          stringptr = findnextnumber(stringptr); // Skip its index.
          p->numberofvertices = 2; // A segment always has two vertices.
          p->vertexlist = new int[p->numberofvertices];
          p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
          stringptr = findnextnumber(stringptr);
          p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
        }
        // Read number of holes.
        stringptr = readnumberline(inputline, infile, infilename);
        f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
        if (f->numberofholes > 0) {
          // Initialize 'f->holelist'.
          f->holelist = new REAL[f->numberofholes * 3];
          // Read the holes' coordinates.
          for (j = 0; j < f->numberofholes; j++) {
            // Read a 2D hole point.
            stringptr = readnumberline(inputline, infile, infilename);
            stringptr = findnextnumber(stringptr); // Skip its index.
            f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
            stringptr = findnextnumber(stringptr);
            f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
            f->holelist[j * 3 + 2] = 0.0; // The z-coord.
          }
        }
        // The regions are skipped.
    
      }
    
      // End of reading poly/smesh file.
      fclose(infile);
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_off()    Load a polyhedron from a .off file.                         //
    //                                                                           //
    // The .off format is one of file formats of the Geomview, an interactive    //
    // program for viewing and manipulating geometric objects.  More information //
    // is available form: http://www.geomview.org.                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_off(char* filebasename)
    {
      FILE *fp;
      tetgenio::facet *f;
      tetgenio::polygon *p;
      char infilename[FILENAMESIZE];
      char buffer[INPUTLINESIZE];
      char *bufferp;
      double *coord;
      int nverts = 0, iverts = 0;
      int nfaces = 0, ifaces = 0;
      int nedges = 0;
      int line_count = 0, i;
    
      // Default, the off file's index is from '0'. We check it by remembering the
      //   smallest index we found in the file. It should be either 0 or 1.
      int smallestidx = 0; 
    
      strncpy(infilename, filebasename, 1024 - 1);
      infilename[FILENAMESIZE - 1] = '\0';
      if (infilename[0] == '\0') {
        printf("Error:  No filename.\n");
        return false;
      }
      if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
        strcat(infilename, ".off");
      }
    
      if (!(fp = fopen(infilename, "r"))) {
        printf("  Unable to open file %s\n", infilename);
        return false;
      }
      printf("Opening %s.\n", infilename);
    
      while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
        // Check section
        if (nverts == 0) {
          // Read header 
          bufferp = strstr(bufferp, "OFF");
          if (bufferp != NULL) {
            // Read mesh counts
            bufferp = findnextnumber(bufferp); // Skip field "OFF".
            if (*bufferp == '\0') {
              // Read a non-empty line.
              bufferp = readline(buffer, fp, &line_count);
            }
            if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3) 
                || (nverts == 0)) {
              printf("Syntax error reading header on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            // Allocate memory for 'tetgenio'
            if (nverts > 0) {
              numberofpoints = nverts;
              pointlist = new REAL[nverts * 3];
              smallestidx = nverts + 1; // A bigger enough number.
            }
            if (nfaces > 0) {        
              numberoffacets = nfaces;
              facetlist = new tetgenio::facet[nfaces];
            }
          }
        } else if (iverts < nverts) {
          // Read vertex coordinates
          coord = &pointlist[iverts * 3];
          for (i = 0; i < 3; i++) {
            if (*bufferp == '\0') {
              printf("Syntax error reading vertex coords on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            coord[i] = (REAL) strtod(bufferp, &bufferp);
            bufferp = findnextnumber(bufferp);
          }
          iverts++;
        } else if (ifaces < nfaces) {
          // Get next face
          f = &facetlist[ifaces];
          init(f);      
          // In .off format, each facet has one polygon, no hole.
          f->numberofpolygons = 1;
          f->polygonlist = new tetgenio::polygon[1];
          p = &f->polygonlist[0];
          init(p);
          // Read the number of vertices, it should be greater than 0.
          p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
          if (p->numberofvertices == 0) {
            printf("Syntax error reading polygon on line %d in file %s\n",
                   line_count, infilename);
            fclose(fp);
            return false;
          }
          // Allocate memory for face vertices
          p->vertexlist = new int[p->numberofvertices];
          for (i = 0; i < p->numberofvertices; i++) {
            bufferp = findnextnumber(bufferp);
            if (*bufferp == '\0') {
              printf("Syntax error reading polygon on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
            // Detect the smallest index.
            if (p->vertexlist[i] < smallestidx) {
              smallestidx = p->vertexlist[i];
            }
          }
          ifaces++;
        } else {
          // Should never get here
          printf("Found extra text starting at line %d in file %s\n", line_count,
                 infilename);
          break;
        }
      }
    
      // Close file
      fclose(fp);
    
      // Decide the firstnumber of the index.
      if (smallestidx == 0) {
        firstnumber = 0;  
      } else if (smallestidx == 1) {
        firstnumber = 1;
      } else {
        printf("A wrong smallest index (%d) was detected in file %s\n",
               smallestidx, infilename);
        return false;
      }
    
      // Check whether read all points
      if (iverts != nverts) {
        printf("Expected %d vertices, but read only %d vertices in file %s\n",
               nverts, iverts, infilename);
        return false;
      }
    
      // Check whether read all faces
      if (ifaces != nfaces) {
        printf("Expected %d faces, but read only %d faces in file %s\n",
               nfaces, ifaces, infilename);
        return false;
      }
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_ply()    Load a polyhedron from a .ply file.                         //
    //                                                                           //
    // This is a simplified version of reading .ply files, which only reads the  //
    // set of vertices and the set of faces. Other informations (such as color,  //
    // material, texture, etc) in .ply file are ignored. Complete routines for   //
    // reading and writing ,ply files are available from: http://www.cc.gatech.  //
    // edu/projects/large_models/ply.html.  Except the header section, ply file  //
    // format has exactly the same format for listing vertices and polygons as   //
    // off file format.                                                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_ply(char* filebasename)
    {
      FILE *fp;
      tetgenio::facet *f;
      tetgenio::polygon *p;
      char infilename[FILENAMESIZE];
      char buffer[INPUTLINESIZE];
      char *bufferp, *str;
      double *coord;
      int endheader = 0, format = 0;
      int nverts = 0, iverts = 0;
      int nfaces = 0, ifaces = 0;
      int line_count = 0, i;
    
      // Default, the ply file's index is from '0'. We check it by remembering the
      //   smallest index we found in the file. It should be either 0 or 1.
      int smallestidx = 0; 
    
      strncpy(infilename, filebasename, FILENAMESIZE - 1);
      infilename[FILENAMESIZE - 1] = '\0';
      if (infilename[0] == '\0') {
        printf("Error:  No filename.\n");
        return false;
      }
      if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
        strcat(infilename, ".ply");
      }
    
      if (!(fp = fopen(infilename, "r"))) {
        printf("Error:  Unable to open file %s\n", infilename);
        return false;
      }
      printf("Opening %s.\n", infilename);
    
      while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
        if (!endheader) {
          // Find if it is the keyword "end_header".
          str = strstr(bufferp, "end_header");
          // strstr() is case sensitive.
          if (!str) str = strstr(bufferp, "End_header");
          if (!str) str = strstr(bufferp, "End_Header");
          if (str) {
            // This is the end of the header section.
            endheader = 1; 
            continue;
          }
          // Parse the number of vertices and the number of faces.
          if (nverts == 0 || nfaces == 0) {
            // Find if it si the keyword "element".
            str = strstr(bufferp, "element");
            if (!str) str = strstr(bufferp, "Element");
            if (str) {
              bufferp = findnextfield(str);
              if (*bufferp == '\0') {
                printf("Syntax error reading element type on line%d in file %s\n",
                       line_count, infilename);
                fclose(fp);
                return false;
              }
              if (nverts == 0) {
                // Find if it is the keyword "vertex".
                str = strstr(bufferp, "vertex");
                if (!str) str = strstr(bufferp, "Vertex");
                if (str) {
                  bufferp = findnextnumber(str);
                  if (*bufferp == '\0') {
                    printf("Syntax error reading vertex number on line");
                    printf(" %d in file %s\n", line_count, infilename);
                    fclose(fp);
                    return false;
                  }
                  nverts = (int) strtol(bufferp, &bufferp, 0);
                  // Allocate memory for 'tetgenio'
                  if (nverts > 0) {
                    numberofpoints = nverts;
                    pointlist = new REAL[nverts * 3];
                    smallestidx = nverts + 1; // A big enough index.
                  }
                }
              }
              if (nfaces == 0) {
                // Find if it is the keyword "face".
                str = strstr(bufferp, "face");
                if (!str) str = strstr(bufferp, "Face");
                if (str) {
                  bufferp = findnextnumber(str);
                  if (*bufferp == '\0') {
                    printf("Syntax error reading face number on line");
                    printf(" %d in file %s\n", line_count, infilename);
                    fclose(fp);
                    return false;
                  }
                  nfaces = (int) strtol(bufferp, &bufferp, 0);
                  // Allocate memory for 'tetgenio'
                  if (nfaces > 0) {        
                    numberoffacets = nfaces;
                    facetlist = new tetgenio::facet[nfaces];
                  }
                }
              }
            } // It is not the string "element". 
          }
          if (format == 0) {
            // Find the keyword "format".
            str = strstr(bufferp, "format");
            if (!str) str = strstr(bufferp, "Format");
            if (str) {
              format = 1;
              bufferp = findnextfield(str);
              // Find if it is the string "ascii".
              str = strstr(bufferp, "ascii");
              if (!str) str = strstr(bufferp, "ASCII");
              if (!str) {
                printf("This routine only reads ascii format of ply files.\n");
                printf("Hint: You can convert the binary to ascii format by\n");
                printf("  using the provided ply tools:\n");
                printf("  ply2ascii < %s > ascii_%s\n", infilename, infilename);
                fclose(fp);
                return false;
              }
            }
          }
        } else if (iverts < nverts) {
          // Read vertex coordinates
          coord = &pointlist[iverts * 3];
          for (i = 0; i < 3; i++) {
            if (*bufferp == '\0') {
              printf("Syntax error reading vertex coords on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            coord[i] = (REAL) strtod(bufferp, &bufferp);
            bufferp = findnextnumber(bufferp);
          }
          iverts++;
        } else if (ifaces < nfaces) {
          // Get next face
          f = &facetlist[ifaces];
          init(f);      
          // In .off format, each facet has one polygon, no hole.
          f->numberofpolygons = 1;
          f->polygonlist = new tetgenio::polygon[1];
          p = &f->polygonlist[0];
          init(p);
          // Read the number of vertices, it should be greater than 0.
          p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
          if (p->numberofvertices == 0) {
            printf("Syntax error reading polygon on line %d in file %s\n",
                   line_count, infilename);
            fclose(fp);
            return false;
          }
          // Allocate memory for face vertices
          p->vertexlist = new int[p->numberofvertices];
          for (i = 0; i < p->numberofvertices; i++) {
            bufferp = findnextnumber(bufferp);
            if (*bufferp == '\0') {
              printf("Syntax error reading polygon on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
            if (p->vertexlist[i] < smallestidx) {
              smallestidx = p->vertexlist[i];
            }
          }
          ifaces++;
        } else {
          // Should never get here
          printf("Found extra text starting at line %d in file %s\n", line_count,
                 infilename);
          break;
        }
      }
    
      // Close file
      fclose(fp);
    
      // Decide the firstnumber of the index.
      if (smallestidx == 0) {
        firstnumber = 0;  
      } else if (smallestidx == 1) {
        firstnumber = 1;
      } else {
        printf("A wrong smallest index (%d) was detected in file %s\n",
               smallestidx, infilename);
        return false;
      }
    
      // Check whether read all points
      if (iverts != nverts) {
        printf("Expected %d vertices, but read only %d vertices in file %s\n",
               nverts, iverts, infilename);
        return false;
      }
    
      // Check whether read all faces
      if (ifaces != nfaces) {
        printf("Expected %d faces, but read only %d faces in file %s\n",
               nfaces, ifaces, infilename);
        return false;
      }
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_stl()    Load a surface mesh from a .stl file.                       //
    //                                                                           //
    // The .stl or stereolithography format is an ASCII or binary file used in   //
    // manufacturing.  It is a list of the triangular surfaces that describe a   //
    // computer generated solid model. This is the standard input for most rapid //
    // prototyping machines.                                                     //
    //                                                                           //
    // Comment: A .stl file many contain many duplicated points.  They will be   //
    // unified during the Delaunay tetrahedralization process.                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_stl(char* filebasename)
    {
      FILE *fp;
      tetgenmesh::arraypool *plist;
      tetgenio::facet *f;
      tetgenio::polygon *p;
      char infilename[FILENAMESIZE];
      char buffer[INPUTLINESIZE];
      char *bufferp, *str;
      double *coord;
      int solid = 0;
      int nverts = 0, iverts = 0;
      int nfaces = 0;
      int line_count = 0, i;
    
      strncpy(infilename, filebasename, FILENAMESIZE - 1);
      infilename[FILENAMESIZE - 1] = '\0';
      if (infilename[0] == '\0') {
        printf("Error:  No filename.\n");
        return false;
      }
      if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
        strcat(infilename, ".stl");
      }
    
      if (!(fp = fopen(infilename, "r"))) {
        printf("Error:  Unable to open file %s\n", infilename);
        return false;
      }
      printf("Opening %s.\n", infilename);
    
      // STL file has no number of points available. Use a list to read points.
      plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10); 
    
      while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
        // The ASCII .stl file must start with the lower case keyword solid and
        //   end with endsolid.
        if (solid == 0) {
          // Read header 
          bufferp = strstr(bufferp, "solid");
          if (bufferp != NULL) {
            solid = 1;
          }
        } else {
          // We're inside the block of the solid.
          str = bufferp;
          // Is this the end of the solid.
          bufferp = strstr(bufferp, "endsolid");
          if (bufferp != NULL) {
            solid = 0;
          } else {
            // Read the XYZ coordinates if it is a vertex.
            bufferp = str;
            bufferp = strstr(bufferp, "vertex");
            if (bufferp != NULL) {
              plist->newindex((void **) &coord);
              for (i = 0; i < 3; i++) {
                bufferp = findnextnumber(bufferp);
                if (*bufferp == '\0') {
                  printf("Syntax error reading vertex coords on line %d\n",
                       line_count);
                  delete plist;
                  fclose(fp);
                  return false;
                }
                coord[i] = (REAL) strtod(bufferp, &bufferp);
              }
            }
          }
        }
      }
      fclose(fp);
    
      nverts = (int) plist->objects;
      // nverts should be an integer times 3 (every 3 vertices denote a face).
      if (nverts == 0 || (nverts % 3 != 0)) {
        printf("Error:  Wrong number of vertices in file %s.\n", infilename);
        delete plist;
        return false;
      }
      numberofpoints = nverts;
      pointlist = new REAL[nverts * 3];
      for (i = 0; i < nverts; i++) {
        coord = (double *) fastlookup(plist, i);
        iverts = i * 3;
        pointlist[iverts] = (REAL) coord[0];
        pointlist[iverts + 1] = (REAL) coord[1];
        pointlist[iverts + 2] = (REAL) coord[2];
      }
    
      nfaces = (int) (nverts / 3);
      numberoffacets = nfaces;
      facetlist = new tetgenio::facet[nfaces];
    
      // Default use '1' as the array starting index.
      firstnumber = 1;
      iverts = firstnumber;
      for (i = 0; i < nfaces; i++) {
        f = &facetlist[i];
        init(f);      
        // In .stl format, each facet has one polygon, no hole.
        f->numberofpolygons = 1;
        f->polygonlist = new tetgenio::polygon[1];
        p = &f->polygonlist[0];
        init(p);
        // Each polygon has three vertices.
        p->numberofvertices = 3;
        p->vertexlist = new int[p->numberofvertices];
        p->vertexlist[0] = iverts;
        p->vertexlist[1] = iverts + 1;
        p->vertexlist[2] = iverts + 2;
        iverts += 3;
      }
    
      delete plist;
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_medit()    Load a surface mesh from a .mesh file.                    //
    //                                                                           //
    // The .mesh format is the file format of Medit, a user-friendly interactive //
    // mesh viewer program.                                                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_medit(char* filebasename, int istetmesh)
    {
      FILE *fp;
      tetgenio::facet *tmpflist, *f;
      tetgenio::polygon *p;
      char infilename[FILENAMESIZE];
      char buffer[INPUTLINESIZE];
      char *bufferp, *str;
      double *coord;
      int *tmpfmlist;
      int dimension = 0;
      int nverts = 0;
      int nfaces = 0;
      int ntets = 0;
      int line_count = 0;
      int corners = 0; // 3 (triangle) or 4 (quad).
      int *plist;
      int i, j;
    
      int smallestidx = 0;
    
      strncpy(infilename, filebasename, FILENAMESIZE - 1);
      infilename[FILENAMESIZE - 1] = '\0';
      if (infilename[0] == '\0') {
        printf("Error:  No filename.\n");
        return false;
      }
      if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
        strcat(infilename, ".mesh");
      }
      
      if (!(fp = fopen(infilename, "r"))) {
        printf("Error:  Unable to open file %s\n", infilename);
        return false;
      }
      printf("Opening %s.\n", infilename);
    
      while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
        if (*bufferp == '#') continue;  // A comment line is skipped.
        if (dimension == 0) {
          // Find if it is the keyword "Dimension".
          str = strstr(bufferp, "Dimension");
          if (!str) str = strstr(bufferp, "dimension");
          if (!str) str = strstr(bufferp, "DIMENSION");
          if (str) {
            // Read the dimensions
            bufferp = findnextnumber(str); // Skip field "Dimension".
            if (*bufferp == '\0') {
              // Read a non-empty line.
              bufferp = readline(buffer, fp, &line_count);
            }
            dimension = (int) strtol(bufferp, &bufferp, 0);
            if (dimension != 2 && dimension != 3) {
              printf("Unknown dimension in file on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            mesh_dim = dimension;
          }
        }
        if (nverts == 0) {
          // Find if it is the keyword "Vertices".
          str = strstr(bufferp, "Vertices");
          if (!str) str = strstr(bufferp, "vertices");
          if (!str) str = strstr(bufferp, "VERTICES");
          if (str) {
            // Read the number of vertices.
            bufferp = findnextnumber(str); // Skip field "Vertices".
            if (*bufferp == '\0') {
              // Read a non-empty line.
              bufferp = readline(buffer, fp, &line_count);
            }
            nverts = (int) strtol(bufferp, &bufferp, 0);
            // Initialize the smallest index.
            smallestidx = nverts + 1;
            // Allocate memory for 'tetgenio'
            if (nverts > 0) {
              numberofpoints = nverts;
              pointlist = new REAL[nverts * 3];
            }
            // Read the follwoing node list.
            for (i = 0; i < nverts; i++) {
              bufferp = readline(buffer, fp, &line_count);
              if (bufferp == NULL) {
                printf("Unexpected end of file on line %d in file %s\n",
                       line_count, infilename);
                fclose(fp);
                return false;
              }
              // Read vertex coordinates
              coord = &pointlist[i * 3];
              for (j = 0; j < 3; j++) {
                if (*bufferp == '\0') {
                  printf("Syntax error reading vertex coords on line");
                  printf(" %d in file %s\n", line_count, infilename);
                  fclose(fp);
                  return false;
                }
                if ((j < 2) || (dimension == 3)) {
                  coord[j] = (REAL) strtod(bufferp, &bufferp);
                } else {
                  assert((j == 2) && (dimension == 2));
                  coord[j] = 0.0;
                }
                bufferp = findnextnumber(bufferp);
              }
            }
            continue;
          }
        }
        if (ntets == 0) {
          // Find if it is the keyword "Tetrahedra"
          corners = 0;
          str = strstr(bufferp, "Tetrahedra");
          if (!str) str = strstr(bufferp, "tetrahedra");
          if (!str) str = strstr(bufferp, "TETRAHEDRA");
          if (str) {
            corners = 4;
          }
          if (corners == 4) {
            // Read the number of tetrahedra
            bufferp = findnextnumber(str); // Skip field "Tetrahedra".
            if (*bufferp == '\0') {
              // Read a non-empty line.
              bufferp = readline(buffer, fp, &line_count);
            }
            ntets = strtol(bufferp, &bufferp, 0);
            if (ntets > 0) {
              // It is a tetrahedral mesh.
              numberoftetrahedra = ntets;
              numberofcorners = 4;
              numberoftetrahedronattributes = 1;
              tetrahedronlist = new int[ntets * 4];
              tetrahedronattributelist = new REAL[ntets];
            }
          } // if (corners == 4)
          // Read the list of tetrahedra.
          for (i = 0; i < numberoftetrahedra; i++) {
            plist = &(tetrahedronlist[i * 4]);
            bufferp = readline(buffer, fp, &line_count);
            if (bufferp == NULL) {
              printf("Unexpected end of file on line %d in file %s\n",
                     line_count, infilename);
              fclose(fp);
              return false;
            }
            // Read the vertices of the tet.
            for (j = 0; j < corners; j++) {
              if (*bufferp == '\0') {
                printf("Syntax error reading face on line %d in file %s\n",
                       line_count, infilename);
                fclose(fp);
                return false;
              }
              plist[j] = (int) strtol(bufferp, &bufferp, 0);
              // Remember the smallest index.
              if (plist[j] < smallestidx) smallestidx = plist[j];
              bufferp = findnextnumber(bufferp);
            }
            // Read the attribute of the tet if it exists.
            tetrahedronattributelist[i] = 0;
            if (*bufferp != '\0') {
              tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
            }
          } // i
        } // Tetrahedra
        if (nfaces == 0) {
          // Find if it is the keyword "Triangles" or "Quadrilaterals".
          corners = 0;
          str = strstr(bufferp, "Triangles");
          if (!str) str = strstr(bufferp, "triangles");
          if (!str) str = strstr(bufferp, "TRIANGLES");
          if (str) {
            corners = 3;
          } else {
            str = strstr(bufferp, "Quadrilaterals");
            if (!str) str = strstr(bufferp, "quadrilaterals");
            if (!str) str = strstr(bufferp, "QUADRILATERALS");
            if (str) {
              corners = 4;
            }
          }
          if (corners == 3 || corners == 4) {
            // Read the number of triangles (or quadrilaterals).
            bufferp = findnextnumber(str); // Skip field "Triangles".
            if (*bufferp == '\0') {
              // Read a non-empty line.
              bufferp = readline(buffer, fp, &line_count);
            }
            nfaces = strtol(bufferp, &bufferp, 0);
            // Allocate memory for 'tetgenio'
            if (nfaces > 0) {
              if (!istetmesh) {
                // It is a PLC surface mesh.
                if (numberoffacets > 0) {
                  // facetlist has already been allocated. Enlarge arrays.
                  // This happens when the surface mesh contains mixed cells.
                  tmpflist = new tetgenio::facet[numberoffacets + nfaces];
                  tmpfmlist = new int[numberoffacets + nfaces];
                  // Copy the data of old arrays into new arrays.
                  for (i = 0; i < numberoffacets; i++) {
                    f = &(tmpflist[i]);
                    tetgenio::init(f);
                    *f = facetlist[i];
                    tmpfmlist[i] = facetmarkerlist[i];
                  }
                  // Release old arrays.
                  delete [] facetlist;
                  delete [] facetmarkerlist;
                  // Remember the new arrays.
                  facetlist = tmpflist;
                  facetmarkerlist = tmpfmlist;
                } else {
                  // This is the first time to allocate facetlist.
                  facetlist = new tetgenio::facet[nfaces];
                  facetmarkerlist = new int[nfaces];
                }
              } else {
                if (corners == 3) {
                  // It is a surface mesh of a tetrahedral mesh.
                  numberoftrifaces = nfaces;
                  trifacelist = new int[nfaces * 3];
                  trifacemarkerlist = new int[nfaces];
                }
              }
            } // if (nfaces > 0)
            // Read the following list of faces.
            if (!istetmesh) {
              for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
                bufferp = readline(buffer, fp, &line_count);
                if (bufferp == NULL) {
                  printf("Unexpected end of file on line %d in file %s\n",
                         line_count, infilename);
                  fclose(fp);
                  return false;
                }
                f = &facetlist[i];
                tetgenio::init(f);
                // In .mesh format, each facet has one polygon, no hole.
                f->numberofpolygons = 1;
                f->polygonlist = new tetgenio::polygon[1];
                p = &f->polygonlist[0];
                tetgenio::init(p);
                p->numberofvertices = corners;
                // Allocate memory for face vertices
                p->vertexlist = new int[p->numberofvertices];
                // Read the vertices of the face.
                for (j = 0; j < corners; j++) {
                  if (*bufferp == '\0') {
                    printf("Syntax error reading face on line %d in file %s\n",
                           line_count, infilename);
                    fclose(fp);
                    return false;
                  }
                  p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
                  // Remember the smallest index.
                  if (p->vertexlist[j] < smallestidx) {
                    smallestidx = p->vertexlist[j];
                  }
                  bufferp = findnextnumber(bufferp);
                }
                // Read the marker of the face if it exists.
                facetmarkerlist[i] = 0;
                if (*bufferp != '\0') {
                  facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
                }
              }
              // Have read in a list of triangles/quads.
              numberoffacets += nfaces;
              nfaces = 0;
            } else {
              // It is a surface mesh of a tetrahedral mesh.
              if (corners == 3) {
                for (i = 0; i < numberoftrifaces; i++) {
                  plist = &(trifacelist[i * 3]);
                  bufferp = readline(buffer, fp, &line_count);
                  if (bufferp == NULL) {
                    printf("Unexpected end of file on line %d in file %s\n",
                           line_count, infilename);
                    fclose(fp);
                    return false;
                  }
                  // Read the vertices of the face.
                  for (j = 0; j < corners; j++) {
                    if (*bufferp == '\0') {
                      printf("Syntax error reading face on line %d in file %s\n",
                             line_count, infilename);
                      fclose(fp);
                      return false;
                    }
                    plist[j] = (int) strtol(bufferp, &bufferp, 0);
                    // Remember the smallest index.
                    if (plist[j] < smallestidx) {
                      smallestidx = plist[j];
                    }
                    bufferp = findnextnumber(bufferp);
                  }
                  // Read the marker of the face if it exists.
                  trifacemarkerlist[i] = 0;
                  if (*bufferp != '\0') {
                    trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
                  }
                } // i
              } // if (corners == 3)
            } // if (b->refine)
          } // if (corners == 3 || corners == 4)
        }
      }
    
      // Close file
      fclose(fp);
    
      // Decide the firstnumber of the index.
      if (smallestidx == 0) {
        firstnumber = 0;  
      } else if (smallestidx == 1) {
        firstnumber = 1;
      } else {
        printf("A wrong smallest index (%d) was detected in file %s\n",
               smallestidx, infilename);
        return false;
      }
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_vtk()    Load VTK surface mesh from file (.vtk ascii or binary).     //
    //                                                                           //
    // This function is contributed by: Bryn Lloyd, Computer Vision Laborator,   //
    // ETH, Zuerich. May 7, 2007.                                                //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    // Two inline functions used in read/write VTK files.
    
    void swapBytes(unsigned char* var, int size)
    {
      int i = 0;
      int j = size - 1;
      char c;
    
      while (i < j) {
        c = var[i]; var[i] = var[j]; var[j] = c;
        i++, j--;
      }
    }
    
    bool testIsBigEndian()
    {
      short word = 0x4321;
      if((*(char *)& word) != 0x21)
        return true;
      else 
        return false;
    }
    
    
    bool tetgenio::load_vtk(char* filebasename)
    {
      FILE *fp;
      tetgenio::facet *f;
      tetgenio::polygon *p;
      char infilename[FILENAMESIZE];
      char line[INPUTLINESIZE];
      char mode[128], id[256], fmt[64];
      char *bufferp;
      double *coord;
      float _x, _y, _z;
      int nverts = 0;
      int nfaces = 0;
      int line_count = 0;
      int dummy;
      int id1, id2, id3;
      int nn = -1;
      int nn_old = -1;
      int i, j;
      bool ImALittleEndian = !testIsBigEndian();
    
      int smallestidx = 0;
    
      strncpy(infilename, filebasename, FILENAMESIZE - 1);
      infilename[FILENAMESIZE - 1] = '\0';
      if (infilename[0] == '\0') {
        printf("Error:  No filename.\n");
        return false;
      }
      if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
        strcat(infilename, ".vtk");
      }
      if (!(fp = fopen(infilename, "r"))) {
        printf("Error:  Unable to open file %s\n", infilename);
        return false;
      }
      printf("Opening %s.\n", infilename);
    
      // Default uses the index starts from '0'.
      firstnumber = 0;
      strcpy(mode, "BINARY");
    
      while((bufferp = readline(line, fp, &line_count)) != NULL) {
        if(strlen(line) == 0) continue;
        //swallow lines beginning with a comment sign or white space
        if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 || 
           line[0] == 32) continue;
    
        sscanf(line, "%s", id);
        if(!strcmp(id, "ASCII")) {
          strcpy(mode, "ASCII");
        }
    
        if(!strcmp(id, "POINTS")) {
          sscanf(line, "%s %d %s", id, &nverts, fmt);
          if (nverts > 0) {
            numberofpoints = nverts;
            pointlist = new REAL[nverts * 3];
            smallestidx = nverts + 1;
          }
    
          if(!strcmp(mode, "BINARY")) {
            for(i = 0; i < nverts; i++) {
              coord = &pointlist[i * 3];
              if(!strcmp(fmt, "double")) {
                fread((char*)(&(coord[0])), sizeof(double), 1, fp);
                fread((char*)(&(coord[1])), sizeof(double), 1, fp);
                fread((char*)(&(coord[2])), sizeof(double), 1, fp);
                if(ImALittleEndian){
                  swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
                  swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
                  swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
                }
              } else if(!strcmp(fmt, "float")) {
                fread((char*)(&_x), sizeof(float), 1, fp);
                fread((char*)(&_y), sizeof(float), 1, fp);
                fread((char*)(&_z), sizeof(float), 1, fp);
                if(ImALittleEndian){
                  swapBytes((unsigned char *) &_x, sizeof(_x));
                  swapBytes((unsigned char *) &_y, sizeof(_y));
                  swapBytes((unsigned char *) &_z, sizeof(_z));
                }
                coord[0] = double(_x);
                coord[1] = double(_y);
                coord[2] = double(_z);
              } else {
                printf("Error: Only float or double formats are supported!\n");
                return false;
              }
            }
          } else if(!strcmp(mode, "ASCII")) {
            for(i = 0; i < nverts; i++){
              bufferp = readline(line, fp, &line_count);
              if (bufferp == NULL) {
                printf("Unexpected end of file on line %d in file %s\n",
                       line_count, infilename);
                fclose(fp);
                return false;
              }
              // Read vertex coordinates
              coord = &pointlist[i * 3];
              for (j = 0; j < 3; j++) {
                if (*bufferp == '\0') {
                  printf("Syntax error reading vertex coords on line");
                  printf(" %d in file %s\n", line_count, infilename);
                  fclose(fp);
                  return false;
                }
                coord[j] = (REAL) strtod(bufferp, &bufferp);
                bufferp = findnextnumber(bufferp);
              }
            }
          }
          continue;
        }
    
        if(!strcmp(id, "POLYGONS")) {
          sscanf(line, "%s %d  %d", id, &nfaces, &dummy);
          if (nfaces > 0) {
            numberoffacets = nfaces;
            facetlist = new tetgenio::facet[nfaces];
          }
    
          if(!strcmp(mode, "BINARY")) {
            for(i = 0; i < nfaces; i++){
              fread((char*)(&nn), sizeof(int), 1, fp);
              if(ImALittleEndian){
                swapBytes((unsigned char *) &nn, sizeof(nn));
              }
              if (i == 0)
                nn_old = nn;
              if (nn != nn_old) {
                printf("Error:  No mixed cells are allowed.\n");
                return false;
              }
    
              if(nn == 3){
                fread((char*)(&id1), sizeof(int), 1, fp);
                fread((char*)(&id2), sizeof(int), 1, fp);
                fread((char*)(&id3), sizeof(int), 1, fp);
                if(ImALittleEndian){
                  swapBytes((unsigned char *) &id1, sizeof(id1));
                  swapBytes((unsigned char *) &id2, sizeof(id2));
                  swapBytes((unsigned char *) &id3, sizeof(id3));
                }
                f = &facetlist[i];
                init(f);
                // In .off format, each facet has one polygon, no hole.
                f->numberofpolygons = 1;
                f->polygonlist = new tetgenio::polygon[1];
                p = &f->polygonlist[0];
                init(p);
                // Set number of vertices
                p->numberofvertices = 3;
                // Allocate memory for face vertices
                p->vertexlist = new int[p->numberofvertices];
                p->vertexlist[0] = id1;
                p->vertexlist[1] = id2;
                p->vertexlist[2] = id3;
                // Detect the smallest index.
                for (j = 0; j < 3; j++) {
                  if (p->vertexlist[j] < smallestidx) {
                    smallestidx = p->vertexlist[j];
                  }
                }
              } else {
                printf("Error: Only triangles are supported\n");
                return false;
              }
            }
          } else if(!strcmp(mode, "ASCII")) {
            for(i = 0; i < nfaces; i++) {
              bufferp = readline(line, fp, &line_count);
              nn = (int) strtol(bufferp, &bufferp, 0);
              if (i == 0)
                nn_old = nn;
              if (nn != nn_old) {
                printf("Error:  No mixed cells are allowed.\n");
                return false;
              }
    
              if (nn == 3) {
                bufferp = findnextnumber(bufferp); // Skip the first field.
                id1 = (int) strtol(bufferp, &bufferp, 0);
                bufferp = findnextnumber(bufferp);
                id2 = (int) strtol(bufferp, &bufferp, 0);
                bufferp = findnextnumber(bufferp);
                id3 = (int) strtol(bufferp, &bufferp, 0);
                f = &facetlist[i];
                init(f);
                // In .off format, each facet has one polygon, no hole.
                f->numberofpolygons = 1;
                f->polygonlist = new tetgenio::polygon[1];
                p = &f->polygonlist[0];
                init(p);
                // Set number of vertices
                p->numberofvertices = 3;
                // Allocate memory for face vertices
                p->vertexlist = new int[p->numberofvertices];
                p->vertexlist[0] = id1;
                p->vertexlist[1] = id2;
                p->vertexlist[2] = id3;
                // Detect the smallest index.
                for (j = 0; j < 3; j++) {
                  if (p->vertexlist[j] < smallestidx) {
                    smallestidx = p->vertexlist[j];
                  }
                }
              } else {
                printf("Error:  Only triangles are supported.\n");
                return false;
              }
            }
          }
    
          fclose(fp);
    
          // Decide the firstnumber of the index.
          if (smallestidx == 0) {
            firstnumber = 0;  
          } else if (smallestidx == 1) {
            firstnumber = 1;
          } else {
            printf("A wrong smallest index (%d) was detected in file %s\n",
                   smallestidx, infilename);
            return false;
          }
    
          return true;
        }
    
        if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
          printf("Warning:  load_vtk(): cannot read formats LINES, CELLS.\n");
        }
      } // while ()
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_plc()    Load a piecewise linear complex from file(s).               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_plc(char* filebasename, int object)
    {
      bool success;
    
      if (object == (int) tetgenbehavior::NODES) {
        success = load_node(filebasename);
      } else if (object == (int) tetgenbehavior::POLY) {
        success = load_poly(filebasename);
      } else if (object == (int) tetgenbehavior::OFF) {
        success = load_off(filebasename);
      } else if (object == (int) tetgenbehavior::PLY) {
        success = load_ply(filebasename);
      } else if (object == (int) tetgenbehavior::STL) {
        success = load_stl(filebasename);
      } else if (object == (int) tetgenbehavior::MEDIT) {
        success = load_medit(filebasename, 0);
      } else if (object == (int) tetgenbehavior::VTK) {
        success = load_vtk(filebasename);
      } else {
        success = load_poly(filebasename);
      }
    
      if (success) {
        load_edge(filebasename);
        load_var(filebasename);
        load_mtr(filebasename);
      }
    
      return success;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // load_mesh()    Load a tetrahedral mesh from file(s).                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenio::load_tetmesh(char* filebasename, int object)
    {
      bool success;
    
      if (object == (int) tetgenbehavior::MEDIT) {
        success = load_medit(filebasename, 1);
      } else {
        success = load_node(filebasename);
        if (success) {
          success = load_tet(filebasename);
        }
        if (success) {
          load_face(filebasename);
          load_edge(filebasename);
          load_vol(filebasename);
        }
      }
    
      if (success) {
        load_var(filebasename);
        load_mtr(filebasename);
      }
    
      return success;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_nodes()    Save points to a .node file.                              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_nodes(char* filebasename)
    {
      FILE *fout;
      char outnodefilename[FILENAMESIZE];
      char outmtrfilename[FILENAMESIZE];
      int i, j;
    
      sprintf(outnodefilename, "%s.node", filebasename);
      printf("Saving nodes to %s\n", outnodefilename);
      fout = fopen(outnodefilename, "w");
      fprintf(fout, "%d  %d  %d  %d\n", numberofpoints, mesh_dim,
              numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
      for (i = 0; i < numberofpoints; i++) {
        if (mesh_dim == 2) {
          fprintf(fout, "%d  %.16g  %.16g", i + firstnumber, pointlist[i * 3],
                  pointlist[i * 3 + 1]);
        } else {
          fprintf(fout, "%d  %.16g  %.16g  %.16g", i + firstnumber,
                  pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
        }
        for (j = 0; j < numberofpointattributes; j++) {
          fprintf(fout, "  %.16g", 
                  pointattributelist[i * numberofpointattributes + j]);
        }
        if (pointmarkerlist != NULL) {
          fprintf(fout, "  %d", pointmarkerlist[i]);
        }
        fprintf(fout, "\n");
      }
      fclose(fout);
    
      // If the point metrics exist, output them to a .mtr file.
      if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
        sprintf(outmtrfilename, "%s.mtr", filebasename);
        printf("Saving metrics to %s\n", outmtrfilename);
        fout = fopen(outmtrfilename, "w");
        fprintf(fout, "%d  %d\n", numberofpoints, numberofpointmtrs);
        for (i = 0; i < numberofpoints; i++) {
          for (j = 0; j < numberofpointmtrs; j++) {
            fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
          }
          fprintf(fout, "\n");
        }
        fclose(fout);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_elements()    Save elements to a .ele file.                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_elements(char* filebasename)
    {
      FILE *fout;
      char outelefilename[FILENAMESIZE];
      int i, j;
    
      sprintf(outelefilename, "%s.ele", filebasename);
      printf("Saving elements to %s\n", outelefilename);
      fout = fopen(outelefilename, "w");
      if (mesh_dim == 3) {
        fprintf(fout, "%d  %d  %d\n", numberoftetrahedra, numberofcorners,
                numberoftetrahedronattributes);
        for (i = 0; i < numberoftetrahedra; i++) {
          fprintf(fout, "%d", i + firstnumber);
          for (j = 0; j < numberofcorners; j++) {
            fprintf(fout, "  %5d", tetrahedronlist[i * numberofcorners + j]);
          }
          for (j = 0; j < numberoftetrahedronattributes; j++) {
            fprintf(fout, "  %g",
              tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
          }
          fprintf(fout, "\n");
        }
      } else {
        // Save a two-dimensional mesh.
        fprintf(fout, "%d  %d  %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
        for (i = 0; i < numberoftrifaces; i++) {
          fprintf(fout, "%d", i + firstnumber);
          for (j = 0; j < 3; j++) {
            fprintf(fout, "  %5d", trifacelist[i * 3 + j]);
          }
          if (trifacemarkerlist != NULL) {
            fprintf(fout, "  %d", trifacemarkerlist[i]);
          }
          fprintf(fout, "\n");
        }
      }
    
      fclose(fout);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_faces()    Save faces to a .face file.                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_faces(char* filebasename)
    {
      FILE *fout;
      char outfacefilename[FILENAMESIZE];
      int i;
    
      sprintf(outfacefilename, "%s.face", filebasename);
      printf("Saving faces to %s\n", outfacefilename);
      fout = fopen(outfacefilename, "w");
      fprintf(fout, "%d  %d\n", numberoftrifaces, 
              trifacemarkerlist != NULL ? 1 : 0);
      for (i = 0; i < numberoftrifaces; i++) {
        fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber, trifacelist[i * 3],
                trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
        if (trifacemarkerlist != NULL) {
          fprintf(fout, "  %d", trifacemarkerlist[i]);
        }
        fprintf(fout, "\n");
      }
    
      fclose(fout);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_edges()    Save egdes to a .edge file.                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_edges(char* filebasename)
    {
      FILE *fout;
      char outedgefilename[FILENAMESIZE];
      int i;
    
      sprintf(outedgefilename, "%s.edge", filebasename);
      printf("Saving edges to %s\n", outedgefilename);
      fout = fopen(outedgefilename, "w");
      fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
      for (i = 0; i < numberofedges; i++) {
        fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
                edgelist[i * 2 + 1]);
        if (edgemarkerlist != NULL) {
          fprintf(fout, "  %d", edgemarkerlist[i]);
        }
        fprintf(fout, "\n");
      }
    
      fclose(fout);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_neighbors()    Save egdes to a .neigh file.                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_neighbors(char* filebasename)
    {
      FILE *fout;
      char outneighborfilename[FILENAMESIZE];
      int i;
    
      sprintf(outneighborfilename, "%s.neigh", filebasename);
      printf("Saving neighbors to %s\n", outneighborfilename);
      fout = fopen(outneighborfilename, "w");
      fprintf(fout, "%d  %d\n", numberoftetrahedra, mesh_dim + 1);
      for (i = 0; i < numberoftetrahedra; i++) {
        if (mesh_dim == 2) {
          fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber,  neighborlist[i * 3],
                  neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
        } else {
          fprintf(fout, "%d  %5d  %5d  %5d  %5d", i + firstnumber,
                  neighborlist[i * 4], neighborlist[i * 4 + 1],
                  neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
        }
        fprintf(fout, "\n");
      }
    
      fclose(fout);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_poly()    Save segments or facets to a .poly file.                   //
    //                                                                           //
    // It only save the facets, holes and regions. No .node file is saved.       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_poly(char* filebasename)
    {
      FILE *fout;
      facet *f;
      polygon *p;
      char outpolyfilename[FILENAMESIZE];
      int i, j, k;
    
      sprintf(outpolyfilename, "%s.poly", filebasename);
      printf("Saving poly to %s\n", outpolyfilename);
      fout = fopen(outpolyfilename, "w");
    
      // The zero indicates that the vertices are in a separate .node file.
      //   Followed by number of dimensions, number of vertex attributes,
      //   and number of boundary markers (zero or one).
      fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
              pointmarkerlist != NULL ? 1 : 0);
    
      // Save segments or facets.
      if (mesh_dim == 2) {
        // Number of segments, number of boundary markers (zero or one).
        fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
        for (i = 0; i < numberofedges; i++) {
          fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
                  edgelist[i * 2 + 1]);
          if (edgemarkerlist != NULL) {
            fprintf(fout, "  %d", edgemarkerlist[i]);
          }
          fprintf(fout, "\n");
        }
      } else {
        // Number of facets, number of boundary markers (zero or one).
        fprintf(fout, "%d  %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
        for (i = 0; i < numberoffacets; i++) {
          f = &(facetlist[i]);
          fprintf(fout, "%d  %d  %d  # %d\n", f->numberofpolygons,f->numberofholes,
                facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
          // Output polygons of this facet.
          for (j = 0; j < f->numberofpolygons; j++) {
            p = &(f->polygonlist[j]);
            fprintf(fout, "%d  ", p->numberofvertices);
            for (k = 0; k < p->numberofvertices; k++) {
              if (((k + 1) % 10) == 0) {
                fprintf(fout, "\n  ");
              }
              fprintf(fout, "  %d", p->vertexlist[k]);
            }
            fprintf(fout, "\n");
          }
          // Output holes of this facet.
          for (j = 0; j < f->numberofholes; j++) {
            fprintf(fout, "%d  %.12g  %.12g  %.12g\n", j + firstnumber,
               f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
          }
        }
      }
    
      // Save holes.
      fprintf(fout, "%d\n", numberofholes);
      for (i = 0; i < numberofholes; i++) {
        // Output x, y coordinates.
        fprintf(fout, "%d  %.12g  %.12g", i + firstnumber, holelist[i * mesh_dim],
                holelist[i * mesh_dim + 1]);
        if (mesh_dim == 3) {
          // Output z coordinate.
          fprintf(fout, "  %.12g", holelist[i * mesh_dim + 2]);
        }
        fprintf(fout, "\n");
      }
    
      // Save regions.
      fprintf(fout, "%d\n", numberofregions);
      for (i = 0; i < numberofregions; i++) {
        if (mesh_dim == 2) {
          // Output the index, x, y coordinates, attribute (region number)
          //   and maximum area constraint (maybe -1).
          fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
                  regionlist[i * 4], regionlist[i * 4 + 1],
                  regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
        } else {
          // Output the index, x, y, z coordinates, attribute (region number)
          //   and maximum volume constraint (maybe -1).
          fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
                  regionlist[i * 5], regionlist[i * 5 + 1],
                  regionlist[i * 5 + 2], regionlist[i * 5 + 3],
                  regionlist[i * 5 + 4]);
        }
      }
    
      fclose(fout);  
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // save_faces2smesh()    Save triangular faces to a .smesh file.             //
    //                                                                           //
    // It only save the facets. No holes and regions. No .node file.             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenio::save_faces2smesh(char* filebasename)
    {
      FILE *fout;
      char outsmeshfilename[FILENAMESIZE];
      int i, j;
    
      sprintf(outsmeshfilename, "%s.smesh", filebasename);
      printf("Saving faces to %s\n", outsmeshfilename);
      fout = fopen(outsmeshfilename, "w");
    
      // The zero indicates that the vertices are in a separate .node file.
      //   Followed by number of dimensions, number of vertex attributes,
      //   and number of boundary markers (zero or one).
      fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
              pointmarkerlist != NULL ? 1 : 0);
    
      // Number of facets, number of boundary markers (zero or one).
      fprintf(fout, "%d  %d\n", numberoftrifaces, 
              trifacemarkerlist != NULL ? 1 : 0);
    
      // Output triangular facets.
      for (i = 0; i < numberoftrifaces; i++) {
        j = i * 3;
        fprintf(fout, "3  %d %d %d", trifacelist[j], trifacelist[j + 1], 
                trifacelist[j + 2]);
        if (trifacemarkerlist != NULL) {
          fprintf(fout, "  %d", trifacemarkerlist[i]);
        }
        fprintf(fout, "\n");
      }
    
      // No holes and regions.
      fprintf(fout, "0\n");
      fprintf(fout, "0\n");
    
      fclose(fout);  
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // readline()   Read a nonempty line from a file.                            //
    //                                                                           //
    // A line is considered "nonempty" if it contains something more than white  //
    // spaces.  If a line is considered empty, it will be dropped and the next   //
    // line will be read, this process ends until reaching the end-of-file or a  //
    // non-empty line.  Return NULL if it is the end-of-file, otherwise, return  //
    // a pointer to the first non-whitespace character of the line.              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
    {
      char *result;
    
      // Search for a non-empty line.
      do {
        result = fgets(string, INPUTLINESIZE - 1, infile);
        if (linenumber) (*linenumber)++;
        if (result == (char *) NULL) {
          return (char *) NULL;
        }
        // Skip white spaces.
        while ((*result == ' ') || (*result == '\t')) result++;
        // If it's end of line, read another line and try again.
      } while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
      return result;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // findnextfield()   Find the next field of a string.                        //
    //                                                                           //
    // Jumps past the current field by searching for whitespace or a comma, then //
    // jumps past the whitespace or the comma to find the next field.            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    char* tetgenio::findnextfield(char *string)
    {
      char *result;
    
      result = string;
      // Skip the current field.  Stop upon reaching whitespace or a comma.
      while ((*result != '\0') && (*result != ' ') &&  (*result != '\t') && 
             (*result != ',') && (*result != ';')) {
        result++;
      }
      // Now skip the whitespace or the comma, stop at anything else that looks
      //   like a character, or the end of a line. 
      while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
             (*result == ';')) {
        result++;
      }
      return result;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // readnumberline()   Read a nonempty number line from a file.               //
    //                                                                           //
    // A line is considered "nonempty" if it contains something that looks like  //
    // a number.  Comments (prefaced by `#') are ignored.                        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
    {
      char *result;
    
      // Search for something that looks like a number.
      do {
        result = fgets(string, INPUTLINESIZE, infile);
        if (result == (char *) NULL) {
          return result;
        }
        // Skip anything that doesn't look like a number, a comment, 
        //   or the end of a line. 
        while ((*result != '\0') && (*result != '#')
               && (*result != '.') && (*result != '+') && (*result != '-')
               && ((*result < '0') || (*result > '9'))) {
          result++;
        }
        // If it's a comment or end of line, read another line and try again.
      } while ((*result == '#') || (*result == '\0'));
      return result;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // findnextnumber()   Find the next field of a number string.                //
    //                                                                           //
    // Jumps past the current field by searching for whitespace or a comma, then //
    // jumps past the whitespace or the comma to find the next field that looks  //
    // like a number.                                                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    char* tetgenio::findnextnumber(char *string)
    {
      char *result;
    
      result = string;
      // Skip the current field.  Stop upon reaching whitespace or a comma.
      while ((*result != '\0') && (*result != '#') && (*result != ' ') && 
             (*result != '\t') && (*result != ',')) {
        result++;
      }
      // Now skip the whitespace and anything else that doesn't look like a
      //   number, a comment, or the end of a line. 
      while ((*result != '\0') && (*result != '#')
             && (*result != '.') && (*result != '+') && (*result != '-')
             && ((*result < '0') || (*result > '9'))) {
        result++;
      }
      // Check for a comment (prefixed with `#').
      if (*result == '#') {
        *result = '\0';
      }
      return result;
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// io_cxx ///////////////////////////////////////////////////////////////////
    
    //// behavior_cxx /////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // syntax()    Print list of command line switches.                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenbehavior::syntax()
    {
      printf("  tetgen [-pYrq_a_AiS_T_dzfenvgKJBNEFICQVh] input_file\n");
      printf("    -p  Tetrahedralizes a piecewise linear complex (PLC).\n");
      printf("    -Y  No splitting of input boundaries (facets and segments).\n");
      printf("    -r  Reconstructs a previously generated mesh.\n");
      printf("    -q  Refines mesh (to improve mesh quality).\n");
      printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
      printf("    -A  Assigns attributes to tetrahedra in different regions.\n");
      printf("    -i  Inserts a list of additional points into mesh.\n");
      printf("    -S  Specifies maximum number of added points.\n");
      printf("    -T  Sets a tolerance for coplanar test (default 1e-8).\n");
      printf("    -d  Detects self-intersections of facets of the PLC.\n");
      printf("    -z  Numbers all output items starting from zero.\n");
      printf("    -f  Outputs all faces to .face file.\n");
      printf("    -e  Outputs all edges to .edge file.\n");
      printf("    -n  Outputs tetrahedra neighbors to .neigh file.\n");
      printf("    -v  Outputs Voronoi diagram to files.\n");
      printf("    -g  Outputs mesh to .mesh file for viewing by Medit.\n");
      printf("    -K  Outputs mesh to .vtk file for viewing by Paraview.\n");
      printf("    -J  No jettison of unused vertices from output .node file.\n");
      printf("    -B  Suppresses output of boundary information.\n");
      printf("    -N  Suppresses output of .node file.\n");
      printf("    -E  Suppresses output of .ele file.\n");
      printf("    -F  Suppresses output of .face file.\n");
      printf("    -I  Suppresses mesh iteration numbers.\n");
      printf("    -C  Checks the consistency of the final mesh.\n");
      printf("    -Q  Quiet:  No terminal output except errors.\n");
      printf("    -V  Verbose:  Detailed information, more terminal output.\n");
      printf("    -h  Help:  A brief instruction for using TetGen.\n");
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // usage()    Print a brief instruction for using TetGen.                    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenbehavior::usage()
    {
      printf("TetGen\n");
      printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
      printf("Triangulator\n");
      printf("Version 1.5 (February 21, 2012).\n");
      printf("\n");
      printf("Copyright (C) 2002 - 2012\n");
      printf("Hang Si\n");
      printf("Mohrenstr. 39, 10117 Berlin, Germany\n");
      printf("Hang.Si@wias-berlin.de\n");
      printf("\n");
      printf("What Can TetGen Do?\n");
      printf("\n");
      printf("  TetGen generates exact Delaunay tetrahedralizations, exact\n");
      printf("  constrained Delaunay tetrahedralizations, and quality ");
      printf("tetrahedral\n  meshes. The latter are nicely graded and whose ");
      printf("tetrahedra have\n  radius-edge ratio bounded, thus are suitable ");
      printf("for finite element and\n  finite volume analysis.\n"); 
      printf("\n");
      printf("Command Line Syntax:\n");
      printf("\n");
      printf("  Below is the basic command line syntax of TetGen with a list of ");
      printf("short\n");
      printf("  descriptions. Underscores indicate that numbers may optionally\n");
      printf("  follow certain switches.  Do not leave any space between a ");
      printf("switch\n");
      printf("  and its numeric parameter.  \'input_file\' contains input data\n");
      printf("  depending on the switches you supplied which may be a ");
      printf("  piecewise\n");
      printf("  linear complex or a list of nodes.  File formats and detailed\n");
      printf("  description of command line switches are found in user's ");
      printf("manual.\n");
      printf("\n");
      syntax();
      printf("\n");
      printf("Examples of How to Use TetGen:\n");
      printf("\n");
      printf("  \'tetgen object\' reads vertices from object.node, and writes ");
      printf("their\n  Delaunay tetrahedralization to object.1.node and ");
      printf("object.1.ele.\n");
      printf("\n");
      printf("  \'tetgen -p object\' reads a PLC from object.poly or object.");
      printf("smesh (and\n  possibly object.node) and writes its constrained ");
      printf("Delaunay\n  tetrahedralization to object.1.node, object.1.ele and ");
      printf("object.1.face.\n");
      printf("\n");
      printf("  \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
      printf("  object.smesh (and possibly object.node), generates a mesh ");
      printf("whose\n  tetrahedra have radius-edge ratio smaller than 1.414 and ");
      printf("have volume\n  of 0.1 or less, and writes the mesh to ");
      printf("object.1.node, object.1.ele\n  and object.1.face.\n");
      printf("\n");
      printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
      terminatetetgen(0);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // parse_commandline()    Read the command line, identify switches, and set  //
    //                        up options and file names.                         //
    //                                                                           //
    // 'argc' and 'argv' are the same parameters passed to the function main()   //
    // of a C/C++ program. They together represent the command line user invoked //
    // from an environment in which TetGen is running.                           //
    //                                                                           //
    // When TetGen is invoked from an environment. 'argc' is nonzero, switches   //
    // and input filename should be supplied as zero-terminated strings in       //
    // argv[0] through argv[argc - 1] and argv[0] shall be the name used to      //
    // invoke TetGen, i.e. "tetgen".  Switches are previously started with a     //
    // dash '-' to identify them from the input filename.                        //
    //                                                                           //
    // When TetGen is called from within another program. 'argc' is set to zero. //
    // switches are given in one zero-terminated string (no previous dash is     //
    // required.), and 'argv' is a pointer points to this string.  No input      //
    // filename is required (usually the input data has been directly created by //
    // user in the 'tetgenio' structure).  A default filename 'tetgen-tmpfile'   //
    // will be created for debugging output purpose.                             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenbehavior::parse_commandline(int argc, char **argv)
    {
      int startindex;
      int increment;
      int meshnumber;
      int scount, ocount;
      int i, j, k;
      char workstring[1024];
    
      // First determine the input style of the switches.
      if (argc == 0) {
        startindex = 0;                    // Switches are given without a dash.
        argc = 1;                    // For running the following for-loop once.
        commandline[0] = '\0';
      } else {
        startindex = 1;
        strcpy(commandline, argv[0]);
        strcat(commandline, " ");
      }
      
      // Count the number of '-O' and '-o' be used.
      scount = ocount = 0;
    
      for (i = startindex; i < argc; i++) {
        // Remember the command line switches.
        strcat(commandline, argv[i]);
        strcat(commandline, " ");
        if (startindex == 1) {
          // Is this string a filename?
          if (argv[i][0] != '-') {
            strncpy(infilename, argv[i], 1024 - 1);
            infilename[1024 - 1] = '\0';
            // Go to the next string directly.
            continue;                     
          }
        }
        // Parse the individual switch from the string.
        for (j = startindex; argv[i][j] != '\0'; j++) {
          if (argv[i][j] == 'p') {
            plc = 1;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              facet_ang_tol = (REAL) strtod(workstring, (char **) NULL);
            }
          } else if (argv[i][j] == 's') {
            psc = 1;        
          } else if (argv[i][j] == 'r') {
            refine++;
          } else if (argv[i][j] == 'q') {
            quality++;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              if (quality == 1) { // -q#
                minratio = (REAL) strtod(workstring, (char **) NULL);
              } else if (quality == 2) { // -qq#
                mindihedral = (REAL) strtod(workstring, (char **) NULL);
              }
            }
          } else if (argv[i][j] == 'm') {
            metric++;
          } else if (argv[i][j] == 'Y') {
            nobisect = 1;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              nobisect_param = (int) strtol(workstring, (char **) NULL, 0);
            }
          } else if (argv[i][j] == 'w') {
            weighted = 1;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              weighted_param = (int) strtol(workstring, (char **) NULL, 0);
            }
          } else if (argv[i][j] == 'a') {
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              fixedvolume = 1;
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              maxvolume = (REAL) strtod(workstring, (char **) NULL);
            } else {
              varvolume = 1;
            }
          } else if (argv[i][j] == 'A') {
            regionattrib++;
          } else if (argv[i][j] == 'l') {
            incrflip = 1;
            // Check if a smallest edge length is given. 
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              minedgelength = (REAL) strtod(workstring, (char **) NULL);
            }
          } else if (argv[i][j] == 'L') {
            flipinsert++;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              if (flipinsert == 1) { // -L
                fliplinklevel = (int) strtol(workstring, (char **) NULL, 0);
              } else if (flipinsert == 2) { // -LL
                flipstarsize = (int) strtol(workstring, (char **) NULL, 0);
              }
            }
          } else if (argv[i][j] == 'u') {
            // Set the maximum btree node size, -u0 means do not use btree.
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              max_btreenode_size = (int) strtol(workstring, (char **) NULL, 0);
            }
            if (max_btreenode_size == 0) {
              btree = 0;
            }
          } else if (argv[i][j] == 'U') {
            hilbertcurve = 1;
            btree = 0;
          } else if (argv[i][j] == 'i') {
            insertaddpoints = 1;
          } else if (argv[i][j] == 'd') {
            diagnose = 1;
          } else if (argv[i][j] == 'c') {
            convex = 1;
          } else if (argv[i][j] == 'z') {
            zeroindex = 1;
          } else if (argv[i][j] == 'f') {
            facesout = 1;
          } else if (argv[i][j] == 'e') {
            edgesout++;
          } else if (argv[i][j] == 'n') {
            neighout++;
          } else if (argv[i][j] == 'v') {
            voroout = 1;
          } else if (argv[i][j] == 'g') {
            meditview = 1;
          } else if (argv[i][j] == 'K') {
            vtkview = 1;  
          } else if (argv[i][j] == 'M') {
            nomerge = 1;
          } else if (argv[i][j] == 'J') {
            nojettison = 1;
          } else if (argv[i][j] == 'B') {
            nobound = 1;
          } else if (argv[i][j] == 'N') {
            nonodewritten = 1;
          } else if (argv[i][j] == 'E') {
            noelewritten = 1;
            if (argv[i][j + 1] == '2') {
              j++;
              noelewritten = 2;
            }
          } else if (argv[i][j] == 'F') {
            nofacewritten = 1;
          } else if (argv[i][j] == 'I') {
            noiterationnum = 1;
          } else if (argv[i][j] == 'S') {
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              steinerleft = (int) strtol(workstring, (char **) NULL, 0);
            }
          } else if (argv[i][j] == 'o') {
            ocount++;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              if (ocount == 1) { // -o#
                optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
              } else if (ocount == 2) { // -oo#
                optminsmtdihed = (REAL) strtod(workstring, (char **) NULL);
              } else if (ocount == 3) { // -ooo#
                optminslidihed = (REAL) strtod(workstring, (char **) NULL);
              } 
            }
          } else if (argv[i][j] == 'O') {
            scount++;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              if (scount == 1) { // -O
                optlevel = (int) strtol(workstring, (char **) NULL, 0);
              } else if (scount == 2) { // -OO
                optpasses = (int) strtol(workstring, (char **) NULL, 0);
              } else if (scount == 3) { // -OOO
                optmaxfliplevel = (int) strtol(workstring, (char **) NULL, 0);
              } else if (scount == 4) { // -OOOO
                delmaxfliplevel = (int) strtol(workstring, (char **) NULL, 0);
              } else if (scount == 5) { // -OOOOO (5 Os)
                optmaxflipstarsize = (int) strtol(workstring, (char **) NULL, 0);
              }
            }
          } else if (argv[i][j] == 'D') {
            conforming = 1;
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              reflevel = (int) strtol(workstring, (char **) NULL, 0);
            }
          } else if (argv[i][j] == 'T') {
            if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                (argv[i][j + 1] == '.')) {
              k = 0;
              while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
                     (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
                     (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
                j++;
                workstring[k] = argv[i][j];
                k++;
              }
              workstring[k] = '\0';
              epsilon = (REAL) strtod(workstring, (char **) NULL);
            }
          } else if (argv[i][j] == 'C') {
            docheck++;
          } else if (argv[i][j] == 'Q') {
            quiet = 1;
          } else if (argv[i][j] == 'V') {
            verbose++;
          } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
                     (argv[i][j] == '?')) {
            usage();
          } else {
            printf("Warning:  Unknown switch -%c.\n", argv[i][j]);
          }
        }
      }
    
      if (startindex == 0) {
        // Set a temporary filename for debugging output.
        strcpy(infilename, "tetgen-tmpfile");
      } else {
        if (infilename[0] == '\0') {
          // No input file name. Print the syntax and exit.
          syntax();
          terminatetetgen(0);
        }
        // Recognize the object from file extension if it is available.
        if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
          infilename[strlen(infilename) - 5] = '\0';
          object = NODES;
        } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
          infilename[strlen(infilename) - 5] = '\0';
          object = POLY;
          plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
          infilename[strlen(infilename) - 6] = '\0';
          object = POLY;
          plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
          infilename[strlen(infilename) - 4] = '\0';
          object = OFF;
          plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
          infilename[strlen(infilename) - 4] = '\0';
          object = PLY;
          plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
          infilename[strlen(infilename) - 4] = '\0';
          object = STL;
          plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
          infilename[strlen(infilename) - 5] = '\0';
          object = MEDIT;
          if (!refine) plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
          infilename[strlen(infilename) - 4] = '\0';
          object = VTK;
          plc = 1;
        } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
          infilename[strlen(infilename) - 4] = '\0';
          object = MESH;
          refine = 1;
        }
      }
    
      if (nobisect && (!plc && !refine)) { // -Y
        plc = 1; // Default -p option.
      }
      if (quality && (!plc && !refine)) { // -q
        plc = 1; // Default -p option.
      }
      if (diagnose && !plc) { // -d
        plc = 1;
      }
    
      // Detect improper combinations of switches.
      if (plc && refine) {
        printf("Error:  Switch -r cannot use together with -p.\n");
        return false;
      }
      if (refine && (plc || noiterationnum)) {
        printf("Error:  Switches %s cannot use together with -r.\n",
               "-p, -d, and -I");
        return false;
      }
      if ((refine || plc) && weighted) {
        printf("Error:  Switches -w cannot use together with -p or -r.\n");
        return false;
      }
    
      // Be careful not to allocate space for element area constraints that 
      //   will never be assigned any value (other than the default -1.0).
      if (!refine && !plc) {
        varvolume = 0;
      }
      // Be careful not to add an extra attribute to each element unless the
      //   input supports it (PLC in, but not refining a preexisting mesh).
      if (refine || !plc) {
        regionattrib = 0;
      }
      // If '-a' or '-aa' is in use, enable '-q' option too.
      if (fixedvolume || varvolume) {
        if (quality == 0) {
          quality = 1;
          if (!plc && !refine) {
            plc = 1; // enable -p.
          }
        }
      }
      if (ocount == 0) {
        // No user-specified dihedral angle bound. Use default ones.
        if (!quality) {
          if (optmaxdihedral < 179.0) {
            optmaxdihedral = 179.0;
          }
          if (optminsmtdihed < 179.999) {
            optminsmtdihed = 179.999;
          }
          if (optminslidihed < 179.999) {
            optminslidihed = 179.99;
          }
        }
      }
    
      increment = 0;
      strcpy(workstring, infilename);
      j = 1;
      while (workstring[j] != '\0') {
        if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
          increment = j + 1;
        }
        j++;
      }
      meshnumber = 0;
      if (increment > 0) {
        j = increment;
        do {
          if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
            meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
          } else {
            increment = 0;
          }
          j++;
        } while (workstring[j] != '\0');
      }
      if (noiterationnum) {
        strcpy(outfilename, infilename);
      } else if (increment == 0) {
        strcpy(outfilename, infilename);
        strcat(outfilename, ".1");
      } else {
        workstring[increment] = '%';
        workstring[increment + 1] = 'd';
        workstring[increment + 2] = '\0';
        sprintf(outfilename, workstring, meshnumber + 1);
      }
      // Additional input file name has the end ".a".
      strcpy(addinfilename, infilename);
      strcat(addinfilename, ".a");
      // Background filename has the form "*.b.ele", "*.b.node", ...
      strcpy(bgmeshfilename, infilename);
      strcat(bgmeshfilename, ".b");
    
      return true;
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// behavior_cxx /////////////////////////////////////////////////////////////
    
    //// mempool_cxx //////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    // Initialize fast lookup tables for mesh maniplulation primitives.
    
    int tetgenmesh::mod12[36] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    
    int tetgenmesh::mod6[18] = {0, 1, 2, 3, 4, 5,
                                0, 1, 2, 3, 4, 5,
                                0, 1, 2, 3, 4, 5};
    
    // Table 'edgepivot' takes an directed edge (version) as input, returns the
    //   inversed edge (version) of it.
    
    int tetgenmesh::edgepivot[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
    
    // The following four tables give the 12 permutations of the set {0,1,2,3}.
    //   An offset 4 is added to each element for a direct access of the points
    //   in the tetrahedron data structure.
    
    int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
    int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
    int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
    int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
    
    // The twelve versions correspond to six undirected edges. The following two
    //   tables map a version to an undirected edge and vice versa.
    
    int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
    int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
    
    // Table 'snextpivot' takes an edge version as input, returns the next edge
    //   version in the same edge ring.
    
    int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
    
    // The following three tables give the 6 permutations of the set {0,1,2}.
    //   An offset 3 is added to each element for a direct access of the points
    //   in the triangle data structure.
    
    int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
    int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
    int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
    
    // Edge versions whose apex or opposite may be dummypoint.
    
    int tetgenmesh::epivot[4] = {4, 5, 2, 11};
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // restart()    Deallocate all objects in this pool.                         //
    //                                                                           //
    // The pool returns to a fresh state, like after it was initialized, except  //
    // that no memory is freed to the operating system.  Rather, the previously  //
    // allocated blocks are ready to be used.                                    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::arraypool::restart()
    {
      objects = 0l;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // poolinit()    Initialize an arraypool for allocation of objects.          //
    //                                                                           //
    // Before the pool may be used, it must be initialized by this procedure.    //
    // After initialization, memory can be allocated and freed in this pool.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
    {
      // Each object must be at least one byte long.
      objectbytes = sizeofobject > 1 ? sizeofobject : 1;
    
      log2objectsperblock = log2objperblk;
      // Compute the number of objects in each block.
      objectsperblock = ((int) 1) << log2objectsperblock;
    
      // No memory has been allocated.
      totalmemory = 0l;
      // The top array has not been allocated yet.
      toparray = (char **) NULL;
      toparraylen = 0;
    
      // Ready all indices to be allocated.
      restart();
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // arraypool()    The constructor and destructor.                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
    {
      poolinit(sizeofobject, log2objperblk);
    }
    
    tetgenmesh::arraypool::~arraypool()
    {
      int i;
    
      // Has anything been allocated at all?
      if (toparray != (char **) NULL) {
        // Walk through the top array.
        for (i = 0; i < toparraylen; i++) {
          // Check every pointer; NULLs may be scattered randomly.
          if (toparray[i] != (char *) NULL) {
            // Free an allocated block.
            free((void *) toparray[i]);
          }
        }
        // Free the top array.
        free((void *) toparray);
      }
    
      // The top array is no longer allocated.
      toparray = (char **) NULL;
      toparraylen = 0;
      objects = 0;
      totalmemory = 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // getblock()    Return (and perhaps create) the block containing the object //
    //               with a given index.                                         //
    //                                                                           //
    // This function takes care of allocating or resizing the top array if nece- //
    // ssary, and of allocating the block if it hasn't yet been allocated.       //
    //                                                                           //
    // Return a pointer to the beginning of the block (NOT the object).          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    char* tetgenmesh::arraypool::getblock(int objectindex)
    {
      char **newarray;
      char *block;
      int newsize;
      int topindex;
      int i;
    
      // Compute the index in the top array (upper bits).
      topindex = objectindex >> log2objectsperblock;
      // Does the top array need to be allocated or resized?
      if (toparray == (char **) NULL) {
        // Allocate the top array big enough to hold 'topindex', and NULL out
        //   its contents.
        newsize = topindex + 128;
        toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
        toparraylen = newsize;
        for (i = 0; i < newsize; i++) {
          toparray[i] = (char *) NULL;
        }
        // Account for the memory.
        totalmemory = newsize * (uintptr_t) sizeof(char *);
      } else if (topindex >= toparraylen) {
        // Resize the top array, making sure it holds 'topindex'.
        newsize = 3 * toparraylen;
        if (topindex >= newsize) {
          newsize = topindex + 128;
        }
        // Allocate the new array, copy the contents, NULL out the rest, and
        //   free the old array.
        newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
        for (i = 0; i < toparraylen; i++) {
          newarray[i] = toparray[i];
        }
        for (i = toparraylen; i < newsize; i++) {
          newarray[i] = (char *) NULL;
        }
        free(toparray);
        // Account for the memory.
        totalmemory += (newsize - toparraylen) * sizeof(char *);
        toparray = newarray;
        toparraylen = newsize;
      }
    
      // Find the block, or learn that it hasn't been allocated yet.
      block = toparray[topindex];
      if (block == (char *) NULL) {
        // Allocate a block at this index.
        block = (char *) malloc((size_t) (objectsperblock * objectbytes));
        toparray[topindex] = block;
        // Account for the memory.
        totalmemory += objectsperblock * objectbytes;
      }
    
      // Return a pointer to the block.
      return block;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // lookup()    Return the pointer to the object with a given index, or NULL  //
    //             if the object's block doesn't exist yet.                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void* tetgenmesh::arraypool::lookup(int objectindex)
    {
      char *block;
      int topindex;
    
      // Has the top array been allocated yet?
      if (toparray == (char **) NULL) {
        return (void *) NULL;
      }
    
      // Compute the index in the top array (upper bits).
      topindex = objectindex >> log2objectsperblock;
      // Does the top index fit in the top array?
      if (topindex >= toparraylen) {
        return (void *) NULL;
      }
    
      // Find the block, or learn that it hasn't been allocated yet.
      block = toparray[topindex];
      if (block == (char *) NULL) {
        return (void *) NULL;
      }
    
      // Compute a pointer to the object with the given index.  Note that
      //   'objectsperblock' is a power of two, so the & operation is a bit mask
      //   that preserves the lower bits.
      return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // newindex()    Allocate space for a fresh object from the pool.            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::arraypool::newindex(void **newptr)
    {
      void *newobject;
      int newindex;
    
      // Allocate an object at index 'firstvirgin'.
      newindex = objects;
      newobject = (void *) (getblock(objects) +
        (objects & (objectsperblock - 1)) * objectbytes);
      objects++;
    
      // If 'newptr' is not NULL, use it to return a pointer to the object.
      if (newptr != (void **) NULL) {
        *newptr = newobject;
      }
      return newindex;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // memorypool()   The constructors of memorypool.                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::memorypool::memorypool()
    {
      firstblock = nowblock = (void **) NULL;
      nextitem = (void *) NULL;
      deaditemstack = (void *) NULL;
      pathblock = (void **) NULL;
      pathitem = (void *) NULL;
      itemwordtype = POINTER;
      alignbytes = 0;
      itembytes = itemwords = 0;
      itemsperblock = 0;
      items = maxitems = 0l;
      unallocateditems = 0;
      pathitemsleft = 0;
    }
    
    tetgenmesh::memorypool::
    memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment)
    {
      poolinit(bytecount, itemcount, wtype, alignment);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // ~memorypool()   Free to the operating system all memory taken by a pool.  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::memorypool::~memorypool()
    {
      while (firstblock != (void **) NULL) {
        nowblock = (void **) *(firstblock);
        free(firstblock);
        firstblock = nowblock;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // poolinit()    Initialize a pool of memory for allocation of items.        //
    //                                                                           //
    // A `pool' is created whose records have size at least `bytecount'.  Items  //
    // will be allocated in `itemcount'-item blocks.  Each item is assumed to be //
    // a collection of words, and either pointers or floating-point values are   //
    // assumed to be the "primary" word type.  (The "primary" word type is used  //
    // to determine alignment of items.)  If `alignment' isn't zero, all items   //
    // will be `alignment'-byte aligned in memory.  `alignment' must be either a //
    // multiple or a factor of the primary word size;  powers of two are safe.   //
    // `alignment' is normally used to create a few unused bits at the bottom of //
    // each item's pointer, in which information may be stored.                  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::memorypool::
    poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
    {
      int wordsize;
    
      // Initialize values in the pool.
      itemwordtype = wtype;
      wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL);
      // Find the proper alignment, which must be at least as large as:
      //   - The parameter `alignment'.
      //   - The primary word type, to avoid unaligned accesses.
      //   - sizeof(void *), so the stack of dead items can be maintained
      //       without unaligned accesses.
      if (alignment > wordsize) {
        alignbytes = alignment;
      } else {
        alignbytes = wordsize;
      }
      if ((int) sizeof(void *) > alignbytes) {
        alignbytes = (int) sizeof(void *);
      }
      itemwords = ((bytecount + alignbytes - 1) /  alignbytes)
                * (alignbytes / wordsize);
      itembytes = itemwords * wordsize;
      itemsperblock = itemcount;
    
      // Allocate a block of items.  Space for `itemsperblock' items and one
      //   pointer (to point to the next block) are allocated, as well as space
      //   to ensure alignment of the items. 
      firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
                                    + alignbytes); 
      if (firstblock == (void **) NULL) {
        terminatetetgen(1);
      }
      // Set the next block pointer to NULL.
      *(firstblock) = (void *) NULL;
      restart();
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // restart()   Deallocate all items in this pool.                            //
    //                                                                           //
    // The pool is returned to its starting state, except that no memory is      //
    // freed to the operating system.  Rather, the previously allocated blocks   //
    // are ready to be reused.                                                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::memorypool::restart()
    {
      uintptr_t alignptr;
    
      items = 0;
      maxitems = 0;
    
      // Set the currently active block.
      nowblock = firstblock;
      // Find the first item in the pool.  Increment by the size of (void *).
      alignptr = (uintptr_t) (nowblock + 1);
      // Align the item on an `alignbytes'-byte boundary.
      nextitem = (void *)
        (alignptr + (uintptr_t) alignbytes -
         (alignptr % (uintptr_t) alignbytes));
      // There are lots of unallocated items left in this block.
      unallocateditems = itemsperblock;
      // The stack of deallocated items is empty.
      deaditemstack = (void *) NULL;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // alloc()   Allocate space for an item.                                     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void* tetgenmesh::memorypool::alloc()
    {
      void *newitem;
      void **newblock;
      uintptr_t alignptr;
    
      // First check the linked list of dead items.  If the list is not 
      //   empty, allocate an item from the list rather than a fresh one.
      if (deaditemstack != (void *) NULL) {
        newitem = deaditemstack;                     // Take first item in list.
        deaditemstack = * (void **) deaditemstack;
      } else {
        // Check if there are any free items left in the current block.
        if (unallocateditems == 0) {
          // Check if another block must be allocated.
          if (*nowblock == (void *) NULL) {
            // Allocate a new block of items, pointed to by the previous block.
            newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) 
                                        + alignbytes);
            if (newblock == (void **) NULL) {
              terminatetetgen(1);
            }
            *nowblock = (void *) newblock;
            // The next block pointer is NULL.
            *newblock = (void *) NULL;
          }
          // Move to the new block.
          nowblock = (void **) *nowblock;
          // Find the first item in the block.
          //   Increment by the size of (void *).
          alignptr = (uintptr_t) (nowblock + 1);
          // Align the item on an `alignbytes'-byte boundary.
          nextitem = (void *)
            (alignptr + (uintptr_t) alignbytes -
             (alignptr % (uintptr_t) alignbytes));
          // There are lots of unallocated items left in this block.
          unallocateditems = itemsperblock;
        }
        // Allocate a new item.
        newitem = nextitem;
        // Advance `nextitem' pointer to next free item in block.
        if (itemwordtype == POINTER) {
          nextitem = (void *) ((void **) nextitem + itemwords);
        } else {
          nextitem = (void *) ((REAL *) nextitem + itemwords);
        }
        unallocateditems--;
        maxitems++;
      }
      items++;
      return newitem;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // dealloc()   Deallocate space for an item.                                 //
    //                                                                           //
    // The deallocated space is stored in a queue for later reuse.               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::memorypool::dealloc(void *dyingitem)
    {
      // Push freshly killed item onto stack.
      *((void **) dyingitem) = deaditemstack;
      deaditemstack = dyingitem;
      items--;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // traversalinit()   Prepare to traverse the entire list of items.           //
    //                                                                           //
    // This routine is used in conjunction with traverse().                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::memorypool::traversalinit()
    {
      uintptr_t alignptr;
    
      // Begin the traversal in the first block.
      pathblock = firstblock;
      // Find the first item in the block.  Increment by the size of (void *).
      alignptr = (uintptr_t) (pathblock + 1);
      // Align with item on an `alignbytes'-byte boundary.
      pathitem = (void *)
        (alignptr + (uintptr_t) alignbytes -
         (alignptr % (uintptr_t) alignbytes));
      // Set the number of items left in the current block.
      pathitemsleft = itemsperblock;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // traverse()   Find the next item in the list.                              //
    //                                                                           //
    // This routine is used in conjunction with traversalinit().  Be forewarned  //
    // that this routine successively returns all items in the list, including   //
    // deallocated ones on the deaditemqueue. It's up to you to figure out which //
    // ones are actually dead.  It can usually be done more space-efficiently by //
    // a routine that knows something about the structure of the item.           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void* tetgenmesh::memorypool::traverse()
    {
      void *newitem;
      uintptr_t alignptr;
    
      // Stop upon exhausting the list of items.
      if (pathitem == nextitem) {
        return (void *) NULL;
      }
      // Check whether any untraversed items remain in the current block.
      if (pathitemsleft == 0) {
        // Find the next block.
        pathblock = (void **) *pathblock;
        // Find the first item in the block.  Increment by the size of (void *).
        alignptr = (uintptr_t) (pathblock + 1);
        // Align with item on an `alignbytes'-byte boundary.
        pathitem = (void *)
          (alignptr + (uintptr_t) alignbytes -
           (alignptr % (uintptr_t) alignbytes));
        // Set the number of items left in the current block.
        pathitemsleft = itemsperblock;
      }
      newitem = pathitem;
      // Find the next item in the block.
      if (itemwordtype == POINTER) {
        pathitem = (void *) ((void **) pathitem + itemwords);
      } else {
        pathitem = (void *) ((REAL *) pathitem + itemwords);
      }
      pathitemsleft--;
      return newitem;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // makeindex2pointmap()    Create a map from index to vertices.              //
    //                                                                           //
    // 'idx2verlist' returns the created map.  Traverse all vertices, a pointer  //
    // to each vertex is set into the array.  The pointer to the first vertex is //
    // saved in 'idx2verlist[0]'.  Don't forget to minus 'in->firstnumber' when  //
    // to get the vertex form its index.                                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
    {
      point pointloop;
      int idx;
    
      if (b->verbose > 1) {
        printf("  Constructing mapping from indices to points.\n");
      }
    
      idx2verlist = new point[points->items + 1];
    
      points->traversalinit();
      pointloop = pointtraverse();
      idx =  in->firstnumber;;
      while (pointloop != (point) NULL) {
        idx2verlist[idx++] = pointloop;
        pointloop = pointtraverse();
      }
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // makesubfacemap()    Create a map from vertex to subfaces incident at it.  //
    //                                                                           //
    // The map is returned in two arrays 'idx2faclist' and 'facperverlist'.  All //
    // subfaces incident at i-th vertex (i is counted from 0) are found in the   //
    // array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1].   //
    // Each entry in facperverlist[j] is a subface whose origin is the vertex.   //
    //                                                                           //
    // NOTE: These two arrays will be created inside this routine, don't forget  //
    // to free them after using.                                                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
                                      face*& facperverlist)
    {
      face shloop;
      int i, j, k;
    
      if (b->verbose > 1) {
        printf("  Making a map from points to subfaces.\n");
      }
    
      // Initialize 'idx2faclist'.
      idx2faclist = new int[points->items + 1];
      for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
    
      // Loop all subfaces, counter the number of subfaces incident at a vertex.
      pool->traversalinit();
      shloop.sh = shellfacetraverse(pool);
      while (shloop.sh != (shellface *) NULL) {
        // Increment the number of incident subfaces for each vertex.
        j = pointmark((point) shloop.sh[3]) - in->firstnumber;
        idx2faclist[j]++;
        j = pointmark((point) shloop.sh[4]) - in->firstnumber;
        idx2faclist[j]++;
        // Skip the third corner if it is a segment.
        if (shloop.sh[5] != NULL) {
          j = pointmark((point) shloop.sh[5]) - in->firstnumber;
          idx2faclist[j]++;
        }
        shloop.sh = shellfacetraverse(pool);
      }
    
      // Calculate the total length of array 'facperverlist'.
      j = idx2faclist[0];
      idx2faclist[0] = 0;  // Array starts from 0 element.
      for (i = 0; i < points->items; i++) {
        k = idx2faclist[i + 1];
        idx2faclist[i + 1] = idx2faclist[i] + j;
        j = k;
      }
    
      // The total length is in the last unit of idx2faclist.
      facperverlist = new face[idx2faclist[i]];
    
      // Loop all subfaces again, remember the subfaces at each vertex.
      pool->traversalinit();
      shloop.sh = shellfacetraverse(pool);
      while (shloop.sh != (shellface *) NULL) {
        j = pointmark((point) shloop.sh[3]) - in->firstnumber;
        shloop.shver = 0; // save the origin.
        facperverlist[idx2faclist[j]] = shloop;
        idx2faclist[j]++;
        // Is it a subface or a subsegment?
        if (shloop.sh[5] != NULL) {
          j = pointmark((point) shloop.sh[4]) - in->firstnumber;
          shloop.shver = 2; // save the origin.
          facperverlist[idx2faclist[j]] = shloop;
          idx2faclist[j]++;
          j = pointmark((point) shloop.sh[5]) - in->firstnumber;
          shloop.shver = 4; // save the origin.
          facperverlist[idx2faclist[j]] = shloop;
          idx2faclist[j]++;
        } else {
          j = pointmark((point) shloop.sh[4]) - in->firstnumber;
          shloop.shver = 1; // save the origin.
          facperverlist[idx2faclist[j]] = shloop;
          idx2faclist[j]++;
        }
        shloop.sh = shellfacetraverse(pool);
      }
    
      // Contents in 'idx2faclist' are shifted, now shift them back.
      for (i = points->items - 1; i >= 0; i--) {
        idx2faclist[i + 1] = idx2faclist[i];
      }
      idx2faclist[0] = 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetrahedrondealloc()    Deallocate space for a tet., marking it dead.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
    {
      // Set tetrahedron's vertices to NULL. This makes it possible to detect
      //   dead tetrahedra when traversing the list of all tetrahedra.
      dyingtetrahedron[4] = (tetrahedron) NULL;
    
      //if (b->plc || b->refine) { //if (b->useshelles) {
        // Dealloc the space to subfaces/subsegments.
        if (dyingtetrahedron[8] != NULL) {
          tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
        }
        if (dyingtetrahedron[9] != NULL) {
          tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
        }
      //}
    
      tetrahedrons->dealloc((void *) dyingtetrahedron);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetrahedrontraverse()    Traverse the tetrahedra, skipping dead ones.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
    {
      tetrahedron *newtetrahedron;
    
      do {
        newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
        if (newtetrahedron == (tetrahedron *) NULL) {
          return (tetrahedron *) NULL;
        }
      } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
               ((point) newtetrahedron[7] == dummypoint));
      return newtetrahedron;
    }
    
    tetgenmesh::tetrahedron* tetgenmesh::alltetrahedrontraverse()
    {
      tetrahedron *newtetrahedron;
    
      do {
        newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
        if (newtetrahedron == (tetrahedron *) NULL) {
          return (tetrahedron *) NULL;
        }
      } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
      return newtetrahedron;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // shellfacedealloc()    Deallocate space for a shellface, marking it dead.  //
    //                       Used both for dealloc a subface and subsegment.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
    {
      // Set shellface's vertices to NULL. This makes it possible to detect dead
      //   shellfaces when traversing the list of all shellfaces.
      dyingsh[3] = (shellface) NULL;
      pool->dealloc((void *) dyingsh);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // shellfacetraverse()    Traverse the subfaces, skipping dead ones. Used    //
    //                        for both subfaces and subsegments pool traverse.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
    {
      shellface *newshellface;
    
      do {
        newshellface = (shellface *) pool->traverse();
        if (newshellface == (shellface *) NULL) {
          return (shellface *) NULL;
        }
      } while (newshellface[3] == (shellface) NULL);          // Skip dead ones.
      return newshellface;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // badfacedealloc()    Deallocate space for a badface, marking it dead.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying)
    {
      // Set badface's forg to NULL. This makes it possible to detect dead
      //   ones when traversing the list of all items.
      dying->forg = (point) NULL;
      pool->dealloc((void *) dying);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // badfacetraverse()    Traverse the pools, skipping dead ones.              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool)
    {
      badface *newsh;
    
      do {
        newsh = (badface *) pool->traverse();
        if (newsh == (badface *) NULL) {
          return (badface *) NULL;
        }
      } while (newsh->forg == (point) NULL);               // Skip dead ones.
      return newsh;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // pointdealloc()    Deallocate space for a point, marking it dead.          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::pointdealloc(point dyingpoint)
    {
      // Mark the point as dead. This  makes it possible to detect dead points
      //   when traversing the list of all points.
      setpointtype(dyingpoint, DEADVERTEX);
      points->dealloc((void *) dyingpoint);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // pointtraverse()    Traverse the points, skipping dead ones.               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    tetgenmesh::point tetgenmesh::pointtraverse()
    {
      point newpoint;
    
      do {
        newpoint = (point) points->traverse();
        if (newpoint == (point) NULL) {
          return (point) NULL;
        }
      } while (pointtype(newpoint) == DEADVERTEX);            // Skip dead ones.
      return newpoint;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // maketetrahedron()    Create a new tetrahedron.                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::maketetrahedron(triface *newtet)
    {
      newtet->tet = (tetrahedron *) tetrahedrons->alloc();
      // Initialize the four adjoining tetrahedra to be "outer space".
      newtet->tet[0] = NULL;
      newtet->tet[1] = NULL;
      newtet->tet[2] = NULL;
      newtet->tet[3] = NULL;
      // Four NULL vertices.
      newtet->tet[4] = NULL;
      newtet->tet[5] = NULL;
      newtet->tet[6] = NULL;
      newtet->tet[7] = NULL;
      // No attached segments and sbfaces yet.
      newtet->tet[8] = NULL; 
      newtet->tet[9] = NULL; 
      // Initialize the marker (for flags).
      setelemmarker(newtet->tet, 0);
      for (int i = 0; i < in->numberoftetrahedronattributes; i++) {
        setelemattribute(newtet->tet, i, 0.0);
      }
      if (b->varvolume) {
        setvolumebound(newtet->tet, -1.0);
      }
    
      // Initialize the version to be Zero.
      newtet->ver = 11;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // makeshellface()    Create a new shellface with version zero. Used for     //
    //                    both subfaces and seusegments.                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::makeshellface(memorypool *pool, face *newface)
    {
      newface->sh = (shellface *) pool->alloc();
      // No adjointing subfaces.
      newface->sh[0] = NULL;
      newface->sh[1] = NULL;
      newface->sh[2] = NULL;
      // Three NULL vertices.
      newface->sh[3] = NULL;
      newface->sh[4] = NULL;
      newface->sh[5] = NULL;
      // No adjoining subsegments.
      newface->sh[6] = NULL;
      newface->sh[7] = NULL;
      newface->sh[8] = NULL;
      // No adjoining tetrahedra.
      newface->sh[9] = NULL;
      newface->sh[10] = NULL;
      if (b->quality && checkconstraints) {
        // Initialize the maximum area bound.
        setareabound(*newface, 0.0);
      }
    
      // Clear the infection and marktest bits.
      ((int *) (newface->sh))[shmarkindex + 1] = 0;
      
      // Set the boundary marker to zero.
      setshellmark(*newface, 0);
      // Set the default face type.
      setshelltype(*newface, NSHARP);
      // Initialize the version to be Zero.
      newface->shver = 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // makepoint()    Create a new point.                                        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
    {
      int ptmark, i;
    
      *pnewpoint = (point) points->alloc();
      // Initialize the metric tensor.
      for (i = 0; i < sizeoftensor; i++) {
        (*pnewpoint)[pointmtrindex + i] = 0.0;
      }
      setpoint2tet(*pnewpoint, NULL);
      setpoint2ppt(*pnewpoint, NULL);
      if (b->plc || b->psc || b->refine) {
        // Initialize the point-to-simplex field.
        setpoint2sh(*pnewpoint, NULL);
        if (b->metric && (bgm != NULL)) {
          setpoint2bgmtet(*pnewpoint, NULL);
        }
      }
      // Initialize the point marker (starting from in->firstnumber).
      ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
      setpointmark(*pnewpoint, ptmark);
      // Initialize the point type.
      setpointtype(*pnewpoint, vtype);
      // Clear the point flags.
      puninfect(*pnewpoint);
      punmarktest(*pnewpoint);
      if (b->psc) {
        // Initialize the u,v coordinates.
        setpointgeomuv(*pnewpoint, 0, 0);
        setpointgeomuv(*pnewpoint, 1, 0);
        // Initialize the geometry tag.
        setpointgeomtag(*pnewpoint, 0);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // initializepools()    Calculate the sizes of the point, tetrahedron, and   //
    //                      subface. Initialize their memory pools.              //
    //                                                                           //
    // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
    // 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'.  They are  //
    // used to find values within each point and tetrahedron, respectively.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::initializepools()
    {
      enum memorypool::wordtype wtype;
      int pointsize, elesize, shsize;
    
      if (b->verbose) {
        printf("  Initializing memorypools.\n");
      }
    
      // Default varconstraint = 0;
      if (in->segmentconstraintlist || in->facetconstraintlist) {
        checkconstraints = 1;
      }
    
      // Each vertex has three coordinates plus a weight, hence 4 REALs.
      // The index within each point at which its metric tensor is found. 
      if (b->psc) {
        // For '-s' option (PSC), the u,v coordinates are provided. It is
        //   saved directly after the list of point attributes.
        pointmtrindex = 6 + in->numberofpointattributes;
      } else {
        pointmtrindex = 4 + in->numberofpointattributes;
      }
      // The index within each point at which its u, v coordinates are found.
      pointparamindex = pointmtrindex - 2; 
      // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
      if (b->metric) {
        // Decide the size (1, 3, or 6) of the metric tensor.
        if (bgm != (tetgenmesh *) NULL) {
          // A background mesh is allocated. It may not exist though.
          sizeoftensor = (bgm->in != (tetgenio *) NULL) ? 
            bgm->in->numberofpointmtrs : in->numberofpointmtrs;
        } else {
          // No given background mesh - Itself is a background mesh.
          sizeoftensor = in->numberofpointmtrs;
        }
        // Make sure sizeoftensor is at least 1.
        sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
      } else {
        // For '-q' option. Make sure to have space for saving a scalar value.
        sizeoftensor = b->quality ? 1 : 0;
      }
      // The index within each point at which an element pointer is found, where
      //   the index is measured in pointers. Ensure the index is aligned to a
      //   sizeof(tetrahedron)-byte address.
      point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
                     + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
      if (b->plc || b->refine || b->voroout) {
        // Increase the point size by three pointers, which are:
        //   - a pointer to a tet, read by point2tet();
        //   - a pointer to a parent point, read by point2ppt()).
        //   - a pointer to a subface or segment, read by point2sh();
        if (b->metric && (bgm != (tetgenmesh *) NULL)) {
          // Increase one pointer to into the background mesh, point2bgmtet().
          pointsize = (point2simindex + 4) * sizeof(tetrahedron);
        } else {
          pointsize = (point2simindex + 3) * sizeof(tetrahedron);
        }
        // The index within each point at which a pbc point is found.
        point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1)
                         / sizeof(tetrahedron);
        if (checkpbcs) {
          // Increase the size by one pointer to a corresponding pbc point,
          //   read by point2pbcpt().
          pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron);
        }
      } else {
        // Increase the point size by two pointer, which are:
        //   - a pointer to a tet, read by point2tet();
        //   - a pointer to a parent point, read by point2ppt()). -- Used by btree.
        pointsize = (point2simindex + 2) * sizeof(tetrahedron);
      }
      // The index within each point at which the boundary marker is found,
      //   Ensure the point marker is aligned to a sizeof(int)-byte address.
      pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
      // Now point size is the ints (inidcated by pointmarkindex) plus:
      //   - an integer for boundary marker;
      //   - an integer for vertex type;
      //   - an integer for geometry tag (optional, -s option).
      //pointsize = (pointmarkindex + 2)*sizeof(int); // Wrong for 64 bit system.
      pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
    
      // Decide the wordtype used in vertex pool.
      wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? 
        memorypool::FLOATINGPOINT : memorypool::POINTER;
      // Initialize the pool of vertices.
      points = new memorypool(pointsize, b->vertexperblock, wtype, 0);
    
      if (b->verbose) {
        printf("  Size of a point: %d bytes.\n", points->itembytes);
      }
    
      // Initialize the infinite vertex.
      dummypoint = (point) new char[pointsize];
      setpointmark(dummypoint, -1);
    
      // The number of bytes occupied by a tetrahedron is varying by the user-
      //   specified options. The contents of the first 12 pointers are listed
      //   in the following table:
      //     [0]  |__ neighbor at f0 __|
      //     [1]  |__ neighbor at f1 __|
      //     [2]  |__ neighbor at f2 __|
      //     [3]  |__ neighbor at f3 __|
      //     [4]  |_____ vertex p0 ____|
      //     [5]  |_____ vertex p1 ____|
      //     [6]  |_____ vertex p2 ____|
      //     [7]  |_____ vertex p3 ____|
      //     [8]  |__ segments array __| (used by -p)
      //     [9]  |__ subfaces array __| (used by -p)
      //    [10]  |_____ reserved _____|
      //    [11]  |___ elem marker ____| (used as an integer)
    
      elesize = 12 * sizeof(tetrahedron); 
    
      // The index to find the element markers. An integer containing varies
      //   flags and element counter. 
      assert(sizeof(int) <= sizeof(tetrahedron));
      assert((sizeof(tetrahedron) % sizeof(int)) == 0);
      elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
    
      // The index within each element at which its attributes are found, where
      //   the index is measured in REALs. 
      elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
      // The index within each element at which the maximum voulme bound is
      //   found, where the index is measured in REALs.  Note that if the
      //   `b->regionattrib' flag is set, an additional attribute will be added.
      volumeboundindex = elemattribindex + in->numberoftetrahedronattributes
                       + (b->regionattrib > 0);
      // If element attributes or an constraint are needed, increase the number
      //   of bytes occupied by an element.
      if (b->varvolume) {
        elesize = (volumeboundindex + 1) * sizeof(REAL);
      } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) {
        elesize = volumeboundindex * sizeof(REAL);
      }
    
    
      // Having determined the memory size of an element, initialize the pool.
      tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, 
                                    memorypool::POINTER, 16);
    
      if (b->verbose) {
        printf("  Size of a tetrahedron: %d (%d) bytes.\n", elesize,
               tetrahedrons->itembytes);
      }
    
      if (b->plc || b->refine) { // if (b->useshelles) {
        // The number of bytes occupied by a subface.  The list of pointers
        //   stored in a subface are: three to other subfaces, three to corners,
        //   three to subsegments, two to tetrahedra.
        shsize = 11 * sizeof(shellface);
        // The index within each subface at which the maximum area bound is
        //   found, where the index is measured in REALs.
        areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
        // If -q switch is in use, increase the number of bytes occupied by
        //   a subface for saving maximum area bound.
        if (b->quality && checkconstraints) {
          shsize = (areaboundindex + 1) * sizeof(REAL);
        } else {
          shsize = areaboundindex * sizeof(REAL);
        }
        // The index within subface at which the facet marker is found. Ensure
        //   the marker is aligned to a sizeof(int)-byte address.
        shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
        // Increase the number of bytes by two or three integers, one for facet
        //   marker, one for shellface type, and optionally one for pbc group.
        shsize = (shmarkindex + 2 + checkpbcs) * sizeof(shellface);
    
        // Initialize the pool of subfaces. Each subface record is eight-byte
        //   aligned so it has room to store an edge version (from 0 to 5) in
        //   the least three bits.
        subfaces = new memorypool(shsize, b->shellfaceperblock, 
                                  memorypool::POINTER, 8);
    
        if (b->verbose) {
          printf("  Size of a shellface: %d (%d) bytes.\n", shsize,
                 subfaces->itembytes);
        }
    
        // Initialize the pool of subsegments. The subsegment's record is same
        //   with subface.
        subsegs = new memorypool(shsize, b->shellfaceperblock, 
                                 memorypool::POINTER, 8);
    
        // Initialize the pool for tet-subseg connections.
        tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock, 
                                     memorypool::POINTER, 0);
        // Initialize the pool for tet-subface connections.
        tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock, 
                                     memorypool::POINTER, 0);
    
        // Initialize arraypools for segment & facet recovery.
        subsegstack = new arraypool(sizeof(face), 10);
        subfacstack = new arraypool(sizeof(face), 10);
        subvertstack = new arraypool(sizeof(point), 8);
    
        suppsteinerptlist = new arraypool(sizeof(point), 8);
    
        // Initialize arraypools for surface Bowyer-Watson algorithm.
        caveshlist = new arraypool(sizeof(face), 8);
        caveshbdlist = new arraypool(sizeof(face), 8);
        cavesegshlist = new arraypool(sizeof(face), 4);
    
        cavetetshlist = new arraypool(sizeof(face), 8);
        cavetetseglist = new arraypool(sizeof(face), 8);
    
        caveencshlist = new arraypool(sizeof(face), 8);
        caveencseglist = new arraypool(sizeof(face), 8);
      }
    
      // Initialize the pool for flips.
      flippool = new memorypool(sizeof(badface), 1024, memorypool::POINTER, 0);
      unflipqueue = new arraypool(sizeof(badface), 10);
    
      // Initialize the arraypools for Bowyer-Watson algorithm.
      cavetetlist = new arraypool(sizeof(triface), 10);
      cavebdrylist = new arraypool(sizeof(triface), 10);
      caveoldtetlist = new arraypool(sizeof(triface), 10);
      cavetetvertlist = new arraypool(sizeof(point), 10);
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// mempool_cxx //////////////////////////////////////////////////////////////
    
    //// geom_cxx /////////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    // PI is the ratio of a circle's circumference to its diameter.
    
    REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tri_edge_test()    Triangle-edge intersection test.                       //
    //                                                                           //
    // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
    // Q) in 3D, and tests if they intersect each other.                         //
    //                                                                           //
    // If the point 'R' is not NULL, it lies strictly above the plane defined by //
    // A, B, C. It is used in test when T and E are coplanar.                    //
    //                                                                           //
    // If T and E intersect each other, they may intersect in different ways. If //
    // 'level' > 0, their intersection type will be reported 'types' and 'pos'.  //
    //                                                                           //
    // The retrun value indicates one of the following cases:                    //
    //   - 0, T and E are disjoint.                                              //
    //   - 1, T and E intersect each other.                                      //
    //   - 2, T and E are not coplanar. They intersect at a single point.        //
    //   - 4, T and E are coplanar. They intersect at a single point or a line   //
    //        segment (if types[1] != DISJOINT).                                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q, 
                                point R, int level, int *types, int *pos)
    {
      point U[3], V[3];  // The permuted vectors of points.
      int pu[3], pv[3];  // The original positions of points.
      REAL abovept[3];
      REAL sA, sB, sC;
      REAL s1, s2, s3, s4;
      int z1;
    
      if (R == NULL) {
        // Calculate a lift point.
        if (1) {
          REAL n[3], len;
          // Calculate a lift point, saved in dummypoint.
          facenormal(A, B, C, n, 1, NULL);
          len = sqrt(DOT(n, n));
          if (len != 0) {
            n[0] /= len;
            n[1] /= len;
            n[2] /= len;
            len = DIST(A, B);
            len += DIST(B, C);
            len += DIST(C, A);
            len /= 3.0;
            R = abovept; //dummypoint;
            R[0] = A[0] + len * n[0];
            R[1] = A[1] + len * n[1];
            R[2] = A[2] + len * n[2];
          } else {
            // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
            //   to a line.  We need a line-line intersection test.
            //assert(0);
            // !!! A non-save return value.!!!
            return 0;  // DISJOINT
          }
        }
      }
    
      // Test A's, B's, and C's orientations wrt plane PQR. 
      sA = orient3d(P, Q, R, A);
      sB = orient3d(P, Q, R, B);
      sC = orient3d(P, Q, R, C);
    
      triedgcopcount++;
    
      if (sA < 0) {
        if (sB < 0) {
          if (sC < 0) { // (---).
            return 0; 
          } else {
            if (sC > 0) { // (--+).
              // All points are in the right positions.
              SETVECTOR3(U, A, B, C);  // I3
              SETVECTOR3(V, P, Q, R);  // I2
              SETVECTOR3(pu, 0, 1, 2);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 0;
            } else { // (--0).
              SETVECTOR3(U, A, B, C);  // I3
              SETVECTOR3(V, P, Q, R);  // I2
              SETVECTOR3(pu, 0, 1, 2);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 1;
            }
          }
        } else { 
          if (sB > 0) {
            if (sC < 0) { // (-+-).
              SETVECTOR3(U, C, A, B);  // PT = ST
              SETVECTOR3(V, P, Q, R);  // I2
              SETVECTOR3(pu, 2, 0, 1);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 0;
            } else {
              if (sC > 0) { // (-++).
                SETVECTOR3(U, B, C, A);  // PT = ST x ST
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 1, 2, 0);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 0;
              } else { // (-+0).
                SETVECTOR3(U, C, A, B);  // PT = ST
                SETVECTOR3(V, P, Q, R);  // I2
                SETVECTOR3(pu, 2, 0, 1);
                SETVECTOR3(pv, 0, 1, 2);
                z1 = 2;
              }
            }
          } else {
            if (sC < 0) { // (-0-).
              SETVECTOR3(U, C, A, B);  // PT = ST
              SETVECTOR3(V, P, Q, R);  // I2
              SETVECTOR3(pu, 2, 0, 1);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 1;
            } else {
              if (sC > 0) { // (-0+).
                SETVECTOR3(U, B, C, A);  // PT = ST x ST
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 1, 2, 0);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 2;
              } else { // (-00).
                SETVECTOR3(U, B, C, A);  // PT = ST x ST
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 1, 2, 0);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 3; 
              }
            }
          }
        }
      } else {
        if (sA > 0) {
          if (sB < 0) {
            if (sC < 0) { // (+--).
              SETVECTOR3(U, B, C, A);  // PT = ST x ST
              SETVECTOR3(V, P, Q, R);  // I2
              SETVECTOR3(pu, 1, 2, 0);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 0;
            } else {
              if (sC > 0) { // (+-+).
                SETVECTOR3(U, C, A, B);  // PT = ST
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 2, 0, 1);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 0;
              } else { // (+-0).
                SETVECTOR3(U, C, A, B);  // PT = ST
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 2, 0, 1);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 2;
              }
            }
          } else { 
            if (sB > 0) {
              if (sC < 0) { // (++-).
                SETVECTOR3(U, A, B, C);  // I3
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 0, 1, 2);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 0;
              } else {
                if (sC > 0) { // (+++).
                  return 0; 
                } else { // (++0).
                  SETVECTOR3(U, A, B, C);  // I3
                  SETVECTOR3(V, Q, P, R);  // PL = SL
                  SETVECTOR3(pu, 0, 1, 2);
                  SETVECTOR3(pv, 1, 0, 2);
                  z1 = 1; 
                }
              }
            } else { // (+0#)
              if (sC < 0) { // (+0-).
                SETVECTOR3(U, B, C, A);  // PT = ST x ST
                SETVECTOR3(V, P, Q, R);  // I2
                SETVECTOR3(pu, 1, 2, 0);
                SETVECTOR3(pv, 0, 1, 2);
                z1 = 2;
              } else {
                if (sC > 0) { // (+0+).
                  SETVECTOR3(U, C, A, B);  // PT = ST
                  SETVECTOR3(V, Q, P, R);  // PL = SL
                  SETVECTOR3(pu, 2, 0, 1);
                  SETVECTOR3(pv, 1, 0, 2);
                  z1 = 1;
                } else { // (+00).
                  SETVECTOR3(U, B, C, A);  // PT = ST x ST
                  SETVECTOR3(V, P, Q, R);  // I2
                  SETVECTOR3(pu, 1, 2, 0);
                  SETVECTOR3(pv, 0, 1, 2);
                  z1 = 3; 
                }
              }
            }
          }
        } else { 
          if (sB < 0) {
            if (sC < 0) { // (0--).
              SETVECTOR3(U, B, C, A);  // PT = ST x ST
              SETVECTOR3(V, P, Q, R);  // I2
              SETVECTOR3(pu, 1, 2, 0);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 1;
            } else {
              if (sC > 0) { // (0-+).
                SETVECTOR3(U, A, B, C);  // I3
                SETVECTOR3(V, P, Q, R);  // I2
                SETVECTOR3(pu, 0, 1, 2);
                SETVECTOR3(pv, 0, 1, 2);
                z1 = 2;
              } else { // (0-0).
                SETVECTOR3(U, C, A, B);  // PT = ST
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 2, 0, 1);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 3; 
              }
            }
          } else { 
            if (sB > 0) {
              if (sC < 0) { // (0+-).
                SETVECTOR3(U, A, B, C);  // I3
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 0, 1, 2);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 2;
              } else {
                if (sC > 0) { // (0++).
                  SETVECTOR3(U, B, C, A);  // PT = ST x ST
                  SETVECTOR3(V, Q, P, R);  // PL = SL
                  SETVECTOR3(pu, 1, 2, 0);
                  SETVECTOR3(pv, 1, 0, 2);
                  z1 = 1;
                } else { // (0+0).
                  SETVECTOR3(U, C, A, B);  // PT = ST
                  SETVECTOR3(V, P, Q, R);  // I2
                  SETVECTOR3(pu, 2, 0, 1);
                  SETVECTOR3(pv, 0, 1, 2);
                  z1 = 3; 
                }
              }
            } else { // (00#)
              if (sC < 0) { // (00-).
                SETVECTOR3(U, A, B, C);  // I3
                SETVECTOR3(V, Q, P, R);  // PL = SL
                SETVECTOR3(pu, 0, 1, 2);
                SETVECTOR3(pv, 1, 0, 2);
                z1 = 3; 
              } else {
                if (sC > 0) { // (00+).
                  SETVECTOR3(U, A, B, C);  // I3
                  SETVECTOR3(V, P, Q, R);  // I2
                  SETVECTOR3(pu, 0, 1, 2);
                  SETVECTOR3(pv, 0, 1, 2);
                  z1 = 3; 
                } else { // (000)
                  // Not possible unless ABC is degenerate.
                  // Avoiding compiler warnings.
                  SETVECTOR3(U, A, B, C);  // I3
                  SETVECTOR3(V, P, Q, R);  // I2
                  SETVECTOR3(pu, 0, 1, 2);
                  SETVECTOR3(pv, 0, 1, 2);
                  z1 = 4;
                }
              }
            }
          }
        }
      }
    
      s1 = orient3d(U[0], U[2], R, V[1]);  // A, C, R, Q
      s2 = orient3d(U[1], U[2], R, V[0]);  // B, C, R, P
    
      if (s1 > 0) {
        return 0;
      }
      if (s2 < 0) {
        return 0;
      }
    
      if (level == 0) {
        return 1;  // They are intersected.
      }
    
      assert(z1 != 4); // SELF_CHECK
    
      if (z1 == 1) {
        if (s1 == 0) {  // (0###)
          // C = Q.
          types[0] = (int) SHAREVERT;
          pos[0] = pu[2]; // C
          pos[1] = pv[1]; // Q
          types[1] = (int) DISJOINT;
        } else {
          if (s2 == 0) { // (#0##)
            // C = P.
            types[0] = (int) SHAREVERT;
            pos[0] = pu[2]; // C
            pos[1] = pv[0]; // P
            types[1] = (int) DISJOINT;
          } else { // (-+##)
            // C in [P, Q].
            types[0] = (int) ACROSSVERT;
            pos[0] = pu[2]; // C
            pos[1] = pv[0]; // [P, Q]
            types[1] = (int) DISJOINT;
          }
        }
        return 4;
      }
    
      s3 = orient3d(U[0], U[2], R, V[0]);  // A, C, R, P
      s4 = orient3d(U[1], U[2], R, V[1]);  // B, C, R, Q
          
      if (z1 == 0) {  // (tritri-03)
        if (s1 < 0) {
          if (s3 > 0) {
            assert(s2 > 0); // SELF_CHECK
            if (s4 > 0) {
              // [P, Q] overlaps [k, l] (-+++).
              types[0] = (int) ACROSSEDGE;
              pos[0] = pu[2]; // [C, A]
              pos[1] = pv[0]; // [P, Q]
              types[1] = (int) TOUCHFACE;
              pos[2] = 3;     // [A, B, C]
              pos[3] = pv[1]; // Q
            } else {
              if (s4 == 0) {
                // Q = l, [P, Q] contains [k, l] (-++0).
                types[0] = (int) ACROSSEDGE;
                pos[0] = pu[2]; // [C, A]
                pos[1] = pv[0]; // [P, Q]
                types[1] = (int) TOUCHEDGE;
                pos[2] = pu[1]; // [B, C]
                pos[3] = pv[1]; // Q
              } else { // s4 < 0
                // [P, Q] contains [k, l] (-++-).
                types[0] = (int) ACROSSEDGE;
                pos[0] = pu[2]; // [C, A]
                pos[1] = pv[0]; // [P, Q]
                types[1] = (int) ACROSSEDGE;
                pos[2] = pu[1]; // [B, C]
                pos[3] = pv[0]; // [P, Q]
              }
            }
          } else {
            if (s3 == 0) {
              assert(s2 > 0); // SELF_CHECK
              if (s4 > 0) {
                // P = k, [P, Q] in [k, l] (-+0+).
                types[0] = (int) TOUCHEDGE;
                pos[0] = pu[2]; // [C, A]
                pos[1] = pv[0]; // P
                types[1] = (int) TOUCHFACE;
                pos[2] = 3;     // [A, B, C]
                pos[3] = pv[1]; // Q
              } else {
                if (s4 == 0) {
                  // [P, Q] = [k, l] (-+00).
                  types[0] = (int) TOUCHEDGE;
                  pos[0] = pu[2]; // [C, A]
                  pos[1] = pv[0]; // P
                  types[1] = (int) TOUCHEDGE;
                  pos[2] = pu[1]; // [B, C]
                  pos[3] = pv[1]; // Q
                } else {
                  // P = k, [P, Q] contains [k, l] (-+0-).
                  types[0] = (int) TOUCHEDGE;
                  pos[0] = pu[2]; // [C, A]
                  pos[1] = pv[0]; // P
                  types[1] = (int) ACROSSEDGE;
                  pos[2] = pu[1]; // [B, C]
                  pos[3] = pv[0]; // [P, Q]
                }
              }
            } else { // s3 < 0
              if (s2 > 0) {
                if (s4 > 0) {
                  // [P, Q] in [k, l] (-+-+).
                  types[0] = (int) TOUCHFACE;
                  pos[0] = 3;     // [A, B, C]
                  pos[1] = pv[0]; // P
                  types[1] = (int) TOUCHFACE;
                  pos[2] = 3;     // [A, B, C]
                  pos[3] = pv[1]; // Q
                } else {
                  if (s4 == 0) {
                    // Q = l, [P, Q] in [k, l] (-+-0).
                    types[0] = (int) TOUCHFACE;
                    pos[0] = 3;     // [A, B, C]
                    pos[1] = pv[0]; // P
                    types[1] = (int) TOUCHEDGE;
                    pos[2] = pu[1]; // [B, C]
                    pos[3] = pv[1]; // Q
                  } else { // s4 < 0
                    // [P, Q] overlaps [k, l] (-+--).
                    types[0] = (int) TOUCHFACE;
                    pos[0] = 3;     // [A, B, C]
                    pos[1] = pv[0]; // P
                    types[1] = (int) ACROSSEDGE;
                    pos[2] = pu[1]; // [B, C]
                    pos[3] = pv[0]; // [P, Q]
                  }
                }
              } else { // s2 == 0
                // P = l (#0##).
                types[0] = (int) TOUCHEDGE;
                pos[0] = pu[1]; // [B, C]
                pos[1] = pv[0]; // P
                types[1] = (int) DISJOINT;
              }
            }
          }
        } else { // s1 == 0
          // Q = k (0####)
          types[0] = (int) TOUCHEDGE;
          pos[0] = pu[2]; // [C, A]
          pos[1] = pv[1]; // Q
          types[1] = (int) DISJOINT;
        }
      } else if (z1 == 2) {  // (tritri-23)
        if (s1 < 0) {
          if (s3 > 0) {
            assert(s2 > 0); // SELF_CHECK
            if (s4 > 0) {
              // [P, Q] overlaps [A, l] (-+++).
              types[0] = (int) ACROSSVERT;
              pos[0] = pu[0]; // A
              pos[1] = pv[0]; // [P, Q]
              types[1] = (int) TOUCHFACE;
              pos[2] = 3;     // [A, B, C]
              pos[3] = pv[1]; // Q
            } else {
              if (s4 == 0) {
                // Q = l, [P, Q] contains [A, l] (-++0).
                types[0] = (int) ACROSSVERT;
                pos[0] = pu[0]; // A
                pos[1] = pv[0]; // [P, Q]
                types[1] = (int) TOUCHEDGE;
                pos[2] = pu[1]; // [B, C]
                pos[3] = pv[1]; // Q
              } else { // s4 < 0
                // [P, Q] contains [A, l] (-++-).
                types[0] = (int) ACROSSVERT;
                pos[0] = pu[0]; // A
                pos[1] = pv[0]; // [P, Q]
                types[1] = (int) ACROSSEDGE;
                pos[2] = pu[1]; // [B, C]
                pos[3] = pv[0]; // [P, Q]
              }
            }
          } else {
            if (s3 == 0) {
              assert(s2 > 0); // SELF_CHECK
              if (s4 > 0) {
                // P = A, [P, Q] in [A, l] (-+0+).
                types[0] = (int) SHAREVERT;
                pos[0] = pu[0]; // A
                pos[1] = pv[0]; // P
                types[1] = (int) TOUCHFACE;
                pos[2] = 3;     // [A, B, C]
                pos[3] = pv[1]; // Q
              } else {
                if (s4 == 0) {
                  // [P, Q] = [A, l] (-+00).
                  types[0] = (int) SHAREVERT;
                  pos[0] = pu[0]; // A
                  pos[1] = pv[0]; // P
                  types[1] = (int) TOUCHEDGE;
                  pos[2] = pu[1]; // [B, C]
                  pos[3] = pv[1]; // Q
                } else { // s4 < 0
                  // Q = l, [P, Q] in [A, l] (-+0-).
                  types[0] = (int) SHAREVERT;
                  pos[0] = pu[0]; // A
                  pos[1] = pv[0]; // P
                  types[1] = (int) ACROSSEDGE;
                  pos[2] = pu[1]; // [B, C]
                  pos[3] = pv[0]; // [P, Q]
                }
              }
            } else { // s3 < 0
              if (s2 > 0) {
                if (s4 > 0) {
                  // [P, Q] in [A, l] (-+-+).
                  types[0] = (int) TOUCHFACE;
                  pos[0] = 3;     // [A, B, C]
                  pos[1] = pv[0]; // P
                  types[0] = (int) TOUCHFACE;
                  pos[0] = 3;     // [A, B, C]
                  pos[1] = pv[1]; // Q
                } else {
                  if (s4 == 0) {
                    // Q = l, [P, Q] in [A, l] (-+-0).
                    types[0] = (int) TOUCHFACE;
                    pos[0] = 3;     // [A, B, C]
                    pos[1] = pv[0]; // P
                    types[0] = (int) TOUCHEDGE;
                    pos[0] = pu[1]; // [B, C]
                    pos[1] = pv[1]; // Q
                  } else { // s4 < 0
                    // [P, Q] overlaps [A, l] (-+--).
                    types[0] = (int) TOUCHFACE;
                    pos[0] = 3;     // [A, B, C]
                    pos[1] = pv[0]; // P
                    types[0] = (int) ACROSSEDGE;
                    pos[0] = pu[1]; // [B, C]
                    pos[1] = pv[0]; // [P, Q]
                  }
                }
              } else { // s2 == 0
                // P = l (#0##).
                types[0] = (int) TOUCHEDGE;
                pos[0] = pu[1]; // [B, C]
                pos[1] = pv[0]; // P
                types[1] = (int) DISJOINT;
              }
            }
          }
        } else { // s1 == 0
          // Q = A (0###).
          types[0] = (int) SHAREVERT;
          pos[0] = pu[0]; // A
          pos[1] = pv[1]; // Q
          types[1] = (int) DISJOINT;
        }
      } else if (z1 == 3) {  // (tritri-33)
        if (s1 < 0) {
          if (s3 > 0) {
            assert(s2 > 0); // SELF_CHECK
            if (s4 > 0) {
              // [P, Q] overlaps [A, B] (-+++).
              types[0] = (int) ACROSSVERT;
              pos[0] = pu[0]; // A
              pos[1] = pv[0]; // [P, Q]
              types[1] = (int) TOUCHEDGE;
              pos[2] = pu[0]; // [A, B]
              pos[3] = pv[1]; // Q
            } else {
              if (s4 == 0) {
                // Q = B, [P, Q] contains [A, B] (-++0).
                types[0] = (int) ACROSSVERT;
                pos[0] = pu[0]; // A
                pos[1] = pv[0]; // [P, Q]
                types[1] = (int) SHAREVERT;
                pos[2] = pu[1]; // B
                pos[3] = pv[1]; // Q
              } else { // s4 < 0
                // [P, Q] contains [A, B] (-++-).
                types[0] = (int) ACROSSVERT;
                pos[0] = pu[0]; // A
                pos[1] = pv[0]; // [P, Q]
                types[1] = (int) ACROSSVERT;
                pos[2] = pu[1]; // B
                pos[3] = pv[0]; // [P, Q]
              }
            }
          } else {
            if (s3 == 0) {
              assert(s2 > 0); // SELF_CHECK
              if (s4 > 0) {
                // P = A, [P, Q] in [A, B] (-+0+).
                types[0] = (int) SHAREVERT;
                pos[0] = pu[0]; // A
                pos[1] = pv[0]; // P
                types[1] = (int) TOUCHEDGE;
                pos[2] = pu[0]; // [A, B]
                pos[3] = pv[1]; // Q
              } else {
                if (s4 == 0) {
                  // [P, Q] = [A, B] (-+00).
                  types[0] = (int) SHAREEDGE;
                  pos[0] = pu[0]; // [A, B]
                  pos[1] = pv[0]; // [P, Q]
                  types[1] = (int) DISJOINT;
                } else { // s4 < 0
                  // P= A, [P, Q] in [A, B] (-+0-).
                  types[0] = (int) SHAREVERT;
                  pos[0] = pu[0]; // A
                  pos[1] = pv[0]; // P
                  types[1] = (int) ACROSSVERT;
                  pos[2] = pu[1]; // B
                  pos[3] = pv[0]; // [P, Q]
                }
              }
            } else { // s3 < 0
              if (s2 > 0) {
                if (s4 > 0) {
                  // [P, Q] in [A, B] (-+-+).
                  types[0] = (int) TOUCHEDGE;
                  pos[0] = pu[0]; // [A, B]
                  pos[1] = pv[0]; // P
                  types[1] = (int) TOUCHEDGE;
                  pos[2] = pu[0]; // [A, B]
                  pos[3] = pv[1]; // Q
                } else {
                  if (s4 == 0) {
                    // Q = B, [P, Q] in [A, B] (-+-0).
                    types[0] = (int) TOUCHEDGE;
                    pos[0] = pu[0]; // [A, B]
                    pos[1] = pv[0]; // P
                    types[1] = (int) SHAREVERT;
                    pos[2] = pu[1]; // B
                    pos[3] = pv[1]; // Q
                  } else { // s4 < 0
                    // [P, Q] overlaps [A, B] (-+--).
                    types[0] = (int) TOUCHEDGE;
                    pos[0] = pu[0]; // [A, B]
                    pos[1] = pv[0]; // P
                    types[1] = (int) ACROSSVERT;
                    pos[2] = pu[1]; // B
                    pos[3] = pv[0]; // [P, Q]
                  }
                }
              } else { // s2 == 0
                // P = B (#0##).
                types[0] = (int) SHAREVERT;
                pos[0] = pu[1]; // B
                pos[1] = pv[0]; // P
                types[1] = (int) DISJOINT;
              }
            }
          }
        } else { // s1 == 0
          // Q = A (0###).
          types[0] = (int) SHAREVERT;
          pos[0] = pu[0]; // A
          pos[1] = pv[1]; // Q
          types[1] = (int) DISJOINT;
        }
      }
    
      return 4;
    }
    
    int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
                                  REAL sP,REAL sQ,int level,int *types,int *pos)
    {
      point U[3], V[3]; //, Ptmp;
      int pu[3], pv[3]; //, itmp;
      REAL s1, s2, s3;
      int z1;
    
      triedgcount++;
    
      if (sP < 0) {
        if (sQ < 0) { // (--) disjoint
          return 0;
        } else {
          if (sQ > 0) { // (-+)
            SETVECTOR3(U, A, B, C);
            SETVECTOR3(V, P, Q, R);
            SETVECTOR3(pu, 0, 1, 2);
            SETVECTOR3(pv, 0, 1, 2);
            z1 = 0;
          } else { // (-0)
            SETVECTOR3(U, A, B, C);
            SETVECTOR3(V, P, Q, R);
            SETVECTOR3(pu, 0, 1, 2);
            SETVECTOR3(pv, 0, 1, 2);
            z1 = 1;
          }
        }
      } else {
        if (sP > 0) { // (+-)
          if (sQ < 0) {
            SETVECTOR3(U, A, B, C);
            SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
            SETVECTOR3(pu, 0, 1, 2);
            SETVECTOR3(pv, 1, 0, 2);
            z1 = 0;
          } else {
            if (sQ > 0) { // (++) disjoint
              return 0;
            } else { // (+0)
              SETVECTOR3(U, B, A, C); // A and B are flipped.
              SETVECTOR3(V, P, Q, R);
              SETVECTOR3(pu, 1, 0, 2);
              SETVECTOR3(pv, 0, 1, 2);
              z1 = 1;
            }
          }
        } else { // sP == 0
          if (sQ < 0) { // (0-)
            SETVECTOR3(U, A, B, C);
            SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
            SETVECTOR3(pu, 0, 1, 2);
            SETVECTOR3(pv, 1, 0, 2);
            z1 = 1;
          } else {
            if (sQ > 0) { // (0+)
              SETVECTOR3(U, B, A, C);  // A and B are flipped.
              SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
              SETVECTOR3(pu, 1, 0, 2);
              SETVECTOR3(pv, 1, 0, 2);
              z1 = 1;
            } else { // (00)
              // A, B, C, P, and Q are coplanar.
              z1 = 2;
            }
          }
        }
      }
    
      if (z1 == 2) {
        // The triangle and the edge are coplanar.
        return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
      }
    
      s1 = orient3d(U[0], U[1], V[0], V[1]);
      if (s1 < 0) {
        return 0;
      }
    
      s2 = orient3d(U[1], U[2], V[0], V[1]);
      if (s2 < 0) {
        return 0;
      }
    
      s3 = orient3d(U[2], U[0], V[0], V[1]);
      if (s3 < 0) {
        return 0;
      }
    
      if (level == 0) {
        return 1;  // The are intersected.
      }
    
      types[1] = (int) DISJOINT; // No second intersection point.
    
      if (z1 == 0) {
        if (s1 > 0) {
          if (s2 > 0) {
            if (s3 > 0) { // (+++)
              // [P, Q] passes interior of [A, B, C].
              types[0] = (int) ACROSSFACE;
              pos[0] = 3;  // interior of [A, B, C]
              pos[1] = 0;  // [P, Q]
            } else { // s3 == 0 (++0)
              // [P, Q] intersects [C, A].
              types[0] = (int) ACROSSEDGE;
              pos[0] = pu[2];  // [C, A]
              pos[1] = 0;  // [P, Q]
            }
          } else { // s2 == 0
            if (s3 > 0) { // (+0+)
              // [P, Q] intersects [B, C].
              types[0] = (int) ACROSSEDGE;
              pos[0] = pu[1];  // [B, C]
              pos[1] = 0;  // [P, Q]
            } else { // s3 == 0 (+00)
              // [P, Q] passes C.
              types[0] = (int) ACROSSVERT;
              pos[0] = pu[2];  // C
              pos[1] = 0;  // [P, Q]
            }
          }
        } else { // s1 == 0
          if (s2 > 0) {
            if (s3 > 0) { // (0++)
              // [P, Q] intersects [A, B].
              types[0] = (int) ACROSSEDGE;
              pos[0] = pu[0];  // [A, B]
              pos[1] = 0;  // [P, Q]
            } else { // s3 == 0 (0+0)
              // [P, Q] passes A.
              types[0] = (int) ACROSSVERT;
              pos[0] = pu[0];  // A
              pos[1] = 0;  // [P, Q]
            }
          } else { // s2 == 0
            if (s3 > 0) { // (00+)
              // [P, Q] passes B.
              types[0] = (int) ACROSSVERT;
              pos[0] = pu[1];  // B
              pos[1] = 0;  // [P, Q]
            } else { // s3 == 0 (000)
              // Impossible.
              assert(0);
            }
          }
        }
      } else { // z1 == 1
        if (s1 > 0) {
          if (s2 > 0) {
            if (s3 > 0) { // (+++)
              // Q lies in [A, B, C].
              types[0] = (int) TOUCHFACE;
              pos[0] = 0; // [A, B, C]
              pos[1] = pv[1]; // Q
            } else { // s3 == 0 (++0)
              // Q lies on [C, A].
              types[0] = (int) TOUCHEDGE;
              pos[0] = pu[2]; // [C, A]
              pos[1] = pv[1]; // Q
            }
          } else { // s2 == 0
            if (s3 > 0) { // (+0+)
              // Q lies on [B, C].
              types[0] = (int) TOUCHEDGE;
              pos[0] = pu[1]; // [B, C]
              pos[1] = pv[1]; // Q
            } else { // s3 == 0 (+00)
              // Q = C.
              types[0] = (int) SHAREVERT;
              pos[0] = pu[2]; // C
              pos[1] = pv[1]; // Q
            }
          }
        } else { // s1 == 0
          if (s2 > 0) {
            if (s3 > 0) { // (0++)
              // Q lies on [A, B].
              types[0] = (int) TOUCHEDGE;
              pos[0] = pu[0]; // [A, B]
              pos[1] = pv[1]; // Q
            } else { // s3 == 0 (0+0)
              // Q = A.
              types[0] = (int) SHAREVERT;
              pos[0] = pu[0]; // A
              pos[1] = pv[1]; // Q
            }
          } else { // s2 == 0
            if (s3 > 0) { // (00+)
              // Q = B.
              types[0] = (int) SHAREVERT;
              pos[0] = pu[1]; // B
              pos[1] = pv[1]; // Q
            } else { // s3 == 0 (000)
              // Impossible.
              assert(0);
            }
          }
        }
      }
    
      // T and E intersect in a single point.
      return 2;
    }
    
    int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q, 
                                  point R, int level, int *types, int *pos)
    {
      REAL sP, sQ;
    
      // Test the locations of P and Q with respect to ABC.
      sP = orient3d(A, B, C, P);
      sQ = orient3d(A, B, C, Q);
    
      return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tri_tri_inter()    Test whether two triangle (abc) and (opq) are          //
    //                    intersecting or not.                                   //
    //                                                                           //
    // Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
    // the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT.         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C,  REAL* P, 
                                        REAL* Q, REAL s_p, REAL s_q)
    {
      int types[2], pos[4];
      int ni;  // =0, 2, 4
    
      ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
    
      if (ni > 0) {
        if (ni == 2) {
          // Get the intersection type.
          if (types[0] == (int) SHAREVERT) {
            return (int) SHAREVERT;
          } else {
            return (int) INTERSECT;
          }
        } else if (ni == 4) { 
          // There may be two intersections.
          if (types[0] == (int) SHAREVERT) {
            if (types[1] == (int) DISJOINT) {
              return (int) SHAREVERT;
            } else {
              assert(types[1] != (int) SHAREVERT);
              return (int) INTERSECT;
            }
          } else {
            if (types[0] == (int) SHAREEDGE) {
              return (int) SHAREEDGE;
            } else {
              return (int) INTERSECT;
            }
          }
        } else {
          assert(0);
        }
      }
    
      return (int) DISJOINT;
    }
    
    int tetgenmesh::tri_tri_inter(REAL* A,REAL* B,REAL* C,REAL* O,REAL* P,REAL* Q)
    {
      REAL s_o, s_p, s_q;
      REAL s_a, s_b, s_c;
    
      s_o = orient3d(A, B, C, O);
      s_p = orient3d(A, B, C, P);
      s_q = orient3d(A, B, C, Q);
      if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
        // o, p, q are all in the same halfspace of ABC.
        return 0; // DISJOINT;
      }
    
      s_a = orient3d(O, P, Q, A);
      s_b = orient3d(O, P, Q, B);
      s_c = orient3d(O, P, Q, C);
      if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
        // a, b, c are all in the same halfspace of OPQ.
        return 0; // DISJOINT;
      }
    
      int abcop, abcpq, abcqo;
      int shareedge = 0;
    
      abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
      if (abcop == (int) INTERSECT) {
        return (int) INTERSECT;
      } else if (abcop == (int) SHAREEDGE) {
        shareedge++;
      }
      abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
      if (abcpq == (int) INTERSECT) {
        return (int) INTERSECT;
      } else if (abcpq == (int) SHAREEDGE) {
        shareedge++;
      }
      abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
      if (abcqo == (int) INTERSECT) {
        return (int) INTERSECT;
      } else if (abcqo == (int) SHAREEDGE) {
        shareedge++;
      }
      if (shareedge == 3) {
        // opq are coincident with abc.
        return (int) SHAREFACE;
      }
    
      // It is only possible either no share edge or one.
      assert(shareedge == 0 || shareedge == 1);
    
      // Continue to detect whether opq and abc are intersecting or not.
      int opqab, opqbc, opqca;
    
      opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
      if (opqab == (int) INTERSECT) {
        return (int) INTERSECT;
      }
      opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
      if (opqbc == (int) INTERSECT) {
        return (int) INTERSECT;
      }
      opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
      if (opqca == (int) INTERSECT) {
        return (int) INTERSECT;
      }
    
      // At this point, two triangles are not intersecting and not coincident.
      //   They may be share an edge, or share a vertex, or disjoint.
      if (abcop == (int) SHAREEDGE) {
        assert((abcpq == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
        // op is coincident with an edge of abc.
        return (int) SHAREEDGE;
      }
      if (abcpq == (int) SHAREEDGE) {
        assert((abcop == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
        // pq is coincident with an edge of abc.
        return (int) SHAREEDGE;
      }
      if (abcqo == (int) SHAREEDGE) {
        assert((abcop == (int) SHAREVERT) && (abcpq == (int) SHAREVERT));
        // qo is coincident with an edge of abc.
        return (int) SHAREEDGE;
      }
    
      // They may share a vertex or disjoint.
      if (abcop == (int) SHAREVERT) {
        // o or p is coincident with a vertex of abc.
        if (abcpq == (int) SHAREVERT) {
          // p is the coincident vertex.
          assert(abcqo != (int) SHAREVERT);
        } else {
          // o is the coincident vertex.
          assert(abcqo == (int) SHAREVERT);
        }
        return (int) SHAREVERT;
      }
      if (abcpq == (int) SHAREVERT) {
        // q is the coincident vertex.
        assert(abcqo == (int) SHAREVERT);
        return (int) SHAREVERT;
      }
    
      // They are disjoint.
      return (int) DISJOINT;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // lu_decmp()    Compute the LU decomposition of a matrix.                   //
    //                                                                           //
    // Compute the LU decomposition of a (non-singular) square matrix A using    //
    // partial pivoting and implicit row exchanges.  The result is:              //
    //     A = P * L * U,                                                        //
    // where P is a permutation matrix, L is unit lower triangular, and U is     //
    // upper triangular.  The factored form of A is used in combination with     //
    // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix.       //
    //                                                                           //
    // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
    // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
    // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row   //
    // permutation effected by the partial pivoting, effectively,  'ps' array    //
    // tells the user what the permutation matrix P is; 'd' is output as +1/-1   //
    // depending on whether the number of row interchanges was even or odd,      //
    // respectively.                                                             //
    //                                                                           //
    // Return true if the LU decomposition is successfully computed, otherwise,  //
    // return false in case that A is a singular matrix.                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
    {
      REAL scales[4];
      REAL pivot, biggest, mult, tempf;
      int pivotindex = 0;
      int i, j, k;
    
      *d = 1.0;                                      // No row interchanges yet.
    
      for (i = N; i < n + N; i++) {                             // For each row.
        // Find the largest element in each row for row equilibration
        biggest = 0.0;
        for (j = N; j < n + N; j++)
          if (biggest < (tempf = fabs(lu[i][j])))
            biggest  = tempf;
        if (biggest != 0.0)
          scales[i] = 1.0 / biggest;
        else {
          scales[i] = 0.0;
          return false;                            // Zero row: singular matrix.
        }
        ps[i] = i;                                 // Initialize pivot sequence.
      }
    
      for (k = N; k < n + N - 1; k++) {                      // For each column.
        // Find the largest element in each column to pivot around.
        biggest = 0.0;
        for (i = k; i < n + N; i++) {
          if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
            biggest = tempf;
            pivotindex = i;
          }
        }
        if (biggest == 0.0) {
          return false;                         // Zero column: singular matrix.
        }
        if (pivotindex != k) {                         // Update pivot sequence.
          j = ps[k];
          ps[k] = ps[pivotindex];
          ps[pivotindex] = j;
          *d = -(*d);                          // ...and change the parity of d.
        }
    
        // Pivot, eliminating an extra variable  each time
        pivot = lu[ps[k]][k];
        for (i = k + 1; i < n + N; i++) {
          lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
          if (mult != 0.0) {
            for (j = k + 1; j < n + N; j++)
              lu[ps[i]][j] -= mult * lu[ps[k]][j];
          }
        }
      }
    
      // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
      return lu[ps[n + N - 1]][n + N - 1] != 0.0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // lu_solve()    Solves the linear equation:  Ax = b,  after the matrix A    //
    //               has been decomposed into the lower and upper triangular     //
    //               matrices L and U, where A = LU.                             //
    //                                                                           //
    // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as    //
    // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]'  //
    // is input as the permutation vector returned by 'lu_decmp';  'b[N..n+N-1]' //
    // is input as the right-hand side vector, and returns with the solution     //
    // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be   //
    // left in place for successive calls with different right-hand sides 'b'.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
    {
      int i, j;
      REAL X[4], dot;
    
      for (i = N; i < n + N; i++) X[i] = 0.0;
    
      // Vector reduction using U triangular matrix.
      for (i = N; i < n + N; i++) {
        dot = 0.0;
        for (j = N; j < i + N; j++)
          dot += lu[ps[i]][j] * X[j];
        X[i] = b[ps[i]] - dot;
      }
    
      // Back substitution, in L triangular matrix.
      for (i = n + N - 1; i >= N; i--) {
        dot = 0.0;
        for (j = i + 1; j < n + N; j++)
          dot += lu[ps[i]][j] * X[j];
        X[i] = (X[i] - dot) / lu[ps[i]][i];
      }
    
      for (i = N; i < n + N; i++) b[i] = X[i];
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // incircle3d()    3D in-circle test.                                        //
    //                                                                           //
    // Return a negative value if pd is inside the circumcircle of the triangle  //
    // pa, pb, and pc.                                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
    {
      REAL area2[2], n1[3], n2[3], c[3];
      REAL sign, r, d;
    
      // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
      facenormal(pa, pb, pc, n1, 1, NULL);
      area2[0] = DOT(n1, n1);
      facenormal(pb, pa, pd, n2, 1, NULL);
      area2[1] = DOT(n2, n2);
    
      if (area2[0] > area2[1]) {
        // Choose [a, b, c] as the base triangle.
        circumsphere(pa, pb, pc, NULL, c, &r);
        d = DIST(c, pd);
      } else {
        // Choose [b, a, d] as the base triangle.
        if (area2[1] > 0) {
          circumsphere(pb, pa, pd, NULL, c, &r);
          d = DIST(c, pc);
        } else {
          // The four points are collinear. This case only happens on the boundary.
          return 0; // Return "not inside".
        }
      }
    
      sign = d - r;
      if (fabs(sign) / r < b->epsilon) {
        sign = 0;
      }
    
      return sign;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // insphere_s()    Insphere test with symbolic perturbation.                 //
    //                                                                           //
    // Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
    // outside the circumscirbed sphere of the four points.                      //
    //                                                                           //
    // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
    // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
    // points pa, pb, and pc. Otherwise, the returned sign is flipped.           //
    //                                                                           //
    // Return a positive value (> 0) if pe lies inside, a negative value (< 0)   //
    // if pe lies outside the sphere, the returned value will not be zero.       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
    {
      REAL sign;
    
      inspherecount++;
    
      sign = insphere(pa, pb, pc, pd, pe);
      if (sign != 0.0) {
        return sign;
      }
    
      insphere_sos_count++;
    
      // Symbolic perturbation.
      point pt[5], swappt;
      REAL oriA, oriB;
      int swaps, count;
      int n, i;
    
      pt[0] = pa;
      pt[1] = pb;
      pt[2] = pc;
      pt[3] = pd;
      pt[4] = pe;
      
      // Sort the five points such that their indices are in the increasing
      //   order. An optimized bubble sort algorithm is used, i.e., it has
      //   the worst case O(n^2) runtime, but it is usually much faster.
      swaps = 0; // Record the total number of swaps.
      n = 5;
      do {
        count = 0;
        n = n - 1;
        for (i = 0; i < n; i++) {
          if (pointmark(pt[i]) > pointmark(pt[i+1])) {
            swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
            count++;
          }
        }
        swaps += count;
      } while (count > 0); // Continue if some points are swapped.
    
      oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
      if (oriA != 0.0) {
        // Flip the sign if there are odd number of swaps.
        if ((swaps % 2) != 0) oriA = -oriA;
        return oriA;
      }
      
      oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
      assert(oriB != 0.0); // SELF_CHECK
      // Flip the sign if there are odd number of swaps.
      if ((swaps % 2) != 0) oriB = -oriB;
      return oriB;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // orient4d_s()    4d orientation test with symbolic perturbation.           //
    //                                                                           //
    // Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
    // point pe' in R^4 lies below or above the hyperplance passing through the  //
    // four points pa', pb', pc', and pd'.                                       //
    //                                                                           //
    // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
    // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
    // the points pa, pb, and pc. Otherwise, the returned sign is flipped.       //
    //                                                                           //
    // Return a positive value (> 0) if pe' lies below, a negative value (< 0)   //
    // if pe' lies above the hyperplane, the returned value should not be zero.  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
                                REAL aheight, REAL bheight, REAL cheight, 
                                REAL dheight, REAL eheight)
    {
      REAL sign;
    
      inspherecount++;
    
      sign = orient4d(pa, pb, pc, pd, pe, 
                      aheight, bheight, cheight, dheight, eheight);
      if (sign != 0.0) {
        return sign;
      }
    
      insphere_sos_count++;
    
      // Symbolic perturbation.
      point pt[5], swappt;
      REAL oriA, oriB;
      int swaps, count;
      int n, i;
    
      pt[0] = pa;
      pt[1] = pb;
      pt[2] = pc;
      pt[3] = pd;
      pt[4] = pe;
      
      // Sort the five points such that their indices are in the increasing
      //   order. An optimized bubble sort algorithm is used, i.e., it has
      //   the worst case O(n^2) runtime, but it is usually much faster.
      swaps = 0; // Record the total number of swaps.
      n = 5;
      do {
        count = 0;
        n = n - 1;
        for (i = 0; i < n; i++) {
          if (pointmark(pt[i]) > pointmark(pt[i+1])) {
            swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
            count++;
          }
        }
        swaps += count;
      } while (count > 0); // Continue if some points are swapped.
    
      oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
      if (oriA != 0.0) {
        // Flip the sign if there are odd number of swaps.
        if ((swaps % 2) != 0) oriA = -oriA;
        return oriA;
      }
      
      oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
      assert(oriB != 0.0); // SELF_CHECK
      // Flip the sign if there are odd number of swaps.
      if ((swaps % 2) != 0) oriB = -oriB;
      return oriB;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // facenormal()    Calculate the normal of the face.                         //
    //                                                                           //
    // The normal of the face abc can be calculated by the cross product of 2 of //
    // its 3 edge vectors.  A better choice of two edge vectors will reduce the  //
    // numerical error during the calculation.  Burdakov proved that the optimal //
    // basis problem is equivalent to the minimum spanning tree problem with the //
    // edge length be the functional, see Burdakov, "A greedy algorithm for the  //
    // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
    // short edges in abc are chosen for the calculation.                        //
    //                                                                           //
    // If 'lav' is not NULL and if 'pivot' is set, the average edge length of    //
    // the edges of the face [a,b,c] is returned.                                //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
                                REAL* lav)
    {
      REAL v1[3], v2[3], v3[3], *pv1, *pv2;
      REAL L1, L2, L3;
    
      v1[0] = pb[0] - pa[0];  // edge vector v1: a->b
      v1[1] = pb[1] - pa[1];
      v1[2] = pb[2] - pa[2];
      v2[0] = pa[0] - pc[0];  // edge vector v2: c->a
      v2[1] = pa[1] - pc[1];
      v2[2] = pa[2] - pc[2];
    
      // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
      if (pivot > 0) {
        // Choose edge vectors by Burdakov's algorithm.
        v3[0] = pc[0] - pb[0];  // edge vector v3: b->c
        v3[1] = pc[1] - pb[1];
        v3[2] = pc[2] - pb[2];
        L1 = DOT(v1, v1);
        L2 = DOT(v2, v2);
        L3 = DOT(v3, v3);
        // Sort the three edge lengths.
        if (L1 < L2) {
          if (L2 < L3) {
            pv1 = v1; pv2 = v2; // n = v1 x (-v2).
          } else {
            pv1 = v3; pv2 = v1; // n = v3 x (-v1).
          }
        } else {
          if (L1 < L3) {
            pv1 = v1; pv2 = v2; // n = v1 x (-v2).
          } else {
            pv1 = v2; pv2 = v3; // n = v2 x (-v3).
          }
        }
        if (lav) {
          // return the average edge length.
          *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
        }
      } else {
        pv1 = v1; pv2 = v2; // n = v1 x (-v2).
      }
    
      // Calculate the face normal.
      CROSS(pv1, pv2, n);
      // Inverse the direction;
      n[0] = -n[0];
      n[1] = -n[1];
      n[2] = -n[2];
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // shortdistance()    Returns the shortest distance from point p to a line   //
    //                    defined by two points e1 and e2.                       //
    //                                                                           //
    // First compute the projection length l_p of the vector v1 = p - e1 along   //
    // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the  //
    // shortest distance.                                                        //
    //                                                                           //
    // This routine allows that p is collinear with the line. In this case, the  //
    // return value is zero. The two points e1 and e2 should not be identical.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
    {
      REAL v1[3], v2[3];
      REAL len, l_p;
    
      v1[0] = e2[0] - e1[0];
      v1[1] = e2[1] - e1[1];
      v1[2] = e2[2] - e1[2];
      v2[0] = p[0] - e1[0];
      v2[1] = p[1] - e1[1];
      v2[2] = p[2] - e1[2];
    
      len = sqrt(dot(v1, v1));
    #ifdef SELF_CHECK
      assert(len != 0.0);
    #endif
      v1[0] /= len;
      v1[1] /= len;
      v1[2] /= len;
      l_p = dot(v1, v2);
    
      return sqrt(dot(v2, v2) - l_p * l_p);
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // triarea()    Return the area of a triangle.                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
    {
      REAL A[4][4];  
    
      // Compute the coefficient matrix A (3x3).
      A[0][0] = pb[0] - pa[0];
      A[0][1] = pb[1] - pa[1];
      A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
      A[1][0] = pc[0] - pa[0];
      A[1][1] = pc[1] - pa[1];
      A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
    
      cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
    
      return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // interiorangle()    Return the interior angle (0 - 2 * PI) between vectors //
    //                    o->p1 and o->p2.                                       //
    //                                                                           //
    // 'n' is the normal of the plane containing face (o, p1, p2).  The interior //
    // angle is the total angle rotating from o->p1 around n to o->p2.  Exchange //
    // the position of p1 and p2 will get the complement angle of the other one. //
    // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1).  Set  //
    // 'n' be NULL if you only want the interior angle between 0 - PI.           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
    {
      REAL v1[3], v2[3], np[3];
      REAL theta, costheta, lenlen;
      REAL ori, len1, len2;
    
      // Get the interior angle (0 - PI) between o->p1, and o->p2.
      v1[0] = p1[0] - o[0];
      v1[1] = p1[1] - o[1];
      v1[2] = p1[2] - o[2];
      v2[0] = p2[0] - o[0];
      v2[1] = p2[1] - o[1];
      v2[2] = p2[2] - o[2];
      len1 = sqrt(dot(v1, v1));
      len2 = sqrt(dot(v2, v2));
      lenlen = len1 * len2;
    #ifdef SELF_CHECK
      assert(lenlen != 0.0);
    #endif
      costheta = dot(v1, v2) / lenlen;
      if (costheta > 1.0) {
        costheta = 1.0; // Roundoff. 
      } else if (costheta < -1.0) {
        costheta = -1.0; // Roundoff. 
      }
      theta = acos(costheta);
      if (n != NULL) {
        // Get a point above the face (o, p1, p2);
        np[0] = o[0] + n[0];
        np[1] = o[1] + n[1];
        np[2] = o[2] + n[2];
        // Adjust theta (0 - 2 * PI).
        ori = orient3d(p1, o, np, p2);
        if (ori > 0.0) {
          theta = 2 * PI - theta;
        }
      }
    
      return theta;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // projpt2edge()    Return the projection point from a point to an edge.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
    {
      REAL v1[3], v2[3];
      REAL len, l_p;
    
      v1[0] = e2[0] - e1[0];
      v1[1] = e2[1] - e1[1];
      v1[2] = e2[2] - e1[2];
      v2[0] = p[0] - e1[0];
      v2[1] = p[1] - e1[1];
      v2[2] = p[2] - e1[2];
    
      len = sqrt(dot(v1, v1));
    #ifdef SELF_CHECK
      assert(len != 0.0);
    #endif
      v1[0] /= len;
      v1[1] /= len;
      v1[2] /= len;
      l_p = dot(v1, v2);
    
      prj[0] = e1[0] + l_p * v1[0];
      prj[1] = e1[1] + l_p * v1[1];
      prj[2] = e1[2] + l_p * v1[2];
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // projpt2face()    Return the projection point from a point to a face.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
    {
      REAL fnormal[3], v1[3];
      REAL len, dist;
    
      // Get the unit face normal.
      facenormal(f1, f2, f3, fnormal, 1, NULL);
      len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] + 
                 fnormal[2]*fnormal[2]);
      fnormal[0] /= len;
      fnormal[1] /= len;
      fnormal[2] /= len;
      // Get the vector v1 = |p - f1|.
      v1[0] = p[0] - f1[0];
      v1[1] = p[1] - f1[1];
      v1[2] = p[2] - f1[2];
      // Get the project distance.
      dist = dot(fnormal, v1);
      
      // Get the project point.
      prj[0] = p[0] - dist * fnormal[0];
      prj[1] = p[1] - dist * fnormal[1];
      prj[2] = p[2] - dist * fnormal[2];
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // facedihedral()    Return the dihedral angle (in radian) between two       //
    //                   adjoining faces.                                        //
    //                                                                           //
    // 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are   //
    // apexes of these two faces.  Return the angle (between 0 to 2*pi) between  //
    // the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2).        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
    {
      REAL n1[3], n2[3];
      REAL n1len, n2len;
      REAL costheta, ori;
      REAL theta;
    
      facenormal(pa, pb, pc1, n1, 1, NULL);
      facenormal(pa, pb, pc2, n2, 1, NULL);
      n1len = sqrt(dot(n1, n1));
      n2len = sqrt(dot(n2, n2));
      costheta = dot(n1, n2) / (n1len * n2len);
      // Be careful rounding error!
      if (costheta > 1.0) {
        costheta = 1.0;
      } else if (costheta < -1.0) {
        costheta = -1.0;
      }
      theta = acos(costheta);
      ori = orient3d(pa, pb, pc1, pc2);
      if (ori > 0.0) {
        theta = 2 * PI - theta;
      }
    
      return theta;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetalldihedral()    Get all (six) dihedral angles of a tet.               //
    //                                                                           //
    // If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles,  //
    // the edge indices are given in the global array 'edge2ver'. If 'cosmaxd'   //
    // (or 'cosmind') is not NULL, it returns the cosine of the maximal (or      //
    // minimal) dihedral angle.                                                  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
                                    REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
    {
      REAL N[4][3], vol, cosd, len;
      int f1, f2, i, j;
    
      vol = 0; // Check if the tet is valid or not.
    
      // Get four normals of faces of the tet.
      tetallnormal(pa, pb, pc, pd, N, &vol);
    
      if (vol > 0) {
        // Normalize the normals.
        for (i = 0; i < 4; i++) {
          len = sqrt(dot(N[i], N[i]));
          if (len != 0.0) {
            for (j = 0; j < 3; j++) N[i][j] /= len;
          } else {
            // There are degeneracies, such as duplicated vertices.
            vol = 0; //assert(0);
          }
        }
      }
    
      if (vol <= 0) { // if (vol == 0.0) {
        // A degenerated tet or an inverted tet.
        facenormal(pc, pb, pd, N[0], 1, NULL);
        facenormal(pa, pc, pd, N[1], 1, NULL);
        facenormal(pb, pa, pd, N[2], 1, NULL);
        facenormal(pa, pb, pc, N[3], 1, NULL);
        // Normalize the normals.
        for (i = 0; i < 4; i++) {
          len = sqrt(dot(N[i], N[i]));
          if (len != 0.0) {
            for (j = 0; j < 3; j++) N[i][j] /= len;
          } else {
            // There are degeneracies, such as duplicated vertices.
            break; // Not a valid normal.
          }
        }
        if (i < 4) {
          // Do not calculate dihedral angles.
          // Set all angles be 0 degree. There will be no quality optimization for
          //   this tet! Use volume optimization to correct it.
          if (cosdd != NULL) {
            for (i = 0; i < 6; i++) {
              cosdd[i] = -1.0; // 180 degree.
            }
          }
          // This tet has zero volume.
          if (cosmaxd != NULL) {
            *cosmaxd = -1.0; // 180 degree.
          }
          if (cosmind != NULL) {
            *cosmind = -1.0; // 180 degree.
          }
          return false;
        }
      }
    
      // Calculate the consine of the dihedral angles of the edges.
      for (i = 0; i < 6; i++) {
        switch (i) {
        case 0: f1 = 0; f2 = 1; break; // [c,d].
        case 1: f1 = 1; f2 = 2; break; // [a,d].
        case 2: f1 = 2; f2 = 3; break; // [a,b].
        case 3: f1 = 0; f2 = 3; break; // [b,c].
        case 4: f1 = 2; f2 = 0; break; // [b,d].
        case 5: f1 = 1; f2 = 3; break; // [a,c].
        }
        cosd = -dot(N[f1], N[f2]);
        if (cosd < -1.0) cosd = -1.0; // Rounding.
        if (cosdd) cosdd[i] = cosd;
        if (cosmaxd || cosmind) {
          if (i == 0) {
            if (cosmaxd) *cosmaxd = cosd;
            if (cosmind) *cosmind = cosd;
          } else {
            if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
            if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
          }
        }
      }
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetallnormal()    Get the in-noramls of the four faces of a given tet.    //
    //                                                                           //
    // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd,   //
    // N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices   //
    // of the mesh data structure). These normals are unnormalized.              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
                                  REAL N[4][3], REAL* volume)
    {
      REAL A[4][4], rhs[4], D;
      int indx[4];
      int i, j;
    
      // get the entries of A[3][3].
      for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i];  // d->a vec
      for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i];  // d->b vec
      for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i];  // d->c vec
    
      // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
      if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
        if (volume != NULL) {
          // Get the volume of the tet.
          *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
        }
        for (j = 0; j < 3; j++) {
          for (i = 0; i < 3; i++) rhs[i] = 0.0;
          rhs[j] = 1.0;  // Positive means the inside direction
          lu_solve(A, 3, indx, rhs, 0);
          for (i = 0; i < 3; i++) N[j][i] = rhs[i];
        }
        // Get the fourth normal by summing up the first three.
        for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
      } else {
        // The tet is degenerated.
        if (volume != NULL) {
          *volume = 0;
        }
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetaspectratio()    Calculate the aspect ratio of the tetrahedron.        //
    //                                                                           //
    // The aspect ratio of a tet is R/h, where R is the circumradius and h is    //
    // the shortest height of the tet.                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
    {
      REAL vda[3], vdb[3], vdc[3];
      REAL N[4][3], A[4][4], rhs[4], D;
      REAL H[4], volume, radius2, minheightinv;
      int indx[4];
      int i, j; 
    
      // Set the matrix A = [vda, vdb, vdc]^T.
      for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
      for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
      for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
      // Lu-decompose the matrix A.
      lu_decmp(A, 3, indx, &D, 0);
      // Get the volume of abcd.
      volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
      // Check if it is zero.
      if (volume == 0.0) return 1.0e+200; // A degenerate tet.
      // if (volume < 0.0) volume = -volume;
      // Check the radiu-edge ratio of the tet.
      rhs[0] = 0.5 * dot(vda, vda);
      rhs[1] = 0.5 * dot(vdb, vdb);
      rhs[2] = 0.5 * dot(vdc, vdc);
      lu_solve(A, 3, indx, rhs, 0);
      // Get the circumcenter.
      // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
      // Get the square of the circumradius.
      radius2 = dot(rhs, rhs);
    
      // Compute the 4 face normals (N[0], ..., N[3]).
      for (j = 0; j < 3; j++) {
        for (i = 0; i < 3; i++) rhs[i] = 0.0;
        rhs[j] = 1.0;  // Positive means the inside direction
        lu_solve(A, 3, indx, rhs, 0);
        for (i = 0; i < 3; i++) N[j][i] = rhs[i];
      }
      // Get the fourth normal by summing up the first three.
      for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
      // Normalized the normals.
      for (i = 0; i < 4; i++) {
        // H[i] is the inverse of the height of its corresponding face.
        H[i] = sqrt(dot(N[i], N[i]));
        // if (H[i] > 0.0) {
        //   for (j = 0; j < 3; j++) N[i][j] /= H[i];
        // }
      }
      // Get the radius of the inscribed sphere.
      // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
      // Get the biggest H[i] (corresponding to the smallest height).
      minheightinv = H[0];
      for (i = 1; i < 3; i++) {
        if (H[i] > minheightinv) minheightinv = H[i];
      }
    
      return sqrt(radius2) * minheightinv;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // circumsphere()    Calculate the smallest circumsphere (center and radius) //
    //                   of the given three or four points.                      //
    //                                                                           //
    // The circumsphere of four points (a tetrahedron) is unique if they are not //
    // degenerate. If 'pd = NULL', the smallest circumsphere of three points is  //
    // the diametral sphere of the triangle if they are not degenerate.          //
    //                                                                           //
    // Return TRUE if the input points are not degenerate and the circumcenter   //
    // and circumradius are returned in 'cent' and 'radius' respectively if they //
    // are not NULLs. Otherwise, return FALSE indicated the points are degenrate.//
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, 
                                  REAL* cent, REAL* radius)
    {
      REAL A[4][4], rhs[4], D;
      int indx[4];
    
      // Compute the coefficient matrix A (3x3).
      A[0][0] = pb[0] - pa[0];
      A[0][1] = pb[1] - pa[1];
      A[0][2] = pb[2] - pa[2];
      A[1][0] = pc[0] - pa[0];
      A[1][1] = pc[1] - pa[1];
      A[1][2] = pc[2] - pa[2];
      if (pd != NULL) {
        A[2][0] = pd[0] - pa[0];
        A[2][1] = pd[1] - pa[1]; 
        A[2][2] = pd[2] - pa[2];
      } else {
        cross(A[0], A[1], A[2]);
      }
    
      // Compute the right hand side vector b (3x1).
      rhs[0] = 0.5 * dot(A[0], A[0]);
      rhs[1] = 0.5 * dot(A[1], A[1]);
      if (pd != NULL) {
        rhs[2] = 0.5 * dot(A[2], A[2]);
      } else {
        rhs[2] = 0.0;
      }
    
      // Solve the 3 by 3 equations use LU decomposition with partial pivoting
      //   and backward and forward substitute..
      if (!lu_decmp(A, 3, indx, &D, 0)) {
        if (radius != (REAL *) NULL) *radius = 0.0;
        return false;
      }    
      lu_solve(A, 3, indx, rhs, 0);
      if (cent != (REAL *) NULL) {
        cent[0] = pa[0] + rhs[0];
        cent[1] = pa[1] + rhs[1];
        cent[2] = pa[2] + rhs[2];
      }
      if (radius != (REAL *) NULL) {
        *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
      }
      return true;
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // planelineint()    Calculate the intersection of a line and a plane.       //
    //                                                                           //
    // The equation of a plane (points P are on the plane with normal N and P3   //
    // on the plane) can be written as: N dot (P - P3) = 0. The equation of the  //
    // line (points P on the line passing through P1 and P2) can be written as:  //
    // P = P1 + u (P2 - P1). The intersection of these two occurs when:          //
    //   N dot (P1 + u (P2 - P1)) = N dot P3.                                    //
    // Solving for u gives:                                                      //
    //         N dot (P3 - P1)                                                   //
    //   u = ------------------.                                                 //
    //         N dot (P2 - P1)                                                   //
    // If the denominator is 0 then N (the normal to the plane) is perpendicular //
    // to the line.  Thus the line is either parallel to the plane and there are //
    // no solutions or the line is on the plane in which case there are an infi- //
    // nite number of solutions.                                                 //
    //                                                                           //
    // The plane is given by three points pa, pb, and pc, e1 and e2 defines the  //
    // line. If u is non-zero, The intersection point (if exists) returns in ip. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
                                  REAL* ip, REAL* u)
    {
      REAL n[3], det, det1;
    
      // Calculate N.
      facenormal(pa, pb, pc, n, 1, NULL);
      // Calculate N dot (e2 - e1).
      det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
          + n[2] * (e2[2] - e1[2]);
      if (det != 0.0) {
        // Calculate N dot (pa - e1)
        det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
             + n[2] * (pa[2] - e1[2]);
        *u = det1 / det;
        ip[0] = e1[0] + *u * (e2[0] - e1[0]);
        ip[1] = e1[1] + *u * (e2[1] - e1[1]);
        ip[2] = e1[2] + *u * (e2[2] - e1[2]);
      } else {
        *u = 0.0;
      }
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetprismvol()    Calculate the volume of a tetrahedral prism in 4D.       //
    //                                                                           //
    // A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
    // tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular  //
    // prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
    // vertices. (Wikipedia).                                                    //
    //                                                                           //
    // Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
    // the lower tetrahedral facet of the prism.  The top tetrahedral facet is   //
    // formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by     //
    // lifting each vertex of the lower facet into R^4 by a weight (height).  A  //
    // canonical choice of the weights is the square of Euclidean norm of of the //
    // points (vectors).                                                         //
    //                                                                           //
    //                                                                           //
    // The return value is (4!) 24 times of the volume of the tetrahedral prism. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
    {
      REAL *p4, *p5, *p6, *p7;
      REAL w4, w5, w6, w7;
      REAL vol[4];
    
      p4 = p0;
      p5 = p1;
      p6 = p2;
      p7 = p3;
    
      // TO DO: these weights can be pre-calculated!
      w4 = dot(p0, p0);
      w5 = dot(p1, p1);
      w6 = dot(p2, p2);
      w7 = dot(p3, p3);
    
      // Calculate the volume of the tet-prism.
      vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
      vol[1] = orient4d(p3, p6, p2, p0, p1,  0, w6,  0, 0,  0);
      vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6,  0, 0,  0);
      vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0,  0);
    
      return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// geom_cxx /////////////////////////////////////////////////////////////////
    
    //// flip_cxx /////////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flippush()    Push a face (possibly will be flipped) into flipstack.      //
    //                                                                           //
    // The face is marked. The flag is used to check the validity of the face on //
    // its popup.  Some other flips may change it already.                       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flippush(badface*& fstack, triface* flipface)
    {
      badface *newflipface;
    
      if (!facemarked(*flipface)) {
        newflipface = (badface *) flippool->alloc();
        newflipface->tt = *flipface;
        markface(newflipface->tt);
        // Push this face into stack.
        newflipface->nextitem = fstack;
        fstack = newflipface;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flip23()    Perform a 2-to-3 flip (face-to-edge flip).                    //
    //                                                                           //
    // 'fliptets' is an array of tetrahedra.  On input it contains two tets      //
    // [a,b,c,d] and [b,a,c,e]. It returns three new tets: [e,d,a,b], [e,d,b,c], //
    // [e,d,c,a]. The face [a,b,c] is removed, and the edge [d,e] is created.    //
    //                                                                           //
    // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of   //
    // the five vertices may be 'dummypoint'. There are two canonical cases:     //
    //   (1) d is 'dummypoint', then all three new tets are hull tets.  If e is  //
    //       'dummypoint', we reconfigure e to d, i.e., turn it up-side down.    //
    //   (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are  //
    //       hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
    //       rotate the three input tets counterclockwisely (right-hand rule)    //
    //       until a or b is in c's position.                                    //
    //                                                                           //
    // If 'flipflag > 0', faces on the convex hull of the five vertices might    //
    // need to be flipped, e.g., for incremental DT construction or mesh quality //
    // improvement. They will be queued in 'flipstack'.                          //
    //                                                                           //
    // If 'flipflag = 1', it is in the process of incrmental flip DT algorithm,  //
    // and we assume that 'd' must be the newly inserted vertex.  In such case,  //
    // only the link faces at 'd', i.e., three faces [a,b,e], [b,c,e], and [c,a, //
    // e] needs to be queued, see [Edelsbrunner & Shah'1996] and [M\"ucke'1998]. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, 
                            int chkencflag)
    {
      triface topcastets[3], botcastets[3];
      triface newface, casface;
      face checksh;
      face checkseg;
      badface *bface; // used by chkencflag
      point pa, pb, pc, pd, pe;
      REAL volneg[2], volpos[3], vol_diff; // volumes of involved tet-prisms.
      int dummyflag = 0;  // range = {-1, 0, 1, 2}.
      int i;
    
      if (hullflag > 0) {
        // Check if e is dummypoint.
        if (oppo(fliptets[1]) == dummypoint) {
          // Swap the two old tets.
          newface = fliptets[0];
          fliptets[0] = fliptets[1];
          fliptets[1] = newface;
          dummyflag = -1;  // d is dummypoint.
        } else {
          // Check if either a or b is dummypoint.
          if (org(fliptets[0]) == dummypoint) {
            dummyflag = 1; // a is dummypoint.
            enextself(fliptets[0]);
            eprevself(fliptets[1]);
          } else if (dest(fliptets[0]) == dummypoint) {
            dummyflag = 2; // b is dummypoint.
            eprevself(fliptets[0]);
            enextself(fliptets[1]);
          } else {
            dummyflag = 0; // either c or d may be dummypoint.
          }
        }
      }
    
      pa = org(fliptets[0]);
      pb = dest(fliptets[0]);
      pc = apex(fliptets[0]);
      pd = oppo(fliptets[0]);
      pe = oppo(fliptets[1]);
    
      if (b->verbose > 3) {
        printf("        flip 2-to-3: (%d, %d, %d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
      }
      flip23count++;
    
      // Get the outer boundary faces.
      for (i = 0; i < 3; i++) {
        fnext(fliptets[0], topcastets[i]);
        enextself(fliptets[0]);
      }
      for (i = 0; i < 3; i++) {
        fnext(fliptets[1], botcastets[i]);
        eprevself(fliptets[1]);
      }
    
      // Re-use fliptets[0] and fliptets[1].
      fliptets[0].ver = 11;
      fliptets[1].ver = 11;
      setelemmarker(fliptets[0].tet, 0); // Clear all flags.
      setelemmarker(fliptets[1].tet, 0);
      if (checksubsegflag) {
        // Dealloc the space to subsegments.
        if (fliptets[0].tet[8] != NULL) {
          tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
          fliptets[0].tet[8] = NULL;
        }
        if (fliptets[1].tet[8] != NULL) {
          tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
          fliptets[1].tet[8] = NULL;
        }
      }
      if (checksubfaceflag) {
        // Dealloc the space to subfaces.
        if (fliptets[0].tet[9] != NULL) {
          tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
          fliptets[0].tet[9] = NULL;
        }
        if (fliptets[1].tet[9] != NULL) {
          tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
          fliptets[1].tet[9] = NULL;
        }
      }
      // Create a new tet.
      maketetrahedron(&(fliptets[2]));
    
      if (hullflag > 0) {
        // Check if d is dummytet.
        if (pd != dummypoint) {
          setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
          setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
          // Check if c is dummypoint.
          if (pc != dummypoint) {
            setvertices(fliptets[2], pe, pd, pc, pa);  // [e,d,c,a] *
          } else {
            setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
            esymself(fliptets[2]);                    // [e,d,c,a] *
          }
          // The hullsize does not change.
        } else {
          // d is dummypoint.
          setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
          setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
          setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
          // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
          for (i = 0; i < 3; i++) {
            eprevesymself(fliptets[i]);
            enextself(fliptets[i]);
          }
          // We deleted one hull tet, and created three hull tets.
          hullsize += 2;
        }
      } else {
        setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
        setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
        setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
      }
    
      if (calc_tetprism_vol) {
        if (pd != dummypoint) {
          if (pc != dummypoint) {
            volpos[0] = tetprismvol(pe, pd, pa, pb);
            volpos[1] = tetprismvol(pe, pd, pb, pc);
            volpos[2] = tetprismvol(pe, pd, pc, pa);
            volneg[0] = tetprismvol(pa, pb, pc, pd);
            volneg[1] = tetprismvol(pb, pa, pc, pe);
          } else { // pc == dummypoint
            volpos[0] = tetprismvol(pe, pd, pa, pb);
            volpos[1] = 0.;
            volpos[2] = 0.;
            volneg[0] = 0.;
            volneg[1] = 0.;
          }
        } else { // pd == dummypoint.
          volpos[0] = 0.;
          volpos[1] = 0.;
          volpos[2] = 0.;
          volneg[0] = 0.;
          volneg[1] = tetprismvol(pb, pa, pc, pe);
        }
        vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
        tetprism_vol_sum  += vol_diff; // Update the total sum.
      } // if (check_tetprism_vol_diff)
    
      // Bond three new tets together.
      for (i = 0; i < 3; i++) {
        esym(fliptets[i], newface);
        bond(newface, fliptets[(i + 1) % 3]);
      }
      // Bond to top outer boundary faces (at [a,b,c,d]).
      for (i = 0; i < 3; i++) {
        enextesym(fliptets[i], newface);
        eprevself(newface); // At edges [b,a], [c,b], [a,c].
        bond(newface, topcastets[i]);
      }
      // Bond bottom outer boundary faces (at [b,a,c,e]).
      for (i = 0; i < 3; i++) {
        eprevesym(fliptets[i], newface);
        enextself(newface); // At edges [a,b], [b,c], [c,a].
        bond(newface, botcastets[i]);
      }
    
      // Bond 15 subsegments if there are.
      if (checksubsegflag) {
        // The middle three: [a,b], [b,c], [c,a].
        for (i = 0; i < 3; i++) {
          tsspivot1(topcastets[i], checkseg);
          if (checkseg.sh != NULL) {
            enextesym(fliptets[i], newface);
            eprevself(newface); // At edges [b,a], [c,b], [a,c].
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
        }
        // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
        for (i = 0; i < 3; i++) {
          eprev(topcastets[i], casface);
          tsspivot1(casface, checkseg);
          if (checkseg.sh != NULL) {
            enext(fliptets[i], newface);
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            esym(fliptets[(i + 2) % 3], newface);
            eprevself(newface);
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
        }
        // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
        for (i = 0; i < 3; i++) {
          enext(botcastets[i], casface);
          tsspivot1(casface, checkseg);
          if (checkseg.sh != NULL) {
            eprev(fliptets[i], newface);
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            esym(fliptets[(i + 2) % 3], newface);
            enextself(newface);
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
        }
      }
    
      // Bond 6 subfaces if there are.
      if (checksubfaceflag) {
        for (i = 0; i < 3; i++) {
          tspivot(topcastets[i], checksh);
          if (checksh.sh != NULL) {
            enextesym(fliptets[i], newface);
            eprevself(newface); // At edge [b,a], [c,b], [a,c].
            sesymself(checksh);
            tsbond(newface, checksh);
            if (chkencflag & 2) {
              if (!smarktest2ed(checksh)) {
                bface = (badface *) badsubfacs->alloc();
                bface->ss = checksh;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checksh); // An alive badface
              }
            }
          }
        }
        for (i = 0; i < 3; i++) {
          tspivot(botcastets[i], checksh);
          if (checksh.sh != NULL) {
            eprevesym(fliptets[i], newface);
            enextself(newface); // At edge [a,b], [b,c], [c,a]
            sesymself(checksh);
            tsbond(newface, checksh);
            if (chkencflag & 2) {
              if (!smarktest2ed(checksh)) {
                bface = (badface *) badsubfacs->alloc();
                bface->ss = checksh;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checksh); // An alive badface
              }
            }
          }
        }
      }
    
      if (chkencflag & 4) {
        // Put three new tets into check list.
        for (i = 0; i < 3; i++) {
          if (!marktest2ed(fliptets[i])) {
            bface = (badface *) badtetrahedrons->alloc();
            bface->tt = fliptets[i];
            marktest2(bface->tt);
            bface->forg = org(fliptets[i]);
          }
        }
      }
    
      // Update the point-to-tet map.
      setpoint2tet(pa, encode(fliptets[0]));
      setpoint2tet(pb, encode(fliptets[0]));
      setpoint2tet(pc, encode(fliptets[1]));
      setpoint2tet(pd, encode(fliptets[0]));
      setpoint2tet(pe, encode(fliptets[0]));
    
      if (hullflag > 0) {
        if (dummyflag != 0) {
          // Restore the original position of the points (for flipnm()).
          if (dummyflag == -1) { 
            // Reverse the edge.
            for (i = 0; i < 3; i++) {
              esymself(fliptets[i]);
            }
            // Swap the last two new tets.
            newface = fliptets[1];
            fliptets[1] = fliptets[2];
            fliptets[2] = newface;
          } else {
            // either a or b were swapped.
            if (dummyflag == 1) {
              // a is dummypoint.
              newface = fliptets[0];
              fliptets[0] = fliptets[2];
              fliptets[2] = fliptets[1];
              fliptets[1] = newface;
            } else { // dummyflag == 2
              // b is dummypoint.
              newface = fliptets[0];
              fliptets[0] = fliptets[1];
              fliptets[1] = fliptets[2];
              fliptets[2] = newface;
            }
          }
        }
      }
    
      if (flipflag > 0) {
        // Queue faces which may be locally non-Delaunay.  
        //pd = dest(fliptets[0]); // 'd' may be a new vertex.
        for (i = 0; i < 3; i++) {
          eprevesym(fliptets[i], newface);
          //flippush(flipstack, &newface, pd);
          flippush(flipstack, &newface);
        }
        if (flipflag > 1) {
          //pe = org(fliptets[0]);
          for (i = 0; i < 3; i++) {
            enextesym(fliptets[i], newface);
            //flippush(flipstack, &newface, pe);
            flippush(flipstack, &newface);
          }
        }
      }
    
      recenttet = fliptets[0];
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flip32()    Perform a 3-to-2 flip (edge-to-face flip).                    //
    //                                                                           //
    // 'fliptets' is an array of three tetrahedra. On input, it contains three   //
    // tets: [e,d,a,b], [e,d,b,c], and [e,d,c,a]. It returns tw tets: [a,b,c,d], //
    // and [b,a,c,e]. The edge [e,d] is replaced by the face [a,b,c].            //
    //                                                                           //
    // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of   //
    // the five vertices may be 'dummypoint'. There are two canonical cases:     //
    //   (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
    //       we reconfigure e to d, i.e., turnover it.                           //
    //   (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets.  //
    //       If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
    //       three old tets counterclockwisely (right-hand rule) until a or b    //
    //       is in c's position.                                                 //
    //                                                                           //
    // If 'flipflag > 0', faces on the convex hull of the five vertices might    //
    // need to be flipped, e.g., for incremental DT construction or mesh quality //
    // improvement. They will be queued in 'flipstack'.                          //
    //                                                                           //
    // If 'flipflag = 1', it is in the process of incrmental flip DT algorithm,  //
    // and we assume that 'a' must be the newly inserted vertex.  In such case,  //
    // only the link faces at 'a', i.e., two faces [c,b,d] and [b,c,e] needs to  //
    // be queued, refer to [Edelsbrunner & Shah'1996] and [M\"ucke'1998].        //
    //                                                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
                            int chkencflag)
    {
      triface topcastets[3], botcastets[3];
      triface newface, casface;
      face checksh; 
      face checkseg; 
      badface *bface; // used by chkencflag
      point pa, pb, pc, pd, pe;
      REAL volneg[3], volpos[2], vol_diff; // volumes of involved tet-prisms.
      int dummyflag = 0;  // Rangle = {-1, 0, 1, 2}
      int i;
    
      // For 2-to-2 flip (subfaces).
      face flipshs[3], flipfaces[2];
      point rempt;
      int spivot = -1, scount = 0;
    
      if (hullflag > 0) {
        // Check if e is 'dummypoint'.
        if (org(fliptets[0]) == dummypoint) {
          // Reverse the edge.
          for (i = 0; i < 3; i++) {
            esymself(fliptets[i]);
          }
          // Swap the last two tets.
          newface = fliptets[1];
          fliptets[1] = fliptets[2];
          fliptets[2] = newface;
          dummyflag = -1; // e is dummypoint.
        } else {
          // Check if a or b is the 'dummypoint'.
          if (apex(fliptets[0]) == dummypoint) { 
            dummyflag = 1;  // a is dummypoint.
            newface = fliptets[0];
            fliptets[0] = fliptets[1];
            fliptets[1] = fliptets[2];
            fliptets[2] = newface;
          } else if (apex(fliptets[1]) == dummypoint) {
            dummyflag = 2;  // b is dummypoint.
            newface = fliptets[0];
            fliptets[0] = fliptets[2];
            fliptets[2] = fliptets[1];
            fliptets[1] = newface;
          } else {
            dummyflag = 0;  // either c or d may be dummypoint.
          }
        }
      }
    
      pa = apex(fliptets[0]);
      pb = apex(fliptets[1]);
      pc = apex(fliptets[2]);
      pd = dest(fliptets[0]);
      pe = org(fliptets[0]);
    
      if (b->verbose > 3) {
        printf("        flip 3-to-2: (%d, %d, %d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
      }
      flip32count++;
    
      // Get the outer boundary faces.
      for (i = 0; i < 3; i++) {
        enextesym(fliptets[i], casface);
        eprevself(casface);
        fsym(casface, topcastets[i]);
      }
      for (i = 0; i < 3; i++) {
        eprevesym(fliptets[i], casface);
        enextself(casface);
        fsym(casface, botcastets[i]);
      }
    
      if (checksubfaceflag) {
        // Check if there are interior subfaces at the edge [e,d].
        spivot = -1;
        scount = 0;
        for (i = 0; i < 3; i++) {
          tspivot(fliptets[i], flipshs[i]);
          if (flipshs[i].sh != NULL) {
            if (b->verbose > 3) {
              printf("        Found an interior subface (%d, %d, %d).\n",
                     pointmark(sorg(flipshs[i])), pointmark(sdest(flipshs[i])),
                     pointmark(sapex(flipshs[i])));
            }
            stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
            scount++;
          } else {
            spivot = i;
          }
        }
      }
    
      // Re-use fliptets[0] and fliptets[1].
      fliptets[0].ver = 11;
      fliptets[1].ver = 11;
      setelemmarker(fliptets[0].tet, 0); // Clear all flags.
      setelemmarker(fliptets[1].tet, 0);
      if (checksubsegflag) {
        // Dealloc the space to subsegments.
        if (fliptets[0].tet[8] != NULL) {
          tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
          fliptets[0].tet[8] = NULL;
        }
        if (fliptets[1].tet[8] != NULL) {
          tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
          fliptets[1].tet[8] = NULL;
        }
      }
      if (checksubfaceflag) {
        // Dealloc the space to subfaces.
        if (fliptets[0].tet[9] != NULL) {
          tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
          fliptets[0].tet[9] = NULL;
        }
        if (fliptets[1].tet[9] != NULL) {
          tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
          fliptets[1].tet[9] = NULL;
        }
      }
    
      // Delete an old tet.
      tetrahedrondealloc(fliptets[2].tet);
    
      if (hullflag > 0) {
        // Check if c is dummypointc.
        if (pc != dummypoint) {
          // Check if d is dummypoint.
          if (pd != dummypoint) {
            // No hull tet is involved.
          } else {
            // We deleted three hull tets, and created one hull tet.
            hullsize -= 2;
          }
          setvertices(fliptets[0], pa, pb, pc, pd);
          setvertices(fliptets[1], pb, pa, pc, pe);
        } else {
          // c is dummypoint. The two new tets are hull tets.
          setvertices(fliptets[0], pb, pa, pd, pc);
          setvertices(fliptets[1], pa, pb, pe, pc);
          // Adjust badc -> abcd.
          esymself(fliptets[0]);
          // Adjust abec -> bace.
          esymself(fliptets[1]);
          // The hullsize does not changle.
        }
      } else {
        setvertices(fliptets[0], pa, pb, pc, pd);
        setvertices(fliptets[1], pb, pa, pc, pe);
      }
    
      if (calc_tetprism_vol) {
        if (pc != dummypoint) {
          if (pd != dummypoint) {
            volneg[0] = tetprismvol(pe, pd, pa, pb);
            volneg[1] = tetprismvol(pe, pd, pb, pc);
            volneg[2] = tetprismvol(pe, pd, pc, pa);
            volpos[0] = tetprismvol(pa, pb, pc, pd);
            volpos[1] = tetprismvol(pb, pa, pc, pe);
          } else { // pd == dummypoint
            volneg[0] = 0.;
            volneg[1] = 0.;
            volneg[2] = 0.;
            volpos[0] = 0.;
            volpos[1] = tetprismvol(pb, pa, pc, pe);
          }
        } else { // pc == dummypoint.
          volneg[0] = tetprismvol(pe, pd, pa, pb);
          volneg[1] = 0.;
          volneg[2] = 0.;
          volpos[0] = 0.;
          volpos[1] = 0.;
        }
        vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
        tetprism_vol_sum  += vol_diff; // Update the total sum.
      }
    
      // Bond abcd <==> bace.
      bond(fliptets[0], fliptets[1]);
      // Bond new faces to top outer boundary faces (at abcd).
      for (i = 0; i < 3; i++) {
        esym(fliptets[0], newface);
        bond(newface, topcastets[i]);
        enextself(fliptets[0]);
      }
      // Bond new faces to bottom outer boundary faces (at bace).
      for (i = 0; i < 3; i++) {
        esym(fliptets[1], newface);
        bond(newface, botcastets[i]);
        eprevself(fliptets[1]);
      }
    
      if (checksubsegflag) {
        // Bond segments to new (flipped) tets.
        for (i = 0; i < 3; i++) {
          tsspivot1(topcastets[i], checkseg);
          if (checkseg.sh != NULL) {
            tssbond1(fliptets[0], checkseg);
            sstbond1(checkseg, fliptets[0]);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
          enextself(fliptets[0]);
        }
        // The three top edges.
        for (i = 0; i < 3; i++) {
          esym(fliptets[0], newface);
          eprevself(newface); // edge b->d, c->d, a->d.
          enext(topcastets[i], casface);
          tsspivot1(casface, checkseg);
          if (checkseg.sh != NULL) {
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
          enextself(fliptets[0]);
        }
        // Process the bottom tet bace.
        for (i = 0; i < 3; i++) {
          tsspivot1(botcastets[i], checkseg);
          if (checkseg.sh != NULL) {
            tssbond1(fliptets[1], checkseg);
            sstbond1(checkseg, fliptets[1]);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
          eprevself(fliptets[1]);
        }
        // The three bot edges.
        for (i = 0; i < 3; i++) {
          esym(fliptets[1], newface);
          enextself(newface); // edge b<-e, c<-e, a<-e.
          eprev(botcastets[i], casface);
          tsspivot1(casface, checkseg);
          if (checkseg.sh != NULL) {
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
          eprevself(fliptets[1]);
        }
      }
    
      if (checksubfaceflag) {
        // Bond the top three casing subfaces.
        for (i = 0; i < 3; i++) {
          tspivot(topcastets[i], checksh);
          if (checksh.sh != NULL) {
            esym(fliptets[0], newface); // At edge [b,a], [c,b], [a,c]
            sesymself(checksh);
            tsbond(newface, checksh);
            if (chkencflag & 2) {
              if (!smarktest2ed(checksh)) {
                bface = (badface *) badsubfacs->alloc();
                bface->ss = checksh;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checksh); // An alive badface
              }
            }
          }
          enextself(fliptets[0]);
        }
        // Bond the bottom three casing subfaces.
        for (i = 0; i < 3; i++) {
          tspivot(botcastets[i], checksh);
          if (checksh.sh != NULL) {
            esym(fliptets[1], newface); // // At edge [a,b], [b,c], [c,a]
            sesymself(checksh);
            tsbond(newface, checksh);
            if (chkencflag & 2) {
              if (!smarktest2ed(checksh)) {
                bface = (badface *) badsubfacs->alloc();
                bface->ss = checksh;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checksh); // An alive badface
              }
            }
          }
          eprevself(fliptets[1]);
        }
      }
    
      if (checksubfaceflag) {
        if (scount > 0) {
          assert(spivot != -1); // spivot = i, in {0,1,2}
          // Perform a 2-to-2 flip in subfaces.
          flipfaces[0] = flipshs[(spivot + 1) % 3];
          flipfaces[1] = flipshs[(spivot + 2) % 3];
          sesymself(flipfaces[1]);
          flip22(flipfaces, 0, chkencflag);
          // Connect the flipped subfaces to flipped tets.
          // First go to the corresponding flipping edge.
          //   Re-use top- and botcastets[0].
          topcastets[0] = fliptets[0];
          botcastets[0] = fliptets[1];
          for (i = 0; i < ((spivot + 1) % 3); i++) {
            enextself(topcastets[0]);
            eprevself(botcastets[0]);
          }
          // Connect the top subface to the top tets.
          esymself(topcastets[0]);
          sesymself(flipfaces[0]);
          // Check if there already exists a subface.
          tspivot(topcastets[0], checksh);
          if (checksh.sh == NULL) {
            tsbond(topcastets[0], flipfaces[0]);
            fsymself(topcastets[0]);
            sesymself(flipfaces[0]);
            tsbond(topcastets[0], flipfaces[0]);
          } else {
            // Found two subfaces are duplicated at the same tet face. 
            //   Due to the same reason explained below.
            assert(sapex(checksh) == sapex(flipfaces[0]));
            sspivot(checksh, checkseg);
            assert(checkseg.sh == NULL);
            // Delete the two duplicated subfaces.
            rempt = sapex(checksh);
            if (b->verbose > 2) {
              printf("      Remove vertex %d from surface.\n", pointmark(rempt));
            }
            // Make sure we do not delete a Steiner points in segment.
            assert(pointtype(rempt) == FREEFACETVERTEX);
            setpointtype(rempt, FREEVOLVERTEX);
            // Re-use flipshs.
            //spivot(checksh, flipshs[0]);
            flipshs[0] = checksh; 
            spivotself(flipshs[0]);
            if (flipshs[0].sh == flipfaces[0].sh) {
              sesym(checksh, flipshs[0]);
              spivotself(flipshs[0]);
            }
            assert(flipshs[0].sh != flipfaces[0].sh);
            //spivot(flipfaces[0], flipshs[1]);
            flipshs[1] = flipfaces[0];
            spivotself(flipshs[1]);
            if (flipshs[1].sh == checksh.sh) {
              sesym(flipfaces[0], flipshs[1]);
              spivotself(flipshs[1]);
            }
            assert(flipshs[1].sh != checksh.sh);
            // Bond the two subfaces together.
            sbond(flipshs[0], flipshs[1]);
            // Detach 'checksh' from the adjacent tets.
            tsdissolve(topcastets[0]);
            fsymself(topcastets[0]);
            tsdissolve(topcastets[0]);
            // Delete the two duplicated subfaces.
            shellfacedealloc(subfaces, checksh.sh);
            shellfacedealloc(subfaces, flipfaces[0].sh);
          }
          // // Push topcastets[0] into queue for checking new sliver.
          // assert(oppo(topcastets[0]) != dummypoint);
          // flippush(&(topcastets[0]), oppo(topcastets[0]));
          // Connect the bot subface to the bottom tets.
          esymself(botcastets[0]);
          sesymself(flipfaces[1]);
          // Check if there already exists a subface.
          tspivot(botcastets[0], checksh);
          if (checksh.sh == NULL) {
            tsbond(botcastets[0], flipfaces[1]);
            fsymself(botcastets[0]);
            sesymself(flipfaces[1]);
            tsbond(botcastets[0], flipfaces[1]);
          } else {
            // Found two subfaces are duplicated at the same tet face. 
            assert(sapex(checksh) == sapex(flipfaces[1]));
            // This happens in case when a Steiner point is not exactly coplanar
            //   or collinear with the subface or subedge where it was added.
            //   See figs illustrated in 2011-11-09.
            sspivot(checksh, checkseg);
            assert(checkseg.sh == NULL); 
            // Since the edge [p,q] is not a segment, both subfaces must be 
            //   removed. The effect is that the Steiner point is removed from
            //   the surface triangulation.
            // Delete the two duplicated subfaces.
            rempt = sapex(checksh);
            if (b->verbose > 2) {
              printf("      Remove vertex %d from surface.\n", pointmark(rempt));
            }
            // Make sure we do not delete a Steiner points in segment.
            assert(pointtype(rempt) == FREEFACETVERTEX);
            setpointtype(rempt, FREEVOLVERTEX);
            // Re-use flipshs.
            //spivot(checksh, flipshs[0]);
            flipshs[0] = checksh;
            spivotself(flipshs[0]);
            if (flipshs[0].sh == flipfaces[1].sh) {
              sesym(checksh, flipshs[0]);
              spivotself(flipshs[0]);
            }
            assert(flipshs[0].sh != flipfaces[1].sh);
            //spivot(flipfaces[1], flipshs[1]);
            flipshs[1] = flipfaces[1];
            spivotself(flipshs[1]);
            if (flipshs[1].sh == checksh.sh) {
              sesym(flipfaces[1], flipshs[1]);
              spivotself(flipshs[1]);
            }
            assert(flipshs[1].sh != checksh.sh);
            // Bond the two subfaces together.
            sbond(flipshs[0], flipshs[1]);
            // Detach 'checksh' from the adjacent tets.
            tsdissolve(botcastets[0]);
            fsymself(botcastets[0]);
            tsdissolve(botcastets[0]);
            // Delete the two duplicated subfaces.
            shellfacedealloc(subfaces, checksh.sh);
            shellfacedealloc(subfaces, flipfaces[1].sh);
          }
          // // Push botcastets[0] into queue for checking new sliver.
          // assert(oppo(botcastets[0]) != dummypoint);
          // flippush(&(botcastets[0]), oppo(botcastets[0]));
        }
      }
    
      if (chkencflag & 4) {
        // Put two new tets into check list.
        for (i = 0; i < 2; i++) {
          if (!marktest2ed(fliptets[i])) {
            bface = (badface *) badtetrahedrons->alloc();
            bface->tt = fliptets[i];
            marktest2(bface->tt);
            bface->forg = org(fliptets[i]);
          }
        }
      }
    
      setpoint2tet(pa, encode(fliptets[0]));
      setpoint2tet(pb, encode(fliptets[0]));
      setpoint2tet(pc, encode(fliptets[0]));
      setpoint2tet(pd, encode(fliptets[0]));
      setpoint2tet(pe, encode(fliptets[1]));
    
      if (hullflag > 0) {
        if (dummyflag != 0) {
          // Restore the original position of the points (for flipnm()).
          if (dummyflag == -1) {
            // e were dummypoint. Swap the two new tets.
            newface = fliptets[0];
            fliptets[0] = fliptets[1];
            fliptets[1] = newface;
          } else {
            // a or b was dummypoint.
            if (dummyflag == 1) {
              eprevself(fliptets[0]);
              enextself(fliptets[1]);
            } else { // dummyflag == 2
              enextself(fliptets[0]);
              eprevself(fliptets[1]);
            }
          }
        }
      }
      
      if (flipflag > 0) {
        // Queue faces which may be locally non-Delaunay.
        // pa = org(fliptets[0]); // 'a' may be a new vertex.
        enextesym(fliptets[0], newface);
        flippush(flipstack, &newface);
        eprevesym(fliptets[1], newface);
        flippush(flipstack, &newface);
        if (flipflag > 1) {
          //pb = dest(fliptets[0]);
          eprevesym(fliptets[0], newface);
          flippush(flipstack, &newface);
          enextesym(fliptets[1], newface);
          flippush(flipstack, &newface);
          //pc = apex(fliptets[0]);
          esym(fliptets[0], newface);
          flippush(flipstack, &newface);
          esym(fliptets[1], newface);
          flippush(flipstack, &newface);
        }
      }
    
      recenttet = fliptets[0];
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flip41()    Perform a 4-to-1 flip (Remove a vertex).                      //
    //                                                                           //
    // 'fliptets' is an array of four tetrahedra in the star of the removing     //
    // vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
    // four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
    // p].  On return, 'fliptets[0]' is the new tet [a,b,c,d].                   //
    //                                                                           //
    // If 'hullflag' is set (> 0), one of the four vertices may be 'duumypoint'. //
    // The 'hullsize' may be changed.                                            //
    //                                                                           //
    // If 'checksubface' flag is set (>0), it is possible that there are three   //
    // interior subfaces connecting at p.  If so, a 3-to-1 flip is performed to  //
    // to remove p from the surface triangulation.                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
                            int chkencflag)
    {
      triface topcastets[3], botcastet;
      triface newface, neightet;
      face flipshs[4];
      face checksh;
      face checkseg;
      point pa, pb, pc, pd, pp;
      badface *bface; // used by chkencflag
      REAL volneg[4], volpos[1], vol_diff; // volumes of involved tet-prisms.
      int dummyflag = 0; // in {0, 1, 2, 3, 4}
      int spivot = -1, scount = 0;
      int i;
    
      pa =  org(fliptets[3]);
      pb = dest(fliptets[3]);
      pc = apex(fliptets[3]);
      pd = dest(fliptets[0]);
      pp =  org(fliptets[0]); // The removing vertex.
    
      if (b->verbose > 3) {
        printf("        flip 4-to-1: (%d, %d, %d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pp));
      }
      // flip41count++;
    
      // Get the outer boundary faces.
      for (i = 0; i < 3; i++) {
        enext(fliptets[i], topcastets[i]);
        fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
        enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
      }
      fsym(fliptets[3], botcastet); // [b,a,c,#]
    
      if (checksubfaceflag) {
        // Check if there are three subfaces at 'p'.
        //   Re-use 'newface'.
        spivot = -1;
        scount = 0;
        for (i = 0; i < 3; i++) {
          fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
          tspivot(newface, flipshs[i]);
          if (flipshs[i].sh != NULL) {
            spivot = i; // Remember this subface.
            scount++;
          }
          enextself(fliptets[3]);
        }
        if (scount > 0) {
          // There are three subfaces connecting at p.
          if (scount < 3) {
            // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
            assert(scount == 1); // spivot >= 0
            // Go to the tet containing the three subfaces.
            fsym(topcastets[spivot], neightet);
            // Get the three subfaces connecting at p.
            for (i = 0; i < 3; i++) {
              esym(neightet, newface);
              tspivot(newface, flipshs[i]);
              assert(flipshs[i].sh != NULL);
              eprevself(neightet);
            }
          } else {
            spivot = 3; // The new subface is [a,b,c].
          }
        }
      } // if (checksubfaceflag)
    
      // Re-use fliptets[0] for [a,b,c,d].
      fliptets[0].ver = 11;
      setelemmarker(fliptets[0].tet, 0); // Clean all flags.
      if (checksubsegflag) {
        // Dealloc the space to subsegments.
        if (fliptets[0].tet[8] != NULL) {
          tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
          fliptets[0].tet[8] = NULL;
        }
      }
      if (checksubfaceflag) {
        // Dealloc the space to subfaces.
        if (fliptets[0].tet[9] != NULL) {
          tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
          fliptets[0].tet[9] = NULL;
        }
      }
    
      // Delete the other three tets.
      for (i = 1; i < 4; i++) {
        tetrahedrondealloc(fliptets[i].tet);
      }
    
      // Mark the point pp as unused.
      setpointtype(pp, UNUSEDVERTEX);
      unuverts++;
    
      // Create the new tet [a,b,c,d].
      if (hullflag > 0) {
        // One of the four vertices may be 'dummypoint'.
        if (pa == dummypoint) {
          // pa is dummypoint.
          setvertices(fliptets[0], pc, pb, pd, pa);
          esymself(fliptets[0]);  // [b,c,a,d]
          eprevself(fliptets[0]); // [a,b,c,d]
          dummyflag = 1;
        } else if (pb == dummypoint) {
          setvertices(fliptets[0], pa, pc, pd, pb);
          esymself(fliptets[0]);  // [c,a,b,d]
          enextself(fliptets[0]); // [a,b,c,d]
          dummyflag = 2;
        } else if (pc == dummypoint) {
          setvertices(fliptets[0], pb, pa, pd, pc);
          esymself(fliptets[0]);  // [a,b,c,d]
          dummyflag = 3;
        } else if (pd == dummypoint) {
          setvertices(fliptets[0], pa, pb, pc, pd);
          dummyflag = 4;
        } else {
          setvertices(fliptets[0], pa, pb, pc, pd);
          dummyflag = 0;
        }
        if (dummyflag > 0) {
          // We delete 3 hull tets, and create 1 hull tet.
          hullsize -= 2;
        }
      } else {
        setvertices(fliptets[0], pa, pb, pc, pd);
      }
    
      if (calc_tetprism_vol) {
        if (dummyflag > 0) {
          if (pa == dummypoint) {
            volneg[0] = 0.;
            volneg[1] = tetprismvol(pp, pd, pb, pc);
            volneg[2] = 0.;
            volneg[3] = 0.;
          } else if (pb == dummypoint) {
            volneg[0] = 0.;
            volneg[1] = 0.;
            volneg[2] = tetprismvol(pp, pd, pc, pa);
            volneg[3] = 0.;
          } else if (pc == dummypoint) {
            volneg[0] = tetprismvol(pp, pd, pa, pb);
            volneg[1] = 0.;
            volneg[2] = 0.;
            volneg[3] = 0.;
          } else { // pd == dummypoint
            volneg[0] = 0.;
            volneg[1] = 0.;
            volneg[2] = 0.;
            volneg[3] = tetprismvol(pa, pb, pc, pp);
          }
          volpos[0] = 0.;
        } else {
          volneg[0] = tetprismvol(pp, pd, pa, pb);
          volneg[1] = tetprismvol(pp, pd, pb, pc);
          volneg[2] = tetprismvol(pp, pd, pc, pa);
          volneg[3] = tetprismvol(pa, pb, pc, pp);
          volpos[0] = tetprismvol(pa, pb, pc, pd);
        }
        vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
        tetprism_vol_sum  += vol_diff; // Update the total sum.
      }
    
      // Bond the new tet to adjacent tets.
      for (i = 0; i < 3; i++) {
        esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
        bond(newface, topcastets[i]);
        enextself(fliptets[0]);
      }
      bond(fliptets[0], botcastet);
    
      if (checksubsegflag) {
        // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
        for (i = 0; i < 3; i++) {
          eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
          tsspivot1(newface, checkseg);
          if (checkseg.sh != NULL) {
            esym(fliptets[0], newface);
            enextself(newface); // At edges [a,d], [b,d], [c,d].
            tssbond1(newface, checkseg);
            sstbond1(checkseg, newface);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
          enextself(fliptets[0]);
        }
        for (i = 0; i < 3; i++) {
          tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
          if (checkseg.sh != NULL) {
            tssbond1(fliptets[0], checkseg);
            sstbond1(checkseg, fliptets[0]);
            if (chkencflag & 1) {
              // Skip it if it has already queued.
              if (!smarktest2ed(checkseg)) {
                bface = (badface *) badsubsegs->alloc();
                bface->ss = checkseg;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checkseg); // An alive badface.
              }
            }
          }
          enextself(fliptets[0]);
        }
      }
    
      if (checksubfaceflag) {
        // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
        for (i = 0; i < 3; i++) {
          tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
          if (checksh.sh != NULL) {
            esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
            sesymself(checksh);
            tsbond(newface, checksh);
            if (chkencflag & 2) {
              if (!smarktest2ed(checksh)) {
                bface = (badface *) badsubfacs->alloc();
                bface->ss = checksh;
                smarktest2(bface->ss); // Only queue it once.
                bface->forg = sorg(checksh); // An alive badface
              }
            }
          }
          enextself(fliptets[0]);
        }
        tspivot(botcastet, checksh); // At face [b,a,c]
        if (checksh.sh != NULL) {
          sesymself(checksh);
          tsbond(fliptets[0], checksh);
          if (chkencflag & 2) {
            if (!smarktest2ed(checksh)) {
              bface = (badface *) badsubfacs->alloc();
              bface->ss = checksh;
              smarktest2(bface->ss); // Only queue it once.
              bface->forg = sorg(checksh); // An alive badface
            }
          }
        }
      }
    
      if (checksubfaceflag) {
        if (spivot >= 0) {
          // Perform a 3-to-1 flip in surface triangulation.
          // Depending on the value of 'spivot', the three subfaces are:
          //   - 0: [a,b,p], [b,d,p], [d,a,p]
          //   - 1: [b,c,p], [c,d,p], [d,b,p] 
          //   - 2: [c,a,p], [a,d,p], [d,c,p] 
          //   - 3: [a,b,p], [b,c,p], [c,a,p]
          // Adjust the three subfaces such that their origins are p, i.e., 
          //   - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
          for (i = 0; i < 3; i++) {
            senext2self(flipshs[i]);
          }
          flip31(flipshs, 0);
          // Delete the three old subfaces.
          for (i = 0; i < 3; i++) {
            shellfacedealloc(subfaces, flipshs[i].sh);
          }
          if (spivot < 3) {
            // // Bond the new subface to the new tet [a,b,c,d].
            tsbond(topcastets[spivot], flipshs[3]);
            fsym(topcastets[spivot], newface);
            sesym(flipshs[3], checksh);
            tsbond(newface, checksh);
          } else {
            // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
            tsbond(fliptets[0], flipshs[3]);
            fsym(fliptets[0], newface);
            sesym(flipshs[3], checksh);
            tsbond(newface, checksh);
          }
        } // if (spivot > 0)
      } // if (checksubfaceflag)
    
      if (chkencflag & 4) {
        // Put the new tet into check list.
        if (!marktest2ed(fliptets[0])) {
          bface = (badface *) badtetrahedrons->alloc();
          bface->tt = fliptets[0];
          marktest2(bface->tt);
          bface->forg = org(fliptets[0]);
        }
      }
    
      // Update the point-to-tet map.
      setpoint2tet(pa, encode(fliptets[0]));
      setpoint2tet(pb, encode(fliptets[0]));
      setpoint2tet(pc, encode(fliptets[0]));
      setpoint2tet(pd, encode(fliptets[0]));
    
      if (flipflag > 0) {
        // Queue faces which may be locally non-Delaunay.
        for (i = 0; i < 3; i++) {
          esym(fliptets[0], newface);
          flippush(flipstack, &newface);
          enextself(fliptets[0]);
        }
        flippush(flipstack, &(fliptets[0]));
      }
    
      recenttet = fliptets[0];
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flipnm()    Try to flip an edge through a sequence of elementary flips.   //
    //                                                                           //
    // 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
    // ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
    // use the right-hand rule.                                                  //
    //                                                                           //
    // 'level' (>= 0) indicates the current link level. If 'level > 0', we are   //
    // flipping a link edge of an edge [a',b'],  and 'abedgepivot' indicates     //
    // which link edge, i.e., [c',b'] or [a',c'], is [a,b]  These two parameters //
    // allow us to determine the new tets after a 3-to-2 flip, i.e., tets that   //
    // do not inside the reduced star of edge [a',b'].                           //
    //                                                                           //
    // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
    // in flipnm([a,b]) so that the mesh is returned to its original state       //
    // before doing the flipnm([a,b]) operation.                                 //
    //                                                                           //
    // The return value is an integer nn, where nn <= n.  If nn is 2, then the   //
    // edge is flipped.  The first and the second tets in 'abtets' are new tets. //
    // Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets  //
    // in the current star of [a,b].                                             //
    //                                                                           //
    // ASSUMPTIONS:                                                              //
    //  - Neither a nor b is 'dummypoint'.                                       //
    //  - [a,b] must not be a segment.                                           //
    //                                                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
                           flipconstraints* fc)
    {
      triface fliptets[3], spintet, flipedge;
      triface *tmpabtets, *parytet;
      face checksh;
      face checkseg, *paryseg;
      point pa, pb, pc, pd, pe, pf;
      point tmppts[3];
      REAL abovept[3];
      REAL ori, ori1, ori2;
      int reducflag, rejflag;
      int hullflag;
      int reflexlinkedgecount;
      int edgepivot;
      int n1, nn;
      int i, j;
    
      pa = org(abtets[0]);
      pb = dest(abtets[0]);
    
      if (b->verbose > 2) {
        printf("      flipnm(%d): (%d, %d) - n(%d), e(%d).\n", level, pointmark(pa),
               pointmark(pb), n, abedgepivot);
      }
    
      if (n > 3) {
        // Try to reduce the size of the Star(ab) by flipping a face in it. 
        reflexlinkedgecount = 0;
    
        for (i = 0; i < n; i++) {
          // Let the face of 'abtets[i]' be [a,b,c].
          if (checksubfaceflag) {
            // Do not flip this face if it is a constraining face.
            tspivot(abtets[i], checksh);
            if (checksh.sh != NULL) {
              continue; // Skip a subface.
            }
          }
          // Do not flip this face if it is involved in two Stars.
          if ((elemcounter(abtets[i]) > 1) ||
              (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
            continue;
          }
          pc = apex(abtets[i]); 
          pd = apex(abtets[(i + 1) % n]);
          pe = apex(abtets[(i - 1 + n) % n]);
          if ((pd == dummypoint) || (pe == dummypoint)) {
            // [a,b,c] is a hull face, it is not flipable.
            continue;
          }
          if (checkinverttetflag) {
            // The mesh contains inverted (or degenerated) elements.
            // Only do check if both elements are valid.
            if (pc != dummypoint) {
              ori = orient3d(pa, pb, pc, pd);
              if (ori < 0) {
                ori = orient3d(pb, pa, pc, pe);
              }
              if (ori >= 0) {
                continue; // An invalid tet.
              }
            } else {
              continue;
            }
          } // if (checkinverttetflag)
    
          reducflag = 0; // Not reducible.
    
          hullflag = (pc == dummypoint); // pc may be dummypoint.
          if (hullflag == 0) {
            ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
            if (ori > 0) {
              ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
              if (ori > 0) {
                // Test if [a,b] is locally convex OR flat.
                ori = orient3d(pa, pb, pd, pe);
                if (ori > 0) {
                  // Found a 2-to-3 flip: [a,b,c] => [e,d]
                  reducflag = 1;
                } else if (ori == 0) {
                  // [a,b] is flat.
                  if (n == 4) {
                    // The "flat" tet can be removed immedately by a 3-to-2 flip.
                    reducflag = 1;
                  }
                }
              }
            }
            if (!reducflag) {
              reflexlinkedgecount++;
            }
          } else {
            // 'c' is dummypoint.
            if (n == 4) {
              // Let the vertex opposite to 'c' is 'f'.
              // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
              //   are valid tets. 
              // Note: When the mesh is not convex, it is possible that [a,b] is
              //   locally non-convex (at hull faces [a,b,e] and [b,a,d]).
              //   In this case, an edge flip [a,b] to [e,d] is still possible.
              pf = apex(abtets[(i + 2) % n]);
              assert(pf != dummypoint);
              ori = orient3d(pd, pe, pf, pa);
              if (ori < 0) {
                ori = orient3d(pe, pd, pf, pb);
                if (ori < 0) {
                  // Found a 4-to-4 flip: [a,b] => [e,d]
                  reducflag = 1;
                  ori = 0; // Signal as a 4-to-4 flip (like a co-palanar case).
                }
              }
            }
          } // if (hullflag)
    
          if (reducflag) {
            // [a,b,c] could be removed by a 2-to-3 flip.
            rejflag = 0;
            if (fc != NULL) {
              // Check if the flip can be performed.
              rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
                                             abedgepivot, fc);
            }
            if (!rejflag) {
              // Do flip: [a,b,c] => [e,d].
              fliptets[0] = abtets[i];
              fsym(fliptets[0], fliptets[1]); // abtets[i-1].
              flip23(fliptets, hullflag, 0, 0);
    
              // Shrink the array 'abtets', maintain the original order.
              //   Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
              //   are flipped, i.e., they do not in Star(ab) anymore. 
              //   'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
              //   'abtets[i-1]' (adjust it to be [a,b,e,d]), see below: 
              // 
              //            before                   after
              //     [0] |___________|        [0] |___________| 
              //     ... |___________|        ... |___________|
              //   [i-1] |_[a,b,e,c]_|      [i-1] |_[a,b,e,d]_|
              //     [i] |_[a,b,c,d]_| -->    [i] |_[a,b,d,#]_|
              //   [i+1] |_[a,b,d,#]_|      [i+1] |_[a,b,#,*]_|
              //     ... |___________|        ... |___________|
              //   [n-2] |___________|      [n-2] |___________| 
              //   [n-1] |___________|      [n-1] |_[i]_2-t-3_|
              //
              eprevself(fliptets[0]);
              esymself(fliptets[0]);
              enextself(fliptets[0]); // [a,b,e,d]
              // Increase the counter of this new tet (it is in Star(ab)).
              increaseelemcounter(fliptets[0]); //marktest(fliptets[0]);
              abtets[(i - 1 + n) % n] = fliptets[0];
              for (j = i; j < n - 1; j++) {
                abtets[j] = abtets[j + 1];  // Upshift
              }
              // The last entry 'abtets[n-1]' is empty. It is used in two ways:
              //   (i) it remebers the vertex 'c' (in 'abtets[n-1].tet'), and
              //  (ii) it remebers the position [i] where this flip took place.
              // These informations let us to either undo this flip or recover
              //   the original edge link (for collecting new created tets).
              //abtets[n - 1] = fliptets[1]; // [e,d,b,c] is remebered.
              abtets[n - 1].tet = (tetrahedron *) pc;
              abtets[n - 1].ver = 0; // Clear it.
              // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
              // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
              abtets[n - 1].ver |= (1 << 4);
              // The poisition [i] of this flip is saved above the 7th bit.
              abtets[n - 1].ver |= (i << 6);
    
              if (fc->collectnewtets) {
                // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
                //   Re-use the global array 'cavetetlist'.
                for (j = 1; j < 3; j++) {
                  cavetetlist->newindex((void **) &parytet);
                  *parytet = fliptets[j]; // fliptets[1], fliptets[2].
                }
              }
    
              // Star(ab) is reduced. Try to flip the edge [a,b].
              nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
    
              if (nn > 2) {
                // The edge is not flipped.
                if (fc->unflip || (ori == 0)) {
                  // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to 
                  //   transform [e,d] => [a,b,c].
                  // 'ori == 0' means that the previous flip created a degenrated
                  //   tet. It must be removed. 
                  // Remeber that 'abtets[i-1]' is [a,b,e,d]. We can use it to
                  //   find another two tets [e,d,b,c] and [e,d,c,a].
                  fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
                  eprevself(fliptets[0]);
                  esymself(fliptets[0]);
                  enextself(fliptets[0]); // [e,d,a,b]
                  fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
                  fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
                  assert(apex(fliptets[0]) == oppo(fliptets[2])); // SELF_CHECK
                  // Restore the two original tets in Star(ab). 
                  flip32(fliptets, hullflag, 0, 0);
                  // Marktest the two restored tets in Star(ab).
                  for (j = 0; j < 2; j++) {
                    increaseelemcounter(fliptets[j]); //marktest(fliptets[j]);
                  }
                  // Expand the array 'abtets', maintain the original order.
                  for (j = n - 2; j>= i; j--) {
                    abtets[j + 1] = abtets[j];  // Downshift
                  }
                  // Insert the two new tets 'fliptets[0]' [a,b,c,d] and 
                  //  'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries, 
                  //  respectively.
                  esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
                  abtets[i] = fliptets[0]; // [a,b,c,d]
                  nn++;
                  if (fc->collectnewtets) {
                    // Pop two (flipped) tets from the stack.
                    cavetetlist->objects -= 2;
                  }
                } // if (upflip || (ori == 0))
              } // if (nn > 2)
    
              if (nn == 2) { //if ((nn == 2) || !fullsearch) {
                // The edge has been flipped.
                return nn;
              }
              if (!fc->unflip) {
                // The flips are not reversed. The current Star(ab) can not be
                //   further reduced. Return its size (# of tets).
                return nn; 
              }
              // unflip is set. 
              // Continue the search for flips.
            } else {
              if (b->verbose > 2) {
                printf("      -- Reject a 2-to-3 flip at star face (%d, %d, %d)",
                       pointmark(pa), pointmark(pb), pointmark(pc));
                printf(", link (%d)\n", level);
              }
              if (fc != NULL) {
                fc->rejf23count++;
              }
            } // if (rejflag)
          } // if (reducflag)
        } // i
    
        // The Star(ab) is not reduced. 
        if (reflexlinkedgecount > 0) {
          // There are reflex edges in the Link(ab).
          if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) || 
              ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
            // Record the largest level.
            if ((level + 1) > maxfliplinklevel) {
              maxfliplinklevel = level + 1;
            }
            if (fc != NULL) {
              // Increase the link level counter.
              if ((level + 1) > fc->maxflippedlinklevelcount) {
                fc->maxflippedlinklevelcount = level + 1;
              }
            }
            // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
            for (i = 0; i < n; i++) {
              // Do not flip this face [a,b,c] if there are two Stars involved.
              if ((elemcounter(abtets[i]) > 1) ||
                  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
                continue;
              }
              pc = apex(abtets[i]);
              if (pc == dummypoint) {
                continue; // [a,b,dummypoint] is a hull edge.
              }
              pd = apex(abtets[(i + 1) % n]);
              pe = apex(abtets[(i - 1 + n) % n]);
              if ((pd == dummypoint) || (pe == dummypoint)) {
                continue; // [a,b,c] is a hull face.
              }
              if (checkinverttetflag) {
                // The mesh contains inverted (or degenerated) elements.
                // Only do check if both elements are valid.
                // assert(pc != dummypoint);
                ori = orient3d(pa, pb, pc, pd);
                if (ori < 0) {
                  ori = orient3d(pb, pa, pc, pe);
                }
                if (ori >= 0) {
                  continue; // An invalid tet.
                }
              } // if (checkinverttetflag)
    
              edgepivot = 0; // No edge is selected yet.
    
              // Test if [b,c] is locally convex or flat.
              ori = orient3d(pb, pc, pd, pe);
              if (ori <= 0) {
                // Select the edge [c,b].
                enext(abtets[i], flipedge); // [b,c,a,d]
                edgepivot = 1;
              }
              if (!edgepivot) {
                // Test if [c,a] is locally convex or flat.
                ori = orient3d(pc, pa, pd, pe);
                if (ori <= 0) {
                  // Select the edge [a,c].
                  eprev(abtets[i], flipedge); // [c,a,b,d].
                  edgepivot = 2;
                }
              }
    
              if (!edgepivot) continue;
    
              // An edge is selected.
              if (checksubsegflag) {
                // Do not flip it if it is a segment.
                tsspivot1(flipedge, checkseg);
                if (checkseg.sh != NULL) {
                  if (b->verbose > 2) {
                    printf("      -- Can't flip a link(%d) segment (%d, %d).\n",
                      level, pointmark(org(flipedge)), pointmark(dest(flipedge)));
                  }
                  if (fc != NULL) {
                    fc->encsegcount++;
                    if (fc->collectencsegflag) {
                      if (!sinfected(checkseg)) {
                        // Queue this segment in list.
                        sinfect(checkseg);                
                        caveencseglist->newindex((void **) &paryseg);
                        *paryseg = checkseg;
                      }
                    }
                  }
                  continue;
                }
              }
    
              // Try to flip the selected edge ([c,b] or [a,c]).
              esymself(flipedge); 
              // Count the number of tets at the edge.
              n1 = 0;
              j = 0; // Sum of the star counters.
              spintet = flipedge;
              while (1) {
                n1++;
                j += (elemcounter(spintet)); //if (marktested(spintet)) j++;
                fnextself(spintet);
                if (spintet.tet == flipedge.tet) break;
              }
              assert(n1 >= 3);
              if (j > 2) {
                // The Star(flipedge) overlaps other Stars.
                continue; // Do not flip this edge.
              }
              // Only two tets can be marktested.
              assert(j == 2); 
    
              flipstarcount++;
              // Record the maximum star size.
              if (n1 > maxflipstarsize) {
                maxflipstarsize = n1;
              }
              if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
                // The star size exceeds the given limit (-LL__).
                skpflipstarcount++;
                continue; // Do not flip it.
              }
    
              // Allocate spaces for Star(flipedge).
              tmpabtets = new triface[n1];
              // Form the Star(flipedge).
              j = 0;
              spintet = flipedge;
              while (1) {
                tmpabtets[j] = spintet;
                // Increase the star counter of this tet.
                increaseelemcounter(tmpabtets[j]); 
                j++;
                fnextself(spintet);
                if (spintet.tet == flipedge.tet) break;
              }
              // SELF_CHECK BEGIN
              // These two tets are inside both of the Stars.
              assert(elemcounter(tmpabtets[0]) == 2);
              assert(elemcounter(tmpabtets[1]) == 2);
              // Marktest the tets in Star(flipedge) but not in Star(ab).
              for (j = 2; j < n1; j++) {
                assert(elemcounter(tmpabtets[j]) == 1);
                //marktest(tmpabtets[j]);
              }
    
              // Try to flip the selected edge away.
              nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
    
              if (nn == 2) {
                // The edge is flipped. Star(ab) is reduced.
                // Shrink the array 'abtets', maintain the original order.
                if (edgepivot == 1) {
                  // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
                  spintet = tmpabtets[0]; // [d,a,e,b]
                  enextself(spintet);
                  esymself(spintet);
                  enextself(spintet); // [a,b,e,d]
                } else {
                  // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
                  spintet = tmpabtets[1]; // [b,d,e,a]
                  eprevself(spintet);
                  esymself(spintet);
                  eprevself(spintet); // [a,b,e,d]
                } // edgepivot == 2
                //assert(!marktested(spintet)); // It's a new tet.
                assert(elemcounter(spintet) == 0);
                //marktest(spintet); // It is in Star(ab).
                increaseelemcounter(spintet);
                // Put the new tet at [i-1]-th entry.
                abtets[(i - 1 + n) % n] = spintet;
                for (j = i; j < n - 1; j++) {
                  abtets[j] = abtets[j + 1];  // Upshift
                }
                // Remember the flips in the last entry of the array 'abtets'.
                // They can be used to recover the flipped edge.
                abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
                abtets[n - 1].ver = 0; // Clear it.
                // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
                abtets[n - 1].ver |= edgepivot;
                // Use the 6th bit to signal this n1-to-m1 flip.
                abtets[n - 1].ver |= (1 << 5); 
                // The poisition [i] of this flip is saved from 7th to 19th bit.
                abtets[n - 1].ver |= (i << 6);
                // The size of the star 'n1' is saved from 20th bit.
                abtets[n - 1].ver |= (n1 << 19);
    
                // Remember the flipped link vertex 'c'. It can be used to recover
                //   the original edge link of [a,b], and to collect new tets.
                tmpabtets[0].tet = (tetrahedron *) pc;
                tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
    
                // Continue to flip the edge [a,b].
                nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
    
                if (nn > 2) {
                  // The edge is not flipped.
                  if (fc->unflip) {
                    // Recover the flipped edge ([c,b] or [a,c]).
                    assert(nn == (n - 1));
                    // The sequence of flips are saved in 'tmpabtets'. 
                    // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
                    //   the flipping of edge [c,b] or [a,c].It must still exist in
                    //   Star(ab). It is the start tet to recover the flipped edge.
                    if (edgepivot == 1) { 
                      // The flip edge is [c,b].
                      tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
                      eprevself(tmpabtets[0]);
                      esymself(tmpabtets[0]);
                      eprevself(tmpabtets[0]); // [d,a,e,b]
                      fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
                    } else {
                      // The flip edge is [a,c].
                      tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
                      enextself(tmpabtets[1]);
                      esymself(tmpabtets[1]);
                      enextself(tmpabtets[1]); // [b,d,e,a]
                      fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
                    } // if (edgepivot == 2)
    
                    // Recover the flipped edge ([c,b] or [a,c]).
                    flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
    
                    // Insert the two recovered tets into Star(ab).
                    for (j = n - 2; j >= i; j--) {
                      abtets[j + 1] = abtets[j];  // Downshift
                    }
                    if (edgepivot == 1) {
                      // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
                      // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
                      // tmpabtets[2] is [c,b,e,d]
                      fliptets[0] = tmpabtets[1];
                      enextself(fliptets[0]);
                      esymself(fliptets[0]); // [a,b,e,c]
                      fliptets[1] = tmpabtets[0];
                      esymself(fliptets[1]);
                      eprevself(fliptets[1]); // [a,b,c,d]
                    } else {
                      // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
                      // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
                      // tmpabtets[2] is [a,c,e,d]
                      fliptets[0] = tmpabtets[1];
                      eprevself(fliptets[0]);
                      esymself(fliptets[0]); // [a,b,e,c]
                      fliptets[1] = tmpabtets[0];
                      esymself(fliptets[1]);
                      enextself(fliptets[1]); // [a,b,c,d]
                    } // edgepivot == 2
                    for (j = 0; j < 2; j++) {
                      assert(elemcounter(fliptets[j]) == 0); // SELF_CHECK
                      increaseelemcounter(fliptets[j]);
                    }
                    // Insert the two recovered tets into Star(ab).
                    abtets[(i - 1 + n) % n] = fliptets[0];
                    abtets[i] = fliptets[1];
                    nn++;
                    // Release the allocated spaces.
                    delete [] tmpabtets;
                  } // if (unflip)
                } // if (nn > 2)
    
                if (nn == 2) { //if ((nn == 2) || !fullsearch) {
                  // The edge has been flipped.
                  return nn;
                }
                if (!fc->unflip) {
                  // The flips are not reversed. The current Star(ab) can not be
                  //   further reduced. Return its size (# of tets).
                  return nn; 
                }
                // unflip is set. 
                // Continue the search for flips.
              } else {
                // The seclected edge is not flipped.
                if (fc->unflip) {
                  // The memory should already be freed.
                  assert(nn == n1);
                } else {
                  // Release the memory used in this attempted flip.
                  flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
                }
                // Decrease the star counters of tets in Star(flipedge).
                for (j = 0; j < nn; j++) {
                  assert(elemcounter(tmpabtets[j]) > 0); // SELF_CHECK
                  decreaseelemcounter(tmpabtets[j]);
                }
                // Release the allocated spaces.
                delete [] tmpabtets;
              }
            } // i
          } else {
            if (b->verbose > 2) {
              printf("      -- Maximal link level (%d) reached at edge (%d, %d).\n",
                     level, pointmark(org(abtets[0])), pointmark(dest(abtets[0])));
            }
            if (fc != NULL) {
              fc->misfliplinklevelcount++;
            }
          } // if (level...)
        } // if (reflexlinkedgecount > 0)
      } else {
        // Check if a 3-to-2 flip is possible.
        pc = apex(abtets[0]);
        pd = apex(abtets[1]);
        pe = apex(abtets[2]);
    
        // Check if one of them is dummypoint. If so, we rearrange the vertices
        //   c, d, and e into p0, p1, and p2, such that p2 is the dummypoint.
        hullflag = 0;
        if (pc == dummypoint) {
          hullflag = 1;
          tmppts[0] = pd;
          tmppts[1] = pe;
          tmppts[2] = pc;
        } else if (pd == dummypoint) {
          hullflag = 1;
          tmppts[0] = pe;
          tmppts[1] = pc;
          tmppts[2] = pd;
        } else if (pe == dummypoint) {
          hullflag = 1;
          tmppts[0] = pc;
          tmppts[1] = pd;
          tmppts[2] = pe;
        } else {
          tmppts[0] = pc;
          tmppts[1] = pd;
          tmppts[2] = pe;
        }
    
        reducflag = 0;
        rejflag = 0;
    
        if (checkinverttetflag) {
          // Only do flip if no tet is inverted (or degenerated).
          if (hullflag == 0) {
            ori = orient3d(pa, pb, pc, pd);
            if (ori < 0) {
              ori = orient3d(pa, pb, pd, pe);
              if (ori < 0) {
                ori = orient3d(pa, pb, pe, pc);
              }
            }
          } else {
            ori = orient3d(pa, pb, tmppts[0], tmppts[1]);
          }
          if (ori >= 0) {
            if (b->verbose > 2) {
              printf("      -- Hit a non-valid tet (%d, %d) - (%d, %d, %d)",
                     pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
                     pointmark(pe));
              printf(" at link(%d)\n", level);
            }
            return 3;
          }
        } // if (checkinverttetflag)
    
        if (hullflag == 0) {
          // Make sure that no inverted tet will be created, i.e. the new tets
          //   [d,c,e,a] and [c,d,e,b] must be valid tets. 
          ori = orient3d(pd, pc, pe, pa);
          if (ori < 0) {
            ori = orient3d(pc, pd, pe, pb);
            if (ori < 0) {
              reducflag = 1;
            }
          } else {
            if (b->verbose > 2) {
              printf("      -- Hit a chrismastree (%d, %d) - (%d, %d, %d)",
                     pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
                     pointmark(pe));
              printf(" at link(%d)\n", level);
            }
            if (fc != NULL) {
              fc->chrismastreecount++;
            }
          }
        } else {
          // [a,b] is a hull edge. Moreover, the tet [a,b,p0,p1] is a hull tet
          //   ([a,b,p0] and [a,b,p1] are two hull faces). 
          //   This can happen when it is in the middle of a 4-to-4 flip.
          //   Note that [a,b] may even be a non-convex hull edge.
          if (!nonconvex) {
            // [a,b], [a,b,p0] and [a,b,p1] are on the convex hull.
            ori = orient3d(pa, pb, tmppts[0], tmppts[1]);
            if (ori == 0) {
              // They four vertices are coplanar. A 2-to-2 flip is possible if
              //   [a,b] and [p0,p1] are intersecting each other. 
              // NOTE: The following test is not robust, should be replaced in 
              //   the future. 2011-12-01.
              calculateabovepoint4(pa, pb, tmppts[0], tmppts[1]);
              for (j = 0; j < 3; j++) {
                abovept[j] = dummypoint[j];
              }
              // Make sure that no inverted face will be created, i.e., [p1,p0,
              //   abvpt,pa] and [p0,p1,abvpt,pb] must be valid tets.
              ori1 = orient3d(tmppts[0], tmppts[1], abovept, pa);
              ori2 = orient3d(tmppts[0], tmppts[1], abovept, pb);
              if (ori1 * ori2 < 0) {
                reducflag = 1; // Flipable.
              }
              if (!reducflag) {
                if (b->verbose > 2) {
                  printf("      -- Hit a degenerate chrismastree (%d, %d)",
                         pointmark(pa), pointmark(pb));
                  printf(" - (%d, %d, -1) at link(%d)\n", 
                         pointmark(tmppts[0]), pointmark(tmppts[1]), level);
                }
                if (fc != NULL) {
                  fc->chrismastreecount++;
                }
              }
            } else {
              if (b->verbose > 2) {
                printf("      -- Hit a convex hull edge (%d, %d) at link(%d).\n",
                       pointmark(pa), pointmark(pb), level);
              }
              if (fc != NULL) {
                fc->convexhulledgecount++;
              }
            }
          } else { // if (nonconvex)
            // [a,b,p0] and [a,b,p1] must be two subfaces.
            // Since [a,b] is not a segment. A 3-to-2 flip (including a 2-to-2
            //   flip) is possible.
            // Here we only do flip if there are exactly three tets containing
            //   the edge [p0,p1]. In this case, the other two tets at [p0,p1]
            //   (not [a,b,p0,p1]) must be valid. Since they already exist.
            for (j = 0; j < 3; j++) {
              if (apex(abtets[j]) == dummypoint) {
                flipedge = abtets[(j + 1) % 3]; // [a,b,p0,p1].
                break;
              }
            }
            // assert(j < 3);
            eprevself(flipedge);
            esymself(flipedge);
            enextself(flipedge); // [p0,p1,a,b].
            assert(apex(flipedge) == pa);
            spintet = flipedge;
            j = 0;
            while (1) {
              j++;
              fnextself(spintet);
              if (spintet.tet == flipedge.tet) break;
            }
            if (j == 3) {
              reducflag = 1;
            } else {
              if (b->verbose > 2) {
                printf("      -- Hit a hull edge (%d, %d) at link(%d).\n",
                       pointmark(pa), pointmark(pb), level);
              }
              //if (fc != NULL) {
              //  fc->convexhulledgecount++;
              //}
            }
          }
        } // if (hullflag == 1)
    
        if (reducflag) {
          // A 3-to-2 flip is possible.
          if (checksubfaceflag) {
            // This edge (must not be a segment) can be flipped ONLY IF it belongs
            //   to either 0 or 2 subfaces.  In the latter case, a 2-to-2 flip in 
            //   the surface mesh will be automatically performed within the 
            //   3-to-2 flip.
            nn = 0;
            for (j = 0; j < 3; j++) {
              tspivot(abtets[j], checksh);
              if (checksh.sh != NULL) {
                nn++; // Found a subface.
              }
            }
            assert(nn < 3);
            if (nn == 1) {
              // Found only 1 subface containing this edge. This can happen in 
              //   the boundary recovery phase. The neighbor subface is not yet 
              //   recovered. This edge should not be flipped at this moment.
              rejflag = 1; 
            }
          }
          if (!rejflag && (fc != NULL)) {
            //rejflag = checkflipeligibility(2, tmppts[0], tmppts[1], tmppts[2], 
            //                               pa, pb, level, abedgepivot, fc);
            // Here we must permute 'a' and 'b'. Since in the check... function,
            //   we assume the following point sequence, 'a,b,c,d,e', where
            //   the face [a,b,c] will be flipped and the edge [e,d] will be
            //   created. The two new tets are [a,b,c,d] and [b,a,c,e]. 
            rejflag = checkflipeligibility(2, tmppts[0], tmppts[1], tmppts[2], 
                                           pb, pa, level, abedgepivot, fc);
          }
          if (!rejflag) {
            // Do flip: [a,b] => [c,d,e]
            flip32(abtets, hullflag, 0, 0);
            sucflipstarcount++;
            if (fc->remove_ndelaunay_edge) {
              if (level == 0) {
                // It is the desired removing edge.
                if (tetprism_vol_sum >= fc->bak_tetprism_vol) {
                  if (b->verbose > 2) {
                    printf("      -- Reject to flip (%d, %d) at link(%d)\n",
                           pointmark(pa), pointmark(pb), level);
                    printf("         due to an increased volume (%.17g).\n",
                           tetprism_vol_sum - fc->bak_tetprism_vol);
                  }
                  // flip back: [c,d,e] => [a,b].
                  flip23(abtets, hullflag, 0, 0);
                  // Increase the element counter -- They are in cavity.
                  for (j = 0; j < 3; j++) {
                    increaseelemcounter(abtets[j]); 
                  }
                  return 3;
                }
              } // if (level == 0)
            }
            if (fc->collectnewtets) {
              // Collect new tets.
              if (level == 0) {
                // Push the two new tets into stack.
                for (j = 0; j < 2; j++) {
                  cavetetlist->newindex((void **) &parytet);
                  *parytet = abtets[j];
                }
              } else {
                // Only one of the new tets is collected. The other one is inside
                //   the reduced edge star. 'abedgepivot' is either '1' or '2'.
                cavetetlist->newindex((void **) &parytet);
                if (abedgepivot == 1) { // [c,b]
                  *parytet = abtets[1];
                } else { 
                  assert(abedgepivot == 2); // [a,c]
                  *parytet = abtets[0];
                }
              }
            } // if (fc->collectnewtets)
            return 2;
          } else {
            if (b->verbose > 2) {
              printf("      -- Reject a 3-to-2 flip (%d, %d) at link(%d).\n",
                     pointmark(pa), pointmark(pb), level);
            }
            if (fc != NULL) {
              fc->rejf32count++;
            }
          } // if (rejflag)
        } // if (reducflag)
      } // if (n == 3)
    
      // The current (reduced) Star size.
      return n;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flipnm_post()    Post process a n-to-m flip.                              //
    //                                                                           //
    // IMPORTANT: This routine only works when there is no other flip operation  //
    // is done after flipnm([a,b]) which attempts to remove an edge [a,b].       //
    //                                                                           //
    // 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
    // [a,b] before flipnm([a,b]).  'nn' (< n) is the value returned by flipnm.  //
    // If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
    // are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
    // b] and its initial Star([a,b]).  If 'nn >= 3' edge [a,b] still exists in  //
    // current mesh and 'nn' is the current number of tets in Star([a,b]).       //
    //                                                                           //
    // Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a      //
    // flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet        //
    // 'abtets[t-1]', where '0 <= t <= i'.  These information can be used to     //
    // undo the flips performed in flipnm([a,b]) or to collect new tets created  //
    // by the flipnm([a,b]) operation.                                           //
    //                                                                           //
    // Default, this routine only walks through the flips and frees the spaces   //
    // allocated during the flipnm([a,b]) operation.                             //
    //                                                                           //
    // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
    // in flipnm([a,b]) so that the mesh is returned to its original state       //
    // before doing the flipnm([a,b]) operation.                                 //
    //                                                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
                                flipconstraints* fc)
    {
      triface fliptets[3], flipface;
      triface *tmpabtets;
      int fliptype;
      int edgepivot;
      int t, n1;
      int i, j;
    
    
      if (nn == 2) {
        // The edge [a,b] has been flipped.
        // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
        // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
        if (fc->unflip) {
          // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
          flip23(abtets, 1, 0, 0);
          if (fc->collectnewtets) {
            // Pop up new (flipped) tets from the stack.
            if (abedgepivot == 0) {
              // Two new tets were collected.
              cavetetlist->objects -= 2;
            } else {
              // Only one of the two new tets was collected.
              cavetetlist->objects -= 1;
            }
          }
        } 
        // The initial size of Star(ab) is 3.
        nn++;
      } else { // nn > 2.
        // The edge [a,b] exists.
      }
    
      // Walk through the performed flips.
      for (i = nn; i < n; i++) {
        // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
        // At the end of this step, the size of the Star([a,b]) is 'i+1'.
        // The sizes of the Link([a,b]) are the same.
        fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
        if (fliptype == 1) {
          // It was a 2-to-3 flip: [a,b,c]->[e,d].
          t = (abtets[i].ver >> 6);
          assert(t <= i);
          if (fc->unflip) {
            if (b->verbose > 2) {
              printf("      Recover a 2-to-3 flip at f[%d].\n", t);
            }
            // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
            //   it is created by a 2-to-3 flip [a,b,c] => [e,d].
            fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
            eprevself(fliptets[0]);
            esymself(fliptets[0]);
            enextself(fliptets[0]); // [e,d,a,b]
            fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
            fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
            // Do a 3-to-2 flip: [e,d] => [a,b,c].
            // NOTE: hull tets may be invloved.
            flip32(fliptets, 1, 0, 0);
            // Expand the array 'abtets', maintain the original order.
            // The new array length is (i+1).
            for (j = i - 1; j >= t; j--) {
              abtets[j + 1] = abtets[j];  // Downshift
            }
            // The tet abtets[(t-1)%i] is deleted. Insert the two new tets 
            //   'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
            //   the (t-1)-th and t-th entries, respectively.
            esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
            abtets[t] = fliptets[0]; // [a,b,c,d]
            if (fc->collectnewtets) {
              // Pop up two (flipped) tets from the stack.
              cavetetlist->objects -= 2;
            }
          } 
        } else if (fliptype == 2) {
          tmpabtets = (triface *) (abtets[i].tet);
          n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
          edgepivot = (abtets[i].ver & 3); 
          t = ((abtets[i].ver >> 6) & 8191);
          assert(t <= i);
          if (fc->unflip) {        
            if (b->verbose > 2) {
              printf("      Recover a %d-to-m flip at e[%d] of f[%d].\n", n1, 
                     edgepivot, t);
            }
            // Recover the flipped edge ([c,b] or [a,c]).
            // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
            //   the flipping of edge [c,b] or [a,c]. It must still exist in
            //   Star(ab). Use it to recover the flipped edge.
            if (edgepivot == 1) { 
              // The flip edge is [c,b].
              tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
              eprevself(tmpabtets[0]);
              esymself(tmpabtets[0]);
              eprevself(tmpabtets[0]); // [d,a,e,b]
              fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
            } else {
              // The flip edge is [a,c].
              tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
              enextself(tmpabtets[1]);
              esymself(tmpabtets[1]);
              enextself(tmpabtets[1]); // [b,d,e,a]
              fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
            } // if (edgepivot == 2)
    
            // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
            flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
    
            // Insert the two recovered tets into the original Star(ab).
            for (j = i - 1; j >= t; j--) {
              abtets[j + 1] = abtets[j];  // Downshift
            }
            if (edgepivot == 1) {
              // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
              // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
              // tmpabtets[2] is [c,b,e,d]
              fliptets[0] = tmpabtets[1];
              enextself(fliptets[0]);
              esymself(fliptets[0]); // [a,b,e,c]
              fliptets[1] = tmpabtets[0];
              esymself(fliptets[1]);
              eprevself(fliptets[1]); // [a,b,c,d]
            } else {
              // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
              // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
              // tmpabtets[2] is [a,c,e,d]
              fliptets[0] = tmpabtets[1];
              eprevself(fliptets[0]);
              esymself(fliptets[0]); // [a,b,e,c]
              fliptets[1] = tmpabtets[0];
              esymself(fliptets[1]);
              enextself(fliptets[1]); // [a,b,c,d]
            } // edgepivot == 2
            // Insert the two recovered tets into Star(ab).
            abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
            abtets[t] = fliptets[1];
          } 
          else {
            // Only free the spaces.
            flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
          } // if (!unflip)
          if (b->verbose > 2) {
            printf("      Release %d spaces at f[%d].\n", n1, i);
          }
          delete [] tmpabtets;
        } else {
          assert(fliptype == 0); // Not a saved flip.
          assert(0); // Should be not possible.
        }
      } // i
    
      return 1;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // lawsonflip3d()    A three-dimensional Lawson's flip algorithm.            //
    //                                                                           //
    // The basic idea of Lawson's algorithm is to flip every face of the triang- //
    // ulation which is not locally Delaunay until no such face exists, then the //
    // triangulation is a DT. However, in 3D, it is common that a face which is  //
    // not locally Delaunay and is not flippable. Hence, Laowson's algorithm may //
    // get stuck. It is still an open problem, whether there exists a flip algo- //
    // rithm which has a guarantee to create a DT in 3D.                         //
    //                                                                           //
    // If only one vertex is added into a DT, then Lawson's flip algorithm is    //
    // guaranteed to transform it into a new DT [Joe'91]. Moreover, an arbitrary //
    // order of flips is sufficient [Edelsbrunner & Shah'96].                    //
    //                                                                           //
    // In practice, it is desired to remove not locally Delaunay faces by flips  //
    // as many as possible. For this purpose, a second queue is used to store    //
    // the not locally Delaunay faces which are not flippable, and try them at a //
    // later time.                                                               //
    //                                                                           //
    // If 'newpt' (p) is not NULL, it is a new vertex just inserted into the     //
    // tetrahedralization T.                                                     //
    //                                                                           //
    // 'flipflag' indicates the property of the tetrahedralization 'T' which     //
    // does not include 'p' yet.                                                 //
    //                                                                           //
    // If 'peelsliverflag' is set, the purpose of calling Lawson's flip is to    //
    // remove "hull slivers". This flag only works with a non-convex mesh, i.e., //
    // the mesh must contains boundaries (segments and subfaces).                //
    //                                                                           //
    // 'chkencflag' indicates whether segments, subfaces, and tets should be     //
    //  checked (for encroaching and quality) after flips.                       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, 
                                  int chkencflag, int flipedgeflag)
    {
      badface *popface, *bface;
      triface fliptets[5], baktets[2];
      triface fliptet, neightet, *parytet;
      face checksh, *parysh;
      face checkseg, *paryseg;
      point *ppt, pd, pe, pf;
      long flipcount;
      REAL sign, ori;
      int convflag;
      int n, i;
    
      // For removing hull slivers.
      face neighsh; 
      point p1, p2;
      point pa, pb, pc, rempt;
      REAL ang; 
      long tetpeelcount; 
      int remflag;
    
      flipconstraints fc;
    
      if (b->verbose > 2) {
        printf("      Lawson flip %ld faces.\n", flippool->items);
      }
    
      flipcount = flip23count + flip32count + flip44count;
      tetpeelcount = opt_sliver_peels;
    
      if (flipedgeflag) {
        fc.remove_ndelaunay_edge = 1;
        fc.unflip = 1; // Unflip if the edge is not flipped.
        fc.collectnewtets = 1;
        assert(cavetetlist->objects == 0l);
        assert(calc_tetprism_vol == 1); // Swith on.
      } else {
        assert(unflipqueue->objects == 0); // The second queue must be empty.
      }
    
      while (1) {
    
        while (flipstack != (badface *) NULL) {
    
          // Pop a face from the stack.
          popface = flipstack;
          flipstack = flipstack->nextitem; // The next top item in stack.
          fliptet = popface->tt;
          flippool->dealloc((void *) popface);
    
          // Skip it if it is a dead tet (destroyed by previous flips).
          if (isdeadtet(fliptet)) continue;
          // Skip it if it is not the same tet as we saved.
          if (!facemarked(fliptet)) continue;
    
          unmarkface(fliptet);
    
          // FOR DEBUG
          if (flipflag == 1) {
            assert(oppo(fliptet) == newpt);
          }
    
          if (ishulltet(fliptet)) {
            // It is a hull tet.
            if (((flipflag == 4) || peelsliverflag) && !b->convex) {
              fliptet.ver = epivot[fliptet.ver & 3];
              if (oppo(fliptet) == dummypoint) {
                // It's a hull face (oppo(fliptet) == dummypoint).
                // Check if there exists a "hull sliver".
                fsymself(fliptet);
                tspivot(fliptet, checksh);
                assert(checksh.sh != NULL);
                for (i = 0; i < 3; i++) {
                  sspivot(checksh, checkseg);
                  if (checkseg.sh == NULL) {
                    spivot(checksh, neighsh);
                    assert(neighsh.sh != NULL);
                    if (sorg(checksh) != sdest(neighsh)) {
                      sesymself(neighsh);
                    }
                    stpivot(neighsh, neightet);
                    if (neightet.tet == fliptet.tet) {
                      // Found a hull sliver 'neightet' [d,e,a,b], where [d,e,a] 
                      //   and [e,d,b] are two hull faces. Normally, a 3-to-2 flip
                      //   (including a 2-to-2 flip on hull subfaces) can remove 
                      //   this hull sliver.
                      // A special case is the existence of a hull tet [b,a,d,-1]
                      //   or [a,b,e,-1]. It was creared by a previous hull tet
                      //   removal. Moreover, 'd' or 'e' might be Steiner points
                      //   on segments [a,b]. In this case, eithe [a,d],[b,d] or 
                      //   [a,e],[b,e] are subsegments. If so, a 4-to-1 flip
                      //   (including a 3-to-1, and maybe a 2-to-1 flip) should be
                      //   applied to remove an exterior vertex.
                      //   See figures (2011-11-13 and 15) for illustraions.
    
                      // First check if the face [b,a,d] is a hull face.
                      eprev(neightet, fliptets[0]);
                      esymself(fliptets[0]);  // [d,a,b,e]
                      enextself(fliptets[0]); // [a,b,d,e]
                      fsymself(fliptets[0]);  // [b,a,d,#]
                      if (oppo(fliptets[0]) != dummypoint) {
                        // Second check if the face [a,b,e] is a hull face.
                        enext(neightet, fliptets[0]);
                        esymself(fliptets[0]);  // [a,e,b,d]
                        eprevself(fliptets[0]); // [b,a,e,d]
                        fsymself(fliptets[0]);  // [b,a,e,#]
                      }
    
                      if (oppo(fliptets[0]) != dummypoint) {
                        // Make sure we do not create an "inverted triangle" in the
                        //   boundary, i.e., in exactly planar case, d and e must
                        //   lie in the different sides of the edge [a,b]. 
                        // If the dihedral angle formed by [a,b,e] and [a,b,d] is
                        //   larger than 90 degree, we can remove [a,b,e,d].  
                        fliptets[0] = neightet; // [e,d,a,b]
                        eprevself(fliptets[0]);
                        esymself(fliptets[0]);
                        enextself(fliptets[0]); // [a,b,e,d].
                        pa = org(fliptets[0]);
                        pb = dest(fliptets[0]);
                        p1 = apex(fliptets[0]); // pe
                        p2 = oppo(fliptets[0]); // pd
                        ang = facedihedral(pa, pb, p1, p2);
                        ang *= 2.0;
                        if (ang > PI) {
                          if (b->verbose > 2) {
                            printf("      Remove a hull sliver (%d, %d, %d, %d).\n",
                              pointmark(org(fliptet)), pointmark(dest(fliptet)),
                              pointmark(apex(fliptet)), pointmark(oppo(fliptet)));
                          }
                          // Remove the ill tet from bounday.
                          fliptets[0] = neightet;          // [e,d,a,b]
                          fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
                          fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
                          // FOR DEBUG
                          fnext(fliptets[2], fliptets[3]);
                          assert(fliptets[3].tet == neightet.tet);
                          assert(oppo(fliptets[1]) == dummypoint);
                          // Do a 3-to-2 flip to remove the ill tet. Two hull tets
                          // are removed toether. Two hull subfaces are flipped.
                          flip32(fliptets, 1, flipflag, 0);
                          // Update counters.
                          flip32count--;
                          flip22count--;
                          opt_sliver_peels++;
                        }
                      } else {
                        // There exists a thrid hull tet at vertex.
                        rempt = apex(fliptets[0]);
                        if (pointmark(rempt) > 
                          (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
                          if (pointtype(rempt) == FREESEGVERTEX) {
                            st_segref_count--;
                          } else if (pointtype(rempt) == FREEFACETVERTEX) {
                            st_facref_count--;
                          } else {
                            assert(0); // Impossible.
                          }
                          if (b->verbose > 2) {
                            printf("      Remove an exterior Steiner vertex %d.\n", 
                                   pointmark(rempt));
                          }
                          if (removevertexbyflips(rempt)) {
                            // exsteinercount++;
                          } else {
                            assert(0); // Not possible.
                          }
                        } else {
                          //if (b->verbose > 2) {
                          //  printf("      Remove an exterior input vertex %d.\n", 
                          //         pointmark(rempt));
                          //}
                          // Comment: We do not remove an input point.
                        }
                      }
                      break;
                    }
                  } // if (checkseg.sh == NULL)
                  senextself(checksh);
                } // i
              } else {
                // It's a hull edge.
                assert(apex(fliptet) == dummypoint);
                if (!peelsliverflag) { 
                  // The hull edge may be not locally Delaunay. Put interior
                  //   faces at this edge into 'flipstack' for flipping.
                  neightet = fliptet;  // [a,b,c,d] ('c' is dummypoint).
                  fnextself(neightet); // [a,b,d,#1] ([a,b,d] is a hull face).
                  while (1) {
                    fnextself(neightet); // [a,b,#1,#2]
                    if (oppo(neightet) != dummypoint) {
                      // It is an interior face.
                      flippush(flipstack, &neightet);
                    } else {
                      // We assume the interior of the domain is connected.
                      // Hence we can hit hull faces only twice.
                      break;
                    }
                  } // while (1)
                } // if (!peelsliverflag)
              }
            } // if ((flipflag == 4) || peelsliverflag)
    
            // Do not flip a hull face/edge UNLESS it is in the process of
            //   incrementally creating a DT in which the convex hull may be
            //   enlarged by the flips (when p lies outside of it).
            if (flipflag != 1) {
              continue;
            }
          } // if (ishulltet(fliptet))
    
          if (peelsliverflag) {
            continue; // Only check hull tets.
          }
    
          // Let 'fliptet' be [a,b,c,d], the face [a,b,c] is the flip face.
          // Get its opposite tet [b,a,c,e].
          fsym(fliptet, neightet);
    
          if (ishulltet(neightet)) {
            // It is a hull tet.
            if (flipflag == 1) {
              // Check if the new point is visible by the hull face.
              ppt = (point *) neightet.tet;
              ori = orient3d(ppt[4], ppt[5], ppt[6], newpt); orient3dcount++;
              if (ori < 0) {
                // Visible. Perform a 2-to-3 flip on the flip face.
                fliptets[0] = fliptet;  // [a,b,c,d], d = newpt.
                fliptets[1] = neightet; // [b,a,c,e], c = dummypoint.
                flip23(fliptets, 1, flipflag, chkencflag); // flip a hull tet.
                //recenttet = fliptets[0];
              } else if (ori == 0) {
                // Handle degenerate case ori == 0.
                if (oppo(neightet) == newpt) {
                  // Two hull tets have the same base face.
                  if (b->verbose > 2) {
                    printf("      Close an open face (%d, %d, %d)\n", 
                           pointmark(org(fliptet)), pointmark(dest(fliptet)),
                           pointmark(apex(fliptet)));
                  }
                  // The following code connect adjacent tets at corresponding
                  //   sides of the two hull tets. It is hard to understand.
                  //   See an example in 2011-11-11.
                  // First infect the two hull tets (they will be deleted).
                  infect(fliptet);
                  infect(neightet);
                  // Connect the actual adjacent tets.
                  for (i = 0; i < 3; i++) {
                    fnext(fliptet, fliptets[0]);
                    fnext(neightet, fliptets[1]);
                    if (!infected(fliptets[0])) {
                      assert(!infected(fliptets[1]));
                      bond(fliptets[0], fliptets[1]);
                      // Update the point-to-tet map.
                      pa = org(fliptet);
                      pb = dest(fliptet);
                      setpoint2tet(pa, encode(fliptets[0]));
                      setpoint2tet(pb, encode(fliptets[0]));
                      // Remeber a recent tet for point location.
                      recenttet = fliptets[0];
                      // apex(fliptets[0]) is the new point. The opposite face may
                      // be not locally Delaunay. Put it in flip stack.
                      assert(apex(fliptets[0]) == newpt); // SELF_CHECK
                      esymself(fliptets[0]);
                      flippush(flipstack, &(fliptets[0]));
                      assert(apex(fliptets[1]) == newpt); // SELF_CHECK
                      esymself(fliptets[1]);
                      flippush(flipstack, &(fliptets[1]));                  
                    }
                    enextself(fliptet);
                    eprevself(neightet);
                  }
                  // Delete the two tets.
                  tetrahedrondealloc(fliptet.tet);
                  tetrahedrondealloc(neightet.tet);
                  // Update the hull size.
                  hullsize -= 2;
                }
              }
            } // if (flipflag == 1)
     
            continue; // Do not flip a hull face.
          } // if (ishulltet(neightet))
    
          if (ishulltet(fliptet)) {
            continue; // Do not flip a hull tet.
          }
          
          if ((flipflag == 3) || (flipflag == 4)) {
            if (checksubfaceflag) {
              // Do not flip a subface.
              tspivot(fliptet, checksh);
              if (checksh.sh != NULL) {
                if (chkencflag & 2) {
                  // Mesh refinement.
                  // Put this subface into list.
                  if (!smarktest2ed(checksh)) {
                    bface = (badface *) badsubfacs->alloc();
                    bface->ss = checksh;
                    smarktest2(checksh); // Only queue it once.
                    bface->forg = sorg(checksh); // An alive badface.
                  }
                }
                continue;
              }
            }
          } // if ((flipflag == 3) || (flipflag == 4))
    
          ppt = (point *) fliptet.tet;
          pe = oppo(neightet);
    
          sign = insphere_s(ppt[4], ppt[5], ppt[6], ppt[7], pe);
    
          if (sign < 0) {
            if (b->verbose > 3) {
              printf("        A non-Delaunay face (%d, %d, %d) - %d, %d\n",
                     pointmark(org(fliptet)), pointmark(dest(fliptet)),
                     pointmark(apex(fliptet)), pointmark(oppo(fliptet)),
                     pointmark(pe));
            }
    
            // Try to flip this face.
            pd = oppo(fliptet);
            // Check the convexity of its three edges.
            convflag = 1;
            for (i = 0; i < 3; i++) {
              p1 = org(fliptet);
              p2 = dest(fliptet);
              ori = orient3d(p1, p2, pd, pe); orient3dcount++;
              if (ori < 0) {
                // A locally non-convex edge.
                convflag = -1;
                break;  
              } else if (ori == 0) {
                // A locally flat edge.
                convflag = 0;
                break;
              }
              enextself(fliptet);
            }
    
            if (convflag > 0) {
              // A 2-to-3 flip is found.
              fliptets[0] = fliptet; // abcd, d may be the new vertex.
              fliptets[1] = neightet; // bace.
              if ((flipflag == 1) || (flipflag == 2)) { // CDT boundary recovery.
                if (checksubfaceflag) {
                  // Check if a subface will be flipped.
                  tspivot(fliptets[0], checksh);
                  if (checksh.sh != NULL) {
                    assert(flipflag < 3); // 1 or 2.
                    // It is updateing a conforming DT or a CDT.
                    if (b->verbose > 3) {
                      printf("        Queue a flipped subface (%d, %d, %d).\n",
                             pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                             pointmark(sapex(checksh)));
                    }
                    for (i = 0; i < 2; i++) {
                      tsdissolve(fliptets[i]); // Disconnect the tet->sub bond.
                    }
                    stdissolve(checksh); // Disconnect the sub->tet bond.
                    // Add the missing subface into list.
                    subfacstack->newindex((void **) &parysh);
                    *parysh = checksh;
                  } // if (checksh.sh != NULL)
                }
              } // if ((flipflag == 1) || (flipflag == 2))
              flip23(fliptets, 0, flipflag, chkencflag);
              //recenttet = fliptets[0]; // for point location.
            } else {
              // The edge ('fliptet') is non-convex or flat.
              if ((flipflag == 3) || (flipflag == 4)) {
                // Do not flip a subsegment.
                tsspivot1(fliptet, checkseg);
                if (checkseg.sh != NULL) {
                  if (b->verbose > 3) {
                    printf("        Found a non-Delaunay segment (%d, %d).\n",
                           pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
                  }
                  // Comment: this should be only possible when a new Steiner
                  //   point is inserted on a segment nearby.
                  if (chkencflag & 1) {
                    // Put this segment into list.
                    if (!smarktest2ed(checkseg)) {
                      bface = (badface *) badsubsegs->alloc();
                      bface->ss = checkseg;
                      smarktest2(checkseg); // Only queue it once.
                      bface->forg = sorg(checkseg); // An alive badface.
                    }
                  }
                  continue;
                }
              }
    
              // A 3-to-2 or 4-to-4 may be possible.
              esym(fliptet, fliptets[0]); // [b,a,d,c]
              // assert(apex(fliptets[0]) == pd);
              n = 0;
              do {
                fnext(fliptets[n], fliptets[n + 1]);
                n++;
              } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
    
              if (n == 3) {
                // Found a 3-to-2 flip.
                if ((flipflag == 1) || (flipflag == 2)) { // CDT boundary recovery.
                  if (checksubsegflag) {
                    // Check if the flip edge is subsegment.
                    tsspivot1(fliptets[0], checkseg);
                    if (checkseg.sh != NULL) {
                      if (!sinfected(checkseg)) {
                        // This subsegment will be flipped. Queue it.
                        if (b->verbose > 3) {
                          printf("        Queue a flipped segment (%d, %d).\n",
                            pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
                        }
                        sinfect(checkseg);  // Only save it once.
                        subsegstack->newindex((void **) &paryseg);
                        *paryseg = checkseg;
                      }
                      // Clean tet-to-seg pointers.
                      for (i = 0; i < 3; i++) {
                        tssdissolve1(fliptets[i]);
                      }
                      // Clean the seg-to-tet pointer.
                      sstdissolve1(checkseg);
                    }
                  }
                  if (checksubfaceflag) {
                    // Check if there are subfaces to be flipped.
                    for (i = 0; i < 3; i++) {
                      tspivot(fliptets[i], checksh);
                      if (checksh.sh != NULL) {//if (flipshs[i].sh != NULL) {
                        if (b->verbose > 2) {
                          printf("        Queue a flipped subface (%d, %d, %d).\n",
                            pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                            pointmark(sapex(checksh)));
                        }
                        tsdissolve(fliptets[i]); // Disconnect the tet->sub bond.
                        stdissolve(checksh); // Disconnect the sub->tet bond.
                        // Add the missing subface into list.
                        subfacstack->newindex((void **) &parysh);
                        *parysh = checksh;
                      }
                    }
                  }
                } // if ((flipflag == 1) || (flipflag == 2))
    
                // Now flip the edge.
                flip32(fliptets, 0, flipflag, chkencflag);
                //recenttet = fliptets[0]; // for point location.
              } else {
                // There are more than 3 tets shared at this edge.
                if ((n == 4) && (convflag < 0)) {
                  // Check if a 4-to-4 flip is possible.
                  pf = apex(fliptets[3]);
                  if (pf == dummypoint) {
                    // It is a non-convex hull edge shared by four tets (two hull
                    //   tets and two interior tets). 
                    // Let the two interior tets be [a,b,c,d] and [b,a,c,e] where
                    //   [a,b] be the hull edge, [a,b,c] be the interior face.
                    //   [a,b,d] and [a,b,e] are two hull faces.
                    //   A 4-to-4 flip is possible if the two new tets [e,d,b,c]
                    //   and [e,d,c,a] are valid tets.
                    // Current status:
                    //   'fliptets[0]' is [a,b,e,c]
                    //   'fliptets[1]' is [a,b,c,d]
                    //   'fliptets[2]' is [a,b,d,f] (hull tet)
                    //   'fliptets[3]' is [a,b,f,e] (hull tet)
                    pa =  org(fliptets[1]);
                    pb = dest(fliptets[1]);
                    pc = apex(fliptets[1]);
                    p1 = oppo(fliptets[1]); // pd
                    p2 = apex(fliptets[0]); // pe
                    ori = orient3d(p2, p1, pb, pc);
                    if (ori < 0) {
                      ori = orient3d(p2, p1, pc, pa);
                      if (ori < 0) {
                        convflag = -2; // A 4-to-4 flip is possible.
                      }
                    }
                  }
    	    } // if ((n == 4) && (convflag < 0))
                if ((n == 4) && ((convflag == 0) || (convflag == -2))) {
                  // Found a 4-to-4 flip.
                  if (b->verbose > 3) {
                    printf("        A 4-to-4 flip (%d, %d) - (%d, %d).\n",
                           pointmark(org(fliptet)), pointmark(dest(fliptet)),
                           pointmark(pd), pointmark(pe));
                  }
                  if ((flipflag == 1) || (flipflag == 2)) { // CDT boundary recovery
                    if (checksubsegflag) {
                      // Check if the flip edge is subsegment.
                      tsspivot1(fliptets[0], checkseg);
                      if (checkseg.sh != NULL) {
                        if (!sinfected(checkseg)) {
                          // This subsegment will be flipped. Queue it.
                          if (b->verbose > 3) {
                            printf("        Queue a flipped segment (%d, %d).\n",
                             pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
                          }
                          sinfect(checkseg);  // Only save it once.
                          subsegstack->newindex((void **) &paryseg);
                          *paryseg = checkseg;
                        }
                        // Clean the tet-to-seg pointers.
                        for (i = 0; i < 4; i++) {
                          tssdissolve1(fliptets[i]);
                        }
                        // Clean the seg-to-tet pointer.
                        sstdissolve1(checkseg);
                      }
                    }
                    if (checksubfaceflag) {
                      // Check if there are subfaces to be flipped.
                      for (i = 0; i < 4; i++) {
                        tspivot(fliptets[i], checksh);
                        if (checksh.sh != NULL) {
                          if (b->verbose > 3) {
                            printf("        Queue a flipped subface (%d,%d,%d).\n",
                              pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                              pointmark(sapex(checksh)));
                          }
                          tsdissolve(fliptets[i]); // Disconnect the tet->sub bond.
                          stdissolve(checksh); // Disconnect the sub->tet bond.
                          // Add the missing subface into list.
                          subfacstack->newindex((void **) &parysh);
                          *parysh = checksh;
                        }
                      }
                    }
                  } // if ((flipflag == 1) || (flipflag == 2))
    
                  // First do a 2-to-3 flip.
                  // Comment: This flip temporarily creates either a degenerated
                  //   tet (convflag == 0) or an inverted tet (convflag < 0).
                  //   It is removed by the followed 3-to-2 flip.
                  fliptets[0] = fliptet; // tet abcd, d is the new vertex.
                  baktets[0] = fliptets[2];
                  baktets[1] = fliptets[3];
                  // The flip may involve hull tets.
                  flip23(fliptets, 1, flipflag, chkencflag);
                  // Then do a 3-to-2 flip.
                  enextesymself(fliptets[0]);  // fliptets[0] is edab.
                  eprevself(fliptets[0]); // tet badc, d is the new vertex.
                  fliptets[1] = baktets[0];
                  fliptets[2] = baktets[1];
                  flip32(fliptets, 1, flipflag, chkencflag);
                  flip23count--;
                  flip32count--;
                  flip44count++;
                  //recenttet = fliptets[0]; // for point location.
                } else {
                  // This edge is shared by more than 4 tets.
                  if (b->verbose > 2) {
                    printf("        An unflippable non-Delaunay edge (%d,%d).\n",
                           pointmark(org(fliptet)), pointmark(dest(fliptet)));
                  }
                  remflag = 0;
                  if (flipedgeflag == 2) {
                    // Try to flip this edge by my edge flip algorithm.
                    // Remember the the objective value (volume of all tetprisms).
                    fc.bak_tetprism_vol = tetprism_vol_sum; 
                    if (removeedgebyflips(&fliptet, &fc) == 2) {
                      if (b->verbose > 2) {
                        printf("      Decreased quantity: %.17g.\n", 
                               fc.bak_tetprism_vol - tetprism_vol_sum);
                      }
                      // Queue new faces in flipstack.
                      for (i = 0; i < cavetetlist->objects; i++) {
                        parytet = (triface *) fastlookup(cavetetlist, i);
                        if (!isdeadtet(*parytet)) { // Skip a dead tet.
                          for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
                            // Avoid queue a face twice.
                            fsym(*parytet, neightet);
                            if (!facemarked(neightet)) {
                              //flippush(flipstack, parytet);
                              bface = (badface *) flippool->alloc();
                              bface->tt = *parytet;
                              markface(bface->tt);
                              bface->forg = org(bface->tt); // An alive badface.
                              bface->fdest = dest(bface->tt); 
                              bface->fapex = apex(bface->tt); 
                              // bface->foppo = oppo(bface->tt);
                              // Push this face into stack.
                              bface->nextitem = flipstack;
                              flipstack = bface;
                            }
                          } // parytet->ver
                        }
                      } // i
                      cavetetlist->restart();
                      remflag = 1;
                    }
                  }
                  if (!remflag) {
                    // Found an unflippable non-Delaunay edge.
                    if (flipedgeflag > 0) { // if (flipflag > 1) {
                      // Save this face (of the edge) in a second queue.
                      unflipqueue->newindex((void **) &bface);
                      bface->tt = fliptet;
                      bface->forg = org(fliptet);
                      bface->fdest = dest(fliptet);
                      bface->fapex = apex(fliptet); // FOR DEBUG.
                    }
                  }
                }
              } // if (n > 3)
            } // if (convflag <= 0)
          } // if (sign < 0)
    
        } // while (flipstack != NULL)
    
    
        break;
    
      } // while (1)
    
    
      if (b->verbose > 2) {
        printf("      Total %ld flips", flip23count + flip32count + flip44count
               - flipcount);
        if ((flipflag == 4) || peelsliverflag) {
          printf(", %ld sliver peels", opt_sliver_peels - tetpeelcount);
        }
        printf("\n");
      }
    
    
      return flip23count + flip32count + flip44count - flipcount;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // insertvertex()    Insert a point into current tetrahedralization.         //
    //                                                                           //
    // This routine implements the famous Bowyer-Watson (B-W) algorithm to add a //
    // new point p into current tetrahedralization, denoted as T. The baisc idea //
    // of B-W algorithm is: first finds a "cavity", denoted as C inside T, where //
    // C is a simplicial polyhedron formed by a union of tetrahedra in T. If all //
    // boundary faces (triangles) of C are visible by p, i.e., C is star-shaped, //
    // then T can be re-tetrahedralized by first deleting all old tetrahedra in  //
    // C, then replacing new tetrahedra formed by boundary faces of C and p. The //
    // result is that p becomesis a vertex of T.                                 //
    //                                                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
                                 face *splitseg, insertvertexflags *ivf)
    {
      arraypool *swaplist; // for updating cavity.
      triface *cavetet, spintet, neightet, neineitet, *parytet;
      triface oldtet, newtet, newneitet;
      face checksh, *parysh, neighsh, spinsh;
      face checkseg, *paryseg;
      point *pts, pa, pb, pc, *parypt;
      badface *bface;
      enum locateresult loc;
      REAL sign, ori;
      REAL rd, cent[3];
      REAL attrib, volume;
      long cutcount, cutshcount, tetcount = 0;
      long bakhullsize;
      bool enqflag;
      int i, j, k, s;
    
      int rejptflag, encptflag; // for protecting balls.
      int bgmloc;
    
    #ifdef WITH_RUNTIME_COUNTERS
      clock_t tstart, tend;
    #endif
    
      if (b->verbose > 2) {
        printf("      Insert point %d\n", pointmark(insertpt));
      }
    
    
      // Locate the point.
      loc = OUTSIDE; // Set a default value.
    
      if (searchtet->tet != NULL) {
        loc = (enum locateresult) ivf->iloc;
      }
    
      if (loc == OUTSIDE) {
    #ifdef WITH_RUNTIME_COUNTERS
        tstart = clock();
    #endif
        tetcount = ptloc_count; // Count the number of walked tets.
        if (searchtet->tet == NULL) {
          if (!b->weighted) {
            if (b->btree) {
              btree_search(insertpt, searchtet);
            } else if (b->hilbertcurve) { // -U
              *searchtet = recenttet;
            } else { // -u0
              randomsample(insertpt, searchtet);
            }
          } else {
            // There may exist dangling vertex. 
            *searchtet = recenttet;
          }
        }
        // Locate the point.  Use 'randflag' if the mesh is non-convex.
        loc = locate(insertpt, searchtet, ivf->chkencflag, checksubfaceflag); 
        if (b->verbose > 3) {
            printf("        Walk distance (# tets): %ld\n", ptloc_count-tetcount);
        }
        if (ptloc_max_count < (ptloc_count - tetcount)) {
          ptloc_max_count = (ptloc_count - tetcount);
        }
    #ifdef WITH_RUNTIME_COUNTERS
        tend = clock();
        t_ptloc += (tend - tstart);
    #endif
      }
    
      if (b->verbose > 3) {
        printf("        Located tet (%d, %d, %d, %d).\n",
               pointmark(org(*searchtet)), pointmark(dest(*searchtet)), 
               pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
      }
    
    #ifdef WITH_RUNTIME_COUNTERS
      tstart = clock();
    #endif
    
      if (b->weighted) {
        if (loc != OUTSIDE) {
          // Check if this vertex is regular.
          pts = (point *) searchtet->tet;
          assert(pts[7] != dummypoint);
          sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
                            pts[4][3], pts[5][3], pts[6][3], pts[7][3],
                            insertpt[3]);
          if (sign > 0) {
            // This new vertex does not lie below the lower hull. Skip it.
            if (b->verbose > 2) {
              printf("      The point is above the lower hull, skipped.\n");
            }
            return OUTSIDE;
          }
        }
      }
    
      // Create the initial cavity C(p) which contains all tetrahedra directly
      //   intersect with p.
      // If 'bowywat > 2' and p lies on a segment or subface, also create the 
      //   initial sub-cavity sC(p) which contains all subfaces (and segment)
      //   which directly intersect with p.
      // If 'bowywat > 2', the initial C(p) is validated, i.e., all boundary
      //   faces of C(p) should be visible by p.
    
      // Remember the current hullsize. It is used to restore the hullsize
      //   if the new point is rejected for insertion.
      bakhullsize = hullsize;
    
      if (loc == OUTSIDE) {
        if (b->verbose > 3) {
          printf("        Outside hull.\n");
        }
        // The current hull will be enlarged.
        // Add four adjacent boundary tets into list.
        for (i = 0; i < 4; i++) {
          decode(searchtet->tet[i], neightet);
          neightet.ver = epivot[neightet.ver & 3];
          cavetetlist->newindex((void **) &parytet);
          *parytet = neightet;
        }
        if ((point) searchtet->tet[7] == dummypoint) hullsize--;
        // tetrahedrondealloc(searchtet->tet);
        infect(*searchtet);
        caveoldtetlist->newindex((void **) &parytet);
        *parytet = *searchtet;
        flip14count++;
      } else if (loc == INTETRAHEDRON) {
        if (b->verbose > 3) {
          printf("        Inside tet.\n");
        }
        // Add four adjacent boundary tets into list.
        for (i = 0; i < 4; i++) {
          decode(searchtet->tet[i], neightet);
          neightet.ver = epivot[neightet.ver & 3];
          cavetetlist->newindex((void **) &parytet);
          *parytet = neightet;
        }
        // tetrahedrondealloc(searchtet->tet);
        infect(*searchtet);
        caveoldtetlist->newindex((void **) &parytet);
        *parytet = *searchtet;
        flip14count++;
      } else if (loc == ONFACE) {
        if (b->verbose > 3) {
          printf("        On face.\n");
        }
        // Add six adjacent boundary tets into list.
        j = (searchtet->ver & 3); // The current face number.
        for (i = 1; i < 4; i++) { 
          decode(searchtet->tet[(j + i) % 4], neightet);
          neightet.ver = epivot[neightet.ver & 3];
          cavetetlist->newindex((void **) &parytet);
          *parytet = neightet;
        }
        decode(searchtet->tet[j], spintet);
        j = (spintet.ver & 3); // The current face number.
        for (i = 1; i < 4; i++) {
          decode(spintet.tet[(j + i) % 4], neightet);
          neightet.ver = epivot[neightet.ver & 3];
          cavetetlist->newindex((void **) &parytet);
          *parytet = neightet;
        }
        if ((point) spintet.tet[7] == dummypoint) hullsize--;
        if ((point) searchtet->tet[7] == dummypoint) hullsize--;
        // tetrahedrondealloc(spintet.tet);
        infect(spintet);
        caveoldtetlist->newindex((void **) &parytet);
        *parytet = spintet;
        // tetrahedrondealloc(searchtet->tet);
        infect(*searchtet);
        caveoldtetlist->newindex((void **) &parytet);
        *parytet = *searchtet;
        flip26count++;
    
        if (ivf->splitbdflag) { //if (bowywat > 2) {
          if (splitsh != NULL) {
            // Create the initial sub-cavity sC(p).
            smarktest(*splitsh);
            caveshlist->newindex((void **) &parysh);
            *parysh = *splitsh;
          }
        } // if (splitbdflag)
      } else if (loc == ONEDGE) {
        if (b->verbose > 3) {
          printf("        On edge.\n");
        }
        // Add all adjacent boundary tets into list.
        spintet = *searchtet;
        while (1) {
          enextesym(spintet, neightet);
          fsymself(neightet);
          neightet.ver = epivot[neightet.ver & 3];
          cavetetlist->newindex((void **) &parytet);
          *parytet = neightet;
          eprevesym(spintet, neightet);
          fsymself(neightet);
          neightet.ver = epivot[neightet.ver & 3];
          cavetetlist->newindex((void **) &parytet);
          *parytet = neightet;
          if ((point) spintet.tet[7] == dummypoint) hullsize--;
          // tetrahedrondealloc(spintet.tet);
          infect(spintet);
          caveoldtetlist->newindex((void **) &parytet);
          *parytet = spintet;
          fnextself(spintet);
          if (spintet.tet == searchtet->tet) break;
        } // while (1)
        flipn2ncount++;
    
        if (ivf->splitbdflag) { //if (bowywat > 2) {
          // Create the initial sub-cavity sC(p).
          if (splitseg != NULL) {
            smarktest(*splitseg);
            splitseg->shver = 0;
            spivot(*splitseg, *splitsh);
          }
          if (splitsh != NULL) {
            if (splitsh->sh != NULL) {
              // Collect all subfaces share at this edge.
              pa = sorg(*splitsh);
              neighsh = *splitsh;
              while (1) {
                // Adjust the origin of its edge to be 'pa'.
                if (sorg(neighsh) != pa) {
                  sesymself(neighsh);
                }
                // Add this face into list (in B-W cavity).
                smarktest(neighsh);
                caveshlist->newindex((void **) &parysh);
                *parysh = neighsh;
                // Add this face into face-at-splitedge list.
                cavesegshlist->newindex((void **) &parysh);
                *parysh = neighsh;
                // Go to the next face at the edge.
                spivotself(neighsh);
                // Stop if all faces at the edge have been visited.
                if (neighsh.sh == splitsh->sh) break;
                if (neighsh.sh == NULL) break;
              } // while (1)
            } // if (not a dangling segment)
          }
        } // if (splitbdflag)
      } else if (loc == INSTAR) {
        if (b->verbose > 3) {
          printf("        Inside star.\n");
        }
        // We assume that all tets in the star are given in 'caveoldtetlist',
        //   and they are all infected.
        assert(caveoldtetlist->objects > 0);
        // Collect the boundary faces of the star.
        for (i = 0; i < caveoldtetlist->objects; i++) {
          cavetet = (triface *) fastlookup(caveoldtetlist, i);
          // Check its 4 neighbor tets.
          for (j = 0; j < 4; j++) {
            decode(cavetet->tet[j], neightet);
            if (!infected(neightet)) {
              // It's a boundary face.
              neightet.ver = epivot[neightet.ver & 3];
              cavetetlist->newindex((void **) &parytet);
              *parytet = neightet;
            }
          }
        }
      } else if (loc == ONVERTEX) {
        pa = org(*searchtet);
        if (b->verbose > 3) {
          printf("        On vertex %d.\n", pointmark(pa));
        }
        if (insertpt != pa) {
          // Remember it is a duplicated point.
          setpointtype(insertpt, DUPLICATEDVERTEX);
          // Set a pointer to the point it duplicates.
          setpoint2ppt(insertpt, pa);
        }
        // The point already exist. Do nothing and return.
        return (int) loc;
      } else if (loc == ENCSUBFACE) {
        if (b->verbose > 3) {
          printf("        Encroached.\n");
        }
        // The vertex lies outside of the region boundary.
        // Treated it as outside
        loc = OUTSIDE;
        return (int) loc;
      } else {
        assert(0); // Unknown type.
      }
    
    
      if (ivf->assignmeshsize) {
        // Assign mesh size for the new point.
        if (bgm != NULL) {
          // Interpolate the mesh size from the background mesh. 
          pa = org(*searchtet);
          bgm->decode(point2bgmtet(pa), neightet); // neightet is in 'bgm'!
          bgmloc = bgm->scoutpoint(insertpt, &neightet, 0); // randflag = 0
          if (bgmloc != (int) OUTSIDE) {
            insertpt[pointmtrindex] =  // posflag = 1
              bgm->getpointmeshsize(insertpt, &neightet, bgmloc, 1);
            setpoint2bgmtet(insertpt, bgm->encode(neightet));
          }
        } else {
          insertpt[pointmtrindex] = // posflag = 1
            getpointmeshsize(insertpt, searchtet, (int) loc, 1);
        }
      } // if (assignmeshsize)
    
      if (ivf->validflag) { //if (bowywat > 2) { 
        // Validate the initial C(p). Enlarge it at a face which is not visible
        //   by p. This removes (interior) slivers. Re-use 'cavebdrylist'.
        tetcount = 0l;
    
        for (i = 0; i < cavetetlist->objects; i++) {
          cavetet = (triface *) fastlookup(cavetetlist, i);
          // Other expansions may make this face inside C(p).
          if (!infected(*cavetet)) {
            pc = apex(*cavetet);
            // Do valid if it is a face (not a hull edge).
            if (pc != dummypoint) {
              pa = org(*cavetet);
              pb = dest(*cavetet);
              ori = orient3d(pa, pb, pc, insertpt); 
              if (ori <= 0) {
                // An invalid face. Enlarge the cavity.
                //if (oppo(*cavetet) != dummypoint) {
                  if (b->verbose > 3) {
                    printf("        Enlarge cavity at (%d, %d, %d)\n",
                           pointmark(pa), pointmark(pb), pointmark(pc));
                  }
                  // Add the other three faces into list.
                  j = (cavetet->ver & 3); // The current face number.
                  for (k = 1; k < 4; k++) { 
                    decode(cavetet->tet[(j + k) % 4], neightet);
                    neightet.ver = epivot[neightet.ver & 3];
                    cavetetlist->newindex((void **) &parytet);
                    *parytet = neightet;
                  }
                  if ((point) cavetet->tet[7] == dummypoint) hullsize--;
                  infect(*cavetet);
                  caveoldtetlist->newindex((void **) &parytet);
                  *parytet = *cavetet;
                  tetcount++;
    	    //} else {
                //  printf("Error in insertvertex %d: ", pointmark(insertpt));
                //  printf("Invalid initial cavity at face %d.\n", i + 1);
                //  assert(0);
    	    //}
              } else {
                // A valid face.
                cavebdrylist->newindex((void **) &parytet);
                *parytet = *cavetet;
              }
            } else {
              // A hull edge is valid.
              cavebdrylist->newindex((void **) &parytet);
              *parytet = *cavetet;
            }
          } // if (!infected(*cavetet))
        } // i
    
        if (tetcount > 0l) {
          // The cavity has been enlarged. Update it.
          cavetetlist->restart();
          for (i = 0; i < cavebdrylist->objects; i++) {
            cavetet = (triface *) fastlookup(cavebdrylist, i);
            if (!infected(*cavetet)) {
              cavetetlist->newindex((void **) &parytet);
              *parytet = *cavetet;
            }
          } // i
        } // if (tetcount)
    
        cavebdrylist->restart();
        tetcount = 0l;
      } // if (bowywat > 2)
    
      // Update the cavity C(p) using the Bowyer-Watson approach (bowywat > 0). 
    
      for (i = 0; i < cavetetlist->objects; i++) {
        // 'cavetet' is an adjacent tet at outside of the cavity.
        cavetet = (triface *) fastlookup(cavetetlist, i);
        // The tet may be tested and included in the (enlarged) cavity.
        if (!infected(*cavetet)) {
          // Check for two possible cases for this tet: 
          //   (1) It is a cavity tet, or
          //   (2) it is a cavity boundary face.
          // In case (1), this tet is grabbed in the cavity and three adjacent 
          //   tets on other faces of this tet are added into 'cavetetlist'.
          enqflag = false;
          if (!marktested(*cavetet)) {
            if (ivf->bowywat) {
              // Do Delaunay (in-sphere) test.
              pts = (point *) cavetet->tet;
              if (pts[7] != dummypoint) {
                // A volume tet. Operate on it.
                if (b->weighted) {
                  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
                                    pts[4][3], pts[5][3], pts[6][3], pts[7][3],
                                    insertpt[3]);
                } else {
                  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
                }
                enqflag = (sign < 0.0);
              } else {
                if (!nonconvex) {
                  // Test if this hull face is visible by the new point. 
                  ori = orient3d(pts[4], pts[5], pts[6], insertpt); 
                  orient3dcount++;
                  if (ori < 0) {
                    // A visible hull face. 
                    //if (!nonconvex) { 
                    // Include it in the cavity. The convex hull will be enlarged.
                    enqflag = true; // (ori < 0.0);
    		//}
                  } else if (ori == 0.0) {
                    // A coplanar hull face. We need to test if this hull face is
                    //   Delaunay or not. We test if the adjacent tet (not faked)
                    //   of this hull face is Delaunay or not.
                    neightet = *cavetet;
                    neightet.ver = 3; // The face opposite to dummypoint.
                    fsym(neightet, neineitet);
                    if (!infected(neineitet)) {
                      if (!marktested(neineitet)) {
                        // Do Delaunay test on this tet.
                        pts = (point *) neineitet.tet;
                        assert(pts[7] != dummypoint);
                        if (b->weighted) {
                          sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
                                            pts[4][3], pts[5][3], pts[6][3], 
                                            pts[7][3], insertpt[3]);
                        } else {
                          sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
                        }
                        enqflag = (sign < 0.0);
                      } else {
                        // The adjacent tet has been tested (marktested), and it
                        //   is Delaunay (not get infected). Hence the the hull
                        //   face is Delaunay as well.
                        // enqflag = false;
                      }
                    } else {
                      // The adjacent tet is non-Delaunay. The hull face is non-
                      //   Delaunay as well. Include it in the cavity.
                      enqflag = true;
                    } // if (!infected(neineitet))
                  } // if (ori == 0.0)
                } else {
                  // A hull face (must be a subface).
                  assert(checksubfaceflag);
                  assert(ivf->validflag);
                  // We FIRST include it in the initial cavity if the adjacent tet
                  //   (not faked) of this hull face is not Delaunay wrt p.
                  //   Whether it belongs to the final cavity will be determined
                  //   during the validation process. 'validflag'.
                  neightet = *cavetet;
                  neightet.ver = 3; // The face opposite to dummypoint.
                  fsym(neightet, neineitet);
                  if (!infected(neineitet)) {
                    if (!marktested(neineitet)) {
                      // Do Delaunay test on this tet.
                      pts = (point *) neineitet.tet;
                      assert(pts[7] != dummypoint);
                      if (b->weighted) {
                        sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
                                          pts[4][3], pts[5][3], pts[6][3], 
                                          pts[7][3], insertpt[3]);
                      } else {
                        sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
                      }
                      enqflag = (sign < 0.0);
                    } else {
                      // The adjacent tet has been tested (marktested), and it
                      //   is Delaunay (not get infected). Hence the the hull
                      //   face is Delaunay as well.
                      // enqflag = false;
                    } // if (marktested(neineitet))
                  } else {
                    // The adjacent tet is non-Delaunay. The hull face is non-
                    //   Delaunay as well. Include it in the cavity.
                    enqflag = true;
                  } // if (infected(neineitet))
                } // if (nonconvex)
              } // if (pts[7] != dummypoint)
            } // if (bowywat)
            marktest(*cavetet); // Only test it once.
          } // if (!marktested(*cavetet))
    
          if (enqflag) {
            // Found a tet in the cavity. Put other three faces in check list.
            k = (cavetet->ver & 3); // The current face number
            for (j = 1; j < 4; j++) {
              decode(cavetet->tet[(j + k) % 4], neightet);
              neightet.ver = epivot[neightet.ver & 3];
              cavetetlist->newindex((void **) &parytet);
              *parytet = neightet;
            }
            if ((point) cavetet->tet[7] == dummypoint) hullsize--;
            // tetrahedrondealloc(cavetet->tet);
            infect(*cavetet);
            caveoldtetlist->newindex((void **) &parytet);
            *parytet = *cavetet;
          } else {
            // Found a boundary face of the cavity. It may be a face of a hull
            //   tet which contains 'dummypoint'. Choose the edge in the face 
            //   such that its endpoints are not 'dummypoint', while its apex
            //   may be 'dummypoint'.
            //j = (cavetet->ver & 3); // j is the face number.
            //cavetet->ver = epivot[j]; // [4,5,2,11]
            cavebdrylist->newindex((void **) &parytet);
            *parytet = *cavetet;
          }
        } // if (!infected(*cavetet))
      } // i
    
      if (b->verbose > 3) {
        printf("        Initial cavity size: %ld tets, %ld faces.\n", 
               caveoldtetlist->objects, cavebdrylist->objects);
      }
    
    
      if (checksubsegflag) {
        // Collect all segments of C(p).
        for (i = 0; i < caveoldtetlist->objects; i++) {
          cavetet = (triface *) fastlookup(caveoldtetlist, i);
          for (j = 0; j < 6; j++) {
            cavetet->ver = edge2ver[j];
            tsspivot1(*cavetet, checkseg);
            if (checkseg.sh != NULL) {
              if (!sinfected(checkseg)) {
                sinfect(checkseg);
                cavetetseglist->newindex((void **) &paryseg);
                *paryseg = checkseg;
              }
            }
          }
        }
        // Uninfect collected segments.
        for (i = 0; i < cavetetseglist->objects; i++) {
          checkseg = * (face *) fastlookup(cavetetseglist, i);
          suninfect(checkseg);
        }
      } // if (checksubsegflag)
    
      if (checksubfaceflag) {
        // Collect all subfaces of C(p).
        for (i = 0; i < caveoldtetlist->objects; i++) {
          cavetet = (triface *) fastlookup(caveoldtetlist, i);
          oldtet = *cavetet;
          for (oldtet.ver = 0; oldtet.ver < 4; oldtet.ver++) {
            tspivot(oldtet, checksh);
            if (checksh.sh != NULL) {
              if (!sinfected(checksh)) {
                sinfect(checksh);
                cavetetshlist->newindex((void **) &parysh);
                *parysh = checksh;
              }
            }
          }
        }
        // Uninfect collected subfaces.
        for (i = 0; i < cavetetshlist->objects; i++) {
          checksh = * (face *) fastlookup(cavetetshlist, i);
          suninfect(checksh);
        }
      } // if (checksubfaceflag)
    
      if (ivf->rejflag & 1) {
        // Reject insertion of this point if it encroaches upon any segment.
        for (i = 0; i < cavetetseglist->objects; i++) {
          checkseg = * (face *) fastlookup(cavetetseglist, i);
          pa = sorg(checkseg);
          pb = sdest(checkseg);
          if (checkseg4encroach(pa, pb, insertpt)) {
            if (b->verbose > 3) {
              printf("        Found an encroached seg (%d, %d).\n",
                     pointmark(pa), pointmark(pb));
            }
            encseglist->newindex((void **) &paryseg);
            *paryseg = checkseg;
          }
        } // i
        if (encseglist->objects > 0) {
          if (b->verbose > 3) {
            printf("        Found %ld encroached segments. Reject it.\n",
                   encseglist->objects);
          }
          for (i = 0; i < caveoldtetlist->objects; i++) {
            cavetet = (triface *) fastlookup(caveoldtetlist, i);
            uninfect(*cavetet);
            unmarktest(*cavetet);
          }
          for (i = 0; i < cavebdrylist->objects; i++) {
            cavetet = (triface *) fastlookup(cavebdrylist, i);
            unmarktest(*cavetet); // Unmark it.
          }
          // Clear working lists.
          cavetetlist->restart();
          cavebdrylist->restart();
          caveoldtetlist->restart();
          cavetetseglist->restart();
          cavetetshlist->restart();
          if (ivf->splitbdflag) { //if (bowywat > 2) {
            if (splitseg != NULL) {
              sunmarktest(*splitseg);
            }
            for (i = 0; i < caveshlist->objects; i++) {
              parysh = (face *) fastlookup(caveshlist, i);
              assert(smarktested(*parysh));
              sunmarktest(*parysh);
            }
            caveshlist->restart();
            cavesegshlist->restart();
          }
          // Restore the hullsize.
          hullsize = bakhullsize;
          return (int) ENCSEGMENT;
        }
      } // if (reject & 1)
    
      if (ivf->rejflag & 2) {
        // Reject insertion of this point if it encroaches upon any subface.
        for (i = 0; i < cavetetshlist->objects; i++) {
          checksh = * (face *) fastlookup(cavetetshlist, i);
          pa = sorg(checksh);
          pb = sdest(checksh);
          pc = sapex(checksh);
          if (checkfac4encroach(pa, pb, pc, insertpt, cent, &rd)) {
            if (b->verbose > 3) {
              printf("        Found an encroached subface (%d, %d, %d).\n",
                     pointmark(pa), pointmark(pb), pointmark(pc));
            }
            encshlist->newindex((void **) &bface);
            bface->ss = checksh;
            bface->forg = pa; // Not a dad one.
            for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
            bface->key = rd;
          }
        } // i
        if (encshlist->objects > 0) {
          if (b->verbose > 3) {
            printf("        Found %ld encroached subfaces. Reject it.\n",
                   caveencshlist->objects);
          }
          for (i = 0; i < caveoldtetlist->objects; i++) {
            cavetet = (triface *) fastlookup(caveoldtetlist, i);
            uninfect(*cavetet);
            unmarktest(*cavetet);
          }
          for (i = 0; i < cavebdrylist->objects; i++) {
            cavetet = (triface *) fastlookup(cavebdrylist, i);
            unmarktest(*cavetet); // Unmark it.
          }
          cavetetlist->restart();
          cavebdrylist->restart();
          caveoldtetlist->restart();
          cavetetseglist->restart();
          cavetetshlist->restart();
          if (ivf->splitbdflag) { //if (bowywat > 2) {
            if (splitseg != NULL) {
              sunmarktest(*splitseg);
            }
            for (i = 0; i < caveshlist->objects; i++) {
              parysh = (face *) fastlookup(caveshlist, i);
              assert(smarktested(*parysh));
              sunmarktest(*parysh);
            }
            caveshlist->restart();
            cavesegshlist->restart();
          }
          // Restore the hullsize.
          hullsize = bakhullsize;
          return (int) ENCSUBFACE;
        }
      } // if (reject & 2)
    
      if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
        // Update the sC(p). 
        // We have already 'smarktested' the subfaces which directly intersect
        //   with p in 'caveshlist'. From them, we 'smarktest' their neighboring
        //   subfaces which are included in C(p). Do not across a segment.
        for (i = 0; i < caveshlist->objects; i++) {
          parysh = (face *) fastlookup(caveshlist, i);
          assert(smarktested(*parysh));
          checksh = *parysh;
          for (j = 0; j < 3; j++) {
            sspivot(checksh, checkseg);
            if (checkseg.sh == NULL) {
              spivot(checksh, neighsh);
              assert(neighsh.sh != NULL);
              if (!smarktested(neighsh)) {
                // Add this subface if it is inside C(p).
                stpivot(neighsh, neightet);
                if (infected(neightet)) {
                  fsymself(neightet);
                  if (infected(neightet)) {
                    smarktest(neighsh);
                    caveshlist->newindex((void **) &parysh);
                    *parysh = neighsh;
                  }
                }
              }
            }
            senextself(checksh);
          } // j
        } // i
        if (b->verbose > 3) {
          printf("        Initial subcavity size: %ld subfacess.\n", 
                 caveshlist->objects);
        }
      }
    
      cutcount = 0l;
    
      if (ivf->validflag) { 
        //if (bowywat > 1) { // if (bowywat == 2 || bowywat == 3) {
        // T is a CT. Validation is needed (fig/dump-cavity-case8).
        cavetetlist->restart(); // Re-use it.
    
        //if (splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
        if (ivf->respectbdflag) {
          // The initial cavity may include subfaces which are not on the facets
          //   being splitting. Find them and make them as boundary of C(p).      
          // Comment: We have already 'smarktested' the subfaces in sC(p).
          //   It is needed by 'splitbdflag'.
          for (i = 0; i < cavetetshlist->objects; i++) {
            parysh = (face *) fastlookup(cavetetshlist, i);
            stpivot(*parysh, neightet);
            if (infected(neightet)) {
              fsymself(neightet);
              if (infected(neightet)) {
                if (!smarktested(*parysh)) {
                  if (b->verbose > 3) {
                    printf("        Found a subface (%d, %d, %d) inside cavity.\n", 
                           pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
                           pointmark(sapex(*parysh)));
                  }
                  // It is possible that this face is a boundary subface.
                  // Check if it is a hull face.
                  assert(apex(neightet) != dummypoint);
                  if (oppo(neightet) != dummypoint) {
                    fsymself(neightet);
                  }
                  if (oppo(neightet) != dummypoint) {
                    pa = org(neightet);
                    pb = dest(neightet);
                    pc = apex(neightet);
                    ori = orient3d(pa, pb, pc, insertpt);
                    if (ori < 0) {
                      // A visible face, get its neighbor face.
                      fsymself(neightet);
                      ori = -ori; // It must be invisible by p.
                    }
                  } else {
                    // A hull tet. It needs to be cut.
                    ori = 1;
                  }
                  // Cut this tet if it is either invisible by or coplanar with p.
                  if (ori >= 0) {
                    if (b->verbose > 3) {
                      printf("        Cut tet (%d, %d, %d, %d)\n", 
                             pointmark(org(neightet)), pointmark(dest(neightet)),
                             pointmark(apex(neightet)), pointmark(oppo(neightet)));
                    }
                    uninfect(neightet);
                    unmarktest(neightet);
                    cutcount++;
                    neightet.ver = epivot[neightet.ver & 3];
                    cavebdrylist->newindex((void **) &parytet);
                    *parytet = neightet;
                    // Add three new faces to find new boundaries.
                    for (j = 0; j < 3; j++) {
                      esym(neightet, neineitet);
                      neineitet.ver = epivot[neineitet.ver & 3];
                      cavebdrylist->newindex((void **) &parytet);
                      *parytet = neineitet;
                      enextself(neightet);
                    }
                    // Update hullsize.
                    if (oppo(neightet) == dummypoint) hullsize++;
                  } // if (ori >= 0) 
                }
              }
            }
          } // i
    
          // The initial cavity may include segments in its interior. We need to
          //   Update the cavity so that these segments are on the boundary of
          //   the cavity.
          for (i = 0; i < cavetetseglist->objects; i++) {
            paryseg = (face *) fastlookup(cavetetseglist, i);
            // Check this segment if it is not a splitting segment.
            if (!smarktested(*paryseg)) {
              sstpivot1(*paryseg, neightet);
              spintet = neightet;
              while (1) {
                if (!infected(spintet)) break;
                fnextself(spintet);
                if (spintet.tet == neightet.tet) break;
              }
              if (infected(spintet)) {
                if (b->verbose > 3) {
                  printf("        Found an interior segment (%d, %d).\n", 
                         pointmark(sorg(*paryseg)), pointmark(sdest(*paryseg)));
                }
                // Find an adjacent tet at this segment such that both faces
                //   at this segment are not visible by p.
                pa = org(neightet);
                pb = dest(neightet);
                spintet = neightet;
                j = 0;
                while (1) {
                  // Check if this face is visible by p.
                  pc = apex(spintet);
                  if (pc != dummypoint) {
                    ori = orient3d(pa, pb, pc, insertpt);
                    if (ori >= 0) {
                      // Not visible. Check another face in this tet.
                      esym(spintet, neineitet);
                      pc = apex(neineitet);
                      if (pc != dummypoint) {
                        ori = orient3d(pb, pa, pc, insertpt);
                        if (ori >= 0) {
                          // Not visible. Found this face.
                          j = 1; // Flag that it is found.
                          break;
                        }
                      }
                    }
                  } else {
                  }
                  fnextself(spintet);
                  if (spintet.tet == neightet.tet) break;
                }
                if (j == 0) {
                  // Not found such a face.
                  assert(0); // debug this case.
                }
                neightet = spintet;
                if (b->verbose > 3) {
                   printf("        Cut tet (%d, %d, %d, %d)\n", 
                          pointmark(org(neightet)), pointmark(dest(neightet)),
                          pointmark(apex(neightet)), pointmark(oppo(neightet)));
                }
                uninfect(neightet);
                unmarktest(neightet);
                cutcount++;
                neightet.ver = epivot[neightet.ver & 3];
                cavebdrylist->newindex((void **) &parytet);
                *parytet = neightet;
                // Add three new faces to find new boundaries.
                for (j = 0; j < 3; j++) {
                  esym(neightet, neineitet);
                  neineitet.ver = epivot[neineitet.ver & 3];
                  cavebdrylist->newindex((void **) &parytet);
                  *parytet = neineitet;
                  enextself(neightet);
                }
                // Update hullsize.
                //if (oppo(neightet) == dummypoint) hullsize++;
                if ((point) (neightet.tet[7]) == dummypoint) hullsize++;
              }
            }
          } // i
        } // if (bowywat > 2)
    
        // Update the cavity by removing invisible faces until it is star-shaped.
        for (i = 0; i < cavebdrylist->objects; i++) {
          cavetet = (triface *) fastlookup(cavebdrylist, i);
          // 'cavetet' is an exterior tet adjacent to the cavity.      
          assert(cavetet->ver == epivot[cavetet->ver & 3]); // SELF_CHECK
          // It must be not inside the cavity (since we only cut tets).
          assert(!infected(*cavetet));
          // Check if its neighbor is inside C(p).
          fsym(*cavetet, neightet);
          if (infected(neightet)) {        
            if (apex(*cavetet) != dummypoint) {
              // It is a cavity boundary face. Check its visibility.
              if (oppo(neightet) != dummypoint) {
                pa = org(*cavetet);
                pb = dest(*cavetet);
                pc = apex(*cavetet);
                ori = orient3d(pa, pb, pc, insertpt); orient3dcount++;
                enqflag = (ori > 0);
                // Comment: if ori == 0 (coplanar case), we also cut the tet.
              } else {
                // It is a hull face. And its adjacent tet (at inside of the 
                //   domain) has been cut from the cavity. Cut it as well.
                //assert(nonconvex);
                enqflag = false;
              }
            } else {
              enqflag = true; // A hull edge.
            }
            if (enqflag) {
              // This face is valid, save it.
              cavetetlist->newindex((void **) &parytet);
              *parytet = *cavetet; 
            } else {
              if (b->verbose > 3) {
                printf("        Cut tet (%d, %d, %d, %d)\n", 
                       pointmark(org(neightet)), pointmark(dest(neightet)),
                       pointmark(apex(neightet)), pointmark(oppo(neightet)));
              }
              uninfect(neightet);
              unmarktest(neightet);
              cutcount++;
              // Add three new faces to find new boundaries.
              for (j = 0; j < 3; j++) {
                esym(neightet, neineitet);
                neineitet.ver = epivot[neineitet.ver & 3];
                cavebdrylist->newindex((void **) &parytet);
                *parytet = neineitet;
                enextself(neightet);
              }
              // Update the hullsize.
              if (oppo(neightet) == dummypoint) hullsize++;
              // 'cavetet' is not on the cavity boundary anymore.
              unmarktest(*cavetet);
            }
          } else {
            // 'cavetet' is not on the cavity boundary anymore.
            unmarktest(*cavetet);
          }
        } // i
    
        if (cutcount > 0) {
          // The cavity has been updated.
    
          // Update the cavity boundary faces.
          cavebdrylist->restart();
          for (i = 0; i < cavetetlist->objects; i++) {
            cavetet = (triface *) fastlookup(cavetetlist, i);
            // 'cavetet' was an exterior tet adjacent to the cavity.
            assert(cavetet->ver == epivot[cavetet->ver & 3]); // SELF_CHECK
            assert(!infected(*cavetet));
            fsym(*cavetet, neightet);
            if (infected(neightet)) {
              // It is a cavity boundary face.
              cavebdrylist->newindex((void **) &parytet);
              *parytet = *cavetet;
            } else {
              // Not a cavity boundary face.
              unmarktest(*cavetet);
            }
          }
    
          // Update the list of old tets.
          cavetetlist->restart();
          for (i = 0; i < caveoldtetlist->objects; i++) {
            cavetet = (triface *) fastlookup(caveoldtetlist, i);
            if (infected(*cavetet)) {
              cavetetlist->newindex((void **) &parytet);
              *parytet = *cavetet;
            }
          }
          // Swap 'cavetetlist' and 'caveoldtetlist'.
          swaplist = caveoldtetlist;
          caveoldtetlist = cavetetlist;
          cavetetlist = swaplist;
    
          // The cavity should contain at least one tet.
          if (caveoldtetlist->objects == 0l) {
            printf("Invalid cavity of Steiner point %d.\n", pointmark(insertpt));
            assert(0);
          }
    
          if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
            cutshcount = 0;
            // Update the sub-cavity sC(p).
            for (i = 0; i < caveshlist->objects; i++) {
              parysh = (face *) fastlookup(caveshlist, i);
              if (smarktested(*parysh)) {
                enqflag = false;
                stpivot(*parysh, neightet);
                if (infected(neightet)) {
                  fsymself(neightet);
                  if (infected(neightet)) {
                    enqflag = true;
                  }
                }
                if (!enqflag) {
                  if (b->verbose > 3) {
                    printf("        Cut subface (%d, %d, %d).\n",
                           pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
                           pointmark(sapex(*parysh)));
                  }
                  sunmarktest(*parysh);
                  // Use the last entry of this array to fill this entry.
                  j = caveshlist->objects - 1;
                  checksh = * (face *) fastlookup(caveshlist, j);
                  *parysh = checksh;
                  cutshcount++;
                  caveshlist->objects--; // The list is shrinked.
                  i--;
                }
              }
            }
    
            if (cutshcount > 0) {
              i = 0; // Count the number of invalid subfaces/segments.
              // Valid the updated sub-cavity sC(p).
              if (loc == ONFACE) {
                if (splitsh != NULL) {
                  // The to-be split subface should be in sC(p).
                  if (!smarktested(*splitsh)) i++;
                }
              } else if (loc == ONEDGE) {
                if (splitseg != NULL) {
                  // The to-be split segment should be in sC(p).
                  if (!smarktested(*splitseg)) i++;
                }
                if (splitsh != NULL) {
                  // All subfaces at this edge should be in sC(p).
                  pa = sorg(*splitsh);
                  neighsh = *splitsh;
                  while (1) {
                    // Adjust the origin of its edge to be 'pa'.
                    if (sorg(neighsh) != pa) {
                      sesymself(neighsh);
                    }
                    // Add this face into list (in B-W cavity).
                    if (!smarktested(neighsh)) i++;
                    // Go to the next face at the edge.
                    spivotself(neighsh);
                    // Stop if all faces at the edge have been visited.
                    if (neighsh.sh == splitsh->sh) break;
                    if (neighsh.sh == NULL) break;
                  } // while (1)
                }
              }
    
              if (i > 0) {
                // The updated sC(p) is invalid. Do not insert this vertex.
                if (b->verbose > 3) {
                  printf("        Found %d invalid items. Reject it.\n", i);
                }
                for (i = 0; i < caveoldtetlist->objects; i++) {
                  cavetet = (triface *) fastlookup(caveoldtetlist, i);
                  uninfect(*cavetet);
                  unmarktest(*cavetet);
                }
                for (i = 0; i < cavebdrylist->objects; i++) {
                  cavetet = (triface *) fastlookup(cavebdrylist, i);
                  unmarktest(*cavetet); // Unmark it.
                }
                cavetetlist->restart();
                cavebdrylist->restart();
                caveoldtetlist->restart();
                cavetetseglist->restart();
                cavetetshlist->restart();
                if (ivf->splitbdflag) { //if (bowywat > 2) {
                  if (splitseg != NULL) {
                    sunmarktest(*splitseg);
                  }
                  for (i = 0; i < caveshlist->objects; i++) {
                    parysh = (face *) fastlookup(caveshlist, i);
                    assert(smarktested(*parysh));
                    sunmarktest(*parysh);
                  }
                  caveshlist->restart();
                  cavesegshlist->restart();
                }
                // Restore the hullsize.
                hullsize = bakhullsize;
                return (int) BADELEMENT;
              }
            } // if (cutshcount > 0)
          } // if (bowywat > 2)
    
        } // if (cutcount > 0)
    
      } // if (validflag) // if (bowywat > 1)
    
      if (b->verbose > 3) {
        printf("        Final cavity: %ld tets, %ld faces.", 
               caveoldtetlist->objects, cavebdrylist->objects);
        if (cutcount > 0l) {
          printf(" Updated %ld times.", cutcount);
        }
        printf("\n");
      }
    
    
      if (ivf->refineflag) {
        // The new point is inserted by Delaunay refinement, i.e., it is the 
        //   circumcenter of a tetrahedron, or a subface, or a segment.
        //   Do not insert this point if the tetrahedron, or subface, or segment
        //   is not inside the final cavity.
        rejptflag = 0;
        if (ivf->refineflag == 1) {
          // The new point is the circumcenter of a tetrahedron.
          assert(!isdeadtet(ivf->refinetet));
          if (!infected(ivf->refinetet)) {
            rejrefinetetcount++;
            rejptflag = 1;
          }
        } else if (ivf->refineflag == 2) {
          // The new point is the circumcenter of a subface.
          assert(ivf->refinesh.sh != NULL);
          if (!smarktested(ivf->refinesh)) {
            rejrefineshcount++;
            rejptflag = 1;
          }
        }
        if (rejptflag) {
          if (b->verbose > 2) {
            printf("      Point %d does not refine its element. Rejected.\n",
                   pointmark(insertpt));
          }
          // Restore the original status.
          for (i = 0; i < caveoldtetlist->objects; i++) {
            cavetet = (triface *) fastlookup(caveoldtetlist, i);
            uninfect(*cavetet);
            unmarktest(*cavetet);
          }
          for (i = 0; i < cavebdrylist->objects; i++) {
            cavetet = (triface *) fastlookup(cavebdrylist, i);
            unmarktest(*cavetet); // Unmark it.
          }
          // Clear working lists.
          cavetetlist->restart();
          cavebdrylist->restart();
          caveoldtetlist->restart();
          cavetetshlist->restart();
          cavetetseglist->restart();
          cavetetvertlist->restart();
          if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
            if (splitseg != NULL) {
              sunmarktest(*splitseg);
            }
            for (i = 0; i < caveshlist->objects; i++) {
              parysh = (face *) fastlookup(caveshlist, i);
              assert(smarktested(*parysh));
              sunmarktest(*parysh);
            }
            caveshlist->restart();
            cavesegshlist->restart();
          }
    
          // Restore the hullsize.
          hullsize = bakhullsize;
          loc = BADELEMENT;
          return (int) loc;
        } // if (rejptflag)
      } // if (ivf->refineflag)
    
      rejptflag = (ivf->rejflag & 4);
      encptflag = 0;
    
      if (b->weighted || b->plc || rejptflag) {
        // Collect all vertices of C(p).
        for (i = 0; i < caveoldtetlist->objects; i++) {
          cavetet = (triface *) fastlookup(caveoldtetlist, i);
          assert(infected(*cavetet));
          pts = (point *) &(cavetet->tet[4]);
          for (j = 0; j < 4; j++) {
            if (pts[j] != dummypoint) {
              if (!pinfected(pts[j])) {
                pinfect(pts[j]);
                cavetetvertlist->newindex((void **) &parypt);
                *parypt = pts[j];
              }
            }
          } // j
        } // i
        if (b->verbose > 3) {
          printf("        %ld cavity vertices.\n", cavetetvertlist->objects);
        }
        // Uninfect all collected (cavity) vertices.
        for (i = 0; i < cavetetvertlist->objects; i++) {
          parypt = (point *) fastlookup(cavetetvertlist, i);
          puninfect(*parypt);
        }
        if (b->plc || rejptflag) {
          // Check if p is too close to an existing vertex.
          pts = NULL;
          for (i = 0; i < cavetetvertlist->objects; i++) {
            parypt = (point *) fastlookup(cavetetvertlist, i);
            rd = distance(*parypt, insertpt);
            // Is the point very close to an existing point?
            if (rd < b->minedgelength) {
              pts = parypt; 
              break;
            }
            if (rejptflag) {
              // Is the point encroaches upon an existing point?
              if (rd < (*parypt)[pointmtrindex]) {
                // The point lies inside the protection ball.
                if (b->verbose > 2) {
                  printf("      Point %d lies in protball of %d. Rejected.\n",
                         pointmark(insertpt), pointmark(*parypt));
                }
                pts = parypt;
                encptflag = 1; 
                break;
              }
            }
          } // i
          if (pts != NULL) {
            // p is too close to *pts.
            if (ivf->iloc != (int) INSTAR) {
              if (pointmark(insertpt) <= in->numberofpoints) {
                // It's an input point.
                if (!b->quiet) {
                  printf("Warning:  Point %d is replaced by point %d.\n",
                         pointmark(insertpt), pointmark(*pts));
                }
                // Count the number of duplicated points.
                dupverts++;
              } else { // It's a Steiner point.
                if (b->verbose) {
                  if (!rejptflag) {
                    printf("Warning:  Reject a Steiner point %d (close to %d).\n",
                           pointmark(insertpt), pointmark(*pts));
                  }
                }
              }
              // Remember it is a duplicated point.
              setpointtype(insertpt, DUPLICATEDVERTEX);
              // Set a pointer to the point it duplicates.
              setpoint2ppt(insertpt, *pts);
    
              // Restore the original status.
              for (i = 0; i < caveoldtetlist->objects; i++) {
                cavetet = (triface *) fastlookup(caveoldtetlist, i);
                uninfect(*cavetet);
                unmarktest(*cavetet);
              }
              for (i = 0; i < cavebdrylist->objects; i++) {
                cavetet = (triface *) fastlookup(cavebdrylist, i);
                unmarktest(*cavetet); // Unmark it.
              }
              // Clear working lists.
              cavetetlist->restart();
              cavebdrylist->restart();
              caveoldtetlist->restart();
              cavetetshlist->restart();
              cavetetseglist->restart();
              cavetetvertlist->restart();
              if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
                if (splitseg != NULL) {
                  sunmarktest(*splitseg);
                }
                for (i = 0; i < caveshlist->objects; i++) {
                  parysh = (face *) fastlookup(caveshlist, i);
                  assert(smarktested(*parysh));
                  sunmarktest(*parysh);
                }
                caveshlist->restart();
                cavesegshlist->restart();
              }
    
              // Restore the hullsize.
              hullsize = bakhullsize;
              if (!encptflag) {
                loc = NEARVERTEX;
              } else {
                loc = ENCVERTEX; 
              }
              return (int) loc;
            } else {  // (iloc == (int) INSTAR)
              // The cavity is guaranteed to be valid by the caller of this 
              //   function. We still insert this vertex.
              if (b->verbose) {
                printf("Warning:  The Steiner point %d is very close to %d.\n",
                       pointmark(insertpt), pointmark(*pts));
              }
            }
          } // if (pts != NULL)
        } 
      } 
    
      // The new point will be inserted.
      totaldeadtets += caveoldtetlist->objects;
      totalbowatcavsize += cavebdrylist->objects;
      if (maxbowatcavsize < cavebdrylist->objects) {
        maxbowatcavsize = cavebdrylist->objects;
      }
    
      // Before re-mesh C(p). Process the segments and subfaces which are on the
      //   boundary of C(p). Make sure that each such segment or subface is
      //   connecting to a tet outside C(p). So we can re-connect them to the
      //   new tets inside the C(p) later.
    
      if (checksubsegflag) {
        for (i = 0; i < cavetetseglist->objects; i++) {
          paryseg = (face *) fastlookup(cavetetseglist, i);
          // Operate on it if it is not the splitting segment, i.e., in sC(p).
          if (!smarktested(*paryseg)) {
            // Check if the segment is inside the cavity.
            //   'j' counts the num of adjacent tets of this seg.
            //   'k' counts the num of adjacent tets which are 'sinfected'.
            j = k = 0;
            sstpivot1(*paryseg, neightet);
            spintet = neightet;
            while (1) {
              j++;
              if (!infected(spintet)) {
                neineitet =  spintet; // An outer tet. Remember it.
              } else {
                k++; // An in tet.
              }
              fnextself(spintet);
              if (spintet.tet == neightet.tet) break;
            }
            // assert(j > 0);
            if (k == 0) {
              // The segment is not connect to C(p) anymore. Remove it by
              //   Replacing it by the last entry of this list.
              s = cavetetseglist->objects - 1;
              checkseg = * (face *) fastlookup(cavetetseglist, s);
              *paryseg = checkseg;
              cavetetseglist->objects--;
              i--;
            } else if (k < j) {
              // The segment is on the boundary of C(p).
              sstbond1(*paryseg, neineitet);
            } else { // k == j
              // The segment is inside C(p).
              if (!ivf->splitbdflag) {//if (bowywat < 3) { // if (bowywat == 2) {
                checkseg = *paryseg;
                if (b->verbose > 3) {
                  printf("        Queueing a missing seg (%d, %d)\n", 
    	             pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
                }
                sinfect(checkseg); // Flag it as an interior segment.
                caveencseglist->newindex((void **) &paryseg);
                *paryseg = checkseg;
              } else {
                assert(0); // Not possible.
              }
            }
          } else { 
            // assert(smarktested(*paryseg));
            // Flag it as an interior segment. Do not queue it, since it will
            //   be deleted after the segment splitting.
            sinfect(*paryseg);
          }
        } // i
        if (b->verbose > 3) {
          printf("        %ld (%ld) cavity (interior) segments.\n", 
                 cavetetseglist->objects, caveencseglist->objects);
        }
      } // if (checksubsegflag)
    
      if (checksubfaceflag) {
        for (i = 0; i < cavetetshlist->objects; i++) {
          parysh = (face *) fastlookup(cavetetshlist, i);
          // Operate on it if it is not inside the sub-cavity sC(p).
          if (!smarktested(*parysh)) {
            // Check if this subface is inside the cavity.
            k = 0;
            for (j = 0; j < 2; j++) {
              stpivot(*parysh, neightet);
              if (!infected(neightet)) {
                checksh = *parysh; // Remeber this side.
              } else {
                k++;
              }
              sesymself(*parysh);
            }
            if (k == 0) {
              // The subface is not connected to C(p). Remove it.
              s = cavetetshlist->objects - 1;
              checksh = * (face *) fastlookup(cavetetshlist, s);
              *parysh = checksh;
              cavetetshlist->objects--;
              i--;
            } else if (k == 1) {
              // This side is the outer boundary of C(p).
              *parysh = checksh;
            } else { // k == 2
              if (!ivf->splitbdflag) { //if (bowywat < 3) { // if (bowywat == 2) {
                checksh = *parysh;
                if (b->verbose > 3) {
                  printf("        Queueing a missing subface (%d, %d, %d)\n", 
                         pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                         pointmark(sapex(checksh)));
                }
                sinfect(checksh); // Flag it.
                caveencshlist->newindex((void **) &parysh);
                *parysh = checksh;
              } else {
                assert(0); // Not possible.
              }
            }
          } else {
            // assert(smarktested(*parysh));
            // Flag it as an interior subface. Do not queue it. It will be
            //   deleted after the facet point insertion.
            sinfect(*parysh);
          }
        } // i
        if (b->verbose > 3) {
          printf("        %ld (%ld) cavity (interior) subfaces.\n", 
                 cavetetshlist->objects, caveencshlist->objects);
        }
      } // if (checksubfaceflag) {
    
      // Create new tetrahedra to fill the cavity.
    
      for (i = 0; i < cavebdrylist->objects; i++) {
        cavetet = (triface *) fastlookup(cavebdrylist, i);
        neightet = *cavetet;
        assert(!infected(neightet));
        unmarktest(neightet); // Unmark it.
        // Get the oldtet (inside the cavity).
        fsym(neightet, oldtet);
        if (apex(neightet) != dummypoint) {
          // Create a new tet in the cavity (see Fig. bowyerwatson 1 or 3).
          maketetrahedron(&newtet);
          setorg(newtet, dest(neightet));
          setdest(newtet, org(neightet));
          setapex(newtet, apex(neightet));
          setoppo(newtet, insertpt);
          // The new tet inherits attribtes from the old tet.
          for (j = 0; j < in->numberoftetrahedronattributes; j++) {
            attrib = elemattribute(oldtet.tet, j);
            setelemattribute(newtet.tet, j, attrib);
          }
          if (b->varvolume) {
            volume = volumebound(oldtet.tet);
            setvolumebound(newtet.tet, volume);
          }
        } else {
          // Create a new hull tet (see Fig. bowyerwatson 2).
          hullsize++;
          maketetrahedron(&newtet);
          setorg(newtet, org(neightet));
          setdest(newtet, dest(neightet));
          setapex(newtet, insertpt);
          setoppo(newtet, dummypoint); // It must opposite to face 3.
          // Adjust back to the cavity bounday face.
          esymself(newtet);
        }
        // Connect newtet <==> neightet, this also disconnect the old bond.
        bond(newtet, neightet);
        // oldtet still connects to neightet.
        *cavetet = oldtet; // *cavetet = newtet;
      } // i
    
      // Set a handle for speeding point location.
      recenttet = newtet;
      setpoint2tet(insertpt, encode(newtet));
    
      if (ivf->lawson > 1) { // if (lawson == 2 || lawson == 3) {
        // Re-use this list to save new interior cavity faces.
        cavetetlist->restart();
      }
    
      // Connect adjacent new tetrahedra together.
      for (i = 0; i < cavebdrylist->objects; i++) {
        cavetet = (triface *) fastlookup(cavebdrylist, i);
        // cavtet is an oldtet, get the newtet at this face.
        oldtet = *cavetet;
        fsym(oldtet, neightet);
        fsym(neightet, newtet);
        // Comment: oldtet and newtet must be at the same directed edge.
        // Connect the three other faces of this newtet.
        for (j = 0; j < 3; j++) {
          esym(newtet, neightet); // Go to the face.
          if (neightet.tet[neightet.ver & 3] == NULL) {
            // Find the adjacent face of this newtet.
            spintet = oldtet;
            while (1) {
              fnextself(spintet);
              if (!infected(spintet)) break;
            }
            fsym(spintet, newneitet);
            esymself(newneitet);
            assert(newneitet.tet[newneitet.ver & 3] == NULL); // FOR DEBUG
            bond(neightet, newneitet);
            if (ivf->lawson > 1) {
              // We are updateing a CDT. Queue the internal face.
              //   See also fig/dump-cavity-case13, -case21.
              cavetetlist->newindex((void **) &parytet);
              *parytet = neightet;
            }
          }
          setpoint2tet(org(newtet), encode(newtet));
          enextself(newtet);
          enextself(oldtet);
        }
        *cavetet = newtet; // Save the new tet.
      } // i
    
      if (checksubfaceflag) {
        // Connect subfaces on the boundary of the cavity to the new tets.
        for (i = 0; i < cavetetshlist->objects; i++) {
          parysh = (face *) fastlookup(cavetetshlist, i);
          // Connect it if it is not a missing subface.
          if (!sinfected(*parysh)) {
            stpivot(*parysh, neightet);
            fsym(neightet, spintet);
            sesymself(*parysh);
            tsbond(spintet, *parysh);
          }
        }
      }
    
      if (checksubsegflag) {
        // Connect segments on the boundary of the cavity to the new tets.
        for (i = 0; i < cavetetseglist->objects; i++) {
          paryseg = (face *) fastlookup(cavetetseglist, i);
          // Connect it if it is not a missing segment.
          if (!sinfected(*paryseg)) {
            sstpivot1(*paryseg, neightet);
            spintet = neightet;
            while (1) {
              tssbond1(spintet, *paryseg);
              fnextself(spintet);
              if (spintet.tet == neightet.tet) break;
            }
          }
        }
      }
    
      if (splitsh != NULL) {
        // Split a subface or a segment.
        sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat);
      }
    
      if (checksubfaceflag) {
        if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
          // Recover new subfaces in C(p).
          for (i = 0; i < caveshbdlist->objects; i++) {
            // Get an old subface at edge [a, b].
            parysh = (face *) fastlookup(caveshbdlist, i);
            spivot(*parysh, checksh); // The new subface [a, b, p].
            // Do not recover a deleted new face (degenerated).
            if (checksh.sh[3] != NULL) {
              // Note that the old subface still connects to adjacent old tets 
              //   of C(p), which still connect to the tets outside C(p).
              stpivot(*parysh, neightet);
              assert(infected(neightet));
              // Find the adjacent tet containing the edge [a,b] outside C(p).
              spintet = neightet;
              while (1) {
                fnextself(spintet);
                if (!infected(spintet)) break;
                assert(spintet.tet != neightet.tet);
              }
              // The adjacent tet connects to a new tet in C(p).
              fsym(spintet, neightet);
              assert(!infected(neightet));
              // Find the tet containing the face [a, b, p].
              spintet = neightet;
              while (1) {
                fnextself(spintet);
                if (apex(spintet) == insertpt) break;
                assert(spintet.tet != neightet.tet);
              }
              // Adjust the edge direction in spintet and checksh.
              if (sorg(checksh) != org(spintet)) {
                sesymself(checksh);
                assert(sorg(checksh) == org(spintet));
              }
              assert(sdest(checksh) == dest(spintet));
              // Connect the subface to two adjacent tets.
              tsbond(spintet, checksh);
              fsymself(spintet);
              sesymself(checksh);
              tsbond(spintet, checksh);
            } // if (checksh.sh[3] != NULL)
          }
          // There should be no missing interior subfaces in C(p).
          assert(caveencshlist->objects == 0l);
        } else { 
          // bowywat = 1 or bowywat = 2.
          // The Boundary reocvery phase.
          // Put all new subfaces into stack for recovery.
          for (i = 0; i < caveshbdlist->objects; i++) {
            // Get an old subface at edge [a, b].
            parysh = (face *) fastlookup(caveshbdlist, i);
            spivot(*parysh, checksh); // The new subface [a, b, p].
            // Do not recover a deleted new face (degenerated).
            if (checksh.sh[3] != NULL) {
              if (b->verbose > 3) {
                printf("        Queue new subface (%d, %d, %d).\n",
                       pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                       pointmark(sapex(checksh)));
              }
              //sdissolve(checksh); // It has not been connected yet.
              subfacstack->newindex((void **) &parysh);
              *parysh = checksh;
            }
          }
          // Put all interior subfaces into stack for recovery.
          for (i = 0; i < caveencshlist->objects; i++) {
            parysh = (face *) fastlookup(caveencshlist, i);
            assert(sinfected(*parysh));
            // Some subfaces inside C(p) might be split in sinsertvertex().
            //   Only queue those faces which are not split.
            if (!smarktested(*parysh)) {
              if (b->verbose > 3) {
                printf("        Queue a missing subface (%d, %d, %d) x%lx.\n",
                       pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
                       pointmark(sapex(*parysh)), (uintptr_t) parysh->sh);
              }
              checksh = *parysh;
              suninfect(checksh);
              stdissolve(checksh); // Detach connections to old tets.
              subfacstack->newindex((void **) &parysh);
              *parysh = checksh;
            }
          }
        }
      } // if (checksubfaceflag)
    
      if (checksubsegflag) {
        if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
          if (splitseg != NULL) {
            // Recover the two new subsegments in C(p).
            for (i = 0; i < cavesegshlist->objects; i++) {
              paryseg = (face *) fastlookup(cavesegshlist, i);
              // Insert this subsegment into C(p).
              checkseg = *paryseg;
              // Get the adjacent new subface.
              checkseg.shver = 0;
              spivot(checkseg, checksh);
              if (checksh.sh != NULL) {
                // Get the adjacent new tetrahedron.
                stpivot(checksh, neightet);
              } else {
                // It's a dangling segment.
                pa = sorg(checkseg);
                pb = sdest(checkseg);
                point2tetorg(pa, neightet);
                finddirection(&neightet, pb, 1);
                assert(dest(neightet) == pb);
              }
              assert(!infected(neightet));
              sstbond1(checkseg, neightet);
              spintet = neightet;
              while (1) {
                tssbond1(spintet, checkseg);
                fnextself(spintet);
                if (spintet.tet == neightet.tet) break;
              }
            }
          } // if (splitseg != NULL)
          // There should be no interior segment in C(p).
          assert(caveencseglist->objects == 0l);
        } else {
          // bowywat == 1 or bowywat == 2;
          // The Boundary Recovery Phase.  
          // Queue missing segments in C(p) for recovery.
          if (splitseg != NULL) {
            // Queue two new subsegments in C(p) for recovery.
            for (i = 0; i < cavesegshlist->objects; i++) {
              paryseg = (face *) fastlookup(cavesegshlist, i);
              if (b->verbose > 3) {
                printf("        Queue new subseg (%d, %d)\n", 
                       pointmark(sorg(*paryseg)), pointmark(sdest(*paryseg)));
              }
              checkseg = *paryseg;
              //sstdissolve1(checkseg); // It has not been connected yet.
              s = randomnation(subsegstack->objects + 1);
              subsegstack->newindex((void **) &paryseg);
              *paryseg = * (face *) fastlookup(subsegstack, s); 
              paryseg = (face *) fastlookup(subsegstack, s);
              *paryseg = checkseg;
            }
          } // if (splitseg != NULL)
          for (i = 0; i < caveencseglist->objects; i++) {
            paryseg = (face *) fastlookup(caveencseglist, i);
            assert(sinfected(*paryseg));
            if (!smarktested(*paryseg)) { // It may be split.
              if (b->verbose > 3) {
                printf("        Queue a missing segment (%d, %d).\n",
                       pointmark(sorg(*paryseg)), pointmark(sdest(*paryseg)));
              }
              checkseg = *paryseg;
              suninfect(checkseg);
              sstdissolve1(checkseg); // Detach connections to old tets.
              s = randomnation(subsegstack->objects + 1);
              subsegstack->newindex((void **) &paryseg);
              *paryseg = * (face *) fastlookup(subsegstack, s); 
              paryseg = (face *) fastlookup(subsegstack, s);
              *paryseg = checkseg;
            }
          }
        }
      } // if (checksubsegflag)
    
      if (b->plc || b->weighted) {
        // Some vertices may be completed inside the cavity. They must be
        //   detected and added to recovering list.
        if (b->plc) {
          tetcount = subvertstack->objects; // Re-use tetcount;
        }
        // Since every "live" vertex must contain a pointer to a non-dead
        //   tetrahedron, we can check for each vertex this pointer.
        for (i = 0; i < cavetetvertlist->objects; i++) {
          pts = (point *) fastlookup(cavetetvertlist, i);
          decode(point2tet(*pts), *searchtet);
          assert(searchtet->tet != NULL); // No tet has been deleted yet.
          if (infected(*searchtet)) {
            if (b->weighted) {
              if (b->verbose > 2) {
                printf("      Point #%d is removed from the hull.\n",
                       pointmark(*pts));
              }
              setpointtype(*pts, UNUSEDVERTEX);
            } else {
              if (b->verbose > 3) {
                printf("        Queue a dangling vertex %d.\n", pointmark(*pts));
              }
              subvertstack->newindex((void **) &parypt);
              *parypt = *pts;
            }
          }
        }
        if (b->plc) {
          if (subvertstack->objects > tetcount) {
            // There are missing vertices after inserting the new point.
            printf("DBG: Insert %d. Found %ld interior vertices.\n",
                   pointmark(insertpt), subvertstack->objects);
            assert(0); // NEED TO DEBUG.
          }
        }
      }
    
      if (ivf->chkencflag & 1) {
        // Queue all segment outside C(p).
        for (i = 0; i < cavetetseglist->objects; i++) {
          paryseg = (face *) fastlookup(cavetetseglist, i);
          // Skip if it is the split segment.
          if (!sinfected(*paryseg)) {
            // Skip it if it has already queued.
            if (!smarktest2ed(*paryseg)) {
              bface = (badface *) badsubsegs->alloc();
              bface->ss = *paryseg;
              smarktest2(bface->ss); // Only queue it once.
              bface->forg = sorg(*paryseg); // An alive badface.
            }
          }
        }
        if (splitseg != NULL) {
          // Queue the two new subsegments inside C(p).
          for (i = 0; i < cavesegshlist->objects; i++) {
            paryseg = (face *) fastlookup(cavesegshlist, i);
            bface = (badface *) badsubsegs->alloc();
            bface->ss = *paryseg;
            smarktest2(bface->ss); // Only queue it once.
            bface->forg = sorg(*paryseg); // An alive badface.
          }
        }
      } // if (chkencflag & 1)
    
      if (ivf->chkencflag & 2) {
        // Queue all subfaces outside C(p).
        for (i = 0; i < cavetetshlist->objects; i++) {
          parysh = (face *) fastlookup(cavetetshlist, i);
          // Skip if it is a split subface.
          if (!sinfected(*parysh)) {
            // Skip it if it has already queued.
            if (!smarktest2ed(*parysh)) {
              bface = (badface *) badsubfacs->alloc();
              bface->ss = *parysh;
              smarktest2(bface->ss); // Only queue it once.
              bface->forg = sorg(*parysh); // An alive badface.
              //bface->fdest = sdest(*parysh);
              //bface->fapex = sapex(*parysh);
            }
          }
        }
        // Queue all new subfaces inside C(p).
        for (i = 0; i < caveshbdlist->objects; i++) {
          // Get an old subface at edge [a, b].
          parysh = (face *) fastlookup(caveshbdlist, i);
          spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
          // Do not recover a deleted new face (degenerated).
          if (checksh.sh[3] != NULL) {
            //assert(!smarktest2ed(checksh));
            bface = (badface *) badsubfacs->alloc();
            bface->ss = checksh;
            smarktest2(bface->ss); // Only queue it once.
            bface->forg = sorg(checksh); // An alive badface.
          }
        }
      } // if (chkencflag & 2)
    
      if (ivf->chkencflag & 4) {
        // Queue all new tetrahedra in C(p).
        for (i = 0; i < cavebdrylist->objects; i++) {
          cavetet = (triface *) fastlookup(cavebdrylist, i);
          //assert(!marktest2ed(*cavetet));
          bface = (badface *) badtetrahedrons->alloc();
          bface->tt = *cavetet;
          marktest2(bface->tt);
          bface->forg = org(*cavetet);
        }
      }
    
      // C(p) is re-meshed successfully. 
    
      // Deleted the old tets in C(p).
      for (i = 0; i < caveoldtetlist->objects; i++) {
        searchtet = (triface *) fastlookup(caveoldtetlist, i);
        tetrahedrondealloc(searchtet->tet);
      }
    
      if (splitsh != NULL) {
        // Delete the old subfaces in sC(p).
        for (i = 0; i < caveshlist->objects; i++) {
          parysh = (face *) fastlookup(caveshlist, i);
          if (checksubfaceflag) {//if (bowywat == 2) {
            // It is possible that this subface still connects to adjacent
            //   tets which are not in C(p). If so, clear connections in the
            //   adjacent tets at this subface.
            stpivot(*parysh, neightet);
            if (neightet.tet != NULL) {
              if (neightet.tet[4] != NULL) {
                // Found an adjacent tet. It must be not in C(p).
                assert(!infected(neightet));
                tsdissolve(neightet);
                fsymself(neightet);
                assert(!infected(neightet));
                tsdissolve(neightet);
              }
            }
          }
          shellfacedealloc(subfaces, parysh->sh);
        }
        if (splitseg != NULL) {
          // Delete the old segment in sC(p).
          shellfacedealloc(subsegs, splitseg->sh);
        }
      }
    
      if (ivf->lawson) {
        for (i = 0; i < cavebdrylist->objects; i++) {
          searchtet = (triface *) fastlookup(cavebdrylist, i);
          //flippush(flipstack, searchtet, insertpt);
          flippush(flipstack, searchtet);
        }
        if (ivf->lawson > 1) {
          for (i = 0; i < cavetetlist->objects; i++) {
            searchtet = (triface *) fastlookup(cavetetlist, i);
            //flippush(flipstack, searchtet, oppo(*searchtet));
            flippush(flipstack, searchtet);
          }
        }
      }
    
      // The vertex should already have a type.
      assert(pointtype(insertpt) != UNUSEDVERTEX);
    
    #ifdef WITH_RUNTIME_COUNTERS
      tend = clock();
      t_ptinsert += (tend - tstart);
    #endif
    
      if (b->btree) {
        btree_insert(insertpt);
      }
    
      // Clean the working lists.
    
      caveoldtetlist->restart();
      cavebdrylist->restart();
      cavetetlist->restart();
    
      if (checksubsegflag) {
        cavetetseglist->restart();
        caveencseglist->restart();
      }
    
      if (checksubfaceflag) {
        cavetetshlist->restart();
        caveencshlist->restart();
      }
      
      if (b->plc || b->weighted) {
        cavetetvertlist->restart();
      }
      
      if (splitsh != NULL) {
        caveshlist->restart();
        caveshbdlist->restart();
        cavesegshlist->restart();
      }
    
      return (int) loc;
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// flip_cxx /////////////////////////////////////////////////////////////////
    
    //// delaunay_cxx /////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // transfernodes()    Read the vertices from the input (tetgenio).           //
    //                                                                           //
    // Initializing 'this->points'.  Transferring all points from 'in->pointlist'//
    // into it. All points are indexed (start from in->firstnumber).  Each point //
    // is initialized be UNUSEDVERTEX.  The bounding box (xmin, xmax, ymin, ymax,//
    // zmin, zmax) and the diameter (longest) of the point set are calculated.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::transfernodes()
    {
      point pointloop;
      REAL x, y, z, w;
      int coordindex;
      int attribindex;
      int mtrindex;
      int i, j;
    
      if (b->psc) {
        assert(in->pointparamlist != NULL);
      }
    
      // Read the points.
      coordindex = 0;
      attribindex = 0;
      mtrindex = 0;
      for (i = 0; i < in->numberofpoints; i++) {
        makepoint(&pointloop, UNUSEDVERTEX);
        // Read the point coordinates.
        x = pointloop[0] = in->pointlist[coordindex++];
        y = pointloop[1] = in->pointlist[coordindex++];
        z = pointloop[2] = in->pointlist[coordindex++];    
        if (b->weighted) { // -w option
          if (in->numberofpointattributes > 0) {
            // The first point attribute is weight.
            w = in->pointattributelist[in->numberofpointattributes * i];
          } else {
            // No given weight available.
            w = 0;
          }
          if (b->weighted_param == 0) {
            pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
          } else { // -w1 option
            pointloop[3] = w;  // Regular tetrahedralization.
          }
        } else {
          pointloop[3] = 0;
        }
        // Read the point attributes.
        for (j = 0; j < in->numberofpointattributes; j++) {
          pointloop[4 + j] = in->pointattributelist[attribindex++];
        }
        // Read the point metric tensor.
        for (j = 0; j < in->numberofpointmtrs; j++) {
          pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
        }
        // Determine the smallest and largests x, y and z coordinates.
        if (i == 0) {
          xmin = xmax = x;
          ymin = ymax = y;
          zmin = zmax = z;
        } else {
          xmin = (x < xmin) ? x : xmin;
          xmax = (x > xmax) ? x : xmax;
          ymin = (y < ymin) ? y : ymin;
          ymax = (y > ymax) ? y : ymax;
          zmin = (z < zmin) ? z : zmin;
          zmax = (z > zmax) ? z : zmax;
        }
        if (b->psc) {
          // Read the geometry parameters.
          setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
          setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
          setpointgeomtag(pointloop, in->pointparamlist[i].tag);
          if (in->pointparamlist[i].type == 0) {
            setpointtype(pointloop, RIDGEVERTEX);
          } else if (in->pointparamlist[i].type == 1) {
            setpointtype(pointloop, FREESEGVERTEX);
          } else if (in->pointparamlist[i].type == 2) {
            setpointtype(pointloop, FREEFACETVERTEX);
          } else if (in->pointparamlist[i].type == 3) {
            setpointtype(pointloop, FREEVOLVERTEX);
          }
        }
      }
    
      // 'longest' is the largest possible edge length formed by input vertices.
      x = xmax - xmin;
      y = ymax - ymin;
      z = zmax - zmin;
      longest = sqrt(x * x + y * y + z * z);
      if (longest == 0.0) {
        printf("Error:  The point set is trivial.\n");
        terminatetetgen(3);
      }
    
      // Two identical points are distinguished by 'lengthlimit'.
      if (b->minedgelength == 0.0) {
        b->minedgelength = longest * b->epsilon;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // btree_sort()    Sort vertices using a binary space partition (bsp) tree.  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::btree_sort(point* vertexarray, int arraysize, int axis, 
                                REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, 
                                REAL bzmin, REAL bzmax, int depth)
    {
      point *leftarray, *rightarray;
      point **pptary, swapvert;
      REAL split;
      bool lflag, rflag;
      int i, j, k; // *iptr,
    
      if (b->verbose > 3) {
        printf("  Depth %d, %d verts. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
               depth, arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
               axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
      }
    
      if (depth > max_btree_depth) {
        max_btree_depth = depth;
      }
    
      if (axis == 0) {
        // Split along x-axis.
        split = 0.5 * (bxmin + bxmax);
      } else if (axis == 1) {
        // Split along y-axis.
        split = 0.5 * (bymin + bymax);
      } else {
        // Split along z-axis.
        split = 0.5 * (bzmin + bzmax);
      }
    
    
      i = 0;
      j = arraysize - 1;
    
      // Partition the vertices into left- and right-arraies.
      do {
        for (; i < arraysize; i++) {
          if (vertexarray[i][axis] >= split) {
            break;
          }
        }
        for (; j >= 0; j--) {
          if (vertexarray[j][axis] < split) {
            break;
          }
        }
        // Is the partition finished?
        if (i == (j + 1)) {
          break;
        }
        // Swap i-th and j-th vertices.
        swapvert = vertexarray[i];
        vertexarray[i] = vertexarray[j];
        vertexarray[j] = swapvert;
        // Continue patitioning the array;
      } while (true);
    
      if (b->verbose > 3) {
        printf("        leftsize = %d, rightsize = %d\n", i, arraysize - i);
      }
      lflag = rflag = false;
    
      // Do not continue the partition if one of the array sizes is 0.
      // if (depth < max_tree_depth) {
      if (!((i == 0) || (i == arraysize))) {
        if (i > b->max_btreenode_size) {
          // Recursively partition the left array (length = i).
          if (axis == 0) { // x
            btree_sort(vertexarray, i, (axis + 1) % 3, bxmin, split, bymin, 
                       bymax, bzmin, bzmax, depth + 1);
          } else if (axis == 1) { // y
            btree_sort(vertexarray, i, (axis + 1) % 3, bxmin, bxmax, bymin, 
                       split, bzmin, bzmax, depth + 1);
          } else { // z
            btree_sort(vertexarray, i, (axis + 1) % 3, bxmin, bxmax, bymin, 
                       bymax, bzmin, split, depth + 1);
          }
        } else {
          lflag = true;
        }
        if ((arraysize - i) > b->max_btreenode_size) {
          // Recursively partition the right array (length = arraysize - i).
          if (axis == 0) { // x
            btree_sort(&(vertexarray[i]), arraysize - i, (axis + 1) % 3, split, 
                       bxmax, bymin, bymax, bzmin, bzmax, depth + 1);
          } else if (axis == 1) { // y
            btree_sort(&(vertexarray[i]), arraysize - i, (axis + 1) % 3, bxmin, 
                       bxmax, split, bymax, bzmin, bzmax, depth + 1);
          } else { // z
            btree_sort(&(vertexarray[i]), arraysize - i, (axis + 1) % 3, bxmin, 
                       bxmax, bymin, bymax, split, bzmax, depth + 1);
          }
        } else {
          rflag = true;
        }
      } else {
        // Both left and right are done.
        lflag = rflag = true;
      }
    
      if (lflag && (i > 0)) {
        // Remember the maximal length of the partitions.
        if (i > max_btreenode_size) {
          max_btreenode_size = i;
        }
        // Allocate space for the left array (use the first entry to save
        //   the length of this array).
        leftarray = new point[i + 1]; 
        leftarray[0] = (point) i; // The array lenth.
        //iptr = (int *) &(leftarray[0]);
        //*iptr = i; // Save the array lenth in the first entry.
        // Put all points in this array.
        for (k = 0; k < i; k++) {
          leftarray[k + 1] = vertexarray[k];
          setpoint2ppt(leftarray[k + 1], (point) leftarray);
        }
        // Save this array in list.
        btreenode_list->newindex((void **) &pptary);
        *pptary = leftarray;
      }
    
      // Get the length of the right array.
      j = arraysize - i;
      if (rflag && (j > 0)) {
        if (j > max_btreenode_size) {
          max_btreenode_size = j;
        }
        // Allocate space for the right array (use the first entry to save
        //   the length of this array).
        rightarray = new point[j + 1];
        rightarray[0] = (point) j; // The array lenth.
        //iptr = (int *) &(rightarray[0]);
        //*iptr = j; // Save the array length in the first entry.
        // Put all points in this array.
        for (k = 0; k < j; k++) {
          rightarray[k + 1] = vertexarray[i + k];
          setpoint2ppt(rightarray[k + 1], (point) rightarray);
        }
        // Save this array in list.
        btreenode_list->newindex((void **) &pptary);
        *pptary = rightarray;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // btree_insert()    Add a vertex into a tree node.                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::btree_insert(point insertpt)
    {
      point *ptary;
      long arylen; // The array lenhgth is saved in ptary[0].
    
      // Get the tree node (save in this point).
      ptary = (point *) point2ppt(insertpt);
      // Get the current array length.
      arylen = (long) ptary[0];
      // Insert the point into the node.
      ptary[arylen + 1] = insertpt;
      // Increase the array length by 1.
      ptary[0] = (point) (arylen + 1);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // btree_search()    Search a near point for an inserting point.             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::btree_search(point insertpt, triface* searchtet)
    {
      point *ptary;
      point nearpt, candpt;
      REAL dist2, mindist2;
      int ptsamples, ptidx;
      long arylen;
      int i;
    
      // Get the tree node (save in this point).
      ptary = (point *) point2ppt(insertpt);
      // Get the current array length.
      arylen = (long) ptary[0];
    
      if (arylen == 0) {
        searchtet->tet = NULL;
        return;
      }
    
      if (1) {
    
        if (arylen < 5) { //if (arylen < 10) {
          ptsamples = arylen;
        } else {
          ptsamples = 5; // Take at least 10 samples.
          //   The number of random samples taken is proportional to the third root
          //   of the number of points in the cell.
          while (ptsamples * ptsamples * ptsamples < arylen) {
            ptsamples++;
          }
        }
    
        // Select "good" candidate using k random samples, taking the closest one.
        mindist2 = 1.79769E+308; // The largest double value (8 byte).
        nearpt = NULL;
    
        for (i = 0; i < ptsamples; i++) {
          ptidx = randomnation((unsigned long) arylen);
          candpt = ptary[ptidx + 1];
          dist2 = (candpt[0] - insertpt[0]) * (candpt[0] - insertpt[0])
                + (candpt[1] - insertpt[1]) * (candpt[1] - insertpt[1])
                + (candpt[2] - insertpt[2]) * (candpt[2] - insertpt[2]);
          if (dist2 < mindist2) {
            mindist2 = dist2;
            nearpt = candpt;
          }
        }
    
      } else {
    
        // TEST, randomly select a point.
        ptidx = randomnation((unsigned long) arylen);
        nearpt = ptary[ptidx + 1];
    
      }
    
      if (b->verbose > 2) {
        printf("      Get point %d (cell size %ld).\n", pointmark(nearpt), arylen);
      }
    
      decode(point2tet(nearpt), *searchtet);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // ordervertices()    Order the vertices for incremental inserting.          //
    //                                                                           //
    // We assume the vertices have been sorted by a binary tree.                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::ordervertices(point* vertexarray, int arraysize)
    {
      point **ipptary, **jpptary, *swappptary; 
      point *ptary;
      long arylen;
      int index, i, j;
    
      // First pick one vertex from each tree node.
      for (i = 0; i < (int) btreenode_list->objects; i++) {
        ipptary = (point **) fastlookup(btreenode_list, i);
        ptary = *ipptary;
        vertexarray[i] = ptary[1]; // Skip the first entry.
      }
    
      index = i;
      // Then put all other points in the array node by node.
      for (i = (int) btreenode_list->objects - 1; i >= 0; i--) {
        // Randomly pick a tree node.
        j = randomnation(i + 1);
        // Save the i-th node.
        ipptary = (point **) fastlookup(btreenode_list, i);
        // Get the j-th node.
        jpptary = (point **) fastlookup(btreenode_list, j);
        // Order the points in the node.
        ptary = *jpptary;
        arylen = (long) ptary[0];
        for (j = 2; j <= arylen; j++) { // Skip the first point.
          vertexarray[index] = ptary[j];
          index++;
        }
        // Clear this tree node.
        ptary[0] = (point) 0;
        // Swap i-th node to j-th node.
        swappptary = *ipptary;
        *ipptary = *jpptary; // [i] <= [j]
        *jpptary = swappptary; // [j] <= [i]
      }
    
      // Make sure we've done correctly.
      assert(index == arraysize);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // randomnation()    Generate a random number between 0 and 'choices' - 1.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    unsigned long tetgenmesh::randomnation(unsigned int choices)
    {
      unsigned long newrandom;
    
      if (choices >= 714025l) {
        newrandom = (randomseed * 1366l + 150889l) % 714025l;
        randomseed = (newrandom * 1366l + 150889l) % 714025l;
        newrandom = newrandom * (choices / 714025l) + randomseed;
        if (newrandom >= choices) {
          return newrandom - choices;
        } else {
          return newrandom;
        }
      } else {
        randomseed = (randomseed * 1366l + 150889l) % 714025l;
        return randomseed % choices;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // randomsample()    Randomly sample the tetrahedra for point loation.       //
    //                                                                           //
    // This routine implements Muecke's Jump-and-walk point location algorithm.  //
    // It improves the simple walk-through by "jumping" to a good starting point //
    // via random sampling.  Searching begins from one of handles:  the input    //
    // 'searchtet', a recently encountered tetrahedron 'recenttet',  or from one //
    // chosen from a random sample.  The choice is made by determining which one //
    // 's origin is closest to the point we are searcing for.  Having chosen the //
    // starting tetrahedron, the simple Walk-through algorithm is executed.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::randomsample(point searchpt, triface *searchtet)
    {
      tetrahedron *firsttet, *tetptr;
      point torg;
      void **sampleblock;
      uintptr_t alignptr;
      long sampleblocks, samplesperblock, samplenum;
      long tetblocks, i, j;
      REAL searchdist, dist;
    
      if (b->verbose > 2) {
        printf("      Random sampling tetrahedra for searching point %d.\n",
               pointmark(searchpt));
      }
    
      if (searchtet->tet == NULL) {
        // A null tet. Choose the recenttet as the starting tet.
        *searchtet = recenttet;
        // Recenttet should not be dead.
        assert(recenttet.tet[4] != NULL);
      }
    
      // 'searchtet' should be a valid tetrahedron. Choose the base face
      //   whose vertices must not be 'dummypoint'.
      searchtet->ver = 3;
      // Record the distance from its origin to the searching point.
      torg = org(*searchtet);
      searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
                   (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
                   (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
      if (b->verbose > 3) {
        printf("        Dist %g from tet (%d, %d, %d, %d).\n", searchdist,
               pointmark(torg), pointmark(dest(*searchtet)), 
               pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
      }
    
      // If a recently encountered tetrahedron has been recorded and has not
      //   been deallocated, test it as a good starting point.
      if (recenttet.tet != searchtet->tet) {
        recenttet.ver = 3;
        torg = org(recenttet);
        dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
               (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
               (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
        if (dist < searchdist) {
          *searchtet = recenttet;
          searchdist = dist;
          if (b->verbose > 3) {
            printf("        Dist %g from recent tet (%d, %d, %d, %d).\n", 
                   searchdist, pointmark(torg), pointmark(dest(*searchtet)), 
                   pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
          }
        }
      }
    
      // Select "good" candidate using k random samples, taking the closest one.
      //   The number of random samples taken is proportional to the fourth root
      //   of the number of tetrahedra in the mesh. 
      while (samples * samples * samples * samples < tetrahedrons->items) {
        samples++;
      }
      // Find how much blocks in current tet pool.
      tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1) 
                / b->tetrahedraperblock;
      // Find the average samples per block. Each block at least have 1 sample.
      samplesperblock = 1 + (samples / tetblocks);
      sampleblocks = samples / samplesperblock;
      sampleblock = tetrahedrons->firstblock;
      for (i = 0; i < sampleblocks; i++) {
        alignptr = (uintptr_t) (sampleblock + 1);
        firsttet = (tetrahedron *)
                   (alignptr + (uintptr_t) tetrahedrons->alignbytes
                   - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
        for (j = 0; j < samplesperblock; j++) {
          if (i == tetblocks - 1) {
            // This is the last block.
            samplenum = randomnation((int)
                          (tetrahedrons->maxitems - (i * b->tetrahedraperblock)));
          } else {
            samplenum = randomnation(b->tetrahedraperblock);
          }
          tetptr = (tetrahedron *)
                   (firsttet + (samplenum * tetrahedrons->itemwords));
          torg = (point) tetptr[4];
          if (torg != (point) NULL) {
            dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
                   (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
                   (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
            if (dist < searchdist) {
              searchtet->tet = tetptr;
              searchtet->ver = 11; // torg = org(t);
              searchdist = dist;
              if (b->verbose > 3) {
                printf("        Dist %g from tet (%d, %d, %d, %d).\n", searchdist,
                   pointmark(torg), pointmark(dest(*searchtet)), 
                   pointmark(apex(*searchtet)), pointmark(oppo(*searchtet)));
              }
            }
          } else {
            // A dead tet. Re-sample it.
            if (i != tetblocks - 1) j--;
          }
        }
        sampleblock = (void **) *sampleblock;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // locate()    Find a tetrahedron containing a given point.                  //
    //                                                                           //
    // This routine implements the simple Walk-through point location algorithm. //
    // Begins its search from 'searchtet', assume there is a line segment L from //
    // a vertex of 'searchtet' to the query point 'searchpt', and simply walk    //
    // towards 'searchpt' by traversing all faces intersected by L.              //
    //                                                                           //
    // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
    // returned value indicates one of the following cases:                      //
    //   - ONVERTEX, the search point lies on the origin of 'searchtet'.         //
    //   - ONEDGE, the search point lies on an edge of 'searchtet'.              //
    //   - ONFACE, the search point lies on a face of 'searchtet'.               //
    //   - INTET, the search point lies in the interior of 'searchtet'.          //
    //   - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a     //
    //     hull tetrahedron whose base face is visible by the search point.      //
    //                                                                           //
    // WARNING: This routine is designed for convex triangulations, and will not //
    // generally work after the holes and concavities have been carved.          //
    //                                                                           //
    // If 'randflag' is set (> 0). Randomly choose a tetrahedron when there are  //
    // multiple choices in the path.                                             // 
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    enum tetgenmesh::locateresult 
      tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag, 
                         int randflag)
    {
      triface neightet; 
      face checksh;
      point torg, tdest, tapex, toppo;
      enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
      REAL ori, oriorg, oridest, oriapex;
      enum locateresult loc;
      int s; // i;
    
    
      if (searchtet->tet == NULL) {
        // A null tet. Choose the recenttet as the starting tet.
        *searchtet = recenttet;
        // Recenttet should not be dead.
        assert(recenttet.tet[4] != NULL);
      }
    
      // Check if we are in the outside of the convex hull.
      if (ishulltet(*searchtet)) {
        // Get its adjacent tet (inside the hull).
        searchtet->ver = 3;
        fsymself(*searchtet);
        assert(!ishulltet(*searchtet));
      }
    
      // Let searchtet be the face such that 'searchpt' lies above to it.
      for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
        torg = org(*searchtet);
        tdest = dest(*searchtet);
        tapex = apex(*searchtet);
        ori = orient3d(torg, tdest, tapex, searchpt); orient3dcount++;
        if (ori < 0.0) break;
      }
      if (searchtet->ver == 4) {
        // Either 'searchtet' is a very flat tet, or the 'searchpt' lies in
        //   infinity, or both of them. Return OUTSIDE.
        assert(0); // return OUTSIDE;
      }
    
      loc = OUTSIDE; // Set a default return value.
    
      // Walk through tetrahedra to locate the point.
      while (true) {
    
        ptloc_count++;  // Algorithimic count.
    
        toppo = oppo(*searchtet);
        
        // Check if the vertex is we seek.
        if (toppo == searchpt) {
          // Adjust the origin of searchtet to be searchpt.
          esymself(*searchtet);
          eprevself(*searchtet);
          loc = ONVERTEX; // return ONVERTEX;
          break;
        }
    
        // We enter from serarchtet's base face. There are three other faces in
        //   searchtet (all connecting to toppo), which one is the exit?
        oriorg = orient3d(tdest, tapex, toppo, searchpt); 
        oridest = orient3d(tapex, torg, toppo, searchpt);
        oriapex = orient3d(torg, tdest, toppo, searchpt);
        orient3dcount+=3;
    
        // Now decide which face to move. It is possible there are more than one
        //   faces are viable moves. Use the opposite points of thier neighbors
        //   to discriminate, i.e., we choose the face whose opposite point has
        //   the shortest distance to searchpt.
        if (oriorg < 0) {
          if (oridest < 0) {
            if (oriapex < 0) {
              if (0) { //if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(3); // 's' is in {0,1,2}.
                if (s == 0) {
                  nextmove = ORGMOVE;
                } else if (s == 1) {
                  nextmove = DESTMOVE;
                } else {
                  nextmove = APEXMOVE;
                }
              } // if (randflag)
            } else {
              // Two faces, opposite to origin and destination, are viable.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(2); // 's' is in {0,1}.
                if (s == 0) {
                  nextmove = ORGMOVE;
                } else {
                  nextmove = DESTMOVE;
                }
              } // if (randflag)
            }
          } else {
            if (oriapex < 0) {
              // Two faces, opposite to origin and apex, are viable.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(2); // 's' is in {0,1}.
                if (s == 0) {
                  nextmove = ORGMOVE;
                } else {
                  nextmove = APEXMOVE;
                }
              } // if (randflag)
            } else {
              // Only the face opposite to origin is viable.
              nextmove = ORGMOVE;
            }
          }
        } else {
          if (oridest < 0) {
            if (oriapex < 0) {
              // Two faces, opposite to destination and apex, are viable.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(2); // 's' is in {0,1}.
                if (s == 0) {
                  nextmove = DESTMOVE;
                } else {
                  nextmove = APEXMOVE;
                }
              } // if (randflag)
            } else {
              // Only the face opposite to destination is viable.
              nextmove = DESTMOVE;
            }
          } else {
            if (oriapex < 0) {
              // Only the face opposite to apex is viable.
              nextmove = APEXMOVE;
            } else {
              // The point we seek must be on the boundary of or inside this
              //   tetrahedron. Check for boundary cases.
              if (oriorg == 0) {
                // Go to the face opposite to origin.
                //enextfnextself(*searchtet);
                enextesymself(*searchtet);
                if (oridest == 0) {
                  //enextself(*searchtet); // edge apex->oppo
                  eprevself(*searchtet); // edge oppo->apex
                  if (oriapex == 0) {
                    // oppo is duplicated with p.
                    loc = ONVERTEX; // return ONVERTEX;
                    break;
                  }
                  loc = ONEDGE; // return ONEDGE;
                  break;
                }
                if (oriapex == 0) {
                  //enext2self(*searchtet);
                  enextself(*searchtet); // edge dest->oppo
                  loc = ONEDGE; // return ONEDGE;
                  break;
                }
                loc = ONFACE; // return ONFACE;
                break;
              }
              if (oridest == 0) {
                // Go to the face opposite to destination.
                //enext2fnextself(*searchtet);
                eprevesymself(*searchtet);
                if (oriapex == 0) {
                  //enextself(*searchtet);
                  eprevself(*searchtet); // edge oppo->org
                  loc = ONEDGE; // return ONEDGE;
                  break;
                }
                loc = ONFACE; // return ONFACE;
                break;
              }
              if (oriapex == 0) {
                // Go to the face opposite to apex
                //fnextself(*searchtet);
                esymself(*searchtet);
                loc = ONFACE; // return ONFACE;
                break;
              }
              loc = INTETRAHEDRON; // return INTETRAHEDRON;
              break;
            }
          }
        }
        
        // Move to the selected face.
        if (nextmove == ORGMOVE) {
          enextesymself(*searchtet);
        } else if (nextmove == DESTMOVE) {
          eprevesymself(*searchtet);
        } else {
          esymself(*searchtet);
        }
        if (chkencflag) {
          // Check if we are walking across a subface.
          tspivot(*searchtet, checksh);
          if (checksh.sh != NULL) {
            loc = ENCSUBFACE;
            break;
          }
        }
        // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
        fsymself(*searchtet);
        if (oppo(*searchtet) == dummypoint) {
          loc = OUTSIDE; // return OUTSIDE;
          break;
        }
    
        // Retreat the three vertices of the base face.
        torg = org(*searchtet);
        tdest = dest(*searchtet);
        tapex = apex(*searchtet);
    
      } // while (true)
    
      return loc;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // initialdelaunay()    Create an initial Delaunay tetrahedralization.       //
    //                                                                           //
    // The tetrahedralization contains only one tetrahedron abcd, and four hull  //
    // tetrahedra. The points pa, pb, pc, and pd must be linearly independent.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
    {
      triface firsttet, tetopa, tetopb, tetopc, tetopd;
      triface worktet, worktet1;
    
      if (b->verbose > 2) {
        printf("      Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd));
      }
    
      // Create the first tetrahedron.
      maketetrahedron(&firsttet);
      setvertices(firsttet, pa, pb, pc, pd);
      // Create four hull tetrahedra.
      maketetrahedron(&tetopa);
      setvertices(tetopa, pb, pc, pd, dummypoint);
      maketetrahedron(&tetopb);
      setvertices(tetopb, pc, pa, pd, dummypoint);
      maketetrahedron(&tetopc);
      setvertices(tetopc, pa, pb, pd, dummypoint);
      maketetrahedron(&tetopd);
      setvertices(tetopd, pb, pa, pc, dummypoint);
      hullsize += 4;
    
      // Connect hull tetrahedra to firsttet (at four faces of firsttet).
      bond(firsttet, tetopd);
      esym(firsttet, worktet);
      bond(worktet, tetopc); // ab
      enextesym(firsttet, worktet);
      bond(worktet, tetopa); // bc 
      eprevesym(firsttet, worktet);
      bond(worktet, tetopb); // ca
    
      // Connect hull tetrahedra together (at six edges of firsttet).
      esym(tetopc, worktet); 
      esym(tetopd, worktet1);
      bond(worktet, worktet1); // ab
      esym(tetopa, worktet);
      eprevesym(tetopd, worktet1);
      bond(worktet, worktet1); // bc
      esym(tetopb, worktet);
      enextesym(tetopd, worktet1);
      bond(worktet, worktet1); // ca
      eprevesym(tetopc, worktet);
      enextesym(tetopb, worktet1);
      bond(worktet, worktet1); // da
      eprevesym(tetopa, worktet);
      enextesym(tetopc, worktet1);
      bond(worktet, worktet1); // db
      eprevesym(tetopb, worktet);
      enextesym(tetopa, worktet1);
      bond(worktet, worktet1); // dc
    
      // Set the vertex type.
      if (pointtype(pa) == UNUSEDVERTEX) {
        setpointtype(pa, VOLVERTEX);
      }
      if (pointtype(pb) == UNUSEDVERTEX) {
        setpointtype(pb, VOLVERTEX);
      }
      if (pointtype(pc) == UNUSEDVERTEX) {
        setpointtype(pc, VOLVERTEX);
      }
      if (pointtype(pd) == UNUSEDVERTEX) {
        setpointtype(pd, VOLVERTEX);
      }
    
      if (b->btree) {
        btree_insert(pa);
        btree_insert(pb);
        btree_insert(pc);
        btree_insert(pd);
      }
    
      setpoint2tet(pa, encode(firsttet));
      setpoint2tet(pb, encode(firsttet));
      setpoint2tet(pc, encode(firsttet));
      setpoint2tet(pd, encode(firsttet));
    
      // Remember the first tetrahedron.
      recenttet = firsttet;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // incrementaldelaunay()    Create a Delaunay tetrahedralization by          //
    //                          the incremental approach.                        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::incrementaldelaunay(clock_t& tv)
    {
      triface searchtet;
      point *permutarray, swapvertex;
      insertvertexflags ivf;
      REAL v1[3], v2[3], n[3];
      REAL bboxsize, bboxsize2, bboxsize3, ori;
      int randindex, loc; 
      int i, j;
    
      if (!b->quiet) {
        printf("Delaunizing vertices...\n");
      }
    
      if (b->max_btreenode_size > 0) { // not -u0.
        b->btree = 1;
        btreenode_list = new arraypool(sizeof(point*), 10);
        max_btreenode_size = 0;
        max_btree_depth = 0;
      }
    
    
      // Form a random permuation (uniformly at random) of the set of vertices.
      permutarray = new point[in->numberofpoints];
      points->traversalinit();
      if (b->btree) { // -u option
        for (i = 0; i < in->numberofpoints; i++) {
          permutarray[i] = (point) points->traverse();
        }
        if (b->verbose) {
          printf("  Sorting vertices by a bsp-tree.\n");
        }
        // Sort the points using a binary tree recursively.
        btree_sort(permutarray, in->numberofpoints, 0, xmin, xmax, ymin, ymax,
                   zmin, zmax, 0);
        if (b->verbose) {
          printf("  Number of tree nodes: %ld.\n", btreenode_list->objects);
          printf("  Maximum tree node size: %d.\n", max_btreenode_size);
          printf("  Maximum tree depth: %d.\n", max_btree_depth);
        }
        // Order the sorted points.
        ordervertices(permutarray, in->numberofpoints);
      } else if (b->hilbertcurve) {
        if (b->verbose) {
          printf("  Sorting vertices by hilbert curve.\n"); 
        }
        // To be done...
        for (i = 0; i < in->numberofpoints; i++) {
          permutarray[i] = (point) points->traverse();
        }
      } else {
        if (b->verbose) {
          printf("  Permuting vertices.\n"); 
        }
        for (i = 0; i < in->numberofpoints; i++) {
          randindex = randomnation(i + 1);
          permutarray[i] = permutarray[randindex];
          permutarray[randindex] = (point) points->traverse();
        }
      }
    
      tv = clock(); // Remember the time for sorting points.
    
      // Calculate the diagonal size of its bounding box.
      bboxsize = sqrt(NORM2(xmax - xmin, ymax - ymin, zmax - zmin));
      bboxsize2 = bboxsize * bboxsize;
      bboxsize3 = bboxsize2 * bboxsize;
    
      // Make sure the second vertex is not identical with the first one.
      i = 1;
      while ((DIST(permutarray[0], permutarray[i]) / bboxsize) < b->epsilon) {
        i++;
        if (i == in->numberofpoints - 1) {
          printf("Exception:  All vertices are (nearly) identical (Tol = %g).\n",
                 b->epsilon);
          terminatetetgen(10);
        }
      }
      if (i > 1) {
        // Swap to move the non-indetical vertex from index i to index 1.
        swapvertex = permutarray[i];
        permutarray[i] = permutarray[1];
        permutarray[1] = swapvertex;
      }
    
      // Make sure the third vertex is not collinear with the first two.
      i = 2;
      for (j = 0; j < 3; j++) {
        v1[j] = permutarray[1][j] - permutarray[0][j];
        v2[j] = permutarray[i][j] - permutarray[0][j];
      }
      CROSS(v1, v2, n);
      while ((sqrt(NORM2(n[0], n[1], n[2])) / bboxsize2) < b->epsilon) {
        i++;
        if (i == in->numberofpoints - 1) {
          printf("Exception:  All vertices are (nearly) collinear (Tol = %g).\n",
                 b->epsilon);
          terminatetetgen(10);
        }
        for (j = 0; j < 3; j++) {
          v2[j] = permutarray[i][j] - permutarray[0][j];
        }
        CROSS(v1, v2, n);
      }
      if (i > 2) {
        // Swap to move the non-indetical vertex from index i to index 1.
        swapvertex = permutarray[i];
        permutarray[i] = permutarray[2];
        permutarray[2] = swapvertex;
      }
    
      // Make sure the fourth vertex is not coplanar with the first three.
      i = 3;
      ori = orient3d(permutarray[0], permutarray[1], permutarray[2], 
                     permutarray[i]);
      while ((fabs(ori) / bboxsize3) < b->epsilon) {
        i++;
        if (i == in->numberofpoints) {
          printf("Exception:  All vertices are coplanar (Tol = %g).\n",
                 b->epsilon);
          terminatetetgen(10);
        }
        ori = orient3d(permutarray[0], permutarray[1], permutarray[2], 
                       permutarray[i]);
      }
      if (i > 3) {
        // Swap to move the non-indetical vertex from index i to index 1.
        swapvertex = permutarray[i];
        permutarray[i] = permutarray[3];
        permutarray[3] = swapvertex;
      }
    
      // Orient the first four vertices in permutarray so that they follow the
      //   right-hand rule.
      if (ori > 0.0) {
        // Swap the first two vertices.
        swapvertex = permutarray[0];
        permutarray[0] = permutarray[1];
        permutarray[1] = swapvertex;
      }
    
      // Create the initial Delaunay tetrahedralization.
      initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
                      permutarray[3]);
    
      if (b->verbose) {
        printf("  Incrementally inserting vertices.\n");
      }
    
      // Choose algorithm: Bowyer-Watson (default) or Incremental Flip (-l).
      if (b->incrflip) {
        ivf.bowywat = 0;
        ivf.lawson = 1;
      } else {
        ivf.bowywat = 1;
        ivf.lawson = 0;
      }
    
      for (i = 4; i < in->numberofpoints; i++) {
        if (b->verbose > 2) printf("      #%d", i);
        if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
          setpointtype(permutarray[i], VOLVERTEX);
        }
        // Auto choose the starting tet for point location.
        searchtet.tet = NULL;
        ivf.iloc = (int) OUTSIDE;
        // Insert the vertex.
        loc = insertvertex(permutarray[i], &searchtet, NULL, NULL, &ivf);
        if (loc == (int) ONVERTEX) {
          // The point already exists. Mark it and do nothing on it.
          swapvertex = org(searchtet);
          assert(swapvertex != permutarray[i]); // SELF_CHECK
          if (b->object != tetgenbehavior::STL) {
            if (!b->quiet) {
              printf("Warning:  Point #%d is coincident with #%d. Ignored!\n",
                     pointmark(permutarray[i]), pointmark(swapvertex));
            }
          }
          setpoint2ppt(permutarray[i], swapvertex);
          setpointtype(permutarray[i], DUPLICATEDVERTEX);
          dupverts++;
          continue;
        }
        if (ivf.lawson) {
          // If -l option. Perform flip to recover Delaunayness.
          lawsonflip3d(permutarray[i], ivf.lawson, 0, 0, 0);
        }
      }
    
      if (b->btree) {
        // Bsp-tree is used only in DT construction.
        point **pptary;
        for (i = 0; i < (int) btreenode_list->objects; i++) {
          pptary = (point **) fastlookup(btreenode_list, i);
          delete [] *pptary;
        }
        delete btreenode_list;
        b->btree = 0; // Disable it.
      }
    
      delete [] permutarray;
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// delaunay_cxx /////////////////////////////////////////////////////////////
    
    //// surface_cxx //////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // calculateabovepoint()    Calculate a point above a facet in 'dummypoint'. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
                                         point *ppb, point *ppc)
    {
      point *ppt, pa, pb, pc;
      REAL v1[3], v2[3], n[3];
      REAL lab, len, A, area;
      REAL x, y, z;
      int i;
    
      ppt = (point *) fastlookup(facpoints, 0);
      pa = *ppt; // a is the first point.
      pb = pc = NULL; // Avoid compiler warnings.
    
      // Get a point b s.t. the length of [a, b] is maximal.
      lab = 0;
      for (i = 1; i < facpoints->objects; i++) {
        ppt = (point *) fastlookup(facpoints, i);
        x = (*ppt)[0] - pa[0];
        y = (*ppt)[1] - pa[1];
        z = (*ppt)[2] - pa[2];
        len = x * x + y * y + z * z;
        if (len > lab) {
          lab = len;
          pb = *ppt;
        }
      }
      lab = sqrt(lab);
      if (lab == 0) {
        if (!b->quiet) {
          printf("Warning:  All points of a facet are coincident with %d.\n",
            pointmark(pa));
        }
        return false;
      }
    
      // Get a point c s.t. the area of [a, b, c] is maximal.
      v1[0] = pb[0] - pa[0];
      v1[1] = pb[1] - pa[1];
      v1[2] = pb[2] - pa[2];
      A = 0;
      for (i = 1; i < facpoints->objects; i++) {
        ppt = (point *) fastlookup(facpoints, i);
        v2[0] = (*ppt)[0] - pa[0];
        v2[1] = (*ppt)[1] - pa[1];
        v2[2] = (*ppt)[2] - pa[2];
        CROSS(v1, v2, n);
        area = DOT(n, n);
        if (area > A) {
          A = area;
          pc = *ppt;
        }
      }
      if (A == 0) {
        // All points are collinear. No above point.
        if (!b->quiet) {
          printf("Warning:  All points of a facet are collinaer with [%d, %d].\n",
            pointmark(pa), pointmark(pb));
        }
        return false;
      }
    
      // Calculate an above point of this facet.
      facenormal(pa, pb, pc, n, 1, NULL);
      len = sqrt(DOT(n, n));
      n[0] /= len;
      n[1] /= len;
      n[2] /= len;
      lab /= 2.0; // Half the maximal length.
      dummypoint[0] = pa[0] + lab * n[0];
      dummypoint[1] = pa[1] + lab * n[1];
      dummypoint[2] = pa[2] + lab * n[2];
    
      if (ppa != NULL) {
        // Return the three points.
        *ppa = pa;
        *ppb = pb;
        *ppc = pc;
      }
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // Calculate an above point. It lies above the plane containing  the subface //
    //   [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
    //   is the normal of the plane.                                             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
    {
      arraypool *ptarray;
      point *parypt;
    
      ptarray = new arraypool(sizeof(point), 4);
    
      ptarray->newindex((void **) &parypt);
      *parypt = pa;
      ptarray->newindex((void **) &parypt);
      *parypt = pb;
      ptarray->newindex((void **) &parypt);
      *parypt = pc;
      ptarray->newindex((void **) &parypt);
      *parypt = pd;
    
      calculateabovepoint(ptarray, NULL, NULL, NULL);
    
      delete ptarray;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flipshpush()    Push a facet edge into flip stack.                        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flipshpush(face* flipedge)
    {
      badface *newflipface;
    
      newflipface = (badface *) flippool->alloc();
      newflipface->ss = *flipedge;
      newflipface->forg = sorg(*flipedge);
      newflipface->fdest = sdest(*flipedge);
      newflipface->nextitem = flipstack;
      flipstack = newflipface;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flip22()    Remove an edge by transforming 2-to-2 subfaces.               //
    //                                                                           //
    // 'flipfaces' contains two faces: abc and bad. This routine removes these 2 //
    // faces and replaces them by two new faces: cdb and dca.                    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
    {
      face bdedges[4], outfaces[4], infaces[4], bdsegs[4];
      face checkface, checkseg;
      point pa, pb, pc, pd;
      badface *bface;
      int i;
    
      pa = sorg(flipfaces[0]);
      pb = sdest(flipfaces[0]);
      pc = sapex(flipfaces[0]);
      pd = sapex(flipfaces[1]);
    
      if (sorg(flipfaces[1]) != pb) {
        sesymself(flipfaces[1]);
      }
    
      if (b->verbose > 3) {
        printf("        flip 2-to-2: (%d, %d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd));
      }
      flip22count++;
    
      // Collect the four boundary edges.
      senext(flipfaces[0], bdedges[0]);
      senext2(flipfaces[0], bdedges[1]);
      senext(flipfaces[1], bdedges[2]);
      senext2(flipfaces[1], bdedges[3]);
    
      // Collect outer boundary faces.
      for (i = 0; i < 4; i++) {
        spivot(bdedges[i], outfaces[i]);
        infaces[i] = outfaces[i];
        sspivot(bdedges[i], bdsegs[i]);
        if (outfaces[i].sh != NULL) {
          sspivot(bdedges[i], checkseg);
          if (checkseg.sh != NULL) {
            spivot(infaces[i], checkface);
            while (checkface.sh != bdedges[i].sh) {
              infaces[i] = checkface;
              spivot(infaces[i], checkface);
            }
          }
        }
      }
    
      // The flags set in these two subfaces do not change.
      // Shellmark does not change.
      // area constraint does not change.
    
      // Transform abc -> cdb.
      setshvertices(flipfaces[0], pc, pd, pb);
      // Transform bad -> dca.
      setshvertices(flipfaces[1], pd, pc, pa);
    
      // Update the point-to-subface map.
      if (pointtype(pa) == FREEFACETVERTEX) {
        setpoint2sh(pa, sencode(flipfaces[1]));
      }
      if (pointtype(pb) == FREEFACETVERTEX) {
        setpoint2sh(pb, sencode(flipfaces[0]));
      }
      if (pointtype(pc) == FREEFACETVERTEX) {
        setpoint2sh(pc, sencode(flipfaces[0]));
      }
      if (pointtype(pd) == FREEFACETVERTEX) {
        setpoint2sh(pd, sencode(flipfaces[0]));
      }
    
      // Reconnect boundary edges to outer boundary faces.
      for (i = 0; i < 4; i++) {
        if (outfaces[(3 + i) % 4].sh != NULL) {
          // Make sure that the subface has the ori as the segment.
          if (bdsegs[(3 + i) % 4].sh != NULL) {
            bdsegs[(3 + i) % 4].shver = 0;
            if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
              sesymself(bdedges[i]);
            }
          }
          sbond1(bdedges[i], outfaces[(3 + i) % 4]);
          sbond1(infaces[(3 + i) % 4], bdedges[i]);
        } else {
          sdissolve(bdedges[i]);
        }
        if (bdsegs[(3 + i) % 4].sh != NULL) {
          ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
          if (chkencflag & 1) {
            // Queue this segment for encroaching check.
            if (!smarktest2ed(bdsegs[(3 + i) % 4])) {
              bface = (badface *) badsubsegs->alloc();
              bface->ss = bdsegs[(3 + i) % 4];
              smarktest2(bface->ss); // Only queue it once.
              bface->forg = sorg(bface->ss); // An alive badface.
            }
          }
        } else {
          ssdissolve(bdedges[i]);
        }
      }
    
      if (chkencflag & 2) {
        // Queue the flipped subfaces for quality/encroaching checks.
        for (i = 0; i < 2; i++) {
          if (!smarktest2ed(flipfaces[i])) {
            bface = (badface *) badsubfacs->alloc();
            bface->ss = flipfaces[i];
            smarktest2(bface->ss); // Only queue it once.
            bface->forg = sorg(bface->ss); // An alive badface.
          }
        }
      }
    
      recentsh = flipfaces[0];
    
      if (flipflag) {
        // Put the boundary edges into flip stack.
        for (i = 0; i < 4; i++) {
          flipshpush(&(bdedges[i]));
        }
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flip31()    Remove a vertex by transforming 3-to-1 subfaces.              //
    //                                                                           //
    // 'flipfaces' is an array of subfaces. Its length is at least 4.  On input, //
    // the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine    //
    // replaces them by one face [a,b,c], it is returned in flipfaces[3].        //
    //                                                                           //
    // NOTE: The three old subfaces are not deleted within this routine.  They   //
    // still hold pointers to their adjacent subfaces. These informations are    //
    // needed by the routine 'sremovevertex()' for recovering a segment.         //
    // The caller of this routine must delete the old subfaces after their uses. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flip31(face* flipfaces, int flipflag)
    {
      face bdedges[3], outfaces[3], infaces[3], bdsegs[3];
      face checkface, checkseg;
      point pa, pb, pc, delpt;
      REAL area;
      int i;
    
      delpt = sorg(flipfaces[0]);
      pa = sdest(flipfaces[0]);
      pb = sdest(flipfaces[1]);
      pc = sdest(flipfaces[2]);
    
      if (b->verbose > 3) {
        printf("        flip 3-to-1: (%d, %d, %d) - %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(delpt));
      }
      // flip31count++;
    
      // Collect all infos at the three boundary edges.
      for (i = 0; i < 3; i++) {
        senext(flipfaces[i], bdedges[i]);
        spivot(bdedges[i], outfaces[i]);
        infaces[i] = outfaces[i];
        sspivot(bdedges[i], bdsegs[i]);
        if (outfaces[i].sh != NULL) {
          sspivot(bdedges[i], checkseg);
          if (checkseg.sh != NULL) {
            spivot(infaces[i], checkface);
            while (checkface.sh != bdedges[i].sh) {
              infaces[i] = checkface;
              spivot(infaces[i], checkface);
            }
          }
        }
      } // i
    
      // Create a new subface.
      makeshellface(subfaces, &(flipfaces[3]));
      setshvertices(flipfaces[3], pa, pb,pc);
      setshellmark(flipfaces[3], shellmark(flipfaces[0]));
      if (checkconstraints) {
        area = areabound(flipfaces[0]);
        setareabound(flipfaces[3], area);
      }
    
      // Update the point-to-subface map.
      if (pointtype(pa) == FREEFACETVERTEX) {
        setpoint2sh(pa, sencode(flipfaces[3]));
      }
      if (pointtype(pb) == FREEFACETVERTEX) {
        setpoint2sh(pb, sencode(flipfaces[3]));
      }
      if (pointtype(pc) == FREEFACETVERTEX) {
        setpoint2sh(pc, sencode(flipfaces[3]));
      }
    
      // Update the three new boundary edges.
      bdedges[0] = flipfaces[3];         // [a,b]
      senext(flipfaces[3], bdedges[1]);  // [b,c]
      senext2(flipfaces[3], bdedges[2]); // [c,a]
    
      // Reconnect boundary edges to outer boundary faces.
      for (i = 0; i < 3; i++) {
        if (outfaces[i].sh != NULL) {
          // Make sure that the subface has the ori as the segment.
          if (bdsegs[i].sh != NULL) {
            bdsegs[i].shver = 0;
            if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
              sesymself(bdedges[i]);
            }
          }
          sbond1(bdedges[i], outfaces[i]);
          sbond1(infaces[i], bdedges[i]);
        }
        if (bdsegs[i].sh != NULL) {
          ssbond(bdedges[i], bdsegs[i]);
        }
      }
    
      recentsh = flipfaces[3];
    
      if (flipflag) {
        // Put the boundary edges into flip stack.
        for (i = 0; i < 3; i++) {
          flipshpush(&(bdedges[i]));
        }
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // lawsonflip()    Flip non-locally Delaunay edges.                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    long tetgenmesh::lawsonflip()
    {
      badface *popface;
      face flipfaces[2];
      face checkseg;
      point pa, pb, pc, pd;
      REAL sign;
      long flipcount;
    
      if (b->verbose > 2) {
        printf("      Lawson flip %ld edges.\n", flippool->items);
      }
      flipcount = flip22count;
    
      while (flipstack != (badface *) NULL) {
    
        // Pop an edge from the stack.
        popface = flipstack;
        flipfaces[0] = popface->ss;
        pa = popface->forg;
        pb = popface->fdest;
        flipstack = popface->nextitem; // The next top item in stack.
        flippool->dealloc((void *) popface);
    
        // Skip it if it is dead.
        if (flipfaces[0].sh[3] == NULL) continue;
        // Skip it if it is not the same edge as we saved.
        if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
        // Skip it if it is a subsegment.
        sspivot(flipfaces[0], checkseg);
        if (checkseg.sh != NULL) continue;
    
        // Get the adjacent face.
        spivot(flipfaces[0], flipfaces[1]);
        if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
        pc = sapex(flipfaces[0]);
        pd = sapex(flipfaces[1]);
    
        sign = incircle3d(pa, pb, pc, pd);
    
        if (sign < 0) {
          // It is non-locally Delaunay. Flip it.
          flip22(flipfaces, 1, 0);
        }
      }
    
      if (b->verbose > 2) {
        printf("      %ld edges stacked, %ld flips.\n", flippool->items,
          flip22count - flipcount);
      }
      assert(flippool->items == 0l); // SELF_CHECK
    
      return flip22count - flipcount;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // sinsertvertex()    Insert a vertex into a triangulation of a facet.       //
    //                                                                           //
    // This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
    // 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p),   //
    // 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a  //
    // segment, 'cavesegshlist' returns the two new subsegments.                 //
    //                                                                           //
    // NOTE: the old subfaces in C(p) are not deleted. Theyare needed in case we //
    // want to remove the new point immedately.                                  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
                                  int iloc, int bowywat)
    {
      triface adjtet;
      face cavesh, neighsh, *parysh;
      face newsh, casout, casin;
      face aseg, bseg, aoutseg, boutseg;
      face checkseg;
      point pa, pb, pc;
      enum locateresult loc;
      REAL sign, ori, area;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      Insert facet point %d.\n", pointmark(insertpt));
      }
    
      if (splitseg != NULL) {
        // A segment is going to be split, no point location.
        spivot(*splitseg, *searchsh);
        loc = ONEDGE;
      } else {
        loc = (enum locateresult) iloc;
        if (loc == OUTSIDE) {
          // Do point location in surface mesh.
          if (searchsh->sh == NULL) {
            *searchsh = recentsh;
          }
          // Start searching from 'searchsh'.
          loc = slocate(insertpt, searchsh, 1, 1, 0);
        }
      }
    
      if (b->verbose > 2) {
        if (searchsh->sh != NULL) {
          pa = sorg(*searchsh);
          pb = sdest(*searchsh);
          pc = sapex(*searchsh);
          printf("      Located subface (%d, %d, %d).\n", pointmark(pa), 
                 pointmark(pb), pointmark(pc));
        } else {
          assert(splitseg != NULL);
          pa = sorg(*splitseg);
          pb = sdest(*splitseg);
          printf("      Located segment (%d, %d).\n", pointmark(pa),pointmark(pb));
        }
      }
    
    if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
    
      // Form the initial sC(p).
      if (loc == ONFACE) {
        if (b->verbose > 2) {
          printf("      Inside face.\n");
        }
        // Add the face into list (in B-W cavity).
        smarktest(*searchsh);
        caveshlist->newindex((void **) &parysh);
        *parysh = *searchsh;
      } else if (loc == ONEDGE) {
        if (b->verbose > 2) {
          printf("      On edge.\n");
        }
        if (splitseg != NULL) {
          splitseg->shver = 0;
          pa = sorg(*splitseg);
        } else {
          pa = sorg(*searchsh);
        }
        if (searchsh->sh != NULL) {
          // Collect all subfaces share at this edge.
          neighsh = *searchsh;
          while (1) {
            // Adjust the origin of its edge to be 'pa'.
            if (sorg(neighsh) != pa) {
              sesymself(neighsh);
            }
            // Add this face into list (in B-W cavity).
            smarktest(neighsh);
            caveshlist->newindex((void **) &parysh);
            *parysh = neighsh;
            // Add this face into face-at-splitedge list.
            cavesegshlist->newindex((void **) &parysh);
            *parysh = neighsh;
            // Go to the next face at the edge.
            spivotself(neighsh);
            // Stop if all faces at the edge have been visited.
            if (neighsh.sh == searchsh->sh) break;
            if (neighsh.sh == NULL) break;
          }
        } // If (not a non-dangling segment).
      } else if (loc == ONVERTEX) {
        if (b->verbose > 2) {
          printf("      On vertex.\n");
        }
        return (int) loc;
      } else if (loc == OUTSIDE) {
        // Comment: This should only happen during the surface meshing step.
        // Enlarge the convex hull of the triangulation by including p.
        // An above point of the facet is set in 'dummypoint' to replace
        // orient2d tests by orient3d tests.
        if (b->verbose > 2) {
          printf("      Outside face.\n");
        }
        // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
        //   plane, and a->b is directed from left to right, p lies above a->b.  
        //   Find the right-most edge of the triangulation which is visible by p.
        neighsh = *searchsh;
        while (1) {
          senext2self(neighsh);
          spivot(neighsh, casout);
          if (casout.sh == NULL) {
            // A convex hull edge. Is it visible by p.
            pa = sorg(neighsh);
            pb = sdest(neighsh);
            ori = orient3d(pa, pb, dummypoint, insertpt);
            if (ori < 0) {
              *searchsh = neighsh; // Visible, update 'searchsh'.
            } else {
              break; // 'searchsh' is the right-most visible edge.
            }
          } else {
            if (sorg(casout) != sdest(neighsh)) sesymself(casout);
            neighsh = casout;
          }
        }
        // Create new triangles for all visible edges of p (from right to left).
        casin.sh = NULL;  // No adjacent face at right.
        pa = sorg(*searchsh);
        pb = sdest(*searchsh);
        while (1) {
          // Create a new subface on top of the (visible) edge.
          makeshellface(subfaces, &newsh); 
          setshvertices(newsh, pb, pa, insertpt);
          setshellmark(newsh, shellmark(*searchsh));
          if (checkconstraints) {
            area = areabound(*searchsh);
            setareabound(newsh, area);
          }
          // Connect the new subface to the bottom subfaces.
          sbond1(newsh, *searchsh);
          sbond1(*searchsh, newsh);
          // Connect the new subface to its right-adjacent subface.
          if (casin.sh != NULL) {
            senext(newsh, casout);
            sbond1(casout, casin);
            sbond1(casin, casout);
          }
          // The left-adjacent subface has not been created yet.
          senext2(newsh, casin);
          // Add the new face into list (inside the B-W cavity).
          smarktest(newsh);
          caveshlist->newindex((void **) &parysh);
          *parysh = newsh;
          // Move to the convex hull edge at the left of 'searchsh'.
          neighsh = *searchsh;
          while (1) {
            senextself(neighsh);
            spivot(neighsh, casout);
            if (casout.sh == NULL) {
              *searchsh = neighsh;
              break;
            }
            if (sorg(casout) != sdest(neighsh)) sesymself(casout);
            neighsh = casout;
          }
          // A convex hull edge. Is it visible by p.
          pa = sorg(*searchsh);
          pb = sdest(*searchsh);
          ori = orient3d(pa, pb, dummypoint, insertpt);
          // Finish the process if p is not visible by the hull edge.
          if (ori >= 0) break;
        }
      }
    
    } else {
    
      // Under this case, the sub-cavity sC(p) has already been formed in
      //   insertvertex().  Check it.
      // FOR DEBUG ONLY.
      for (i = 0; i < caveshlist->objects; i++) {
        cavesh = * (face *) fastlookup(caveshlist, i);
        assert(smarktested(cavesh));
      }
      if (splitseg != NULL) {
        assert(smarktested(*splitseg));
      }
    
    
    }// if (bowywat < 3) 
    
      // Form the Bowyer-Watson cavity sC(p).
      for (i = 0; i < caveshlist->objects; i++) {
        cavesh = * (face *) fastlookup(caveshlist, i);
        for (j = 0; j < 3; j++) {
          sspivot(cavesh, checkseg);
          if (checkseg.sh == NULL) {
            spivot(cavesh, neighsh);
            if (neighsh.sh != NULL) {
              // The adjacent face exists.
              if (!smarktested(neighsh)) {
                if (bowywat) {
                  if (bowywat > 2) {
                    // It must be a boundary edge.
                    sign = 1;
                  } else {
                    // Check if this subface is connected to adjacent tet(s).
                    stpivot(neighsh, adjtet);
                    if (adjtet.tet == NULL) {
                      // Check if the subface is non-Delaunay wrt. the new pt.
                      pa = sorg(neighsh);
                      pb = sdest(neighsh);
                      pc = sapex(neighsh);
                      sign = incircle3d(pa, pb, pc, insertpt);
                    } else {
                      // It is connected to an adjacent tet. A boundary edge.
                      sign = 1;
                    }
                  }
                  if (sign < 0) {
                    // Add the adjacent face in list (in B-W cavity).
                    smarktest(neighsh);
                    caveshlist->newindex((void **) &parysh);
                    *parysh = neighsh;
                  }
                } else {
                  sign = 1; // A boundary edge.
                }
              } else {
                sign = -1; // Not a boundary edge.
              }
            } else {
              // No adjacent face. It is a hull edge.
              if (loc == OUTSIDE) {
                // It is a boundary edge if it does not contain p.
                if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
                  sign = -1; // Not a boundary edge.
                } else {
                  sign = 1; // A boundary edge.
                }
              } else {
                sign = 1; // A boundary edge.
              }
            }
          } else {
            // Do not across a segment. It is a boundary edge.
            sign = 1;
          }
          if (sign >= 0) {
            // Add a boundary edge.
            caveshbdlist->newindex((void **) &parysh);
            *parysh = cavesh;
          }
          senextself(cavesh);
        } // j
      } // i
    
      if (b->verbose > 3) {
        printf("        Size of cavity: %ld faces, %ld bdry edges.\n",
               caveshlist->objects, caveshbdlist->objects);
      }
    
      // Creating new subfaces.
      for (i = 0; i < caveshbdlist->objects; i++) {
        parysh = (face *) fastlookup(caveshbdlist, i);
        sspivot(*parysh, checkseg);
        if ((parysh->shver & 01) != 0) sesymself(*parysh);
        pa = sorg(*parysh);
        pb = sdest(*parysh);
        // Create a new subface.
        makeshellface(subfaces, &newsh); 
        setshvertices(newsh, pa, pb, insertpt);
        setshellmark(newsh, shellmark(*parysh));
        setshelltype(newsh, shelltype(*parysh));
        if (checkconstraints) {
          area = areabound(*parysh);
          setareabound(newsh, area);
        }
        // Update the point-to-subface map.
        if (pointtype(pa) == FREEFACETVERTEX) {
          setpoint2sh(pa, sencode(newsh));
        }
        if (pointtype(pb) == FREEFACETVERTEX) {
          setpoint2sh(pb, sencode(newsh));
        }
        // Connect newsh to outer subfaces.
        spivot(*parysh, casout);
        if (casout.sh != NULL) {
          casin = casout;
          if (checkseg.sh != NULL) {
            // Make sure that newsh has the right ori at this segment.
            checkseg.shver = 0;
            if (sorg(newsh) != sorg(checkseg)) {
              sesymself(newsh);
              sesymself(*parysh); // This side should also be inversed.
            }
            spivot(casin, neighsh);
            while (neighsh.sh != parysh->sh) {
              casin = neighsh;
              spivot(casin, neighsh);
            }
          }
          sbond1(newsh, casout);
          sbond1(casin, newsh);
        }
        if (checkseg.sh != NULL) {
          ssbond(newsh, checkseg);
        }
        // Connect oldsh <== newsh (for connecting adjacent new subfaces).
        //   *parysh and newsh point to the same edge and the same ori.
        sbond1(*parysh, newsh);
      }
    
      // Set a handle for searching.
      recentsh = newsh;
    
      // Update the point-to-subface map.
      if (pointtype(insertpt) == FREEFACETVERTEX) {
        setpoint2sh(insertpt, sencode(newsh));
      }
    
      // Connect adjacent new subfaces together.
      for (i = 0; i < caveshbdlist->objects; i++) {
        // Get an old subface at edge [a, b].
        parysh = (face *) fastlookup(caveshbdlist, i);
        spivot(*parysh, newsh); // The new subface [a, b, p].
        senextself(newsh); // At edge [b, p].
        spivot(newsh, neighsh);
        if (neighsh.sh == NULL) {
          // Find the adjacent new subface at edge [b, p].
          pb = sdest(*parysh);
          neighsh = *parysh;
          while (1) {
            senextself(neighsh);
            spivotself(neighsh);
            if (neighsh.sh == NULL) break;
            if (!smarktested(neighsh)) break;
            if (sdest(neighsh) != pb) sesymself(neighsh);
          }
          if (neighsh.sh != NULL) {
            // Now 'neighsh' is a new subface at edge [b, #].
            if (sorg(neighsh) != pb) sesymself(neighsh);
            assert(sorg(neighsh) == pb); // SELF_CHECK
            assert(sapex(neighsh) == insertpt); // SELF_CHECK
            senext2self(neighsh); // Go to the open edge [p, b].
            sbond(newsh, neighsh);
          } else {
            // There is no adjacent new face at this side.
            assert(loc == OUTSIDE); // SELF_CHECK
          }
        }
        spivot(*parysh, newsh); // The new subface [a, b, p].
        senext2self(newsh); // At edge [p, a].
        spivot(newsh, neighsh);
        if (neighsh.sh == NULL) {
          // Find the adjacent new subface at edge [p, a].
          pa = sorg(*parysh);
          neighsh = *parysh;
          while (1) {
            senext2self(neighsh);
            spivotself(neighsh);
            if (neighsh.sh == NULL) break;
            if (!smarktested(neighsh)) break;
            if (sorg(neighsh) != pa) sesymself(neighsh);
          }
          if (neighsh.sh != NULL) {
            // Now 'neighsh' is a new subface at edge [#, a].
            if (sdest(neighsh) != pa) sesymself(neighsh);
            assert(sdest(neighsh) == pa); // SELF_CHECK
            assert(sapex(neighsh) == insertpt); // SELF_CHECK
            senextself(neighsh); // Go to the open edge [a, p].
            sbond(newsh, neighsh);
          } else {
            // There is no adjacent new face at this side.
            assert(loc == OUTSIDE); // SELF_CHECK
          }
        }
      }
    
      if (loc == ONEDGE) {
    
        // An edge is being split. We distinguish two cases:
        //   (1) the edge is not on the boundary of the cavity;
        //   (2) the edge is on the boundary of the cavity.
        // In case (2), the edge is either a segment or a hull edge. There are
        //   degenerated new faces in the cavity. They must be removed.
        for (i = 0; i < cavesegshlist->objects; i++) {
          // Get the saved old subface.
          parysh = (face *) fastlookup(cavesegshlist, i);
          // Get a possible new degenerated subface.
          spivot(*parysh, cavesh);
          if (sapex(cavesh) == insertpt) {
            // Found a degenerated new subface, i.e., case (2).
            if (cavesegshlist->objects > 1) {
              // There are more than one subface share at this edge.
              j = (i + 1) % (int) cavesegshlist->objects;
              parysh = (face *) fastlookup(cavesegshlist, j);
              spivot(*parysh, neighsh);
              // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
              if (sorg(neighsh) != sorg(cavesh)) {
                sesymself(neighsh);
                assert(sorg(neighsh) == sorg(cavesh)); // SELF_CHECK
              }
              assert(sapex(neighsh) == insertpt); // SELF_CHECK
              // Connect adjacent faces at two other edges of cavesh and neighsh.
              //   As a result, the two degenrated new faces are squessed from the
              //   new triangulation of the cavity. Note that the squeezed faces
              //   still hold the adjacent informations which will be used in 
              //   re-connecting subsegments (if they exist). 
              for (j = 0; j < 2; j++) { 
                senextself(cavesh);
                senextself(neighsh);
                spivot(cavesh, newsh);
                spivot(neighsh, casout);
                sbond1(newsh, casout); // newsh <- casout.
              }
            } else {
              // There is only one subface containing this edge [a,b]. Squeese the
              //   degenerated new face [a,b,c] by disconnecting it from its two 
              //   adjacent subfaces at edges [b,c] and [c,a]. Note that the face
              //   [a,b,c] still hold the connection to them.
              for (j = 0; j < 2; j++) {
                senextself(cavesh);
                spivot(cavesh, newsh);
                sdissolve(newsh);
              }
            }
            recentsh = newsh;
            // Update the point-to-subface map.
            if (pointtype(insertpt) == FREEFACETVERTEX) {
              setpoint2sh(insertpt, sencode(newsh));
            }
          }
        }
    
        if (splitseg != NULL) {
          if (bowywat < 3) {
            smarktest(*splitseg); // Mark it as being processed.
          }
          
          aseg = *splitseg;
          pa = sorg(*splitseg);
          pb = sdest(*splitseg);
          if (b->verbose > 2) {
            printf("      Split seg (%d, %d) by %d.\n", pointmark(pa), 
                   pointmark(pb), pointmark(insertpt));
          }
    
          // Insert the new point p.
          makeshellface(subsegs, &aseg);
          makeshellface(subsegs, &bseg);
    
          setshvertices(aseg, pa, insertpt, NULL);
          setshvertices(bseg, insertpt, pb, NULL);
          setshellmark(aseg, shellmark(*splitseg));
          setshellmark(bseg, shellmark(*splitseg));
          setshelltype(aseg, shelltype(*splitseg));
          setshelltype(bseg, shelltype(*splitseg));
          if (checkconstraints) {
            setareabound(bseg, areabound(*splitseg));
            setareabound(bseg, areabound(*splitseg));
          }
    
          // Connect [#, a]<->[a, p].
          senext2(*splitseg, boutseg); // Temporarily use boutseg.
          spivotself(boutseg);
          if (boutseg.sh != NULL) {
            senext2(aseg, aoutseg);
            sbond(boutseg, aoutseg);
          }
          // Connect [p, b]<->[b, #].
          senext(*splitseg, aoutseg);
          spivotself(aoutseg);
          if (aoutseg.sh != NULL) {
            senext(bseg, boutseg);
            sbond(boutseg, aoutseg);
          }
          // Connect [a, p] <-> [p, b].
          senext(aseg, aoutseg);
          senext2(bseg, boutseg);
          sbond(aoutseg, boutseg);
    
          // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
          // Although the degenerated new faces have been squeesed. They still
          //   hold the connections to the actual new faces. 
          for (i = 0; i < cavesegshlist->objects; i++) {        
            parysh = (face *) fastlookup(cavesegshlist, i);
            spivot(*parysh, neighsh);
            // neighsh is a degenerated new face.
            if (sorg(neighsh) != pa) {
              sesymself(neighsh);
            }
            senext2(neighsh, newsh);
            spivotself(newsh); // The edge [p, a] in newsh
            ssbond(newsh, aseg);
            senext(neighsh, newsh);
            spivotself(newsh); // The edge [b, p] in newsh
            ssbond(newsh, bseg);
          }
    
    
          // Let the point remember the segment it lies on.
          setpoint2sh(insertpt, sencode(aseg));
          // Update the point-to-seg map.
          setpoint2sh(pa, sencode(aseg));
          setpoint2sh(pb, sencode(bseg));
        } // if (splitseg != NULL)
    
        // Delete all degenerated new faces.
        for (i = 0; i < cavesegshlist->objects; i++) {
          parysh = (face *) fastlookup(cavesegshlist, i);
          spivotself(*parysh);
          if (sapex(*parysh) == insertpt) {
            shellfacedealloc(subfaces, parysh->sh);
          }
        }
        cavesegshlist->restart();
    
        if (splitseg != NULL) {
          // Return the two new subsegments (for further process).
          //   Re-use 'cavesegshlist'.
          cavesegshlist->newindex((void **) &parysh);
          *parysh = aseg;
          cavesegshlist->newindex((void **) &parysh);
          *parysh = bseg;
        }
    
      } // if (loc == ONEDGE)
    
    
      return (int) loc;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // sremovevertex()    Remove a vertex from the surface mesh.                 //
    //                                                                           //
    // 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
    // a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a   //
    // facet vertex, and the origin of 'parentsh' is p.                          //
    //                                                                           //
    // If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay-   //
    // ness after p is removed.                                                  //
    //                                                                           //
    // Within each facet, we first use a sequence of 2-to-2 flips to flip any    //
    // edge at p, finally use a 3-to-1 flip to remove p.                         //
    //                                                                           //
    // All new created subfaces are returned in the global array 'caveshbdlist'. //
    // The new segment (when p is on segment) is returned in 'parentseg'.        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
                                  int lawson)
    {
      face flipfaces[4], *parysh;
      face spinsh, startsh, neighsh, nextsh, fakesh;
      face abseg, prevseg, checkseg;
      face adjseg1, adjseg2;
      point pa, pb, pc, pd;
      int it, i, j;
    
      REAL *norm, n1[3], n2[3];
      REAL len, len1, len2;
      REAL ori1, ori2;
    
      if (parentseg != NULL) {
        assert(sorg(*parentseg) == delpt);
        assert(parentseg->shver == 0);
        // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
        //   where 'parentseg' should be [p,b]. Find the segment [a,p].
        senext2(*parentseg, prevseg);
        spivotself(prevseg);
        assert(prevseg.sh != NULL);
        prevseg.shver = 0;
        assert(sdest(prevseg) == delpt);
        // Restore the original segment [a,b].
        pa = sorg(prevseg);
        pb = sdest(*parentseg);
        if (b->verbose > 2) {
          printf("      Remove vertex %d from segment [%d, %d].\n", 
                 pointmark(delpt), pointmark(pa), pointmark(pb));
        }
        makeshellface(subsegs, &abseg);
        setshvertices(abseg, pa, pb, NULL);
        setshellmark(abseg, shellmark(*parentseg));
        setshelltype(abseg, shelltype(*parentseg));
        if (checkconstraints) {
          setareabound(abseg, areabound(*parentseg));
        }
        // Connect [#, a]<->[a, b].
        senext2(prevseg, adjseg1);
        spivotself(adjseg1);
        if (adjseg1.sh != NULL) {
          adjseg1.shver = 0;
          assert(sdest(adjseg1) == pa);
          senextself(adjseg1);
          senext2(abseg, adjseg2);
          sbond(adjseg1, adjseg2);
        }
        // Connect [a, b]<->[b, #].
        senext(*parentseg, adjseg1);
        spivotself(adjseg1);
        if (adjseg1.sh != NULL) {
          adjseg1.shver = 0;
          assert(sorg(adjseg1) == pb);
          senext2self(adjseg1);
          senext(abseg, adjseg2);
          sbond(adjseg1, adjseg2);
        }
        // Update the point-to-segment map.
        setpoint2sh(pa, sencode(abseg));
        setpoint2sh(pb, sencode(abseg));
    
        // Get the faces in face ring at segment [p, b].
        //   Re-use array 'caveshlist'.
        spivot(*parentseg, *parentsh);
        spinsh = *parentsh;
        while (1) {
          // Save this face in list.
          caveshlist->newindex((void **) &parysh);
          *parysh = spinsh;
          // Go to the next face in the ring.
          spivotself(spinsh);
          if (spinsh.sh == NULL) break;
          if (spinsh.sh == parentsh->sh) break;
        } 
    
        // Create the face ring of the new segment [a,b]. Each face in the ring
        //   is [a,b,p] (degenerated!). It will be removed (automatically).
        for (i = 0; i < caveshlist->objects; i++) {
          parysh = (face *) fastlookup(caveshlist, i);
          startsh = *parysh;
          if (sorg(startsh) != delpt) {
            sesymself(startsh);
            assert(sorg(startsh) == delpt);
          }      
          // startsh is [p, b, #1], find the subface [a, p, #2].
          neighsh = startsh;
          while (1) {
            senext2self(neighsh);
            sspivot(neighsh, checkseg);
            if (checkseg.sh != NULL) {
              // It must be the segment [a, p].
              assert(checkseg.sh == prevseg.sh);
              break;
            }
            spivotself(neighsh);
            assert(neighsh.sh != NULL);
            if (sorg(neighsh) != delpt) sesymself(neighsh);
          }
          // Now neighsh is [a, p, #2].
          if (neighsh.sh != startsh.sh) {
            // Detach the two subsegments [a,p] and [p,b] from subfaces.
            ssdissolve(startsh);
            ssdissolve(neighsh);
            // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
            //   new segment [a,b]; (2) connect to the two adjacent subfaces
            //   [p,b,#] and [a,p,#].
            makeshellface(subfaces, &fakesh);
            setshvertices(fakesh, pa, pb, delpt);
            setshellmark(fakesh, shellmark(startsh));
            // Connect fakesh to the segment [a,b].
            ssbond(fakesh, abseg);
            // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
            senext(fakesh, nextsh);
            sbond(nextsh, startsh);
            senext2(fakesh, nextsh);
            sbond(nextsh, neighsh);
            smarktest(fakesh); // Mark it as faked.
          } else {
            // Special case. There exists already a degenerated face [a,b,p]!
            //   There is no need to create a faked subface here.
            senext2self(neighsh); // [a,b,p]
            assert(sapex(neighsh) == delpt);
            // Since we will re-connect the face ring using the faked subfaces.
            //   We put the adjacent face of [a,b,p] to the list.
            spivot(neighsh, startsh); // The original adjacent subface.
            if (sorg(startsh) != pa) {
              sesymself(startsh);
            }
            assert(sorg(startsh) == pa);
            assert(sdest(startsh) == pb);
            assert(sapex(startsh) != delpt);
            sdissolve(startsh);
            // Connect fakesh to the segment [a,b].
            ssbond(startsh, abseg);
            fakesh = startsh; // Do not mark it!
            // Delete the degenerated subface.
            shellfacedealloc(subfaces, neighsh.sh);
          }
          // Save the fakesh in list (for re-creating the face ring).
          cavesegshlist->newindex((void **) &parysh);
          *parysh = fakesh;
        } // i
        caveshlist->restart();
    
        // Re-create the face ring.
        if (cavesegshlist->objects > 1) {
          for (i = 0; i < cavesegshlist->objects; i++) {
            parysh = (face *) fastlookup(cavesegshlist, i);
            fakesh = *parysh;
            // Get the next face in the ring.
            j = (i + 1) % cavesegshlist->objects;
            parysh = (face *) fastlookup(cavesegshlist, j);
            nextsh = *parysh;
            sbond1(fakesh, nextsh);
          }
        }
    
        // Delete the two subsegments containing p.
        shellfacedealloc(subsegs, parentseg->sh);
        shellfacedealloc(subsegs, prevseg.sh);
        // Return the new segment.
        *parentseg = abseg;
      } else {
        // p is inside the surface.
        if (b->verbose > 2) {
          printf("      Remove vertex %d from surface.\n", pointmark(delpt));
        }
        assert(sorg(*parentsh) == delpt);
        // Let 'delpt' be its apex.
        senextself(*parentsh);
        // For unifying the code, we add parentsh to list.
        cavesegshlist->newindex((void **) &parysh);
        *parysh = *parentsh;
      }
    
      // Remove the point (p).
    
      for (it = 0; it < cavesegshlist->objects; it++) {
        parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
        senextself(*parentsh); // [b,p,a].
        spivotself(*parentsh);
        if (sorg(*parentsh) != delpt) {
          sesymself(*parentsh);
        } 
        // now parentsh is [p,b,#].
        if (sorg(*parentsh) != delpt) {
          // The vertex has already been removed in above special case.
          assert(!smarktested(*parentsh));
          continue;
        }
    
        while (1) {      
          // Initialize the flip edge list. Re-use 'caveshlist'.
          spinsh = *parentsh; // [p, b, #]
          while (1) {
            caveshlist->newindex((void **) &parysh);
            *parysh = spinsh;
            senext2self(spinsh);
            spivotself(spinsh);
            assert(spinsh.sh != NULL);
            if (spinsh.sh == parentsh->sh) break;
            if (sorg(spinsh) != delpt) {
              sesymself(spinsh);
              assert(sorg(spinsh) == delpt);
            }
          } // while (1)
    
          if (caveshlist->objects == 3) {
            // Delete the point by a 3-to-1 flip.
            for (i = 0; i < 3; i++) {
              parysh = (face *) fastlookup(caveshlist, i);
              flipfaces[i] = *parysh;
            }
            flip31(flipfaces, lawson);
            for (i = 0; i < 3; i++) { 
              shellfacedealloc(subfaces, flipfaces[i].sh);
            }
            caveshlist->restart();
            // Save the new subface.
            caveshbdlist->newindex((void **) &parysh);
            *parysh = flipfaces[3];
            // The vertex is removed.
            break;
          } else {
            // There should be more than 3 subfaces in list.
            assert(caveshlist->objects > 3);
          }
    
          // Search an edge to flip.
          for (i = 0; i < caveshlist->objects; i++) {
            parysh = (face *) fastlookup(caveshlist, i);
            flipfaces[0] = *parysh;
            spivot(flipfaces[0], flipfaces[1]);
            if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
              sesymself(flipfaces[1]);
            }
            // Skip this edge if it belongs to a faked subface.
            if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
              pa = sorg(flipfaces[0]);
              pb = sdest(flipfaces[0]);
              pc = sapex(flipfaces[0]);
              pd = sapex(flipfaces[1]);
              // Select a base.
              facenormal(pa, pb, pc, n1, 1, NULL);
              len1 = sqrt(DOT(n1, n1));
              facenormal(pa, pb, pd, n2, 1, NULL);
              len2 = sqrt(DOT(n2, n2));
              if (len1 > len2) {
                norm = n1;
                len = len1;
              } else {
                norm = n2;
                len = len2;
              }
              assert(len > 0);
              norm[0] /= len;
              norm[1] /= len;
              norm[2] /= len;
              len = DIST(pa, pb);
              dummypoint[0] = pa[0] + len * norm[0];
              dummypoint[1] = pa[1] + len * norm[1];
              dummypoint[2] = pa[2] + len * norm[2];
              // Check if a 2-to-2 flip is possible.
              ori1 = orient3d(pc, pd, dummypoint, pa);
              ori2 = orient3d(pc, pd, dummypoint, pb);
              if (ori1 * ori2 < 0) {
                // A 2-to-2 flip is found.
                flip22(flipfaces, lawson, 0);
                // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
                //   changed. The 'flipfaces[1]' contains p as its apex.
                senext2(flipfaces[1], *parentsh);
                // Save the new subface.
                caveshbdlist->newindex((void **) &parysh);
                *parysh = flipfaces[0];
                break;
              }
            } //
          } // i
          if (i == caveshlist->objects) {
            // This can happen only if there are 4 edges at p, and they are
            //   orthogonal to each other, see Fig. 2010-11-01.
            assert(caveshlist->objects == 4);
            // Do a flip22 and a flip31 to remove p.
            parysh = (face *) fastlookup(caveshlist, 0);
            flipfaces[0] = *parysh;
            spivot(flipfaces[0], flipfaces[1]);
            if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
              sesymself(flipfaces[1]);
            }
            flip22(flipfaces, lawson, 0);
            senext2(flipfaces[1], *parentsh);
            // Save the new subface.
            caveshbdlist->newindex((void **) &parysh);
            *parysh = flipfaces[0];
          }
          // The edge list at p are changed.
          caveshlist->restart();
        } // while (1)
    
      } // it
    
      cavesegshlist->restart();
    
      if (b->verbose > 2) {
        printf("      Created %ld new subfaces.\n", caveshbdlist->objects);
      }
    
    
      if (lawson) {
        lawsonflip();
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // slocate()    Locate a point in a surface triangulation.                   //
    //                                                                           //
    // Staring the search from 'searchsh'(it should not be NULL). Perform a line //
    // walk search for a subface containing the point (p).                       //
    //                                                                           //
    // If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies     //
    // above the 'searchsh' in its current orientation. The test if c is CCW to  //
    // the line a->b can be done by the test if c is below the oriented plane    //
    // a->b->dummypoint.                                                         //
    //                                                                           //
    // If 'cflag' is not TRUE, the triangulation may not be convex.  Stop search //
    // when a segment is met and return OUTSIDE.                                 //
    //                                                                           //
    // If 'rflag' (rounding) is set, after the location of the point is found,   //
    // either ONEDGE or ONFACE, round the result using an epsilon.               //
    //                                                                           //
    // The returned value inducates the following cases:                         //
    //   - ONVERTEX, p is the origin of 'searchsh'.                              //
    //   - ONEDGE, p lies on the edge of 'searchsh'.                             //
    //   - ONFACE, p lies in the interior of 'searchsh'.                         //
    //   - OUTSIDE, p lies outside of the triangulation, p is on the left-hand   //
    //     side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt, 
      face* searchsh, int aflag, int cflag, int rflag)
    {
      face neighsh;
      face checkseg;
      point pa, pb, pc, pd, *parypt;
      enum locateresult loc;
      enum {MOVE_BC, MOVE_CA} nextmove;
      REAL ori, ori_bc, ori_ca;
      REAL dist_bc, dist_ca;
      int i;
    
      // For finding an approximate location.
      //REAL n[3], len, len3;
      REAL n[3], area_abc, area_abp, area_bcp, area_cap;
    
      pa = sorg(*searchsh);
      pb = sdest(*searchsh);
      pc = sapex(*searchsh);
    
      if (!aflag) {
        // No above point is given. Calculate an above point for this facet.
        //   Re-use the 'cavetetvertlist'.
        cavetetvertlist->newindex((void **) &parypt);
        *parypt = pa;
        cavetetvertlist->newindex((void **) &parypt);
        *parypt = pb;
        cavetetvertlist->newindex((void **) &parypt);
        *parypt = pc;
        cavetetvertlist->newindex((void **) &parypt);
        *parypt = searchpt;
        calculateabovepoint(cavetetvertlist, NULL, NULL, NULL);
        cavetetvertlist->restart();
      }
    
      // 'dummypoint' is given. Make sure it is above [a,b,c]
      ori = orient3d(pa, pb, pc, dummypoint);
      assert(ori != 0); // SELF_CHECK
      if (ori > 0) {
        sesymself(*searchsh); // Reverse the face orientation.
      }
    
      // Find an edge of the face s.t. p lies on its right-hand side (CCW).
      for (i = 0; i < 3; i++) {
        pa = sorg(*searchsh);
        pb = sdest(*searchsh);
        ori = orient3d(pa, pb, dummypoint, searchpt);
        if (ori > 0) break;
        senextself(*searchsh);
      }
      assert(i < 3); // SELF_CHECK
    
      pc = sapex(*searchsh);
    
      if (pc == searchpt) {
        senext2self(*searchsh);
        return ONVERTEX;
      }
    
      while (1) {
    
        ori_bc = orient3d(pb, pc, dummypoint, searchpt);
        ori_ca = orient3d(pc, pa, dummypoint, searchpt);
    
        if (ori_bc < 0) {
          if (ori_ca < 0) { // (--)
            // Any of the edges is a viable move.
            senext(*searchsh, neighsh); // At edge [b, c].
            spivotself(neighsh);
            if (neighsh.sh != NULL) {
              pd = sapex(neighsh);
              dist_bc = NORM2(searchpt[0] - pd[0], searchpt[1] - pd[1],
                searchpt[2] - pd[2]);
            } else {
              dist_bc = NORM2(xmax - xmin, ymax - ymin, zmax - zmin);
            }
            senext2(*searchsh, neighsh); // At edge [c, a].
            spivotself(neighsh);
            if (neighsh.sh != NULL) {
              pd = sapex(neighsh);
              dist_ca = NORM2(searchpt[0] - pd[0], searchpt[1] - pd[1],
                searchpt[2] - pd[2]);
            } else {
              dist_ca = dist_bc;
            }
            if (dist_ca < dist_bc) {
              nextmove = MOVE_CA;
            } else {
              nextmove = MOVE_BC;
            }
          } else { // (-#)
            // Edge [b, c] is viable.
            nextmove = MOVE_BC;
          }
        } else {
          if (ori_ca < 0) { // (#-)
            // Edge [c, a] is viable.
            nextmove = MOVE_CA;
          } else {
            if (ori_bc > 0) {
              if (ori_ca > 0) { // (++)
                loc = ONFACE;  // Inside [a, b, c].
                break;
              } else { // (+0)
                senext2self(*searchsh); // On edge [c, a].
                loc = ONEDGE;
                break;
              }
            } else { // ori_bc == 0
              if (ori_ca > 0) { // (0+)
                senextself(*searchsh); // On edge [b, c].
                loc = ONEDGE;
                break;
              } else { // (00)
                // p is coincident with vertex c. 
                senext2self(*searchsh);
                return ONVERTEX;
              }
            }
          }
        }
    
        // Move to the next face.
        if (nextmove == MOVE_BC) {
          senextself(*searchsh);
        } else {
          senext2self(*searchsh);
        }
        if (!cflag) {
          // NON-convex case. Check if we will cross a boundary.
          sspivot(*searchsh, checkseg);
          if (checkseg.sh != NULL) {
            return ENCSEGMENT;
          }
        }
        spivot(*searchsh, neighsh);
        if (neighsh.sh == NULL) {
          return OUTSIDE; // A hull edge.
        }
        // Adjust the edge orientation.
        if (sorg(neighsh) != sdest(*searchsh)) {
          sesymself(neighsh);
        }
        assert(sorg(neighsh) == sdest(*searchsh)); // SELF_CHECK
    
        // Update the newly discovered face and its endpoints.
        *searchsh = neighsh;
        pa = sorg(*searchsh);
        pb = sdest(*searchsh);
        pc = sapex(*searchsh);
    
        if (pc == searchpt) {
          senext2self(*searchsh);
          return ONVERTEX;
        }
    
      } // while (1)
    
      // assert(loc == ONFACE || loc == ONEDGE);
    
    
      if (rflag) {
        // Round the locate result before return.
        pa = sorg(*searchsh);
        pb = sdest(*searchsh);
        pc = sapex(*searchsh);
    
        facenormal(pa, pb, pc, n, 1, NULL);
        area_abc = sqrt(dot(n, n));
    
        facenormal(pb, pc, searchpt, n, 1, NULL);
        area_bcp = sqrt(dot(n, n));
        if ((area_bcp / area_abc) < b->epsilon) {
          area_bcp = 0; // Rounding.
        }
    
        facenormal(pc, pa, searchpt, n, 1, NULL);
        area_cap = sqrt(dot(n, n));
        if ((area_cap / area_abc) < b->epsilon) {
          area_cap = 0; // Rounding
        }
    
        if ((loc == ONFACE) || (loc == OUTSIDE)) {
          facenormal(pa, pb, searchpt, n, 1, NULL);
          area_abp = sqrt(dot(n, n));
          if ((area_abp / area_abc) < b->epsilon) {
            area_abp = 0; // Rounding
          }
        } else { // loc == ONEDGE
          area_abp = 0;
        }
    
        if (area_abp == 0) {
          if (area_bcp == 0) {
            assert(area_cap != 0);
            senextself(*searchsh); 
            loc = ONVERTEX; // p is close to b.
          } else {
            if (area_cap == 0) {
              loc = ONVERTEX; // p is close to a.
            } else {
              loc = ONEDGE; // p is on edge [a,b].
            }
          }
        } else if (area_bcp == 0) {
          if (area_cap == 0) {
            senext2self(*searchsh); 
            loc = ONVERTEX; // p is close to c.
          } else {
            senextself(*searchsh);
            loc = ONEDGE; // p is on edge [b,c].
          }
        } else if (area_cap == 0) {
          senext2self(*searchsh);
          loc = ONEDGE; // p is on edge [c,a].
        } else {
          loc = ONFACE; // p is on face [a,b,c].
        }
      } // if (rflag)
    
      return loc;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // sscoutsegment()    Look for a segment in surface triangulation.           //
    //                                                                           //
    // The segment is given by the origin of 'searchsh' and 'endpt'.  Assume the //
    // orientation of 'searchsh' is CCW w.r.t. the above point.                  //
    //                                                                           //
    // If an edge in T is found matching this segment, the segment is "locaked"  //
    // in T at the edge.  Otherwise, flip the first edge in T that the segment   //
    // crosses. Continue the search from the flipped face.                       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    enum tetgenmesh::interresult 
      tetgenmesh::sscoutsegment(face *searchsh, point endpt)
    {
      face flipshs[2], neighsh;
      face newseg, checkseg;
      point startpt, pa, pb, pc, pd;
      enum interresult dir;
      enum {MOVE_AB, MOVE_CA} nextmove;
      REAL ori_ab, ori_ca;
      REAL dist_b, dist_c;
      int shmark = 0;
    
      // The origin of 'searchsh' is fixed.
      startpt = sorg(*searchsh); // pa = startpt;
      nextmove = MOVE_AB; // Avoid compiler warning.
    
      if (b->verbose > 2) {
        printf("      Scout segment (%d, %d).\n", pointmark(startpt),
               pointmark(endpt));
      }
    
      // Search an edge in 'searchsh' on the path of this segment.
      while (1) {
    
        pb = sdest(*searchsh);
        if (pb == endpt) {
          dir = SHAREEDGE; // Found!
          break;
        }
    
        pc = sapex(*searchsh);
        if (pc == endpt) {
          senext2self(*searchsh);
          sesymself(*searchsh);
          dir = SHAREEDGE; // Found!
          break;
        }
    
        ori_ab = orient3d(startpt, pb, dummypoint, endpt);
        ori_ca = orient3d(pc, startpt, dummypoint, endpt);
    
        if (ori_ab < 0) {
          if (ori_ca < 0) { // (--)
            // Both sides are viable moves.
            spivot(*searchsh, neighsh); // At edge [a, b].
            assert(neighsh.sh != NULL); // SELF_CHECK
            pd = sapex(neighsh);
            dist_b = NORM2(endpt[0] - pd[0], endpt[1] - pd[1], endpt[2] - pd[2]);
            senext2(*searchsh, neighsh); // At edge [c, a].
            spivotself(neighsh);
            assert(neighsh.sh != NULL); // SELF_CHECK
            pd = sapex(neighsh);
            dist_c = NORM2(endpt[0] - pd[0], endpt[1] - pd[1], endpt[2] - pd[2]);
            if (dist_c < dist_b) {
              nextmove = MOVE_CA;
            } else {
              nextmove = MOVE_AB;
            }
          } else { // (-#)
            nextmove = MOVE_AB;
          }
        } else {
          if (ori_ca < 0) { // (#-)
            nextmove = MOVE_CA;
          } else {
            if (ori_ab > 0) {
              if (ori_ca > 0) { // (++)
                // The segment intersects with edge [b, c].
                dir = ACROSSEDGE;
                break;
              } else { // (+0)
                // The segment collinear with edge [c, a].
                senext2self(*searchsh);
                sesymself(*searchsh);
                dir = ACROSSVERT;
                break;
              }
            } else {
              if (ori_ca > 0) { // (0+)
                // The segment collinear with edge [a, b].
                dir = ACROSSVERT;
                break;
              } else { // (00)
                // startpt == endpt. Not possible.
                assert(0); // SELF_CHECK
              }
            }
          }
        }
    
        // Move 'searchsh' to the next face, keep the origin unchanged.
        if (nextmove == MOVE_AB) {
          spivot(*searchsh, neighsh);
          if (sorg(neighsh) != pb) sesymself(neighsh);
          senext(neighsh, *searchsh);      
        } else {
          senext2(*searchsh, neighsh);
          spivotself(neighsh);
          if (sdest(neighsh) != pc) sesymself(neighsh);
          *searchsh = neighsh;
        }
        assert(sorg(*searchsh) == startpt); // SELF_CHECK
    
      } // while
    
      if (dir == SHAREEDGE) {
        // Insert the segment into the triangulation.
        makeshellface(subsegs, &newseg);
        setshvertices(newseg, startpt, endpt, NULL);
        // Set the actual segment marker.
        if (in->facetmarkerlist != NULL) {
          shmark = shellmark(*searchsh);
          setshellmark(newseg, in->facetmarkerlist[shmark - 1]);
        }
        ssbond(*searchsh, newseg);
        spivot(*searchsh, neighsh);
        if (neighsh.sh != NULL) {
          ssbond(neighsh, newseg);
        }
        return dir;
      }
    
      if (dir == ACROSSVERT) {
        // A point is found collinear with this segment.
        return dir;
      }
    
      if (dir == ACROSSEDGE) {
        // Edge [b, c] intersects with the segment.
        senext(*searchsh, flipshs[0]);
        sspivot(flipshs[0], checkseg);
        if (checkseg.sh != NULL) {
          printf("Error:  Invalid PLC.\n");
          pb = sorg(flipshs[0]);
          pc = sdest(flipshs[0]);
          printf("  Two segments (%d, %d) and (%d, %d) intersect.\n",
            pointmark(startpt), pointmark(endpt), pointmark(pb), pointmark(pc));
          terminatetetgen(3);
        }
        // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
        spivot(flipshs[0], flipshs[1]);
        assert(flipshs[1].sh != NULL); // SELF_CHECK
        if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
        flip22(flipshs, 1, 0);
        // The flip may create an invered triangle, check it.
        pa = sapex(flipshs[1]);
        pb = sapex(flipshs[0]);
        pc = sorg(flipshs[0]);
        pd = sdest(flipshs[0]);
        // Check if pa and pb are on the different sides of [pc, pd]. 
        // Re-use ori_ab, ori_ca for the tests.
        ori_ab = orient3d(pc, pd, dummypoint, pb);
        ori_ca = orient3d(pd, pc, dummypoint, pa);
        //assert(ori_ab * ori_ca != 0); // SELF_CHECK
        if (ori_ab < 0) {
          if (b->verbose > 2) {
            printf("      Queue an inversed triangle (%d, %d, %d) %d\n",
              pointmark(pc), pointmark(pd), pointmark(pb), pointmark(pa));
          }
          flipshpush(&(flipshs[0]));  // push it to 'flipstack'
        } else if (ori_ca < 0) {
          if (b->verbose > 2) {
            printf("      Queue an inversed triangle (%d, %d, %d) %d\n",
              pointmark(pd), pointmark(pc), pointmark(pa), pointmark(pb));
          }
          flipshpush(&(flipshs[1])); // // push it to 'flipstack'
        }
        // Set 'searchsh' s.t. its origin is 'startpt'.
        *searchsh = flipshs[0];
        assert(sorg(*searchsh) == startpt);
      }
    
      return sscoutsegment(searchsh, endpt);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // scarveholes()    Remove triangles not in the facet.                       //
    //                                                                           //
    // This routine re-uses the two global arrays: caveshlist and caveshbdlist.  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::scarveholes(int holes, REAL* holelist)
    {
      face *parysh, searchsh, neighsh;
      face checkseg;
      enum locateresult loc;
      int i, j;
    
      // Get all triangles. Infect unprotected convex hull triangles. 
      smarktest(recentsh);
      caveshlist->newindex((void **) &parysh);
      *parysh = recentsh;
      for (i = 0; i < caveshlist->objects; i++) {
        parysh = (face *) fastlookup(caveshlist, i);
        searchsh = *parysh;
        searchsh.shver = 0;
        for (j = 0; j < 3; j++) {
          spivot(searchsh, neighsh);
          // Is this side on the convex hull?
          if (neighsh.sh != NULL) {
            if (!smarktested(neighsh)) {
              smarktest(neighsh);
              caveshlist->newindex((void **) &parysh);
              *parysh = neighsh;
            }
          } else {
            // A hull side. Check if it is protected by a segment.
            sspivot(searchsh, checkseg);
            if (checkseg.sh == NULL) {
              // Not protected. Save this face.
              if (!sinfected(searchsh)) {
                sinfect(searchsh);
                caveshbdlist->newindex((void **) &parysh);
                *parysh = searchsh;
              }
            }
          }
          senextself(searchsh);
        }
      }
    
      // Infect the triangles in the holes.
      for (i = 0; i < 3 * holes; i += 3) {
        searchsh = recentsh;
        loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
        if (loc != OUTSIDE) {
          sinfect(searchsh);
          caveshbdlist->newindex((void **) &parysh);
          *parysh = searchsh;
        }
      }
    
      // Find and infect all exterior triangles.
      for (i = 0; i < caveshbdlist->objects; i++) {
        parysh = (face *) fastlookup(caveshbdlist, i);
        searchsh = *parysh;
        searchsh.shver = 0;
        for (j = 0; j < 3; j++) {
          spivot(searchsh, neighsh);
          if (neighsh.sh != NULL) {
            sspivot(searchsh, checkseg);
            if (checkseg.sh == NULL) {
              if (!sinfected(neighsh)) {
                sinfect(neighsh);
                caveshbdlist->newindex((void **) &parysh);
                *parysh = neighsh;
              }
            } else {
              sdissolve(neighsh); // Disconnect a protected face.
            }
          }
          senextself(searchsh);
        }
      }
    
      // Delete exterior triangles, unmark interior triangles.
      for (i = 0; i < caveshlist->objects; i++) {
        parysh = (face *) fastlookup(caveshlist, i);
        if (sinfected(*parysh)) {
          shellfacedealloc(subfaces, parysh->sh);
        } else {
          sunmarktest(*parysh);
        }
      }
    
      caveshlist->restart();
      caveshbdlist->restart();
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // triangulate()    Create a CDT for the facet.                              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
                                 int holes, REAL* holelist)
    {
      face searchsh, newsh, *parysh; 
      face newseg;
      point pa, pb, pc, *ppt, *cons;
      enum locateresult loc;
      int iloc;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      f%d:  %ld vertices, %ld segments", shmark, ptlist->objects,
               conlist->objects);
        if (holes > 0) {
          printf(", %d holes", holes);
        }
        printf(".\n");
      }
    
      if (ptlist->objects < 2l) {
        // Not a segment or a facet.
        return;
      } if (ptlist->objects == 2l) {
        pa = * (point *) fastlookup(ptlist, 0);
        pb = * (point *) fastlookup(ptlist, 1);
        if (distance(pa, pb) > 0) {
          // It is a single segment.
          makeshellface(subsegs, &newseg);
          setshvertices(newseg, pa, pb, NULL);
          // Set the actual segment marker.
          if (in->facetmarkerlist != NULL) {
            setshellmark(newseg, in->facetmarkerlist[shmark - 1]);
          }
        }
        if (pointtype(pa) == VOLVERTEX) {
          setpointtype(pa, RIDGEVERTEX);
        }
        if (pointtype(pb) == VOLVERTEX) {
          setpointtype(pb, RIDGEVERTEX);
        }
        return;
      } if (ptlist->objects == 3l) {
        // The facet has only one triangle.
        pa = * (point *) fastlookup(ptlist, 0);
        pb = * (point *) fastlookup(ptlist, 1);
        pc = * (point *) fastlookup(ptlist, 2);
        if (triarea(pa, pb, pc) > 0) {
          makeshellface(subfaces, &newsh);
          setshvertices(newsh, pa, pb, pc);
          setshellmark(newsh, shmark);
          // Create three new segments.
          for (i = 0; i < 3; i++) {
            makeshellface(subsegs, &newseg);
            setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
            // Set the actual segment marker.
            if (in->facetmarkerlist != NULL) {
              setshellmark(newseg, in->facetmarkerlist[shmark - 1]);
            }
            ssbond(newsh, newseg);
            senextself(newsh);
          }
          if (pointtype(pa) == VOLVERTEX) {
            setpointtype(pa, FACETVERTEX);
          }
          if (pointtype(pb) == VOLVERTEX) {
            setpointtype(pb, FACETVERTEX);
          }
          if (pointtype(pc) == VOLVERTEX) {
            setpointtype(pc, FACETVERTEX);
          }
        }
        return;
      }
    
      // Calulcate an above point of this facet.
      if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
        return; // The point set is degenerate.
      }
    
      // Create an initial triangulation.
      makeshellface(subfaces, &newsh);
      setshvertices(newsh, pa, pb, pc);
      setshellmark(newsh, shmark);
      recentsh = newsh;
    
      if (pointtype(pa) == VOLVERTEX) {
        setpointtype(pa, FACETVERTEX);
      }
      if (pointtype(pb) == VOLVERTEX) {
        setpointtype(pb, FACETVERTEX);
      }
      if (pointtype(pc) == VOLVERTEX) {
        setpointtype(pc, FACETVERTEX);
      }
    
      // Incrementally build the triangulation.
      pinfect(pa);
      pinfect(pb);
      pinfect(pc);
      for (i = 0; i < ptlist->objects; i++) {
        ppt = (point *) fastlookup(ptlist, i);
        if (!pinfected(*ppt)) {
          searchsh = recentsh; // Start from 'recentsh'.
          iloc = (int) OUTSIDE;
          if (b->verbose > 2) printf("      # %d", i);
          loc = (enum locateresult) sinsertvertex(*ppt, &searchsh, NULL, iloc, 1);
          assert(loc != ONVERTEX); // SELF_CHECK
          if (pointtype(*ppt) == VOLVERTEX) {
            setpointtype(*ppt, FACETVERTEX);
          }
          // Delete all removed subfaces.
          for (j = 0; j < caveshlist->objects; j++) {
            parysh = (face *) fastlookup(caveshlist, j);
            shellfacedealloc(subfaces, parysh->sh);
          }
          // Clear the global lists.
          caveshbdlist->restart();
          caveshlist->restart();
          cavesegshlist->restart();
        } else {
          puninfect(*ppt); // This point has inserted.
        }
      }
    
      // Insert the segments.
      for (i = 0; i < conlist->objects; i++) {
        cons = (point *) fastlookup(conlist, i);
        searchsh = recentsh;
        loc = slocate(cons[0], &searchsh, 1, 1, 0);
        assert(loc == ONVERTEX); // SELF_CHECK
        // Recover the segment. Some edges may be flipped.
        sscoutsegment(&searchsh, cons[1]);
        if (flipstack != NULL) {
          // Recover locally Delaunay edges.
          lawsonflip();
        }
      }
    
      // Remove exterior and hole triangles.
      scarveholes(holes, holelist);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // unifysubfaces()    Unify two identical subfaces.                          //
    //                                                                           //
    // Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b].  //
    // If c = d, then f1 and f2 are identical. Otherwise, these two subfaces     //
    // intersect, and the mesher is stopped.                                     //
    //                                                                           //
    // If the two subfaces are indentical, we try to replace f2 by f1, i.e, all  //
    // neighbors of f2 are re-connected to f1.                                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::unifysubfaces(face *f1, face *f2)
    {
      face casout, casin, neighsh;
      face sseg, checkseg;
      point pa, pb, pc, pd;
      int i;
    
      assert(f1->sh != f2->sh); // SELF_CHECK
    
      pa = sorg(*f1);
      pb = sdest(*f1);
      pc = sapex(*f1);
    
      assert(sorg(*f2) == pa); // SELF_CHECK
      assert(sdest(*f2) == pb); // SELF_CHECK
      pd = sapex(*f2);
    
      if (pc != pd) {
        printf("Found two facets intersect each other.\n");
        printf("  1st: [%d, %d, %d] #%d\n", 
    	   pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
        printf("  2nd: [%d, %d, %d] #%d\n",
    	   pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
        terminatetetgen(3);
      } else {
        printf("Found two duplicated facets.\n");
        printf("  1st: [%d, %d, %d] #%d\n", 
    	   pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
        printf("  2nd: [%d, %d, %d] #%d\n",
    	   pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
        terminatetetgen(3);
      }
    
      // f1 and f2 are identical, replace f2 by f1.
      if (!b->quiet) {
        printf("Warning:  Facet #%d is duplicated with Facet #%d. Removed!\n",
               shellmark(*f2), shellmark(*f1));
      }
    
      // Make possible disconnections/reconnections at neighbors of f2.
      for (i = 0; i < 3; i++) {
        spivot(*f1, casout);
        if (casout.sh == NULL) {
          // f1 has no adjacent subfaces yet.
          spivot(*f2, casout);
          if (casout.sh != NULL) {
            // Re-direct the adjacent connections of f2 to f1.
            casin = casout;
            spivot(casin, neighsh);
            while (neighsh.sh != f2->sh) {
              casin = neighsh;
              spivot(casin, neighsh);
            }
            // Connect casout <= f1 <= casin.
            sbond1(*f1, casout);
            sbond1(casin, *f1);
          }
        }
        sspivot(*f2, sseg); 
        if (sseg.sh != NULL) {
          // f2 has a segment. It must be different to f1's.
          sspivot(*f1, checkseg); // SELF_CHECK
          if (checkseg.sh != NULL) { // SELF_CHECK
            assert(checkseg.sh != sseg.sh); // SELF_CHECK
          }
          // Disconnect bonds of subfaces to this segment.
          spivot(*f2, casout);
          if (casout.sh != NULL) {
            casin = casout;
            ssdissolve(casin);
            spivot(casin, neighsh);
            while (neighsh.sh != f2->sh) {
              casin = neighsh;
              ssdissolve(casin);
              spivot(casin, neighsh);
            }
          }
          // Delete the segment.
          shellfacedealloc(subsegs, sseg.sh);
        }
        spivot(*f2, casout);
        if (casout.sh != NULL) {
          // Find the subface (casin) pointing to f2.
          casin = casout;
          spivot(casin, neighsh);
          while (neighsh.sh != f2->sh) {
            casin = neighsh;
            spivot(casin, neighsh);
          }
          // Disconnect f2 <= casin.
          sdissolve(casin);
        }
        senextself(*f1);
        senextself(*f2);
      } // i
    
      // Delete f2.
      shellfacedealloc(subfaces, f2->sh);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // unifysegments()    Remove redundant segments and create face links.       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::unifysegments()
    {
      badface *facelink = NULL, *newlinkitem, *f1, *f2;
      face *facperverlist, sface;
      face subsegloop, testseg;
      point torg, tdest;
      REAL ori1, ori2, ori3;
      REAL n1[3], n2[3];
      int *idx2faclist;
      int idx, k, m;
    
      if (b->verbose > 1) {
        printf("  Unifying segments.\n");
      }
    
      // Create a mapping from vertices to subfaces.
      makepoint2submap(subfaces, idx2faclist, facperverlist);
    
      subsegloop.shver = 0;
      subsegs->traversalinit();
      subsegloop.sh = shellfacetraverse(subsegs);
      while (subsegloop.sh != (shellface *) NULL) {
        torg = sorg(subsegloop);
        tdest = sdest(subsegloop);
    
        idx = pointmark(torg) - in->firstnumber;
        // Loop through the set of subfaces containing 'torg'.  Get all the
        //   subfaces containing the edge (torg, tdest). Save and order them
        //   in 'sfacelist', the ordering is defined by the right-hand rule
        //   with thumb points from torg to tdest.
        for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
          sface = facperverlist[k];
          // The face may be deleted if it is a duplicated face.
          if (sface.sh[3] == NULL) continue;
          // Search the edge torg->tdest.
          assert(sorg(sface) == torg); // SELF_CHECK
          if (sdest(sface) != tdest) {
            senext2self(sface);
            sesymself(sface);
          }
          if (sdest(sface) != tdest) continue;
    
          // Save the face f in facelink.
          if (flippool->items >= 2) {
            f1 = facelink;
            for (m = 0; m < flippool->items - 1; m++) {
              f2 = f1->nextitem;
              ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
              ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
              if (ori1 > 0) {
                // apex(f2) is below f1.
                if (ori2 > 0) {
                  // apex(f) is below f1 (see Fig.1). 
                  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
                  if (ori3 > 0) {
                    // apex(f) is below f2, insert it.
                    break; 
                  } else if (ori3 < 0) {
                    // apex(f) is above f2, continue.
                  } else { // ori3 == 0; 
                    // f is coplanar and codirection with f2.
                    unifysubfaces(&(f2->ss), &sface);
                    break;
                  }
                } else if (ori2 < 0) {
                  // apex(f) is above f1 below f2, inset it (see Fig. 2).
                  break;
                } else { // ori2 == 0;
                  // apex(f) is coplanar with f1 (see Fig. 5).
                  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
                  if (ori3 > 0) {
                    // apex(f) is below f2, insert it.
                    break; 
                  } else {
                    // f is coplanar and codirection with f1.
                    unifysubfaces(&(f1->ss), &sface);
                    break;
                  }
                }
              } else if (ori1 < 0) {
                // apex(f2) is above f1.
                if (ori2 > 0) {
                  // apex(f) is below f1, continue (see Fig. 3).
                } else if (ori2 < 0) {
                  // apex(f) is above f1 (see Fig.4).
                  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
                  if (ori3 > 0) {
                    // apex(f) is below f2, insert it.
                    break;
                  } else if (ori3 < 0) {
                    // apex(f) is above f2, continue.
                  } else { // ori3 == 0;
                    // f is coplanar and codirection with f2.
                    unifysubfaces(&(f2->ss), &sface);
                    break;
                  }
                } else { // ori2 == 0;
                  // f is coplanar and with f1 (see Fig. 6).
                  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
                  if (ori3 > 0) {
                    // f is also codirection with f1.
                    unifysubfaces(&(f1->ss), &sface);
                    break;
                  } else {
                    // f is above f2, continue.
                  }
                }
              } else { // ori1 == 0;
                // apex(f2) is coplanar with f1. By assumption, f1 is not
                //   coplanar and codirection with f2.
                if (ori2 > 0) {
                  // apex(f) is below f1, continue (see Fig. 7).
                } else if (ori2 < 0) {
                  // apex(f) is above f1, insert it (see Fig. 7).
                  break;
                } else { // ori2 == 0.
                  // apex(f) is coplanar with f1 (see Fig. 8).
                  // f is either codirection with f1 or is codirection with f2. 
                  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
                  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
                  if (DOT(n1, n2) > 0) {
                    unifysubfaces(&(f1->ss), &sface);
                  } else {
                    unifysubfaces(&(f2->ss), &sface);
                  }
                  break;
                }
              }
              // Go to the next item;
              f1 = f2;
            } // for (m = 0; ...)
            if (sface.sh[3] != NULL) {
              // Insert sface between f1 and f2.
              newlinkitem = (badface *) flippool->alloc();
              newlinkitem->ss = sface;
              newlinkitem->nextitem = f1->nextitem;
              f1->nextitem = newlinkitem;
            }
          } else if (flippool->items == 1) {
            f1 = facelink;
            // Make sure that f is not coplanar and codirection with f1.
            ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
            if (ori1 == 0) {
              // f is coplanar with f1 (see Fig. 8).
              facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
              facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
              if (DOT(n1, n2) > 0) {
                // The two faces are codirectional as well.
                unifysubfaces(&(f1->ss), &sface);
              }
            }
            // Add this face to link if it is not deleted.
            if (sface.sh[3] != NULL) {
              // Add this face into link.
              newlinkitem = (badface *) flippool->alloc();
              newlinkitem->ss = sface;
              newlinkitem->nextitem = NULL;
              f1->nextitem = newlinkitem;
            }
          } else {
            // The first face.
            newlinkitem = (badface *) flippool->alloc();
            newlinkitem->ss = sface;
            newlinkitem->nextitem = NULL;
            facelink = newlinkitem;
          }
        } // for (k = idx2faclist[idx]; ...)
    
        if (b->verbose > 2) {
          printf("      Found %ld segments at (%d  %d).\n", flippool->items,
                 pointmark(torg), pointmark(tdest));
        }
    
        //if (b->nobisect || b->nomerge) { // -Y or -M
          // Set the vertex types of the endpoints of the segment.
          setpointtype(torg, RIDGEVERTEX);
          setpointtype(tdest, RIDGEVERTEX);
        //}
    
        // Set the connection between this segment and faces containing it,
        //   at the same time, remove redundant segments.
        f1 = facelink;
        for (k = 0; k < flippool->items; k++) {
          sspivot(f1->ss, testseg);
          // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
          if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
            shellfacedealloc(subsegs, testseg.sh);
          }
          // Bonds the subface and the segment together.
          ssbond(f1->ss, subsegloop);
          f1 = f1->nextitem;
        }
    
        // Create the face ring at the segment.
        if (flippool->items > 1) {
          f1 = facelink;
          for (k = 1; k <= flippool->items; k++) {
            k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
            if (b->verbose > 3) {
              printf("        Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n",
                     pointmark(torg), pointmark(tdest), pointmark(sapex(f1->ss)),
                     pointmark(torg), pointmark(tdest), pointmark(sapex(f2->ss)));
            }
            sbond1(f1->ss, f2->ss);
            f1 = f2;
          }
        }
    
        // // All identified segments has a marker "-1".
        //setshellmark(subsegloop, -1);
        // All identified segments has an init marker "0".
        flippool->restart();
    
        subsegloop.sh = shellfacetraverse(subsegs);
      }
    
      delete [] idx2faclist;
      delete [] facperverlist;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // mergefacets()    Merge adjacent facets.                                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::mergefacets()
    {
      face parentsh, neighsh, neineish;
      face segloop;
      point pa, pb, pc, pd;
      REAL ang_tol, ang;
      int remsegcount;
      int fidx1, fidx2;
      int fmrk1, fmrk2;
    
      if (b->verbose > 1) {
        printf("    Merging adjacent facets.\n");
      }
    
      // The dihedral angle bound for two different facets.
      //   Set by -p option. Default is 179 degree.
      ang_tol = b->facet_ang_tol / 180.0 * PI;
      remsegcount = 0;
    
      // Loop all segments, merge adjacent coplanar facets.
      subsegs->traversalinit();
      segloop.sh = shellfacetraverse(subsegs);
      while (segloop.sh != (shellface *) NULL) {
        spivot(segloop, parentsh);
        if (parentsh.sh != NULL) {
          spivot(parentsh, neighsh);
          if (neighsh.sh != NULL) {
            spivot(neighsh, neineish);
            if (neineish.sh == parentsh.sh) {
              // Exactly two subfaces at this segment.
              fidx1 = shellmark(parentsh) - 1;
              fidx2 = shellmark(neighsh) - 1;
              // Only merge them if they are in different facet.
              if (fidx1 != fidx2) {
                // The two subfaces are not in the same facet.
                if (in->facetmarkerlist != NULL) { 
                  fmrk1 = in->facetmarkerlist[fidx1];
                  fmrk2 = in->facetmarkerlist[fidx2];
                } else {
                  fmrk1 = fmrk2 = 0;
                }
                // Only merge them if they have the same boundary marker.
                if (fmrk1 == fmrk2) {
                  pa = sorg(segloop);
                  pb = sdest(segloop);
                  pc = sapex(parentsh);
                  pd = sapex(neighsh);
                  // Calculate the dihedral angle at the segment [a,b].
                  ang = facedihedral(pa, pb, pc, pd);
                  if (ang > PI) ang = (2 * PI - ang);
                  if (ang > ang_tol) {
                    if (b->verbose > 2) {
                      printf("      Merge at segment (%d, %d)-(%d, %d) ang = %g\n",
                             pointmark(pa), pointmark(pb), pointmark(pc), 
                             pointmark(pd), ang / PI * 180.0);
                    }
                    remsegcount++;
                    ssdissolve(parentsh);
                    ssdissolve(neighsh);
                    shellfacedealloc(subsegs, segloop.sh);
                    // Add the edge to flip stack.
                    flipshpush(&parentsh);
                  } // if (ang > ang_tol)
                } // if (fmrk1 == fmrk2)
              } // if (fidx1 != fidx2)
            } // if (neineish.sh == parentsh.sh)
          }
        }
        segloop.sh = shellfacetraverse(subsegs);
      }
    
      if (flipstack != NULL) {
        lawsonflip(); // Recover Delaunayness.
      }
    
    
      if (b->verbose > 1) {
        printf("    %d segments are removed.\n", remsegcount);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // identifypscedges()    Identify PSC edges.                                 //
    //                                                                           //
    // The set of PSC edges are provided in the 'in->edgelist'. Each edge should //
    // also be an edge in the surface mesh.  We find the corresponding edges in  //
    // the surface mesh and make them segments of the mesh.                      //
    //                                                                           //
    // It is possible to give an edge which is not in any facet, i.e., it is a   //
    // dangling edge inside the volume.                                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::identifypscedges(point *idx2verlist)
    {
      face* shperverlist;
      int* idx2shlist;
      face searchsh, neighsh;
      face segloop, checkseg, newseg;
      point checkpt, pa, pb;
      int *endpts;
      int edgemarker;
      int idx, i, j;
    
      if (!b->quiet) {
        printf("Inserting edges ...\n");
      }
    
      //assert(in->numberofedges > 0); // SELF_CHECK
      //assert(in->edgemarkerlist != NULL); // SELF_CHECK
      // All identified segments have the initial marker '0'.
      // All segments inserted here should have a non-zero marker.
    
      // Construct a map from points to subfaces.
      makepoint2submap(subfaces, idx2shlist, shperverlist);
    
      // Process the set of PSC edges.
      for (i = 0; i < in->numberofedges; i++) {
        endpts = &(in->edgelist[(i << 1)]);
        // Find a face contains the edge.
        searchsh.sh = NULL;
        idx = endpts[0] - in->firstnumber;
        for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
          checkpt = sdest(shperverlist[j]);
          if (pointmark(checkpt) == endpts[1]) {
            searchsh = shperverlist[j];
            break; // Found.
          } else {
            checkpt = sapex(shperverlist[j]);
            if (pointmark(checkpt) == endpts[1]) {
              senext2(shperverlist[j], searchsh);
              sesymself(searchsh);
              break;
            }
          }
        } // j
        edgemarker = 0;
        if (in->edgemarkerlist) {
          edgemarker = in->edgemarkerlist[i];
        }
        if (edgemarker == 0) {
          edgemarker = 1;
        }
        // We should find a subface having this edge.
        if (searchsh.sh != NULL) {
          // Check if this edge is already a segment of the mesh.
          sspivot(searchsh, checkseg);
          if (checkseg.sh != NULL) {
            // There should be no duplicated edges.
            assert(shellmark(checkseg) == 0);
            setshellmark(checkseg, edgemarker);
          } else {
            // Create a new segment at this edge.
            pa = sorg(searchsh);
            pb = sdest(searchsh);
            if (b->verbose > 2) {
              printf("      Create a new segment (%d, %d).\n", 
                     pointmark(pa), pointmark(pb));
            }
            makeshellface(subsegs, &newseg);
            setshvertices(newseg, pa, pb, NULL);
            setshellmark(newseg, edgemarker);
            ssbond(searchsh, newseg);
            spivot(searchsh, neighsh);
            if (neighsh.sh != NULL) {
              ssbond(neighsh, newseg);
              // There should be only two subfaces at this segment.
              spivotself(neighsh); // SELF_CHECK
              assert(neighsh.sh == searchsh.sh);
            }
            if (!b->psc) {
              setpointtype(pa, RIDGEVERTEX);
              setpointtype(pb, RIDGEVERTEX);
            }
          }
        } else {
          // It is a dangling segment (not belong to any facets).
          // Get the two endpoints of this segment.
          pa = idx2verlist[endpts[0]];
          pb = idx2verlist[endpts[1]];
          if (b->verbose > 2) {
            printf("      Create a new segment (%d, %d) - dangling.\n", 
                   pointmark(pa), pointmark(pb));
          }
          makeshellface(subsegs, &newseg);
          setshvertices(newseg, pa, pb, NULL);
          setshellmark(newseg, edgemarker);
          //if (!b->psc) {
            setpointtype(pa, RIDGEVERTEX);
            setpointtype(pb, RIDGEVERTEX);
          //}
        }
      } // i
    
      if (b->psc) {
        // Delete all segments of the mesh with a marker '0'.
        subsegs->traversalinit();
        segloop.sh = shellfacetraverse(subsegs);
        while (segloop.sh != NULL) {
          if (shellmark(segloop) == 0) {
            if (b->verbose > 2) {
              printf("      Remove a segment (%d, %d).\n", 
                     pointmark(sorg(segloop)), pointmark(sdest(segloop)));
            }
            spivot(segloop, searchsh);
            if (searchsh.sh != NULL) {
              ssdissolve(searchsh);
              spivot(searchsh, neighsh);
              if (neighsh.sh != NULL) {
                ssdissolve(neighsh);
                // There should be only two subfaces at this segment.
                spivotself(neighsh); // SELF_CHECK
                assert(neighsh.sh == searchsh.sh);
              }
            }
            shellfacedealloc(subsegs, segloop.sh);
          }
          segloop.sh = shellfacetraverse(subsegs);
        }
      }
    
      delete [] shperverlist;
      delete [] idx2shlist;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // meshsurface()    Create a surface mesh of the input PLC.                  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::meshsurface()
    {
      arraypool *ptlist, *conlist;
      point *idx2verlist;
      point tstart, tend, *pnewpt, *cons;
      tetgenio::facet *f;
      tetgenio::polygon *p;
      int end1, end2;
      int shmark, i, j;
    
      if (!b->quiet) {
        printf("Creating surface mesh ...\n");
      }
    
      // Create a map from indices to points.
      makeindex2pointmap(idx2verlist);
    
      // Initialize arrays (block size: 2^8 = 256).
      ptlist = new arraypool(sizeof(point *), 8);
      conlist = new arraypool(2 * sizeof(point *), 8);
    
      // Loop the facet list, triangulate each facet.
      for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
    
        // Get a facet F.
        f = &in->facetlist[shmark - 1];
    
        // Process the duplicated points first, they are marked with type
        //   DUPLICATEDVERTEX.  If p and q are duplicated, and p'index > q's,
        //   then p is substituted by q.
        if (dupverts > 0l) {
          // Loop all polygons of this facet.
          for (i = 0; i < f->numberofpolygons; i++) {
            p = &(f->polygonlist[i]);
            // Loop other vertices of this polygon.
            for (j = 0; j < p->numberofvertices; j++) {
              end1 = p->vertexlist[j];
              tstart = idx2verlist[end1];
              if (pointtype(tstart) == DUPLICATEDVERTEX) {
                // Reset the index of vertex-j.
                tend = point2ppt(tstart);
                end2 = pointmark(tend);
                p->vertexlist[j] = end2;
              }
            }
          }
        }
    
        // Loop polygons of F, get the set of vertices and segments.
        for (i = 0; i < f->numberofpolygons; i++) {
          // Get a polygon.
          p = &(f->polygonlist[i]);
          // Get the first vertex.
          end1 = p->vertexlist[0];
          if ((end1 < in->firstnumber) || 
              (end1 >= in->firstnumber + in->numberofpoints)) {
            if (!b->quiet) {
              printf("Warning:  Invalid the 1st vertex %d of polygon", end1);
              printf(" %d in facet %d.\n", i + 1, shmark);
            }
            continue; // Skip this polygon.
          }
          tstart = idx2verlist[end1];
          // Add tstart to V if it haven't been added yet.
          if (!pinfected(tstart)) {
            pinfect(tstart);
            ptlist->newindex((void **) &pnewpt);
            *pnewpt = tstart;
          }
          // Loop other vertices of this polygon.
          for (j = 1; j <= p->numberofvertices; j++) {
            // get a vertex.
            if (j < p->numberofvertices) {
              end2 = p->vertexlist[j];
            } else {
              end2 = p->vertexlist[0];  // Form a loop from last to first.
            }
            if ((end2 < in->firstnumber) ||
                (end2 >= in->firstnumber + in->numberofpoints)) {
              if (!b->quiet) {
                printf("Warning:  Invalid vertex %d in polygon %d", end2, i + 1);
                printf(" in facet %d.\n", shmark);
              }
            } else {
              if (end1 != end2) {
                // 'end1' and 'end2' form a segment.
                tend = idx2verlist[end2];
                // Add tstart to V if it haven't been added yet.
                if (!pinfected(tend)) {
                  pinfect(tend);
                  ptlist->newindex((void **) &pnewpt);
                  *pnewpt = tend;
                }
                // Save the segment in S (conlist).
                conlist->newindex((void **) &cons);
                cons[0] = tstart;
                cons[1] = tend;
                // Set the start for next continuous segment.
                end1 = end2;
                tstart = tend;
              } else {
                // Two identical vertices mean an isolated vertex of F.
                if (p->numberofvertices > 2) {
                  // This may be an error in the input, anyway, we can continue
                  //   by simply skipping this segment.
                  if (!b->quiet) {
                    printf("Warning:  Polygon %d has two identical verts", i + 1);
                    printf(" in facet %d.\n", shmark);
                  }
                } 
                // Ignore this vertex.
              }
            }
            // Is the polygon degenerate (a segment or a vertex)?
            if (p->numberofvertices == 2) break;
          }
        }
        // Unmark vertices.
        for (i = 0; i < ptlist->objects; i++) {
          pnewpt = (point *) fastlookup(ptlist, i);
          puninfect(*pnewpt);
        }
    
        // Triangulate F into a CDT.
        triangulate(shmark, ptlist, conlist, f->numberofholes, f->holelist);
    
        // Clear working lists.
        ptlist->restart();
        conlist->restart();
      }
    
      if (!b->diagnose) {
        // Remove redundant segments and build the face links.
        unifysegments();
      }
    
      if (!b->nomerge && !b->nobisect && !b->diagnose) {
        // Merge adjacent coplanar facets.
        mergefacets();
      }
    
      if (in->numberofedges > 0) { // if (b->psc)
        // There are segments specified by the user. Read and create them.
        identifypscedges(idx2verlist);
      }
    
      if (b->object == tetgenbehavior::STL) {
        // Remove redundant vertices (for .stl input mesh).
        jettisonnodes();
      }
    
      if (b->verbose) {
        printf("  %ld (%ld) subfaces (segments).\n", subfaces->items, 
               subsegs->items);
      }
    
      // The total number of iunput segments.
      insegments = subsegs->items;
    
      delete [] idx2verlist;
      delete ptlist;
      delete conlist;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // interecursive()    Recursively do intersection test on a set of triangles.//
    //                                                                           //
    // Recursively split the set 'subfacearray' of subfaces into two sets using  //
    // a cut plane parallel to x-, or, y-, or z-axies.  The split criteria are   //
    // follows. Assume the cut plane is H, and H+ denotes the left halfspace of  //
    // H, and H- denotes the right halfspace of H; and s be a subface:           //
    //                                                                           //
    //    (1) If all points of s lie at H+, put it into left array;              //
    //    (2) If all points of s lie at H-, put it into right array;             //
    //    (3) If some points of s lie at H+ and some of lie at H-, or some       //
    //        points lie on H, put it into both arraies.                         //
    //                                                                           //
    // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis  //
    // if axis == '2'. If current cut plane is parallel to the x-axis, the next  //
    // one will be parallel to y-axis, and the next one after the next is z-axis,//
    // and then alternately return back to x-axis.                               //
    //                                                                           //
    // Stop splitting when the number of triangles of the input array is not     //
    // decreased anymore. Do tests on the current set.                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::interecursive(shellface** subfacearray, int arraysize, 
                                   int axis, REAL bxmin, REAL bxmax, REAL bymin, 
                                   REAL bymax, REAL bzmin, REAL bzmax, 
                                   int* internum)
    {
      shellface **leftarray, **rightarray;
      face sface1, sface2;
      point p1, p2, p3;
      point p4, p5, p6;
      enum interresult intersect;
      REAL split;
      bool toleft, toright;
      int leftsize, rightsize;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
               arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
               axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
      }
        
      leftarray = new shellface*[arraysize];
      if (leftarray == NULL) {
        terminatetetgen(1);
      }
      rightarray = new shellface*[arraysize];
      if (rightarray == NULL) {
        terminatetetgen(1);
      }
      leftsize = rightsize = 0;
    
      if (axis == 0) {
        // Split along x-axis.
        split = 0.5 * (bxmin + bxmax);
      } else if (axis == 1) {
        // Split along y-axis.
        split = 0.5 * (bymin + bymax);
      } else {
        // Split along z-axis.
        split = 0.5 * (bzmin + bzmax);
      }
    
      for (i = 0; i < arraysize; i++) {
        sface1.sh = subfacearray[i];
        p1 = (point) sface1.sh[3];
        p2 = (point) sface1.sh[4];
        p3 = (point) sface1.sh[5];
        toleft = toright = false;
        if (p1[axis] < split) {
          toleft = true;
          if (p2[axis] >= split || p3[axis] >= split) {
            toright = true;
          } 
        } else if (p1[axis] > split) {
          toright = true;
          if (p2[axis] <= split || p3[axis] <= split) {
            toleft = true;
          } 
        } else {
          // p1[axis] == split;
          toleft = true;
          toright = true;
        }
        // At least one is true;
    #ifdef SELF_CHECK
        assert(!(toleft == false && toright == false));
    #endif
        if (toleft) {
          leftarray[leftsize] = sface1.sh;
          leftsize++;
        }
        if (toright) {
          rightarray[rightsize] = sface1.sh;
          rightsize++;
        }
      }
    
      if (leftsize < arraysize && rightsize < arraysize) {
        // Continue to partition the input set. Now 'subfacearray' has been
        //   split into two sets, it's memory can be freed. 'leftarray' and
        //   'rightarray' will be freed in the next recursive (after they're
        //   partitioned again or performing tests).
        delete [] subfacearray;
        // Continue to split these two sets.
        if (axis == 0) {
          interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
                        bzmin, bzmax, internum);
          interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
                        bzmin, bzmax, internum);
        } else if (axis == 1) {
          interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
                        bzmin, bzmax, internum);
          interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
                        bzmin, bzmax, internum);
        } else {
          interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
                        bzmin, split, internum);
          interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
                        split, bzmax, internum);
        }
      } else {
        if (b->verbose > 1) {
          printf("  Checking intersecting faces.\n");
        }
        // Perform a brute-force compare on the set.
        for (i = 0; i < arraysize; i++) {
          sface1.sh = subfacearray[i];
          p1 = (point) sface1.sh[3];
          p2 = (point) sface1.sh[4];
          p3 = (point) sface1.sh[5];
          for (j = i + 1; j < arraysize; j++) {
            sface2.sh = subfacearray[j];
            p4 = (point) sface2.sh[3];
            p5 = (point) sface2.sh[4];
            p6 = (point) sface2.sh[5];
            intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
            if (intersect == INTERSECT || intersect == SHAREFACE) {
              if (!b->quiet) {
                if (intersect == INTERSECT) {
                  printf("  Facet #%d intersects facet #%d at triangles:\n",
                         shellmark(sface1), shellmark(sface2));
                  printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
                         pointmark(p1), pointmark(p2), pointmark(p3),
                         pointmark(p4), pointmark(p5), pointmark(p6));
                } else {
                  printf("  Facet #%d duplicates facet #%d at triangle:\n",
                         shellmark(sface1), shellmark(sface2));
                  printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
                         pointmark(p1), pointmark(p2), pointmark(p3),
                         pointmark(p4), pointmark(p5), pointmark(p6));
                }
              }
              // Increase the number of intersecting pairs.
              (*internum)++; 
              // Infect these two faces (although they may already be infected).
              sinfect(sface1);
              sinfect(sface2);
            }
          }
        }
        // Don't forget to free all three arrays. No further partition.
        delete [] leftarray;
        delete [] rightarray;  
        delete [] subfacearray;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // detectinterfaces()    Detect intersecting triangles.                      //
    //                                                                           //
    // Given a set of triangles,  find the pairs of intersecting triangles from  //
    // them.  Here the set of triangles is in 'subfaces' which is a surface mesh //
    // of a PLC (.poly or .smesh).                                               //
    //                                                                           //
    // To detect whether two triangles are intersecting is done by the routine   //
    // 'tri_tri_inter()'.  The algorithm for the test is very simple and stable. //
    // It is based on geometric orientation test which uses exact arithmetics.   //
    //                                                                           //
    // Use divide-and-conquer algorithm for reducing the number of intersection  //
    // tests.  Start from the bounding box of the input point set, recursively   //
    // partition the box into smaller boxes, until the number of triangles in a  //
    // box is not decreased anymore. Then perform triangle-triangle tests on the //
    // remaining set of triangles.  The memory allocated in the input set is     //
    // freed immediately after it has been partitioned into two arrays.  So it   //
    // can be re-used for the consequent partitions.                             //
    //                                                                           //
    // On return, the pool 'subfaces' will be cleared, and only the intersecting //
    // triangles remain for output (to a .face file).                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::detectinterfaces()
    {
      shellface **subfacearray;
      face shloop;
      int internum;
      int i;
    
      if (!b->quiet) {
        printf("Detecting self-intersecting facets...\n");
      }
    
      // Construct a map from indices to subfaces;
      subfacearray = new shellface*[subfaces->items];
      subfaces->traversalinit();
      shloop.sh = shellfacetraverse(subfaces);
      i = 0;
      while (shloop.sh != (shellface *) NULL) {
        subfacearray[i] = shloop.sh;
        shloop.sh = shellfacetraverse(subfaces);
        i++;
      }
    
      internum = 0;
      // Recursively split the set of triangles into two sets using a cut plane
      //   parallel to x-, or, y-, or z-axies.  Stop splitting when the number
      //   of subfaces is not decreasing anymore. Do tests on the current set.
      interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
                    zmin, zmax, &internum);
    
      if (!b->quiet) {
        if (internum > 0) {
          printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
        } else {
          printf("\nNo faces are intersecting.\n\n");
        }
      }
    
      if (internum > 0) {
        // Traverse all subfaces, deallocate those have not been infected (they
        //   are not intersecting faces). Uninfect those have been infected.
        //   After this loop, only intersecting faces remain.
        subfaces->traversalinit();
        shloop.sh = shellfacetraverse(subfaces);
        while (shloop.sh != (shellface *) NULL) {
          if (sinfected(shloop)) {
            suninfect(shloop);
          } else {
            shellfacedealloc(subfaces, shloop.sh);
          }
          shloop.sh = shellfacetraverse(subfaces);
        }
      } else {
        // Deallocate all subfaces.
        subfaces->restart();
      }
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// surface_cxx //////////////////////////////////////////////////////////////
    
    //// constrained_cxx //////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // markacutevertices()    Classify vertices as ACUTEVERTEXs or RIDGEVERTEXs. //
    //                                                                           //
    // Initially all segment vertices have type RIDGEVERTEX.  A segment is acute //
    // if there are at least two segments incident at it form an angle less than //
    // theta (= 60 degree).                                                      //
    //                                                                           //
    // The minimum segment-segment angle (minfaceang) is calculated.             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::markacutevertices()
    {
      face* segperverlist;
      int* idx2seglist;
      point pa, pb, pc;
      REAL anglimit, ang;
      bool acuteflag;
      int acutecount;
      int idx, i, j;
    
      REAL sharpanglimit;
      int sharpsegcount;
    
      if (b->verbose) {
        printf("  Marking acute vertices.\n");
      }
      anglimit = PI / 3.0;  // 60 degree.
      sharpanglimit = 10.0 / 180.0 * PI; // 10 degree. 
      minfaceang = PI; // 180 degree.
      acutecount = sharpsegcount = 0;
    
      // Construct a map from points to segments.
      makepoint2submap(subsegs, idx2seglist, segperverlist);
    
      // Loop over the set of vertices.
      points->traversalinit();
      pa = pointtraverse();
      while (pa != NULL) {
        idx = pointmark(pa) - in->firstnumber;
        // Mark it if it is an endpoint of some segments.
        if (idx2seglist[idx + 1] > idx2seglist[idx]) {
          if (b->psc) {
            // Only test it if it is an input vertex.
            if (pointtype(pa) == FREESEGVERTEX) {
              pa = pointtraverse();
              continue;
            }
          }
          acuteflag = false;
          // Do a brute-force pair-pair check.
          for (i=idx2seglist[idx]; i<idx2seglist[idx + 1]; i++) {
            pb = sdest(segperverlist[i]);
            //for (j = i + 1; j < idx2seglist[idx + 1] && !acuteflag; j++) {
            for (j = i + 1; j < idx2seglist[idx + 1]; j++) {
              pc = sdest(segperverlist[j]);
              ang = interiorangle(pa, pb, pc, NULL); 
              //acuteflag = ang < anglimit;
              if (!acuteflag) {
                acuteflag = ang < anglimit;
              }
              // Remember the smallest angle.
              if (ang < minfaceang) minfaceang = ang;
              // Mark segments at extremely small angle.
              if (ang < sharpanglimit) {
                if (shelltype(segperverlist[i]) != SHARP) {
                  setshelltype(segperverlist[i], SHARP);
                  sharpsegcount++;
                }
                if (shelltype(segperverlist[j]) != SHARP) {
                  setshelltype(segperverlist[j], SHARP);
                  sharpsegcount++;
                }
              }
            } // j
          } // i
          if (!acuteflag) {
            if ((idx2seglist[idx + 1] - idx2seglist[idx]) > 4) {
              // There are at least 5 segments shared at this vertices.
              acuteflag = true;
            }
          }
          if (acuteflag) {
            if (b->verbose > 2) {
              printf("      Mark %d as ACUTEVERTEX.\n", pointmark(pa));
            }
            setpointtype(pa, ACUTEVERTEX);
            acutecount++;
          }
        }
        pa = pointtraverse();
      }
    
      if (b->verbose) {
        if (acutecount > 0) {
          printf("  Found %d acute vertices.\n", acutecount);
        }
        if (sharpsegcount > 0) {
          printf("  Found %d sharp segments.\n", sharpsegcount);
        }
        printf("  Minimum seg-seg angle = %g.\n", minfaceang / PI * 180.0);
      }
    
      delete [] idx2seglist;
      delete [] segperverlist;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // reportselfintersect()    Report a self-intersection.                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::reportselfintersect(face *checkseg, face *checksh)
    {
      face parentsh;
      point pa, pb, pc, pd, pe;
      point fa, fb;
    
      pa = sorg(*checkseg);
      pb = sdest(*checkseg);
      fa = farsorg(*checkseg);
      fb = farsdest(*checkseg);
    
      pc = sorg(*checksh);
      pd = sdest(*checksh);
      pe = sapex(*checksh);
    
      printf("  !! Detected a self-intersection between:\n");
      printf("     A segment [%d,%d] < [%d,%d], \n", pointmark(pa), pointmark(pb),
             pointmark(fa), pointmark(fb));
      printf("     a subface [%d,%d,%d] in facet #%d.\n", pointmark(pc), 
             pointmark(pd), pointmark(pe), shellmark(*checksh));
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // finddirection()    Find the tet on the path from one point to another.    //
    //                                                                           //
    // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
    // 'searchtet' contains a tet on the path, its origin does not change.       //
    //                                                                           //
    // The return value indicates one of the following cases (let 'searchtet' be //
    // abcd, a is the origin of the path):                                       //
    //   - ACROSSVERT, edge ab is collinear with the path;                       //
    //   - ACROSSEDGE, edge bc intersects with the path;                         //
    //   - ACROSSFACE, face bcd intersects with the path.                        //
    //                                                                           //
    // WARNING: This routine is designed for convex triangulations, and will not //
    // generally work after the holes and concavities have been carved.          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    enum tetgenmesh::interresult 
      tetgenmesh::finddirection(triface* searchtet, point endpt, int randflag)
    {
      triface neightet;
      point pa, pb, pc, pd;
      enum {HMOVE, RMOVE, LMOVE} nextmove;
      REAL hori, rori, lori;
      int s;
    
    
      // The origin is fixed.
      pa = org(*searchtet);
      if ((point) searchtet->tet[7] == dummypoint) {
        // A hull tet. Choose the neighbor of its base face.
        searchtet->ver = 11;
        fsymself(*searchtet);
        // Reset the origin to be pa.
        if ((point) searchtet->tet[4] == pa) {
          searchtet->ver = 11;
        } else if ((point) searchtet->tet[5] == pa) {
          searchtet->ver = 3;
        } else if ((point) searchtet->tet[6] == pa) {
          searchtet->ver = 7;
        } else {
          assert((point) searchtet->tet[7] == pa); // SELF_CHECK
          searchtet->ver = 0;
        }
      }
    
      pb = dest(*searchtet);
      // Check whether the destination or apex is 'endpt'.
      if (pb == endpt) {
        // pa->pb is the search edge.
        return ACROSSVERT;
      }
    
      pc = apex(*searchtet);
      if (pc == endpt) {
        // pa->pc is the search edge.
        eprevself(*searchtet);
        esymself(*searchtet);
        return ACROSSVERT;
      }
    
      // Walk through tets around pa until the right one is found.
      while (1) {
    
        pd = oppo(*searchtet);
    
        if (b->verbose > 3) {
          printf("        From tet (%d, %d, %d, %d) to %d.\n", pointmark(pa),
            pointmark(pb), pointmark(pc), pointmark(pd), pointmark(endpt));
        }
    
        // Check whether the opposite vertex is 'endpt'.
        if (pd == endpt) {
          // pa->pd is the search edge.
          esymself(*searchtet);
          enextself(*searchtet);
          return ACROSSVERT;
        }
        // Check if we have entered outside of the domain.
        if (pd == dummypoint) {
          // This is possible when the mesh is non-convex.
          assert(nonconvex);
          return ACROSSSUB; // Hit a bounday.
        }
    
        // Now assume that the base face abc coincides with the horizon plane,
        //   and d lies above the horizon.  The search point 'endpt' may lie
        //   above or below the horizon.  We test the orientations of 'endpt'
        //   with respect to three planes: abc (horizon), bad (right plane),
        //   and acd (left plane). 
        hori = orient3d(pa, pb, pc, endpt);
        rori = orient3d(pb, pa, pd, endpt);
        lori = orient3d(pa, pc, pd, endpt);
        orient3dcount += 3;
    
        // Now decide the tet to move.  It is possible there are more than one
        //   tet are viable moves. Use the opposite points of thier neighbors
        //   to discriminate, i.e., we choose the tet whose opposite point has
        //   the shortest distance to 'endpt'.
        if (hori > 0) {
          if (rori > 0) {
            if (lori > 0) {
              // Any of the three neighbors is a viable move.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(3); // 's' is in {0,1,2}.
                if (s == 0) {
                  nextmove = HMOVE;
                } else if (s == 1) {
                  nextmove = RMOVE;
                } else {
                  nextmove = LMOVE;
                }
              } // if (randflag)
            } else {
              // Two tets, below horizon and below right, are viable.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(2); // 's' is in {0,1}.
                if (s == 0) {
                  nextmove = HMOVE;
                } else {
                  nextmove = RMOVE;
                }
              } // if (randflag)
            }
          } else {
            if (lori > 0) {
              // Two tets, below horizon and below left, are viable.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(2); // 's' is in {0,1}.
                if (s == 0) {
                  nextmove = HMOVE;
                } else {
                  nextmove = LMOVE;
                }
              } // if (randflag)
            } else {
              // The tet below horizon is chosen.
              nextmove = HMOVE;
            }
          }
        } else {
          if (rori > 0) {
            if (lori > 0) {
              // Two tets, below right and below left, are viable.
              if (0) { // if (!randflag) {
              } else {
                // Randomly choose a direction.
                s = randomnation(2); // 's' is in {0,1}.
                if (s == 0) {
                  nextmove = RMOVE;
                } else {
                  nextmove = LMOVE;
                }
              } // if (randflag)
            } else {
              // The tet below right is chosen.
              nextmove = RMOVE;
            }
          } else {
            if (lori > 0) {
              // The tet below left is chosen.
              nextmove = LMOVE;
            } else {
              // 'endpt' lies either on the plane(s) or across face bcd.
              if (hori == 0) {
                if (rori == 0) {
                  // pa->'endpt' is COLLINEAR with pa->pb.
                  return ACROSSVERT;
                }
                if (lori == 0) {
                  // pa->'endpt' is COLLINEAR with pa->pc.
                  eprevself(*searchtet);
                  esymself(*searchtet); // [a,c,d]
                  return ACROSSVERT;
                }
                // pa->'endpt' crosses the edge pb->pc.
                return ACROSSEDGE;
              }
              if (rori == 0) {
                if (lori == 0) {
                  // pa->'endpt' is COLLINEAR with pa->pd.
                  esymself(*searchtet); // face bad.
                  enextself(*searchtet); // face [a,d,b]
                  return ACROSSVERT;
                }
                // pa->'endpt' crosses the edge pb->pd.
                esymself(*searchtet); // face bad.
                enextself(*searchtet); // face adb
                return ACROSSEDGE;
              }
              if (lori == 0) {
                // pa->'endpt' crosses the edge pc->pd.
                eprevself(*searchtet);
                esymself(*searchtet); // face acd
                return ACROSSEDGE;
              }
              // pa->'endpt' crosses the face bcd.
              return ACROSSFACE;
            }
          }
        }
    
        // Move to the next tet, fix pa as its origin.
        if (nextmove == RMOVE) {
          fnextself(*searchtet);
        } else if (nextmove == LMOVE) {
          eprevself(*searchtet);
          fnextself(*searchtet);
          enextself(*searchtet);
        } else { // HMOVE
          fsymself(*searchtet);
          enextself(*searchtet);
        }
        assert(org(*searchtet) == pa); // SELF_CHECK
        pb = dest(*searchtet);
        pc = apex(*searchtet);
    
      } // while (1)
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // scoutsegment()    Look for a given segment in the tetrahedralization T.   //
    //                                                                           //
    // Search an edge in the tetrahedralization that matches the given segmment. //
    // If such an edge exists, the segment is 'locked' at the edge. 'searchtet'  //
    // returns this (constrained) edge. Otherwise, the segment is missing.       //
    //                                                                           //
    // The returned value indicates one of the following cases:                  //
    //   - SHAREEDGE, the segment exists and is inserted in T;                   //
    //   - ACROSSEDGE, the segment intersects an edge (in 'searchtet').          //
    //   - ACROSSFACE, the segment crosses a face (in 'searchtet').              //
    //                                                                           //
    // The following cases can happen when the input PLC is not valid.           //
    //   - ACROSSVERT, the segment intersects a vertex ('refpt').                //
    //   - ACROSSSEG, the segment intersects a segment(returned by 'searchtet'). //
    //   - ACROSSSUB, the segment intersects a subface(returned by 'searchtet'). //
    //                                                                           //
    // If the returned value is ACROSSEDGE or ACROSSFACE, i.e., the segment is   //
    // missing, 'refpt' returns the reference point for splitting thus segment,  //
    // 'searchtet' returns a tet containing the 'refpt'.                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    enum tetgenmesh::interresult 
      tetgenmesh::scoutsegment(point startpt, point endpt, triface* searchtet, 
                               point* refpt, arraypool* intfacelist)
    {
      triface neightet, reftet;
      face checkseg, checksh;
      point pa, pb, pc, pd;
      badface *bface;
      enum interresult dir;
      REAL angmax, ang;
      long facecount;
      int types[2], poss[4];
      int pos, i, j;
    
      if (b->verbose > 2) {
        printf("      Scout seg (%d, %d).\n", pointmark(startpt), pointmark(endpt));
      }
    
      point2tetorg(startpt, *searchtet);
      dir = finddirection(searchtet, endpt, 0);
    
      if (dir == ACROSSVERT) {
        pd = dest(*searchtet);
        if (pd == endpt) {
          // The job is done. 
          return SHAREEDGE;
        } else {
          // A point is on the path.
          *refpt = pd;
          return ACROSSVERT;
        }
      } // if (dir == ACROSSVERT)
    
      if (b->verbose > 2) {
        printf("      Seg is missing.\n");
      }
      // dir is either ACROSSEDGE or ACROSSFACE.
    
      enextesymself(*searchtet); // Go to the opposite face.
      fsymself(*searchtet); // Enter the adjacent tet.
    
      if (dir == ACROSSEDGE) {
        // Check whether two segments are intersecting.
        tsspivot1(*searchtet, checkseg);
        if (checkseg.sh != NULL) {
          return ACROSSSEG;
        }
        across_edge_count++;
      } else if (dir == ACROSSFACE) {
        if (checksubfaceflag) {
          // Check whether a segment and a subface are intersecting.
          tspivot(*searchtet, checksh);
          if (checksh.sh != NULL) {
            return ACROSSSUB;
          }
        }
      }
    
      if (refpt == NULL) {
        return dir;
      }
    
      if (b->verbose > 2) {
        printf("      Scout a ref-point for it.\n");
      }
      facecount = across_face_count;
    
      pa = org(*searchtet);
      angmax = interiorangle(pa, startpt, endpt, NULL);
      *refpt = pa;
      pb = dest(*searchtet);
      ang = interiorangle(pb, startpt, endpt, NULL);
      if (ang > angmax) {
        angmax = ang;
        *refpt = pb;
      }
      pc = apex(*searchtet);
      ang = interiorangle(pc, startpt, endpt, NULL);
      if (ang > angmax) {
        angmax = ang;
        *refpt = pc;
      }
      reftet = *searchtet; // Save the tet containing the refpt.
    
      // Search intersecting faces along the segment.
      while (1) {
    
        if (intfacelist != NULL) {
          if (dir == ACROSSFACE) { 
            // Save the intersecting face.
            intfacelist->newindex((void **) &bface);
            bface->tt = *searchtet;
            bface->forg = org(*searchtet);
            bface->fdest = dest(*searchtet);
            bface->fapex = apex(*searchtet);
            // Save the intersection type (ACROSSFACE or ACROSSEDGE).
            bface->key = (REAL) dir;
          } else { // dir == ACROSSEDGE
            i = 0;      
            if (intfacelist->objects > 0l) {
              // Get the last saved one.
              bface = (badface *) fastlookup(intfacelist, intfacelist->objects - 1);
              if (((enum interresult) (int) bface->key) == ACROSSEDGE) {
                // Skip this edge if it is the same as the last saved one.
                if (((bface->forg == org(*searchtet)) &&
                     (bface->fdest == dest(*searchtet))) ||
                    ((bface->forg == dest(*searchtet)) &&
                     (bface->fdest == org(*searchtet)))) {
                  i = 1; // Skip this edge.
                }
              }
            }
            if (i == 0) {
              // Save this crossing edge.
              intfacelist->newindex((void **) &bface);
              bface->tt = *searchtet;
              bface->forg = org(*searchtet);
              bface->fdest = dest(*searchtet);
              // bface->fapex = apex(*searchtet);
              // Save the intersection type (ACROSSFACE or ACROSSEDGE).
              bface->key = (REAL) dir;
            }
          }
        }
    
        pd = oppo(*searchtet);
        assert(pd != dummypoint);  // SELF_CHECK
    
        if (b->verbose > 3) {
          printf("        Passing face (%d, %d, %d, %d), dir(%d).\n", 
                 pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd), 
                 (int) dir);
        }
        across_face_count++;
    
        // Stop if we meet 'endpt'.
        if (pd == endpt) break;
    
        ang = interiorangle(pd, startpt, endpt, NULL);
        if (ang > angmax) {
          angmax = ang;
          *refpt = pd;
          reftet = *searchtet;
        }
    
        // Find a face intersecting the segment.
        if (dir == ACROSSFACE) {
          // One of the three oppo faces in 'searchtet' intersects the segment.
          neightet = *searchtet;
          j = (neightet.ver & 3); // j is the current face number.
          for (i = j + 1; i < j + 4; i++) {
            neightet.ver = (i % 4);
            pa = org(neightet);
            pb = dest(neightet);
            pc = apex(neightet);
            pd = oppo(neightet); // The above point.
            if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
              dir = (enum interresult) types[0];
              pos = poss[0];
              break;
            } else {
              dir = DISJOINT;
              pos = 0;
            }
          }
          assert(dir != DISJOINT);  // SELF_CHECK
        } else { // dir == ACROSSEDGE
          // Check the two opposite faces (of the edge) in 'searchtet'.      
          for (i = 0; i < 2; i++) {
            if (i == 0) {
              enextesym(*searchtet, neightet);
            } else {
              eprevesym(*searchtet, neightet);
            }
            pa = org(neightet);
            pb = dest(neightet);
            pc = apex(neightet);
            pd = oppo(neightet); // The above point.
            if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
              dir = (enum interresult) types[0];
              pos = poss[0];
              break;
            } else {
              dir = DISJOINT;
              pos = 0;
            }
          }
          if (dir == DISJOINT) {
            // No intersection. Rotate to the next tet at the edge.
            dir = ACROSSEDGE;
            fnextself(*searchtet);
            continue;
          }
        }
    
        if (dir == ACROSSVERT) {
          // This segment passing a vertex. Choose it and return.
          for (i = 0; i < pos; i++) {
            enextself(neightet);
          }
          pd = org(neightet);
          if (b->verbose > 2) {
            angmax = interiorangle(pd, startpt, endpt, NULL);
          }
          *refpt = pd;
          // break;
          return ACROSSVERT;
        } else if (dir == ACROSSEDGE) {
          // Get the edge intersects with the segment.
          for (i = 0; i < pos; i++) {
            enextself(neightet);
          }
        }
        // Go to the next tet.
        fsym(neightet, *searchtet);
    
        if (dir == ACROSSEDGE) {
          // Check whether two segments are intersecting.
          tsspivot1(*searchtet, checkseg);
          if (checkseg.sh != NULL) {
            return ACROSSSEG;
          }
          across_edge_count++;
        } else if (dir == ACROSSFACE) {
          if (checksubfaceflag) {
            // Check whether a segment and a subface are intersecting.
            tspivot(*searchtet, checksh);
            if (checksh.sh != NULL) {
              return ACROSSSUB;
            }
          }
        }
    
      } // while (1)
    
      // A valid reference point should inside the diametrial circumsphere of
      //   the missing segment, i.e., it encroaches upon it.
      if (2.0 * angmax < PI) {
        *refpt = NULL;
      }
    
      // dir is either ACROSSVERT, or ACROSSEDGE, or ACROSSFACE.
      if (b->verbose > 2) {
        if (*refpt != NULL) {
          printf("      Refpt %d (%g), visited %ld faces.\n", pointmark(*refpt),
                 angmax / PI * 180.0, across_face_count - facecount);
        } else {
          printf("      No refpt (%g) is found, visited %ld faces.\n", 
                 angmax / PI * 180.0, across_face_count - facecount);
        }
      }
      if (across_face_count - facecount > across_max_count) {
        across_max_count = across_face_count - facecount;
      }
    
      *searchtet = reftet;
      return dir;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // getsteinerpointonsegment()    Get a Steiner point on a segment.           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
    {
      point ei, ej;
      REAL Li, Lj, L, dj, dr;
      REAL ti = 0.0, tj = 0.0, t;
      int type, eid = 0, i;
    
      REAL diff, stept = 0.0, L1;
      int iter;
    
      ei = sorg(*seg);
      ej = sdest(*seg);
    
    
      if (b->verbose > 2) {
        printf("      Get Steiner point on seg [%d (%c), %d (%c)].\n", 
               pointmark(ei), pointtype(ei) == ACUTEVERTEX ? 'A' : 'N',  
               pointmark(ej), pointtype(ej) == ACUTEVERTEX ? 'A' : 'N');
      }
    
      if (b->psc) {
        eid = shellmark(*seg);
        if (pointtype(ei) != FREESEGVERTEX) {
          ti = in->getvertexparamonedge(in->geomhandle, pointmark(ei), eid);
        } else {
          ti = pointgeomuv(ei, 0);
        }
        if (pointtype(ej) != FREESEGVERTEX) {
          tj = in->getvertexparamonedge(in->geomhandle, pointmark(ej), eid);
        } else {
          tj = pointgeomuv(ej, 0);
        }
      }
    
      if (refpt != NULL) {
        if (pointtype(ei) == ACUTEVERTEX) {
          if (pointtype(ej) == ACUTEVERTEX) {
            // Choose the vertex which is closer to refpt.
            Li = distance(ei, refpt);
            Lj = distance(ej, refpt);
            if (Li > Lj) {
              // Swap ei and ej;
              sesymself(*seg);
              ei = sorg(*seg);
              ej = sdest(*seg);
              t = ti;
              ti = tj;
              tj = t;
            }
            type = 1;
          } else {
            type = 1;
          }
        } else {
          if (pointtype(ej) == ACUTEVERTEX) {
            type = 1;
            // Swap ei and ej;
            sesymself(*seg);
            ei = sorg(*seg);
            ej = sdest(*seg);
            t = ti;
            ti = tj;
            tj = t;
          } else {
            type = 0;
          }
        }
      } else {
        type = 0;
      }
    
      if (type == 1) {
        L = distance(ei, ej);
        Li = distance(ei, refpt);
        // Cut the segment by a sphere centered at ei with radius Li.
        if (b->psc) {
          stept = (tj - ti) / 100.0;
          iter = 0;
          t = ti + (Li / L) * (tj - ti);
          while (1) {
            in->getsteineronedge(in->geomhandle, eid, t, steinpt);
            L1 = distance(steinpt, ei);
            diff = L1 - Li;
            if ((fabs(diff) / L) < 1e-3) {
              break;
            }
            if (diff > 0) {
              t -= stept; // Move it towards ei.
            } else {
              t += stept; // Move it towards ej.
            }
            iter++;
            if (iter > 10) {
              printf("Warning:  Get the right Steiner point failed.\n");
              break;
            }
          } // while (1)
        } else {
          t = Li / L;
          for (i = 0; i < 3; i++) {
            steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
          }
        }
        // Avoid creating a too short edge.
        dj = distance(steinpt, ej);
        dr = distance(steinpt, refpt);
        if (dj < dr) {
          // Cut the segment by the radius equal to Li / 2.
          if (b->psc) {
            iter = 0;
            t = ti + ((Li / 2.0) / L) * (tj - ti);
            while (1) {
              in->getsteineronedge(in->geomhandle, eid, t, steinpt);
              L1 = distance(steinpt, ei);
              diff = L1 - (Li / 2.0);
              if ((fabs(diff) / L) < 1e-3) {
                break;
              }
              if (diff > 0) {
                t -= stept; // Move it towards ei.
              } else {
                t += stept; // Move it towards ej.
              }
              iter++;
              if (iter > 10) {
                printf("Warning:  Get the right Steiner point failed.\n");
                break;
              }
            } // while (1)
          } else {
            t = (Li / 2.0) / L;
            for (i = 0; i < 3; i++) {
              steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
            }
          }
          r3count++;
        } else {
          r2count++;
        }
      } else {
        // Split the point at the middle.
        if (b->psc) {
          t = 0.5 * (ti + tj);
          in->getsteineronedge(in->geomhandle, eid, t, steinpt);
        } else {
          t = 0.5;
          for (i = 0; i < 3; i++) {
            steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
          }
        }
        r1count++;
      }
    
      if (b->psc) {
        setpointgeomuv(steinpt, 0, t);
        setpointgeomtag(steinpt, eid);
      }
    
      if (pointtype(steinpt) == UNUSEDVERTEX) {
        setpointtype(steinpt, FREESEGVERTEX);
      }
    
      if (b->verbose > 2) {
        printf("      Split at t(%g)", t);
        if (b->psc) {
          printf(", ti(%g), tj(%g)", ti, tj);
        }
        printf(".\n");
      }
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // delaunizesegments()    Recover segments in a DT.                          //
    //                                                                           //
    // All segments need to be recovered are in 'subsegstack' (Q).  They will be //
    // be recovered one by one (in a random order).                              //
    //                                                                           //
    // Given a segment s in the Q, this routine first queries s in the DT, if s  //
    // matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split  //
    // by inserting a new point p in both the DT and itself. The two new subseg- //
    // ments of s are queued in Q.  The process continues until Q is empty.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::delaunizesegments()
    {
      triface searchtet, spintet;
      face searchsh, checksh;
      face sseg, checkseg, *psseg;
      point refpt, newpt;
      enum interresult dir;
      insertvertexflags ivf;
      int loc;
    
      // For reporting PLC problems.
      point forg1, fdest1;   // The 1st segment.
      point forg2, fdest2, fapex2;   // The 2nd segment.
    
      // Does this mesh containing subfaces? 
      if (checksubfaceflag) {
        ivf.bowywat = 2;   // The mesh is a CDT. 
        ivf.lawson = 2;    // Do flip to recover Delaunayness.
        ivf.validflag = 1; // Validation is needed.
      } else {
        ivf.bowywat = 1;   // The mesh is a DT.
        ivf.lawson = 0;    // No need to do flip.
        ivf.validflag = 0; // No need to valid the B-W cavity.
      }
    
      searchsh.sh = NULL;
    
      // Loop until 'subsegstack' is empty.
      while (subsegstack->objects > 0l) {
        // seglist is used as a stack.
        subsegstack->objects--;
        psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
        sseg = *psseg;
    
        assert(!sinfected(sseg)); // FOR DEBUG
        // Check if this segment has been recovered.
        sstpivot1(sseg, searchtet);
        if (searchtet.tet != NULL) {
          // FOR DEBUG
          // Check if the tet contains the same segment.
          tsspivot1(searchtet, checkseg);
          assert(checkseg.sh == sseg.sh);
          continue; // Not a missing segment.
        }
    
        // Search the segment.
        dir = scoutsegment(sorg(sseg), sdest(sseg), &searchtet, &refpt, NULL);
    
        if (dir == SHAREEDGE) {
          // Found this segment, insert it.
          tsspivot1(searchtet, checkseg);  // SELF_CHECK
          if (checkseg.sh == NULL) {
            // Let the segment remember an adjacent tet.
            sstbond1(sseg, searchtet);
            // Bond the segment to all tets containing it.
            spintet = searchtet;
            do {
              tssbond1(spintet, sseg);
              fnextself(spintet);
            } while (spintet.tet != searchtet.tet);
          } else {
            // Collision! Should not happen.
            assert(0);
          }
        } else {
          if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
            // The segment is missing. Split it.
            // Create a new point.
            makepoint(&newpt, FREESEGVERTEX);
            //setpointtype(newpt, FREESEGVERTEX);
            getsteinerptonsegment(&sseg, refpt, newpt);
    
            // Start searching from the 'searchtet'.
            ivf.iloc = (int) OUTSIDE;
            //ivf.bowywat;
            //ivf.lawson;
            ivf.rejflag = 0;
            ivf.chkencflag = 0;
            ivf.sloc = ivf.iloc;
            ivf.sbowywat = ivf.bowywat;
            ivf.splitbdflag = 0;
            // ivf.validflag
            ivf.respectbdflag = 0;
            ivf.assignmeshsize = 0;
            // Insert the new point into the tetrahedralization T.
            //   Missing segments and subfaces are queued for recovery.
            //   Note that T is convex (nonconvex = 0).
            loc = insertvertex(newpt, &searchtet, &searchsh, &sseg, &ivf);
    
            assert(loc != (int) ONVERTEX);
            if (loc != (int) NEARVERTEX) {
              // The new point has been inserted.
              if (ivf.lawson > 0) {
                // For CDT, use flips to reocver Delaunayness.
                lawsonflip3d(newpt, ivf.lawson, 0, 0, 0);
              }
              st_segref_count++; //st_segpro_count++;
              if (steinerleft > 0) steinerleft--;
            } else {
              // The new point is either ON or VERY CLOSE to an existing point.
              refpt = point2ppt(newpt);
              printf("  !! Avoid to create a short edge (length = %g)\n",
                     distance(newpt, refpt));
    
              // It is probably an input problem. Two possible cases are:
              //   (1) An input vertex is very close an input segment; or
              //   (2) Two input segments are nearly intersect each other.
              forg1 = farsorg(sseg);
              fdest1 = farsdest(sseg);
    
              if ((pointtype(refpt) == RIDGEVERTEX) || 
    	      (pointtype(refpt) == ACUTEVERTEX) ||
                  (pointtype(refpt) == VOLVERTEX)) {
                // Case (1)
                printf("  !! Point %d is very close to segment (%d, %d).\n", 
                       pointmark(refpt), pointmark(forg1), pointmark(fdest1));
              } else if (pointtype(refpt) == FREESEGVERTEX) {
                // Case (2). Find a subsegment contain 'refpt'.
                subsegs->traversalinit();
                checkseg.sh = shellfacetraverse(subsegs);
                while (checkseg.sh != NULL) {
                  if (((point) checkseg.sh[3] == refpt) || 
                      ((point) checkseg.sh[4] == refpt)) break;
                  checkseg.sh = shellfacetraverse(subsegs);
                }
                assert(checkseg.sh != NULL);
                checkseg.shver = 0;
                forg2 = farsorg(checkseg);
                fdest2 = farsdest(checkseg);
                printf("  !! Two segments are very close to each other.\n");
                printf("  1st: (%d, %d), 2nd: (%d, %d)\n", pointmark(forg1), 
                       pointmark(fdest1), pointmark(forg2), pointmark(fdest2));
              } else {
                // Unknown case
                assert(0);
              }
              // Indicate it may be an input problem.
              printf("  Short edge length bound is: %g. Tolerance is %g.\n", 
                     b->minedgelength, b->epsilon);
              terminatetetgen(4);
            }
          } else {
            // The input PLC contains self-intersections.
            if (dir == ACROSSVERT) {
              // refpt is the vertex intersecting the segment.
              forg1 = farsorg(sseg);
              fdest1 = farsdest(sseg);
              if ((pointtype(refpt) == RIDGEVERTEX) || 
    	      (pointtype(refpt) == ACUTEVERTEX) ||
                  (pointtype(refpt) == FACETVERTEX) ||
                  (pointtype(refpt) == VOLVERTEX)) {
                printf("Point %d is on segment (%d, %d).\n", 
                       pointmark(refpt), pointmark(forg1), pointmark(fdest1));
              } else if (pointtype(refpt) == FREESEGVERTEX) {
                // Case (2). Find a subsegment contain 'refpt'.
                subsegs->traversalinit();
                checkseg.sh = shellfacetraverse(subsegs);
                while (checkseg.sh != NULL) {
                  if (((point) checkseg.sh[3] == refpt) || 
                      ((point) checkseg.sh[4] == refpt)) break;
                  checkseg.sh = shellfacetraverse(subsegs);
                }
                assert(checkseg.sh != NULL);
                checkseg.shver = 0;
                forg2 = farsorg(checkseg);
                fdest2 = farsdest(checkseg);
                printf("Two segments intersect.\n");
                printf("    1st: (%d, %d), 2nd: (%d, %d)", pointmark(forg1), 
                       pointmark(fdest1), pointmark(forg2), pointmark(fdest2));
              } else if (pointtype(refpt) == FREEFACETVERTEX) {
                assert(0); // Report this case.
              }
            } else if (dir == ACROSSSEG) {
              tsspivot1(searchtet, checkseg);
              if (!b->quiet) {
                printf("Two segments intersect.\n");
                forg1 = farsorg(sseg);
                fdest1 = farsdest(sseg);
                forg2 = farsorg(checkseg);
                fdest2 = farsdest(checkseg);
                printf("  1st: (%d, %d), 2nd: (%d, %d).\n", pointmark(forg1), 
                       pointmark(fdest1), pointmark(forg2), pointmark(fdest2));
              }
            } else if (dir == ACROSSSUB) {
              tspivot(searchtet, checksh);
              if (!b->quiet) {
                printf("A segment and a subface intersect.\n");
                forg1 = farsorg(sseg);
                fdest1 = farsdest(sseg);
                forg2 = sorg(checksh);
                fdest2 = sdest(checksh);
                fapex2 = sapex(checksh);
                printf("  Seg: (%d, %d), Sub: (%d, %d, %d).\n", 
                       pointmark(forg1), pointmark(fdest1), 
                       pointmark(forg2), pointmark(fdest2), pointmark(fapex2));
              }
            } else {
              // Unknown cases.
              assert(0);
            }
            // Indicate it is an input problem.
            terminatetetgen(3);
          }
        }
      } // while
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // scoutsubface()    Look for a given subface in the tetrahedralization T.   //
    //                                                                           //
    // 'searchsh' is searched in T. If it exists, it is 'locked' at the face in  //
    // T. 'searchtet' refers to the face. Otherwise, it is missing.              //
    //                                                                           //
    // The return value indicates one of the following cases:                    //
    //   - SHAREFACE, 'searchsh' exists and is inserted in T.                    //
    //   - COLLISIONFACE, 'searchsh' exists in T, but it conflicts with another  //
    //     subface which was inserted earlier. It is not inserted.               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    enum tetgenmesh::interresult 
      tetgenmesh::scoutsubface(face* searchsh, triface* searchtet)
    {
      triface spintet;
      face checksh;
      point pa, pb, pc;
      enum interresult dir;
    
      pa = sorg(*searchsh);
      pb = sdest(*searchsh);
    
      if (b->verbose > 2) {
        printf("      Scout subface (%d, %d, %d).\n", pointmark(pa), pointmark(pb),
               pointmark(sapex(*searchsh)));
      }
    
      // Get a tet whose origin is a.
      point2tetorg(pa, *searchtet);
      // Search the edge [a,b].
      dir = finddirection(searchtet, pb, 0);
      if (dir == ACROSSVERT) {
        // Check validity of a PLC.
        if (dest(*searchtet) != pb) {
          // A vertex lies on the search edge. Return it.
          enextself(*searchtet);
          return TOUCHEDGE;
        }
        // The edge exists. Check if the face exists.
        pc = sapex(*searchsh);
        // Searchtet holds edge [a,b]. Search a face with apex c.
        spintet = *searchtet;
        while (1) {
          if (apex(spintet) == pc) {
            // Found a face matching to 'searchsh'!
            tspivot(spintet, checksh);
            if (checksh.sh == NULL) {
              // Insert 'searchsh'.
              tsbond(spintet, *searchsh);
              fsymself(spintet);
              sesymself(*searchsh);
              tsbond(spintet, *searchsh);
              *searchtet = spintet;
              return SHAREFACE;
            } else {
              // Another subface is already inserted.
              assert(checksh.sh != searchsh->sh); // SELF_CHECK
              // This is possibly an input problem, i.e., two facets overlap.
              // Report this problem and exit.
              printf("Warning:  Found two facets nearly overlap.\n");
              terminatetetgen(5);
              // unifysubfaces(&checksh, searchsh);
              *searchtet = spintet;
              return COLLISIONFACE;
            }
          }
          fnextself(spintet);
          if (spintet.tet == searchtet->tet) break;
        }
      }
    
      // dir is either ACROSSEDGE or ACROSSFACE.
      return dir; //ACROSSTET;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // formmissingregion()    Form the missing region of a missing subface.      //
    //                                                                           //
    // 'missh' is a missing subface. From it we form a missing region R which is //
    // a collection of missing subfaces connected through adjacent edges.        //
    //                                                                           //
    // The missing region R is returned in the array 'missingshs'.  All subfaces //
    // in R are oriented as 'missh'. The array 'missingshverts' returns all ver- //
    // tices of R. All subfaces and vertices of R are marktested.                //
    //                                                                           //
    // 'adjtets' returns a list of tetrahedra adjacent to R.  They are used to   //
    // search a crossing tetrahedron of R.                                       //
    //                                                                           //
    // Many ways are possible to form the missing region.  The method used here  //
    // is to search missing edges in R. Starting from 'missh', its three edges   //
    // are checked. If one of the edges is missing, then the adjacent subface at //
    // this edge is also missing. It is added to the array. By an incrementally  //
    // broad-first searching, we can find all subfaces of R.                     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs,  
                                       arraypool* missingshbds, 
                                       arraypool* missingshverts, 
                                       arraypool* adjtets)
    {
      triface searchtet, *parytet;
      face neighsh, *parysh;
      point pa, pb, *parypt;
      enum interresult dir;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      Form missing region from subface (%d, %d, %d)\n", 
               pointmark(sorg(*missh)), pointmark(sdest(*missh)), 
               pointmark(sapex(*missh)));
      }
      smarktest(*missh);
      missingshs->newindex((void **) &parysh);
      *parysh = *missh;
    
      // Incrementally find other missing subfaces.
      for (i = 0; i < missingshs->objects; i++) {
        missh = (face *) fastlookup(missingshs, i);
        for (j = 0; j < 3; j++) {
          pa = sorg(*missh);
          pb = sdest(*missh);
          // Get a tet whose origin is a.
          point2tetorg(pa, searchtet);
          // Search the edge [a,b].
          dir = finddirection(&searchtet, pb, 0);
          if (dir != ACROSSVERT) {
            // This edge is missing. Its neighbor is a missing subface.
            spivot(*missh, neighsh);
            assert(neighsh.sh != NULL);
            if (!smarktested(neighsh)) {
              // Adjust the face orientation.
              if (sorg(neighsh) != pb) {
                sesymself(neighsh);
              }
              if (b->verbose > 3) {
                printf("      Add a missing subface (%d, %d, %d)\n", 
                       pointmark(pb), pointmark(pa), pointmark(sapex(neighsh)));
              }
              smarktest(neighsh);
              missingshs->newindex((void **) &parysh);
              *parysh = neighsh;
            }
          } else {
            if (dest(searchtet) == pb) {
              // Remember an existing edge for searching the first crossing tet.
              adjtets->newindex((void **) &parytet);
              *parytet = searchtet;
              // Found an existing edge, it must be a boundary edge of R.
              if (b->verbose > 3) {
                printf("      -- A boundary edge (%d, %d)\n", pointmark(pa), 
                       pointmark(pb));
              }
              missingshbds->newindex((void **) &parysh);
              *parysh = *missh; // It is only queued once.
            } else {
              // The input PLC has problem.
              //assert(0);
              terminatetetgen(3);
            }
          }
          // Collect the vertices of R.
          if (!pmarktested(pa)) {
            pmarktest(pa);
            missingshverts->newindex((void **) &parypt);
            *parypt = pa;
          }
          senextself(*missh);
        } // j
      } // i
    
      if (b->verbose > 2) {
        printf("      Region has: %ld subfaces, %ld vertices\n", 
               missingshs->objects, missingshverts->objects);
      }
    
      if (missingshs->objects > maxregionsize) {
        maxregionsize = missingshs->objects;
      }
    
      // Unmarktest collected missing subfaces.
      for (i = 0; i < missingshs->objects; i++) {
        missh = (face *) fastlookup(missingshs, i);
        sunmarktest(*missh);
      }
    
      // Comment: All vertices in R are pmarktested.
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // scoutcrossedge()    Search an edge that crosses the missing region.       //
    //                                                                           //
    // Assumption: All vertices of the missing region are marktested.            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets, 
                                   arraypool* missingshs)
    {
      triface *searchtet, spintet;
      face *parysh;
      face checkseg;
      point pa, pb, pc, pd, pe;
      enum interresult dir;
      REAL ori;
      int types[2], poss[4];
      int searchflag, interflag;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      Search a crossing edge.\n");
      }
      searchflag = 0;
    
      for (j = 0; j < adjtets->objects && !searchflag; j++) {
        searchtet = (triface *) fastlookup(adjtets, j);
        interflag = 0;
        // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
        spintet = *searchtet;
        while (1) {
          pd = apex(spintet);
          pe = oppo(spintet);
          // Skip a hull edge.
          if ((pd != dummypoint) && (pe != dummypoint)) {
            // Skip an edge containing a vertex of R.
            if (!pmarktested(pd) && !pmarktested(pe)) {
              // Check if [d,e] intersects R.
              for (i = 0; i < missingshs->objects && !interflag; i++) {
                parysh = (face *) fastlookup(missingshs, i);
                pa = sorg(*parysh);
                pb = sdest(*parysh);
                pc = sapex(*parysh);
                interflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
                if (interflag > 0) { 
                  if (interflag == 2) {
                    // They intersect at a single point.
                    dir = (enum interresult) types[0];
                    if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
                      //pos = poss[0];
                      // Go to the crossing edge [d,e,#,#].
                      eprev(spintet, crosstet);
                      esymself(crosstet);
                      enextself(crosstet); // [d,e,#,#].
                      // Check if it is a segment.
                      tsspivot1(crosstet, checkseg);
                      if (checkseg.sh != NULL) {
                        reportselfintersect(&checkseg, parysh);
                        terminatetetgen(3);
                      }
                      // Adjust the edge such that d lies below [a,b,c].
                      ori = orient3d(pa, pb, pc, pd);
                      assert(ori != 0);
                      if (ori < 0) {
                        esymself(crosstet);
                      }
                      if (b->verbose > 2) {
                        printf("      Found edge (%d, %d) intersect", pointmark(pd),
                               pointmark(pe));
                        printf(" face (%d, %d, %d)\n", pointmark(pa), pointmark(pb),
                               pointmark(pc));
                      }
                      // Save the corners of this subface.
                      plane_pa = pa;
                      plane_pb = pb;
                      plane_pc = pc;              
                      searchflag = 1;                  
                    } else {
                      // An improper intersection type.
                      // Maybe it is a PLC problem.
                      // At the moment, just ignore it.
                    }
                  }
                  break;
                } // if (interflag > 0)
              }
            } 
          }
          // Leave search at this bdry edge if an intersection is found.
          if (interflag > 0) break;
          // Go to the next tetrahedron.
          fnextself(spintet);
          if (spintet.tet == searchtet->tet) break; 
        } // while (1)
      } // j
    
      adjtets->restart();
      return searchflag;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // formcavity()    Form the cavity of a missing region.                      //
    //                                                                           //
    // The missing region R is formed by a set of missing subfaces 'missingshs'. //
    // In the following, we assume R is horizontal and oriented. (All subfaces   //
    // of R are oriented in the same way.)  'searchtet' is a tetrahedron [d,e,#, //
    // #] which intersects R in its interior, where the edge [d,e] intersects R, //
    // and d lies below R.                                                       //
    //                                                                           //
    // By knowing a crossing edge [d,e], all tetrahedra sharing at [d,e] must    //
    // cross R. They are added into the list 'crosstets'. From this set of tets, //
    // new crossing edges (if there exist) can be detected.  The key is how to   //
    // detect them correctly.  The approach used here is described as follows:   //
    // Suppose [d,e,a,b] is a crossing tet, where [d,e] intersects R and d lies  //
    // below R. We look at the face [d,e,a]. If the apex a is not pmarktested,   //
    // i.e., it is not a vertex of R, then either edge [e,a] or [a,d] intersects //
    // R. A simple way is to perform above/below test between [a] and R.  But it //
    // is not clear which subface of R is the best for this test. Also, this is  //
    // not safe when R is not strictly planar.  A second way is to test if [e,a] //
    // intersects one of the subfaces of R. If an intersection is found, then [e,//
    // a] is a crossing edge. Otherwise, the edge [a,d] must be a crossing edge  //
    // of R. NOTE: This statement is correct if the input PLC is correct. We can //
    // also detect the incorrectness of the input, e.g., if [a] only touches a   //
    // subface of R. The second approach is implemented here. It is slow, but is //
    // more robust.                                                              //
    //                                                                           //
    // 'crosstets' returns the set of crossing tets. Every tet in it has the     //
    // form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R.  The   //
    // set of tets form the cavity C, which is divided into two parts by R, one  //
    // at top and one at bottom. 'topfaces' and 'botfaces' return the upper and  //
    // lower boundary faces of C. 'toppoints' contains vertices of 'crosstets'   //
    // in the top part of C, and so does 'botpoints'. Both 'toppoints' and       //
    // 'botpoints' contain vertices of R.                                        //
    //                                                                           //
    // NOTE: 'toppoints' may contain points which are not vertices of any top    //
    // faces, and so may 'botpoints'. Such points may belong to other facets and //
    // need to be present after the recovery of this cavity (P1029.poly).        //
    //                                                                           //
    // A pair of boundary faces: 'firsttopface' and 'firstbotface', are saved.   //
    // They share the same edge in the boundary of the missing region.           //
    //                                                                           //
    // Important: This routine assumes all vertices of the facet containing this //
    // subface are marked, i.e., pmarktested(p) returns true.                    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
                                arraypool* crosstets, arraypool* topfaces, 
                                arraypool* botfaces, arraypool* toppoints, 
                                arraypool* botpoints)
    {
      arraypool *crossedges, *testededges;
      triface spintet, neightet, *parytet;
      face checksh, *parysh = NULL;
      face checkseg; // *paryseg;
      point pa, pd, pe, *parypt;
      enum interresult dir; 
      //REAL ori;
      //REAL elen[3];
      bool testflag, invalidflag;
      int types[2], poss[4];
      int i, j, k;
    
      // Temporarily re-use 'topfaces' for all crossing edges.
      crossedges = topfaces;
      // Temporarily re-use 'botfaces' for all tested edges.
      testededges = botfaces; // Only used by 'b->psc'.
    
      if (b->verbose > 2) {
        printf("      Form the cavity of missing region.\n"); 
      }
      missingsubfacecount += missingshs->objects;
      // Mark this edge to avoid testing it later.
      markedge(*searchtet);
      crossedges->newindex((void **) &parytet);
      *parytet = *searchtet;
    
      invalidflag = 0; 
    
      // Collect all crossing tets.  Each cross tet is saved in the standard
      //   form [d,e,#,#], where [d,e] is a corossing edge, d lies below R.
      //   NEITHER d NOR e is a vertex of R (!pmarktested). 
      // NOTE: hull tets may be collected. See fig/dump-cavity-case2a(b).lua.
      //   Make sure that neither d nor e is dummypoint.
      for (i = 0; i < crossedges->objects; i++) {
        // Get a crossing edge [d,e,#,#].
        searchtet = (triface *) fastlookup(crossedges, i);
    
        // Sort vertices into the bottom and top arrays.
        pd = org(*searchtet);
        assert(!pmarktested(pd)); // pd is not on R.
        if (!pinfected(pd)) {
          pinfect(pd);
          botpoints->newindex((void **) &parypt);
          *parypt = pd;
        }
        pe = dest(*searchtet);
        assert(!pmarktested(pe)); // pe is not on R.
        if (!pinfected(pe)) {
          pinfect(pe);
          toppoints->newindex((void **) &parypt);
          *parypt = pe;
        }
    
        // All tets sharing this edge are crossing tets.
        spintet = *searchtet;
        while (1) {
          if (!infected(spintet)) {
            if (b->verbose > 3) {
              printf("      Add a crossing tet (%d, %d, %d, %d)\n",
                     pointmark(org(spintet)), pointmark(dest(spintet)),
                     pointmark(apex(spintet)), pointmark(oppo(spintet)));
            }
            infect(spintet);
            crosstets->newindex((void **) &parytet);
            *parytet = spintet;
          }
          // Go to the next crossing tet.
          fnextself(spintet);
          if (spintet.tet == searchtet->tet) break;
        } // while (1)
    
        // Detect new crossing edges.
        spintet = *searchtet;
        while (1) {
          // spintet is [d,e,a,#], where d lies below R, and e lies above R. 
          pa = apex(spintet);
          if (pa != dummypoint) {
            if (!pmarktested(pa) || b->psc) {
    	  // There exists a crossing edge, either [e,a] or [a,d]. First check
              //   if the crossing edge has already be added. This is to check if
              //   a tetrahedron at this edge is marked.
              testflag = true;
              for (j = 0; j < 2 && testflag; j++) {
                if (j == 0) {
                  enext(spintet, neightet);
                } else {
                  eprev(spintet, neightet);
                }
                while (1) {
                  if (edgemarked(neightet)) {
                    // This crossing edge has already been tested. Skip it.
                    testflag = false;
                    break;
                  }
                  fnextself(neightet);
                  if (neightet.tet == spintet.tet) break;
                }
              } // j
              if (testflag) {
                // Test if [e,a] or [a,d] intersects R.
                // Do a brute-force search in the set of subfaces of R. Slow!
                //   Need to be improved!
                pd = org(spintet);
                pe = dest(spintet);
                for (k = 0; k < missingshs->objects; k++) {
                  parysh = (face *) fastlookup(missingshs, k);
                  plane_pa = sorg(*parysh);
                  plane_pb = sdest(*parysh);
                  plane_pc = sapex(*parysh);
                  // Test if this face intersects [e,a].
                  if (tri_edge_test(plane_pa, plane_pb, plane_pc, pe, pa, 
                                    NULL, 1, types, poss)) {
                    // Found intersection. 'a' lies below R.
                    enext(spintet, neightet);
                    dir = (enum interresult) types[0];
                    if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
                      // A valid intersection.
                    } else {
                      // A non-valid intersection. Maybe a PLC problem.
                      invalidflag = 1;
                    }
                    break;
                  }
                  // Test if this face intersects [a,d].
                  if (tri_edge_test(plane_pa, plane_pb, plane_pc, pa, pd, 
                                    NULL, 1, types, poss)) {
                    // Found intersection. 'a' lies above R.
                    eprev(spintet, neightet);
                    dir = (enum interresult) types[0];
                    if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
                      // A valid intersection.
                    } else {
                      // A non-valid intersection. Maybe a PLC problem.
                      invalidflag = 1;
                    }
                    break;
                  }
                } // k
                if (k < missingshs->objects) {
                  // Found a pair of triangle - edge interseciton.
                  if (invalidflag) {
                    if (b->verbose > 2) {
                      printf("      A non-valid subface - edge intersection\n");
                      printf("      subface: (%d, %d, %d) edge: (%d, %d)\n",
                             pointmark(plane_pa), pointmark(plane_pb), 
                             pointmark(plane_pc), pointmark(org(neightet)),
                             pointmark(dest(neightet)));
                    }
                    // It may be a PLC problem.
                    terminatetetgen(3);
                  } else if (b->psc) {
                    if (pmarktested(pa)) {
                      // The intersection is invalid.
                      if (b->verbose > 2) {
                        printf("    A non-valid subface - edge intersection\n");
                        printf("      subface: (%d, %d, %d) edge: (%d, %d)\n",
                               pointmark(plane_pa), pointmark(plane_pb), 
                               pointmark(plane_pc), pointmark(org(neightet)),
                               pointmark(dest(neightet)));
                      }
                      // Split the subface intersecting this edge.
                      recentsh = *parysh;
                      recenttet = neightet; // For point location.
                      invalidflag = 1;
                      break;
                    } // if (pmarktested(pa))
                  } // if (b->psc)
                  // Adjust the edge direction, so that its origin lies below R,
                  //   and its destination lies above R.
                  esymself(neightet);
                  // Check if this edge is a segment.
                  tsspivot1(neightet, checkseg);
                  if (checkseg.sh != NULL) {
                    // Invalid PLC!
                    reportselfintersect(&checkseg, parysh);
                    terminatetetgen(3);
                  }
                  if (b->verbose > 3) {
                    printf("      Add a crossing edge (%d, %d)\n", 
                           pointmark(org(neightet)), pointmark(dest(neightet)));
                  }
                  // Mark this edge to avoid testing it again.
                  markedge(neightet);
                  crossedges->newindex((void **) &parytet);
                  *parytet = neightet;            
                } else {
                  // No intersection is found. It may be a PLC problem.
                  //assert(b->psc);              
                  // Mark this edge to avoid testing it again.
                  //markedge(neightet);
                  //testededges->newindex((void **) &parytet);
                  //*parytet = neightet;
                  invalidflag = 1;
                  // Split the subface intersecting [d,e].
                  for (k = 0; k < missingshs->objects; k++) {
                    parysh = (face *) fastlookup(missingshs, k);
                    plane_pa = sorg(*parysh);
                    plane_pb = sdest(*parysh);
                    plane_pc = sapex(*parysh);
                    // Test if this face intersects [e,a].
                    if (tri_edge_test(plane_pa, plane_pb, plane_pc, pd, pe, 
                                      NULL, 1, types, poss)) {
                      break;
                    }
                  } // k
                  assert(k < missingshs->objects);
                  recentsh = *parysh;
                  recenttet = spintet; // For point location.
                  break; // the while (1) loop
                } // if (k == missingshs->objects)
              } // if (testflag)
    	} // if (!pmarktested(pa) || b->psc)
          }
          // Go to the next crossing tet.
          fnextself(spintet);
          if (spintet.tet == searchtet->tet) break;
        } // while (1)
    
        //if (b->psc) {
          if (invalidflag) break;
        //}
      } // i
    
      if (b->verbose > 2) {
        printf("      Formed cavity: %ld (%ld) cross tets (edges).\n", 
               crosstets->objects, crossedges->objects);
      }
      crossingtetcount += crosstets->objects;
    
      // Unmark all marked edges.
      for (i = 0; i < crossedges->objects; i++) {
        searchtet = (triface *) fastlookup(crossedges, i);
        assert(edgemarked(*searchtet)); // SELF_CHECK
        unmarkedge(*searchtet);
      }
      crossedges->restart();
    
      if (b->psc) {
        // Unmark all marked edges.
        for (i = 0; i < testededges->objects; i++) {
          searchtet = (triface *) fastlookup(testededges, i);
          assert(edgemarked(*searchtet)); // SELF_CHECK
          unmarkedge(*searchtet);
        }
        testededges->restart();
      } else { // only p->plc
        assert(testededges->objects == 0l);
      }
    
      if (invalidflag) {
        // Unmark all collected tets.
        for (i = 0; i < crosstets->objects; i++) {
          searchtet = (triface *) fastlookup(crosstets, i);
          uninfect(*searchtet);
        }
        // Unmark all collected vertices.
        for (i = 0; i < botpoints->objects; i++) {
          parypt = (point *) fastlookup(botpoints, i);
          puninfect(*parypt);
        }
        for (i = 0; i < toppoints->objects; i++) {
          parypt = (point *) fastlookup(toppoints, i);
          puninfect(*parypt);
        }
        crosstets->restart();
        botpoints->restart();
        toppoints->restart();
        return false;
      }
    
      // Find a pair of cavity boundary faces from the top and bottom sides of
      //   the facet each, and they share the same edge. Save them in the
      //   global variables: firsttopface, firstbotface. They will be used in
      //   fillcavity() for gluing top and bottom new tets.
      for (i = 0; i < crosstets->objects; i++) {
        searchtet = (triface *) fastlookup(crosstets, i);
        // Crosstet is [d,e,a,b].
        enextesym(*searchtet, spintet);
        eprevself(spintet); // spintet is [b,a,e,d]
        fsym(spintet, neightet); // neightet is [a,b,e,#]
        if (!infected(neightet)) {
          // A top face.
          firsttopface = neightet;
        } else {
          continue; // Go to the next cross tet.
        }
        eprevesym(*searchtet, spintet);
        enextself(spintet); // spintet is [a,b,d,e]
        fsym(spintet, neightet); // neightet is [b,a,d,#]
        if (!infected(neightet)) {
          // A bottom face.
          firstbotface = neightet;
        } else {
          continue;
        }
        break;
      } // i
      assert(i < crosstets->objects); // SELF_CHECK
    
      // Collect the top and bottom faces and the middle vertices. Since all top
      //   and bottom vertices have been infected. Uninfected vertices must be
      //   middle vertices (i.e., the vertices of R).
      // NOTE 1: Hull tets may be collected. Process them as a normal one.
      // NOTE 2: Some previously recovered subfaces may be completely inside the
      //   cavity. In such case, we remove these subfaces from the cavity and put     //   them into 'subfacstack'. They will be recovered later.
      // NOTE 3: Some segments may be completely inside the cavity, e.g., they
      //   attached to a subface which is inside the cavity. Such segments are
      //   put in 'subsegstack'. They will be recovered later. 
      // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
      //   are identified in the routine "carvecavity()". 
    
      for (i = 0; i < crosstets->objects; i++) {
        searchtet = (triface *) fastlookup(crosstets, i);
        // searchtet is [d,e,a,b].
        enextesym(*searchtet, spintet);
        eprevself(spintet); // spintet is [b,a,e,d]
        fsym(spintet, neightet); // neightet is [a,b,e,#]
        if (!infected(neightet)) {
          // A top face.
          topfaces->newindex((void **) &parytet);
          *parytet = neightet;
        } 
        eprevesym(*searchtet, spintet);
        enextself(spintet); // spintet is [a,b,d,e]
        fsym(spintet, neightet); // neightet is [b,a,d,#]
        if (!infected(neightet)) {
          // A bottom face.
          botfaces->newindex((void **) &parytet);
          *parytet = neightet;
        }
        // Add middle vertices if there are (skip dummypoint).
        pa = org(neightet);
        if (!pinfected(pa)) {
          if (pa != dummypoint) {
            pinfect(pa);
            botpoints->newindex((void **) &parypt);
            *parypt = pa;
            toppoints->newindex((void **) &parypt);
            *parypt = pa;
          }
        }
        pa = dest(neightet);
        if (!pinfected(pa)) {
          if (pa != dummypoint) {
            pinfect(pa);
            botpoints->newindex((void **) &parypt);
            *parypt = pa;
            toppoints->newindex((void **) &parypt);
            *parypt = pa;
          }
        }
      } // i
    
      // Uninfect all collected top, bottom, and middle vertices.
      for (i = 0; i < toppoints->objects; i++) {
        parypt = (point *) fastlookup(toppoints, i);
        puninfect(*parypt);
      }
      for (i = 0; i < botpoints->objects; i++) {
        parypt = (point *) fastlookup(botpoints, i);
        puninfect(*parypt);
      }
      cavitycount++;
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // delaunizecavity()    Fill a cavity by Delaunay tetrahedra.                //
    //                                                                           //
    // The cavity C to be tetrahedralized is the top or bottom part of a whole   //
    // cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
    // faces' do not form a closed polyhedron.  The "open" side are subfaces of  //
    // the missing facet. These faces will be recovered later in fillcavity().   //
    //                                                                           //
    // This routine first constructs the DT of the vertices. Then it identifies  //
    // the half boundary faces of the cavity in DT. Possiblely the cavity C will //
    // be enlarged.                                                              //
    //                                                                           //
    // The DT is returned in 'newtets'.                                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces, 
                                     arraypool *cavshells, arraypool *newtets, 
                                     arraypool *crosstets, arraypool *misfaces)
    {
      triface searchtet, neightet, spintet, *parytet, *parytet1;
      face checksh, tmpsh, *parysh;
      face checkseg;
      point pa, pb, pc, pd, pt[3], *parypt;
      enum interresult dir;
      insertvertexflags ivf;
      REAL ori; //, ang, len;
      long baknum, bakhullsize;
      int bakchecksubsegflag, bakchecksubfaceflag;
      //int iloc;
      int i, j;
    
    
      if (b->verbose > 2) {
        printf("      Delaunizing cavity: %ld points, %ld faces.\n", 
               cavpoints->objects, cavfaces->objects);
      }
      // Remember the current number of crossing tets. It may be enlarged later.
      baknum = crosstets->objects;
      bakhullsize = hullsize;
      bakchecksubsegflag = checksubsegflag;
      bakchecksubfaceflag = checksubfaceflag;
      hullsize = 0l;
      checksubsegflag = 0;
      checksubfaceflag = 0;
      b->verbose--;  // Suppress informations for creating Delaunay tetra.
      b->plc = 0; // Do not do unifypoint();
    
      // Get four non-coplanar points (no dummypoint).
      parytet = (triface *) fastlookup(cavfaces, 0);
      pa = org(*parytet);
      pb = dest(*parytet);
      pc = apex(*parytet);
      pd = NULL;
      for (i = 1; i < cavfaces->objects; i++) {
        parytet = (triface *) fastlookup(cavfaces, i);
        pt[0] = org(*parytet);
        pt[1] = dest(*parytet);
        pt[2] = apex(*parytet);
        for (j = 0; j < 3; j++) {
          if (pt[j] != dummypoint) { // Do not include a hull point.
            // if (!pinfected(pt[j])) {
              ori = orient3d(pa, pb, pc, pt[j]);
              if (ori != 0) {
                pd = pt[j];
                if (ori > 0) {  // Swap pa and pb.
                  pt[j] = pa; pa = pb; pb = pt[j]; 
                }
                break;
              }
    	// }
          }
        }
        if (pd != NULL) break;
      }
      assert(i < cavfaces->objects); // SELF_CHECK
    
      // Create an init DT.
      initialdelaunay(pa, pb, pc, pd);
    
      // Incrementally insert the vertices (duplicated vertices are ignored).
      for (i = 0; i < cavpoints->objects; i++) {
        pt[0] = * (point *) fastlookup(cavpoints, i);
        assert(pt[0] != dummypoint); // SELF_CHECK
        searchtet = recenttet;
        ivf.iloc = (int) OUTSIDE;
        ivf.bowywat = 1;
        insertvertex(pt[0], &searchtet, NULL, NULL, &ivf);
      }
    
      if (b->verbose > 2) {
        printf("      Identfying %ld boundary faces of the cavity.\n", 
               cavfaces->objects);
      }
    
      while (1) {
    
        // Identify boundary faces. Mark interior tets. Save missing faces.
        for (i = 0; i < cavfaces->objects; i++) {
          parytet = (triface *) fastlookup(cavfaces, i);
          // Skip an interior face (due to the enlargement of the cavity).
          if (infected(*parytet)) continue;
          // This face may contain dummypoint (See fig/dum-cavity-case2).
          //   If so, dummypoint must be its apex.
          j = (parytet->ver & 3); // j is the face number.
          parytet->ver = epivot[j]; // [4,5,2,11]
          pt[0] = org(*parytet);
          pt[1] = dest(*parytet);
          pt[2] = apex(*parytet);
          // Create a temp subface.
          makeshellface(subfaces, &tmpsh);
          setshvertices(tmpsh, pt[0], pt[1], pt[2]);
          // Insert tmpsh in DT.
          searchtet.tet = NULL; 
          dir = scoutsubface(&tmpsh, &searchtet);
          if (dir == SHAREFACE) {
            // Inserted. Make sure that tmpsh connects an interior tet of C.
            stpivot(tmpsh, neightet);
            // neightet and tmpsh refer to the same edge [pt[0], pt[1]].
            //   If the origin of neightet is pt[1], it is inside.
            if (org(neightet) != pt[1]) {
              fsymself(neightet);
              assert(org(neightet) == pt[1]); // SELF_CHECK
              // Make sure that tmpsh is connected with an interior tet.
              sesymself(tmpsh);
              tsbond(neightet, tmpsh);
            }
            assert(dest(neightet) == pt[0]); // SELF_CHECK
          } else if (dir == COLLISIONFACE) {
            // This case is not possible anymore. 2010-02-01
            assert(0);
          } else {
            if (b->verbose > 2) {
              printf("        bdry face (%d, %d, %d) -- %d is missing\n",
                     pointmark(pt[0]), pointmark(pt[1]), pointmark(pt[2]), i);
            }
            shellfacedealloc(subfaces, tmpsh.sh);
            // Save this face in list.
            misfaces->newindex((void **) &parytet1);
            *parytet1 = *parytet;
            continue;
          }
          // Remember the boundary tet (outside the cavity) in tmpsh 
          //   (use the adjacent tet slot). 
          tmpsh.sh[0] = (shellface) encode(*parytet);
          // Save this subface.
          cavshells->newindex((void **) &parysh);
          *parysh = tmpsh;
        } // i
    
        if (misfaces->objects > 0) {
          if (b->verbose > 2) {
            printf("      Enlarging the cavity. %ld missing bdry faces\n", 
                   misfaces->objects);
          }
    
          // Removing all tempoaray subfaces.
          for (i = 0; i < cavshells->objects; i++) {
            parysh = (face *) fastlookup(cavshells, i);
            stpivot(*parysh, neightet);
            tsdissolve(neightet); // Detach it from adj. tets.
            fsymself(neightet);
            tsdissolve(neightet);
            shellfacedealloc(subfaces, parysh->sh);
          }
          cavshells->restart();
    
          // Infect the points which are of the cavity.
          for (i = 0; i < cavpoints->objects; i++) {
            pt[0] = * (point *) fastlookup(cavpoints, i);
            pinfect(pt[0]); // Mark it as inserted.
          }
    
          // Enlarge the cavity.
          for (i = 0; i < misfaces->objects; i++) {
            // Get a missing face.
            parytet = (triface *) fastlookup(misfaces, i);
            if (!infected(*parytet)) {
              // Put it into crossing tet list.
              infect(*parytet);
              crosstets->newindex((void **) &parytet1);
              *parytet1 = *parytet;
              // Insert the opposite point if it is not in DT.
              pd = oppo(*parytet);
              if (!pinfected(pd)) {
                searchtet = recenttet;
                ivf.iloc = (int) OUTSIDE;
                ivf.bowywat = 1;
                insertvertex(pd, &searchtet, NULL, NULL, &ivf);
                if (b->verbose > 2) {
                  printf("      Add point %d into list.\n", pointmark(pd));
                }
                pinfect(pd);
                cavpoints->newindex((void **) &parypt);
                *parypt = pd;
              }
              // Add three opposite faces into the boundary list.
              for (j = 0; j < 3; j++) {
                esym(*parytet, neightet);
                fsymself(neightet);
                if (!infected(neightet)) {
                  if (b->verbose > 2) {
                    printf("      Add a cavface (%d, %d, %d).\n",
                           pointmark(org(neightet)), pointmark(dest(neightet)),
                           pointmark(apex(neightet)));
                  }
                  cavfaces->newindex((void **) &parytet1);
                  *parytet1 = neightet;
                } else {
                }
                enextself(*parytet);
              } // j
            } // if (!infected(parytet))
          } // i
    
          // Uninfect the points which are of the cavity.
          for (i = 0; i < cavpoints->objects; i++) {
            pt[0] = * (point *) fastlookup(cavpoints, i);
            puninfect(pt[0]);
          }
    
          misfaces->restart();
          continue;
        } // if (misfaces->objects > 0)
    
        break;
    
      } // while (1)
    
      // Collect all tets of the DT. All new tets are marktested.
      marktest(recenttet);
      newtets->newindex((void **) &parytet);
      *parytet = recenttet;
      for (i = 0; i < newtets->objects; i++) {
        searchtet = * (triface *) fastlookup(newtets, i);
        for (searchtet.ver = 0; searchtet.ver < 4; searchtet.ver++) {
          fsym(searchtet, neightet);
          if (!marktested(neightet)) {
            marktest(neightet);
            newtets->newindex((void **) &parytet);
            *parytet = neightet;
          }
        }
      }
    
      cavpoints->restart();
      cavfaces->restart();
    
      if (cavshells->objects > maxcavsize) {
        maxcavsize = cavshells->objects;
      }
      if (crosstets->objects > baknum) {
        // The cavity has been enlarged.
        cavityexpcount++;
      }
    
      // Restore the original values.
      hullsize = bakhullsize;
      checksubsegflag = bakchecksubsegflag;
      checksubfaceflag = bakchecksubfaceflag;
      b->verbose++;
      b->plc = 1;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // fillcavity()    Fill new tets into the cavity.                            //
    //                                                                           //
    // The new tets are stored in two disjoint sets(which share the same facet). //
    // 'topfaces' and 'botfaces' are the boundaries of these two sets, respect-  //
    // ively. 'midfaces' is empty on input, and will store faces in the facet.   //
    //                                                                           //
    // Important: This routine assumes all vertices of the missing region R are  //
    // marktested, i.e., pmarktested(p) returns true.                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
                                arraypool* midfaces, arraypool* missingshs)
    {
      arraypool *cavshells;
      triface *parytet, bdrytet, toptet, bottet, midface;
      triface neightet, spintet;
      face checksh, *parysh;
      face checkseg;
      point pa, pb, pc, pf, pg; //, *pts;
      int types[2], poss[4];
      //REAL elen[3]; //ori, len, n[3];
      bool mflag, bflag;
      int i, j, k;
    
      // Connect newtets to tets outside the cavity.  These connections are needed
      //   for identifying the middle faces (which belong to R).
      for (k = 0; k < 2; k++) {
        cavshells = (k == 0 ? topshells : botshells);
        if (cavshells != NULL) {
          for (i = 0; i < cavshells->objects; i++) {
            // Get a temp subface.
            parysh = (face *) fastlookup(cavshells, i);
            // Get the boundary tet outside the cavity.
            decode(parysh->sh[0], bdrytet);
            pa = org(bdrytet);
            pb = dest(bdrytet);
            pc = apex(bdrytet);
            // Get the adjacent new tet.
            stpivot(*parysh, neightet);
            assert(org(neightet) == pb); // SELF_CHECK
            assert(dest(neightet) == pa); // SELF_CHECK
            // Mark neightet as an interior tet of this cavity, 2009-04-24.
            // Comment: We know neightet is an interior tet.
            if (!infected(neightet)) {
              infect(neightet);
            }
            assert(oppo(bdrytet) != NULL); // No faked tet.
            // if (oppo(bdrytet) != NULL) {
              // Bond the two tets.
              bond(bdrytet, neightet); // Also cleared the pointer to tmpsh.
    	// }
            tsdissolve(neightet); // Clear the pointer to tmpsh.
            // Update the point-to-tets map.
            setpoint2tet(pa, encode(neightet));
            setpoint2tet(pb, encode(neightet));
            setpoint2tet(pc, encode(neightet));
            // Delete the temp subface.
            // shellfacedealloc(subfacepool, parysh->sh);
          } // i
        } // if (cavshells != NULL)
      } // k
    
      mflag = true;  // Initialize it.
    
      if (midfaces != NULL) {
    
        // The first pair of top and bottom tets share the same edge [a, b].
        // toptet = * (triface *) fastlookup(topfaces, 0);
        if (infected(firsttopface)) {
          // This is due to he enlargement of the cavity. Find the updated top
          //   boundary face at edge [a,b].
          // Comment: An uninfected tet at [a,b] should be found since [a,b] is a
          //   boundary edge of the missing region R. It should not be enclosed
          //   by the enlarged cavity.
          pa = apex(firsttopface); // SELF_CHECK
          while (1) {
            fnextself(firsttopface);
            if (!infected(firsttopface)) break;
            assert(apex(firsttopface) != pa); // SELF_CHECK
          }
        }
        toptet = firsttopface;
        pa = apex(toptet);
        fsymself(toptet);
        // Search a subface from the top mesh.
        while (1) {
          esymself(toptet); // The next face in the same tet.
          pc = apex(toptet);
          assert(pc != pa);  // We should not return to the starting point.
          if (pmarktested(pc)) break; // [a,b,c] is a subface.
          fsymself(toptet); // Go to the adjacent tet.
        }
        // Search the subface [a,b,c] in the bottom mesh.
        // bottet = * (triface *) fastlookup(botfaces, 0);
        if (infected(firstbotface)) {
          pa = apex(firstbotface); // SELF_CHECK
          while (1) {
            fnextself(firstbotface);
            if (!infected(firstbotface)) break;
            assert(apex(firstbotface) != pa); // SELF_CHECK
          }
        }
        bottet = firstbotface;
        pa = apex(bottet);
        fsymself(bottet);
        while (1) {
          esymself(bottet); // The next face in the same tet.
          pf = apex(bottet);
          assert(pf != pa); // We should not return to the starting point.
          if (pf == pc) break; // Face matched.
          if (pmarktested(pf)) {
            mflag = false; break; // Not matched.
          }
          fsymself(bottet);
        }
        if (mflag) {
          // Connect the two tets together.
          bond(toptet, bottet);
          // Both are interior tets.
          infect(toptet);
          infect(bottet);
          // Add this face into search list.
          markface(toptet);
          midfaces->newindex((void **) &parytet);
          *parytet = toptet;
        }
    
        // Match pairs of subfaces (middle faces), connect top and bottom tets.
        for (i = 0; i < midfaces->objects && mflag; i++) {
          // Get a matched middle face [a, b, c]
          midface = * (triface *) fastlookup(midfaces, i);
          // The tet must be a new created tet (marktested).
          assert(marktested(midface)); // SELF_CHECK
    
          // Check the neighbors at edges [b, c] and [c, a].
          for (j = 0; j < 2 && mflag; j++) {
            enextself(midface); // [b, c] or [c, a].
            pg = apex(midface);
            toptet = midface;
            bflag = false;
            while (1) {
              // Go to the next face in the same tet.
              esymself(toptet);
              pc = apex(toptet);
              if (pmarktested(pc)) {
                break; // Find a subface.
              }
              if (pc == dummypoint) {
                break; // Find a subface.
              }
              // Go to the adjacent tet.
              fsymself(toptet);
              // Do we walk outside the cavity? 
              if (!marktested(toptet)) {
                // Yes, the adjacent face is not a middle face.
                bflag = true; break; 
              }
            }
            if (!bflag) {
              // assert(marktested(toptet)); // SELF_CHECK
              if (!facemarked(toptet)) {
                fsym(midface, bottet);
                while (1) {
                  esymself(bottet);
                  pf = apex(bottet);
                  if (pf == pc) break; // Face matched.
                  if (pmarktested(pf)) {
                    mflag = false; break; // Not matched
                  }
                  fsymself(bottet);
                }
                if (mflag) {
                  if (marktested(bottet)) {
                    // Connect two tets together.
                    bond(toptet, bottet);
                    // Both are interior tets.
                    infect(toptet);
                    infect(bottet);
                    // Add this face into list.
                    markface(toptet);
                    midfaces->newindex((void **) &parytet);
                    *parytet = toptet;
                  } else {
                    // The 'bottet' is not inside the cavity! 
                    // This case can happen when the cavity was enlarged, and the
                    //   'toptet' is a co-facet (sub)face adjacent to the missing
                    //   region, and it is a boundary face of the top cavity.
                    // So the toptet and bottet should be bonded already through
                    //   a temp subface. See fig/dump-cavity-case18. Check it.
                    fsym(toptet, neightet);
                    assert(neightet.tet == bottet.tet); // SELF_CHECK
                    assert(neightet.ver == bottet.ver); // SELF_CHECK
                    // Do not add this face into 'midfaces'.
                  }
                }
              } // if (!facemarked(toptet))
            }
          } // j
        } // i
    
      } // if (midfaces != NULL)
    
      if (mflag) {
        if (midfaces != NULL) {
          if (b->verbose > 2) {
            printf("      Found %ld middle subfaces.\n", midfaces->objects);
          }
          if (midfaces->objects > maxregionsize) {
            maxregionsize = midfaces->objects;
          }
          // Unmark middle faces.
          for (i = 0; i < midfaces->objects; i++) {
            // Get a matched middle face [a, b, c]
            midface = * (triface *) fastlookup(midfaces, i);
            assert(facemarked(midface)); // SELF_CHECK
            unmarkface(midface);
          }
        }
      } else {
        // Faces at top and bottom are not matched. There exists non-Delaunay
        //   subedges. See fig/dump-cavity-case5.lua. 
        pa = org(toptet);
        pb = dest(toptet);
        pc = apex(toptet);
        pf = apex(bottet);
    
        pf = oppo(toptet);
        pg = oppo(bottet);
        // Find a subface in R which intersects the edge [f,g].
        for (i = 0; i < missingshs->objects; i++) {
          parysh = (face *) fastlookup(missingshs, i);
          pa = sorg(*parysh);
          pb = sdest(*parysh);
          pc = sapex(*parysh);
          if (tri_edge_test(pa, pb, pc, pf, pg, NULL, 1, types, poss)) {
            // Found a subface.
            break;
          }
        }
    
        if (i < missingshs->objects) { 
          // Such subface exist.
          recentsh = *parysh;
        } else {
          assert(0); // Debug this case.
        }
    
    
        // Set a tet for searching the new point.
        recenttet = firsttopface;
      }
    
      // Delete the temp subfaces.
      for (k = 0; k < 2; k++) {
        cavshells = (k == 0 ? topshells : botshells);
        if (cavshells != NULL) {
          for (i = 0; i < cavshells->objects; i++) {
            parysh = (face *) fastlookup(cavshells, i);
            shellfacedealloc(subfaces, parysh->sh);
          }
        }
      }
    
      topshells->restart();
      if (botshells != NULL) {
        botshells->restart();
      }
      if (midfaces != NULL) {
        midfaces->restart();
      }
    
      return mflag;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // carvecavity()    Delete old tets and outer new tets of the cavity.        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
                                 arraypool *botnewtets)
    {
      arraypool *newtets;
      triface *parytet, *pnewtet, newtet, neightet, spintet;
      face checksh, *parysh;
      face checkseg, *paryseg;
      int i, j, k;
    
      if (b->verbose > 2) {
        printf("      Carve cavity: %ld old tets.\n", crosstets->objects);
      }
    
      // First process subfaces and segments which are adjacent to the cavity.
      //   They must be re-connected to new tets in the cavity.
      // Comment: It is possible that some subfaces and segments are completely
      //   inside the cavity. This can happen even if the cavity is not enlarged. 
      //   Before deleting the old tets, find and queue all interior subfaces
      //   and segments. They will be recovered later. 2010-05-06.
    
      // Collect all subfaces and segments which attached to the old tets.
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        assert(infected(*parytet)); // SELF_CHECK
        for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
          tspivot(*parytet, checksh);
          if (checksh.sh != NULL) {
            if (!sinfected(checksh)) {
              sinfect(checksh);
              cavetetshlist->newindex((void **) &parysh);
              *parysh = checksh;
            }
          }
        }
        for (j = 0; j < 6; j++) {
          parytet->ver = edge2ver[j];
          tsspivot1(*parytet, checkseg);
          if (checkseg.sh != NULL) {
            if (!sinfected(checkseg)) {
              sinfect(checkseg);
              cavetetseglist->newindex((void **) &paryseg);
              *paryseg = checkseg;
            }
          }
        }
      } // i
      // Uninfect collected subfaces.
      for (i = 0; i < cavetetshlist->objects; i++) {
        checksh = * (face *) fastlookup(cavetetshlist, i);
        suninfect(checksh);
      }
      // Uninfect collected segments.
      for (i = 0; i < cavetetseglist->objects; i++) {
        checkseg = * (face *) fastlookup(cavetetseglist, i);
        suninfect(checkseg);
      }
    
      // Connect subfaces to new tets.
      for (i = 0; i < cavetetshlist->objects; i++) {
        parysh = (face *) fastlookup(cavetetshlist, i);
        // Get an adjacent tet at this subface.
        stpivot(*parysh, neightet);
        // Does this tet lie inside the cavity.
        if (infected(neightet)) {
          // Yes. Get the other adjacent tet at this subface.
          sesymself(*parysh);
          stpivot(*parysh, neightet);
          // Does this tet lie inside the cavity.
          if (infected(neightet)) {
            checksh = *parysh;
            if (b->verbose > 2) {
              printf("      Found an interior subface (%d, %d, %d)\n", 
                     pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                     pointmark(sapex(checksh)));
            }
            stdissolve(checksh);
            caveencshlist->newindex((void **) &parysh);
            *parysh = checksh;
          }
        }
        if (!infected(neightet)) {
          // Found an outside tet. Re-connect this subface to a new tet.
          fsym(neightet, newtet);
          assert(marktested(newtet)); // It's a new tet.
          sesymself(*parysh);
          tsbond(newtet, *parysh);
        }
      } // i
      if (b->verbose > 2) {
        printf("      %ld (%ld) cavity (interior) subfaces.\n", 
               cavetetshlist->objects, caveencshlist->objects);
      }
    
      for (i = 0; i < cavetetseglist->objects; i++) {
        checkseg = * (face *) fastlookup(cavetetseglist, i);
        // Check if the segment is inside the cavity.
        sstpivot1(checkseg, neightet);
        spintet = neightet;
        while (1) {
          if (!infected(spintet)) {
            // This segment is on the boundary of the cavity.
            break;
          }
          fnextself(spintet);
          if (spintet.tet == neightet.tet) {
            if (b->verbose > 2) {
              printf("      Found an interior seg (%d, %d)\n", 
    	         pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
            }
            sstdissolve1(checkseg);
            caveencseglist->newindex((void **) &paryseg);
            *paryseg = checkseg;
            break;
          }
        }
        if (!infected(spintet)) {
          // A boundary segment. Connect this segment to the new tets.
          sstbond1(checkseg, spintet);
          neightet = spintet;
          while (1) {
            tssbond1(spintet, checkseg);
            fnextself(spintet);
            if (spintet.tet == neightet.tet) break;
          }
        }
      } // i
      if (b->verbose > 2) {
        printf("      %ld (%ld) cavity (interior) segments.\n", 
               cavetetseglist->objects, caveencseglist->objects);
      }
    
      cavetetshlist->restart();
      cavetetseglist->restart();
    
      // Delete the old tets in cavity.
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        tetrahedrondealloc(parytet->tet);
      }
    
      crosstets->restart(); // crosstets will be re-used.
    
      // Collect new tets in cavity.  Some new tets have already been found 
      //   (and infected) in the fillcavity(). We first collect them.
      for (k = 0; k < 2; k++) {
        newtets = (k == 0 ? topnewtets : botnewtets);
        if (newtets != NULL) {
          for (i = 0; i < newtets->objects; i++) {
            parytet = (triface *) fastlookup(newtets, i);
            if (infected(*parytet)) {
              crosstets->newindex((void **) &pnewtet);
              *pnewtet = *parytet;
            }
          } // i
        }
      } // k
    
      // Now we collect all new tets in cavity.
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        if (i == 0) {
          recenttet = *parytet; // Remember a live handle.
        }
        for (j = 0; j < 4; j++) {
          decode(parytet->tet[j], neightet);
          if (marktested(neightet)) { // Is it a new tet?
            if (!infected(neightet)) {
              // Find an interior tet.
              assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
              infect(neightet);
              crosstets->newindex((void **) &pnewtet);
              *pnewtet = neightet;
            }
          }
        } // j
      } // i
    
      // Delete outer new tets.
      for (k = 0; k < 2; k++) {
        newtets = (k == 0 ? topnewtets : botnewtets);
        if (newtets != NULL) {
          for (i = 0; i < newtets->objects; i++) {
            parytet = (triface *) fastlookup(newtets, i);
            if (infected(*parytet)) {
              // This is an interior tet.
              uninfect(*parytet);
              unmarktest(*parytet);
            } else {
              // An outer tet. Delete it.
              tetrahedrondealloc(parytet->tet);
            }
          }
        }
      }
    
      crosstets->restart();
      topnewtets->restart();
      if (botnewtets != NULL) {
        botnewtets->restart();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // restorecavity()    Reconnect old tets and delete new tets of the cavity.  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
                                   arraypool *botnewtets)
    {
      triface *parytet, neightet;
      face checksh;
      face checkseg;
      point *ppt;
      int i, j;
    
      // Reconnect crossing tets to cavity boundary.
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        assert(infected(*parytet)); // SELF_CHECK
        if (i == 0) {
          recenttet = *parytet; // Remember a live handle.
        }
        parytet->ver = 0;
        for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
          fsym(*parytet, neightet);
          if (!infected(neightet)) {
            // Restore the old connections of tets.
            bond(*parytet, neightet);
          }
        }
        // Update the point-to-tet map.
        parytet->ver = 0;
        ppt = (point *) &(parytet->tet[4]);
        for (j = 0; j < 4; j++) {
          setpoint2tet(ppt[j], encode(*parytet));
        }
      }
    
      // Uninfect all crossing tets.
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        uninfect(*parytet);
      }
    
      // Delete new tets.
      for (i = 0; i < topnewtets->objects; i++) {
        parytet = (triface *) fastlookup(topnewtets, i);
        tetrahedrondealloc(parytet->tet);
      }
    
      if (botnewtets != NULL) {
        for (i = 0; i < botnewtets->objects; i++) {
          parytet = (triface *) fastlookup(botnewtets, i);
          tetrahedrondealloc(parytet->tet);
        }
      }
    
      crosstets->restart();
      topnewtets->restart();
      if (botnewtets != NULL) {
        botnewtets->restart();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flipcertify()    Insert a crossing face into priority queue.              //
    //                                                                           //
    // A crossing face of a facet must have at least one top and one bottom ver- //
    // tex of the facet.                                                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flipcertify(triface *chkface, badface **pqueue)
    {
      badface *parybf, *prevbf, *nextbf;
      triface neightet;
      face checksh;
      point p[5];
      REAL w[5];
      REAL insph, ori4;
      int topi, boti;
      int i;
    
      // Compute the flip time \tau.
      fsym(*chkface, neightet);
    
      p[0] = org(*chkface);
      p[1] = dest(*chkface);
      p[2] = apex(*chkface);
      p[3] = oppo(*chkface);
      p[4] = oppo(neightet);
    
      // Check if the face is a crossing face.
      topi = boti = 0;
      for (i = 0; i < 3; i++) {
        if (pmarktest2ed(p[i])) topi++;
        if (pmarktest3ed(p[i])) boti++;
      }
      if ((topi == 0) || (boti == 0)) {
        // It is not a crossing face.
        // return;
        for (i = 3; i < 5; i++) {
          if (pmarktest2ed(p[i])) topi++;
          if (pmarktest3ed(p[i])) boti++;
        }
        if ((topi == 0) || (boti == 0)) {
          // The two tets sharing at this face are on one side of the facet.
          // Check if this face is locally Delaunay (due to rounding error).
          if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
            // Do not check it if it is a subface.
            tspivot(*chkface, checksh);
            if (checksh.sh == NULL) {
              insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
              assert(insph != 0);
              if (insph > 0) {
                // Add the face into queue.
                if (b->verbose > 2) {
                  printf("      A locally non-Delanay face (%d, %d, %d)-%d,%d\n", 
                         pointmark(p[0]), pointmark(p[1]), pointmark(p[2]), 
                         pointmark(p[3]), pointmark(p[4]));
                }
                parybf = (badface *) flippool->alloc();
                parybf->key = 0.;  // tau = 0, do immediately.
                parybf->tt = *chkface;
                parybf->forg = p[0];
                parybf->fdest = p[1];
                parybf->fapex = p[2];
                parybf->foppo = p[3];
                parybf->noppo = p[4];
                // Add it at the top of the priority queue.
                if (*pqueue == NULL) {
                  *pqueue = parybf;
                  parybf->nextitem = NULL;
                } else {
                  parybf->nextitem = *pqueue;
                  *pqueue = parybf;
                }
              } // if (insph > 0)
            } // if (checksh.sh == NULL)
          }
          //return;
        }
        return; // Test: omit this face.
      }
    
      // Decide the "height" for each point.
      for (i = 0; i < 5; i++) {
        if (pmarktest2ed(p[i])) {
          // A top point has a positive weight.
          w[i] = orient3d(plane_pa, plane_pb, plane_pc, p[i]);      
          if (w[i] < 0) w[i] = -w[i];
          assert(w[i] != 0);
        } else {
          w[i] = 0;
        }
      }
    
      // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
      //   Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
      //     p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
      //   The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
      //     p[4] lies below the oriented hyperplane passing through 
      //     p[1], p[0], p[2], p[3].
    
      insph = insphere(p[1], p[0], p[2], p[3], p[4]);
    
      if (b->flipinsert_ori4dexact) {
        ori4 = orient4dexact(p[1], p[0], p[2], p[3], p[4],w[1],w[0],w[2],w[3],w[4]);
      } else {
        ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
      }
    
      if (b->verbose > 2) {
        printf("      Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]);
        printf("      Insph: %g, ori4: %g, tau = %g\n", insph, ori4, -insph/ori4);
      }
    
      if (ori4 > 0) {
        // Add the face into queue.
        if (b->verbose > 2) {
          printf("      Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
            pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
        }
        
        parybf = (badface *) flippool->alloc();
    
        parybf->key = -insph / ori4;
        parybf->tt = *chkface;
        parybf->forg = p[0];
        parybf->fdest = p[1];
        parybf->fapex = p[2];
        parybf->foppo = p[3];
        parybf->noppo = p[4];
    
        // Push the face into priority queue.
        //pq.push(bface);
        if (*pqueue == NULL) {
          *pqueue = parybf;
          parybf->nextitem = NULL;
        } else {
          // Search an item whose key is larger or equal to current key.
          prevbf = NULL;
          nextbf = *pqueue;
          if (!b->flipinsert_random) { // Default use a priority queue.
            // Insert the item into priority queue.
            while (nextbf != NULL) {
              if (nextbf->key < parybf->key) {
                prevbf = nextbf;
                nextbf = nextbf->nextitem;
              } else {
                break;
              }
            }
          } // if (!b->flipinsert_random) // -L1
          // Insert the new item between prev and next items.
          if (prevbf == NULL) {
            *pqueue = parybf;
          } else {
            prevbf->nextitem = parybf;
          }
          parybf->nextitem = nextbf;
        }
      } else if (ori4 == 0) {
        
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // flipinsertfacet()    Insert a facet into a CDT by flips.                  //
    //                                                                           //
    // The algorithm is described in Shewchuk's paper "Updating and Constructing //
    // Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
    // Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003.                     //
    //                                                                           //
    // 'crosstets' contains the set of crossing tetrahedra (infected) of the     //
    // facet.  'toppoints' and 'botpoints' are points lies above and below the   //
    // facet, not on the facet.                                                  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
                                     arraypool *botpoints, arraypool *midpoints)
    {
      arraypool *crossfaces, *bfacearray;
      triface fliptets[5], baktets[2], fliptet, newface;
      triface neightet, *parytet;
      face checksh;
      face checkseg;
      badface *pqueue;
      badface *popbf, bface;
      point p1, p2, pd, pe;
      point *parypt;
      REAL ori[3];
      int convcount, copcount;
      int flipflag, fcount;
      int n, i;
    
      long f23count, f32count, f44count;
      long totalfcount;
    
      f23count = flip23count;
      f32count = flip32count;
      f44count = flip44count;
    
      // Get three affinely independent vertices in the missing region R.
      calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
    
      // Mark top and bottom points. Do not mark midpoints.
      for (i = 0; i < toppoints->objects; i++) {
        parypt = (point *) fastlookup(toppoints, i);
        if (!pmarktested(*parypt)) {
          pmarktest2(*parypt);
        }
      }
      for (i = 0; i < botpoints->objects; i++) {
        parypt = (point *) fastlookup(botpoints, i);
        if (!pmarktested(*parypt)) {
          pmarktest3(*parypt);
        }
      }
    
      // Collect crossing faces. 
      crossfaces = cavetetlist;  // Re-use array 'cavetetlist'.
    
      // Each crossing face contains at least one bottom vertex and
      //   one top vertex.
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        fliptet = *parytet;
        for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
          fsym(fliptet, neightet);
          if (infected(neightet)) { // It is an interior face.
            if (!marktested(neightet)) { // It is an unprocessed face.
              crossfaces->newindex((void **) &parytet);
              *parytet = fliptet;
            }
          }
        }
        marktest(fliptet);
      }
    
      if (b->verbose > 1) {
        printf("    Found %ld crossing faces.\n", crossfaces->objects);
      }
      if (crossfaces->objects > maxcrossfacecount) {
        maxcrossfacecount = crossfaces->objects;
      }
    
      for (i = 0; i < crosstets->objects; i++) {
        parytet = (triface *) fastlookup(crosstets, i);
        unmarktest(*parytet);
        uninfect(*parytet);
      }
    
      // Initialize the priority queue.
      pqueue = NULL;
    
      for (i = 0; i < crossfaces->objects; i++) {
        parytet = (triface *) fastlookup(crossfaces, i);
        flipcertify(parytet, &pqueue);
      }
      crossfaces->restart();
    
      // The list for temporarily storing unflipable faces.
      bfacearray = new arraypool(sizeof(triface), 4);
    
     fliploop:
    
      fcount = 0;  // Count the number of flips.
    
      // Flip insert the facet.
      while (pqueue != NULL) {
    
        // Pop a face from the priotity queue.
        popbf = pqueue;
        bface = *popbf;
    
        // Update the queue.
        pqueue = pqueue->nextitem;
    
        // Delete the popped item from the pool.
        flippool->dealloc((void *) popbf);
    
        if (!isdeadtet(bface.tt)) {
          if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
              (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
            // It is still a crossing face of R.
            fliptet = bface.tt;
            fsym(fliptet, neightet);
            assert(!isdeadtet(neightet));
            if (oppo(neightet) == bface.noppo) {
              pd = oppo(fliptet);
              pe = oppo(neightet);
    
              if (b->verbose > 2) {
                printf("      Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
                       pointmark(bface.forg), pointmark(bface.fdest),
                       pointmark(bface.fapex), pointmark(bface.foppo),
                       pointmark(bface.noppo), bface.key);
              }
              flipflag = 0;
    
              // Check for which type of flip can we do.
              convcount = 3;
              copcount = 0;
              for (i = 0; i < 3; i++) {
                p1 = org(fliptet);
                p2 = dest(fliptet);
                ori[i] = orient3d(p1, p2, pd, pe);
                if (ori[i] < 0) {
                  convcount--;
                  //break;
                } else if (ori[i] == 0) {
                  convcount--; // Possible 4-to-4 flip.
                  copcount++;
                  //break;
                }
                enextself(fliptet);
              }
    
              if (convcount == 3) {
                // A 2-to-3 flip is found.
                // The face should not be a subface.
                tspivot(fliptet, checksh);
                assert(checksh.sh == NULL);
    
                fliptets[0] = fliptet; // abcd, d may be the new vertex.
                fliptets[1] = neightet; // bace.
                flip23(fliptets, 1, 0, 0);  
                // Put the link faces into check list.
                for (i = 0; i < 3; i++) {
                  eprevesym(fliptets[i], newface);
                  crossfaces->newindex((void **) &parytet);
                  *parytet = newface;
                }
                for (i = 0; i < 3; i++) {
                  enextesym(fliptets[i], newface);
                  crossfaces->newindex((void **) &parytet);
                  *parytet = newface;
                }
                flipflag = 1;
              } else if (convcount == 2) {
                assert(copcount <= 1);
                //if (copcount <= 1) {
                // A 3-to-2 or 4-to-4 may be possible.
                // Get the edge which is locally non-convex or flat. 
                for (i = 0; i < 3; i++) {
                  if (ori[i] <= 0) break;
                  enextself(fliptet);
                }
                // The edge should not be a segment.
                tsspivot1(fliptet, checkseg);
                assert(checkseg.sh == NULL);
    
                // Collect tets sharing at this edge.
                esym(fliptet, fliptets[0]); // [b,a,d,c]
                n = 0;
                do {
                  fnext(fliptets[n], fliptets[n + 1]);
                  n++;
                } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
    
                if (n == 3) {
                  // Found a 3-to-2 flip.
                  flip32(fliptets, 1, 0, 0);
                  // Put the link faces into check list.
                  for (i = 0; i < 3; i++) {
                    esym(fliptets[0], newface);
                    crossfaces->newindex((void **) &parytet);
                    *parytet = newface;
                    enextself(fliptets[0]);
                  }
                  for (i = 0; i < 3; i++) {
                    esym(fliptets[1], newface);
                    crossfaces->newindex((void **) &parytet);
                    *parytet = newface;
                    enextself(fliptets[1]);
                  }
                  flipflag = 1;
                } else if (n == 4) {
                  if (copcount == 1) {                
                    // Found a 4-to-4 flip. 
                    // Let the six vertices are: a,b,c,d,e,f, where
                    //   fliptets[0] = [b,a,d,c]
                    //           [1] = [b,a,c,e]
                    //           [2] = [b,a,e,f]
                    //           [3] = [b,a,f,d]
                    // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
                    //   is created.
                    // First do a 2-to-3 flip.
                    // Comment: This flip temporarily creates a degenerated
                    //   tet (whose volume is zero). It will be removed by the 
                    //   followed 3-to-2 flip.
                    fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
                    // fliptets[1];        // = [b,a,c,e].
                    baktets[0] = fliptets[2]; // = [b,a,e,f]
                    baktets[1] = fliptets[3]; // = [b,a,f,d]
                    // The flip may involve hull tets.
                    flip23(fliptets, 1, 0, 0);
                    // Put the "outer" link faces into check list.
                    //   fliptets[0] = [e,d,a,b] => will be flipped, so 
                    //   [a,b,d] and [a,b,e] are not "outer" link faces.
                    for (i = 1; i < 3; i++) {
                      eprevesym(fliptets[i], newface);
                      crossfaces->newindex((void **) &parytet);
                      *parytet = newface;
                    }
                    for (i = 1; i < 3; i++) {
                      enextesym(fliptets[i], newface);
                      crossfaces->newindex((void **) &parytet);
                      *parytet = newface;
                    }
                    // Then do a 3-to-2 flip.
                    enextesymself(fliptets[0]);  // fliptets[0] is [e,d,a,b].
                    eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
                    fliptets[1] = baktets[0]; // = [b,a,e,f]
                    fliptets[2] = baktets[1]; // = [b,a,f,d]
                    flip32(fliptets, 1, 0, 0);
                    // Put the "outer" link faces into check list.
                    //   fliptets[0] = [d,e,f,a]
                    //   fliptets[1] = [e,d,f,b]
                    //   Faces [a,b,d] and [a,b,e] are not "outer" link faces.
                    enextself(fliptets[0]);
                    for (i = 1; i < 3; i++) {
                      esym(fliptets[0], newface);
                      crossfaces->newindex((void **) &parytet);
                      *parytet = newface;
                      enextself(fliptets[0]);
                    }
                    enextself(fliptets[1]);
                    for (i = 1; i < 3; i++) {
                      esym(fliptets[1], newface);
                      crossfaces->newindex((void **) &parytet);
                      *parytet = newface;
                      enextself(fliptets[1]);
                    }
                    flip23count--;
                    flip32count--;
                    flip44count++;
                    flipflag = 1;
                  } else {
                    //n == 4, convflag != 0; assert(0);
                  }
                } else { 
                  // n > 4 => unflipable. //assert(0);
                }
              } else {
                // There are more than 1 non-convex or coplanar cases.
                flipflag = -1; // Ignore this face.
                if (b->verbose > 2) {
                  printf("        Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
                         pointmark(bface.forg), pointmark(bface.fdest),
                         pointmark(bface.fapex), pointmark(bface.foppo),
                         pointmark(bface.noppo), bface.key);
                }
                dbg_ignore_facecount++;
              } // if (convcount == 1)
    
              if (flipflag == 1) {
                // Update the priority queue.
                for (i = 0; i < crossfaces->objects; i++) {
                  parytet = (triface *) fastlookup(crossfaces, i);
                  flipcertify(parytet, &pqueue);
                }
                crossfaces->restart();
                if (!b->flipinsert_random) {
                  // Insert all queued unflipped faces.
                  for (i = 0; i < bfacearray->objects; i++) {
                    parytet = (triface *) fastlookup(bfacearray, i);
                    // This face may be changed.
                    if (!isdeadtet(*parytet)) {
                      flipcertify(parytet, &pqueue);
                    }
                  }
                  bfacearray->restart();
                }
                fcount++;
              } else if (flipflag == 0) {
                // Queue an unflippable face. To process it later.
                bfacearray->newindex((void **) &parytet);
                *parytet = fliptet;
              }
            } // if (pe == bface.noppo)  
          } // if ((pa == bface.forg) && ...)
        } // if (bface.tt != NULL)
    
      } // while (pqueue != NULL)
    
      if (bfacearray->objects > 0) {
        if (fcount == 0) {
          printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
          assert(0);
        }
        if (b->flipinsert_random) {
          // Insert all queued unflipped faces.
          for (i = 0; i < bfacearray->objects; i++) {
            parytet = (triface *) fastlookup(bfacearray, i);
            // This face may be changed.
            if (!isdeadtet(*parytet)) {
              flipcertify(parytet, &pqueue);
            }
          }
          bfacearray->restart();
          goto fliploop;
        }
      }
    
      // 'bfacearray' may be not empty (for what reason ??).
      dbg_unflip_facecount += bfacearray->objects;
    
      assert(flippool->items == 0l);
      delete bfacearray;
    
      // Un-mark top and bottom points.
      for (i = 0; i < toppoints->objects; i++) {
        parypt = (point *) fastlookup(toppoints, i);
        punmarktest2(*parypt);
      }
      for (i = 0; i < botpoints->objects; i++) {
        parypt = (point *) fastlookup(botpoints, i);
        punmarktest3(*parypt);
      }
    
      f23count = flip23count - f23count;
      f32count = flip32count - f32count;
      f44count = flip44count - f44count;
      totalfcount = f23count + f32count + f44count;
    
      if (totalfcount > maxflipsequence) {
        maxflipsequence = totalfcount;
      }
    
      if (b->verbose > 2) {
        printf("      Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
               totalfcount, f23count, f32count, f44count);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // fillregion()    Fill the missing region by a set of new subfaces.         //
    //                                                                           //
    // 'missingshs' contains the list of subfaces in R.  Moreover, each subface  //
    // (except the first one) in this list represents an interior edge of R.     //
    // Note: All subfaces in R are smarktested.                                  //
    //                                                                           //
    // Note: We assume that all vertices of R are marktested so we can detect    //
    // new subface by checking the flag in apexes.                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds, 
                                arraypool* newshs)
    {
      badface *newflipface, *popface;
      triface searchtet, spintet;
      face oldsh, newsh, opensh, *parysh;
      face casout, casin, neighsh, checksh;
      face checkseg, fakeseg;
      point pc, pd, pe, pf, ppt[2];
      enum interresult dir;
      REAL n[3], len; // elen[3];
      bool insideflag;
      int types[2], poss[4];
      int i, j, k;
    
      if (b->verbose > 2) {
        printf("      Fill region: %ld old subfaces (%ld).\n", missingshs->objects,
               fillregioncount);
      }
    
      // Search the first constrained face of R. It is found from the set of
      //   faces sharing at a boundary edge [a,b]. Such face must be found.
      //   The search takes the following two steps:
      //   - First, finds a candidate face [a,b,c] where c is also a vertex of R;
      //     Note that [a,b,c] may not be the right face to fill R. For instance,
      //     when R is concave at b.
      //   - Second, check if [a,b,c] can fill R. This can be checked if an
      //     adjacent tet of [a,b,c] intersects R. This is a tetrahedron-triangle
      //     intersection test. It can be reduced to two triangle-edge intersect
      //     tests, i.e., intersect the two faces not containing the edge [a,b] in
      //     this tet with all interior edges of R.
    
      // We start from the first boundary edge of R.
      oldsh = * (face *) fastlookup(missingshbds, 0);
      ppt[0] = sorg(oldsh);
      ppt[1] = sdest(oldsh);
      point2tetorg(ppt[0], searchtet);
      dir = finddirection(&searchtet, ppt[1], 0);
      assert(dir == ACROSSVERT); // SELF_CHECK
    
      insideflag = false;
    
      // Each face has two adjacent tets.
      for (k = 0; k < 2; k++) {
        if (b->verbose > 2) {
          printf("      Search an interior face from edge (%d, %d).\n",
                 pointmark(ppt[0]), pointmark(ppt[1]));
        }
        spintet = searchtet;
        while (1) {
          pc = apex(spintet);
          if (pmarktested(pc)) {
            // Found a candidate face. Check if it is inside R.
            if (missingshs->objects > 2l) {
              // pd = oppo(spintet);
              // if (pd == dummypoint) {
                // Calculate an above point for this subface.
    	    facenormal(ppt[0], ppt[1], pc, n, 1, NULL);
                len = sqrt(DOT(n, n));
                n[0] /= len;
                n[1] /= len;
                n[2] /= len;
                len = DIST(ppt[0], ppt[1]);
                len += DIST(ppt[1], pc);
                len += DIST(pc, ppt[0]);
                len /= 3.0;
                dummypoint[0] = ppt[0][0] + len * n[0];
                dummypoint[1] = ppt[0][1] + len * n[1];
                dummypoint[2] = ppt[0][2] + len * n[2];
                pd = dummypoint;
    	  // }
              //if (pd != dummypoint) {
                for (j = 0; j < 2 && !insideflag; j++) {
                  for (i = 1; i < missingshs->objects && !insideflag; i++) {
                    parysh = (face *) fastlookup(missingshs, i);
                    // Get an interior edge of R.
                    pe = sorg(*parysh);
                    pf = sdest(*parysh);
                    if (tri_edge_test(ppt[j],pc,pd,pe,pf,NULL,1,types,poss)) {
                      dir = (enum interresult) types[0];
                      if (dir == ACROSSFACE) {
                        searchtet = spintet;
                        insideflag = true;
                      } else if (dir == ACROSSEDGE) {
                        searchtet = spintet;
                        insideflag = true;
                      }
                    }
                  } // i
                } // j
    	  // }
              // if (pd == dummypoint) {
                dummypoint[0] = 0;
                dummypoint[1] = 0;
                dummypoint[2] = 0;
    	  // }
            } else {
              // It is a simple 2-to-2 flip.
              searchtet = spintet;
              insideflag = true;
            }
          } // if (pmarktested(pc))
          if (insideflag) break;
          fnextself(spintet);
          if (spintet.tet == searchtet.tet) break;
        } // while (1)
        if (insideflag) break;
        esymself(searchtet);
        ppt[0] = org(searchtet);
        ppt[1] = dest(searchtet);
      } // k
    
      if (!insideflag) {
        // Something strange is happening.
        // Refine the missing region by adding a Steiner point.
        recentsh = oldsh;
        recenttet = searchtet; // For point location.
        return false;
      }
    
      // Create a new subface at the boundary edge.
      if (b->verbose > 2) {
        printf("      Create a new subface (%d, %d, %d)\n", pointmark(ppt[0]),
               pointmark(ppt[1]), pointmark(pc));
      }
      makeshellface(subfaces, &newsh);
      setsorg(newsh, ppt[0]);
      setsdest(newsh, ppt[1]);
      setsapex(newsh, pc);
      // The new subface gets its markers from the old one.
      setshellmark(newsh, shellmark(oldsh));
      if (checkconstraints) {
        setareabound(newsh, areabound(oldsh));
      }
      // Connect the new subface to adjacent tets.
      tspivot(searchtet, checksh); // SELF_CHECK
      assert(checksh.sh == NULL); // SELF_CHECK 
      tsbond(searchtet, newsh);
      fsymself(searchtet);
      sesymself(newsh);
      tsbond(searchtet, newsh);
      // Connect newsh to outer subfaces.
      sspivot(oldsh, checkseg);
      spivot(oldsh, casout);
      if (casout.sh != NULL) {
        casin = casout;
        if (checkseg.sh != NULL) {
          // Make sure that the subface has the right ori at the segment.
          checkseg.shver = 0;
          if (sorg(newsh) != sorg(checkseg)) {
            sesymself(newsh);
          }
          spivot(casin, neighsh);
          while (neighsh.sh != oldsh.sh) {
            casin = neighsh;
            spivot(casin, neighsh);
          }
        }
        sbond1(newsh, casout);
        sbond1(casin, newsh);
      }
      if (checkseg.sh != NULL) {
        ssbond(newsh, checkseg);
      }
      // Add this new subface into list.
      sinfect(newsh);
      newshs->newindex((void **) &parysh);
      *parysh = newsh;
    
      // Push two "open" side of the new subface into stack.
      for (i = 0; i < 2; i++) {
        senextself(newsh);
        newflipface = (badface *) flippool->alloc();
        newflipface->ss = newsh;
        newflipface->nextitem = flipstack;
        flipstack = newflipface;
      }
    
      // Every other boundary edge of R is identified as a segment. Insert a faked
      //   segments at the place if it is not a segment.
      for (i = 1; i < missingshbds->objects; i++) {
        parysh = (face *) fastlookup(missingshbds, i);
        ppt[0] = sorg(*parysh);
        ppt[1] = sdest(*parysh);
        point2tetorg(ppt[0], searchtet);
        dir = finddirection(&searchtet, ppt[1], 0);
        assert(dir == ACROSSVERT); // SELF_CHECK
        tsspivot1(searchtet, checkseg);
        if (checkseg.sh == NULL) {
          // Insert a fake segment at this tet.
          if (b->verbose > 2) {
            printf("      Insert a fake segment (%d, %d)\n", pointmark(ppt[0]),
                   pointmark(ppt[1]));
          }
          makeshellface(subsegs, &fakeseg);
          setsorg(fakeseg, ppt[0]);
          setsdest(fakeseg, ppt[1]);
          sinfect(fakeseg); // Mark it as faked.
          // Connect it to all tets at this edge.
          spintet = searchtet;
          while (1) {
            tssbond1(spintet, fakeseg);
            fnextself(spintet);
            if (spintet.tet == searchtet.tet) break;
          }
          checkseg = fakeseg;
        }
        // Let the segment hold the old subface.
        checkseg.shver = 0;
        sbond1(checkseg, *parysh);
        // Remember it to free it later.
        *parysh = checkseg;
      }
    
      // Loop until 'flipstack' is empty.
      while (flipstack != NULL) {
    
        // Pop an "open" side from the stack.
        popface = flipstack;
        opensh = popface->ss;
        flipstack = popface->nextitem; // The next top item in stack.
        flippool->dealloc((void *) popface);
    
        // Process it if it is still open.
        spivot(opensh, casout);
        if (casout.sh == NULL) {
          if (b->verbose > 2) {
            printf("      Get an open side (%d, %d) - %d.\n",
                   pointmark(sorg(opensh)), pointmark(sdest(opensh)),
                   pointmark(sapex(opensh)));
          }
          // Search a neighbor to close this side.
          stpivot(opensh, searchtet);
          tsspivot1(searchtet, checkseg);
          if (checkseg.sh == NULL) {
            // No segment. It is inside R. Search for a new face to fill in R.
            //   Note that the face may not be found (see fig 2010-05-25-c).
            spintet = searchtet;
            fnextself(spintet); // Skip the current face.
            while (1) {
              pc = apex(spintet);
              if (pmarktested(pc)) {
                // Found a place for a new subface inside R -- Case (i).
                tspivot(spintet, checksh);
                if (checksh.sh == NULL) {
                  // Create a new subface.
                  if (b->verbose > 2) {
                    printf("      Create a new subface (%d, %d, %d)\n", 
                           pointmark(org(spintet)), pointmark(dest(spintet)),
                           pointmark(pc));
                  }
                  makeshellface(subfaces, &newsh);
                  setsorg(newsh, org(spintet));
                  setsdest(newsh, dest(spintet));
                  setsapex(newsh, pc);
                  // The new subface gets its markers from its neighbor.
                  setshellmark(newsh, shellmark(opensh));
                  if (checkconstraints) {
                    setareabound(newsh, areabound(opensh));
                  }
                  // Connect the new subface to adjacent tets.
                  tsbond(spintet, newsh);
                  fsymself(spintet);
                  sesymself(newsh);
                  tsbond(spintet, newsh);
                  // Connect newsh to its adjacent subface.
                  sbond(newsh, opensh);
                  // Add this new subface into list.
                  sinfect(newsh);
                  newshs->newindex((void **) &parysh);
                  *parysh = newsh;
                  // Push two "open" side of the new subface into stack.
                  for (i = 0; i < 2; i++) {
                    senextself(newsh);
                    newflipface = (badface *) flippool->alloc();
                    newflipface->ss = newsh;
                    newflipface->nextitem = flipstack;
                    flipstack = newflipface;
                  }
                } else {
                  // A new subface has already been created.
                  assert(sinfected(checksh)); // It must be in stack.
                  spivot(checksh, neighsh); // SELF_CHECK
                  assert(neighsh.sh == NULL); // Its side must be open.
                  if (b->verbose > 2) {
                    printf("      Connect to another open side (%d, %d, %d)\n", 
                           pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                           pointmark(sapex(checksh)));
                  }
                  sbond(opensh, checksh); // Simply connect them.
                }
                break; // -- Case (i)
              }
              fnextself(spintet);
              if (spintet.tet == searchtet.tet) {
                // Not find any face to fill in R at this side.
                // TO DO: suggest a point to split the edge.
                assert(0);
              }
            } // while (1)
          } else {
            // This side coincident with a boundary edge of R.
            checkseg.shver = 0;
            spivot(checkseg, oldsh);
            if (sinfected(checkseg)) {
              // It's a faked segment. Delete it.
              if (b->verbose > 2) {
                printf("      Delete a fake segment (%d, %d)\n", 
                       pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
              }
              spintet = searchtet;
              while (1) {
                tssdissolve1(spintet);
                fnextself(spintet);
                if (spintet.tet == searchtet.tet) break;
              }
              shellfacedealloc(subsegs, checkseg.sh);
            }
            if (b->verbose > 2) {
              printf("      Connect to a boundary edge (%d, %d, %d)\n", 
                     pointmark(sorg(oldsh)), pointmark(sdest(oldsh)),
                     pointmark(sapex(oldsh)));
            }
            sspivot(oldsh, checkseg);
            spivot(oldsh, casout);
            if (casout.sh != NULL) {
              casin = casout;
              if (checkseg.sh != NULL) {
                // Make sure that the subface has the right ori at the segment.
                checkseg.shver = 0;
                if (sorg(opensh) != sorg(checkseg)) {
                  sesymself(opensh);
    	    }
                spivot(casin, neighsh);
                while (neighsh.sh != oldsh.sh) {
                  casin = neighsh;
                  spivot(casin, neighsh);
                }
              }
              sbond1(opensh, casout);
              sbond1(casin, opensh);
            }
            if (checkseg.sh != NULL) {
              ssbond(opensh, checkseg);
            }
          }
    
        } // if (casout.sh == NULL)
    
      } // while (flipstack != NULL)
    
      // Uninfect all new subfaces.
      for (i = 0; i < newshs->objects; i++) {
        parysh = (face *) fastlookup(newshs, i);
        suninfect(*parysh);
      }
    
      if (b->verbose > 2) {
        printf("      Created %ld new subfaces.\n", newshs->objects);
      }
      fillregioncount++;
    
      return true;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // refineregion()    Refine a missing region by inserting points.            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::refineregion()
    {
      triface searchtet;
      face splitsh;
      face *paryseg, sseg;
      point steinpt, pa, pb, pc;
      insertvertexflags ivf;
      REAL auv[2], buv[2], newuv[2], t;
      int fmark, fid, eid;
      int loc; // iloc, sloc;
      int s, i;
    
      // The mesh is a CDT.
      assert(subsegstack->objects == 0l); // SELF_CHECK
    
      // Create a new point.
      makepoint(&steinpt, FREEFACETVERTEX);
    
      // The 'recentsh' saved an edge to be split.
      splitsh = recentsh;
      // Add the Steiner point at the barycenter of the face.
      pa = sorg(splitsh);
      pb = sdest(splitsh);
      pc = sapex(splitsh);
    
      if (b->psc) {
        assert(in->facetmarkerlist != NULL);
        fmark = shellmark(splitsh) - 1;
        fid = in->facetmarkerlist[fmark];
        if (pointtype(pa) == RIDGEVERTEX) {
          in->getvertexparamonface(in->geomhandle, pointmark(pa), fid, auv);
        } else if (pointtype(pa) == FREESEGVERTEX) {
          eid = pointgeomtag(pa); // The Edge containing this Steiner point.
          t = pointgeomuv(pa, 0);  // The Steiner point's parameter on Edge.
          in->getedgesteinerparamonface(in->geomhandle, eid, t, fid, auv);
        } else if (pointtype(pa) == FREEFACETVERTEX) {
          auv[0] = pointgeomuv(pa, 0);
          auv[1] = pointgeomuv(pa, 1);
        } else {
          assert(0);
        }
        if (pointtype(pb) == RIDGEVERTEX) {
          in->getvertexparamonface(in->geomhandle, pointmark(pb), fid, buv);
        } else if (pointtype(pb) == FREESEGVERTEX) {
          eid = pointgeomtag(pb); // The Edge containing this Steiner point.
          t = pointgeomuv(pb, 0);  // The Steiner point's parameter on Edge.
          in->getedgesteinerparamonface(in->geomhandle, eid, t, fid, buv);
        } else if (pointtype(pb) == FREEFACETVERTEX) {
          buv[0] = pointgeomuv(pb, 0);
          buv[1] = pointgeomuv(pb, 1);
        } else {
          assert(0);
        }
        newuv[0] = 0.5 * (auv[0] + buv[0]);
        newuv[1] = 0.5 * (auv[1] + buv[1]);
        in->getsteineronface(in->geomhandle, fid, newuv, steinpt);
        setpointgeomuv(steinpt, 0, newuv[0]);
        setpointgeomuv(steinpt, 1, newuv[1]);
        setpointgeomtag(steinpt, fid);
      } else {
        for (i = 0; i < 3; i++) {
          steinpt[i] = (pa[i] + pb[i] + pc[i]) / 3.0;
        }
      }
    
      // Start searching it from 'recentet'.
      searchtet = recenttet;
      // Now insert the point p. The flags are chosen as follows: 
      //   - boywat  = 2, the current T is a CDT, 
      //   - lawson  = 2, do flip after inserting p, some existing segments
      //                  and subfaces may be flipped, they are queued and
      //                  and will be recovered.
      //   - rejflag = 1, reject p if it encroaches upon at least one segment,
      //                  queue encroached segments.
      ivf.iloc = (int) OUTSIDE;
      ivf.bowywat = 2;
      ivf.lawson = 2;
      ivf.rejflag = 1;
      ivf.chkencflag = 0;
      ivf.sloc = (int) ONFACE;
      ivf.sbowywat = 2;
      ivf.splitbdflag = 0;
      ivf.validflag = 1;
      ivf.respectbdflag = 0;
      ivf.assignmeshsize = 0;
      loc = insertvertex(steinpt, &searchtet, &splitsh, NULL, &ivf);
    
      assert((loc != OUTSIDE) && (loc != ONVERTEX));
      if (loc == NEARVERTEX) {
        // The new point is either ON or VERY CLOSE to an existing point.
        pa = point2ppt(steinpt);
        printf("  !! Avoid to create a short edge (length = %g)\n",
               distance(steinpt, pa));
        // Indicate it may be an input problem.
        printf("  Short edge length bound is: %g. Tolerance is %g.\n", 
               b->minedgelength, b->epsilon);
        terminatetetgen(4);
      }
    
      if (loc == ENCSEGMENT) {
        // Some segments are encroached and queued.
        assert(encseglist->objects > 0l);
        // Randomly pick one encroached segment to split.
        s = randomnation(encseglist->objects);
        paryseg = (face *) fastlookup(encseglist, s);
        sseg = *paryseg;
        // The new point p is the midpoint of this segment.
        getsteinerptonsegment(&sseg, NULL, steinpt);
        setpointtype(steinpt, FREESEGVERTEX);
        encseglist->restart();  // Clear the queue.
    
        // Start searching from an adjacent tetrahedron (containing the segment).
        sstpivot1(sseg, searchtet);
        spivot(sseg, splitsh);
        // Insert the point p. The flags are chosen as follows: 
        //   - boywat  = 2, the current T is a CDT, 
        //   - lawson  = 2, do flip after inserting p, some existing segments
        //                  and subfaces may be flipped, they are queued and
        //                  and will be recovered.
        //   - rejflag = 0, always insert p, even it will cause some segments
        //                  or subfaces missing, queue missing boundaries.
        ivf.iloc = (int) ONEDGE;
        ivf.bowywat = 2;
        ivf.lawson = 2;
        ivf.rejflag = 0;
        ivf.chkencflag = 0;
        ivf.sloc = (int) ONEDGE;
        ivf.sbowywat = 2;
        ivf.splitbdflag = 0;
        ivf.validflag = 1;
        ivf.respectbdflag = 0;
        ivf.assignmeshsize = 0;
        loc = insertvertex(steinpt, &searchtet, &splitsh, &sseg, &ivf);
    
        if (loc == NEARVERTEX) {
          // The new point is either ON or VERY CLOSE to an existing point.
          pa = point2ppt(steinpt);
          printf("  !! Avoid to create a short edge (length = %g)\n",
                 distance(steinpt, pa));
          // Indicate it may be an input problem.
          printf("  Short edge length bound is: %g. Tolerance is %g.\n", 
                 b->minedgelength, b->epsilon);
          terminatetetgen(4);
        }
    
        st_segref_count++;
      } else {
        st_facref_count++;
      }
      if (steinerleft > 0) steinerleft--;
    
      // Do flip to recover Delaunayniess.
      lawsonflip3d(steinpt, 2, 0, 0, 0);
    
      // Some vertices may be queued, recover them.
      if (subvertstack->objects > 0l) {
        assert(0); //delaunizevertices();
      }
    
      // Some subsegments may be queued, recover them.
      if (subsegstack->objects > 0l) {
        delaunizesegments();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // constrainedfacets()    Recover subfaces saved in 'subfacestack'.          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::constrainedfacets()
    {
      arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
      arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
      arraypool *tg_topshells, *tg_botshells, *tg_facfaces; 
      arraypool *tg_toppoints, *tg_botpoints;
      arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
    
      triface searchtet, neightet;
      face searchsh, neighsh, *parysh;
      face checkseg, *paryseg;
      point refpt, *parypt;
      enum interresult dir;
      bool success;
      int facetcount;
      //int bakhullsize;
      int crossflag;
      int i, j;
    
      // Initialize arrays.
      tg_crosstets      = new arraypool(sizeof(triface), 10);
      tg_topnewtets     = new arraypool(sizeof(triface), 10);
      tg_botnewtets     = new arraypool(sizeof(triface), 10);
      tg_topfaces       = new arraypool(sizeof(triface), 10);
      tg_botfaces       = new arraypool(sizeof(triface), 10);
      tg_midfaces       = new arraypool(sizeof(triface), 10);
      tg_toppoints      = new arraypool(sizeof(point), 8);
      tg_botpoints      = new arraypool(sizeof(point), 8);
      tg_facfaces       = new arraypool(sizeof(face), 10);
      tg_topshells      = new arraypool(sizeof(face), 10);
      tg_botshells      = new arraypool(sizeof(face), 10);
      tg_missingshs     = new arraypool(sizeof(face), 10);
      tg_missingshbds   = new arraypool(sizeof(face), 10);
      tg_missingshverts = new arraypool(sizeof(point), 8);
    
      // This is a global array used by refineregion().
      encseglist        = new arraypool(sizeof(face), 4); 
    
      facetcount = 0;
    
      // Loop until 'subfacstack' is empty.
      while (subfacstack->objects > 0l) {
        subfacstack->objects--;
        parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
        searchsh = *parysh;
    
        if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
    
        stpivot(searchsh, neightet);
        if (neightet.tet == NULL) {
          // Find an unrecovered subface.
          smarktest(searchsh);
          tg_facfaces->newindex((void **) &parysh);
          *parysh = searchsh;
          // Collect all non-recovered subfaces of the same facet.
          for (i = 0; i < tg_facfaces->objects; i++) {
            searchsh = * (face *) fastlookup(tg_facfaces, i);
            for (j = 0; j < 3; j++) {
              sspivot(searchsh, checkseg);
              if (checkseg.sh == NULL) {
                spivot(searchsh, neighsh);
                assert(neighsh.sh != NULL); // SELF_CHECK
                if (!smarktested(neighsh)) {
                  // It may be already recovered.
                  stpivot(neighsh, neightet);
                  if (neightet.tet == NULL) {
                    smarktest(neighsh);
                    tg_facfaces->newindex((void **) &parysh);
                    *parysh = neighsh;
                  }
                }
              }
              senextself(searchsh);
            } // j
          } // i
          // Have found all facet subfaces (vertices). Uninfect them.
          for (i = 0; i < tg_facfaces->objects; i++) {
            parysh = (face *) fastlookup(tg_facfaces, i);
            sunmarktest(*parysh);
          }
    
          if (b->verbose > 2) {
            printf("    Recover facet #%d: %ld subfaces.\n", facetcount + 1, 
                   tg_facfaces->objects);
          }
          facetcount++;
    
          // Loop until 'tg_facfaces' is empty.
          while (tg_facfaces->objects > 0l) {
            // Get the last subface of this array.
            tg_facfaces->objects--;
            parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
            searchsh = *parysh;
    
            if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
    
            stpivot(searchsh, neightet);
            if (neightet.tet != NULL) continue; // Not a missing subface.
    
            // Insert the subface.
            searchtet.tet = NULL;
            dir = scoutsubface(&searchsh, &searchtet);
            if (dir == SHAREFACE) continue; // The subface is inserted.
            if (dir == COLLISIONFACE) continue; // The subface is removed.
    
            // The subface is missing. Form the missing region.
            //   Re-use 'tg_crosstets' for 'adjtets'.
            formmissingregion(&searchsh, tg_missingshs, tg_missingshbds,
                              tg_missingshverts, tg_crosstets);
    
            // Search for a crossing edge (tg_crosstets is cleared).
            crossflag = scoutcrossedge(searchtet, tg_crosstets, tg_missingshs);
    
            if (crossflag == 1) {
              // Recover subfaces by local retetrahedralization.
              // Form a cavity of crossing tets.
              if (formcavity(&searchtet, tg_missingshs, tg_crosstets, tg_topfaces, 
                             tg_botfaces, tg_toppoints, tg_botpoints)) {
                if (!b->flipinsert) {
                  // Tetrahedralize the top part. Re-use 'tg_midfaces'.
                  delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
                                  tg_topnewtets, tg_crosstets, tg_midfaces);
                  // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
                  delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
                                  tg_botnewtets, tg_crosstets, tg_midfaces);
                  // Fill the cavity with new tets.
                  success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
                                       tg_missingshs);
                  if (success) {
                    // Cavity is remeshed. Delete old tets and outer new tets.
                    carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
                    // Insert the missing region into cavity.
                    j = 0; // FOR DEBUG! Count the number of non-recovered faces. 
                    for (i = 0; i < tg_missingshs->objects; i++) {
                      searchsh = * (face *) fastlookup(tg_missingshs, i);
                      searchtet.tet = NULL;
                      dir = scoutsubface(&searchsh, &searchtet);
                      assert(dir != COLLISIONFACE); // SELF_CHECK
                      if (dir != SHAREFACE) {
                        // A subface is missing. This is possible that the subface
                        //   is not actually a constrained Delaunay face in T. 
                        // Add this face at the end of the list, so it will be
                        //   processed immediately. This is necessary because we
                        //   have created some non-locally Delaunay face (by the
                        //   remesh of the cavity). We have to insert the subfaces
                        //   to make these face constrained Delaunay.
                        tg_facfaces->newindex((void **) &parysh);
                        *parysh = searchsh;
                        j++; // FOR DEBUG!
                      }
                    } // i
                    // Recover interior subfaces.
                    for (i = 0; i < caveencshlist->objects; i++) {
                      searchsh = * (face *) fastlookup(caveencshlist, i);
                      searchtet.tet = NULL;
                      dir = scoutsubface(&searchsh, &searchtet);
                      assert(dir != COLLISIONFACE); // SELF_CHECK
                      if (dir != SHAREFACE) {
                        // The subface is missing. This is possible that the subface
                        //   is removed by the enlargement of the cavity. It has to
                        //   be recovered. 
                        // Add this face at the end of the list, so it will be
                        //   processed immediately. We have to insert the subfaces
                        //   to make these face constrained Delaunay.
                        tg_facfaces->newindex((void **) &parysh);
                        *parysh = searchsh;
                        j++; // FOR DEBUG!
                      }
                    } // i
                    // Recover interior segments. This should always be recovered.
                    for (i = 0; i < caveencseglist->objects; i++) {
                      paryseg = (face *) fastlookup(caveencseglist, i);
                      searchtet.tet = NULL;
                      refpt = NULL;
                      dir = scoutsegment(sorg(*paryseg),sdest(*paryseg),&searchtet,
                                         &refpt, NULL);
                      assert(dir == SHAREEDGE);
                      // Insert this segment.
                      tsspivot1(searchtet, checkseg);  // SELF_CHECK
                      if (checkseg.sh == NULL) {
                        // Let the segment remember an adjacent tet.
                        sstbond1(*paryseg, searchtet);
                        // Bond the segment to all tets containing it.
                        neightet = searchtet;
                        do {
                          tssbond1(neightet, *paryseg);
                          fnextself(neightet);
                        } while (neightet.tet != searchtet.tet);
                      } else {
                        // Collision! Should not happen.
                        assert(0);
                      }
                    } // i
                    caveencshlist->restart();
                    caveencseglist->restart();
                  } else {
                    // Restore old tets and delete new tets.
                    restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
                    // Set a handle for searching subface.
                    //recentsh = searchsh;
                  }
                } else {
                  // Use the flip algorithm of Shewchuk to recover the subfaces.
                  flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints, 
                                  tg_missingshverts);
                  // Check the missing subfaces again.
                  j = 0; // FOR DEBUG! Count the number of non-recovered faces. 
                  for (i = 0; i < tg_missingshs->objects; i++) {
                    searchsh = * (face *) fastlookup(tg_missingshs, i);
                    searchtet.tet = NULL;
                    dir = scoutsubface(&searchsh, &searchtet);
                    assert(dir != COLLISIONFACE); // SELF_CHECK
                    if (dir != SHAREFACE) {
                      // A subface is missing. This is possible that the subface
                      //   is not actually a constrained Delaunay face in T. 
                      // Add this face at the end of the list, so it will be
                      //   processed immediately. This is necessary because we
                      //   have created some non-locally Delaunay face (by the
                      //   remesh of the cavity). We have to insert the subfaces
                      //   to make these face constrained Delaunay.
                      tg_facfaces->newindex((void **) &parysh);
                      *parysh = searchsh;
                      j++; // FOR DEBUG!
                    }
                  } // i
                  // Clear working lists.
                  tg_crosstets->restart();
                  tg_topfaces->restart();
                  tg_botfaces->restart();
                  tg_toppoints->restart();
                  tg_botpoints->restart();
                  success = true;
                } // if (b->flipinsert)
              } else {
                // Formcavity failed.
                success = false;
              }
            } else { //if (crossflag == 0) {
              // Recover subfaces by retriangulate the surface mesh.
              //   Re-use tg_topshells for newshs.
              success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
              if (success) {
                // Region is remeshed. Delete old subfaces (in tg_missingshs).
                for (i = 0; i < tg_missingshs->objects; i++) {
                  parysh = (face *) fastlookup(tg_missingshs, i);
                  shellfacedealloc(subfaces, parysh->sh);
                }
                tg_topshells->restart();
              } else {
                // Search a handle for searching tetrahedron.
                recenttet = searchtet;
              }
            }
    
            // Unmarktest all points of the missing region.
            for (i = 0; i < tg_missingshverts->objects; i++) {
              parypt = (point *) fastlookup(tg_missingshverts, i);
              punmarktest(*parypt);
            }
            tg_missingshverts->restart();
            tg_missingshbds->restart();
            tg_missingshs->restart();
    
            if (!success) {
              // The missing region can not be recovered. Refine it.
              refineregion();
              // Clean the current list of facet subfaces.
              //tg_facfaces->restart();
            }
          } // while (tg_facfaces->objects > 0l)
    
        } // if (neightet.tet == NULL)
      } // while (subfacstack->objects > 0l)
    
      // Delete arrays.
      delete tg_crosstets;
      delete tg_topnewtets;
      delete tg_botnewtets;
      delete tg_topfaces;
      delete tg_botfaces;
      delete tg_midfaces;
      delete tg_toppoints;
      delete tg_botpoints;
      delete tg_facfaces;
      delete tg_topshells;
      delete tg_botshells;
      delete tg_missingshs;
      delete tg_missingshbds;
      delete tg_missingshverts;
      delete encseglist;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // constraineddelaunay()    Create a constrained Delaunay tetrahedralization.//
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::constraineddelaunay(clock_t& tv)
    {
      face searchsh, *parysh;
      face searchseg, *paryseg;
      int s, i;
    
      // Statistics.
      long bakfillregioncount;
      long bakcavitycount, bakcavityexpcount;
    
      if (!b->quiet) {
        printf("Constrained Delaunay...\n");
      }
    
      //if (!b->psc) {
        // Only identify acute vertex for PLC inputs.
        markacutevertices();
      //}
    
      if (b->verbose) {
        printf("  Delaunizing segments.\n");
      }
    
      checksubsegflag = 1;
    
      // Put all segments into the list.
      if (0) { //if (b->order == 4) {  // '-o4' option (for debug)
        // In sequential order.
        subsegs->traversalinit();
        for (i = 0; i < subsegs->items; i++) {
          searchseg.sh = shellfacetraverse(subsegs);
          //sinfect(searchseg);  // Only save it once.
          subsegstack->newindex((void **) &paryseg);
          *paryseg = searchseg;
        }
      } else {
        // In random order.
        subsegs->traversalinit();
        for (i = 0; i < subsegs->items; i++) {
          s = randomnation(i + 1);
          // Move the s-th seg to the i-th.
          subsegstack->newindex((void **) &paryseg);
          *paryseg = * (face *) fastlookup(subsegstack, s);
          // Put i-th seg to be the s-th.
          searchseg.sh = shellfacetraverse(subsegs);
          //sinfect(searchseg);  // Only save it once.
          paryseg = (face *) fastlookup(subsegstack, s);
          *paryseg = searchseg;
        }
      }
    
      // Recover non-Delaunay segments.
      delaunizesegments();
    
      if (b->verbose) {
        printf("  %ld Steiner points.\n", st_segref_count); 
      }
    
      tv = clock();
    
      if (b->verbose) {
        printf("  Constraining facets.\n");
      }
    
      if (b->flipinsert) {
        // Clear the counters.
        flip23count = flip32count = flip44count = 0l;
      }
    
      // Subfaces will be introduced.
      checksubfaceflag = 1;
    
      bakfillregioncount = fillregioncount;
      bakcavitycount = cavitycount;
      bakcavityexpcount = cavityexpcount;
    
      // Randomly order the subfaces.
      subfaces->traversalinit();
      for (i = 0; i < subfaces->items; i++) {
        s = randomnation(i + 1);
        // Move the s-th subface to the i-th.
        subfacstack->newindex((void **) &parysh);
        *parysh = * (face *) fastlookup(subfacstack, s);
        // Put i-th subface to be the s-th.
        searchsh.sh = shellfacetraverse(subfaces);
        parysh = (face *) fastlookup(subfacstack, s);
        *parysh = searchsh;
      }
    
      // Recover facets.
      constrainedfacets();
    
      if (b->verbose) {
        if (fillregioncount > bakfillregioncount) {
          printf("  Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
        }
        if (cavitycount > bakcavitycount) {
          printf("  Remeshed %ld cavities", cavitycount - bakcavitycount);
          if (cavityexpcount - bakcavityexpcount) {
            printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
          }
          printf(".\n");
        }
        if (st_segref_count + st_facref_count > 0) {
          printf("  Inserted %ld (%ld, %ld) refine points.\n", 
                 st_segref_count + st_facref_count, st_segref_count,
                 st_facref_count);
        }
      }
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// constrained_cxx //////////////////////////////////////////////////////////
    
    //// steiner_cxx //////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkflipeligibility()    A call back function for boundary recovery.     //
    //                                                                           //
    // 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
    // and 2 : 3-to-2, respectively.                                             //
    //                                                                           //
    // 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is    //
    // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
    // other points must not be 'dummypoint'.                                    //
    //                                                                           //
    // For avoiding mutually flipping, once a crossing face is flipped, it will  //
    // never be re-created again. Also, we never create a face or edge which is  //
    // intersecting the current recovering segment or subface.                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb, 
                                         point pc, point pd, point pe,
                                         int level, int edgepivot,
                                         flipconstraints* fc)
    {
      int rejflag;
      int i;
    
      point tmppts[3];
      REAL normal[3], area, len;
      REAL ori1, ori2;
      REAL abovept[3];
    
      enum interresult dir;
      int types[2], poss[4];
      int intflag;
    
      rejflag = 0;
    
      if (fc->seg[0] != NULL) {
        // A constraining edge is given (e.g., for edge recovery).
        if (fliptype == 1) {
          // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
          if (pc != dummypoint) {
            // Do not flip if the newly created faces intersect this edge in 
            //   their interiors.
            tmppts[0] = pa;
            tmppts[1] = pb;
            tmppts[2] = pc;
            if (0) {
              // Make sure that the three new faces are not degenerate.
              for (i = 0; i < 3 && !rejflag; i++) {
                facenormal(pe, pd, tmppts[i], normal, 1, &len);
                area = sqrt(DOT(normal, normal));
                if (area == 0) {
                  rejflag = 1; // A degenerate face.
                } else {
                  if ((area / (len * len)) < b->epsilon) {
                    rejflag = 1; // A nearly degenerate face.
                  }
                }
              } // i
            }
            for (i = 0; i < 3 && !rejflag; i++) {
              intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1], 
                                      NULL, 1, types, poss);
              if (intflag == 2) {
                // They intersect at a single point.
                dir = (enum interresult) types[0];
                if (dir == ACROSSFACE) {
                  // The interior of [e,d,#] intersect the segment.
                  rejflag = 1;
                } else if (dir == ACROSSEDGE) {
                  if (poss[0] == 0) {
                    // The interior of [e,d] intersect the segment.
                    // Since [e,d] is the newly created edge. Reject this flip.
                    rejflag = 1; 
                  }
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                } // dir
              } else if (intflag == 4) {
                // They may intersect at either a point or a line segment.
                dir = (enum interresult) types[0];
                if (dir == ACROSSEDGE) {
                  if (poss[0] == 0) {
                    // The interior of [e,d] intersect the segment.
                    // Since [e,d] is the newly created edge. Reject this flip.
                    rejflag = 1;
                  }
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                }
              } // if (intflag == 4)
            } // i
          } else { // pc == dummypoint
            // Do not flip if the new hull edge [e,d] will intersect this edge
            //   in its interior. 
            // Comment: Here we actually need a 3D edge-edge test.
            //   We only do test if the edge in 'fc' is coplanar with the plane
            //   containing a,b,e,and d.
            // Choose a better triangle [a,b,e] or [a,b,d].
            facenormal(pa, pb, pe, normal, 1, &len);
            area = sqrt(DOT(normal, normal));
            facenormal(pa, pb, pd, normal, 1, &len);
            len = sqrt(DOT(normal, normal)); // Re-use len as area.
            if (area > len) {
              // Choose [a,b,e]
              ori1 = orient3d(pa, pb, pe, fc->seg[0]);
              ori2 = orient3d(pa, pb, pe, fc->seg[1]);
            } else {
              // Choose [a,b,d]
              ori1 = orient3d(pa, pb, pd, fc->seg[0]);
              ori2 = orient3d(pa, pb, pd, fc->seg[1]);
            }
            if ((ori1 == 0) && (ori2 == 0)) {
              calculateabovepoint4(pa, pb, pe, pd);
              for (i = 0; i < 3; i++) {
                abovept[i] = dummypoint[i];
              }
              intflag = tri_edge_test(pe, pd, abovept, fc->seg[0], fc->seg[1], 
                                      NULL, 1, types, poss);
              if (intflag == 2) {
                dir = (enum interresult) types[0];
                assert(dir != ACROSSFACE);
                if (dir == ACROSSEDGE) {
                  if (poss[0] == 0) {
                    // The interior of [e,d] intersect the segment.
                    // Since [e,d] is the newly created edge. Reject this flip.
                    rejflag = 1;
                  }
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                }
              } else if (intflag == 4) {
                // [e,d,abovept] is coplanar with the constraining edge 'fc'.
                // This is poissible if the edge in 'fc' is just the edge [e,d]
                //   (SHAREEDGE) or they share a common vertex (SHAREVEER)
                dir = (enum interresult) types[0];
                if (dir == ACROSSEDGE) {
                  // This case can only happen if [e,d] is coplanar with 'fc'.
                  assert(0);  // Not possible.
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                }
              }
            }
          } // if (pc == dummypoint)
        } else if (fliptype == 2) {
          // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
          if (pc != dummypoint) {
            if (0) {
              // Make sure that [a,b,c] is a valid face.      
              facenormal(pa, pb, pc, normal, 1, &len);
              area = sqrt(DOT(normal, normal));
              if (area == 0) {
                rejflag = 1; // A degenerate face.
              } else {
                if ((area / (len * len)) < b->epsilon) {
                  rejflag = 1; // A nearly degenerate face.
                }
              }
            }
            if (!rejflag) {
              // Check if the new face [a,b,c] intersect the edge in its interior.
              intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL, 
                                      1, types, poss);
              if (intflag == 2) {
                // They intersect at a single point.
                dir = (enum interresult) types[0];
                if (dir == ACROSSFACE) {
                  // The interior of [a,b,c] intersect the segment.
                  rejflag = 1; // Do not flip.
                } else if (dir == ACROSSEDGE) {
                  // This case is possible since we allow a previous 2-to-3 flip
                  //   even it will create a degenerate tet at edge [a,b].
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                }
              } else if (intflag == 4) {
                // [a,b,c] is coplanar with the edge. 
                dir = (enum interresult) types[0];
                if (dir == ACROSSEDGE) {
                  // The boundary of [a,b,c] intersect the segment.
                  // An example is found in case 'camila.poly', during the recovery
                  //   of segment [151, 161] (at linklevel = 2). See: 2011-06-10-a.
                  rejflag = 1; // Do not flip.
                }
              }
            } // if (!relflag)
          } else { // pc == dummypoint
            // The flip 3-to-2 will replace [e,d] with a new hull edge [a,b].
            // Only do flip if [a,b] does not intersect the edge of 'fc'.
            // Comment: Here we acutually need a 3D edge-edge intersection test.
            //   We only do test if the edge in 'fc' is coplanar with the plane
            //   containing a,b,e, and d.
            // Choose a better triangle [a,b,e] or [a,b,d].
            facenormal(pa, pb, pe, normal, 1, &len);
            area = sqrt(DOT(normal, normal));
            facenormal(pa, pb, pd, normal, 1, &len);
            len = sqrt(DOT(normal, normal)); // Re-use len as area.
            if (area > len) {
              // Choose [a,b,e]
              ori1 = orient3d(pa, pb, pe, fc->seg[0]);
              ori2 = orient3d(pa, pb, pe, fc->seg[1]);
            } else {
              // Choose [a,b,d]
              ori1 = orient3d(pa, pb, pd, fc->seg[0]);
              ori2 = orient3d(pa, pb, pd, fc->seg[1]);
            }
            if ((ori1 == 0) && (ori2 == 0)) {
              // The edge in 'fc' is coplanar with the plane containing [a,b,e,d].
              calculateabovepoint4(pa, pb, pe, pd);
              for (i = 0; i < 3; i++) {
                abovept[i] = dummypoint[i];
              }
              intflag = tri_edge_test(pa, pb, abovept, fc->seg[0], fc->seg[1], 
                                      NULL, 1, types, poss);
              if (intflag == 2) {
                dir = (enum interresult) types[0];
                assert(dir != ACROSSFACE);
                if (dir == ACROSSEDGE) {
                  assert(0); // Check this case.
                  rejflag = 1; // Do not flip.
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                }
              } else if (intflag == 4) {
                // The edge 'fc' is coplanar with [a,b,abovept]. 
                // This is poissible if the edge in 'fc' is just the edge [a,b]
                //   (SHAREEDGE) or they share a common vertex (SHAREVEER)
                dir = (enum interresult) types[0];
                if (dir == ACROSSEDGE) {
                  // This case can only happen if [a,b] is coplanar with 'fc'.
                  assert(0);  // Not possible.
                } else {
                  if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || 
                      (dir == TOUCHFACE)) {
                    assert(0); // Check this case.
                  }
                }
              }
            } // if (ori1 == 0 && ori2 == 0)
          }
        } else {
          assert(0); // An unknown flip type.
        }
      } // if (fc->seg[0] != NULL)
    
      if ((fc->fac[0] != NULL) && !rejflag) {
        // A constraining face is given (e.g., for face recovery).
        if (fliptype == 1) {
          // A 2-to-3 flip.
          // Test if the new edge [e,d] intersects the face.
          intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd, 
                                  NULL, 1, types, poss);
          if (intflag == 2) {
            // They intersect at a single point.
            dir = (enum interresult) types[0];
            if (dir == ACROSSFACE) {
              rejflag = 1;
            } else if (dir == ACROSSEDGE) {
              rejflag = 1;
            } else {
              if ((dir == ACROSSVERT) || (dir == TOUCHEDGE) || (dir == TOUCHFACE)) {
                assert(0); // Check this case.
              }
            }
          } else if (intflag == 4) {
            // The edge [e,d] is coplanar with the face.
            // There may be two intersections.
            for (i = 0; i < 2 && !rejflag; i++) {
              dir = (enum interresult) types[i];
              if (dir == ACROSSFACE) {
                rejflag = 1;
              } else if (dir == ACROSSEDGE) {
                rejflag = 1;
              }
            }
          }
        } // if (fliptype == 1)
      } // if (fc->fac[0] != NULL)
    
      if ((fc->remvert != NULL) && !rejflag) {
        // The vertex is going to be removed. Do not create a new edge which
        //   contains this vertex.
        if (fliptype == 1) {
          // A 2-to-3 flip.
          if ((pd == fc->remvert) || (pe == fc->remvert)) {
            rejflag = 1;
          }
        }
      }
    
      if (fc->remove_large_angle && !rejflag) {
        // Remove a large dihedral angle. Do not create a new small angle.
        REAL cosmaxd = 0, diff;
        if (fliptype == 1) {
          // We assume that neither 'a' nor 'b' is dummypoint.
          assert((pa != dummypoint) && (pb != dummypoint)); // SELF_CHECK
          // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
          // The new tet [e,d,a,b] will be flipped later. Only two new tets:
          //   [e,d,b,c] and [e,d,c,a] need to be checked.
          if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
            // Get the largest dihedral angle of [e,d,b,c].
            tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
            diff = cosmaxd - fc->cosdihed_in;
            if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
            if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
              rejflag = 1;
            } else {
              // Record the largest new angle.
              if (cosmaxd < fc->cosdihed_out) {
                fc->cosdihed_out = cosmaxd; 
              }
              // Get the largest dihedral angle of [e,d,c,a].
              tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
              diff = cosmaxd - fc->cosdihed_in;
              if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
              if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
                rejflag = 1;
              } else {
                // Record the largest new angle.
                if (cosmaxd < fc->cosdihed_out) {
                  fc->cosdihed_out = cosmaxd; 
                }
              }
            }
          } // if (pc != dummypoint && ...)
        } else if (fliptype == 2) {
          // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
          // We assume that neither 'e' nor 'd' is dummypoint.
          assert((pe != dummypoint) && (pd != dummypoint)); // SELF_CHECK
          if (level == 0) {
            // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
            if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
              // Get the largest dihedral angle of [a,b,c,d].
              tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
              diff = cosmaxd - fc->cosdihed_in;
              if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
              if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
                rejflag = 1;
              } else {
                // Record the largest new angle.
                if (cosmaxd < fc->cosdihed_out) {
                  fc->cosdihed_out = cosmaxd; 
                }
                // Get the largest dihedral angle of [b,a,c,e].
                tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
                diff = cosmaxd - fc->cosdihed_in;
                if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
                if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
                  rejflag = 1;
                } else {
                  // Record the largest new angle.
                  if (cosmaxd < fc->cosdihed_out) {
                    fc->cosdihed_out = cosmaxd; 
                  }
                }
              }
            }
          } else { // level > 0
            assert(edgepivot != 0);
            if (edgepivot == 1) {
              // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
              if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
                // Get the largest dihedral angle of [b,a,c,e].
                tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
                diff = cosmaxd - fc->cosdihed_in;
                if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
                if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
                  rejflag = 1;
                } else {
                  // Record the largest new angle.
                  if (cosmaxd < fc->cosdihed_out) {
                    fc->cosdihed_out = cosmaxd; 
                  }
                }
              }
            } else {
              assert(edgepivot == 2);
              // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
              if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
                // Get the largest dihedral angle of [b,a,c,e].
                tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
                diff = cosmaxd - fc->cosdihed_in;
                if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
                if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
                  rejflag = 1;
                } else {
                  // Record the largest new angle.
                  if (cosmaxd < fc->cosdihed_out) {
                    fc->cosdihed_out = cosmaxd; 
                  }
                }
              }
            } // edgepivot
          } // level
        }
      }
    
      return rejflag;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // removeedgebyflips()    Remove an edge by flips.                           //
    //                                                                           //
    // 'flipedge' is a non-convex or flat edge [a,b,#,#].                        //
    //                                                                           //
    // The return value is a positive integer, it indicates whether the edge is  //
    // removed or not.  A value "2" means the edge is removed, othereise, the    //
    // edge is not removed and the value (must >= 3) is the current number of    //
    // tets in the edge star.                                                    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
    {
      triface *abtets, spintet;
      face checkseg, *paryseg;
      int counter; // DEBUG
      int n, nn, i;
    
    
      // Bakup valuses (for free spaces in flipnm_post()).
      int bakunflip = fc->unflip;
      int bakcollectnewtets = fc->collectnewtets;
    
    
      if (b->verbose > 2) {
        printf("      Removing edge (%d, %d)\n", pointmark(org(*flipedge)), 
               pointmark(dest(*flipedge)));
      }
    
      //if (fc != NULL) {
        fc->clearcounters();
      //}
    
      if (checksubsegflag) {
        // Do not flip a segment.
        tsspivot1(*flipedge, checkseg);
        if (checkseg.sh != NULL) {
          if (b->verbose > 2) {
            printf("      Can't flip a segment (%d, %d).\n", 
                   pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); 
          }
          //if (fc != NULL) {
            fc->encsegcount++;
            if (fc->collectencsegflag) {
              if (!sinfected(checkseg)) {
                // Queue this segment in list.
                sinfect(checkseg);                
                caveencseglist->newindex((void **) &paryseg);
                *paryseg = checkseg;
              }
            }
          //}
          return 0;
        }
      }
    
      // Count the number of tets at edge [a,b].
      n = 0;
      counter = 0; // Sum of star counters;
      spintet = *flipedge;
      i = 0;
      while (1) {
        counter += elemcounter(spintet);
        i++;
        fnextself(spintet);
        if (spintet.tet == flipedge->tet) break;
      }
      //assert(i >= 3);
      if (i < 3) {
        // It is only possible when the mesh contains inverted tetrahedra.  
        assert(checkinverttetflag);
        // Since "return 2" means success, we return 0.
        return 0;
      }
      assert(counter == 0); // SELF_CHECK
      n = i;
    
      flipstarcount++;
      // Record the maximum star size.
      if (n > maxflipstarsize) {
        maxflipstarsize = n;
      }
      if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
        // The star size exceeds the given limit (-YY__).
        skpflipstarcount++;
        return 0; // Do not flip it.
      }
    
      // Allocate spaces.
      abtets = new triface[n];
      // Collect the tets at edge [a,b].
      spintet = *flipedge;
      i = 0;
      while (1) {
        abtets[i] = spintet;
        //marktest(abtets[i]); // Marktest it (in Star(ab)).
        setelemcounter(abtets[i], 1);
        i++;
        fnextself(spintet);
        if (spintet.tet == flipedge->tet) break;
      }
    
    
      // Try to flip the edge (level = 0, edgepivot = 0).
      nn = flipnm(abtets, n, 0, 0, fc);
    
    
      if (nn == 2) {
        // Edge is flipped.
        if (b->verbose > 2) {
          printf("      Edge is removed.\n");
        }
      } else {
        // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
        for (i = 0; i < nn; i++) {
          //assert(marktested(abtets[i]));
          //unmarktest(abtets[i]);
          assert(elemcounter(abtets[i]) == 1);
          setelemcounter(abtets[i], 0);
        }
        if (b->verbose > 2) {
          printf("      Edge is not removed. n(%d), nn(%d).\n", n, nn);
        }
        // Restore the input edge (needed by Lawson's flip).
        *flipedge = abtets[0];
      }
    
      // Release the temporary allocated spaces.
      // NOTE: fc->unflip must be 0.
      fc->unflip = 0;
      fc->collectnewtets = 0;
    
      flipnm_post(abtets, n, nn, 0, fc);
    
      fc->unflip = bakunflip;
      fc->collectnewtets = bakcollectnewtets;
    
      delete [] abtets;
    
      return nn; //return nn == 2;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // removefacebyflips()    Remove a face by flips.                            //
    //                                                                           //
    // ASSUMPTIONS:                                                              //
    //   - 'flipface' must not be a hull face.                                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
    {
      triface fliptets[3], flipedge;
      face checksh;
      point pa, pb, pc, pd, pe;
      point pts[3];
      enum interresult dir;
      int types[2], poss[4], pos;
      REAL ori;
      int reducflag, rejflag;
      int i, j;
    
      if (checksubfaceflag) {
        tspivot(*flipface, checksh);
        if (checksh.sh != NULL) {
          if (b->verbose > 2) {
            printf("      Can't flip a subface.\n"); 
          }
          return 0;
        }
      }
    
      fliptets[0] = *flipface;
      fsym(*flipface, fliptets[1]);
    
      assert(!ishulltet(fliptets[0]));
      assert(!ishulltet(fliptets[1]));
    
      pa = org(fliptets[0]);
      pb = dest(fliptets[0]);
      pc = apex(fliptets[0]);
      pd = oppo(fliptets[0]);
      pe = oppo(fliptets[1]);
    
      if (b->verbose > 2) {
        printf("      Removing face (%d, %d, %d) -- %d, %d\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
      }
    
      reducflag = 0;
    
      ori = orient3d(pa, pb, pd, pe);
      if (ori > 0) {
        ori = orient3d(pb, pc, pd, pe);
        if (ori > 0) {
          ori = orient3d(pc, pa, pd, pe);
          if (ori > 0) {
            // Found a 2-to-3 flip.
            reducflag = 1;
          } else {
            eprev(*flipface, flipedge); // [c,a]
          }
        } else {
          enext(*flipface, flipedge); // [b,c]
        }
      } else {
        flipedge = *flipface; // [a,b]
      }
    
      if (reducflag) {
        // A 2-to-3 flip is found.
        rejflag = 0;
        if (fc != NULL) {
          //rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, fc);
        }
        if (!rejflag) {
          flip23(fliptets, 0, 0, 0);
          if (b->verbose > 2) {
            printf("      Face is removed by a 2-to-3 flip.\n");
          }
          return 1;
        } else {
          if (b->verbose > 2) {
            printf("      -- Reject a 2-to-3 flip at face (%d, %d, %d)\n",
                   pointmark(pa), pointmark(pb), pointmark(pc));
          }
          if (fc != NULL) {
            fc->rejf23count++;
          }
        }
      } else {
        if (0) {
          // Try to flip one of the edges of this face.
          pts[0] = org(flipedge);
          pts[1] = dest(flipedge);
          pts[2] = apex(flipedge);
          // Start from the recorded locally non-convex edge 'flipedge'.
          for (i = 0; i < 3; i++) {
            if (removeedgebyflips(&flipedge, fc) == 2) {
              if (b->verbose > 2) {
                printf("      Face is removed by removing edge (%d, %d).\n",
                       pointmark(pts[i]), pointmark(pts[(i+1)%3]));
              }
              return 1;
            }
            // The 'flipedge' may be dead in above call.
            point2tetorg(pts[i], flipedge);
            finddirection(&flipedge, pts[(i+1)%3], 1);
            if (dest(flipedge) != pts[(i+1)%3]) {
              if (b->verbose > 2) {
                printf("      Face is removed during removing edge (%d, %d).\n",
                       pointmark(pts[i]), pointmark(pts[(i+1)%3]));
              }
              return 1;
            }
          } // i
        } else {
          if (0) { //if (fc->seg[0] != NULL) {
            // The face is intersecting a segment.
            // Find the edge shared by three corssing faces.
            // We assume that the 'flipface' is facing to 'fc->seg[0]'. It is the
            //   case when the function is called from 'recoveredgebyflips()'.
            // DEBUG BEGIN
            pa = org(*flipface);
            pb = dest(*flipface);
            pc = apex(*flipface);
            ori = orient3d(pa, pb, pc, fc->seg[0]);
            assert(ori < 0);
            // DEBUG END
            fsym(*flipface, flipedge);
            pc = oppo(flipedge);
            for (i = 0; i < 3; i++) {
              pa = org(flipedge);
              pb = dest(flipedge);
              if (tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL, 1, 
                                types, poss)) {
                dir = (enum interresult) types[0];
                if (dir == ACROSSFACE) {
                  break; // Found the crossing face.
                } else if (dir == ACROSSEDGE) {
                  // Found an edge intersects the segment.
                  esymself(flipedge);
                  pos = poss[0];
                  for (j = 0; j < pos; j++) {
                    eprevself(flipedge);
                  }
                  // Flip this edge.
                  break;
                } else if (dir == SHAREVERT) {
                  // We have reached the endpoint of the segment.
                  assert(pc == fc->seg[1]);
                  // The face is not flippable.
                  return 0;
                } else {
                  assert(0);  // Not possible.
                }
              }
              enextself(flipedge);
            }
            assert(i < 3);
          } else {
            if (b->verbose > 2) {
              pa = org(flipedge);
              pb = dest(flipedge);
            }
          }
          // Try to flip the selected edge of this face.
          if (removeedgebyflips(&flipedge, fc) == 2) {
            if (b->verbose > 2) {
              printf("      Face is removed by removing edge (%d, %d).\n",
                     pointmark(pa), pointmark(pb));
            }
            return 1;
          }
        }
      }
    
      // Face is not removed.
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // recoveredge()    Recover an edge in current tetrahedralization.           //
    //                                                                           //
    // If the edge is recovered, 'searchtet' returns a tet containing the edge.  //
    //                                                                           //
    // This edge may intersect a set of faces and edges in the mesh.  All these  //
    // faces or edges are needed to be flipped.                                  //
    //                                                                           //
    // If the parameter 'fullsearch' is set, it tries to flip any face or edge   //
    // that intersects the recovering edge.  Otherwise, only the face or edge    //
    // which is visible by 'startpt' is tried.                                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::recoveredgebyflips(point startpt, point endpt, 
                                       triface* searchtet, int fullsearch)
    {
      triface neightet, spintet; // *abtets;
      point pa, pb, pc, pd;
      badface bakface;
      enum interresult dir, dir1;
      flipconstraints fc;
      int types[2], poss[4], pos = 0;
      int success;
      //int n, endi;
      int i, j; //, k;
    
      if (b->verbose > 2) {
        printf("      Recovering edge (%d, %d)\n", pointmark(startpt), 
               pointmark(endpt));
      }
    
    
      fc.seg[0] = startpt;
      fc.seg[1] = endpt;
    
      // The mainloop of the edge reocvery.
      while (1) { // Loop I
    
        // Search the edge from 'startpt'.
        point2tetorg(startpt, *searchtet);
        assert(org(*searchtet) == startpt); // SELF_CHECK
        dir = finddirection(searchtet, endpt, 1);
        if (dir == ACROSSVERT) {
          if (dest(*searchtet) == endpt) {
            return 1; // Edge is recovered.
          } else {
            // A PLC problem, or there is a Steiner point.
            terminatetetgen(3); //assert(0); // Debug
          }
        }
    
        // The edge is missing. 
    
        // Try to flip the first intersecting face/edge.
        enextesymself(*searchtet); // Go to the opposite face.
        if (dir == ACROSSFACE) {
          // A face is intersected with the segment. Try to flip it.
          if (removefacebyflips(searchtet, &fc)) {
            continue;
          }
        } else if (dir == ACROSSEDGE) {
          // An edge is intersected with the segment. Try to flip it.
          if (removeedgebyflips(searchtet, &fc) == 2) {
            continue;
          }
        } else {
          terminatetetgen(3); //assert(0); // A PLC problem.
        }
    
        // The edge is missing.
    
        if (fullsearch) {
    
          if (1) {
            // Try to flip one of the faces/edges which intersects the edge.
            success = 0;
    
            // Loop through the sequence of intersecting faces/edges from
            //   'startpt' to 'endpt'.
            point2tetorg(startpt, *searchtet);
            assert(org(*searchtet) == startpt); // SELF_CHECK
            dir = finddirection(searchtet, endpt, 1);
            assert(dir != ACROSSVERT);
    
            // Go to the face/edge intersecting the searching edge.
            enextesymself(*searchtet); // Go to the opposite face.
            // This face/edge has been tried in previous step.
    
            while (1) { // Loop I-I
    
              // Find the next intersecting face/edge.
              fsymself(*searchtet);
              if (dir == ACROSSFACE) {
                neightet = *searchtet;
                j = (neightet.ver & 3); // j is the current face number.
                for (i = j + 1; i < j + 4; i++) {
                  neightet.ver = (i % 4);
                  pa = org(neightet);
                  pb = dest(neightet);
                  pc = apex(neightet);
                  pd = oppo(neightet); // The above point.
                  if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
                    dir = (enum interresult) types[0];
                    pos = poss[0];
                    break;
                  } else {
                    dir = DISJOINT;
                    pos = 0;
                  }
                } // i
                // There must be an intersection face/edge.
                assert(dir != DISJOINT);  // SELF_CHECK
              } else {
                assert(dir == ACROSSEDGE);
                while (1) { // Loop I-I-I
                  // Check the two opposite faces (of the edge) in 'searchtet'.  
                  for (i = 0; i < 2; i++) {
                    if (i == 0) {
                      enextesym(*searchtet, neightet);
                    } else {
                      eprevesym(*searchtet, neightet);
                    }
                    pa = org(neightet);
                    pb = dest(neightet);
                    pc = apex(neightet);
                    pd = oppo(neightet); // The above point.
                    if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
                      dir = (enum interresult) types[0];
                      pos = poss[0];
                      break; // for loop
                    } else {
                      dir = DISJOINT;
                      pos = 0;
                    }
                  } // i
                  if (dir != DISJOINT) {
                    // Find an intersection face/edge.
                    break;  // Loop I-I-I
                  }
                  // No intersection. Rotate to the next tet at the edge.
                  fnextself(*searchtet);
                } // while (1) // Loop I-I-I
              }
    
              // Adjust to the intersecting edge/vertex.
              for (i = 0; i < pos; i++) {
                enextself(neightet);
              }
    
              if (dir == SHAREVERT) {
                // Check if we have reached the 'endpt'.
                pd = org(neightet);
                if (pd == endpt) {
                  // Failed to recover the edge.
                  break; // Loop I-I
                } else {
                  // We need to further check this case. It might be a PLC problem
                  //   or a Steiner point that was added at a bad location.
                  assert(0);
                }
              }
    
              // The next to be flipped face/edge.
              *searchtet = neightet;
    
              // Bakup this face (tetrahedron).
              bakface.forg = org(*searchtet);
              bakface.fdest = dest(*searchtet);
              bakface.fapex = apex(*searchtet);
              bakface.foppo = oppo(*searchtet);
    
              // Try to flip this intersecting face/edge.
              if (dir == ACROSSFACE) {
                if (removefacebyflips(searchtet, &fc)) {
                  success = 1;
                  break; // Loop I-I 
                }
              } else if (dir == ACROSSEDGE) {
                if (removeedgebyflips(searchtet, &fc) == 2) {
                  success = 1;
                  break; // Loop I-I
                }
              } else {
                assert(0); // A PLC problem.
              }
    
              // The face/edge is not flipped.
              if ((searchtet->tet == NULL) ||
                  (org(*searchtet) != bakface.forg) ||
                  (dest(*searchtet) != bakface.fdest) ||
                  (apex(*searchtet) != bakface.fapex) ||
                  (oppo(*searchtet) != bakface.foppo)) {
                // 'searchtet' was flipped. We must restore it.
                point2tetorg(bakface.forg, *searchtet);
                dir1 = finddirection(searchtet, bakface.fdest, 1);
                if (dir1 == ACROSSVERT) {
                  assert(dest(*searchtet) == bakface.fdest);
                  spintet = *searchtet;
                  while (1) {
                    if (apex(spintet) == bakface.fapex) {
                      // Found the face.
                      *searchtet = spintet;
                      break;
                    }
                    fnextself(spintet);
                    if (spintet.tet == searchtet->tet) {
                      searchtet->tet = NULL;
                      break; // Not find.
                    }
    	      } // while (1)
                  if (searchtet->tet != NULL) {
                    if (oppo(*searchtet) != bakface.foppo) {
                      fsymself(*searchtet);
                      if (oppo(*searchtet) != bakface.foppo) {
                        assert(0); // Check this case.
                        searchtet->tet = NULL;
                        break; // Not find.
                      }
                    }
                  }
                } else {
                  searchtet->tet = NULL; // Not find.
                }
                if (searchtet->tet == NULL) {
                  success = 0; // This face/edge has been destroed.
                  break; // Loop I-I 
                }
              }
            } // while (1) // Loop I-I
    
            if (success) {
              // One of intersecting faces/edges is flipped.
              continue;
            }
          } // if (0)
    
        } // if (fullsearch)
    
        // The edge is missing.
        break; // Loop I
    
      } // while (1) // Loop I
    
      // The edge is not recovered.
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // add_steinerpt_in_schoenhardtpoly()    Insert a Steiner point in a Schoen- //
    //                                       hardt polyhedron.                   //
    //                                                                           //
    // 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
    // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)].  Moreover, //
    // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'.  A special  //
    // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b].       //
    //                                                                           //
    // These set of tets arises when we want to recover an edge from 'p0' to 'p_ //
    // (n-1)', and the recoveredgenbyflips() routine fails.  Note that the outer //
    // faces of these tets defines a polyhedron P, and the set of tets gives the //
    // ONLY tetrahedralization of P.  If we replace the two boundary faces [a,b, //
    // p0] and [a,b,p_(n-1)] by [p0,p_(n-1),a] and [p0,p_(n-1),b], and call the  //
    // new polyhedron P'. In this routine, we think P' is not tetrahedralizable  //
    // (since the routine recoveredgenbyflips() fails!! AND no flip is possible  //
    // on any of these edges: [a,p1], [b,p1], [a,p2], [b,p2], ..., [a,p_(n-2)],  //
    // and [b,p_(n-1)]). If n = 3, P' is just the famous Schoenhardt polyhedron. //
    // For n > 3, we call P' the generalized Schoenhardt polyhedron, it includes //
    // the Bagemihl's polyhedron as a special case.                              //
    //                                                                           //
    // It is obvious that P is a Star-shaped polyhedron. The mid-point of [a,b]  //
    // is visible by all boundary faces of P, push it slightly inside P does not //
    // change the visibilty. Indeed every interior point of [a,b] is visible by  //
    // the boundary faces of P.                                                  //
    //                                                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
                                                     int chkencflag)
    {
      triface worktet, *parytet;
      triface faketet1, faketet2;
      point pa, pb, pc, pd;
      point p1, p2, p3;
      point steinerpt;
      insertvertexflags ivf;
      optparameters opm;
      REAL vcd[3], sampt[3], smtpt[3];
      REAL maxminvol = 0.0, minvol = 0.0, ori;
      int success, maxidx = 0;
      int loc;
      int it, i;
    
      if (b->verbose > 2) {
        printf("      Find a Steiner in Schoenhardt polyhedron (n=%d).\n", n);
      }
    
      pa = org(abtets[0]);
      pb = dest(abtets[0]);
      pc = apex(abtets[0]);   // pc = p0
      pd = oppo(abtets[n-1]); // pd = p_(n-1)
    
      // Find an optimial point in edge [c,d]. It is visible by all outer faces
      //   of 'abtets', and it maxmizes the min volume.
    
      // initialize the list of 2n boundary faces.
      for (i = 0; i < n; i++) {    
        eprev(abtets[i], worktet);
        esymself(worktet); // [a,p_i,p_i+1].
        cavetetlist->newindex((void **) &parytet);
        *parytet = worktet;
        enext(abtets[i], worktet);
        esymself(worktet); // [p_i,b,p_i+1].
        cavetetlist->newindex((void **) &parytet);
        *parytet = worktet;
      }
    
      // Search the point along the edge [c,d].
      for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
    
      // Sample 100 points in edge [c,d].
      for (it = 1; it < 100; it++) {
        for (i = 0; i < 3; i++) {
          sampt[i] = pc[i] + (0.01 * (double) it) * vcd[i];
        }
        for (i = 0; i < cavetetlist->objects; i++) {
          parytet = (triface *) fastlookup(cavetetlist, i);
          p1 = org(*parytet);
          p2 = dest(*parytet);
          p3 = apex(*parytet);
          ori = orient3d(p2, p1, p3, sampt);
          if (i == 0) {
            minvol = ori;
          } else {
            if (minvol > ori) minvol = ori;
          }
        } // i
        if (it == 1) {
          maxminvol = minvol;
          maxidx = it;
        } else {
          if (maxminvol < minvol) {
            maxminvol = minvol;
            maxidx = it;
          } 
        }
      } // it
    
      if (maxminvol <= 0) {
        if (b->verbose > 2) {
          printf("      Unable to find a initial point: maxminvol = %g\n", 
                 maxminvol);
        }
        cavetetlist->restart();
        return 0;
      }
    
      for (i = 0; i < 3; i++) {
        smtpt[i] = pc[i] + (0.01 * (double) maxidx) * vcd[i];
      }
    
      // Create two faked tets to hold the two non-existing boundary faces:
      //   [d,c,a] and [c,d,b].
      maketetrahedron(&faketet1);
      setvertices(faketet1, pd, pc, pa, dummypoint);
      cavetetlist->newindex((void **) &parytet);
      *parytet = faketet1;
      maketetrahedron(&faketet2);
      setvertices(faketet2, pc, pd, pb, dummypoint);
      cavetetlist->newindex((void **) &parytet);
      *parytet = faketet2;
    
      // Point smooth options.
      opm.max_min_volume = 1;
      opm.numofsearchdirs = 20;
      opm.searchstep = 0.001;  
      opm.maxiter = 100; // Limit the maximum iterations.
      opm.initval = 0.0; // Initial volume is zero.
    
      // Try to relocate the point into the inside of the polyhedron.
      success = smoothpoint(smtpt, cavetetlist, 1, &opm);
    
      if (success) {
        while (opm.smthiter == 100) {
          // It was relocated and the prescribed maximum iteration reached. 
          // Try to increase the search stepsize.
          opm.searchstep *= 10.0;
          //opm.maxiter = 100; // Limit the maximum iterations.
          opm.initval = opm.imprval;
          opm.smthiter = 0; // Init.
          smoothpoint(smtpt, cavetetlist, 1, &opm);  
        }
      } // if (success)
    
      // Delete the two faked tets.
      tetrahedrondealloc(faketet1.tet);
      tetrahedrondealloc(faketet2.tet);
    
      cavetetlist->restart();
    
      if (!success) {
        if (b->verbose > 2) {
          printf("      Unable to relocate the initial point.\n");
        }
        return 0;
      }
    
    
      // Insert the Steiner point.
      makepoint(&steinerpt, FREEVOLVERTEX);
      for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
    
      // Insert the created Steiner point.
      for (i = 0; i < n; i++) {
        infect(abtets[i]);
        caveoldtetlist->newindex((void **) &parytet);
        *parytet = abtets[i];
      }
      worktet = abtets[0]; // No need point location.
      ivf.iloc = (int) INSTAR;
      ivf.bowywat = 0; // Do not use Bowyer-Watson algorithm.
      ivf.lawson = 0; //  Do not flip.
      ivf.rejflag = 0;
      ivf.chkencflag = chkencflag;
      ivf.sloc = 0;
      ivf.sbowywat = 0;
      ivf.splitbdflag = 0;
      ivf.validflag = 0;
      ivf.respectbdflag = 0;
      ivf.assignmeshsize = 0; 
    
      // Insert the new point into the tetrahedralization T.
      // Note that T is convex (nonconvex = 0).
      loc = insertvertex(steinerpt, &worktet, NULL, NULL, &ivf);
    
      if (loc == (int) INSTAR) {
        // The vertex has been inserted.
        st_volref_count++; //st_inpoly_count++;
        if (steinerleft > 0) steinerleft--;
        return 1;
      } else {
        // The Steiner point is too close to an existing vertex. Reject it.
        pointdealloc(steinerpt);
        return 0;
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // addsteiner4recoversegment()    Add a Steiner point for recoveing a seg.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
    {
      triface *abtets, searchtet, spintet;
      face splitsh;
      face checkseg;
      face *paryseg;
      point startpt, endpt;
      point pa, pb, pd, steinerpt, *parypt;
      enum interresult dir;
      insertvertexflags ivf;
      int types[2], poss[4];
      REAL ip[3], u;
      int n, endi, success;
      int loc;
      int i;
    
      startpt = sorg(*misseg);
      if (pointtype(startpt) == FREESEGVERTEX) {
        sesymself(*misseg);
        startpt = sorg(*misseg);
      }
      endpt = sdest(*misseg);
    
      // Try to recover the edge by adding Steiner points.
      point2tetorg(startpt, searchtet);
      assert(org(searchtet) == startpt); // SELF_CHECK
      dir = finddirection(&searchtet, endpt, 1);
      assert(dir != ACROSSVERT);
    
      // Get the first intersecting face/edge.
      assert(!ishulltet(searchtet));
      enextself(searchtet); 
      //assert(apex(searchtet) == startpt);
    
      if (dir == ACROSSFACE) {
        // The segment is crossing at least 3 faces. Find the common edge of 
        //   the first 3 crossing faces.
        esymself(searchtet);
        assert(oppo(searchtet) == startpt);
        fsym(searchtet, spintet);
        pd = oppo(spintet);
        if (pd == endpt) {
          // This should be possible.
          assert(0); // Debug this case.
        }
        for (i = 0; i < 3; i++) {
          pa = org(spintet);
          pb = dest(spintet);
          //pc = apex(neightet);
          if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
            break; // Found the edge.
          }
          enextself(spintet);
          eprevself(searchtet);
        }
        assert(i < 3);
        esymself(searchtet);        
      } else {
        assert(dir == ACROSSEDGE);
        // PLC check.
        tsspivot1(searchtet, checkseg);
        if (checkseg.sh != NULL) {
          printf("Found two segments intersect each other.\n");
          pa = farsorg(*misseg);
          pb = farsdest(*misseg);
          printf("  1st: [%d,%d] %d.\n", pointmark(pa), pointmark(pb), 
                 shellmark(*misseg));
          pa = farsorg(checkseg);
          pb = farsdest(checkseg);
          printf("  2nd: [%d,%d] %d.\n", pointmark(pa), pointmark(pb), 
                 shellmark(checkseg));
          terminatetetgen(3);
        }
      }
      assert(apex(searchtet) == startpt);
    
      spintet = searchtet;
      n = 0; endi = -1;
      while (1) {
        // Check if the endpt appears in the star.
        if (apex(spintet) == endpt) {
          endi = n; // Remember the position of endpt.
        }
        n++; // Count a tet in the star.
        fnextself(spintet);
        if (spintet.tet == searchtet.tet) break;
      }
      assert(n >= 3);
    
      if (endi > 0) {
        // endpt is also in the edge star
        // Get all tets in the edge star.
        abtets = new triface[n];
        spintet = searchtet;
        for (i = 0; i < n; i++) {
          abtets[i] = spintet;
          fnextself(spintet);
        }
        assert(apex(abtets[0]) == startpt);
        assert(apex(abtets[endi]) == endpt);
    
        success = 0;
    
        if (dir == ACROSSFACE) {
          // Find a Steiner points inside the polyhedron.
          if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
            success = 1;
          }
        } else if (dir == ACROSSEDGE) {
          if (n > 4) {
            // In this case, 'abtets' is separated by the plane (containing the
            //   two intersecting edges) into two parts, P1 and P2, where P1
            //   consists of 'endi' tets: abtets[0], abtets[1], ..., 
            //   abtets[endi-1], and P2 consists of 'n - endi' tets: 
            //   abtets[endi], abtets[endi+1], abtets[n-1].
            if (endi > 2) { // P1
              // There are at least 3 tets in the first part.
              if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
                success++;
              }
            }
            if ((n - endi) > 2) { // P2
              // There are at least 3 tets in the first part.
              if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
                success++;
              }
            }
          } else {
            // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
            //   However, there will be invalid tets (either zero or negtive 
            //   volume). Otherwise, [c,d] should already be recovered by the 
            //   recoveredge() function.
            assert(0); // DEBUG IT
          }
        } else {
          assert(0); // A PLC problem.
        }
    
        delete [] abtets;
    
        if (success) {
          // Add the missing segment back to the recovering list.
          subsegstack->newindex((void **) &paryseg);
          *paryseg = *misseg;
          return 1;
        }
      } // if (endi > 0)
    
      if (!splitsegflag) {
        return 0;
      }
    
      if (b->verbose > 2) {
        printf("      Splitting segment (%d, %d)\n", pointmark(startpt), 
               pointmark(endpt));
      }
    
      if (endi == -1) {
        // Let the missing segment be [a,b]. Let the edge [c,d] whose star contains
        // a and intersects [a,b]. We choose the Steiner point at the intersection
        // of the edge star of [c,d] and [a,b] (not a). 
        if (dir == ACROSSFACE) {
          pa = org(searchtet);
          pb = dest(searchtet);
    
          spintet = searchtet;
          n = 0; endi = -1;
          while (1) {
            n++; // Count a tet in the star.
            fnextself(spintet);
            if (spintet.tet == searchtet.tet) break;
            // Check if the segment leaves the edge star.
            pd = apex(spintet);
            assert(pd != endpt);
            if (!tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
              if (endi == -1)  endi = (n - 1);
            }
          }
          assert(n >= 3);
          assert(endi != -1); 
    
          // 'abtets' is only for debug purpose.
          abtets = new triface[endi];
          spintet = searchtet;
          for (i = 0; i < endi; i++) {
            abtets[i] = spintet;
            fnextself(spintet);
          }
          searchtet = abtets[endi - 1]; 
          esymself(searchtet); // The exit face of [startpt, endpt].
          delete [] abtets;
        } else {
          assert(dir == ACROSSEDGE);
          assert(apex(searchtet) == startpt);
          esymself(searchtet); // The exit face of [startpt, endpt].
          //assert(oppo(searchtet) == startpt);
          pa = org(searchtet);
          pb = dest(searchtet);
        }
    
        pd = apex(searchtet);
        // Get the intersection type (ACROSSFACE or ACROSSEDGE).
        if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
          dir = (enum interresult) types[0];
          assert((dir == ACROSSFACE) || (dir == ACROSSEDGE));
        } else {
          assert(0); // not possible.
        }
    
        // Calculate the intersection of the face [a,b,d] and the segment.
        planelineint(pa, pb, pd, startpt, endpt, ip, &u);
        assert((u > 0) && (u < 1));
    
        // Create a Steiner point.
        makepoint(&steinerpt, FREESEGVERTEX);
        for (i = 0; i < 3; i++) steinerpt[i] = ip[i];
    
    
        spivot(*misseg, splitsh);
        if (dir == ACROSSFACE) {
          ivf.iloc = (int) ONFACE;
        } else {
          ivf.iloc = (int) ONEDGE;
        }
        ivf.bowywat = 1;
        ivf.lawson = 0;
        ivf.rejflag = 0;
        ivf.chkencflag = 0;
        ivf.sloc = (int) ONEDGE;
        ivf.sbowywat = 1;
        ivf.splitbdflag = 0;
        ivf.validflag = 1;
        ivf.respectbdflag = 1;
        ivf.assignmeshsize = 0;
        loc = insertvertex(steinerpt, &searchtet, &splitsh, misseg, &ivf);
    
        if (loc != ivf.iloc) {
          if (loc == (int) NEARVERTEX) {
            // The vertex is rejected. Too close to an existing vertex.
            pointdealloc(steinerpt);
            steinerpt = NULL;
          } else {
            assert(0); // Unknown case. 
          }
        }
      } else { // if (endi > 0)
        steinerpt = NULL;
      }
    
      if (steinerpt == NULL) {
        // Split the segment at its midpoint.
        makepoint(&steinerpt, FREESEGVERTEX);
        for (i = 0; i < 3; i++) {
          steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
        }
    
        // We need to locate the point.
        assert(searchtet.tet != NULL); // Start searching from 'searchtet'.
        spivot(*misseg, splitsh);
        ivf.iloc = (int) OUTSIDE;
        ivf.bowywat = 1;
        ivf.lawson = 0;
        ivf.rejflag = 0;
        ivf.chkencflag = 0;
        ivf.sloc = (int) ONEDGE;
        ivf.sbowywat = 1;
        ivf.splitbdflag = 0;
        ivf.validflag = 1;
        ivf.respectbdflag = 1;
        ivf.assignmeshsize = 0; 
        loc = insertvertex(steinerpt, &searchtet, &splitsh, misseg, &ivf);
    
        assert(loc != (int) ONVERTEX);
        assert(loc != (int) NEARVERTEX);
      } // if (endi > 0)
    
      // Save this Steiner point (for removal).
      //   Re-use the array 'subvertstack'.
      subvertstack->newindex((void **) &parypt);
      *parypt = steinerpt;
    
      st_segref_count++;
      if (steinerleft > 0) steinerleft--;
    
      return 1;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // recoversegments()    Recover all segments.                                //
    //                                                                           //
    // All segments need to be recovered are in 'subsegstack' (Q).  They will be //
    // be recovered one by one.                                                  //
    //                                                                           //
    // Each segment is first tried to be recovered by a sequence of flips which  //
    // removes faces intersecting this segment. However, it is not always possi- //
    // ble to recover it by only this way. Then, Steiner points will be added to //
    // help the recovery of it by flips.                                         // 
    //                                                                           //
    // If 'steinerflag' is set, Steiner points will be added if a segment is not //
    // able to recovered by flips.  Otherwise, the segment is not recovered, and //
    // it is returned in 'misseglist'.                                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
                                    int steinerflag)
    {
      triface searchtet, spintet;
      face sseg, checkseg, *paryseg;
      point startpt, endpt;
      int success;
    
      long bak_inpoly_count = st_volref_count; //st_inpoly_count;
    
      if (b->verbose > 1) {
        printf("    Recover segments [%s level = %2d] #:  %ld.\n",
               (b->fliplinklevel > 0) ? "fixed" : "auto",
               (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
               subsegstack->objects);
      }
    
      // Loop until 'subsegstack' is empty.
      while (subsegstack->objects > 0l) {
        // seglist is used as a stack.
        subsegstack->objects--;
        paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
        sseg = *paryseg;
    
        // Check if this segment has been recovered.
        sstpivot1(sseg, searchtet);
        if (searchtet.tet != NULL) {
          continue; // Not a missing segment.
        }
    
        startpt = sorg(sseg);
        endpt = sdest(sseg);
    
        if (b->verbose > 2) {
          printf("      Recover segment (%d, %d).\n", pointmark(startpt), 
                 pointmark(endpt));
        }
    
        success = 0;
    
        if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
          success = 1;
        } else {
          // Try to recover it from the other direction.
          if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
            success = 1;
          }
        }
    
        if (!success && fullsearch) {
          if (recoveredgebyflips(startpt, endpt, &searchtet, fullsearch)) {
            success = 1;
          }
        }
    
        if (success) {
          // Segment is recovered. Insert it.
          tsspivot1(searchtet, checkseg);  // SELF_CHECK
          assert(checkseg.sh == NULL);
          // Let the segment remember an adjacent tet.
          sstbond1(sseg, searchtet);
          // Bond the segment to all tets containing it.
          spintet = searchtet;
          do {
            tssbond1(spintet, sseg);
            fnextself(spintet);
          } while (spintet.tet != searchtet.tet);
        } else {
          if (steinerflag > 0) {
            // Try to recover the segment but do not split it.
            if (addsteiner4recoversegment(&sseg, 0)) {
              success = 1;
            }
            if (!success && (steinerflag > 1)) {
              // Split the segment.
              addsteiner4recoversegment(&sseg, 1);
              success = 1;
            }
          }
          if (!success) {
            if (misseglist != NULL) {
              // Save this segment.
              misseglist->newindex((void **) &paryseg);
              *paryseg = sseg;
            }
          }
        }
    
      } // while (subsegstack->objects > 0l)
    
      if (steinerflag) {
        if (b->verbose > 1) {
          // Report the number of added Steiner points.
          if (st_volref_count > bak_inpoly_count) {
            printf("    Add %ld Steiner points in volume.\n", 
                   st_volref_count - bak_inpoly_count);
          }
        }
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // recoverfacebyflips()    Recover a face by flips.                          //
    //                                                                           //
    // If 'searchsh' is not NULL, it is a subface to be recovered.  It is only   //
    // used for checking self-intersections.                                     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc, 
                                       face *searchsh, triface* searchtet)
    {
      triface spintet, flipedge;
      face checkseg;
      point pd, pe;
      enum interresult dir;
      flipconstraints fc;
      int success, success1;
      int i, j;
    
      int intflag;
      int types[2], poss[4];
    
      if (b->verbose > 2) {
        printf("      Recovering face (%d, %d, %d) by flips\n", pointmark(pa), 
               pointmark(pb), pointmark(pc));
      }
    
    
      fc.fac[0] = pa;
      fc.fac[1] = pb;
      fc.fac[2] = pc;
      success = 0;
    
      for (i = 0; i < 3 && !success; i++) {
        while (1) {
          // Get a tet containing the edge [a,b].
          point2tetorg(fc.fac[i], *searchtet);
          assert(org(*searchtet) == fc.fac[i]); // SELF_CHECK
          dir = finddirection(searchtet, fc.fac[(i+1)%3], 1);
          //assert(dir == ACROSSVERT);
          assert(dest(*searchtet) == fc.fac[(i+1)%3]);
          // Search the face [a,b,c]
          spintet = *searchtet;
          while (1) {
            if (apex(spintet) == fc.fac[(i+2)%3]) {
              // Found the face.
              *searchtet = spintet;
              // Return the face [a,b,c].
              for (j = i; j > 0; j--) {
                eprevself(*searchtet);
              }
              success = 1;
              break;
            }
            fnextself(spintet);
            if (spintet.tet == searchtet->tet) break;
          } // while (1)
          if (success) break;
          // The face is missing. Try to recover it.
          success1 = 0;
          // Find a crossing edge of this face.
          spintet = *searchtet;
          while (1) {
            pd = apex(spintet);
            pe = oppo(spintet);
            if ((pd != dummypoint) && (pe != dummypoint)) {
              // Check if [d,e] intersects [a,b,c]
              intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
              if (intflag > 0) {
                // By our assumptions, they can only intersect at a single point.
                if (intflag == 2) {
                  // Check the intersection type.
                  dir = (enum interresult) types[0];
                  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
                    // Go to the edge [d,e].
                    eprev(spintet, flipedge);
                    esymself(flipedge);
                    enextself(flipedge); // [d,e,a,b].
                    if (searchsh != NULL) {
                      // Check if [e,d] is a segment.
                      tsspivot1(flipedge, checkseg);
                      if (checkseg.sh != NULL) {
                        if (!b->quiet) {                    
                          printf("Found a segment and a subface intersect.\n");
                          pd = farsorg(checkseg);
                          pe = farsdest(checkseg);
                          printf("  1st: [%d, %d] %d.\n",  pointmark(pd), 
                                 pointmark(pe), shellmark(checkseg)); 
                          printf("  2nd: [%d,%d,%d] %d\n", pointmark(pa), 
                            pointmark(pb), pointmark(pc), shellmark(*searchsh));
    	            }
                        terminatetetgen(3);
    		  }
                    }
                    // Try to flip the edge [d,e].
                    success1 = (removeedgebyflips(&flipedge, &fc) == 2);
                  } else {
                    if (dir == TOUCHFACE) {
                      point touchpt, *parypt;
                      if (poss[0] == 0) {
                        touchpt = pd; // pd is a coplanar vertex.
                      } else {
                        touchpt = pe; // pe is a coplanar vertex.
                      }
                      if (pointtype(touchpt) == FREEVOLVERTEX) {
                        // A volume Steiner point was added in this subface.
                        // Split this subface by this point.
                        if (b->verbose > 2) {
                          printf("      Shift volume Steiner point %d to facet.\n",
                                 pointmark(touchpt));
                        }
                        face checksh, *parysh;
                        int siloc = (int) ONFACE;
                        int sbowat = 0; // Only split this subface.
    
                        sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat);
    
                        setpointtype(touchpt, FREEFACETVERTEX);
                        st_volref_count--;
                        st_facref_count++;
                        // Queue this vertex for removal.
                        subvertstack->newindex((void **) &parypt);
                        *parypt = touchpt;
                        // Queue new subfaces for recovery.
                        // Put all new subfaces into stack for recovery.
                        for (i = 0; i < caveshbdlist->objects; i++) {
                          // Get an old subface at edge [a, b].
                          parysh = (face *) fastlookup(caveshbdlist, i);
                          spivot(*parysh, checksh); // The new subface [a, b, p].
                          // Do not recover a deleted new face (degenerated).
                          if (checksh.sh[3] != NULL) {
                            if (b->verbose > 3) {
                              printf("        Queue new subface (%d, %d, %d).\n",
                                pointmark(sorg(checksh)), pointmark(sdest(checksh)),
                                pointmark(sapex(checksh)));
                            }
                            //sdissolve(checksh); // It has not been connected yet.
                            subfacstack->newindex((void **) &parysh);
                            *parysh = checksh;
                          }
                        }
                        // Delete the old subfaces in sC(p).
                        assert(caveshlist->objects == 1);
                        for (i = 0; i < caveshlist->objects; i++) {
                          parysh = (face *) fastlookup(caveshlist, i);
                          shellfacedealloc(subfaces, parysh->sh);
                        }
                        // Clear working lists.
                        caveshlist->restart();
                        caveshbdlist->restart();
                        cavesegshlist->restart();
                        // We can return this function.
                        searchsh->sh = NULL; // It has been split.
                        success1 = 0;
                        success = 1; 
                      } else {
                        // It should be a PLC problem.
                        if (pointtype(touchpt) == FREESEGVERTEX) {
                          // A segment and a subface intersect. 
                        } else if (pointtype(touchpt) == FREEFACETVERTEX) {
                          // Two facets self-intersect.
                        }
                        terminatetetgen(3);
                      }
                    } else {
                      assert(0); // Unknown cases. Debug.
                    }
                  }
                  break;
                } else { // intflag == 4. Coplanar case.
                  // This may be an input PLC error.
                  assert(0);
                }
              } // if (intflag > 0)
            }
            fnextself(spintet);
            assert(spintet.tet != searchtet->tet);
          } // while (1)
          if (!success1) break;
        } // while (1)
      } // i
    
      return success;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // recoversubfaces()    Recover all subfaces.                                //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
    {
      triface searchtet, neightet, spintet;
      face searchsh, neighsh, neineish, *parysh;
      face bdsegs[3], checkseg;
      point startpt, endpt, apexpt, *parypt;
      point steinerpt;
      enum interresult dir;
      insertvertexflags ivf;
      int success;
      int loc;
      int i, j;
    
      if (b->verbose > 1) {
        printf("    Recover subfaces [%s level = %2d] #:  %ld.\n",
               (b->fliplinklevel > 0) ? "fixed" : "auto",
               (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
               subfacstack->objects);
      }
    
      // Loop until 'subfacstack' is empty.
      while (subfacstack->objects > 0l) {
    
        subfacstack->objects--;
        parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
        searchsh = *parysh;
    
        if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
    
        stpivot(searchsh, neightet);
        if (neightet.tet != NULL) continue; // Skip a recovered subface.
    
    
        if (b->verbose > 2) {
          printf("      Recover subface (%d, %d, %d).\n", pointmark(sorg(searchsh)),
                 pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
        }
    
        // The three edges of the face need to be existed first.
        for (i = 0; i < 3; i++) {
          sspivot(searchsh, bdsegs[i]);   
          if (bdsegs[i].sh != NULL) {
            // The segment must exist.
            sstpivot1(bdsegs[i], searchtet);
            if (searchtet.tet == NULL) {
              assert(0);
            }
          } else {
            // This edge is not a segment (due to a Steiner point).
            // Check whether it exists or not.
            success = 0;
            startpt = sorg(searchsh);
            endpt = sdest(searchsh);
            point2tetorg(startpt, searchtet);
            assert(org(searchtet) == startpt); // SELF_CHECK
            dir = finddirection(&searchtet, endpt, 1);
            if (dir == ACROSSVERT) {
              if (dest(searchtet) == endpt) {
                success = 1;  
              } else {
                //assert(0); // A PLC problem.
                terminatetetgen(3);
              }
            } else {
              // The edge is missing. Try to recover it.
              if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
                success = 1;
              } else {
                if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
                  success = 1;
                }
              }
            }
            if (success) {
              // Insert a temporary segment to protect this edge.
              if (b->verbose > 2) {
                printf("      Insert a temp segment to protect edge [%d, %d].\n",
                       pointmark(startpt), pointmark(endpt));
              }
              makeshellface(subsegs, &(bdsegs[i]));
              setshvertices(bdsegs[i], startpt, endpt, NULL);
              //setshellmark(bdsegs[i], -2); // It's a temporary segment.
              smarktest2(bdsegs[i]); // It's a temporary segment.
              // Insert this segment into surface mesh.
              ssbond(searchsh, bdsegs[i]);
              spivot(searchsh, neighsh);
              if (neighsh.sh != NULL) {
                ssbond(neighsh, bdsegs[i]);
              }
              // Insert this segment into tetrahedralization.
              tsspivot1(searchtet, checkseg);  // SELF_CHECK
              assert(checkseg.sh == NULL);
              sstbond1(bdsegs[i], searchtet);
              // Bond the segment to all tets containing it.
              spintet = searchtet;
              do {
                tssbond1(spintet, bdsegs[i]);
                fnextself(spintet);
              } while (spintet.tet != searchtet.tet);
            } else {
              // An edge of this subface is missing. Can't recover this subface.
              // Delete any temporary segment that has been created.
              for (j = (i - 1); j >= 0; j--) {
                if (smarktest2ed(bdsegs[j])) { // if (shellmark(bdsegs[j]) == -2) {
                  if (b->verbose > 2) {
                    printf("      Remove a temp segment (%d, %d).\n", 
                      pointmark(sorg(bdsegs[j])), pointmark(sdest(bdsegs[j])));
                  }
                  spivot(bdsegs[j], neineish);
                  assert(neineish.sh != NULL);
                  //if (neineish.sh != NULL) {
                    ssdissolve(neineish);
                    spivot(neineish, neighsh);
                    if (neighsh.sh != NULL) {
                      ssdissolve(neighsh);
                      // There should be only two subfaces at this segment.
                      spivotself(neighsh); // SELF_CHECK
                      assert(neighsh.sh == neineish.sh);
                    }
    	      //}
                  sstpivot1(bdsegs[j], searchtet);
                  assert(searchtet.tet != NULL);
                  //if (searchtet.tet != NULL) {
                    spintet = searchtet;
                    while (1) {
                      tssdissolve1(spintet);
                      fnextself(spintet);
                      if (spintet.tet == searchtet.tet) break;
                    }
    	      //}
                  shellfacedealloc(subsegs, bdsegs[j].sh);
                }
              } // j
              if (steinerflag) {
                // Add a Steiner point at the midpoint of this edge.
                if (b->verbose > 2) {
                  printf("      Add a Steiner point in subedge (%d, %d).\n",
                         pointmark(startpt), pointmark(endpt));
                }
                makepoint(&steinerpt, FREEFACETVERTEX);
                for (j = 0; j < 3; j++) {
                  steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
                }
    
                point2tetorg(startpt, searchtet); // Start from 'searchtet'.
                ivf.iloc = (int) OUTSIDE; // Need point location.
                ivf.bowywat = 1;
                ivf.lawson = 0;
                ivf.rejflag = 0;
                ivf.chkencflag = 0;
                ivf.sloc = (int) ONEDGE;            
                ivf.sbowywat = 1; // Allow flips in facet.
                ivf.splitbdflag = 0;
                ivf.validflag = 1;
                ivf.respectbdflag = 1;
                ivf.assignmeshsize = 0;
                loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf);
                assert(loc != (int) OUTSIDE);
    
                // Save this Steiner point (for removal).
                //   Re-use the array 'subvertstack'.
                subvertstack->newindex((void **) &parypt);
                *parypt = steinerpt;
    
                st_facref_count++;
                if (steinerleft > 0) steinerleft--;
              } // if (steinerflag)
              break;
            }
          }
          senextself(searchsh);
        } // i
    
        if (i == 3) {
          // Recover the subface.
          startpt = sorg(searchsh);
          endpt   = sdest(searchsh);
          apexpt  = sapex(searchsh);
    
          success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
    
          // Delete any temporary segment that has been created.
          for (j = 0; j < 3; j++) {
            if (smarktest2ed(bdsegs[j])) { //if (shellmark(bdsegs[j]) == -2) {
              if (b->verbose > 2) {
                printf("      Remove a temp segment (%d, %d).\n", 
                       pointmark(sorg(bdsegs[j])), pointmark(sdest(bdsegs[j])));
              }
              spivot(bdsegs[j], neineish);
              assert(neineish.sh != NULL);
              //if (neineish.sh != NULL) {
                ssdissolve(neineish);
                spivot(neineish, neighsh);
                if (neighsh.sh != NULL) {
                  ssdissolve(neighsh);
                  // There should be only two subfaces at this segment.
                  spivotself(neighsh); // SELF_CHECK
                  assert(neighsh.sh == neineish.sh);
                }
    	  //}
              sstpivot1(bdsegs[j], neightet);
              assert(neightet.tet != NULL);
              //if (neightet.tet != NULL) {
                spintet = neightet;
                while (1) {
                  tssdissolve1(spintet);
                  fnextself(spintet);
                  if (spintet.tet == neightet.tet) break;
                }
    	  //}
              shellfacedealloc(subsegs, bdsegs[j].sh);
            }
          } // j
    
          if (success) {
            if (searchsh.sh != NULL) {
              // Face is recovered. Insert it.
              tsbond(searchtet, searchsh);
              fsymself(searchtet);
              sesymself(searchsh);
              tsbond(searchtet, searchsh);
            }
          } else {
            if (steinerflag) {
              // Add a Steiner point at the barycenter of this subface.
              if (b->verbose > 2) {
                printf("      Add a Steiner point in subface (%d, %d, %d).\n",
                       pointmark(startpt), pointmark(endpt), pointmark(apexpt));
              }
              makepoint(&steinerpt, FREEFACETVERTEX);
              for (j = 0; j < 3; j++) {
                steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
              }
    
              point2tetorg(startpt, searchtet); // Start from 'searchtet'.
              ivf.iloc = (int) OUTSIDE; // Need point location.
              ivf.bowywat = 1;
              ivf.lawson = 0;
              ivf.rejflag = 0;
              ivf.chkencflag = 0;
              ivf.sloc = (int) ONFACE;          
              ivf.sbowywat = 1; // Allow flips in facet.
              ivf.splitbdflag = 0;
              ivf.validflag = 1;
              ivf.respectbdflag = 1;
              ivf.assignmeshsize = 0; 
              loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf);
              assert(loc != (int) OUTSIDE);
    
              // Save this Steiner point (for removal).
              //   Re-use the array 'subvertstack'.
              subvertstack->newindex((void **) &parypt);
              *parypt = steinerpt;
    
              st_facref_count++;
              if (steinerleft > 0) steinerleft--;
            } // if (steinerflag)
          }
        } else {
          success = 0;      
        }
    
        if (!success) {
          if (misshlist != NULL) {
            if (b->verbose > 2) {
              printf("      Subface (%d, %d, %d) is missing.\n", 
                     pointmark(sorg(searchsh)), pointmark(sdest(searchsh)), 
                     pointmark(sapex(searchsh)));
            }
            // Save this subface.
            misshlist->newindex((void **) &parysh);
            *parysh = searchsh;
          }
        }
    
      } // while (subfacstack->objects > 0l)
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // getvertexstar()    Return the star of a vertex.                           //
    //                                                                           //
    // If the flag 'fullstar' is set, return the complete star of this vertex.   //
    // Otherwise, only a part of the star which is bounded by facets is returned.// 
    //                                                                           //
    // 'tetlist' returns the list of tets in the star of the vertex 'searchpt'.  //
    // Every tet in 'tetlist' is at the face oppsiting to 'searchpt'.            //
    //                                                                           //
    // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
    //                                                                           //
    // 'shlist' returns the list of subfaces in the star. Each subface must face //
    // to the interior of this star.                                             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist, 
                                  arraypool* vertlist, arraypool* shlist)
    {
      triface searchtet, neightet, *parytet;
      face checksh, *parysh;
      //face checkseg;
      point pt, *parypt;
      int collectflag;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      Form the star of vertex %d.\n", pointmark(searchpt));
      }
    
      point2tetorg(searchpt, searchtet);
    
      // Go to the opposite face (the link face) of the vertex.
      enextself(searchtet);
      esymself(searchtet);
      //assert(oppo(searchtet) == searchpt);
      infect(searchtet); // Collect this tet (link face).
      tetlist->newindex((void **) &parytet);
      *parytet = searchtet;
      if (vertlist != NULL) {
        // Collect three (link) vertices.
        for (i = 0; i < 3; i++) {
          pt = org(searchtet);
          pinfect(pt);
          vertlist->newindex((void **) &parypt);
          *parypt = pt;
          enextself(searchtet);
        }
      }
    
      collectflag = 1;
      esym(searchtet, neightet);
      tspivot(neightet, checksh);
      if (checksh.sh != NULL) {
        if (shlist != NULL) {
          if (!sinfected(checksh)) {
            // Collect this subface (link edge).
            sinfected(checksh);
            shlist->newindex((void **) &parysh);
            *parysh = checksh;
          }
        } // if (checksh.sh != NULL)
        if (!fullstar) {
          collectflag = 0;
        }
      }
      if (collectflag) {
        fsymself(neightet); // Goto the adj tet of this face.
        assert(neightet.tet != NULL);
        esymself(neightet); // Goto the oppo face of this vertex.
        // assert(oppo(neightet) == searchpt);
        infect(neightet); // Collect this tet (link face).
        tetlist->newindex((void **) &parytet);
        *parytet = neightet;
        if (vertlist != NULL) {
          // Collect its apex.
          pt = apex(neightet);
          pinfect(pt);
          vertlist->newindex((void **) &parypt);
          *parypt = pt;
        }
      } // if (collectflag)
    
      // Continue to collect all tets in the star.
      for (i = 0; i < tetlist->objects; i++) {
        searchtet = * (triface *) fastlookup(tetlist, i);
        // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
        //   tet at the current edge is already collected.
        // Check the neighors at the other two edges of this face.
        for (j = 0; j < 2; j++) {
          collectflag = 1;
          enextself(searchtet);
          //fnext(searchtet, neightet);
          esym(searchtet, neightet);
          tspivot(neightet, checksh);
          if (checksh.sh != NULL) {
            if (shlist != NULL) {
              if (!sinfected(checksh)) {
                // Collect this subface (link edge).
                sinfected(checksh);
                shlist->newindex((void **) &parysh);
                *parysh = checksh;
              }
            }
            if (!fullstar) {
              collectflag = 0;
            }
          }
          if (collectflag) {
            fsymself(neightet);
            assert(neightet.tet != NULL);
            if (!infected(neightet)) {
              esymself(neightet); // Go to the face opposite to 'searchpt'.
              infect(neightet);
              tetlist->newindex((void **) &parytet);
              *parytet = neightet;
              if (vertlist != NULL) {
                // Check if a vertex is collected.
                pt = apex(neightet);
                if (!pinfected(pt)) {
                  pinfect(pt);
                  vertlist->newindex((void **) &parypt);
                  *parypt = pt;
                }
              }
            } // if (!infected(neightet))
          } // if (collectflag)
        } // j
      } // i
    
      if (b->verbose > 2) {
        printf("      Collected %ld tets", tetlist->objects);
        if (vertlist != NULL) {
          printf(", %ld vertices", vertlist->objects);
        }
        if (shlist != NULL) {
          printf(", %ld subfaces", shlist->objects);
        }
        printf(".\n");
      }
    
      // Uninfect the list of tets and vertices.
      for (i = 0; i < tetlist->objects; i++) {
        parytet = (triface *) fastlookup(tetlist, i);
        uninfect(*parytet);
      }
    
      if (vertlist != NULL) {
        for (i = 0; i < vertlist->objects; i++) {
          parypt = (point *) fastlookup(vertlist, i);
          puninfect(*parypt);
        }
      }
    
      if (shlist != NULL) {
        for (i = 0; i < shlist->objects; i++) {
          parysh = (face *) fastlookup(shlist, i);
          suninfect(*parysh);
        }
      }
    
      return (int) tetlist->objects;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // getedge()    Get a tetrahedron having the two endpoints.                  //
    //                                                                           //
    // The method here is to search the second vertex in the link faces of the   //
    // first vertex. The global array 'cavetetlist' is re-used for searching.    //
    //                                                                           //
    // This function is used for the case when the mesh is non-convex. Otherwise,//
    // the function finddirection() should be faster than this.                  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::getedge(point e1, point e2, triface *tedge)
    {
      triface searchtet, neightet, *parytet;
      point pt;
      int done;
      int i, j;
    
      if (b->verbose > 2) {
        printf("      Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
      }
    
      // Quickly check if 'tedge' is just this edge.
      if (!isdeadtet(*tedge)) {
        if (org(*tedge) == e1) {
          if (dest(*tedge) == e2) {
            return 1;
          }
        } else if (org(*tedge) == e2) {
          if (dest(*tedge) == e1) {
            esymself(*tedge);
            return 1;
          }
        }
      }
    
      // Search for the edge [e1, e2].
      point2tetorg(e1, *tedge);
      finddirection(tedge, e2, 1);
      if (dest(*tedge) == e2) {
        return 1;
      } else {
        // Search for the edge [e2, e1].
        point2tetorg(e2, *tedge);
        finddirection(tedge, e1, 1);
        if (dest(*tedge) == e1) {
          esymself(*tedge);
          return 1;
        }
      }
    
    
      // Go to the link face of e1.
      point2tetorg(e1, searchtet);
      enextself(searchtet);
      esymself(searchtet);
      //assert(oppo(searchtet) == e1);
    
      assert(cavetetlist->objects == 0l); // It will re-use this list.
    
      // Search e2.
      for (i = 0; i < 3; i++) {
        pt = apex(searchtet);
        if (pt == e2) {
          // Found. 'searchtet' is [#,#,e2,e1].
          enext(searchtet, *tedge);
          esymself(*tedge);
          eprevself(*tedge); // [e1,e2,#,#].
          return 1;
        }
        enextself(searchtet);
      }
    
      // Get the adjacent link face at 'searchtet'.
      fnext(searchtet, neightet);
      esymself(neightet);
      // assert(oppo(neightet) == e1);
      pt = apex(neightet);
      if (pt == e2) {
        // Found. 'neightet' is [#,#,e2,e1].
        enext(neightet, *tedge);
        esymself(*tedge);
        eprevself(*tedge); // [e1,e2,#,#].
        return 1;
      }
    
      // Continue searching in the link face of e1.
      infect(searchtet);
      cavetetlist->newindex((void **) &parytet);
      *parytet = searchtet;
      infect(neightet);
      cavetetlist->newindex((void **) &parytet);
      *parytet = neightet;
    
      done = 0;
    
      for (i = 0; (i < cavetetlist->objects) && !done; i++) {
        parytet = (triface *) fastlookup(cavetetlist, i);
        searchtet = *parytet;
        for (j = 0; (j < 2) && !done; j++) {
          enextself(searchtet);
          fnext(searchtet, neightet);
          if (!infected(neightet)) {        
            esymself(neightet);
            pt = apex(neightet);
            if (pt == e2) {
              // Found. 'neightet' is [#,#,e2,e1].
              enext(neightet, *tedge);
              esymself(*tedge);
              eprevself(*tedge); // [e1,e2,#,#].
              done = 1;
            } else {
              infect(neightet);
              cavetetlist->newindex((void **) &parytet);
              *parytet = neightet;
            }
          }
        } // j
      } // i 
    
      // Uninfect the list of visited tets.
      for (i = 0; i < cavetetlist->objects; i++) {
        parytet = (triface *) fastlookup(cavetetlist, i);
        uninfect(*parytet);
      }
      cavetetlist->restart();
    
      return done;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // reduceedgesatvertex()    Reduce the number of edges at a given vertex.    //
    //                                                                           //
    // 'endptlist' contains the endpoints of edges connecting at the vertex.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
    {
      triface searchtet;
      face checkseg;
      point *pendpt, *parypt;
      enum interresult dir;
      flipconstraints fc;
      int reduceflag;
      int count;
      int n, i, j;
    
      if (b->verbose > 2) {
        printf("      Initial edge degree = %ld.\n", endptlist->objects);
      }
      assert(endptlist->objects >= 4l);
    
      // Reduce the number of edges.
      fc.remvert = startpt;
    
      while (1) {
    
        count = 0;
    
        for (i = 0; i < endptlist->objects; i++) {
          pendpt = (point *) fastlookup(endptlist, i);
          if (*pendpt == dummypoint) {
            continue; // Do not reduce a virtual edge.
          }
          reduceflag = 0;
          // Find the edge.
          if (nonconvex) {
            if (getedge(startpt, *pendpt, &searchtet)) {
              dir = ACROSSVERT;
            } else {
              // The edge does not exist (was flipped).
              dir = INTERSECT;
            }
          } else {
            point2tetorg(startpt, searchtet);
            dir = finddirection(&searchtet, *pendpt, 1);
          }
          if (dir == ACROSSVERT) {
            if (dest(searchtet) == *pendpt) {
              // Do not flip a segment.
              tsspivot1(searchtet, checkseg);
              if (checkseg.sh == NULL) {
                n = removeedgebyflips(&searchtet, &fc);
                if (n == 2) {
                  reduceflag = 1;
                }
              }
            } else {
              assert(0); // A plc problem.
            }
          } else {
            // The edge has been flipped.
            reduceflag = 1;
          }
          if (reduceflag) {
            count++;
            // Move the last vertex into this slot.
            j = endptlist->objects - 1;
            parypt = (point *) fastlookup(endptlist, j);
            *pendpt = *parypt;
            endptlist->objects--;
            i--;
          }
        } // i
    
        if (count == 0) {
          // No edge is reduced.
          break;
        }
    
      } // while (1)
    
      if (b->verbose > 2) {
        printf("      Final edge degree = %ld.\n", endptlist->objects);
      }
    
      return (int) endptlist->objects;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // removevertexbyflips()    Remove a vertex by flips.                        //
    //                                                                           //
    // This routine attempts to remove the given vertex 'rempt' (p) from the cur-//
    // rent tetrahedralization (T) by a sequence of elementary flips.            //
    //                                                                           //
    // The algorithm used here is a simple edge reduce method. Suppose there are //
    // n edges connected at p. We try to reduce the number of edges by flipping  //
    // any edge (not a segment) that is connecting at p.                         //
    //                                                                           //
    // The original location of 'p' in the tetrahedralization without 'p' is ind-//
    // icated by 'iloc'. 'searchtet' (t) is a tet in the current tetrahedralizat-//
    // ion which contains 'p'. Depending on 'iloc', it means the followig:       //
    //   - INTET:  the origin of 't' is 'p';                                     //
    //   - ONFACE: the origin of 't' is 'p', the face of 't' was split by 'p';   //
    //   - ONEDGE: the origin of 't' is 'p', the edge of 't' was split by 'p';   //
    //                                                                           //
    // If 'parentsh' (s) is given (not NULL), it indicates that 'p' is a Steiner //
    // point on a facet, and 's' was a subface created by the insertion of 'p'.  //
    // 'iloc' must be either ONFACE or 'OEDGE'. The origin of 's' is 'p'.        //
    //                                                                           //
    // If 'parentseg' (seg) is given (not NULL), it indicated that 'p' is a      //
    // Steiner point on a segment, and 'seg' was a subsegment created by 'p'.    //
    // 'iloc' must be ONEDGE. The original of 'seg' is 'p'.                      // 
    //                                                                           //
    // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
    // can be successfully removed.                                              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::removevertexbyflips(point steinerpt)
    {
      triface *fliptets = NULL, wrktets[4];
      triface searchtet, spintet, neightet;
      face parentsh, spinsh, checksh;
      face leftseg, rightseg, checkseg;
      point lpt = NULL, rpt = NULL, apexpt, *parypt;
      enum verttype vt;
      enum locateresult loc;
      int valence, removeflag;
      int slawson;
      int n, i;
    
      vt = pointtype(steinerpt);
    
      if (vt == FREESEGVERTEX) {
        sdecode(point2sh(steinerpt), leftseg);
        assert(leftseg.sh != NULL);
        leftseg.shver = 0;
        if (sdest(leftseg) == steinerpt) {
          senext(leftseg, rightseg);
          spivotself(rightseg);
          assert(rightseg.sh != NULL);
          rightseg.shver = 0;
          assert(sorg(rightseg) == steinerpt);
        } else {
          assert(sorg(leftseg) == steinerpt);
          rightseg = leftseg;
          senext2(rightseg, leftseg);
          spivotself(leftseg);
          assert(leftseg.sh != NULL);
          leftseg.shver = 0;
          assert(sdest(leftseg) == steinerpt);
        }
        lpt = sorg(leftseg);
        rpt = sdest(rightseg);
        if (b->verbose > 2) {
          printf("      Removing Steiner point %d in segment (%d, %d).\n",
                 pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
    
        }
      } else if (vt == FREEFACETVERTEX) {
        if (b->verbose > 2) {
          printf("      Removing Steiner point %d in facet.\n",
                 pointmark(steinerpt));
    
        }
      } else if (vt == FREEVOLVERTEX) {
        if (b->verbose > 2) {
          printf("      Removing Steiner point %d in volume.\n",
                 pointmark(steinerpt));
    
        }
      } else {
        // It is not a Steiner point.
        return 0;
      }
    
      // Try to reduce the number of edges at 'p' by flips.
      getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
      cavetetlist->restart(); // This list may be re-used.
      if (cavetetvertlist->objects > 3l) {
        valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
      } else {
        valence = cavetetvertlist->objects;
      }
      assert(cavetetlist->objects == 0l);
      cavetetvertlist->restart();
    
      removeflag = 0;
    
      if (valence < 3) {
        assert(0); // Unknown cases.
      }
    
      if (valence == 3) {
        // Only three edges at this vertex. This is only possible when there are
        //   Inverted elements.
        getvertexstar(1, steinerpt, cavetetlist, NULL, NULL);
        if (cavetetlist->objects == 2) {
          printf("to be continued...");
          assert(0);
        } else {
          assert(0); // Unknown cases.
        }
        cavetetlist->restart();
        loc = OUTSIDE;
        removeflag = 1;
      } else if (valence == 4) {
        // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
        //   vertices. This case is due to that 'p' is not exactly on the segment.
        point2tetorg(steinerpt, searchtet);
        loc = INTETRAHEDRON;
        removeflag = 1;
      } else if (valence == 5) {
        // There are 5 edges.
        if (vt == FREESEGVERTEX) {
          sstpivot1(leftseg, searchtet);
          if (org(searchtet) != steinerpt) {
            esymself(searchtet);
          }
          assert(org(searchtet) == steinerpt);
          assert(dest(searchtet) == lpt);
          i = 0; // Count the numbe of tet at the edge [p,lpt].
          neightet.tet = NULL; // Init the face.
          spintet = searchtet;
          while (1) {
            i++;
            if (apex(spintet) == rpt) {
              // Remember the face containing the edge [lpt, rpt].
              neightet = spintet;
            }
            fnextself(spintet);
            if (spintet.tet == searchtet.tet) break;
          }
          if (i == 3) {
            // This case has been checked below.
          } else if (i == 4) {
            // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
            //   at [p,rpt].  There must be a face [p, lpt, rpt].  
            if (apex(neightet) == rpt) {
              // The edge (segment) has been already recovered!  At first, this is 
              //   due to the same reason as the case 'valence == 4'.  Second, 
              //   there are 4 vertices (including p, lpt, rpt) exactly coplanar. 
              // We can do a 6-to-2 flip to remove p and recover a face 
              //  [lpt, rpt, c] = [a,b,c].
              // Let 'searchtet' be [p,d,a,b]
              esym(neightet, searchtet);
              enextself(searchtet);
              loc = ONFACE;
              removeflag = 1;
            }
          }
        } else if (vt == FREEFACETVERTEX) {
          point2tetorg(steinerpt, searchtet);
          // Get the three faces of 'searchtet' which share at p.
          //    All faces has p as origin.
          wrktets[0] = searchtet;
          wrktets[1] = searchtet;
          esymself(wrktets[1]);
          enextself(wrktets[1]);
          wrktets[2] = searchtet;
          eprevself(wrktets[2]);
          esymself(wrktets[2]);
          // Get the one which has a subface (should be only 1).
          n = -1;
          valence = 0; // Re-use it as a counter.
          for (i = 0; i < 3; i++) {
            tspivot(wrktets[i], checksh);
            if (checksh.sh != NULL) {
              n = i;
              valence++; 
            }
          }
          assert(valence == 1);
          searchtet = wrktets[n];
          esymself(searchtet);
          enextself(searchtet);
          loc = ONFACE;
          removeflag = 1;
        } else {
          // assert(0); DEBUG IT
        }
        //removeflag = 1;
      } else { // valence > 5.
        
      } // if (valence > 5)
    
      if (!removeflag) {
        if (vt == FREESEGVERTEX) { 
          // Check is it possible to recover the edge [lpt,rpt].
          // The condition to check is:  Whether each tet containing 'leftseg' is
          //   adjacent to a tet containing 'rightseg'.
          sstpivot1(leftseg, searchtet);
          if (org(searchtet) != steinerpt) {
            esymself(searchtet);
          }
          assert(org(searchtet) == steinerpt);
          assert(dest(searchtet) == lpt);
          spintet = searchtet;
          while (1) {
            // Go to the bottom face of this tet.
            eprev(spintet, neightet);
            esymself(neightet);  // [steinerpt, p1, p2, lpt]
            // Get the adjacent tet.
            fsymself(neightet);  // [p1, steinerpt, p2, rpt]
            if (oppo(neightet) != rpt) {
              // Found a non-matching adjacent tet.
              break;
            }
            fnextself(spintet);
            if (spintet.tet == searchtet.tet) {
              // 'searchtet' is [p,d,p1,p2].
              loc = ONEDGE;
              removeflag = 1;
              break;
            }
          }
        } // if (vt == FREESEGVERTEX)
      }
    
      if (!removeflag) {
        if (vt == FREESEGVERTEX) {
          // Check if the edge [lpr, rpt] exists.
          if (getedge(lpt, rpt, &searchtet)) {
            // We have recovered this edge. Shift the vertex into the volume.
            // We can recover this edge if the subfaces are not recovered yet.
            if (!checksubfaceflag) {
              // Remove the vertex from the surface mesh.
              //   This will re-create the segment [lpt, rpt] and re-triangulate
              //   all the facets at the segment.
              // Detach the subsegments from their surronding tets.
              for (i = 0; i < 2; i++) {
                checkseg = (i == 0) ? leftseg : rightseg;
                sstpivot1(checkseg, neightet);
                spintet = neightet;
                while (1) {
                  tssdissolve1(spintet);
                  fnextself(spintet);
                  if (spintet.tet == neightet.tet) break;
                }
                sstdissolve1(checkseg);
              } // i
              slawson = 1; // Do lawson flip after removal.
              spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
              sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
              // Clear the list for new subfaces.
              caveshbdlist->restart();
              // Insert the new segment.
              assert(org(searchtet) == lpt);
              assert(dest(searchtet) == rpt);
              sstbond1(rightseg, searchtet);
              spintet = searchtet;
              while (1) {
                tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
                assert(checkseg.sh == NULL);  // FOR DEBUG ONLY
                tssbond1(spintet, rightseg);
                fnextself(spintet);
                if (spintet.tet == searchtet.tet) break;
              }
              // The Steiner point has been shifted into the volume.
              setpointtype(steinerpt, FREEVOLVERTEX);          
              st_segref_count--;
              st_volref_count++;
              // Save this Steiner points in (global) list.
              suppsteinerptlist->newindex((void **) &parypt);
              *parypt = steinerpt;
              return 1;
            } // if (!checksubfaceflag)
          } // if (getedge(...))
        } // if (vt == FREESEGVERTEX)
      } // if (!removeflag)
    
      if (!removeflag) {
        if (b->verbose > 2) {
          printf("      Unable to remove Steiner point %d val(%d).\n",
                 pointmark(steinerpt), valence);
        }
        return 0;
      }
    
      assert(org(searchtet) == steinerpt);
    
      if (vt == FREESEGVERTEX) {
        // Detach the subsegments from their surronding tets.
        for (i = 0; i < 2; i++) {
          checkseg = (i == 0) ? leftseg : rightseg;
          sstpivot1(checkseg, neightet);
          spintet = neightet;
          while (1) {
            tssdissolve1(spintet);
            fnextself(spintet);
            if (spintet.tet == neightet.tet) break;
          }
          sstdissolve1(checkseg);
        } // i
        if (checksubfaceflag) {
          // Detach the subfaces at the subsegments from their attached tets.
          for (i = 0; i < 2; i++) {
            checkseg = (i == 0) ? leftseg : rightseg;
            spivot(checkseg, parentsh);
            if (parentsh.sh != NULL) {
              spinsh = parentsh;
              while (1) {
                stpivot(spinsh, neightet);
                if (neightet.tet != NULL) {
                  tsdissolve(neightet);
                }
                sesymself(spinsh);
                stpivot(spinsh, neightet);
                if (neightet.tet != NULL) {
                  tsdissolve(neightet);
                }
                stdissolve(spinsh);
                spivotself(spinsh); // Go to the next subface.
                if (spinsh.sh == parentsh.sh) break;
              }
            }
          } // i
        } // if (checksubfaceflag)
      }
    
      if (loc == INTETRAHEDRON) {
        // Collect the four tets containing 'p'.
        fliptets = new triface[4];
        fliptets[0] = searchtet; // [p,d,a,b]
        for (i = 0; i < 2; i++) {
          fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
        }
        eprev(fliptets[0], fliptets[3]);
        fnextself(fliptets[3]); // it is [a,p,b,c]
        eprevself(fliptets[3]);
        esymself(fliptets[3]); // [a,b,c,p].
        // Remove p by a 4-to-1 flip.
        flip41(fliptets, 1, 0, 0);
        //recenttet = fliptets[0];
      } else if (loc == ONFACE) {
        // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
        //   face [a,b,c].  Let 'searchtet' be the tet [p,d,a,b].
        // Collect the six tets containing 'p'.
        fliptets = new triface[6];
        fliptets[0] = searchtet; // [p,d,a,b]
        for (i = 0; i < 2; i++) {
          fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
        }
        eprev(fliptets[0], fliptets[3]);
        fnextself(fliptets[3]); // [a,p,b,e]
        esymself(fliptets[3]);  // [p,a,e,b]
        eprevself(fliptets[3]); // [e,p,a,b]
        for (i = 3; i < 5; i++) {
          fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
        }
        // Remove p by a 6-to-2 flip, which is a combination of two flips:
        //   a 3-to-2 (deletes the edge [e,p]), and
        //   a 4-to-1 (deletes the vertex p).
        // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
        //   two new tets: [a,b,c,p] and [b,a,c,e].  The new tet [a,b,c,p] is
        //   degenerate (has zero volume). It will be deleted in the followed
        //   4-to-1 flip.
        flip32(&(fliptets[3]), 1, 0, 0);
        // DEBUG BEGIN
        // fliptets[3] is [a,b,c,p], check it.
        assert(org(fliptets[3]) == apex(fliptets[0]));  // a
        assert(dest(fliptets[3]) == apex(fliptets[1])); // b
        assert(apex(fliptets[3]) == apex(fliptets[2])); // c
        assert(oppo(fliptets[3]) == steinerpt);
        // fliptets[4] is [b,a,c,e].
        // DEBUG END
        // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
        //   This creates a new tet [a,b,c,d].
        flip41(fliptets, 1, 0, 0);
        //recenttet = fliptets[0];
      } else if (loc == ONEDGE) {
        // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
        //   tets sharing at edge [e,d] originally.  We number the link vertices
        //   of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
        // Count the number of tets at edge [e,p] and [p,d] (this is n).
        n = 0;
        spintet = searchtet;
        while (1) {
          n++;
          fnextself(spintet);
          if (spintet.tet == searchtet.tet) break;
        }
        assert(n >= 3);
        // Collect the 2n tets containing 'p'.
        fliptets = new triface[2 * n];
        fliptets[0] = searchtet; // [p,b,p_0,p_1] 
        for (i = 0; i < (n - 1); i++) {
          fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
        }
        eprev(fliptets[0], fliptets[n]);
        fnextself(fliptets[n]); // [p_0,p,p_1,e]
        esymself(fliptets[n]);  // [p,p_0,e,p_1]
        eprevself(fliptets[n]); // [e,p,p_0,p_1]
        for (i = n; i <  (2 * n - 1); i++) {
          fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
        }
        // Remove p by a 2n-to-n flip, it is a sequence of n flips:
        // - Do a 2-to-3 flip on 
        //     [p_0,p_1,p,d] and 
        //     [p,p_1,p_0,e].
        //   This produces: 
        //     [e,d,p_0,p_1], 
        //     [e,d,p_1,p] (degenerated), and 
        //     [e,d,p,p_0] (degenerated).
        wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
        eprevself(wrktets[0]);    // [p_0,p,d,p_1]
        esymself(wrktets[0]);     // [p,p_0,p_1,d]
        enextself(wrktets[0]);    // [p_0,p_1,p,d] [0]
        wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
        enextself(wrktets[1]);    // [p,p_0,e,p_1]
        esymself(wrktets[1]);     // [p_0,p,p_1,e]
        eprevself(wrktets[1]);    // [p_1,p_0,p,e] [1]
        flip23(wrktets, 1, 0, 0);
        // Save the new tet [e,d,p,p_0] (degenerated).
        fliptets[n] = wrktets[2];
        // Save the new tet [e,d,p_0,p_1].
        fliptets[0] = wrktets[0];
        // - Repeat from i = 1 to n-2: (n - 2) flips
        //   - Do a 3-to-2 flip on 
        //       [p,p_i,d,e], 
        //       [p,p_i,e,p_i+1], and 
        //       [p,p_i,p_i+1,d]. 
        //     This produces: 
        //       [d,e,p_i+1,p_i], and
        //       [e,d,p_i+1,p] (degenerated).
        for (i = 1; i < (n - 1); i++) {
          wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
          enextself(wrktets[0]);   // [d,p_i,e,p] (...)
          esymself(wrktets[0]);    // [p_i,d,p,e] (...) 
          eprevself(wrktets[0]);   // [p,p_i,d,e] (degenerated) [0].
          wrktets[1] = fliptets[n+i];  // [e,p,p_i,p_i+1]
          enextself(wrktets[1]);       // [p,p_i,e,p_i+1] [1]
          wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
          eprevself(wrktets[2]);    // [p_i,p,d,p_i+1]
          esymself(wrktets[2]);     // [p,p_i,p_i+1,d] [2]
          flip32(wrktets, 1, 0, 0);
          // Save the new tet [e,d,p_i,p_i+1].         // FOR DEBUG ONLY
          fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
          esymself(fliptets[i]);    // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
        }
        // - Do a 4-to-1 flip on 
        //     [p,p_0,e,d],     [d,e,p_0,p],
        //     [p,p_0,d,p_n-1], [e,p_n-1,p_0,p], 
        //     [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
        //     [e,d,p_n-1,p]. 
        //   This produces 
        //     [e,d,p_n-1,p_0] and 
        //     deletes p.
        wrktets[3] = wrktets[1];  // [e,d,p_n-1,p] (degenerated) [3]
        wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
        eprevself(wrktets[0]);    // [p,e,d,p_0] (...)
        esymself(wrktets[0]);     // [e,p,p_0,d] (...)
        enextself(wrktets[0]);    // [p,p_0,e,d] (degenerated) [0]
        wrktets[1] = fliptets[n-1];   // [p,d,p_n-1,p_0]
        esymself(wrktets[1]);         // [d,p,p_0,p_n-1]
        enextself(wrktets[1]);        // [p,p_0,d,p_n-1] [1]
        wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
        enextself(wrktets[2]);        // [p_p_n-1,e,p_0]
        esymself(wrktets[2]);         // [p_n-1,p,p_0,e]
        enextself(wrktets[2]);        // [p,p_0,p_n-1,e] [2]
        flip41(wrktets, 1, 0, 0);
        // Save the new tet [e,d,p_n-1,p_0]             // FOR DEBUG ONLY
        fliptets[n-1] = wrktets[0];  // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
        //recenttet = fliptets[0];
      } else {
        assert(0); // Unknown location.
      } // if (iloc == ...)
    
      delete [] fliptets;
    
      if (vt == FREESEGVERTEX) {
        // Remove the vertex from the surface mesh.
        //   This will re-create the segment [lpt, rpt] and re-triangulate
        //   all the facets at the segment.
        // Only do lawson flip when subfaces are not recovery yet.
        slawson = (checksubfaceflag ? 0 : 1);
        spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
        sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
    
        // The original segment is returned in 'rightseg'. 
        rightseg.shver = 0;
        assert(sorg(rightseg) == lpt);
        assert(sdest(rightseg) == rpt);
    
        // Insert the new segment.
        point2tetorg(lpt, searchtet);
        finddirection(&searchtet, rpt, 1);
        assert(dest(searchtet) == rpt);
        sstbond1(rightseg, searchtet);
        spintet = searchtet;
        while (1) {
          tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
          assert(checkseg.sh == NULL);  // FOR DEBUG ONLY
          tssbond1(spintet, rightseg);
          fnextself(spintet);
          if (spintet.tet == searchtet.tet) break;
        }
    
        if (checksubfaceflag) {
          // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
          spivot(rightseg, parentsh);
          if (parentsh.sh != NULL) {
            spinsh = parentsh;
            while (1) {
              if (sorg(spinsh) != lpt) {
                sesymself(spinsh);
                assert(sorg(spinsh) == lpt);
              }
              assert(sdest(spinsh) == rpt);
              apexpt = sapex(spinsh);
              // Find the adjacent tet of [lpt,rpt,apexpt];
              spintet = searchtet;
              while (1) {
                if (apex(spintet) == apexpt) {
                  tsbond(spintet, spinsh);
                  sesymself(spinsh); // Get to another side of this face.
                  fsym(spintet, neightet);
                  tsbond(neightet, spinsh);
                  sesymself(spinsh); // Get back to the original side.
                  break;
                }
                fnextself(spintet);
                assert(spintet.tet != searchtet.tet);
                //if (spintet.tet == searchtet.tet) break;
              }
              spivotself(spinsh);
              if (spinsh.sh == parentsh.sh) break;
            }
          }
        } // if (checksubfaceflag)
    
        // Clear the set of new subfaces.
        caveshbdlist->restart();
      } // if (vt == FREESEGVERTEX)
    
      // The point has been removed.
      setpointtype(steinerpt, UNUSEDVERTEX);
      unuverts++;
      // Update the correspinding counters.
      if (vt == FREESEGVERTEX) {
        st_segref_count--;
      } else if (vt == FREEFACETVERTEX) {
        st_facref_count--;
      } else if (vt == FREEVOLVERTEX) {
        st_volref_count--;
      }
      if (steinerleft > 0) steinerleft++;
    
      return 1;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // suppresssteinerpoint()    Suppress a Steiner point.                       //
    //                                                                           //
    // Remove a Steiner point 'p' from the segment it lies on. It is replaced by //
    // a set of volume Steiner points in each sector at the segment.             //
    //                                                                           //
    // The list of volume Steiner points is returned in 'suppsteinerptlist'.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::suppressssteinerpoint(point steinerpt)
    {
      triface searchtet, neightet, spintet, *parytet;
      triface newtet, newface;
      face parentsh, spinsh, *parysh;
      face newsh, neighsh;
      face leftseg, rightseg, checkseg, *splitseg;
      point lpt = NULL, rpt = NULL, newpt, *parypt;
      point pa, pb, pc;
      verttype vt;
      long bak_supp_steiners;
      int slawson;
      int i, j, k;
    
      vt = pointtype(steinerpt);
    
      if (vt == FREESEGVERTEX) {
        sdecode(point2sh(steinerpt), leftseg);
        assert(leftseg.sh != NULL);
        leftseg.shver = 0;
        if (sdest(leftseg) == steinerpt) {
          senext(leftseg, rightseg);
          spivotself(rightseg);
          assert(rightseg.sh != NULL);
          rightseg.shver = 0;
          assert(sorg(rightseg) == steinerpt);
        } else {
          assert(sorg(leftseg) == steinerpt);
          rightseg = leftseg;
          senext2(rightseg, leftseg);
          spivotself(leftseg);
          assert(leftseg.sh != NULL);
          leftseg.shver = 0;
          assert(sdest(leftseg) == steinerpt);
        }
        lpt = sorg(leftseg);
        rpt = sdest(rightseg);
        if (b->verbose > 2) {
          printf("      Suppressing point %d from segment (%d, %d).\n",
                 pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
        }
      } else if (vt == FREEFACETVERTEX) {
        if (b->verbose > 2) {
          printf("      Suppressing point %d from facet.\n",
                 pointmark(steinerpt));
        }
        //point2shorg(steinerpt, parentsh);
        getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
        parysh = (face *) fastlookup(caveshlist, 0);
        parentsh = *parysh;
        //assert(sapex(parentsh) == steinerpt);
        senext2self(parentsh);
        assert(sorg(parentsh) == steinerpt);
        cavetetlist->restart();
        caveshlist->restart();
      } else {
        // Do nothing.
        return 0;
      }
    
      if (vt == FREESEGVERTEX) {
        // Check if this edge [lpt, rpt] already exists.
        if (getedge(lpt, rpt, &searchtet)) {
          tsspivot1(searchtet, checkseg);  // SELF_CHECK
          assert(checkseg.sh == NULL);
          return 0;
        }
      }
    
      bak_supp_steiners = suppsteinerptlist->objects;
    
      if (vt == FREESEGVERTEX) {
        // Get all subfaces at the left segment [lpt, steinerpt].
        spivot(leftseg, parentsh);
        spinsh = parentsh;
        while (1) {
          cavesegshlist->newindex((void **) &parysh);
          *parysh = spinsh;
          spivotself(spinsh);
          if (spinsh.sh == NULL) break;
          if (spinsh.sh == parentsh.sh) break;
        }
        if (cavesegshlist->objects < 2) {
          // It is a single segment. Not handle it yet.
          cavesegshlist->restart();
          return 0;
        }
        // Detach 'leftseg' and 'rightseg' from their adjacent tets.
        //   These two subsegments will be deleted. 
        sstpivot1(leftseg, neightet);
        spintet = neightet;
        while (1) {
          tssdissolve1(spintet);
          fnextself(spintet);
          if (spintet.tet == neightet.tet) break;
        }
        sstpivot1(rightseg, neightet);
        spintet = neightet;
        while (1) {
          tssdissolve1(spintet);
          fnextself(spintet);
          if (spintet.tet == neightet.tet) break;
        }
      } else { // vt == FREEFACETVERTEX
        // A facet Steiner point. There are exactly two sectors.
        for (i = 0; i < 2; i++) {
          cavesegshlist->newindex((void **) &parysh);
          *parysh = parentsh;
          sesymself(parentsh);
        }
      }
    
      // Loop through all sectors bounded by facets at this segment.
      //   Within each sector, create a new Steiner point 'np', and replace 'p'
      //   by 'np' for all tets in this sector.
      for (i = 0; i < cavesegshlist->objects; i++) {
        parysh = (face *) fastlookup(cavesegshlist, i);
        // 'parysh' is the face [lpt, steinerpt, #].
        stpivot(*parysh, neightet);
        // Get all tets in this sector.
        setpoint2tet(steinerpt, encode(neightet));
        getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
        assert(caveshlist->objects > 0);
        // Create a new vertex 'np'. 
        makepoint(&newpt, FREEVOLVERTEX);
        st_volref_count++;
        // Init 'np' at the same location of 'p'.
        for (j = 0; j < 3; j++) newpt[j] = steinerpt[j];
        // Within the tet, replace 'p' by 'np'.
        for (j = 0; j < cavetetlist->objects; j++) {
          parytet = (triface *) fastlookup(cavetetlist, j);
          setoppo(*parytet, newpt);
        } // j
        // Save the new Steiner point in list.
        suppsteinerptlist->newindex((void **) &parypt);
        *parypt = newpt;
        // Disconnect the set of boundary faces. They're temporarily open faces.
        //   They will be connected to the new tets after 'p' is removed.
        for (j = 0; j < caveshlist->objects; j++) {
          // Get a boundary face.
          parysh = (face *) fastlookup(caveshlist, j);
          stpivot(*parysh, neightet);
          assert(apex(neightet) == newpt);
          // Clear the connection at this face.
          dissolve(neightet);
          tsdissolve(neightet);
        }
        // Clear the working lists.
        cavetetlist->restart();
        caveshlist->restart();
      } // i
      cavesegshlist->restart();
    
      // Remove p from the segment.
      slawson = 0; // Do not do flip afterword.
      if (vt == FREESEGVERTEX) { 
        spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
        splitseg = &rightseg;
      } else {
        assert(sorg(parentsh) == steinerpt);
        splitseg = NULL;
      }
      sremovevertex(steinerpt, &parentsh, splitseg, slawson);
    
      if (vt == FREESEGVERTEX) {
        // The original segment is returned in 'rightseg'. 
        rightseg.shver = 0;
        assert(sorg(rightseg) == lpt);
        assert(sdest(rightseg) == rpt);
      }
      // The set of new subfaces are found in 'caveshbdlist'.
      assert(caveshbdlist->objects > 0);
    
    
      // For each new subface, create two new tets at each side of it.
      //   Both of the two new tets have its opposite be dummypoint. 
      for (i = 0; i < caveshbdlist->objects; i++) {
        parysh = (face *) fastlookup(caveshbdlist, i);
        sinfect(*parysh); // Mark it for connecting new tets.
        newsh = *parysh;
        pa = sorg(newsh);
        pb = sdest(newsh);
        pc = sapex(newsh);
        maketetrahedron(&newtet);
        maketetrahedron(&neightet);
        setvertices(newtet, pa, pb, pc, dummypoint);
        setvertices(neightet, pb, pa, pc, dummypoint);
        bond(newtet, neightet);
        tsbond(newtet, newsh);
        sesymself(newsh);
        tsbond(neightet, newsh);
      }
    
      if (vt == FREESEGVERTEX) {
        // Connecting new tets at the recovered segment.
        spivot(rightseg, parentsh);
        assert(parentsh.sh != NULL);
        spinsh = parentsh;
        while (1) {
          assert(sinfected(spinsh));
          if (sorg(spinsh) != lpt) sesymself(spinsh);
          assert(sorg(spinsh) == lpt);
          assert(sdest(spinsh) == rpt);
          // Get the new tet at this subface.
          stpivot(spinsh, newtet);
          assert(oppo(newtet) == dummypoint);
          tssbond1(newtet, rightseg);
          // Go to the other face at this segment.
          esymself(newtet);
          assert(org(newtet) == rpt);
          assert(newtet.tet[newtet.ver & 3] == NULL);
          // Get the adjacent tet at this segment.
          spivot(spinsh, neighsh);
          if (sorg(neighsh) != lpt) sesymself(neighsh);
          sesymself(neighsh);
          stpivot(neighsh, neightet);
          assert(oppo(neightet) == dummypoint);
          tssbond1(neightet, rightseg);
          sstbond1(rightseg, neightet); 
          // Go to the other face at this segment.
          esymself(neightet);
          assert(org(neightet) == lpt);
          assert(neightet.tet[neightet.ver & 3] == NULL);
          // Connect the two tets (at rightseg) together.
          bond(newtet, neightet);
          // Go to the next subface.
          spivotself(spinsh);
          if (spinsh.sh == parentsh.sh) break;
        }
      }
    
      // Connecting new tets at new subfaces together.
      for (i = 0; i < caveshbdlist->objects; i++) {
        parysh = (face *) fastlookup(caveshbdlist, i);
        newsh = *parysh;
        //assert(sinfected(newsh));
        // Each new subface contains two new tets.
        for (k = 0; k < 2; k++) {
          stpivot(newsh, newtet);
          for (j = 0; j < 3; j++) {
            // Check if this side is open.
            esym(newtet, newface);
            if (newface.tet[newface.ver & 3] == NULL) {
              // An open face. Connect it to its adjacent tet.
              sspivot(newsh, checkseg);
              if (checkseg.sh != NULL) {
                // A segment. It must not be the recovered segment.
                assert(checkseg.sh != rightseg.sh);
                tssbond1(newtet, checkseg);
                //sstbond1(checkseg, newtet);
              }
              spivot(newsh, neighsh);
              if (neighsh.sh != NULL) {
                // The adjacent subface exists. It's not a dangling segment.
                if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
                stpivot(neighsh, neightet);
                if (sinfected(neighsh)) {
                  esymself(neightet);
                  assert(neightet.tet[neightet.ver & 3] == NULL);          
                } else {
                  // Search for an open face at this edge.
                  spintet = neightet;
                  while (1) {
                    esym(spintet, searchtet);
                    fsym(searchtet, spintet);
                    if (spintet.tet == NULL) break;
                    assert(spintet.tet != neightet.tet);
                  }
                  // Found an open face at 'searchtet'.
                  neightet = searchtet;
                }
              } else {
                // The edge (at 'newsh') is a dangling segment.
                assert(checkseg.sh != NULL);
                // Get an adjacent tet at this segment.
                sstpivot1(checkseg, neightet);
                assert(!isdeadtet(neightet));
                if (org(neightet) != sdest(newsh)) esymself(neightet);
                assert((org(neightet) == sdest(newsh)) &&
                       (dest(neightet) == sorg(newsh)));
                // Search for an open face at this edge.
                spintet = neightet;
                while (1) {
                  esym(spintet, searchtet);
                  fsym(searchtet, spintet);
                  if (spintet.tet == NULL) break;
                  assert(spintet.tet != neightet.tet);
                }
                // Found an open face at 'searchtet'.
                neightet = searchtet;
              }
              pc = apex(newface);
              if (pc == dummypoint) {
                setapex(newface, apex(neightet));
              } else {
                assert(pc == apex(neightet));
              }
              bond(newface, neightet);
            } // if (newface.tet[newface.ver & 3] == NULL)
            enextself(newtet);
            senextself(newsh);
          } // j
          sesymself(newsh);
        } // k
      } // i
    
      // Unmark all new subfaces.
      for (i = 0; i < caveshbdlist->objects; i++) {
        parysh = (face *) fastlookup(caveshbdlist, i);
        suninfect(*parysh);
      }
      caveshbdlist->restart();
    
    
      setpointtype(steinerpt, UNUSEDVERTEX);
      unuverts++;
      if (vt == FREESEGVERTEX) {
        st_segref_count--;
      } else { // vt == FREEFACETVERTEX
        st_facref_count--;
      }
      if (steinerleft > 0) steinerleft++;
    
      if (b->verbose > 2) {
        printf("      Duplicated %ld Steiner points.\n", 
               suppsteinerptlist->objects - bak_supp_steiners);
      }
    
      return 1;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // suppresssteinerpoints()    Suppress Steiner points.                       //
    //                                                                           //
    // Each Steiner point is either removed or shifted into the interior.        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::suppresssteinerpoints()
    {
      triface *parytet;
      point rempt, *parypt, *plastpt, *ppt;
      optparameters opm;
      REAL ori;
      int bak_fliplinklevel;
      int remcount, smtcount;
      int count, nt;
      int i, j;
    
      if (!b->quiet) {
        printf("Suppressing Steiner points ...\n");
      }
    
      bak_fliplinklevel = b->fliplinklevel;
      b->fliplinklevel = 100000; // Unlimited flip level.
      remcount = 0;
    
      if (b->nobisect_param > 1) { // -Y2
        // Try to remove all the Steiner points.
        for (i = 0; i < subvertstack->objects; i++) {
          parypt = (point *) fastlookup(subvertstack, i);
          rempt = *parypt;
          if (pointtype(rempt) != UNUSEDVERTEX) {
            if (removevertexbyflips(rempt)) {
              remcount++;
            }
          }
        }
        if (b->verbose) {
          if (remcount > 0) {
            printf("  Removed %d Steiner points.\n", remcount);
          }
        }
        subvertstack->restart();
      }
    
      remcount = smtcount = 0;
    
      // Try to remove the suppressed Steiner points.
      for (i = 0; i < suppsteinerptlist->objects; i++) {
        // Get the Steiner point.
        parypt = (point *) fastlookup(suppsteinerptlist, i);
        rempt = *parypt;
        if (pointtype(rempt) != UNUSEDVERTEX) {
          assert((pointtype(rempt) == FREESEGVERTEX) ||
                 (pointtype(rempt) == FREEFACETVERTEX) ||
                 (pointtype(rempt) == FREEVOLVERTEX));
          if (removevertexbyflips(rempt)) {
            // Move the last entry to fill the current one.
            j = (int) (suppsteinerptlist->objects - 1);
            plastpt = (point *) fastlookup(suppsteinerptlist, j);
            *parypt = *plastpt;
            suppsteinerptlist->objects--;
            i--;
            remcount++;
          }
        } else {
          // The point has been removed.
          // Move the last entry to fill the current one.
          j = (int) (suppsteinerptlist->objects - 1);
          plastpt = (point *) fastlookup(suppsteinerptlist, j);
          *parypt = *plastpt;
          suppsteinerptlist->objects--;
          i--;
        }
      } // i
    
      if (b->verbose) {
        if (remcount > 0) {
          printf("  Removed %d suppressed Steiner points.\n", remcount);
        }
      }
    
      if (suppsteinerptlist->objects == 0l) {
        b->fliplinklevel = bak_fliplinklevel;
        return remcount;
      }
    
      // Point smooth options.
      opm.max_min_volume = 1;
      opm.numofsearchdirs = 20;
      opm.searchstep = 0.001;
    
      nt = 0;
    
      while (1) {
        // Try to smooth volume Steiner points.
        count = 0;
    
        for (i = 0; i < suppsteinerptlist->objects; i++) {
          parypt = (point *) fastlookup(suppsteinerptlist, i);
          rempt = *parypt;
          if (pointtype(rempt) == FREEVOLVERTEX) {
            getvertexstar(1, rempt, cavetetlist, NULL, NULL);
            // Calculate the initial smallest volume (maybe zero or negative).
            for (j = 0; j < cavetetlist->objects; j++) {
              parytet = (triface *) fastlookup(cavetetlist, j);
              ppt = (point *) &(parytet->tet[4]);
              ori = orient3d(ppt[1], ppt[0], ppt[2], ppt[3]);
              if (j == 0) {
                opm.initval = ori;
              } else {
                if (opm.initval > ori) opm.initval = ori; 
              }
            }
            if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
              count++;
            }
            cavetetlist->restart();
          }
        } // i
    
        smtcount += count;
    
        if (count == 0) {
          // No point has been smoothed.
          break;
        }
    
        nt++;
        if (nt > 2) {
          break; // Already three iterations.
        }
      } // while
    
      // The mesh should not contain inverted (or degenrrated) tets now.
      checkinverttetflag = 0;
    
      if (b->verbose) {
        if (smtcount > 0) {
          printf("  Smoothed %d Steiner points.\n", smtcount); 
        }
      }
    
      b->fliplinklevel = bak_fliplinklevel;
    
      return smtcount;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // recoverboundary()    Recover segments and facets.                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::recoverboundary(clock_t& tv)
    {
      arraypool *misseglist, *misshlist;
      arraypool *bdrysteinerptlist;
      face searchsh, *parysh;
      face searchseg, *paryseg;
      point rempt, *parypt;
      long ms; // The number of missing segments/subfaces.
      int nit; // The number of iterations.
      int s, i;
    
      // Counters.
      long bak_segref_count, bak_facref_count, bak_volref_count;
      long bak_supp_count;
    
      if (!b->quiet) {
        printf("Recovering boundaries...\n");
      }
    
      if (b->verbose) {
        printf("  Flip link level = %d\n", b->fliplinklevel);
      }
    
      //markacutevertices();
    
      if (b->verbose) {
        printf("  Recovering segments.\n");
      }
    
      // Segments will be introduced.
      checksubsegflag = 1;
    
      misseglist = new arraypool(sizeof(face), 8);
      bdrysteinerptlist = new arraypool(sizeof(point), 8);
    
      if (0) { //if (b->order == 4) {  // '-o4' option (for debug)
        // In sequential order.
        subsegs->traversalinit();
        for (i = 0; i < subsegs->items; i++) {
          searchseg.sh = shellfacetraverse(subsegs);
          //sinfect(searchseg);  // Only save it once.
          subsegstack->newindex((void **) &paryseg);
          *paryseg = searchseg;
        }
      } else {
        // In random order.
        subsegs->traversalinit();
        for (i = 0; i < subsegs->items; i++) {
          s = randomnation(i + 1);
          // Move the s-th seg to the i-th.
          subsegstack->newindex((void **) &paryseg);
          *paryseg = * (face *) fastlookup(subsegstack, s);
          // Put i-th seg to be the s-th.
          searchseg.sh = shellfacetraverse(subsegs);
          //sinfect(searchseg);  // Only save it once.
          paryseg = (face *) fastlookup(subsegstack, s);
          *paryseg = searchseg;
        }
      }
    
      // The init number of missing segments.
      ms = subsegs->items;
      nit = 0; 
      if (b->fliplinklevel < 0) {
        autofliplinklevel = 1; // Init value.
      }
    
      while (1) {
    
        recoversegments(misseglist, 0, 0);
    
        if (misseglist->objects > 0) {
          if (b->fliplinklevel >= 0) {
            break;
          } else {
            if (misseglist->objects >= ms) {
              nit++;
              if (nit >= 3) {
                //break;
                // Do the last round with unbounded flip link level.
                b->fliplinklevel = 100000;
              }
            } else {
              ms = misseglist->objects;
              if (nit > 0) {
                nit--;
              }
            }
            for (i = 0; i < misseglist->objects; i++) {
              subsegstack->newindex((void **) &paryseg);
              *paryseg = * (face *) fastlookup(misseglist, i);
            }
            misseglist->restart();
            autofliplinklevel+=b->fliplinklevelinc;
          }
        } else {
          // All segments are recovered.
          break;
        }
      } // while (1)
    
      if (b->verbose) {
        printf("  %ld (%ld) segments are recovered (missing).\n", 
               subsegs->items - misseglist->objects, misseglist->objects);
      }
    
      if (misseglist->objects > 0) {
        // There are missing segments. Increase the fliplevel.
        nit = 0;
        while (misseglist->objects > 0) {
          ms = misseglist->objects;
          for (i = 0; i < misseglist->objects; i++) {
            subsegstack->newindex((void **) &paryseg);
            *paryseg = * (face *) fastlookup(misseglist, i);
          }
          misseglist->restart();
    
          // Recover the missing segments by doing more flips.
          recoversegments(misseglist, 1, 0);
    
          if (misseglist->objects < ms) {
            // The number of missing segments is reduced.
            continue;
          } else {
            nit++;
            if (nit >= 3) {
              break;
            }
          }
        }
        if (b->verbose) {
          printf("  %ld (%ld) segments are recovered (missing).\n", 
                 subsegs->items - misseglist->objects, misseglist->objects);
        }
      }
    
      if (misseglist->objects > 0) {
        // There are missing segments. Add Steiner points in volume.
        nit = 0;
        while (misseglist->objects > 0) {
          ms = misseglist->objects;
          for (i = 0; i < misseglist->objects; i++) {
            subsegstack->newindex((void **) &paryseg);
            *paryseg = * (face *) fastlookup(misseglist, i);
          }
          misseglist->restart();
    
          // Recover the missing segments (with Steiner points).
          recoversegments(misseglist, 1, 1);
    
          if (misseglist->objects < ms) {
            // The number of missing segments is reduced.
            continue;
          } else {
            nit++;
            if (nit >= 3) {
              break;
            }
          }
        }
        if (b->verbose) {
          printf("  Added %ld Steiner points in volume.\n", st_volref_count);
        }
      }
    
      if (misseglist->objects > 0) {
        // There are missing segments. Add Steiner points to split them.
        long bak_inpoly_count = st_volref_count; //st_inpoly_count;
        for (i = 0; i < misseglist->objects; i++) {
          subsegstack->newindex((void **) &paryseg);
          *paryseg = * (face *) fastlookup(misseglist, i);
        }
        misseglist->restart();
    
        // Recover the missing segments (with Steiner points).
        recoversegments(misseglist, 1, 2);
    
        if (b->verbose) {
          printf("  Added %ld Steiner points in segments.\n", st_segref_count);
          if (st_volref_count > bak_inpoly_count) {
            printf("  Added another %ld Steiner points in volume.\n", 
                   st_volref_count - bak_inpoly_count);
          }
        }
        assert(misseglist->objects == 0l);
      }
    
    
      if (st_segref_count > 0) {
        // Try to remove the Steiner points added in segments.
        bak_segref_count = st_segref_count;
        bak_volref_count = st_volref_count;
        for (i = 0; i < subvertstack->objects; i++) {
          // Get the Steiner point.
          parypt = (point *) fastlookup(subvertstack, i);
          rempt = *parypt;
          if (!removevertexbyflips(rempt)) {
            // Save it in list.
            bdrysteinerptlist->newindex((void **) &parypt);
            *parypt = rempt;
          }
        }
        if (b->verbose) {
          if (st_segref_count < bak_segref_count) {
            if (bak_volref_count < st_volref_count) {
              printf("  Suppressed %ld Steiner points in segments.\n", 
                     st_volref_count - bak_volref_count);
            }
            if ((st_segref_count + (st_volref_count - bak_volref_count)) <
                bak_segref_count) {
              printf("  Removed %ld Steiner points in segments.\n", 
                     bak_segref_count - 
                       (st_segref_count + (st_volref_count - bak_volref_count)));
            }
          }
        }
        subvertstack->restart();
      }
    
    
      tv = clock();
    
      if (b->verbose) {
        printf("  Recovering facets.\n");
      }
    
      // Subfaces will be introduced.
      checksubfaceflag = 1;
    
      misshlist = new arraypool(sizeof(face), 8);
    
      // Randomly order the subfaces.
      subfaces->traversalinit();
      for (i = 0; i < subfaces->items; i++) {
        s = randomnation(i + 1);
        // Move the s-th subface to the i-th.
        subfacstack->newindex((void **) &parysh);
        *parysh = * (face *) fastlookup(subfacstack, s);
        // Put i-th subface to be the s-th.
        searchsh.sh = shellfacetraverse(subfaces);
        parysh = (face *) fastlookup(subfacstack, s);
        *parysh = searchsh;
      }
    
      ms = subfaces->items;
      nit = 0; 
      b->fliplinklevel = -1; // Init.
      if (b->fliplinklevel < 0) {
        autofliplinklevel = 1; // Init value.
      }
    
      while (1) {
        recoversubfaces(misshlist, 0);
        if (misshlist->objects > 0) {
          if (b->fliplinklevel >= 0) {
            break;
          } else {
            if (misshlist->objects >= ms) {
              nit++;
              if (nit >= 3) {
                //break;
                // Do the last round with unbounded flip link level.
                b->fliplinklevel = 100000;
              }
            } else {
              ms = misshlist->objects;
              if (nit > 0) {
                nit--;
              }
            }
            for (i = 0; i < misshlist->objects; i++) {
              subfacstack->newindex((void **) &parysh);
              *parysh = * (face *) fastlookup(misshlist, i);
            }
            misshlist->restart();
            autofliplinklevel+=b->fliplinklevelinc;
          }
        } else {
          // All subfaces are recovered.
          break;
        }
      } // while (1)
    
      if (b->verbose) {
        printf("  %ld (%ld) subfaces are recovered (missing).\n", 
               subfaces->items - misshlist->objects, misshlist->objects);
      }
    
      if (misshlist->objects > 0) {
        // There are missing subfaces. Add Steiner points.
        for (i = 0; i < misshlist->objects; i++) {
          subfacstack->newindex((void **) &parysh);
          *parysh = * (face *) fastlookup(misshlist, i);
        }
        misshlist->restart();
    
        recoversubfaces(NULL, 1);
    
        if (b->verbose) {
          printf("  Added %ld Steiner points in facets.\n", st_facref_count);
        }
      }
    
    
      if (st_facref_count > 0) {
        // Try to remove the Steiner points added in facets.
        bak_facref_count = st_facref_count;
        for (i = 0; i < subvertstack->objects; i++) {
          // Get the Steiner point.
          parypt = (point *) fastlookup(subvertstack, i);
          rempt = *parypt;
          if (!removevertexbyflips(*parypt)) {
            // Save it in list.
            bdrysteinerptlist->newindex((void **) &parypt);
            *parypt = rempt;
          }
        }
        if (b->verbose) {
          if (st_facref_count < bak_facref_count) {
            printf("  Removed %ld Steiner points in facets.\n", 
                   bak_facref_count - st_facref_count);
          }
        }
        subvertstack->restart();
      }
    
    
      if ((bdrysteinerptlist->objects > 0) && (b->nobisect_param > 0)) { // -Y1
        bak_supp_count = 0;
        b->fliplinklevel = 100000; // Unlimited flip levels.
        do {
          // Suppress boundary Steiner points.
          for (i = 0; i < bdrysteinerptlist->objects; i++) {
            parypt = (point *) fastlookup(bdrysteinerptlist, i);
            rempt = *parypt;
            suppressssteinerpoint(rempt);
            bak_supp_count++;
          }
          bdrysteinerptlist->restart();
          // There may be subfaces need to be recover.
          if (subfacstack->objects > 0l) {
            recoversubfaces(NULL, 1);
          }
        } while (bdrysteinerptlist->objects > 0);
        if (b->verbose) {
          printf("  Suppressed %ld Steiner points from boundary.\n", 
                 bak_supp_count);
        }
        // The mesh contains inverted (or degenrrated) tets now.
        checkinverttetflag = 1;
      } // if
    
    
      delete bdrysteinerptlist;
      delete misseglist;
      delete misshlist;
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// steiner_cxx //////////////////////////////////////////////////////////////
    
    
    //// reconstruct_cxx //////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // carveholes()    Remove tetrahedra not in the mesh domain.                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::carveholes()
    {
      arraypool *tetarray;
      triface tetloop, neightet, hulltet, *parytet;
      triface openface, casface;
      triface *regiontets;
      face checksh, casingout, casingin, *parysh;
      face checkseg;
      point *ppt, pa, pb, pc, *parypt;
      enum locateresult loc;
      REAL volume;
      long delsegcount, delvertcount, delsteinercount;
      int regioncount;
      int attrnum, attr, maxattr;
      int remflag;
      int i, j;
    
      tetrahedron ptr;
    
      if (!b->quiet) {
        printf("Removing exterior tetrahedra ...\n");
      }
    
      // Initialize the pool of exterior tets.
      tetarray = new arraypool(sizeof(triface), 10);
      regiontets = NULL;
    
      maxattr = 0; // Choose a small number here.
      attrnum = in->numberoftetrahedronattributes;
    
      // Mark as infected any unprotected hull tets.
      tetrahedrons->traversalinit();
      tetloop.ver = 11; // The face opposite to dummypoint.
      tetloop.tet = alltetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        if ((point) tetloop.tet[7] == dummypoint) {
          // Is this side protected by a subface?
          tspivot(tetloop, checksh);
          if (checksh.sh == NULL) {
            infect(tetloop);
            tetarray->newindex((void **) &parytet);
            *parytet = tetloop;
          }
        }
        tetloop.tet = alltetrahedrontraverse();
      }
    
      hullsize -= tetarray->objects;
    
      if (in->numberofholes > 0) {
        // Mark as infected any tets inside volume holes.
        for (i = 0; i < 3 * in->numberofholes; i += 3) {
          // Search a tet containing the i-th hole point.
          neightet.tet = NULL;
          randomsample(&(in->holelist[i]), &neightet);
          loc = locate(&(in->holelist[i]), &neightet, 0, 1); // randflag = 1;
          if (loc != OUTSIDE) {
            infect(neightet);
            tetarray->newindex((void **) &parytet);
            *parytet = neightet;
          } else {
            // A hole point locates outside of the convex hull.
            if (!b->quiet) {
              printf("Warning:  The %d-th hole point ", i/3 + 1);
              printf("lies outside the convex hull.\n");
            }
          }
        }
      }
    
      if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option.
        // Record the tetrahedra that contains the region points for assigning
        //   region attributes after the holes have been carved.
        regiontets = new triface[in->numberofregions];
        // Mark as marktested any tetrahedra inside volume regions.
        for (i = 0; i < 5 * in->numberofregions; i += 5) {
          // Search a tet containing the i-th region point.
          neightet.tet = NULL;
          randomsample(&(in->regionlist[i]), &neightet);
          loc = locate(&(in->regionlist[i]), &neightet, 0, 1); // randflag = 1;
          if (loc != OUTSIDE) {
            regiontets[i/5] = neightet;
            if ((int) in->regionlist[i + 3] > maxattr) {
              maxattr = (int) in->regionlist[i + 3];
            }
          } else {
            if (!b->quiet) {
              printf("Warning:  The %d-th region point ", i/5+1);
              printf("lies outside the convex hull.\n");
            }
            regiontets[i/5].tet = NULL;
          }
        }
      }
    
      // Find and infect all exterior tets (in concave place and in holes).
      for (i = 0; i < tetarray->objects; i++) {
        parytet = (triface *) fastlookup(tetarray, i);
        tetloop = *parytet;
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, neightet);
          // Is this side protected by a subface?
          tspivot(tetloop, checksh);
          if (checksh.sh == NULL) {
            // Not protected. Infect it if it is not a hull tet.
            if ((point) neightet.tet[7] != dummypoint) {
              if (!infected(neightet)) {
                infect(neightet);
                tetarray->newindex((void **) &parytet);
                *parytet = neightet;
              }
            }
          } else {
            // Its adjacent tet is protected.
            if ((point) neightet.tet[7] == dummypoint) {
              // A hull tet. It is dead.
              assert(!infected(neightet));
              infect(neightet);
              tetarray->newindex((void **) &parytet);
              *parytet = neightet;
              // Both sides of this subface are exterior.
              stdissolve(checksh);
              // Queue this subface (to be deleted later).
              if (!sinfected(checksh)) {
                sinfect(checksh); // Only queue it once.
                subfacstack->newindex((void **) &parysh);
                *parysh = checksh;
              }
              hullsize--;
            } else {
              if (!infected(neightet)) {
                // The subface is still connect to a "live" tet - it survived.
                // tsbond(neightet, checksh);
              } else {
                // Both sides of this subface are exterior.
                stdissolve(checksh);
                // Queue this subface (to be deleted later).
                if (!sinfected(checksh)) {
                  sinfect(checksh); // Only queue it once.
                  subfacstack->newindex((void **) &parysh);
                  *parysh = checksh;
                }
              }
            }
          }
        }
      }
    
      if (b->regionattrib && (in->numberofregions > 0)) {
        // Re-check saved region tets to see if they lie outside.
        for (i = 0; i < in->numberofregions; i++) {
          if (infected(regiontets[i])) {
            if (b->verbose) {
              printf("Warning:  The %d-th region point ", i+1);
              printf("lies in the exterior of the domain.\n");
            }
            regiontets[i].tet = NULL;
          }
        }
      }
    
      // Remove all exterior tetrahedra (including infected hull tets).
      for (i = 0; i < tetarray->objects; i++) {
        parytet = (triface *) fastlookup(tetarray, i);
        tetloop = *parytet;
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, neightet);
          if (!infected(neightet)) {
            // A "live" tet (may be a hull tet). Clear its adjacent tet.
            neightet.tet[neightet.ver & 3] = NULL;
          }
        }
        tetrahedrondealloc(parytet->tet);
      } // i
    
      tetarray->restart(); // Re-use it for new hull tets.
    
      // Create new hull tets. 
      // Update point-to-tet map, segment-to-tet map, and subface-to-tet map.
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          if (tetloop.tet[tetloop.ver] == NULL) {
            tspivot(tetloop, checksh);
            assert(checksh.sh != NULL); // SELF_CHECK
            // Create a new hull tet.
            maketetrahedron(&hulltet);
            pa = org(tetloop);
            pb = dest(tetloop);
            pc = apex(tetloop);
            setvertices(hulltet, pb, pa, pc, dummypoint);
            bond(tetloop, hulltet);
            // Update the subface-to-tet map.
            sesymself(checksh);
            tsbond(hulltet, checksh);
            // Update the segment-to-tet map.
            for (i = 0; i < 3; i++) {
              tsspivot1(tetloop, checkseg);
              if (checkseg.sh != NULL) {
                tssbond1(hulltet, checkseg);
                sstbond1(checkseg, hulltet);
              }
              enextself(tetloop);
              eprevself(hulltet);
            }
            // Save this hull tet in list.
            tetarray->newindex((void **) &parytet);
            *parytet = hulltet;
          }
        }
        // Update the point-to-tet map.
        tetloop.ver = 0;
        ptr = encode(tetloop);
        ppt = (point *) tetloop.tet;
        for (i = 4; i < 8; i++) {
          setpoint2tet(ppt[i], ptr);
        }
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (subfacstack->objects > 0) {
        // Remove all subfaces which do not attach to any tetrahedron.
        //   Segments which are not attached to any subfaces and tets
        //   are deleted too.
        delsegcount = 0;
        for (i = 0; i < subfacstack->objects; i++) {
          parysh = (face *) fastlookup(subfacstack, i);
          if (i == 0) {
            if (b->verbose) {
              printf("Warning:  Removing an open face (%d, %d, %d)\n",
                     pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
                     pointmark(sapex(*parysh)));
            }
          }
          // Dissolve this subface from face links.
          for (j = 0; j < 3; j++) {         
            spivot(*parysh, casingout);
            sspivot(*parysh, checkseg);
            if (casingout.sh != NULL) {
              casingin = casingout;
              while (1) {
                spivot(casingin, checksh);
                if (checksh.sh == parysh->sh) break;
                casingin = checksh;
              }
              if (casingin.sh != casingout.sh) {
                // Update the link: ... -> casingin -> casingout ->...
                sbond1(casingin, casingout);
              } else {
                // Only one subface at this edge is left.
                sdissolve(casingout);
              }
              if (checkseg.sh != NULL) {
                // Make sure the segment does not connect to a dead one.
                ssbond(casingout, checkseg);
              }
            } else {
              if (checkseg.sh != NULL) {
                // The segment is also dead.
                if (delsegcount == 0) {
                  if (b->verbose) {
                    printf("Warning:  Removing a dangling segment (%d, %d)\n",
                           pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
                  }
                }
                shellfacedealloc(subsegs, checkseg.sh);
                delsegcount++;
              }
            }
            senextself(*parysh);
          } // j
          // Delete this subface.
          shellfacedealloc(subfaces, parysh->sh);
        } // i
        if (b->verbose) {
          printf("  Deleted %ld subfaces.\n", subfacstack->objects);
          if (delsegcount > 0) {
            printf("  Deleted %ld segments.\n", delsegcount);
          }
        }
        subfacstack->restart();
      }
    
      // Some vertices may be not belong to any tet. Mark them.
      delvertcount = unuverts;
      delsteinercount = 0l;
      points->traversalinit();
      pa = pointtraverse();
      while (pa != NULL) {
        if (pointtype(pa) != UNUSEDVERTEX) {
          remflag = 0;
          decode(point2tet(pa), neightet);
          if ((neightet.tet == NULL) || (neightet.tet[4] == NULL)) {
            remflag = 1; // It's a dead tet.
          } else {
            // Check if this tet contains pa.
            ppt = (point *) &(neightet.tet[4]);
            if (!((ppt[0] == pa) || (ppt[1] == pa) || 
                  (ppt[2] == pa) || (ppt[3] == pa))) {
              remflag = 1; // It's a wrong pointer.
            }
          }
          if (remflag) {
            // Found an exterior vertex.
            if (pointmark(pa) > 
                  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
              if (pointtype(pa) == FREESEGVERTEX) {
                st_segref_count--;
              } else if (pointtype(pa) == FREEFACETVERTEX) {
                st_facref_count--;
              } else {
                assert(pointtype(pa) == FREEVOLVERTEX);
                st_volref_count--; //st_inpoly_count--;
              }
              delsteinercount++; // A Steiner point.
              if (steinerleft > 0) steinerleft++;
            }
            setpointtype(pa, UNUSEDVERTEX);
            unuverts++;
          } else {
            // This vertex survived. 
            if (b->nobisect && (b->nobisect_param > 1)) { // -Y2
              // Queue it if it is a Steiner point.
              if ((pointtype(pa) == FREESEGVERTEX) ||
                  (pointtype(pa) == FREEFACETVERTEX) ||
                  (pointtype(pa) == FREEVOLVERTEX)) {
                subvertstack->newindex((void **) &parypt);
                *parypt = pa;
              }
            }
          }
        }
        pa = pointtraverse();
      }
    
      if (b->verbose) {
        if (unuverts > delvertcount) {
          if (delsteinercount > 0l) {
            if (unuverts > (delvertcount + delsteinercount)) {
              printf("  Removed %ld exterior input vertices.\n", 
                     unuverts - delvertcount - delsteinercount);
            }
            printf("  Removed %ld exterior Steiner vertices.\n", delsteinercount);
          } else {
            printf("  Removed %ld exterior input vertices.\n", 
                   unuverts - delvertcount);
          }
        }
      }
    
      // Update the hull size.
      hullsize += tetarray->objects;
    
      // Connect new hull tets.
      for (i = 0; i < tetarray->objects; i++) {
        parytet = (triface *) fastlookup(tetarray, i);
        hulltet = *parytet;
        for (j = 0; j < 3; j++) {
          esym(hulltet, neightet);
          if (neightet.tet[neightet.ver & 3] == NULL) {
            tspivot(hulltet, checksh);
            assert(checksh.sh != NULL);
            // Get the next subface in the same face ring of checksh. It must
            //   exist, otherwise, checksh is either a dangling subface (which
            //   should be removed already), or it is not a hull face.
            sfnext(checksh, casingout);
            assert(casingout.sh != NULL);
            // Go to the hull side.
            sesymself(casingout);
            stpivot(casingout, casface);
            assert(ishulltet(casface));
            esymself(casface);
            assert(casface.tet[casface.ver & 3] == NULL);
            // Bond the two hull tets together.
            bond(neightet, casface);
          }
          enextself(hulltet);
        }
      }
    
      // Set region attributes (when has -A and -AA options).
      if (b->regionattrib) {
    
        if (!b->quiet) {
          printf("Spreading region attributes.\n");
        }
        regioncount = 0;
    
        // If has user-defined region attributes.
        if (in->numberofregions > 0) {
          // Spread region attributes.
          for (i = 0; i < 5 * in->numberofregions; i += 5) {
            if (regiontets[i/5].tet != NULL) {
              attr = (int) in->regionlist[i + 3];
              volume = in->regionlist[i + 4];
              tetarray->restart(); // Re-use this array.
              infect(regiontets[i/5]);
              tetarray->newindex((void **) &parytet);
              *parytet = regiontets[i/5];
              // Collect and set attrs for all tets of this region.
              for (j = 0; j < tetarray->objects; j++) {
                parytet = (triface *) fastlookup(tetarray, j);
                tetloop = *parytet;
                setelemattribute(tetloop.tet, attrnum, attr);
                if (b->varvolume) { // If has -a option.
                  setvolumebound(tetloop.tet, volume);
                }
                for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
                  fsym(tetloop, neightet);
                  // Is this side protected by a subface?
                  tspivot(tetloop, checksh);
                  if (checksh.sh == NULL) {
                    // Not protected. It must not be a hull tet.
                    // assert((point) neightet.tet[7] != dummypoint);
                    if ((point) neightet.tet[7] == dummypoint) {
                      assert(0);
                    }
                    if (!infected(neightet)) {
                      infect(neightet);
                      tetarray->newindex((void **) &parytet);
                      *parytet = neightet;
                    }
                  } else {
                    // Protected. Set attribute for hull tet as well.
                    if ((point) neightet.tet[7] == dummypoint) {
                      setelemattribute(neightet.tet, attrnum, attr);
                      if (b->varvolume) { // If has -a option.
                        setvolumebound(neightet.tet, volume);
                      }
                    }
                  }
                } // ver
              } // j
              regioncount++;
            } // if (regiontets[i/5].tet != NULL)
          } // i
        }
    
        if (b->regionattrib > 1) { // If has -AA option.
          // Set attributes for all tetrahedra.
          attr = maxattr + 1;
          tetrahedrons->traversalinit();
          tetloop.tet = tetrahedrontraverse();
          while (tetloop.tet != (tetrahedron *) NULL) {
            if (!infected(tetloop)) {
              // An unmarked region.
              tetarray->restart(); // Re-use this array.
              infect(tetloop);
              tetarray->newindex((void **) &parytet);
              *parytet = tetloop;
              // Find and mark all tets.
              for (j = 0; j < tetarray->objects; j++) {
                parytet = (triface *) fastlookup(tetarray, j);
                tetloop = *parytet;
                setelemattribute(tetloop.tet, attrnum, attr);
                for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
                  fsym(tetloop, neightet);
                  // Is this side protected by a subface?
                  tspivot(tetloop, checksh);
                  if (checksh.sh == NULL) {
                    // Not protected. It must not be a hull tet.
                    assert((point) neightet.tet[7] != dummypoint);
                    if (!infected(neightet)) {
                      infect(neightet);
                      tetarray->newindex((void **) &parytet);
                      *parytet = neightet;
                    }
                  } else {
                    // Protected. Set attribute for hull tet as well.
                    if ((point) neightet.tet[7] == dummypoint) {
                      setelemattribute(neightet.tet, attrnum, attr);
                    }
                  }
                } // loc
              }
              attr++; // Increase the attribute.
              regioncount++;
            } // if (!infected(tetloop))
            tetloop.tet = tetrahedrontraverse();
          }
          // Until here, every tet has a region attribute.
        }
    
        // Uninfect processed tets.
        tetrahedrons->traversalinit();
        tetloop.tet = tetrahedrontraverse();
        while (tetloop.tet != (tetrahedron *) NULL) {
          uninfect(tetloop);
          tetloop.tet = tetrahedrontraverse();
        }
    
        // Mesh elements contain region attributes now.
        in->numberoftetrahedronattributes++;
    
        if (b->verbose) {
          assert(regioncount > 0);
          if (regioncount > 1) {
            printf("  Found %d subdomains.\n", regioncount);
          } else {
            printf("  Found 1 domain.\n");
          }
        }
    
      } // if (b->regionattrib)
    
      if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option.
        delete [] regiontets;
      }
      delete tetarray;
    
      // The mesh is non-convex now.
      nonconvex = 1;
    
      // Push all hull tets into 'flipstack'.
      tetrahedrons->traversalinit();
      tetloop.ver = 11; // The face opposite to dummypoint.
      tetloop.tet = alltetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        if ((point) tetloop.tet[7] == dummypoint) {
          flippush(flipstack, &tetloop);
        }
        tetloop.tet = alltetrahedrontraverse();
      }
    
      // Peel "slivers" off the hull.
      lawsonflip3d(NULL, 4, 1, 0, 0);
    
      if (b->verbose && (opt_sliver_peels > 0l)) {
        printf("  Peeled %ld hull slivers.\n", opt_sliver_peels);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // reconstructmesh()    Reconstruct a tetrahedral mesh.                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::reconstructmesh()
    {
      tetrahedron *ver2tetarray;
      point *idx2verlist;
      triface tetloop, checktet, prevchktet;
      triface hulltet, face1, face2;
      tetrahedron tptr;
      face subloop, neighsh, nextsh;
      face segloop;
      shellface sptr;
      point p[4], q[3];
      REAL ori, attrib, volume;
      REAL angtol, ang;
      int eextras, marker = 0;
      int bondflag;
      int idx, i, j, k;
    
      if (!b->quiet) {
        printf("Reconstructing mesh ...\n");
      }
      // Default assume the mesh is non-convex.
      nonconvex = 1;
    
      // Create a map from indices to vertices.
      makeindex2pointmap(idx2verlist);
    
      // Allocate an array that maps each vertex to its adjacent tets.
      ver2tetarray = new tetrahedron[in->numberofpoints + 1];
      for (i = 0; i < in->numberofpoints; i++) {
        ver2tetarray[i] = NULL;
      }
    
      // Create the tetrahedra and connect those that share a common face.
      for (i = 0; i < in->numberoftetrahedra; i++) {
        // Get the four vertices.
        idx = i * in->numberofcorners;
        for (j = 0; j < 4; j++) {
          p[j] = idx2verlist[in->tetrahedronlist[idx++]];
          setpointtype(p[j], VOLVERTEX); // initial type.
        }
        // Check the orientation.
        ori = orient3d(p[0], p[1], p[2], p[3]);
        if (ori > 0.0) {
          // Swap the first two vertices.
          q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
        } else if (ori == 0.0) {
          if (!b->quiet) {
            printf("Warning:  Tet #%d is degenerate.\n", i + in->firstnumber);
          }
        }
        // Create a new tetrahedron.
        maketetrahedron(&tetloop); // tetloop.ver = 11.
        setvertices(tetloop, p[0], p[1], p[2], p[3]);
        // Set element attributes if they exist.
        for (j = 0; j < in->numberoftetrahedronattributes; j++) {
          idx = i * in->numberoftetrahedronattributes;
          attrib = in->tetrahedronattributelist[idx + j];
          setelemattribute(tetloop.tet, j, attrib);
        }
        // If -a switch is used (with no number follows) Set a volume
        //   constraint if it exists.
        if (b->varvolume) {
          if (in->tetrahedronvolumelist != (REAL *) NULL) {
            volume = in->tetrahedronvolumelist[i];
          } else {
            volume = -1.0;
          }
          setvolumebound(tetloop.tet, volume);
        }
        // Try connecting this tet to others that share the common faces.
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          p[3] = oppo(tetloop);
          // Look for other tets having this vertex.
          idx = pointmark(p[3]);
          tptr = ver2tetarray[idx];
          // Link the current tet to the next one in the stack.
          tetloop.tet[8 + tetloop.ver] = tptr;
          // Push the current tet onto the stack.
          ver2tetarray[idx] = encode(tetloop);
          decode(tptr, checktet);
          if (checktet.tet != NULL) {
            p[0] =  org(tetloop); // a
            p[1] = dest(tetloop); // b
            p[2] = apex(tetloop); // c
            prevchktet = tetloop;
            do {
              assert(checktet.ver < 4); // SELF_CHECK
              q[0] =  org(checktet); // a'
              q[1] = dest(checktet); // b'
              q[2] = apex(checktet); // c'
              // Check the three faces at 'd' in 'checktet'.
              bondflag = 0;
              for (j = 0; j < 3; j++) {
                // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
                esym(checktet, face2);
                if (face2.tet[face2.ver & 3] == NULL) {
                  k = ((j + 1) % 3);
                  if (q[k] == p[0]) {   // b', c', a' = a
                    if (q[j] == p[1]) { // a', b', c' = b
                      // [#,#,d] is matched to [b,a,d].
                      esym(tetloop, face1);
                      bond(face1, face2);
                      bondflag++;
                    }
                  }
                  if (q[k] == p[1]) {   // b',c',a' = b
                    if (q[j] == p[2]) { // a',b',c' = c
                      // [#,#,d] is matched to [c,b,d].
                      enext(tetloop, face1);
                      esymself(face1);
                      bond(face1, face2);
                      bondflag++;
                    }
                  }
                  if (q[k] == p[2]) {   // b',c',a' = c
                    if (q[j] == p[0]) { // a',b',c' = a
                      // [#,#,d] is matched to [a,c,d].
                      eprev(tetloop, face1);
                      esymself(face1);
                      bond(face1, face2);
                      bondflag++;
                    }
                  }
                } else {
                  bondflag++;
                }
                enextself(checktet);
              } // j
              // Go to the next tet in the link.
              tptr = checktet.tet[8 + checktet.ver];
              if (bondflag == 3) {
                // All three faces at d in 'checktet' have been connected.
                // It can be removed from the link.            
                prevchktet.tet[8 + prevchktet.ver] = tptr;
              } else {
                // Bakup the previous tet in the link.
                prevchktet = checktet;
              }
              decode(tptr, checktet);
            } while (checktet.tet != NULL);
          } // if (checktet.tet != NULL)
        } // for (tetloop.ver = 0; ...
      } // i
    
      // Remember a tet of the mesh.
      recenttet = tetloop;
    
      // Create hull tets, create the point-to-tet map, and clean up the
      //   temporary spaces used in each tet. 
      hullsize = tetrahedrons->items;
    
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        tptr = encode(tetloop);
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          if (tetloop.tet[tetloop.ver] == NULL) {
            // Create a hull tet.
            maketetrahedron(&hulltet);
            p[0] =  org(tetloop);
            p[1] = dest(tetloop);
            p[2] = apex(tetloop);
            setvertices(hulltet, p[1], p[0], p[2], dummypoint);
            bond(tetloop, hulltet);
            // Try connecting this to others that share common hull edges.
            for (j = 0; j < 3; j++) {
              fsym(hulltet, face2);
              while (1) {
                if (face2.tet == NULL) break;
                esymself(face2);
                if (apex(face2) == dummypoint) break;
                fsymself(face2);
              }
              if (face2.tet != NULL) {
                // Found an adjacent hull tet.
                assert(face2.tet[face2.ver & 3] == NULL);
                esym(hulltet, face1);
                bond(face1, face2);
              }
              enextself(hulltet);
            }
            //hullsize++;
          }
          // Create the point-to-tet map.
          setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
          // Clean the temporary used space.
          tetloop.tet[8 + tetloop.ver] = NULL;
        }
        tetloop.tet = tetrahedrontraverse();
      }
    
      hullsize = tetrahedrons->items - hullsize;
    
      // Subfaces will be inserted into the mesh. 
      if (in->trifacelist != NULL) {
        // A .face file is given. It may contain boundary faces. Insert them.
        for (i = 0; i < in->numberoftrifaces; i++) {
          // Is it a subface?
          if (in->trifacemarkerlist != NULL) {
            marker = in->trifacemarkerlist[i];
          } else {
            // Face markers are not available. Assume all of them are subfaces.
            marker = 1;
          }
          if (marker > 0) {
            idx = i * 3;
            for (j = 0; j < 3; j++) {
              p[j] = idx2verlist[in->trifacelist[idx++]];
            }
            // Search the subface.
            bondflag = 0;
            // Make sure all vertices are in the mesh. Avoid crash.
            for (j = 0; j < 3; j++) {
              decode(point2tet(p[j]), checktet);
              if (checktet.tet == NULL) break;
            }
            if ((j == 3) && getedge(p[0], p[1], &checktet)) {
              tetloop = checktet;
              q[2] = apex(checktet);
              while (1) {
                if (apex(tetloop) == p[2]) {
                  // Found the face.
                  // Check if there exist a subface already?
                  tspivot(tetloop, neighsh); 
                  if (neighsh.sh != NULL) {
                    // Found a duplicated subface. 
                    // This happens when the mesh was generated by other mesher.
                    bondflag = 0;
                  } else {
                    bondflag = 1;
                  }
                  break;
                }
                fnextself(tetloop);
                if (apex(tetloop) == q[2]) break;
              }
            }
            if (bondflag) {
              // Create a new subface.
              makeshellface(subfaces, &subloop);
              setshvertices(subloop, p[0], p[1], p[2]);
              // Create the point-to-subface map.
              sptr = sencode(subloop);
              for (j = 0; j < 3; j++) {
                setpointtype(p[j], FACETVERTEX); // initial type.
                setpoint2sh(p[j], sptr);
              }
              if (in->trifacemarkerlist != NULL) {
                setshellmark(subloop, in->trifacemarkerlist[i]);
              }
              // Insert the subface into the mesh.
              tsbond(tetloop, subloop);
              fsymself(tetloop);
              sesymself(subloop);
              tsbond(tetloop, subloop);
            } else {
              if (!b->quiet) {
                if (neighsh.sh == NULL) {
                  printf("Warning:  Subface #%d [%d,%d,%d] is missing.\n", 
                         i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
                         pointmark(p[2]));
                } else {
                  printf("Warning: Ignore a dunplicated subface #%d [%d,%d,%d].\n", 
                         i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
                         pointmark(p[2]));
                }
              }
            } // if (bondflag)
          } // if (marker > 0)
        } // i
      } // if (in->trifacelist)
    
        // Indentify subfaces from the mesh.
        // Create subfaces for hull faces (if they're not subface yet) and
        //   interior faces which separate two different materials.
        eextras = in->numberoftetrahedronattributes;
        tetrahedrons->traversalinit();
        tetloop.tet = tetrahedrontraverse();
        while (tetloop.tet != (tetrahedron *) NULL) {
          for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
            tspivot(tetloop, neighsh);
            if (neighsh.sh == NULL) {
              bondflag = 0;
              fsym(tetloop, checktet);
              if (ishulltet(checktet)) {
                bondflag = 1;  // A hull face.
              } else {
                if (eextras > 0) {
                  if (elemattribute(tetloop.tet, eextras - 1) !=
                      elemattribute(checktet.tet, eextras - 1)) {
                    bondflag = 1; // An interior interface.
                  }
                }
              }
              if (bondflag) {
                // Create a new subface.
                makeshellface(subfaces, &subloop);
                p[0] = org(tetloop);
                p[1] = dest(tetloop);
                p[2] = apex(tetloop);
                setshvertices(subloop, p[0], p[1], p[2]);
                // Create the point-to-subface map.
                sptr = sencode(subloop);
                for (j = 0; j < 3; j++) {
                  setpointtype(p[j], FACETVERTEX); // initial type.
                  setpoint2sh(p[j], sptr);
                }
                setshellmark(subloop, 0); // Default marker.
                // Insert the subface into the mesh.
                tsbond(tetloop, subloop);
                sesymself(subloop);
                tsbond(checktet, subloop);
              } // if (bondflag)
            } // if (neighsh.sh == NULL)
          }
          tetloop.tet = tetrahedrontraverse();
        }
    
      // Connect subfaces together. 
      subfaces->traversalinit();
      subloop.shver = 0;
      subloop.sh = shellfacetraverse(subfaces);
      while (subloop.sh != (shellface *) NULL) {
        for (i = 0; i < 3; i++) {
          spivot(subloop, neighsh);
          if (neighsh.sh == NULL) {
            // Form a subface ring by linking all subfaces at this edge.
            // Traversing all faces of the tets at this edge.
            stpivot(subloop, tetloop);
            q[2] = apex(tetloop);
            neighsh = subloop;
            while (1) {
              fnextself(tetloop);
              tspivot(tetloop, nextsh);
              if (nextsh.sh != NULL) {
                // Link neighsh <= nextsh.
                sbond1(neighsh, nextsh);
                neighsh = nextsh;
              }
              if (apex(tetloop) == q[2]) {
                assert(nextsh.sh == subloop.sh); // It's a ring.
                break;
              }
            } // while (1)
          } // if (neighsh.sh == NULL)
          senextself(subloop);
        }
        subloop.sh = shellfacetraverse(subfaces);
      }
    
      //if (b->verbose) {
      //  printf("  Created %ld subfaces.\n", subfaces->items);
      //}
    
      // Segments will be introudced. 
      if (in->edgelist != NULL) {
        // A .edge file is given. It may contain boundary edges. Insert them.
        for (i = 0; i < in->numberofedges; i++) {
          // Is it a segment?
          if (in->edgemarkerlist != NULL) {
            marker = in->edgemarkerlist[i];
          } else {
            // Edge markers are not available. Assume all of them are segments.
            marker = 1;
          }
          if (marker != 0) { 
            // Insert a segment.
            idx = i * 2;
            for (j = 0; j < 2; j++) {
              p[j] = idx2verlist[in->edgelist[idx++]];
            }
            // Make sure all vertices are in the mesh. Avoid crash.
            for (j = 0; j < 2; j++) {
              decode(point2tet(p[j]), checktet);
              if (checktet.tet == NULL) break;
            }
            // Search the segment.
            if ((j == 2) && getedge(p[0], p[1], &checktet)) {
              // Create a new subface.
              makeshellface(subsegs, &segloop);
              setshvertices(segloop, p[0], p[1], NULL);
              // Create the point-to-segment map.
              sptr = sencode(segloop);
              for (j = 0; j < 2; j++) {
                setpointtype(p[j], RIDGEVERTEX); // initial type.
                setpoint2sh(p[j], sptr);
              }
              if (in->edgemarkerlist != NULL) {
                setshellmark(segloop, marker);
              }
              // Insert the segment into the mesh.
              tetloop = checktet;
              q[2] = apex(checktet);
              subloop.sh = NULL;
              while (1) {
                tssbond1(tetloop, segloop);
                tspivot(tetloop, subloop);
                if (subloop.sh != NULL) {
                  ssbond1(subloop, segloop);
                  sbond1(segloop, subloop);
                }
                fnextself(tetloop);
                if (apex(tetloop) == q[2]) break;
              } // while (1)
              // Remember an adjacent tet for this segment.
              sstbond1(segloop, tetloop);
            } else {
              if (!b->quiet) {
                printf("Warning:  Segment #%d [%d,%d] is missing.\n", 
                       i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
              }
            }
          } // if (marker != 0)
        } // i
      } // if (in->edgelist)
    
        // Identify segments from the mesh. 
        // Create segments for non-manifold edges (which are shared by more 
        //   than two subfaces), and for non-coplanar edges, i.e., two subfaces
        //   form an dihedral angle > 'b->facet_ang_tol' (degree).
        angtol = b->facet_ang_tol / 180.0 * PI;
        subfaces->traversalinit();
        subloop.shver = 0;
        subloop.sh = shellfacetraverse(subfaces);
        while (subloop.sh != (shellface *) NULL) {
          for (i = 0; i < 3; i++) {
            sspivot(subloop, segloop);
            if (segloop.sh == NULL) {
              // Check if this edge is a segment.
              bondflag = 0;
              // Counter the number of subfaces at this edge.
              idx = 0;
              nextsh = subloop;
              while (1) {
                idx++;
                spivotself(nextsh);
                if (nextsh.sh == subloop.sh) break;
              }
              if (idx != 2) {
                // It's a non-manifold edge. Insert a segment.
                p[0] = sorg(subloop);
                p[1] = sdest(subloop);
                bondflag = 1;
              } else {
                // Check the dihedral angle formed by the two subfaces.
                spivot(subloop, neighsh);
                p[0] = sorg(subloop);
                p[1] = sdest(subloop);
                p[2] = sapex(subloop);
                p[3] = sapex(neighsh);
                ang = facedihedral(p[0], p[1], p[2], p[3]);
                if (ang > PI) ang = 2 * PI - ang;
                if (ang < angtol) {
                  bondflag = 1;
                }
              }
              if (bondflag) {
                // Create a new subface.
                makeshellface(subsegs, &segloop);
                setshvertices(segloop, p[0], p[1], NULL);
                // Create the point-to-segment map.
                sptr = sencode(segloop);
                for (j = 0; j < 2; j++) {
                  setpointtype(p[j], RIDGEVERTEX); // initial type.
                  setpoint2sh(p[j], sptr);
                }
                setshellmark(segloop, marker);
                // Insert the subface into the mesh.
                stpivot(subloop, tetloop);
                q[2] = apex(tetloop);
                while (1) {
                  tssbond1(tetloop, segloop);
                  tspivot(tetloop, neighsh);
                  if (neighsh.sh != NULL) {
                    ssbond1(neighsh, segloop);
                  }
                  fnextself(tetloop);
                  if (apex(tetloop) == q[2]) break;
                } // while (1)
                // Remember an adjacent tet for this segment.
                sstbond1(segloop, tetloop);
                sbond1(segloop, subloop);
              } // if (bondflag)
            } // if (neighsh.sh == NULL)
            senextself(subloop);
          }
          subloop.sh = shellfacetraverse(subfaces);
        }
    
      // Remember the number of input segments.
      insegments = subsegs->items;
    
      //if (b->verbose) {
      //  printf("  Created %ld segments.\n", subsegs->items);
      //}
    
      // Set global flags.
      checksubsegflag = 1;
      checksubfaceflag = 1;
      //nonconvex = 1; 
    
      delete [] idx2verlist;
      delete [] ver2tetarray;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // scoutpoint()    Search a point in mesh.                                   //
    //                                                                           //
    // This function searches the point in a mesh whose domain may be not convex.//
    // In case of a convex domain, the locate() function is sufficient.          //
    //                                                                           //
    // If 'randflag' is used, randomly select a start searching tet.  Otherwise, //
    // start searching directly from 'searchtet'.                                //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
    {
      point pa, pb, pc, pd;
      enum locateresult loc = OUTSIDE;
      REAL vol, ori1, ori2, ori3, ori4;
      int iter;
    
      if (searchtet->tet == NULL) {
        *searchtet = recenttet;
      }
    
      iter = 0;
      while (1) {
        // Randonmly select a good starting tet.
        if (randflag) {
          randomsample(searchpt, searchtet);
        }
        loc = locate(searchpt, searchtet, 0, 1);
        if (loc == OUTSIDE) {
          // Not found. This happens when the mesh is not convex.
          if (!randflag) break;
          iter++;
          if (iter > 3) {
            searchtet->tet = NULL;
            break;
          }
        } else {
          // Found the point.
          break;
        }
      } // while (1)
    
      if (loc != OUTSIDE) {
        // Round the result of location.
        pa = org(*searchtet);
        pb = dest(*searchtet);
        pc = apex(*searchtet);
        pd = oppo(*searchtet);
        vol = orient3d(pa, pb, pc, pd);
        ori1 = orient3d(pa, pb, pc, searchpt);
        ori2 = orient3d(pb, pa, pd, searchpt);
        ori3 = orient3d(pc, pb, pd, searchpt);
        ori4 = orient3d(pa, pc, pd, searchpt);
        if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
        if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
        if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
        if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
      } else { // if (loc == OUTSIDE) {
        // Do a brute force search for the point (with rounding).
        tetrahedrons->traversalinit();
        searchtet->tet = tetrahedrontraverse();
        while (searchtet->tet != NULL) {
          pa = org(*searchtet);
          pb = dest(*searchtet);
          pc = apex(*searchtet);
          pd = oppo(*searchtet);
    
          vol = orient3d(pa, pb, pc, pd); 
          assert(vol < 0); // vol != 0
    
          ori1 = orient3d(pa, pb, pc, searchpt);
          if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
          if (ori1 <= 0) {
            ori2 = orient3d(pb, pa, pd, searchpt);
            if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
            if (ori2 <= 0) {
              ori3 = orient3d(pc, pb, pd, searchpt);
              if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
              if (ori3 <= 0) {
                ori4 = orient3d(pa, pc, pd, searchpt);
                if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
                if (ori4 <= 0) {
                  // Found the tet. Return its location. 
                  break;
                } // ori4
              } // ori3
            } // ori2
          } // ori1
    
          searchtet->tet = bgm->tetrahedrontraverse();
        } // while (searchtet->tet != NULL)
      }
    
      if (searchtet->tet != NULL) {
        // Return the point location.
        if (ori1 == 0) { // on face [a,b,c]
          if (ori2 == 0) { // on edge [a,b].
            if (ori3 == 0) { // on vertex [b].
              assert(ori4 != 0);
              enextself(*searchtet); // [b,c,a,d]
              loc = ONVERTEX;
            } else {
              if (ori4 == 0) { // on vertex [a]
                loc =  ONVERTEX; // [a,b,c,d]
              } else {    
                loc =  ONEDGE; // [a,b,c,d]
              }
            }
          } else { // ori2 != 0
            if (ori3 == 0) { // on edge [b,c]
              if (ori4 == 0) { // on vertex [c]
                eprevself(*searchtet); // [c,a,b,d]
                loc =  ONVERTEX;
              } else {
                enextself(*searchtet); // [b,c,a,d]
                loc =  ONEDGE;
              }
            } else { // ori3 != 0
              if (ori4 == 0) { // on edge [c,a]
                eprevself(*searchtet); // [c,a,b,d]
                loc =  ONEDGE;
              } else {
                loc =  ONFACE;
              }
            }
          }
        } else { // ori1 != 0
          if (ori2 == 0) { // on face [b,a,d]
            esymself(*searchtet); // [b,a,d,c]
            if (ori3 == 0) { // on edge [b,d]
              eprevself(*searchtet); // [d,b,a,c]
              if (ori4 == 0) { // on vertex [d]                      
                loc =  ONVERTEX;
              } else {
                loc =  ONEDGE;
              }
            } else { // ori3 != 0
              if (ori4 == 0) { // on edge [a,d]
                enextself(*searchtet); // [a,d,b,c]
                loc =  ONEDGE;
              } else {
                loc =  ONFACE;
              }
            }
          } else { // ori2 != 0
            if (ori3 == 0) { // on face [c,b,d]
              enextself(*searchtet);
              esymself(*searchtet);
              if (ori4 == 0) { // on edge [c,d]
                eprevself(*searchtet);
                loc =  ONEDGE;
              } else {
                loc =  ONFACE;
              }
            } else {
              if (ori4 == 0) { // on face [a,c,d]
                eprevself(*searchtet);
                esymself(*searchtet);
                loc =  ONFACE;
              } else { // inside tet [a,b,c,d]
                loc =  INTETRAHEDRON;
              } // ori4
            } // ori3
          } // ori2
        } // ori1
      } else {
        loc = OUTSIDE;
      }
    
      return (int) loc;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // getpointmeshsize()    Interpolate the mesh size at given point.           //
    //                                                                           //
    // 'iloc' indicates the location of the point w.r.t. 'searchtet'.  The size  //
    // is obtained by linear interpolation on the vertices of the tet.           //
    //                                                                           //
    // If 'posflag' is set, only do interpolation when all vertices have a posi- //
    // tive value.                                                               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc,
                                      int posflag)
    {
      point *pts, pa, pb, pc;
      REAL volume, vol[4], wei[4];
      REAL size;
      int i;
    
      size = 0;
    
      if (iloc == (int) INTETRAHEDRON) {
        pts = (point *) &(searchtet->tet[4]);
        assert(pts[3] != dummypoint);
        if (!posflag || 
            ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
             (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0))) {
          // P1 interpolation.
          volume = orient3d(pts[0], pts[1], pts[2], pts[3]);
          vol[0] = orient3d(searchpt, pts[1], pts[2], pts[3]);
          vol[1] = orient3d(pts[0], searchpt, pts[2], pts[3]);
          vol[2] = orient3d(pts[0], pts[1], searchpt, pts[3]);
          vol[3] = orient3d(pts[0], pts[1], pts[2], searchpt);
          for (i = 0; i < 4; i++) {
            wei[i] = fabs(vol[i] / volume);
            size += (wei[i] * pts[i][pointmtrindex]);
          }
        }
      } else if (iloc == (int) ONFACE) {
        pa = org(*searchtet);
        pb = dest(*searchtet);
        pc = apex(*searchtet);
        if (!posflag ||
            ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
             (pc[pointmtrindex] > 0))) {
          volume = triarea(pa, pb, pc);
          vol[0] = triarea(searchpt, pb, pc);
          vol[1] = triarea(pa, searchpt, pc);
          vol[2] = triarea(pa, pb, searchpt);
          size = (vol[0] / volume) * pa[pointmtrindex]
               + (vol[1] / volume) * pb[pointmtrindex]
               + (vol[2] / volume) * pc[pointmtrindex];
        }
      } else if (iloc == (int) ONEDGE) {
        pa = org(*searchtet);
        pb = dest(*searchtet);
        if (!posflag || ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0))) {
          volume = distance(pa, pb);
          vol[0] = distance(searchpt, pb);
          vol[1] = distance(pa, searchpt);
          size = (vol[0] / volume) * pa[pointmtrindex]
               + (vol[1] / volume) * pb[pointmtrindex];
        }
      } else if (iloc == (int) ONVERTEX) {
        pa = org(*searchtet);
        if (!posflag || (pa[pointmtrindex] > 0)) {
          size = pa[pointmtrindex];
        }
      }
    
      return size;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // interpolatemeshsize()    Interpolate the mesh size from a background mesh //
    //                          (source) to the current mesh (destination).      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::interpolatemeshsize()
    {
      triface searchtet;
      point ploop;
      REAL minval = 0.0, maxval = 0.0;
      int iloc;
      int count;
    
      if (!b->quiet) {
        printf("Interpolating mesh size ...\n");
      }
      count = 0; // Count the number of interpolated points.
    
      // Interpolate sizes for all points in the current mesh.
      points->traversalinit();
      ploop = pointtraverse();
      while (ploop != NULL) {
        // Search a tet in bgm which containing this point.
        searchtet.tet = NULL;
        iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
        if (iloc != (int) OUTSIDE) {
          // Interpolate the mesh size (posflag = 0)
          ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc, 0);
          setpoint2bgmtet(ploop, bgm->encode(searchtet));
          if (count == 0) {
            // This is the first interpolated point.
            minval = maxval = ploop[pointmtrindex];
          } else {
            if (ploop[pointmtrindex] < minval) {
              minval = ploop[pointmtrindex];
            }
            if (ploop[pointmtrindex] > maxval) {
              maxval = ploop[pointmtrindex];
            }
          }
          count++;
        } else {
          if (!b->quiet) {
            printf("Warnning:  Failed to locate point %d in source mesh.\n",
                   pointmark(ploop));
          }
        }
        ploop = pointtraverse();
      }
    
      if (b->verbose) {
        printf("  Interoplated %d points.\n", count);
        printf("  Size rangle [%.17g, %.17g].\n", minval, maxval);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // insertconstrainedpoints()    Insert a list of points into the mesh.       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
    {
      triface searchtet, spintet;
      face checksh, *splitsh;
      face checkseg, *splitseg;
      point newpt;
      insertvertexflags ivf;
      REAL *attr, x, y, z, w;
      int randflag;
      int count, index;
      int loc;
      int i, j;
    
      if (!b->quiet) {
        printf("Inserting constrained points ...\n");
      }
    
      randflag = 1; // Randomly select start tet for point location. 
      count = 0;
      index = 0;
    
      for (i = 0; i < addio->numberofpoints; i++) {
        makepoint(&newpt, VOLVERTEX);
        x = newpt[0] = addio->pointlist[index++];
        y = newpt[1] = addio->pointlist[index++];
        z = newpt[2] = addio->pointlist[index++];
        if (b->weighted) { // -w option
          if (addio->numberofpointattributes > 0) {
            // The first point attribute is weight.
            w = addio->pointattributelist[addio->numberofpointattributes * i];
          } else {
            // No given weight available.
            w = 0;
          }
          if (b->weighted_param == 0) {
            newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
          } else { // -w1 option
            newpt[3] = w;  // Regular tetrahedralization.
          }
        } else {
          newpt[3] = 0;
        }
        // Read the add point attributes if current points have attributes.
        if ((addio->numberofpointattributes > 0) &&
            (in->numberofpointattributes > 0)) {
          attr = addio->pointattributelist + addio->numberofpointattributes * i;
          for (j = 0; j < in->numberofpointattributes; j++) {
            if (j < addio->numberofpointattributes) {
              newpt[4 + j] = attr[j];
            }
          }
        }
        // Read the point metric tensor.
        //for (j = 0; j < in->numberofpointmtrs; j++) {
        //  pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
        //}
    
        // Find the location of the inserted point.
        searchtet.tet = NULL;
        ivf.iloc = scoutpoint(newpt, &searchtet, randflag);
        if (ivf.iloc != (int) OUTSIDE) {
          // Found the point. 
          // Initialize the insertion parameters. 
          if (b->psc) {
            ivf.bowywat = 0;   // Do not enlarge the initial cavity.
            ivf.validflag = 0; // Do not validate the initial cavity.
          } else {
            ivf.bowywat = 3;   // Use the "Bowyer-Watson" algorithm to form cavity.
            ivf.validflag = 1; // Validate the B-W cavity.
          }
          ivf.lawson = 3;
          ivf.rejflag = 0;
          ivf.chkencflag = 0;
          ivf.sloc = ivf.iloc;
          ivf.sbowywat = ivf.bowywat;  // Surface mesh options.
          ivf.splitbdflag = 1;
          ivf.respectbdflag = 1;
          ivf.assignmeshsize = 1;
    
          splitsh = NULL;
          splitseg = NULL;
    
          // Set the right point type.
          if (ivf.iloc == (int) ONEDGE) {
            tsspivot1(searchtet, checkseg);
            if (checkseg.sh != NULL) {
              setpointtype(newpt, RIDGEVERTEX);
              spivot(checkseg, checksh);
              splitsh = &checksh;
              splitseg = &checkseg;        
            } else {
              // Check if it is a subface edge.
              spintet = searchtet;
              while (1) {
                tspivot(spintet, checksh);
                if (checksh.sh != NULL) {
                  setpointtype(newpt, FACETVERTEX);
                  splitsh = &checksh;
                  break;
                }
                fnextself(spintet);
                if (spintet.tet == searchtet.tet) break;
              }
            }
          } else if (ivf.iloc == (int) ONFACE) {
            tspivot(searchtet, checksh);
            if (checksh.sh != NULL) {
              setpointtype(newpt, FACETVERTEX);
              splitsh = &checksh;
            }
          }
    
          // Insert the vertex.
          loc = insertvertex(newpt, &searchtet, splitsh, splitseg, &ivf);
    
          if (loc == ivf.iloc) {
            // The point has been inserted.
            lawsonflip3d(newpt, 4, 0, ivf.chkencflag, 0);
            count++;
          } else {
            if (!b->quiet) {
              printf("Warning:  Failed to insert point #%d. Ignored.\n", i);
            }
            pointdealloc(newpt);
          }
        } else {
          if (!b->quiet) {
            printf("Warning:  Can't locate add point #%d. Ignored.\n", i);
          }
          pointdealloc(newpt);
        }
      } // i
    
      if (b->verbose) {
        printf("  Inserted %d of %d vertices.\n", count, addio->numberofpoints);
      }
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// reconstruct_cxx //////////////////////////////////////////////////////////
    
    //// refine_cxx ///////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // marksharpsegments()    Mark sharp segments.                               //
    //                                                                           //
    // All segments are initialized as type NSHARP.                              //
    //                                                                           //
    // A segment is SHARP if there are two facets intersecting at it with an     //
    // internal dihedral angle (*) less than an angle \theta.                    //
    //                                                                           //
    // A theoretical value of \theta is arccos(1/3) \approx 70.54 degree.  It is //
    // possible to relax it in practice. Here we choose \theta = 65 degree.      //
    //                                                                           //
    // The minimum dihedral angle between facets (minfacetdihed) is calulcated.  //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::marksharpsegments()
    {
      triface adjtet;
      face startsh, spinsh, neighsh;
      face segloop, nextseg, prevseg;
      point eorg, edest;
      REAL ang, smallang;
      bool issharp;
      int sharpcount;
    
      // For storing extremely small dihedral angle.
      face *parysh, *parysh1;
      REAL exsmallang;
      int exsharpcount;
      int i, j, k;
    
      if (b->verbose > 0) {
        printf("  Marking sharp segments.\n");
      }
    
      minfacetdihed = PI;
      smallang = 65.0 * PI / 180.0; // 65 degree.
      exsmallang = 15.0 * PI / 180.0; // 15 degree.
      sharpcount = exsharpcount = 0;
    
      // A segment s may have been split into many subsegments. Operate the one
      //   which contains the origin of s. Then mark the rest of subsegments.
      subsegs->traversalinit();
      segloop.sh = shellfacetraverse(subsegs);
      while (segloop.sh != (shellface *) NULL) {
        segloop.shver = 0;
        senext2(segloop, prevseg);
        spivotself(prevseg);
        if (prevseg.sh == NULL) {
          // Operate on this seg s.
          issharp = false;
          spivot(segloop, startsh);
          if (startsh.sh != NULL) {
            // First check if two facets form an acute dihedral angle at s.
            eorg = sorg(segloop);
            edest = sdest(segloop);
            spinsh = startsh;
            while (1) {
              if (sorg(spinsh) != eorg) sesymself(spinsh);
              // Only do test when the spinsh is faceing inward.
              stpivot(spinsh, adjtet);
              if (adjtet.tet != NULL) {
                if (!ishulltet(adjtet)) {
                  // Get the subface on the adjacent facet.
                  spivot(spinsh, neighsh);
                  // Do not calculate if it is self-bonded.
                  if ((neighsh.sh != NULL) && (neighsh.sh != spinsh.sh)) {
                    // Calculate the dihedral angle between the two subfaces.
                    ang = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh));
                    // Only do check if a sharp angle has not been found.
                    if (!issharp) issharp = (ang < smallang);
                    // Remember the smallest facet dihedral angle.
                    minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang;
                    if (ang < exsmallang) {
                      // It's an extremely small dihedral angle.
                      // Mark the two facets. 
                      // To avoid too many Steiner points, do not refine them.
                      if (shelltype(spinsh) != SHARP) {
                        setshelltype(spinsh, SHARP);
                        cavesegshlist->newindex((void **) &parysh);
                        *parysh = spinsh;
                      }
                      if (shelltype(neighsh) != SHARP) {                 
                        setshelltype(neighsh, SHARP);
                        cavesegshlist->newindex((void **) &parysh);
                        *parysh = neighsh;
                      }
                      exsharpcount++;
                    }
                  }
                }
              }
              // Go to the next facet.
              spivotself(spinsh);
              if (spinsh.sh == NULL) break; // A single subface case.
              if (spinsh.sh == startsh.sh) break;
            }
          } // if (startsh.sh != NULL)
          if (issharp) {
            if (b->verbose > 2) {
              printf("      Mark a sharp segment (%d, %d).\n",
                     pointmark(eorg), pointmark(edest));
            }
            setshelltype(segloop, SHARP);
            // The endpoint of this segment is acute.
            if (pointtype(eorg) == RIDGEVERTEX) {
              setpointtype(eorg, ACUTEVERTEX);
            } else {
              assert(pointtype(eorg) == ACUTEVERTEX); // SELF_CHECK
            }
            // Set the type for all subsegments at forwards.
            edest = sdest(segloop);
            senext(segloop, nextseg);
            spivotself(nextseg);
            while (nextseg.sh != NULL) {
              setshelltype(nextseg, SHARP);
              // Adjust the direction of nextseg.
              nextseg.shver = 0;
              if (sorg(nextseg) != edest) {
                sesymself(nextseg);
              }
              assert(sorg(nextseg) == edest);
              edest = sdest(nextseg);
              // Go the next connected subsegment at edest.
              senextself(nextseg);
              spivotself(nextseg);
            }
            // The endpoint of this segment is acute.
            if (pointtype(edest) == RIDGEVERTEX) {
              setpointtype(edest, ACUTEVERTEX);
            } else {
              assert(pointtype(edest) == ACUTEVERTEX); // SELF_CHECK
            }
            sharpcount++;
          } // if (issharp)
        } // if (prevseg.sh == NULL)
        segloop.sh = shellfacetraverse(subsegs);
      }
    
      // Mark all facets at extremely small dihedral angles.
      if (cavesegshlist->objects > 0) {
        for (i = 0; i < cavesegshlist->objects; i++) {
          parysh = (face *) fastlookup(cavesegshlist, i);
          caveshlist->newindex((void **) &parysh1);
          *parysh1 = *parysh;
          for (j = 0; j < caveshlist->objects; j++) {
            parysh1 = (face *) fastlookup(caveshlist, j);
            spinsh = *parysh1;
            for (k = 0; k < 3; k++) {
              sspivot(spinsh, nextseg);
              if (nextseg.sh == NULL) {
                spivot(spinsh, neighsh);
                if (shelltype(neighsh) != SHARP) {                 
                  setshelltype(neighsh, SHARP);
                  caveshlist->newindex((void **) &parysh1);
                  *parysh1 = neighsh;
                }
              }
              senextself(spinsh);
            } // k
          } // j
          caveshlist->restart();
        } // i
        cavesegshlist->restart();
      } // if (cavesegshlist->objects > 0)
    
      if (b->verbose) {
        if (sharpcount > 0) {
          printf("  Found %d (%d) sharp segments.\n", sharpcount, exsharpcount);
        }
        printf("  Minimum fac-fac angle = %g.\n", minfacetdihed / PI * 180.0);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // decidefeaturepointsizes()    Calculate sizes for all feature points.      //
    //                                                                           //
    // A feature point is either an acute vertex or a Steiner point on a sharp   //
    // segment.  Each feature point p will be protected by a ball whose radius   //
    // is called its "feature size".                                             //
    //                                                                           //
    // NOTE: we should have already marked all features points in the two func-  //
    // tions: markacutevertices() and marksharpsegments().  Each feature point   //
    // has the type ACUTEVERTEX or FREESEGVERTEX.                                //
    //                                                                           //
    // The feature size of a vertex is the minimum of the following sizes:       //
    //   (0) the (approximated) local feature size (the distance to the second   //
    //       nearest boundary) of the vertex;
    //   (1) the value specified in .mtr file (-m option);                       //
    //   (2) the cubic root of a fixed maximal volume constraint ('-a__');       //
    //   (3) the cubic root of a maximal volume constraint in a region ('-a');   //
    //   (4) the square root of a maximal area constraint in a .var file;        //
    //   (5) a maximal length constraint in a .var file;                         //
    //                                                                           //
    // If 'b->nobisect' ('-Y' option) is set, every input vertex has a feature   //
    // size.                                                                     //
    //                                                                           //
    // The feature size of a Steiner point is linearly interpolated from its adj-//
    // acent vertices which belong to the "carrier" (the boundary of the lowrest //
    // dimension) of this Steiner point.  For example, a Steiner point on a seg- //
    // ment gets its size from the two endpoints of the segment.                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::decidefeaturepointsizes()
    {
      arraypool *tetlist, *verlist;
      triface starttet, *parytet;
      face checksh, parentsh, shloop;
      face checkseg, prevseg, nextseg, testseg;
      point ploop, adjpt, e1, e2, *parypt;
      REAL lfs_0, lfs_1, lfs_2;
      REAL len, vol, maxlen = 0.0, varlen;
      REAL ang, a, a1, a2, a3, prjpt[3], n[3];
      int featureflag, featurecount;
      int i, j;
    
      if (b->verbose > 0) {
        printf("  Deciding feature-point sizes.\n");
      }
    
      // Initialize working lists.
      tetlist = cavetetlist;
      verlist = cavetetvertlist;
    
      if (b->fixedvolume) {
        // A fixed volume constraint is imposed. This gives an upper bound of
        //   the maximal radius of the protect ball of a vertex.
        maxlen = pow(6.0 * b->maxvolume, 1.0 / 3.0);
      }
    
      // First only assign a size of p if p is not a Steiner point. The size of
      //   a Steiner point will be interpolated later from the endpoints of the
      //   segment on which it lies. 
      featurecount = 0;
      points->traversalinit();
      ploop = pointtraverse();
      while (ploop != (point) NULL) {
        // Check if it is a feature point.
        featureflag = 0;
        // Only calculate the size if it has a size zero.
        // The point may already has a positive size (-m option).
        if (ploop[pointmtrindex] == 0) {
          if (pointtype(ploop) == ACUTEVERTEX) {
            featureflag = 1;
          } else {
            if (b->nobisect) { // '-Y' option
              if ((pointtype(ploop) == RIDGEVERTEX) ||
                  (pointtype(ploop) == FACETVERTEX) ||
                  (pointtype(ploop) == VOLVERTEX)) {
                featureflag = 1;  // It is an input vertex.
              }
            }
          }
        }
        if (featureflag) {
          // Form star(p).
          getvertexstar(1, ploop, tetlist, verlist, NULL);
          // Calculate lfs_0(p), i.e., the smallest distance from p to a vertex.
          // We approximate it by taking the distance of p to its nearest
          //   vertex in Link(p).
          lfs_0 = longest;
          for (i = 0; i < verlist->objects; i++) {
            parypt = (point *) fastlookup(verlist, i);
            adjpt = * parypt;
            if (adjpt == dummypoint) {
              continue; // Skip a dummypoint.
            }
            if (pointtype(adjpt) == FREESEGVERTEX) {
              // A Steiner point. Get the subsegment.
              sdecode(point2sh(adjpt), checkseg);
              assert(checkseg.sh != NULL);
              checkseg.shver = 0;
              if (sdest(checkseg) != adjpt) {
                sesymself(checkseg);
              }
              assert(sdest(checkseg) == adjpt);
              // It is possible that the original segment of 'adjpt' does not
              //   have 'ploop' as an endpoint.
              if (sorg(checkseg) == ploop) {
                // Find the other end point of the original segment.
                nextseg = checkseg;
                while (1) {
                  senext(nextseg, testseg);
                  spivotself(testseg);
                  if (testseg.sh == NULL) break;
                  // Go to the next subseg.
                  nextseg = testseg;
                  // Adjust the direction of the nextseg.
                  nextseg.shver = 0;
                  if (sorg(nextseg) != adjpt) {
                    sesymself(nextseg);
                  }
                  assert(sorg(nextseg) == adjpt);
                  adjpt = sdest(nextseg);
                }
              }
    	} else if (pointtype(adjpt) == FREEFACETVERTEX) {
              // Ignore a Steiner point on facet.
              continue;
            } else if (pointtype(adjpt) == FREEVOLVERTEX) {
              // Ignore a Steiner point in volume.
              continue;
            }  
            len = distance(ploop, adjpt);
            if (lfs_0 > len) lfs_0 = len;
          } // i
          assert(lfs_0 < longest); // SELF_CHECK
          ploop[pointmtrindex] = lfs_0;
          // Calculate lfs_1(p), i.e., the smallest distance from p to a segment.
          //   We approximate it by restricting the segments in Link(p).
          lfs_1 = lfs_0;
          for (i = 0; i < tetlist->objects; i++) {
            parytet = (triface *) fastlookup(tetlist, i);
            for (j = 0; j < 3; j++) {
              tsspivot1(*parytet, checkseg);
              if (checkseg.sh != NULL) {
                e1 = sorg(checkseg);
                e2 = sdest(checkseg);
                // Only do calculation if the projeciton of 'p' lies inside the
                //   segment [e1, e2].
                ang = interiorangle(ploop, e1, e2, NULL);
                ang *= 2.0;
                if (ang > PI) { 
                  len = shortdistance(ploop, e1, e2);
                  if (lfs_1 > len) {
                    lfs_1 = len;
                  }
                }
              }
              enextself(*parytet);
            } // j
          } // i
          if (ploop[pointmtrindex] > lfs_1) {
            ploop[pointmtrindex] = lfs_1;
          }
          // Calculate lfs_2(p), i.e., the smallest distance from p to a facet.
          //   We approximate it by restricting the facets in Link(p).
          lfs_2 = lfs_0; 
          for (i = 0; i < tetlist->objects; i++) {
            parytet = (triface *) fastlookup(tetlist, i);
            tspivot(*parytet, checksh);
            if (checksh.sh != NULL) {
              adjpt = sorg(checksh);
              e1 = sdest(checksh);
              e2 = sapex(checksh);
              // Only do calculation if the projeciton of 'p' lies inside the
              //   subface [adjpt, e1, e2].
              projpt2face(ploop, adjpt, e1, e2, prjpt);
              facenormal(adjpt, e1, e2, n, 1, NULL);
              a = sqrt(dot(n, n)); // area of [adjpt, e1, e2].
              if (a > 0) {
                facenormal(adjpt, e1, prjpt, n, 1, NULL);
                a1 = sqrt(dot(n, n));
                facenormal(e1, e2, prjpt, n, 1, NULL);
                a2 = sqrt(dot(n, n));
                facenormal(e2, adjpt, prjpt, n, 1, NULL);
                a3 = sqrt(dot(n, n));
                if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
                  len = distance(ploop, prjpt);
                  if (lfs_2 > len) {
                    lfs_2 = len;
                  }
                }
              } else {
                assert(0); // a degenerate triangle.
              } // if (a > 0)
            }
          }
          if (ploop[pointmtrindex] > lfs_2) {
            ploop[pointmtrindex] = lfs_2;
          }
          if (b->fixedvolume) {
            // A fixed volume constraint is imposed. Adjust H(p) <= maxlen.
            if (ploop[pointmtrindex] > maxlen) {
              ploop[pointmtrindex] = maxlen;
            }
          }
          if (b->varvolume) {
            // Variant volume constraints are imposed. Adjust H(p) <= varlen.
            for (i = 0; i < tetlist->objects; i++) {
              parytet = (triface *) fastlookup(tetlist, i);
              starttet = *parytet;
              vol = volumebound(starttet.tet);
              if (vol > 0.0) {
                varlen = pow(6 * vol, 1.0 / 3.0);
                if (ploop[pointmtrindex] > varlen) {
                  ploop[pointmtrindex] = varlen;
                }
              }
            }
          }
          // The size is calculated.
          assert(ploop[pointmtrindex] > 0); // SELF_CHECK
          // Clear working lists.
          tetlist->restart();
          verlist->restart();
          featurecount++;
        } // if (featureflag)
        ploop = pointtraverse();
      }
    
      if (b->verbose) {
        printf("  %d feature points.\n", featurecount);
      }
    
      // Second only assign sizes for all Steiner points. A Steiner point p
      //   inserted on a sharp segment s is assigned a size by interpolating
      //   the sizes of the original endpoints of s.
      featurecount = 0;
      points->traversalinit();
      ploop = pointtraverse();
      while (ploop != (point) NULL) {
        if (ploop[pointmtrindex] == 0.0) {
          if (pointtype(ploop) == FREESEGVERTEX) {
            // A Steiner point on segment.
            featureflag = 0;
            sdecode(point2sh(ploop), checkseg);
            assert(checkseg.sh != NULL);
            checkseg.shver = 0;
            e1 = farsorg(checkseg);  // The origin of this seg.        
            e2 = farsdest(checkseg); // The dest of this seg.      
            if (b->nobisect) { // '-Y' option.
              assert(e1[pointmtrindex] > 0); // SELF_CHECK
              assert(e2[pointmtrindex] > 0); // SELF_CHECK
              featureflag = 1;
            } else {
              if ((e1[pointmtrindex] > 0) && (e2[pointmtrindex] > 0)) {
                featureflag = 1;
              }
            }
            if (featureflag) {
              len = distance(e1, e2);
              lfs_0 = distance(e1, ploop); // Re-use lfs_0.
              ploop[pointmtrindex] = e1[pointmtrindex]
                + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]);
              featurecount++;
            } // if (featureflag)
          } else if (pointtype(ploop) == FREEFACETVERTEX) {
            if (b->nobisect) { // -Y option.
              // Collect vertices in the Star(p) which are also in the facet
              //   containing p.
              point2shorg(ploop, parentsh);
              checksh = parentsh;
              while (1) {
                assert(sorg(checksh) == ploop);
                adjpt = sdest(checksh);
                // Collect this vertex.
                verlist->newindex((void **) &parypt);
                *parypt = adjpt;
                // Go to the next subface at p. (counterclockwise) 
                senext2self(checksh);
                spivotself(checksh);
                assert(checksh.sh != NULL);
                if (checksh.sh == parentsh.sh) break;
                if (sorg(checksh) != ploop) sesymself(checksh);          
              }
              assert(verlist->objects > 0);
              // Using Shepard interpolation (p=1) to interpolate the size for 'p'.
              //   Re-use len, lfs_0, lfs_1, lfs_2;
              lfs_1 = lfs_2 = 0;
              for (i = 0; i < verlist->objects; i++) {
                parypt = (point *) fastlookup(verlist, i);
                adjpt = *parypt;
                if (adjpt[pointmtrindex] > 0) {
                  len = distance(adjpt, ploop);
                  lfs_0 = 1.0 / len;
                  lfs_1 += lfs_0 * adjpt[pointmtrindex];
                  lfs_2 += lfs_0;
                }
              }
              assert(lfs_2 > 0);
              ploop[pointmtrindex] = lfs_1 / lfs_2;
              verlist->restart();
              featurecount++;
            } // if (b->nobisect)
          } else if (pointtype(ploop) == FREEVOLVERTEX) {
            if (b->nobisect) { // -Y option.
              getvertexstar(1, ploop, tetlist, verlist, NULL);
              // Using Shepard interpolation to interpolate the size for 'p'.
              //   Re-use len, lfs_0, lfs_1, lfs_2;
              lfs_1 = lfs_2 = 0;
              for (i = 0; i < verlist->objects; i++) {
                parypt = (point *) fastlookup(verlist, i);
                adjpt = *parypt;
                if (adjpt[pointmtrindex] > 0) {
                  len = distance(adjpt, ploop);
                  lfs_0 = 1.0 / len;
                  lfs_1 += lfs_0 * adjpt[pointmtrindex];
                  lfs_2 += lfs_0;
                }
              }
              assert(lfs_2 > 0);
              ploop[pointmtrindex] = lfs_1 / lfs_2;
              tetlist->restart();
              verlist->restart();
              featurecount++;
            } // if (b->nobisect)
          }
        } // if (ploop[pointmtrindex] == 0.0)
        ploop = pointtraverse();
      }
    
      if (b->verbose && (featurecount > 0)) {
        printf("  %d Steiner feature points.\n", featurecount);
      }
    
      if (checkconstraints) {
        // A .var file exists. Adjust feature sizes.
        if (in->facetconstraintlist) {
          // Have facet area constrains.
          subfaces->traversalinit();
          shloop.sh = shellfacetraverse(subfaces);
          while (shloop.sh != (shellface *) NULL) {
            varlen = areabound(shloop);
            if (varlen > 0.0) {
              // Check if the three corners are feature points.
              varlen = sqrt(varlen);
              for (j = 0; j < 3; j++) {
                ploop = (point) shloop.sh[3 + j];
                if (ploop[pointmtrindex] > 0) {
                  if (ploop[pointmtrindex] > varlen) {
                    ploop[pointmtrindex] = varlen;
                  }
                }
              } // j
            }
            shloop.sh = shellfacetraverse(subfaces);
          }
        }
        if (in->segmentconstraintlist) {
          // Have facet area constrains.
          subsegs->traversalinit();
          shloop.sh = shellfacetraverse(subsegs);
          while (shloop.sh != (shellface *) NULL) {
            varlen = areabound(shloop);
            if (varlen > 0.0) {
              // Check if the two endpoints are feature points.
              for (j = 0; j < 2; j++) {
                ploop = (point) shloop.sh[3 + j];
                if (ploop[pointmtrindex] > 0.0) {
                  if (ploop[pointmtrindex] > varlen) {
                    ploop[pointmtrindex] = varlen;
                  }
                }
              } // j
            }
            shloop.sh = shellfacetraverse(subsegs);
          }
        }
      } // if (checkconstraints)
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkseg4encroach()    Check if an edge is encroached upon by a point.    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
    {
      REAL ang;
      REAL prjpt[3], u, v, t;
    
      // Check if the point lies inside the diametrical sphere of this seg. 
      ang = interiorangle(checkpt, pa, pb, NULL);
      ang *= 2.0; // Compare it to PI/2 (90 degree).
    
      if (ang > PI) {
        // Inside.
        if (b->metric || b->nobisect) { // -m or -Y option.
          if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
            // In this case, we're sure that the projection of 'checkpt' lies
            //   inside the segment [a,b]. Check if 'checkpt' lies inside the
            //   protecting region of this seg.
            projpt2edge(checkpt, pa, pb, prjpt);
            // Get the mesh size at the location 'prjpt'.
            u = distance(pa, pb);
            v = distance(pa, prjpt);
            t = v / u;
            // 'u' is the mesh size at 'prjpt'
            u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
            v = distance(checkpt, prjpt);
            if (v < u) {
              return 1; // Encroached prot-ball!
            }
          } else {
            return 1; // NO protecting ball. Encroached.
          }
        } else {
          return 1; // Inside! Encroached.
        }
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkseg4split()    Check if we need to split a segment.                  //
    //                                                                           //
    // A segment needs to be split if it is in the following case:               //
    //  (1) It is encroached by an existing vertex.                              //
    //  (2) It has bad quality (too long).                                       //
    //                                                                           //
    // Return 1 if it needs to be split, otherwise, return 0.  'pencpt' returns  //
    // an encroaching point if there exists. 'qflag' returns '1' if the segment  //
    // has a length larger than the desired edge length.                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
    {
      triface searchtet, spintet;
      point forg, fdest, eapex;
      REAL ccent[3], len, r, d, diff;
      int i;
    
      REAL ti, tj, t, midpt[3];
      REAL ang;
      int eid;
    
      forg = sorg(*chkseg);
      fdest = sdest(*chkseg);
    
      if (b->verbose > 2) {
        printf("      Check segment (%d, %d)\n", pointmark(forg), pointmark(fdest));
      }
    
      // Initialize the return values.
      encpt = NULL;
      qflag = 0;
    
      len = distance(forg, fdest);
      r = 0.5 * len;
      for (i = 0; i < 3; i++) {
        ccent[i] = 0.5 * (forg[i] + fdest[i]);
      }
    
      // First check its quality.
      if (checkconstraints && (areabound(*chkseg) > 0.0)) {
        if (len > areabound(*chkseg)) {
          if (b->verbose > 2) {
            printf("      has too large size, len = %g (> %g)\n", len, 
                   areabound(*chkseg));
          }
          qflag = 1;
          return 1;
        }
      }
    
      if (b->fixedvolume) { // if (b->varvolume || b->fixedvolume) {
        if ((len * len * len) > b->maxvolume) {
          if (b->verbose > 2) {
            printf("      has too large size, len^3 = %g (> %g)\n", len*len*len, 
                   b->maxvolume);
          }
          qflag = 1;
          return 1;
        }
      }
    
      if (b->metric) { // -m option. Check mesh size. 
        // Check if the ccent lies outside one of the prot.balls at vertices.
        if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
            ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
          qflag = 1; // Enforce mesh size.
          return 1;
        }
      }
    
      if (b->psc) {
        // Check if it satisfies the approximation requirement.
        eid = shellmark(*chkseg);
        if ((pointtype(forg) == ACUTEVERTEX)||(pointtype(forg) == RIDGEVERTEX)) {
          ti = in->getvertexparamonedge(in->geomhandle, pointmark(forg), eid);
        } else {
          ti = pointgeomuv(forg, 0);
        }
        if ((pointtype(fdest) == ACUTEVERTEX)||(pointtype(fdest) == RIDGEVERTEX)) {
          tj = in->getvertexparamonedge(in->geomhandle, pointmark(fdest), eid);
        } else {
          tj = pointgeomuv(fdest, 0);
        }
        t = 0.5 * (ti + tj);
        in->getsteineronedge(in->geomhandle, eid, t, midpt);
        ang = interiorangle(midpt, forg, fdest, NULL) / PI * 180.0;
        if (ang < b->facet_ang_tol) {
          // Refine this segment.
          if (b->verbose > 2) {
            printf("      has bad approx, ang = %g\n", ang);
          }
          qflag = 1;
          return 1;
        }
      } // if (b->psc)
    
      // Second check if it is encroached.
      sstpivot1(*chkseg, searchtet);
      spintet = searchtet;
      while (1) {
        eapex = apex(spintet);
        if (eapex != dummypoint) {
          d = distance(ccent, eapex);
          diff = d - r;
          if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
          if (diff < 0) {
            // This segment is encroached by eapex.
            encpt = eapex;
            break;
          }
        }
        fnextself(spintet);
        if (spintet.tet == searchtet.tet) break;
      } // while (1)
    
      if (encpt != NULL) {
        if (b->verbose > 2) {
          printf("      is encroached by %d\n", pointmark(encpt));
        }
        return 1;
      }
    
      return 0; // No need to split it.
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // splitsegment()    Split a segment.                                        //
    //                                                                           //
    // The segment 'splitseg' is intended to be split. It will be split if it    //
    // is in one of the following cases:                                         //
    //   (1) It is encroached by an existing vertex 'encpt != NULL'; or          //
    //   (2) It is in bad quality 'qflag == 1'; or                               //
    //   (3) Its length is larger than the mesh sizes at its endpoints.          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag, 
                                 int chkencflag)
    {
      triface searchtet;
      face searchsh;
      point newpt, pa, pb;
      insertvertexflags ivf;
      REAL len; //, len1;
      int loc;
      //int i;
    
      pa = sorg(*splitseg);
      pb = sdest(*splitseg);
      len = distance(pa, pb);
    
      if (b->verbose > 2) {
        printf("      Split segment (%d, %d).\n", pointmark(pa), pointmark(pb));
      }
    
    
      if (qflag == 0) {
        if (shelltype(*splitseg) == SHARP) {
          // Do not split it (due to a very small angle) even it is encroached.
          // Avoid creating too many Steiner points.
          return 0;
        }
      }
    
      // Quickly check if we CAN split this segment.
      if ((encpt == NULL) && (qflag == 0)) {
        // Do not split this segment if the length is smaller than the mesh
        //   size at one of its endpoints.    
        if ((len < pa[pointmtrindex]) || (len < pb[pointmtrindex])) {
          return 0;
        }
      }
    
      makepoint(&newpt, FREESEGVERTEX);
      getsteinerptonsegment(splitseg, encpt, newpt);
    
    
      // Split the segment by the "Bowyer-Watson" algorithm.
      // Parameters are chosen as follows: 
      //   - bowywat = 3, preserve subsegments and subfaces;
      //   - flipflag = 3, check star & link facets for flipping;
      //   - rejflag = 0, do insertion even if it encoraches upon
      //                  other subsegments or subfaces.
      sstpivot1(*splitseg, searchtet);
      ivf.iloc = (int) ONEDGE;
      if (b->psc) {
        ivf.bowywat = 0;   // Do not enlarge the initial cavity.
        ivf.validflag = 0; // Do not validate the initial cavity.
      } else {
        ivf.bowywat = 3;   // Use the "Bowyer-Watson" algorithm to form cavity.
        ivf.validflag = 1; // Validate the B-W cavity.
      }
      ivf.lawson = 3;
      ivf.rejflag = 0;
      if ((encpt == NULL) && (qflag == 0)) {
        // Do not insert the point if it lies inside some protecting balls.
        ivf.rejflag |= 4; 
      }
      ivf.chkencflag = chkencflag;
      ivf.sloc = ivf.iloc;
      ivf.sbowywat = ivf.bowywat;  // Surface mesh options.
      ivf.splitbdflag = 1;
      ivf.respectbdflag = 1;
      ivf.assignmeshsize = 1;
      loc = insertvertex(newpt, &searchtet, &searchsh, splitseg, &ivf);
    
      // The new vertex should not too close to an existing point.
      if (loc == (int) NEARVERTEX) {
        outnodes(0);
        outsubfaces(0);
        outsubsegments(0);
        assert(0);
      } else if (loc == ENCVERTEX) {
        // The point lies in some protecting balls. Rejected.
        pointdealloc(newpt);
      } else if (loc == (int) BADELEMENT) {
        // Failed to create a valid sub-cavity in surface mesh.
        pointdealloc(newpt);
        //prob_subseg_count++;
      } else if (loc == (int) ONEDGE) {
        // Flip not locally Delaunay link facets by the 'Lawson's algo'.
        lawsonflip3d(newpt, 4, 0, chkencflag, 0);
        st_segref_count++;
        if (steinerleft > 0) steinerleft--;
        return 1;
      } else {
        // The vertex was not inserted. For unknown reasons.
        //pointdealloc(newpt);
        assert(0);
      }
    
      // Should not be here.
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // repairencsegs()    Repair encroached (sub) segments.                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::repairencsegs(int chkencflag)
    {
      badface *bface;
      point encpt = NULL;
      int qflag = 0;
    
      // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
      //   if an unlimited number of Steiner points is allowed.
      while ((badsubsegs->items > 0) && (steinerleft != 0)) {
        badsubsegs->traversalinit();
        bface = badfacetraverse(badsubsegs);
        while ((bface != NULL) && (steinerleft != 0)) {
          // A queued segment may have been deleted (split).
          if (bface->ss.sh[3] != NULL) {
            // A queued segment may have been processed. 
            if (smarktest2ed(bface->ss)) {
              sunmarktest2(bface->ss);
              if (checkseg4split(&(bface->ss), encpt, qflag)) {
                splitsegment(&(bface->ss), encpt, qflag, chkencflag);
              }
            }
          }
          badfacedealloc(badsubsegs, bface); // Remove this entry from list.
          bface = badfacetraverse(badsubsegs);
        }
      }
    
      if (badsubsegs->items > 0) {
        if (steinerleft == 0) {
          if (b->verbose) {
            printf("The desired number of Steiner points is reached.\n");
          }
        } else {
          assert(0); // Unknown case.
        }
        badsubsegs->traversalinit();
        bface = badfacetraverse(badsubsegs);
        while (bface  != NULL) {
          if (bface->ss.sh[3] != NULL) {
            if (smarktest2ed(bface->ss)) {
              sunmarktest2(bface->ss);
            }
          }
          bface = badfacetraverse(badsubsegs);
        }
        badsubsegs->restart();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkfac4encroach()    Check if a subface is encroached by a point.       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
                                      REAL* cent, REAL* r)
    {
      REAL rd, len;
      REAL prjpt[3], n[3];
      REAL a, a1, a2, a3;
    
      circumsphere(pa, pb, pc, NULL, cent, &rd);
      assert(rd != 0);
      len = distance(cent, checkpt);
      if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
     
      if (len < rd) {
        // The point lies inside the circumsphere of this face.
        if (b->metric || b->nobisect) { // -m or -Y option.
          if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
              (pc[pointmtrindex] > 0)) {
            // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
            projpt2face(checkpt, pa, pb, pc, prjpt);
            // Get the face area of [a,b,c].
            facenormal(pa, pb, pc, n, 1, NULL);
            a = sqrt(dot(n,n));
            // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
            facenormal(pa, pb, prjpt, n, 1, NULL);
            a1 = sqrt(dot(n,n));
            facenormal(pb, pc, prjpt, n, 1, NULL);
            a2 = sqrt(dot(n,n));
            facenormal(pc, pa, prjpt, n, 1, NULL);
            a3 = sqrt(dot(n,n));
            if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
              // This face contains the projection.
              // Get the mesh size at the location of the projection point.
              rd = a1 / a * pc[pointmtrindex]
                 + a2 / a * pa[pointmtrindex]
                 + a3 / a * pb[pointmtrindex];
              len = distance(prjpt, checkpt);
              if (len < rd) {
                return 1; // Encroached.
              }
            } else {
              // The projection lies outside the face.
              // In this case, 'p' must close to another face or a segment than
              //   to this one. We ignore this boundary face. 
            }
          } else {
            return 1;  // No protecting ball. Encroached.
          }
        } else {
          *r = rd;
          return 1;  // Encroached.
        }
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkfac4split()    Check if a subface needs to be split.                 //
    //                                                                           //
    // A subface needs to be split if it is in the following case:               //
    //  (1) It is encroached by an existing vertex.                              //
    //  (2) It has bad quality (has a small angle, -q).                          //
    //  (3) It's area is larger than a prescribed value (.var).                  //
    //                                                                           //
    // Return 1 if it needs to be split, otherwise, return 0.                    //
    // 'chkfac' represents its longest edge.                                     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag, 
                                   REAL *cent)
    {
      triface searchtet;
      face checksh; // *parysh;
      face checkseg;
      point pa, pb, pc;
      REAL area, rd, len, sintheta;
      REAL A[4][4], rhs[4], D;
      int indx[4];
      REAL elen[3];
      int i;
    
      encpt = NULL;
      qflag = 0;
    
      pa = sorg(*chkfac);
      pb = sdest(*chkfac);
      pc = sapex(*chkfac);
    
      if (b->verbose > 2) {
        printf("      Check subface (%d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc));
      }
    
      // Compute the coefficient matrix A (3x3).
      A[0][0] = pb[0] - pa[0];
      A[0][1] = pb[1] - pa[1];
      A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
      A[1][0] = pc[0] - pa[0];
      A[1][1] = pc[1] - pa[1];
      A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
      cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
    
      area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
    
      // Compute the right hand side vector b (3x1).
      elen[0] = dot(A[0], A[0]); // edge [a,b]
      elen[1] = dot(A[1], A[1]); // edge [a,c]
      rhs[0] = 0.5 * elen[0];
      rhs[1] = 0.5 * elen[1];
      rhs[2] = 0.0;
    
      // Solve the 3 by 3 equations use LU decomposition with partial 
      //   pivoting and backward and forward substitute..
      if (lu_decmp(A, 3, indx, &D, 0)) {
        lu_solve(A, 3, indx, rhs, 0);
        cent[0] = pa[0] + rhs[0];
        cent[1] = pa[1] + rhs[1];
        cent[2] = pa[2] + rhs[2];
        rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
    
        if (b->verbose > 2) {
          printf("      circent: (%g, %g, %g)\n", cent[0], cent[1], cent[2]);
          printf("      cirradi: %g\n", rd);
        }
    
        // Check the quality (radius-edge ratio) of this subface.
        //   Re-use variables 'A', 'rhs', and 'D'.
        A[2][0] = pb[0] - pc[0];
        A[2][1] = pb[1] - pc[1];
        A[2][2] = pb[2] - pc[2];
        elen[2] = dot(A[2], A[2]); // edge [b,c]
        // Get the shortest edge length in 'D'.
        D = elen[0]; // edge [a,b]
        for (i = 1; i < 3; i++) {
          if (D > elen[i]) D = elen[i];
        }
    
    
        D = sqrt(D);
        if (b->verbose > 2) {
          printf("      shortest edge length = %g\n", D);
        }
    
        rhs[3] = rd / D; // The radius-edge ratio.
    
        // Check if this subface is nearly degenerate.
        sintheta = 1.0 / (2.0 * rhs[3]);
        if (sintheta < sintheta_tol) {
          // Do not split this subface. Save it in list.
          if (b->verbose > 1) {
            printf("  !! A degenerated subface, theta = %g (deg)\n",
                   asin(sintheta) / PI * 180.0);
          }
          return 0; // Do not split a degenerated subface.
        }
    
        if (checkconstraints && (areabound(*chkfac) > 0.0)) {
          // Check if the subface has too big area.
          if (area > areabound(*chkfac)) {
            if (b->verbose > 2) {
              printf("      has too big area: %g (> %g)\n", area, 
                     areabound(*chkfac));
            }
            qflag = 1;
            return 1;
          }
        }
    
        if (b->metric) { // -m option. Check mesh size. 
          // Check if the ccent lies outside one of the prot.balls at vertices.
          if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
              ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
              ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
            qflag = 1; // Enforce mesh size.
            return 1;
          }
        }
    
    
        // Check if this subface is locally encroached.
        for (i = 0; i < 2; i++) {
          stpivot(*chkfac, searchtet);
          if (!ishulltet(searchtet)) {
            len = distance(oppo(searchtet), cent);
            if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
            if (len < rd) {
              if (b->verbose > 2) {
                printf("      is encroached by point %d\n", 
                       pointmark(oppo(searchtet)));
              }
              encpt = oppo(searchtet);
              return 1;
            }
          }
          sesymself(*chkfac);
        }
      } else {
        assert(0);
      } // if (!lu_decomp)
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // splitsubface()    Split a subface.                                        //
    //                                                                           //
    // The subface may be encroached, or in bad-quality. It is split at its cir- //
    // cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg-  //
    // ments. Instead, one of the encroached segments is split.  It is possible  //
    // that none of the encorached segments can be split.                        //
    //                                                                           //
    // The return value indicates whether a new point is inserted (> 0) or not   //
    // (= 0). Furthermore, it is inserted on an encorached segment (= 1) or in-  //
    // side the facet (= 2).                                                     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag,
                                 REAL *ccent, int chkencflag)
    {
      badface *bface;
      triface searchtet;
      face searchsh;
      face checkseg, *paryseg;
      point newpt, pa, pb, pc;
      insertvertexflags ivf;
      REAL rd;
      int splitflag;
      int loc;
      int i;
    
    
      pa = sorg(*splitfac);
      pb = sdest(*splitfac);
      pc = sapex(*splitfac);
    
      if (b->verbose > 2) {
        printf("      Split subface (%d, %d, %d).\n", pointmark(pa), pointmark(pb),
               pointmark(pc));
      }
    
    
      // Quickly check if we CAN split this subface.
      if (qflag == 0) {
        // Do not split this subface if it forms a very small dihedral with
        //   another facet. Avoid creating too many Steiner points.
        if (shelltype(*splitfac) == SHARP) {
          return 0;
        }
        // Do not split this subface if the 'ccent' lies inside the protect balls
        //   of one of its vertices.
        rd = distance(ccent, pa);
        if ((rd <= pa[pointmtrindex]) || (rd <= pb[pointmtrindex]) ||
            (rd <= pc[pointmtrindex])) {
          if (b->verbose > 2) {
            printf("      Encroaching a protecting ball. Rejected.\n");
          }
          return 0;
        }
      }
    
      // Initialize the inserting point.
      makepoint(&newpt, FREEFACETVERTEX);
    
      if (0) {
      } else {
        // Split the subface at its circumcenter.
        for (i = 0; i < 3; i++) newpt[i] = ccent[i];
        // Search a subface which contains 'newpt'.
        searchsh = *splitfac;
        // Calculate an above point. It lies above the plane containing
        //   the subface [a,b,c], and save it in dummypoint. Moreover,
        //   the vector cent->dummypoint is the normal of the plane.
        calculateabovepoint4(newpt, pa, pb, pc);
        //   Parameters: 'aflag' = 1, - above point exists.
        //   'cflag' = 0, - non-convex, check co-planarity of the result.
        //   'rflag' = 0, - no need to round the locating result.
        ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
        if ((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE)) {
          // Insert this point.
        } else {
          pointdealloc(newpt);
          return 0;
        }
      }
    
      // Insert the point.
      stpivot(searchsh, searchtet);
      //assert((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE));
      // Split the subface by the "Bowyer-Watson" algorithm.
      ivf.bowywat = 3; // Form B-W cavity.
      ivf.lawson = 3; // Queue faces of the cavity for flipping.
      ivf.rejflag = 1; // Reject it if it encroached upon any segment.
      if (qflag == 0) {
        ivf.rejflag |= 4; // Reject it if it encroached upon any vertex.
      }
      ivf.chkencflag = chkencflag;
      ivf.sloc = ivf.iloc;
      ivf.sbowywat = ivf.bowywat;
      ivf.splitbdflag = 1;
      ivf.validflag = 1;
      ivf.respectbdflag = 1;
      ivf.assignmeshsize = 1;
    
      ivf.refineflag = 2;
      ivf.refinesh = searchsh;
    
      loc = insertvertex(newpt, &searchtet, &searchsh, NULL, &ivf);
    
      if (loc == (int) ENCSEGMENT) {
        // The new point encroaches upon some segments.
        pointdealloc(newpt);
        assert(encseglist->objects > 0);
        // Select an encroached segment and split it.
        splitflag = 0;
        for (i = 0; i < encseglist->objects; i++) {
          paryseg = (face *) fastlookup(encseglist, i);
          if (splitsegment(paryseg, NULL, qflag, chkencflag | 1)) {
            splitflag = 1; // A point is inserted on a segment.
            break;
          }
        }
        encseglist->restart();
        if (splitflag) {
          // Some segments may need to be repaired.
          repairencsegs(chkencflag | 1);
          // Queue this subface if it is still alive and not queued.
          if (splitfac->sh[3] != NULL) {
            if (!smarktest2ed(*splitfac)) {
              bface = (badface *) badsubfacs->alloc();
              bface->ss = *splitfac;
              smarktest2(bface->ss); // Only queue it once.
              bface->forg = sorg(*splitfac); // An alive badface.
            }
          }
        }
        return splitflag;
      } else if (loc == (int) ENCVERTEX) {
        // The point lies inside some protecting balls. Rejected.
        pointdealloc(newpt);
      } else if (loc == (int) ONVERTEX) {
        pointdealloc(newpt);
      } else if (loc == (int) NEARVERTEX) {
        pointdealloc(newpt);
      } else if (loc == (int) BADELEMENT) {
        // Failed to create a valid sub-cavity in surface mesh.
        pointdealloc(newpt);
      } else if (loc == (int) ivf.iloc) {
        // Flip not locally Delaunay link facets.
        lawsonflip3d(newpt, 4, 0, chkencflag, 0);
        st_facref_count++;
        if (steinerleft > 0) steinerleft--;
        return 1; // A point is inserted on facet.
      } else {
        // Unknown error.
        assert(0);
      }
    
      // Should not be here.
      return 0;  
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // repairencfacs()    Repair encroached subfaces.                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::repairencfacs(int chkencflag)
    {
      badface *bface;
      point encpt = NULL;
      int qflag = 0;
      REAL ccent[3];
    
      // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
      //   if an unlimited number of Steiner points is allowed.
      while ((badsubfacs->items > 0) && (steinerleft != 0)) {
        badsubfacs->traversalinit();
        bface = badfacetraverse(badsubfacs);
        while ((bface != NULL) && (steinerleft != 0)) {
          // A queued subface may have been deleted (split).
          if (bface->ss.sh[3] != NULL) {
            // A queued subface may have been processed. 
            if (smarktest2ed(bface->ss)) {
              sunmarktest2(bface->ss);
              if (checkfac4split(&(bface->ss), encpt, qflag, ccent)) {
                splitsubface(&(bface->ss), encpt, qflag, ccent, chkencflag);
              }
            }
          }
          badfacedealloc(badsubfacs, bface); // Remove this entry from list.
          bface = badfacetraverse(badsubfacs);
        }
      }
    
      if (badsubfacs->items > 0) {
        if (steinerleft == 0) {
          if (b->verbose) {
            printf("The desired number of Steiner points is reached.\n");
          }
        } else {
          assert(0); // Unknown case.
        }
        badsubfacs->traversalinit();
        bface = badfacetraverse(badsubfacs);
        while (bface  != NULL) {
          if (bface->ss.sh[3] != NULL) {
            if (smarktest2ed(bface->ss)) {
              sunmarktest2(bface->ss);
            }
          }
          bface = badfacetraverse(badsubfacs);
        }
        badsubfacs->restart();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checktet4split()    Check if the tet needs to be split.                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent) 
    {
      point pa, pb, pc, pd, *ppt;
      REAL vda[3], vdb[3], vdc[3];
      REAL vab[3], vbc[3], vca[3];
      REAL N[4][3], L[4], cosd[6], elen[6];
      REAL maxcosd, vol, volbnd, smlen, rd;
      REAL A[4][4], rhs[4], D;
      int indx[4];
      int i, j;
    
      qflag = 0;
    
      pd = (point) chktet->tet[7];
      if (pd == dummypoint) {
        return 0; // Do not split a hull tet.
      }
    
      pa = (point) chktet->tet[4];
      pb = (point) chktet->tet[5];
      pc = (point) chktet->tet[6];
    
      if (b->verbose > 2) {
        printf("      Check tet (%d, %d, %d, %d)\n", pointmark(pa),
               pointmark(pb), pointmark(pc), pointmark(pd));
      }
    
      // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
      // Set the matrix A = [vda, vdb, vdc]^T.
      for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
      for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
      for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
    
      // Get the other edge vectors.
      for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
      for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
      for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
    
      if (!lu_decmp(A, 3, indx, &D, 0)) {
        // A degenerated tet (vol = 0).
        if (b->verbose > 2) {
          printf("      Min dihed = 0 (degree)\n");
        }
        // Return its barycenter.
        for (i = 0; i < 3; i++) {
          ccent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
        }
        return 1;
      }
    
      // Check volume if '-a#' and '-a' options are used.
      if (b->varvolume || b->fixedvolume) {
        vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
        if (b->verbose > 2) {
          printf("      volume = %g.\n", vol);
        }
        if (b->fixedvolume) {
          if (vol > b->maxvolume) {
            qflag = 1;
          }
        } 
        if (!qflag && b->varvolume) {
          volbnd = volumebound(chktet->tet);
          if ((volbnd > 0.0) && (vol > volbnd)) {
            qflag = 1;
          }
        }
        if (qflag == 1) {
          // Calculate the circumcenter of this tet.
          rhs[0] = 0.5 * dot(vda, vda);
          rhs[1] = 0.5 * dot(vdb, vdb);
          rhs[2] = 0.5 * dot(vdc, vdc);
          lu_solve(A, 3, indx, rhs, 0);            
          for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
          return 1;
        }
      }
    
      if (in->tetunsuitable != NULL) {
        // Execute the user-defined meshing sizing evaluation.
        if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
          // Calculate the circumcenter of this tet.
          rhs[0] = 0.5 * dot(vda, vda);
          rhs[1] = 0.5 * dot(vdb, vdb);
          rhs[2] = 0.5 * dot(vdc, vdc);
          lu_solve(A, 3, indx, rhs, 0);            
          for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
          return 1;
        } else {
          return 0; // Do not split this tet.
        }
      }
    
      // Check the radius-edge ratio. Set by -q#.
      if (b->minratio > 0) { 
        // Calculate the circumcenter and radius of this tet.
        rhs[0] = 0.5 * dot(vda, vda);
        rhs[1] = 0.5 * dot(vdb, vdb);
        rhs[2] = 0.5 * dot(vdc, vdc);
        lu_solve(A, 3, indx, rhs, 0);            
        for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
        rd = sqrt(dot(rhs, rhs));
        // Calculate the shortest edge length.
        elen[0] = dot(vda, vda);
        elen[1] = dot(vdb, vdb);
        elen[2] = dot(vdc, vdc);
        elen[3] = dot(vab, vab);
        elen[4] = dot(vbc, vbc);
        elen[5] = dot(vca, vca);
        smlen = elen[0]; //sidx = 0;
        for (i = 1; i < 6; i++) {
          if (smlen > elen[i]) { 
            smlen = elen[i]; //sidx = i; 
          }
        }
        smlen = sqrt(smlen);
        D = rd / smlen;
        if (b->verbose > 2) {
          printf("      Ratio-edge ratio = %g, smlen = %g\n", D, smlen);
        }
        if (D > b->minratio) {
          // A bad radius-edge ratio.
          return 1;
        }
      }
    
      // Check the minimum dihedral angle. Set by -qq#.
      if (b->mindihedral > 0) { 
        // Compute the 4 face normals (N[0], ..., N[3]).
        for (j = 0; j < 3; j++) {
          for (i = 0; i < 3; i++) N[j][i] = 0.0;
          N[j][j] = 1.0;  // Positive means the inside direction
          lu_solve(A, 3, indx, N[j], 0);
        }
        for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
        // Normalize the normals.
        for (i = 0; i < 4; i++) {
          L[i] = sqrt(dot(N[i], N[i]));
          assert(L[i] > 0);
          //if (L[i] > 0.0) {
            for (j = 0; j < 3; j++) N[i][j] /= L[i];
          //}
        }
        // Calculate the six dihedral angles.
        cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
        cosd[1] = -dot(N[0], N[2]);
        cosd[2] = -dot(N[0], N[3]);
        cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
        cosd[4] = -dot(N[1], N[3]);
        cosd[5] = -dot(N[2], N[3]); // Edge ab
        // Get the smallest diehedral angle.
        //maxcosd = mincosd = cosd[0];
        maxcosd = cosd[0];
        for (i = 1; i < 6; i++) {
          //if (cosd[i] > maxcosd) maxcosd = cosd[i];
          maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
          //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
        }
        if (b->verbose > 2) {
          printf("      Min dihed = %g (degree)\n", acos(maxcosd) / PI * 180.0);
        }
        if (maxcosd > cosmindihed) {
          // Calculate the circumcenter of this tet.
          // A bad dihedral angle.
          //if ((b->quality & 1) == 0) {
            rhs[0] = 0.5 * dot(vda, vda);
            rhs[1] = 0.5 * dot(vdb, vdb);
            rhs[2] = 0.5 * dot(vdc, vdc);
            lu_solve(A, 3, indx, rhs, 0);            
            for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
            //*rd = sqrt(dot(rhs, rhs));
          //}
          return 1;
        }
      }
    
      if (b->metric) { // -m option. Check mesh size. 
        // Calculate the circumradius of this tet.
        rhs[0] = 0.5 * dot(vda, vda);
        rhs[1] = 0.5 * dot(vdb, vdb);
        rhs[2] = 0.5 * dot(vdc, vdc);
        lu_solve(A, 3, indx, rhs, 0);            
        for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
        rd = sqrt(dot(rhs, rhs));
        // Check if the ccent lies outside one of the prot.balls at vertices.
        ppt = (point *) &(chktet->tet[4]);
        for (i = 0; i < 4; i++) {
          if (ppt[i][pointmtrindex] > 0) {
            if (rd > ppt[i][pointmtrindex]) {
              qflag = 1; // Enforce mesh size.
              return 1;
            }
          }
        }
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // splittetrahedron()    Split a tetrahedron.                                //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, 
                                     int chkencflag)
    {
      badface *bface;
      triface searchtet;
      face checkseg, *paryseg;
      point newpt, pa, *ppt = NULL;
      insertvertexflags ivf;
      REAL rd;
      int splitflag;
      int loc;
      int i;
    
      if (b->verbose > 2) {
        ppt = (point *) &(splittet->tet[4]);
        printf("      Split tet (%d, %d, %d, %d).\n", pointmark(ppt[0]), 
               pointmark(ppt[1]), pointmark(ppt[2]), pointmark(ppt[3]));
      }
    
    
      if (qflag == 0) {
        // It is a bad quality tet (not due to mesh size).
        // It can be split if 'ccent' does not encroach upon any prot. balls.
        //   Do a quick check if the 'ccent' lies inside the protect balls
        //   of one of the vertices of this tet.
        ppt = (point *) &(splittet->tet[4]);
        rd = distance(ccent, ppt[0]);
        if ((rd <= ppt[0][pointmtrindex]) || (rd <= ppt[1][pointmtrindex]) ||
            (rd <= ppt[2][pointmtrindex]) || (rd <= ppt[3][pointmtrindex])) {
          if (b->verbose > 2) {
            printf("      Encroaching a protecting ball. Rejected.\n");
          }
          return 0;
        }
      }
    
      makepoint(&newpt, FREEVOLVERTEX);
      for (i = 0; i < 3; i++) newpt[i] = ccent[i];
    
      searchtet = *splittet;
      ivf.iloc = (int) OUTSIDE;
      // Parameters are chosen as follows: 
      //   - bowywat = 3, preserve subsegments and subfaces;
      //   - flipflag = 3, check star & link facets for flipping;
      //   - rejflag = 3, do not insert the point if it encroaches upon
      //                  any segment or subface.
      //   - chkencflag = 4, (as input), only check tetrahedra.
      ivf.bowywat = 3;
      ivf.lawson = 3;
      ivf.rejflag = 3;
      if (qflag == 0) {
        ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
      }
      ivf.chkencflag = chkencflag;
      ivf.sloc = ivf.sbowywat = 0; // No use.
      ivf.splitbdflag = 0; // No use.
      ivf.validflag = 1;
      ivf.respectbdflag = 1;
      ivf.assignmeshsize = 1;
    
      ivf.refineflag = 1;
      ivf.refinetet = *splittet;
    
      loc = insertvertex(newpt, &searchtet, NULL, NULL, &ivf);
    
      if (loc == (int) ENCSEGMENT) {
        // There are encroached segments.
        pointdealloc(newpt);
        assert(encseglist->objects > 0);
        splitflag = 0;
        if (!b->nobisect) { // not -Y option
          // Select an encroached segment and split it.
          for (i = 0; i < encseglist->objects; i++) {
            paryseg = (face *) fastlookup(encseglist, i);
            if (splitsegment(paryseg, NULL, qflag, chkencflag | 3)) {
              splitflag = 1; // A point is inserted on a segment.
              break;
            }
          }
        } // if (!b->nobisect)
        encseglist->restart();
        if (splitflag) {
          // Some segments may need to be repaired.
          repairencsegs(chkencflag | 3);
          // Some subfaces may need to be repaired.
          repairencfacs(chkencflag | 2);
          // Queue the tet if it is still alive and not queued.
          if (splittet->tet[4] != NULL) {
            if (!marktest2ed(*splittet)) {
              bface = (badface *) badtetrahedrons->alloc();
              bface->tt = *splittet;
              marktest2(bface->tt); // Only queue it once.
              bface->forg = org(*splittet); // An alive badface.
            }
          }
        }
        return splitflag;
      } else if (loc == (int) ENCSUBFACE) {
        // There are encroached subfaces.
        pointdealloc(newpt);
        assert(encshlist->objects > 0);
        splitflag = 0;
        if (!b->nobisect) { // not -Y option
          // Select an encroached subface and split it.
          for (i = 0; i < encshlist->objects; i++) {
            bface = (badface *) fastlookup(encshlist, i);
            if (splitsubface(&(bface->ss),NULL,qflag,bface->cent,chkencflag | 2)) {
              splitflag = 1; // A point is inserted on a subface or a segment.
              break;
            }
          }
        } // if (!b->nobisect)
        encshlist->restart();
        if (splitflag) {
          assert(badsubsegs->items == 0l); // repairencsegs(chkencflag | 3);
          // Some subfaces may need to be repaired.
          repairencfacs(chkencflag | 2);
          // Queue the tet if it is still alive.
          if (splittet->tet[4] != NULL) {
            if (!marktest2ed(*splittet)) {
              bface = (badface *) badtetrahedrons->alloc();
              bface->tt = *splittet;
              marktest2(bface->tt); // Only queue it once.
              bface->forg = org(*splittet); // An alive badface.
            }
          }
        }
        return splitflag;
      } else if (loc == (int) OUTSIDE) {
        // There exists not boundary conforming segments/subfaces.
        pointdealloc(newpt);
      } else if (loc == (int) ONVERTEX) {
        // Found a coincident vertex. It should be a Steiner point.
        pa = org(searchtet);
        assert(pointtype(pa) == FREEVOLVERTEX);
        // Delete this new point.
        pointdealloc(newpt);
      } else if (loc == (int) NEARVERTEX) {
        // The point lies very close to an existing point.
        pa = point2ppt(newpt);
        assert(pointtype(pa) == FREEVOLVERTEX);
        // Delete this new point.
        pointdealloc(newpt);
      } else if (loc == (int) ENCVERTEX) {
        // The new point encoraches upon some protecting balls. Rejected.
        pointdealloc(newpt);
      } else if (loc == (int) BADELEMENT) {
        pointdealloc(newpt);
      } else {
        // Recover Delaunayness.
        lawsonflip3d(newpt, 4, 0, chkencflag, 0);
        // Vertex is inserted.
        st_volref_count++;
        if (steinerleft > 0) steinerleft--;
        return 1;
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // repairbadtets()    Repair bad quality tetrahedra.                         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::repairbadtets(int chkencflag)
    {
      badface *bface;
      REAL ccent[3];
      int qflag = 0;
    
      // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
      //   if an unlimited number of Steiner points is allowed.
      while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
        badtetrahedrons->traversalinit();
        bface = badfacetraverse(badtetrahedrons);
        while ((bface != NULL) && (steinerleft != 0)) {
          // A queued tet may have been deleted.
          if (!isdeadtet(bface->tt)) {
            // A queued tet may have been processed.
            if (marktest2ed(bface->tt)) {
              unmarktest2(bface->tt);
              if (checktet4split(&(bface->tt), qflag, ccent)) {
                splittetrahedron(&(bface->tt), qflag, ccent, chkencflag);
              }
            }
          }
          badfacedealloc(badtetrahedrons, bface);
          bface = badfacetraverse(badtetrahedrons);
        }
      }
    
      if (badtetrahedrons->items > 0) {
        if (steinerleft == 0) {
          if (b->verbose) {
            printf("The desired number of Steiner points is reached.\n");
          }
        } else {
          assert(0); // Unknown case.
        }
        // Unmark all queued tet.
        badtetrahedrons->traversalinit();
        bface = badfacetraverse(badtetrahedrons);
        while (bface != NULL) {
          if (!isdeadtet(bface->tt)) {
            if (marktest2ed(bface->tt)) {
              unmarktest2(bface->tt);
            }
          }
          bface = badfacetraverse(badtetrahedrons);
        }
        // Clear the pool.
        badtetrahedrons->restart();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // enforcequality()    Refine the mesh.                                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::delaunayrefinement()
    {
      badface *bface;
      triface checktet;
      face checksh;
      face checkseg;
      long steinercount;
      int chkencflag;
    
      long bak_segref_count, bak_facref_count, bak_volref_count;
    
      if (!b->quiet) {
        printf("Refining mesh...\n");
      }
    
      if (b->verbose) {
        printf("  Edge length limit = %g.\n", b->minedgelength);
      }
    
      steinerleft = b->steinerleft;  // Upperbound of # Steiner points (by -S#).
      if (steinerleft > 0) {
        // Check if we've already used up the given number of Steiner points.
        steinercount = st_segref_count + st_facref_count + st_volref_count;
        if (steinercount < steinerleft) {
          steinerleft -= steinercount;
        } else {
          if (!b->quiet) {
            printf("\nWarning:  ");
            printf("The desired number of Steiner points (%d) is reached.\n\n",
                   b->steinerleft);
          }
          return; // No more Steiner points.
        }
      }
    
      if (b->refine || b->nobisect) { // '-r' or '-Y' option.
        markacutevertices();
      }
    
      marksharpsegments();
    
      decidefeaturepointsizes();
    
      encseglist = new arraypool(sizeof(face), 8);
      encshlist = new arraypool(sizeof(badface), 8);
    
      if (!b->nobisect) { // if no '-Y' option
        if (b->verbose) {
          printf("  Splitting encroached subsegments.\n");
        }
    
        chkencflag = 1; // Only check encroaching subsegments.
        steinercount = points->items;
    
        // Initialize the pool of encroached subsegments.
        badsubsegs = new memorypool(sizeof(badface), b->shellfaceperblock, 
                                    memorypool::POINTER, 0);
    
        // Add all segments into the pool.
        subsegs->traversalinit();
        checkseg.sh = shellfacetraverse(subsegs);
        while (checkseg.sh != (shellface *) NULL) {
          bface = (badface *) badsubsegs->alloc();
          bface->ss = checkseg;
          smarktest2(bface->ss); // Only queue it once.
          bface->forg = sorg(checkseg); // An alive badface.
          checkseg.sh = shellfacetraverse(subsegs);
        }
    
        // Split all encroached segments.
        repairencsegs(chkencflag);
    
        if (b->verbose) {
          printf("  Added %ld Steiner points.\n", points->items - steinercount);
        }
    
    
        if (b->reflevel > 1) { // '-D2' option
          if (b->verbose) {
            printf("  Splitting encroached subfaces.\n");
          }
    
          chkencflag = 2; // Only check encroaching subfaces.
          steinercount = points->items;
          bak_segref_count = st_segref_count;
          bak_facref_count = st_facref_count;
    
          // Initialize the pool of encroached subfaces.
          badsubfacs = new memorypool(sizeof(badface), b->shellfaceperblock, 
                                      memorypool::POINTER, 0);
    
          // Add all subfaces into the pool.
          subfaces->traversalinit();
          checksh.sh = shellfacetraverse(subfaces);
          while (checksh.sh != (shellface *) NULL) {
            bface = (badface *) badsubfacs->alloc();
            bface->ss = checksh;
            smarktest2(bface->ss); // Only queue it once.
            bface->forg = sorg(checksh); // An alive badface.
            checksh.sh = shellfacetraverse(subfaces);
          }
    
          // Split all encroached subfaces.
          repairencfacs(chkencflag);
    
          if (b->verbose) {
            printf("  Added %ld (%ld,%ld) Steiner points.\n",  
                   points->items-steinercount, st_segref_count-bak_segref_count,
                   st_facref_count-bak_facref_count);
          }
    
        } // if (b->reflevel > 1)
      } // if (!b->nobisect)
    
      if (b->reflevel > 2) { // '-D3' option (The default option)
        if (b->verbose) {
          printf("  Splitting bad quality tets.\n");
        }
    
        chkencflag = 4; // Only check tetrahedra.
        steinercount = points->items;
        bak_segref_count = st_segref_count;
        bak_facref_count = st_facref_count;
        bak_volref_count = st_volref_count;
    
        // The cosine value of the min dihedral angle (-qq) for tetrahedra.
        cosmindihed = cos(b->mindihedral / 180.0 * PI);
    
        // Initialize the pool of bad quality tetrahedra.
        badtetrahedrons = new memorypool(sizeof(badface), b->tetrahedraperblock,
                                         memorypool::POINTER, 0);
    
        // Add all tetrahedra (no hull tets) into the pool.
        tetrahedrons->traversalinit();
        checktet.tet = tetrahedrontraverse();
        while (checktet.tet != NULL) {
          bface = (badface *) badtetrahedrons->alloc();
          bface->tt = checktet;
          marktest2(bface->tt); // Only queue it once.
          bface->forg = org(checktet); // An alive badface.
          checktet.tet = tetrahedrontraverse();
        }
    
        // Split all bad quality tetrahedra.
        repairbadtets(chkencflag);
    
        if (b->verbose) {
          printf("  Added %ld (%ld,%ld,%ld) Steiner points.\n", 
                 points->items - steinercount, 
                 st_segref_count - bak_segref_count,
                 st_facref_count - bak_facref_count,
                 st_volref_count - bak_volref_count);
        }
      } // if (b->reflevel > 2)
    
      if (steinerleft == 0) {
        if (!b->quiet) {
          printf("\nWarnning:  ");
          printf("The desired number of Steiner points (%d) is reached.\n\n",
                 b->steinerleft);
        }
      }
    
      delete encseglist;
      delete encshlist;
    
      if (!b->nobisect) {
        delete badsubsegs;
        if (b->reflevel > 1) {
          delete badsubfacs;
        }
      }
      if (b->reflevel > 2) {
        delete badtetrahedrons;
      }
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// refine_cxx ///////////////////////////////////////////////////////////////
    
    //// optimize_cxx /////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // recoverdelaunay()    Recovery the locally Delaunay property.              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::recoverdelaunay()
    {
      arraypool *flipqueue, *nextflipqueue, *swapqueue;
      badface *bface, *parybface;
      triface tetloop, neightet, *parytet;
      point *ppt;
      flipconstraints fc;
      int i, j;
    
      if (!b->quiet) {
        printf("Recovering Delaunayness...\n");
      }
    
      if (b->verbose) {
        printf("  max_flipstarsize = %d.\n", b->optmaxflipstarsize);
        printf("  max_fliplinklevel = %d.\n", b->delmaxfliplevel);
      }
    
      calc_tetprism_vol = 1;
      tetprism_vol_sum = 0.0; // Initialize it.
    
      assert(flipstack == NULL);
      assert(unflipqueue->objects == 0l);
    
      // Put all interior faces of the mesh into 'flipstack'.
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != NULL) {
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          // Avoid queue a face twice.
          fsym(tetloop, neightet);
          if (!ishulltet(neightet)) {
            if (!facemarked(neightet)) {
              flippush(flipstack, &tetloop);
            }
          }
        }
        ppt = (point *) &(tetloop.tet[4]);
        tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (b->verbose) {
        printf("  Initial obj = %.17g\n", tetprism_vol_sum);
      }
    
      if (b->verbose > 1) {
        printf("    Recover Delaunay [Lawson] : %ld\n", flippool->items);
      }
      assert(unflipqueue->objects == 0l);
    
      // First only use the basic Lawson's flip.
      lawsonflip3d(NULL, 4, 0, 0, 1);
    
      if (b->verbose > 1) {
        printf("    New obj = %.17g\n", tetprism_vol_sum);
      }
    
      if (unflipqueue->objects == 0l) {
        // The mesh is Delaunay.
        return;
      }
    
      // Set the common options.
      fc.remove_ndelaunay_edge = 1;
      fc.unflip = 1; // Unflip if the edge is not flipped.
      fc.collectnewtets = 1;
    
      autofliplinklevel = 1; // Init value.
      b->fliplinklevel = -1;
    
      // For efficiency reason, we limit the maximium size of the edge star.
      // 'b->optmaxflipstarsize' is set by -OOOOO (5 Os), default is 10.
      int bakmaxflipstarsize = b->flipstarsize;
      b->flipstarsize = b->optmaxflipstarsize;
    
      flipqueue = new arraypool(sizeof(badface), 10);
      nextflipqueue = new arraypool(sizeof(badface), 10);
    
    
      // Swap the two flip queues.
      swapqueue = flipqueue;
      flipqueue = unflipqueue;
      unflipqueue = swapqueue;
    
      while (flipqueue->objects > 0l) {
    
        while (flipqueue->objects > 0l) {
    
          if (b->verbose > 1) {
            printf("    Recover Delaunay [level = %2d] #:  %ld.\n",
                   autofliplinklevel, flipqueue->objects);
          }
    
          for (i = 0; i < flipqueue->objects; i++) {
            bface  = (badface *) fastlookup(flipqueue, i);
            if (getedge(bface->forg, bface->fdest, &bface->tt)) {
              // Remember the the objective value (volume of all tetprisms).
              fc.bak_tetprism_vol = tetprism_vol_sum; 
              if (removeedgebyflips(&(bface->tt), &fc) == 2) {
                if (b->verbose > 2) {
                  printf("      Decreased quantity: %.17g.\n", 
                         fc.bak_tetprism_vol - tetprism_vol_sum);
                }
                // Queue new faces for flips.
                for (j = 0; j < cavetetlist->objects; j++) {
                  parytet = (triface *) fastlookup(cavetetlist, j);
                  // A queued new tet may be dead.
                  if (!isdeadtet(*parytet)) {
                    for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
                      // Avoid queue a face twice.
                      fsym(*parytet, neightet);
                      if (!facemarked(neightet)) {
                        flippush(flipstack, parytet);
                      }
                    } // parytet->ver
                  }
                } // j
                cavetetlist->restart();
                // Remove locally non-Delaunay faces. New non-Delaunay edges
                //   may be found. They are saved in 'unflipqueue'.
                lawsonflip3d(NULL, 4, 0, 0, 1);
              } else {
                // Unable to remove this edge. Save it.
                nextflipqueue->newindex((void **) &parybface);
                *parybface = *bface;
              }
            }
          } // i
    
          flipqueue->restart();
    
          // Swap the two flip queues.
          swapqueue = flipqueue;
          flipqueue = unflipqueue;
          unflipqueue = swapqueue;
        } // while (flipqueue->objects > 0l)
    
        if (b->verbose > 1) {
          printf("    New obj = %.17g.\n", tetprism_vol_sum);
        }
    
        // Swap the two flip queues.
        swapqueue = flipqueue;
        flipqueue = nextflipqueue;
        nextflipqueue = swapqueue;
    
        if (flipqueue->objects > 0l) {
          // 'b->delmaxfliplevel' is set by -OOOO, default is 1.
          if (autofliplinklevel >= b->delmaxfliplevel) {
            // For efficiency reason, we do not search too far.
            break;
          }
          autofliplinklevel+=b->fliplinklevelinc;
        }
    
      } // while (flipqueue->objects > 0l)
    
      if (flipqueue->objects > 0l) {
        if (b->verbose > 1) {
          printf("    %ld non-Delaunay edges remained.\n", flipqueue->objects);
        }
      }
    
      b->flipstarsize = bakmaxflipstarsize;
    
      delete nextflipqueue;
      delete flipqueue;
    
      calc_tetprism_vol = 0;
    
      if (b->verbose) {
        printf("  Final  obj  = %.17g\n", tetprism_vol_sum);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // gettetrahedron()    Get a tetrahedron which have the given vertices.      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::gettetrahedron(point pa, point pb, point pc, point pd, 
                                   triface *searchtet)
    {
      triface spintet;
    
      if (b->verbose > 2) {
        printf("      Get tet [%d,%d,%d,%d].\n", pointmark(pa), pointmark(pb),
               pointmark(pc), pointmark(pd));
      }
    
      if (getedge(pa, pb, searchtet)) {
        spintet = *searchtet;
        while (1) {
          if (apex(spintet) == pc) {
            *searchtet = spintet;
            break;
          }
          fnextself(spintet);
          if (spintet.tet == searchtet->tet) break;
        }
        if (apex(*searchtet) == pc) {
          if (oppo(*searchtet) == pd) {
            return 1;
          } else {
            fsymself(*searchtet);
            if (oppo(*searchtet) == pd) {
              return 1;
            }
          }
        }
      }
    
      return 0;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // improvequalitybyflips()    Improve the mesh quality by flips.             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    long tetgenmesh::improvequalitybyflips()
    {
      arraypool *flipqueue, *nextflipqueue, *swapqueue;
      badface *bface, *parybface;
      triface *parytet;
      point *ppt;
      flipconstraints fc;
      REAL *cosdd, ncosdd[6], maxdd;
      long totalremcount, remcount;
      int remflag;
      int n, i, j, k;
    
      //assert(unflipqueue->objects > 0l);
      flipqueue = new arraypool(sizeof(badface), 10);
      nextflipqueue = new arraypool(sizeof(badface), 10);
    
      // Flip edge options.
      b->fliplinklevel = -1;
      autofliplinklevel = 1; // Init value.
    
      // For efficiency reason, we limit the maximium size of the edge star.
      // 'b->optmaxflipstarsize' is set by -OOOOO (5 Os), default is 10.
      int bakmaxflipstarsize = b->flipstarsize; 
      b->flipstarsize = b->optmaxflipstarsize; 
    
      fc.remove_large_angle = 1;
      fc.unflip = 1;
      fc.collectnewtets = 1;
    
      totalremcount = 0l;
    
      // Swap the two flip queues.
      swapqueue = flipqueue;
      flipqueue = unflipqueue;
      unflipqueue = swapqueue;
    
      while (flipqueue->objects > 0l) {
    
        remcount = 0l;
    
        while (flipqueue->objects > 0l) {
          if (b->verbose > 1) {
            printf("    Improving mesh qualiy by flips [%d]#:  %ld.\n",
                   autofliplinklevel, flipqueue->objects);
          }
    
          for (k = 0; k < flipqueue->objects; k++) {
            bface  = (badface *) fastlookup(flipqueue, k);
            if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
                               bface->foppo, &bface->tt)) {
              // There are bad dihedral angles in this tet.
              if (bface->tt.ver != 11) {
                // The dihedral angles are permuted.
                // Here we simply re-compute them. Slow!!.
                ppt = (point *) & (bface->tt.tet[4]);
                tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
                               &maxdd, NULL);
                bface->forg = ppt[0];
                bface->fdest = ppt[1];
                bface->fapex = ppt[2];
                bface->foppo = ppt[3];
                bface->tt.ver = 11;
              }
              cosdd = bface->cent;
              remflag = 0;
              for (i = 0; (i < 6) && !remflag; i++) {
                if (cosdd[i] < cosmaxdihed) {
                  // Found a large dihedral angle.
                  bface->tt.ver = edge2ver[i]; // Go to the edge.
                  if (b->verbose > 2) {
                    printf("      Found a large angle [%d,%d,%d,%d] (%g).\n", 
                           pointmark(org(bface->tt)), pointmark(dest(bface->tt)),
                           pointmark(apex(bface->tt)), pointmark(oppo(bface->tt)),
                           acos(cosdd[i]) / PI * 180.0);
                  }
                  fc.cosdihed_in = cosdd[i];
                  fc.cosdihed_out = 0.0; // 90 degree.
                  n = removeedgebyflips(&(bface->tt), &fc);
                  if (n == 2) {
                    // Edge is flipped.
                    if (b->verbose > 2) {
                      printf("      Reduced a large angle to %g degree.\n",
                             acos(fc.cosdihed_out) / PI * 180.0);
                    }
                    remflag = 1;
                    if (fc.cosdihed_out < cosmaxdihed) {
                      // Queue new bad tets for further improvements.
                      for (j = 0; j < cavetetlist->objects; j++) {
                        parytet = (triface *) fastlookup(cavetetlist, j);
                        if (!isdeadtet(*parytet)) {
                          ppt = (point *) & (parytet->tet[4]);
                          //if (!marktest2ed(*parytet)) {
                          assert(!marktest2ed(*parytet)); // SELF_CHECK
                          // Do not test a hull tet.
                          if (ppt[3] != dummypoint) {
                            tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, 
                                           &maxdd, NULL);
                            if (maxdd < cosmaxdihed) {
                              // There are bad dihedral angles in this tet.
                              nextflipqueue->newindex((void **) &parybface); 
                              parybface->tt.tet = parytet->tet;
                              parybface->tt.ver = 11;
                              parybface->forg = ppt[0];
                              parybface->fdest = ppt[1];
                              parybface->fapex = ppt[2];
                              parybface->foppo = ppt[3];
                              parybface->key = maxdd;
                              for (n = 0; n < 6; n++) {
                                parybface->cent[n] = ncosdd[n];
                              }
                            }
                          } // if (ppt[3] != dummypoint) { 
    		      //}
                        }
                      } // j
                    } // if (fc.cosdihed_out < cosmaxdihed)
                    cavetetlist->restart();
                    remcount++;
                  }
                }
              } // i          
              if (!remflag) {
                // An unremoved bad tet. Queue it again. 
                unflipqueue->newindex((void **) &parybface);
                *parybface = *bface;
              }
            } // if (gettetrahedron(...))
          } // k
    
          flipqueue->restart();
    
          // Swap the two flip queues.
          swapqueue = flipqueue;
          flipqueue = nextflipqueue;
          nextflipqueue = swapqueue;
        } // while (flipqueues->objects > 0)
    
        if (b->verbose > 1) {
          printf("    Removed %ld bad tets.\n", remcount);
        }
        totalremcount += remcount;
    
        if (unflipqueue->objects > 0l) {
          // 'b->optmaxfliplevel' is set by -OOO, default is 2.
          if (autofliplinklevel >= b->optmaxfliplevel) {
            // For efficiency reason, we do not search too far.
            break;
          }
          autofliplinklevel+=b->fliplinklevelinc;
        }
    
        // Swap the two flip queues.
        swapqueue = flipqueue;
        flipqueue = unflipqueue;
        unflipqueue = swapqueue;
      } // while (flipqueues->objects > 0)
    
      b->flipstarsize = bakmaxflipstarsize;
    
      delete flipqueue;
      delete nextflipqueue;
    
      return totalremcount;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // smoothpoint()    Moving a vertex to improve the mesh quality.             //
    //                                                                           //
    // 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point.  //
    // It may be not a vertex of the mesh.                                       //
    //                                                                           //
    // This routine tries to move 'p' inside its star until a selected objective //
    // function over all tetrahedra in the star is improved. The function may be //
    // the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
    // simply the volume of the tetrahedra.                                      //
    //                                                                           //
    // 'linkfacelist' contains the list of link faces of 'p'.  Since a link face //
    // has two orientations, ccw or cw, with respect to 'p'.  'ccw' indicates    //
    // the orientation is ccw (1) or not (0).                                    //
    //                                                                           //
    // 'of' is a structure contains the parameters of the objective function. It //
    // is needed by the evaluation of the function value.                        //
    //                                                                           //
    // The return value indicates weather the point is smoothed or not.          //
    //                                                                           //
    // ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
    // no face has 'dummypoint' as its vertex.                                   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
                                optparameters *opm)
    {
      triface *parytet, *parytet1, swaptet;
      point pa, pb, pc;
      REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
      REAL oldval, minval = 0.0, val;
      REAL maxcosd; // oldang, newang;
      REAL ori, diff;
      int numdirs, iter;
      int i, j, k;
    
      if (b->verbose > 2) {
        printf("      Smooth a point: %ld faces.\n", linkfacelist->objects);
        if (opm->min_max_dihedangle) {
          printf("      Init value = %g (degree).\n", 
                 acos(opm->initval - 1.0) / PI * 180.0);
        } else {
          printf("      Init value = %g.\n", opm->initval);
        }
      }
    
      // Decide the number of moving directions.
      numdirs = (int) linkfacelist->objects;
      if (numdirs > opm->numofsearchdirs) {
        numdirs = opm->numofsearchdirs; // Maximum search directions.
      }
    
      // Set the initial value.
      if (!opm->max_min_volume) {
        assert(opm->initval >= 0.0);
      }
      opm->imprval = opm->initval;
      iter = 0;
    
      for (i = 0; i < 3; i++) {
        bestpt[i] = startpt[i] = smtpt[i];
      }
    
      // Iterate until the obj function is not improved.
      while (1) {
    
        // Find the best next location.
        oldval = opm->imprval;
    
        for (i = 0; i < numdirs; i++) {
          // Randomly pick a link face (0 <= k <= objects - i - 1).
          k = (int) randomnation(linkfacelist->objects - i);
          parytet = (triface *) fastlookup(linkfacelist, k);
          // Calculate a new position from 'p' to the center of this face.
          pa = org(*parytet);
          pb = dest(*parytet);
          pc = apex(*parytet);
          for (j = 0; j < 3; j++) {
            fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
          }
          for (j = 0; j < 3; j++) {
            nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]); 
          }
          // Calculate the largest minimum function value for the new location.
          for (j = 0; j < linkfacelist->objects; j++) {
            parytet = (triface *) fastlookup(linkfacelist, j);
            if (ccw) {
              pa = org(*parytet);
              pb = dest(*parytet);
            } else {
              pb = org(*parytet);
              pa = dest(*parytet);
            }
            pc = apex(*parytet);
            ori = orient3d(pa, pb, pc, nextpt);
            if (ori < 0.0) {
              // Calcuate the objective function value. 
              if (opm->max_min_volume) {
                val = -ori;
              } else if (opm->max_min_aspectratio) {
                val = tetaspectratio(pa, pb, pc, nextpt);
              } else if (opm->min_max_dihedangle) {
                tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
                if (maxcosd < -1) maxcosd = -1.0; // Rounding.
                val = maxcosd + 1.0; // Make it be positive. 
              } else {
                // Unknown objective function.
                val = 0.0;
              }  
            } else { // ori >= 0.0;
              // An invalid new tet. 
              if (opm->max_min_volume) {
                val = -ori;    
              } else {
                // Discard this point.
                break; // j
              }
            } // if (ori >= 0.0)
            // Stop looping when the object value is not improved.
            if (val <= opm->imprval) {
              break; // j
            } else {
              // Remember the smallest improved value.
              if (j == 0) {
                minval = val;
              } else {
                minval = (val < minval) ? val : minval;
              }
            }
          } // j
          if (j == linkfacelist->objects) {
            // The function value has been improved.
            assert(minval > opm->imprval);          
            opm->imprval = minval;
            // Save the new location of the point.
            for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
          }
          // Swap k-th and (object-i-1)-th entries.
          j = linkfacelist->objects - i - 1;
          parytet  = (triface *) fastlookup(linkfacelist, k);
          parytet1 = (triface *) fastlookup(linkfacelist, j);
          swaptet = *parytet1;
          *parytet1 = *parytet;
          *parytet = swaptet;
        } // i
    
        diff = opm->imprval - oldval;
        if (diff > 0.0) {
          // Is the function value improved effectively?
          if (opm->max_min_volume) {
            //if ((diff / oldval) < b->epsilon) diff = 0.0;  
          } else if (opm->max_min_aspectratio) {
            if ((diff / oldval) < 1e-3) diff = 0.0;
          } else if (opm->min_max_dihedangle) {
            //oldang = acos(oldval - 1.0);
            //newang = acos(opm->imprval - 1.0);
            //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
          } else {
            // Unknown objective function.
            assert(0); // Not possible.
          }
        }
    
        if (diff > 0.0) {
          // Yes, move p to the new location and continue.
          for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
          iter++;
          if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
            // Maximum smoothing iterations reached.
            break;
          }
        } else {
          break;
        }
    
      } // while (1)
    
      if (iter > 0) {
        // The point has been smooothed.
        opm->smthiter = iter; // Remember the number of iterations.    
        if (b->verbose > 2) {
          printf("      Smoothed: %d iterations.\n", iter);
          if (opm->min_max_dihedangle) {
            printf("      Fina value = %g (degree).\n", 
                   acos(opm->imprval - 1.0) / PI * 180.0);
          } else {
            printf("      Fina value = %g.\n", opm->imprval);
          }
        }
        // The point has been smoothed. Update it to its new position.
        for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
    
        if (opm->flipflag) {
          // Push all affected faces into 'flipstack'.
          triface starttet, neightet;
          for (i = 0; i < linkfacelist->objects; i++) {
            parytet = (triface *) fastlookup(linkfacelist, i);
            starttet = *parytet;
            for (starttet.ver = 0; starttet.ver < 4; starttet.ver++) {
              fsym(starttet, neightet);
              if (!infected(neightet)) {
                flippush(flipstack, &starttet);
              }
            }
            infect(*parytet);
          }
          for (i = 0; i < linkfacelist->objects; i++) {
            parytet = (triface *) fastlookup(linkfacelist, i);
            uninfect(*parytet);
          }
        } else if (opm->checkencflag) {
          // Push all affected tets into pool.
          badface *bface;
          for (i = 0; i < linkfacelist->objects; i++) {
            parytet = (triface *) fastlookup(linkfacelist, i);
            if (!marktest2ed(*parytet)) {
              marktest2(*parytet); // Only queue it once.
              bface = (badface *) badtetrahedrons->alloc();
              bface->tt = *parytet;
              bface->forg = org(bface->tt);
            }
          }
        }
      } else {
        if (b->verbose > 2) {
          printf("      Not smoothed.\n");
        }
      }
    
      return iter;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // improvequalitysmoothing()    Improve mesh quality by smoothing.           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
    {
      arraypool *flipqueue, *swapqueue;
      badface *bface, *parybface;
      point *ppt;
      long totalsmtcount, smtcount;
      int smtflag;
      int iter, i, k;
    
      //assert(unflipqueue->objects > 0l);
      flipqueue = new arraypool(sizeof(badface), 10);
    
      totalsmtcount = 0l;
    
      // Swap the two flip queues.
      swapqueue = flipqueue;
      flipqueue = unflipqueue;
      unflipqueue = swapqueue;
    
      iter = 0;
    
      while (flipqueue->objects > 0l) {
    
        smtcount = 0l;
    
        //while (flipqueue->objects > 0l) {
        if (b->verbose > 1) {
          printf("    Improving mesh qualiy by smoothing [%d]#:  %ld.\n",
                 iter, flipqueue->objects);
        }
    
        for (k = 0; k < flipqueue->objects; k++) {      
          bface  = (badface *) fastlookup(flipqueue, k);
          if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
                             bface->foppo, &bface->tt)) {
            if (!marktested(bface->tt)) {
              // Here we simply re-compute the quality. Since other smoothing
              //   operation may have moved the vertices of this tet.
              ppt = (point *) & (bface->tt.tet[4]);
              tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
                             &bface->key, NULL);
              if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
                // It is a sliver. Try to smooth its vertices.
                smtflag = 0;
                //if (opm->min_max_dihedangle) {
                opm->initval = bface->key + 1.0;          
                //opm->checkencflag = 4; // Queue affected tets.            
                //}
                for (i = 0; (i < 4) && !smtflag; i++) {
                  if (pointtype(ppt[i]) == FREEVOLVERTEX) {
                    getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
                    opm->searchstep = 0.001; // Search step size
                    smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
                    if (smtflag) {
                      while (opm->smthiter == opm->maxiter) {
                        opm->searchstep *= 10.0; // Increase the step size.
                        opm->initval = opm->imprval;
                        opm->smthiter = 0; // reset
                        smoothpoint(ppt[i], cavetetlist, 1, opm);
                      }
                      smtcount++;
                    }
                    cavetetlist->restart();
                  }
                } // i
                if (smtflag) {
                  // This tet is modifed. 
                  smtcount++;
                  if ((opm->imprval - 1.0) < cossmtdihed) {
                    // Queue new slivers.
                    badtetrahedrons->traversalinit();
                    bface = badfacetraverse(badtetrahedrons);
                    while (bface != NULL) {
                      assert(!isdeadtet(bface->tt));
                      assert(marktest2ed(bface->tt));
                      unmarktest2(bface->tt);
                      if (!marktested(bface->tt)) {
                        ppt = (point *) & (bface->tt.tet[4]);
                        tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
                                       &(bface->key), NULL);
                        if (bface->key < cossmtdihed) {
                          // A new sliver. Queue it.
                          marktest(bface->tt); // It is in unflipqueue.
                          bface->forg = ppt[0]; 
                          bface->fdest = ppt[1];
                          bface->fapex = ppt[2];
                          bface->foppo = ppt[3];
                          bface->tt.ver = 11;                    
                          unflipqueue->newindex((void **) &parybface);
                          *parybface = *bface;
                        }
                      }
                      bface = badfacetraverse(badtetrahedrons);
                    }
                  } else {
                    // No new slivers. Only unmark the queued tets.
                    badtetrahedrons->traversalinit();
                    bface = badfacetraverse(badtetrahedrons);
                    while (bface != NULL) {
                      assert(!isdeadtet(bface->tt));
                      assert(marktest2ed(bface->tt));
                      unmarktest2(bface->tt);
                      bface = badfacetraverse(badtetrahedrons);
                    }
                  }
                  badtetrahedrons->restart();
                } else {
                  // Didn't smooth. Queue it again.
                  // Adjust the vertices for flipping.
                  marktest(bface->tt); // It is in unflipqueue.
                  bface->forg = ppt[0]; 
                  bface->fdest = ppt[1];
                  bface->fapex = ppt[2];
                  bface->foppo = ppt[3];
                  bface->tt.ver = 11;
                  unflipqueue->newindex((void **) &parybface);
                  *parybface = *bface;
                }
    	  } // if (maxdd < cosslidihed)
            } // if (!marktested(...))
          } // gettetrahedron(...)
        } // k
    
        flipqueue->restart();
    
        // } // while
    
        // Unmark the tets in unflipqueue.
        for (i = 0; i < unflipqueue->objects; i++) {
          bface  = (badface *) fastlookup(unflipqueue, i);
          assert(!isdeadtet(bface->tt));
          assert(marktested(bface->tt));
          unmarktest(bface->tt);
        }
    
        if (b->verbose > 1) {
          printf("    Smooth %ld points.\n", smtcount);
        }
        totalsmtcount += smtcount;
    
        if (smtcount == 0l) {
          // No point has been smoothed. 
          break;
        } else {
          iter++;
          if (iter == 2) { //if (iter >= b->optpasses) {
            break;
          }
        }
    
        // Swap the two flip queues.
        swapqueue = flipqueue;
        flipqueue = unflipqueue;
        unflipqueue = swapqueue;
      } // while
    
      delete flipqueue;
    
      return totalsmtcount;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // splitsliver()    Split a sliver.                                          //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
    {
      triface *abtets;
      triface searchtet, spintet, *parytet;
      face checkseg;
      point pa, pb, steinerpt;
      optparameters opm;
      insertvertexflags ivf;
      REAL smtpt[3], midpt[3];
      int success;
      int loc;
      int n, i;
    
      // 'slitet' is [c,d,a,b], where [c,d] has a big hihedral angle. 
      // Go to the opposite edge [a,b].
      eprev(*slitet, searchtet);
      esymself(searchtet);
      enextself(searchtet); // [a,b,c,d].
    
      // Do not split a segment.
      tsspivot1(searchtet, checkseg);
      if (checkseg.sh != NULL) {
        return 0; 
      }
    
      // Count the number of tets shared at [a,b].
      spintet = searchtet;
      n = 0; 
      while (1) {
        n++;
        fnextself(spintet);
        if (spintet.tet == searchtet.tet) break;
      }
      assert(n >= 3);
    
      // Get all tets at edge [a,b].
      abtets = new triface[n];
      spintet = searchtet;
      for (i = 0; i < n; i++) {
        abtets[i] = spintet;
        fnextself(spintet);
      }
    
      // Initialize the list of 2n boundary faces.
      for (i = 0; i < n; i++) {    
        eprev(abtets[i], searchtet);
        esymself(searchtet); // [a,p_i,p_i+1].
        cavetetlist->newindex((void **) &parytet);
        *parytet = searchtet;
        enext(abtets[i], searchtet);
        esymself(searchtet); // [p_i,b,p_i+1].
        cavetetlist->newindex((void **) &parytet);
        *parytet = searchtet;
      }
    
      // Init the Steiner point at the midpoint of edge [a,b].
      pa = org(abtets[0]);
      pb = dest(abtets[0]);
      for (i = 0; i < 3; i++) {
        smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
      }
    
      // Point smooth options.
      opm.min_max_dihedangle = 1;
      opm.initval = cosd + 1.0; // Initial volume is zero.
      opm.numofsearchdirs = 20;
      opm.searchstep = 0.001;  
      opm.maxiter = 100; // Limit the maximum iterations.
    
      success = smoothpoint(smtpt, cavetetlist, 1, &opm);
    
      if (success) {
        while (opm.smthiter == opm.maxiter) {
          // It was relocated and the prescribed maximum iteration reached. 
          // Try to increase the search stepsize.
          opm.searchstep *= 10.0;
          //opm.maxiter = 100; // Limit the maximum iterations.
          opm.initval = opm.imprval;
          opm.smthiter = 0; // Init.
          smoothpoint(smtpt, cavetetlist, 1, &opm);  
        }
      } // if (success)
    
      cavetetlist->restart();
    
      if (!success) {
        if (b->verbose > 2) {
          printf("      Unable to relocate the initial point.\n");
        }
        delete [] abtets;
        return 0;
      }
    
    
      if (steinerleft == 0) {
        // The desired number of Steiner points is reached.
        return 0;
      }
    
      // Insert the Steiner point.
      makepoint(&steinerpt, FREEVOLVERTEX);
      for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
    
      // Insert the created Steiner point.
      for (i = 0; i < n; i++) {
        infect(abtets[i]);
        caveoldtetlist->newindex((void **) &parytet);
        *parytet = abtets[i];
      }
      searchtet = abtets[0]; // No need point location.
      ivf.iloc = (int) INSTAR;
      ivf.bowywat = 0; // Do not use Bowyer-Watson algorithm.
      ivf.lawson = 0; //  Do not flip.
      ivf.rejflag = 0;
      ivf.chkencflag = chkencflag;
      ivf.sloc = 0;
      ivf.sbowywat = 0;
      ivf.splitbdflag = 0;
      ivf.validflag = 0;
      ivf.respectbdflag = 0;
      ivf.assignmeshsize = 0; 
    
      loc = insertvertex(steinerpt, &searchtet, NULL, NULL, &ivf);
    
      if (loc == (int) INSTAR) {
        // The vertex has been inserted.
        st_volref_count++; //st_inpoly_count++;
        if (steinerleft > 0) steinerleft--;
        return 1;
      } else {
        // The Steiner point is too close to an existing vertex. Reject it.
        pointdealloc(steinerpt);
        return 0;
      }
    
      delete [] abtets;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // removeslivers()    Remove slivers by adding Steiner points.               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    long tetgenmesh::removeslivers(int chkencflag)
    {
      arraypool *flipqueue, *swapqueue;
      badface *bface, *parybface;
      point *ppt;
      REAL *cosdd;
      long totalsptcount, sptcount;
      int iter, j, k;
    
      //assert(unflipqueue->objects > 0l);
      flipqueue = new arraypool(sizeof(badface), 10);
    
      totalsptcount = 0l;
    
      // Swap the two flip queues.
      swapqueue = flipqueue;
      flipqueue = unflipqueue;
      unflipqueue = swapqueue;
    
      iter = 0;
    
      while (flipqueue->objects > 0l) {
    
        sptcount = 0l;
    
        if (b->verbose > 1) {
          printf("    Splitting bad quality tets [%d]#:  %ld.\n",
                 iter, flipqueue->objects);
        }
    
        for (k = 0; k < flipqueue->objects; k++) {      
          bface  = (badface *) fastlookup(flipqueue, k);
          if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
                             bface->foppo, &bface->tt)) {
            //if (!marktested(bface->tt)) {
              // Here we simply re-compute the quality. Since other smoothing
              //   operation may have moved the vertices of this tet.
              ppt = (point *) & (bface->tt.tet[4]);
              tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
                             &bface->key, NULL);
              if (bface->key < cosslidihed) { 
                // It is a sliver. Try to split it.
                cosdd = bface->cent;
                for (j = 0; j < 6; j++) {
                  if (cosdd[j] < cosslidihed) { 
                    // Found a large dihedral angle.
                    bface->tt.ver = edge2ver[j]; // Go to the edge.
                    if (b->verbose > 2) {
                      printf("      Found a bad tet [%d,%d,%d,%d] (%g).\n", 
                             pointmark(org(bface->tt)), pointmark(dest(bface->tt)),
                             pointmark(apex(bface->tt)), pointmark(oppo(bface->tt)),
                             acos(cosdd[j]) / PI * 180.0);
                    }
                    if (splitsliver(&(bface->tt), cosdd[j], chkencflag)) {
                      sptcount++;
                      break;
                    }
                  }
                } // j
                if (j < 6) {
                  // A sliver is split. Queue new slivers.
                  badtetrahedrons->traversalinit();
                  bface = badfacetraverse(badtetrahedrons);
                  while (bface != NULL) {
                    assert(!isdeadtet(bface->tt));
                    assert(marktest2ed(bface->tt));
                    unmarktest2(bface->tt);
                    ppt = (point *) & (bface->tt.tet[4]);
                    tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
                                   &(bface->key), NULL);
                    if (bface->key < cosslidihed) {
                      // A new sliver. Queue it.
                      //marktest(bface->tt); // It is in unflipqueue.
                      bface->forg = ppt[0]; 
                      bface->fdest = ppt[1];
                      bface->fapex = ppt[2];
                      bface->foppo = ppt[3];
                      bface->tt.ver = 11;                    
                      unflipqueue->newindex((void **) &parybface);
                      *parybface = *bface;
                    }
                    bface = badfacetraverse(badtetrahedrons);
                  }
                  badtetrahedrons->restart();
                } else {
                  // Didn't split. Queue it again.
                  // Adjust the vertices for flipping.
                  //marktest(bface->tt); // It is in unflipqueue.
                  bface->forg = ppt[0]; 
                  bface->fdest = ppt[1];
                  bface->fapex = ppt[2];
                  bface->foppo = ppt[3];
                  bface->tt.ver = 11;
                  unflipqueue->newindex((void **) &parybface);
                  *parybface = *bface;
                } // if (j == 6)
              } // if (bface->key < cosslidihed)
    	// } // if (!marktested(bface->tt))
          } // if (gettetrahedron(...))
        } // k
    
        flipqueue->restart();
    
        if (b->verbose > 1) {
          printf("    Split %ld tets.\n", sptcount);
        }
        totalsptcount += sptcount;
    
        if (sptcount == 0l) {
          // No point has been smoothed. 
          break;
        } else {
          iter++;
          if (iter == 2) { //if (iter >= b->optpasses) {
            break;
          }
        }
    
        // Swap the two flip queues.
        swapqueue = flipqueue;
        flipqueue = unflipqueue;
        unflipqueue = swapqueue;
      } // while
    
      delete flipqueue;
    
      return totalsptcount;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // optimizemesh()    Optimize mesh for specified objective functions.        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::optimizemesh(int optflag)
    {
      badface *parybface;
      triface checktet;
      point *ppt;
      optparameters opm;
      REAL ncosdd[6], maxdd;
      long totalremcount, remcount;
      long totalsmtcount, smtcount;
      long totalsptcount, sptcount;
      int chkencflag;
      int iter;
      int n;
    
      if (!b->quiet) {
        printf("Optimizing mesh...\n");
      }
    
      if (b->verbose > 1) {
        printf("    min_max_dihedral = %g.\n", b->optmaxdihedral);
        printf("    max_flipstarsize = %d.\n", b->optmaxflipstarsize);
        printf("    max_fliplinklevel = %d.\n", b->optmaxfliplevel);
        printf("    number of passes = %d.\n", b->optpasses);
      }
      totalsmtcount = totalsptcount = totalremcount = 0l;
    
      if (b->verbose > 1) {
        printf("    Removing large angles (> %g degree).\n", b->optmaxdihedral);
      }
    
      cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
      cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
      cosslidihed = cos(b->optminslidihed / 180.0 * PI);
    
      // Put all bad tetrahedra into array.
      tetrahedrons->traversalinit();
      checktet.tet = tetrahedrontraverse();
      while (checktet.tet != NULL) {
        ppt = (point *) & (checktet.tet[4]);
        tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
        if (maxdd < cosmaxdihed) {
          // There are bad dihedral angles in this tet.
          unflipqueue->newindex((void **) &parybface); 
          parybface->tt.tet = checktet.tet;
          parybface->tt.ver = 11;
          parybface->forg = ppt[0];
          parybface->fdest = ppt[1];
          parybface->fapex = ppt[2];
          parybface->foppo = ppt[3];
          parybface->key = maxdd;
          for (n = 0; n < 6; n++) {
            parybface->cent[n] = ncosdd[n];
          }
        }
        checktet.tet = tetrahedrontraverse();
      }
    
      totalremcount = improvequalitybyflips();
    
      if ((unflipqueue->objects > 0l) && 
          ((b->optlevel & 2) || (b->optlevel & 4))) { // -O2 | -O4
    
        badtetrahedrons = new memorypool(sizeof(badface), b->tetrahedraperblock,
                                         memorypool::POINTER, 0);
    
        // Smoothing options.
        opm.min_max_dihedangle = 1;
        opm.numofsearchdirs = 10;
        // opm.searchstep = 0.001;  
        opm.maxiter = 30; // Limit the maximum iterations.
        opm.checkencflag = 4; // Queue affected tets after smoothing.
        chkencflag = 4; // Queue affected tets after splitting a sliver.
        iter = 0;
    
        while (iter < b->optpasses) {
          smtcount = sptcount = remcount = 0l;
          if (b->optlevel & 2) {
            smtcount += improvequalitybysmoothing(&opm);
            totalsmtcount += smtcount;
            if (smtcount > 0l) {
              remcount = improvequalitybyflips();
              totalremcount += remcount;
            }
          }
          if (unflipqueue->objects > 0l) {
            if (b->optlevel & 4) {
              sptcount += removeslivers(chkencflag);
              totalsptcount += sptcount;
              if (sptcount > 0l) {
                remcount = improvequalitybyflips();
                totalremcount += remcount;
              }
            }
          }
          if (unflipqueue->objects > 0l) {
            if (remcount > 0l) {
              iter++;
            } else {
              break;
            }
          } else {
            break;
          }
        } // while (iter)
    
        delete badtetrahedrons;
    
      } // // -O2 | -O4
    
      if (unflipqueue->objects > 0l) {
        if (b->verbose > 1) {
          printf("    %ld bad tets remained.\n", unflipqueue->objects);
        }
        unflipqueue->restart();
      }
    
      if (b->verbose) {
        if (totalremcount > 0l) {
          printf("  Removed %ld bad tets.\n", totalremcount);
        }
        if (totalsmtcount > 0l) {
          printf("  Smoothed %ld points.\n", totalsmtcount);
        }
        if (totalsptcount > 0l) {
          printf("  Split %ld bad tets.\n", totalsptcount);
        }
      }
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// optimize_cxx /////////////////////////////////////////////////////////////
    
    //// meshstat_cxx /////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkmesh()    Test the mesh for topological consistency.                 //
    //                                                                           //
    // If 'topoflag' is set, only check the topological connection of the mesh,  //
    // i.e., do not report degenerated or inverted elements.                     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkmesh(int topoflag)
    {
      triface tetloop, neightet, symtet;
      point pa, pb, pc, pd;
      REAL ori;
      int horrors, i;
    
      if (!b->quiet) {
        printf("  Checking consistency of mesh...\n");
      }
    
      horrors = 0;
      tetloop.ver = 0;
      // Run through the list of tetrahedra, checking each one.
      tetrahedrons->traversalinit();
      tetloop.tet = alltetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        // Check all four faces of the tetrahedron.
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          pa = org(tetloop);
          pb = dest(tetloop);
          pc = apex(tetloop);
          pd = oppo(tetloop);
          if (tetloop.ver == 0) {  // Only test for inversion once.
            if (!ishulltet(tetloop)) {  // Only do test if it is not a hull tet.
              if (!topoflag) {
                ori = orient3d(pa, pb, pc, pd);
                if (ori >= 0.0) {
                  printf("  !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
                  printf("  (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
                         pointmark(pb), pointmark(pc), pointmark(pd), ori);
                  horrors++;
                }
              }
            }
            if (infected(tetloop)) { 
              // This may be a bug. Report it.
              printf("  !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
                     pointmark(pb), pointmark(pc), pointmark(pd));
              horrors++;
            }
            if (marktested(tetloop)) {
              // This may be a bug. Report it.
              printf("  !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
                     pointmark(pb), pointmark(pc), pointmark(pd));
              horrors++;
            }
          }
          if (tetloop.tet[tetloop.ver] == NULL) {
            printf("  !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
                   pointmark(pb), pointmark(pc));
            horrors++;
          } else {
            // Find the neighboring tetrahedron on this face.
            fsym(tetloop, neightet);
            // Check that the tetrahedron's neighbor knows it's a neighbor.
            fsym(neightet, symtet);
            if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
              printf("  !! !! Asymmetric tetra-tetra bond:\n");
              if (tetloop.tet == symtet.tet) {
                printf("   (Right tetrahedron, wrong orientation)\n");
              }
              printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
                     pointmark(pb), pointmark(pc), pointmark(pd));
              printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
                     pointmark(dest(neightet)), pointmark(apex(neightet)),
                     pointmark(oppo(neightet)));
              horrors++;
            }
            // Check if they have the same edge (the bond() operation).
            if ((org(neightet) != pb) || (dest(neightet) != pa)) {
              printf("  !! !! Wrong edge-edge bond:\n");
              printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
                     pointmark(pb), pointmark(pc), pointmark(pd));
              printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
                     pointmark(dest(neightet)), pointmark(apex(neightet)),
                     pointmark(oppo(neightet)));
              horrors++;
            }
            // Check if they have the same apex.
            if (apex(neightet) != pc) {
              printf("  !! !! Wrong face-face bond:\n");
              printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
                     pointmark(pb), pointmark(pc), pointmark(pd));
              printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
                     pointmark(dest(neightet)), pointmark(apex(neightet)),
                     pointmark(oppo(neightet)));
              horrors++;
            }
            // Check if they have the same opposite.
            if (oppo(neightet) == pd) {
              printf("  !! !! Two identical tetra:\n");
              printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
                     pointmark(pb), pointmark(pc), pointmark(pd));
              printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
                     pointmark(dest(neightet)), pointmark(apex(neightet)),
                     pointmark(oppo(neightet)));
              horrors++;
            }
          }
          if (facemarked(tetloop)) {
            // This may be a bug. Report it.
            printf("  !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
                   pointmark(pb), pointmark(pc), pointmark(pd));
          }
        }
        // Check the six edges of this tet.
        for (i = 0; i < 6; i++) {
          tetloop.ver = edge2ver[i];
          if (edgemarked(tetloop)) {
            // This may be a bug. Report it.
            printf("  !! tetedge (%d, %d) %d, %d is marked.\n", 
                   pointmark(org(tetloop)), pointmark(dest(tetloop)), 
                   pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
          }
        }
        tetloop.tet = alltetrahedrontraverse();
      }
      if (horrors == 0) {
        if (!b->quiet) {
          printf("  In my studied opinion, the mesh appears to be consistent.\n");
        }
      } else {
        printf("  !! !! !! !! %d %s witnessed.\n", horrors, 
               horrors > 1 ? "abnormity" : "abnormities");
      }
    
      return horrors;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkshells()       Test the boundary mesh for topological consistency.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkshells(/*int sub2tet*/)
    {
      triface neightet, symtet;
      face shloop, spinsh, nextsh;
      face checkseg;
      point pa, pb; //, *ppt;
      int bakcount;
      int horrors, i;
    
      if (!b->quiet) {
        printf("  Checking consistency of the mesh boundary...\n");
      }
      horrors = 0;
    
      void **bakpathblock = subfaces->pathblock;
      void *bakpathitem = subfaces->pathitem;
      int bakpathitemsleft = subfaces->pathitemsleft;
      int bakalignbytes = subfaces->alignbytes;
    
      subfaces->traversalinit();
      shloop.sh = shellfacetraverse(subfaces);
      while (shloop.sh != NULL) {
        shloop.shver = 0;
        for (i = 0; i < 3; i++) {
          // Check the face ring at this edge.
          pa = sorg(shloop);
          pb = sdest(shloop);
          spinsh = shloop;
          spivot(spinsh, nextsh);
          bakcount = horrors;
          while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
            if (nextsh.sh[3] == NULL) {
              printf("  !! !! Wrong subface-subface connection (Dead subface).\n");
              printf("    First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh,
                     pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                     pointmark(sapex(spinsh)));
              printf("    Second: x%lx (DEAD)\n", (unsigned long) nextsh.sh);
              horrors++;
              break;
            }
            // check if they have the same edge.
            if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) ||
                  ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) {
               printf("  !! !! Wrong subface-subface connection.\n");
               printf("    First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh,
                      pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                      pointmark(sapex(spinsh)));
               printf("    Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh,
                      pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), 
                      pointmark(sapex(nextsh)));
               horrors++;
               break;
            }
            // Check they should not have the same apex.
            if (sapex(nextsh) == sapex(spinsh)) {
               printf("  !! !! Existing two duplicated subfaces.\n");
               printf("    First: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh,
                      pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                      pointmark(sapex(spinsh)));
               printf("    Scond: x%lx (%d, %d, %d).\n", (unsigned long) nextsh.sh,
                      pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), 
                      pointmark(sapex(nextsh)));
               horrors++;
               break;
            }
            spinsh = nextsh;
            spivot(spinsh, nextsh);
          }
          // Check subface-subseg bond.
          sspivot(shloop, checkseg);
          if (checkseg.sh != NULL) {
            if (checkseg.sh[3] == NULL) {
              printf("  !! !! Wrong subface-subseg connection (Dead subseg).\n");
              printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
                     pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                     pointmark(sapex(shloop)));
              printf("    Sub: x%lx (Dead)\n", (unsigned long) checkseg.sh);
              horrors++;
            } else {
              if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) ||
                    ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) {
                printf("  !! !! Wrong subface-subseg connection.\n");
                printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
                       pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                       pointmark(sapex(shloop)));
                printf("    Seg: x%lx (%d, %d).\n", (unsigned long) checkseg.sh,
                       pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
                horrors++;
              }
            }
          }
          if (horrors > bakcount) break; // An error detected. 
          senextself(shloop);
        }
        // Check tet-subface connection.
        stpivot(shloop, neightet);
        if (neightet.tet != NULL) {
          if (neightet.tet[4] == NULL) {
            printf("  !! !! Wrong sub-to-tet connection (Dead tet)\n");
            printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
                   pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                   pointmark(sapex(shloop)));
            printf("    Tet: x%lx (DEAD)\n", (unsigned long) neightet.tet);
            horrors++;
          } else {
            if (!((sorg(shloop) == org(neightet)) && 
                  (sdest(shloop) == dest(neightet)))) {
              printf("  !! !! Wrong sub-to-tet connection\n");
              printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) shloop.sh,
                     pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                     pointmark(sapex(shloop)));
              printf("    Tet: x%lx (%d, %d, %d, %d).\n",
                     (unsigned long) neightet.tet, pointmark(org(neightet)), 
                     pointmark(dest(neightet)), pointmark(apex(neightet)),
                     pointmark(oppo(neightet)));
              horrors++;
            }
            tspivot(neightet, spinsh);
            if (!((sorg(spinsh) == org(neightet)) && 
                  (sdest(spinsh) == dest(neightet)))) {
              printf("  !! !! Wrong tet-sub connection.\n");
              printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh,
                     pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                     pointmark(sapex(spinsh)));
              printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
                     (unsigned long) neightet.tet, pointmark(org(neightet)), 
                     pointmark(dest(neightet)), pointmark(apex(neightet)), 
                     pointmark(oppo(neightet)));
              horrors++;
            }
            fsym(neightet, symtet);
            tspivot(symtet, spinsh);
            if (spinsh.sh != NULL) {
              if (!((sorg(spinsh) == org(symtet)) && 
                    (sdest(spinsh) == dest(symtet)))) {
                printf("  !! !! Wrong tet-sub connection.\n");
                printf("    Sub: x%lx (%d, %d, %d).\n", (unsigned long) spinsh.sh,
                       pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                       pointmark(sapex(spinsh)));
                printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
                       (unsigned long) symtet.tet, pointmark(org(symtet)), 
                       pointmark(dest(symtet)), pointmark(apex(symtet)), 
                       pointmark(oppo(symtet)));
                horrors++;
              }
            } else {
              printf("  Warning: Broken tet-sub-tet connection.\n");
            }
          }
        }
        if (sinfected(shloop)) {
          // This may be a bug. report it.
          printf("  !! A infected subface: (%d, %d, %d).\n", 
                 pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                 pointmark(sapex(shloop)));
        }
        if (smarktested(shloop)) {
          // This may be a bug. report it.
          printf("  !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)), 
                 pointmark(sdest(shloop)), pointmark(sapex(shloop)));
        }
        shloop.sh = shellfacetraverse(subfaces);
      }
    
      if (horrors == 0) {
        if (!b->quiet) {
          printf("  Mesh boundaries connected correctly.\n");
        }
      } else {
        printf("  !! !! !! !! %d boundary connection viewed with horror.\n",
               horrors);
      }
    
      subfaces->pathblock = bakpathblock;
      subfaces->pathitem = bakpathitem;
      subfaces->pathitemsleft = bakpathitemsleft;
      subfaces->alignbytes = bakalignbytes;
    
      return horrors;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checksegments()    Check the connections between tetrahedra and segments. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checksegments()
    {
      triface tetloop, neightet, spintet;
      shellface *segs;
      face neighsh, spinsh, checksh;
      face sseg, checkseg;
      point pa, pb;
      int miscount;
      int horrors, i;
    
      if (!b->quiet) {
        printf("  Checking tet->seg connections...\n");
      }
    
      horrors = 0;
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != NULL) {
        // Loop the six edges of the tet.
        if (tetloop.tet[8] != NULL) {
          segs = (shellface *) tetloop.tet[8];
          for (i = 0; i < 6; i++) {
            sdecode(segs[i], sseg);
            if (sseg.sh != NULL) {
              // Get the edge of the tet.
              tetloop.ver = edge2ver[i];
              // Check if they are the same edge.
              pa = (point) sseg.sh[3];
              pb = (point) sseg.sh[4];
              if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
                    ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
                printf("  !! Wrong tet-seg connection.\n");
                printf("    Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", 
                       (unsigned long) tetloop.tet, pointmark(org(tetloop)),
                       pointmark(dest(tetloop)), pointmark(apex(tetloop)),
                       pointmark(oppo(tetloop)), (unsigned long) sseg.sh,
                       pointmark(pa), pointmark(pb));
                horrors++;
              } else {
                // Loop all tets sharing at this edge.
                neightet = tetloop;
                do {
                  tsspivot1(neightet, checkseg);
                  if (checkseg.sh != sseg.sh) {
                    printf("  !! Wrong tet->seg connection.\n");
                    printf("    Tet: x%lx (%d, %d, %d, %d) - ", 
                           (unsigned long) neightet.tet, pointmark(org(neightet)),
                           pointmark(dest(neightet)), pointmark(apex(neightet)),
                           pointmark(oppo(neightet)));
                    if (checkseg.sh != NULL) {
                      printf("Seg x%lx (%d, %d).\n", (unsigned long) checkseg.sh,
                             pointmark(sorg(checkseg)),pointmark(sdest(checkseg))); 
                    } else {
                      printf("Seg: NULL.\n");
                    }
                    horrors++;
                  }
                  fnextself(neightet);
                } while (neightet.tet != tetloop.tet);
              }
              // Check the seg->tet pointer.
              sstpivot1(sseg, neightet);
              if (neightet.tet == NULL) {
                printf("  !! Wrong seg->tet connection (A NULL tet).\n");
                horrors++;
              } else {
                if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
                    ((org(neightet) == pb) && (dest(neightet) == pa)))) {
                  printf("  !! Wrong seg->tet connection (Wrong edge).\n");
                  printf("    Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", 
                         (unsigned long) neightet.tet, pointmark(org(neightet)),
                         pointmark(dest(neightet)), pointmark(apex(neightet)),
                         pointmark(oppo(neightet)), (unsigned long) sseg.sh,
                         pointmark(pa), pointmark(pb));
                  horrors++;
                }
              }
            }
          }
        }
        // Loop the six edge of this tet.
        neightet.tet = tetloop.tet;
        for (i = 0; i < 6; i++) {
          neightet.ver = edge2ver[i];
          if (edgemarked(neightet)) {
            // A possible bug. Report it.
            printf("  !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n",
                   pointmark(org(neightet)), pointmark(dest(neightet)),
                   pointmark(apex(neightet)), pointmark(oppo(neightet)),
                   (unsigned long) neightet.tet, neightet.ver);
            // Check if all tets at the edge are marked.
            spintet = neightet;
            while (1) {
              fnextself(spintet);
              if (!edgemarked(spintet)) {
                printf("  !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n",
                       pointmark(org(spintet)), pointmark(dest(spintet)),
                       pointmark(apex(spintet)), pointmark(oppo(spintet)),
                       (unsigned long) spintet.tet, spintet.ver);
                horrors++;
              }
              if (spintet.tet == neightet.tet) break;
            }
          }
        }
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (!b->quiet) {
        printf("  Checking seg->tet connections...\n");
      }
    
      miscount = 0; // Count the number of unrecovered segments.
      subsegs->traversalinit();
      sseg.shver = 0;
      sseg.sh = shellfacetraverse(subsegs);
      while (sseg.sh != NULL) {
        pa = sorg(sseg);
        pb = sdest(sseg);
        spivot(sseg, neighsh);
        if (neighsh.sh != NULL) {      
          spinsh = neighsh;
          while (1) {
            // Check seg-subface bond.
            if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
    	    ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
              // Keep the same rotate direction.
              //if (sorg(spinsh) != pa) {          
              //  sesymself(spinsh);
              //  printf("  !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
              //         pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
              //         pointmark(sapex(spinsh)), (unsigned long) spinsh.sh,
              //         spinsh.shver);
              //  horrors++;
              //}
              stpivot(spinsh, spintet);
              if (spintet.tet != NULL) {
                // Check if all tets at this segment.
                while (1) {
                  tsspivot1(spintet, checkseg);
                  if (checkseg.sh == NULL) {
                    printf("  !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n",
                           pointmark(org(spintet)), pointmark(dest(spintet)),
                           pointmark(apex(spintet)), pointmark(oppo(spintet)),
                           (unsigned long) spintet.tet, spintet.ver);
                    horrors++;
                  }
                  if (checkseg.sh != sseg.sh) {
                    printf("  !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
                           pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
                           pointmark(org(spintet)), pointmark(dest(spintet)),
                           pointmark(apex(spintet)), pointmark(oppo(spintet)));
                    horrors++;
                  }
                  fnextself(spintet);
                  // Stop at the next subface.
                  tspivot(spintet, checksh);
                  if (checksh.sh != NULL) break;
                } // while (1)
              }
            } else { 
              printf("  !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
                     pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
                     pointmark(sapex(spinsh)), (unsigned long) spinsh.sh,
                     spinsh.shver);
              horrors++;
              break;
            } // if pa, pb
            spivotself(spinsh);
            if (spinsh.sh == NULL) break; // A dangling segment.
            if (spinsh.sh == neighsh.sh) break;
          } // while (1)
        } // if (neighsh.sh != NULL)
        // Count the number of "un-recovered" segments.
        sstpivot1(sseg, neightet);
        if (neightet.tet == NULL) {
          miscount++;
        }
        sseg.sh = shellfacetraverse(subsegs);
      }
    
      if (!b->quiet) {
        printf("  Checking seg->seg connections...\n");
      }
    
      points->traversalinit();
      pa = pointtraverse();
      while (pa != NULL) {
        if (pointtype(pa) == FREESEGVERTEX) {
          // There should be two subsegments connected at 'pa'.
          // Get a subsegment containing 'pa'.
          sdecode(point2sh(pa), sseg);
          if ((sseg.sh == NULL) || sseg.sh[3] == NULL) {
            printf("  !! Dead point-to-seg pointer at point %d.\n",
                   pointmark(pa));
            horrors++;
          } else {
            sseg.shver = 0;
            if (sorg(sseg) != pa) {
              if (sdest(sseg) != pa) {
                printf("  !! Wrong point-to-seg pointer at point %d.\n",
                       pointmark(pa));
                horrors++;
              } else {
                // Find the next subsegment at 'pa'.
                senext(sseg, checkseg);
                if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
                  printf("  !! Dead seg-seg connection at point %d.\n",
                         pointmark(pa));
                  horrors++;
                } else {
                  spivotself(checkseg);
                  checkseg.shver = 0;
                  if (sorg(checkseg) != pa) {
                    printf("  !! Wrong seg-seg connection at point %d.\n",
                         pointmark(pa));
                    horrors++;
                  }
                }
              }
            } else {
              // Find the previous subsegment at 'pa'.
              senext2(sseg, checkseg);
              if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
                printf("  !! Dead seg-seg connection at point %d.\n",
                       pointmark(pa));
                horrors++;
              } else {
                spivotself(checkseg);
                checkseg.shver = 0;
                if (sdest(checkseg) != pa) {
                  printf("  !! Wrong seg-seg connection at point %d.\n",
                         pointmark(pa));
                  horrors++;
                }
              }
            }
          }
        }
        pa = pointtraverse();
      }
    
      if (horrors == 0) {
        printf("  Segments are connected properly.\n");
      } else {
        printf("  !! !! !! !! Found %d missing connections.\n", horrors);
      }
      if (miscount > 0) {
        printf("  !! !! Found %d missing segments.\n", miscount);
      }
    
      return horrors;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkdelaunay()    Ensure that the mesh is (constrained) Delaunay.        //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkdelaunay()
    {
      triface tetloop;
      triface symtet;
      face checksh;
      point pa, pb, pc, pd, pe;
      REAL sign;
      int ndcount; // Count the non-locally Delaunay faces.
      int horrors;
    
      if (!b->quiet) {
        printf("  Checking Delaunay property of the mesh...\n");
      }
    
      ndcount = 0;
      horrors = 0;
      tetloop.ver = 0;
      // Run through the list of triangles, checking each one.
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        // Check all four faces of the tetrahedron.
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, symtet);
          // Only do test if its adjoining tet is not a hull tet or its pointer
          //   is larger (to ensure that each pair isn't tested twice).
          if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
            pa = org(tetloop);
            pb = dest(tetloop);
            pc = apex(tetloop);
            pd = oppo(tetloop);
            pe = oppo(symtet);
            sign = insphere_s(pa, pb, pc, pd, pe);
            if (sign < 0.0) {
              ndcount++;
              if (checksubfaceflag) {
                tspivot(tetloop, checksh);
              }
              if (checksh.sh == NULL) {
                printf("  !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
                       pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
                       pointmark(pe));
                horrors++;
              }
            }
          }
        }
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (horrors == 0) {
        if (!b->quiet) {
          if (ndcount > 0) {
            printf("  The mesh is constrained Delaunay.\n");
          } else {
            printf("  The mesh is Delaunay.\n");
          } 
        }
      } else {
        printf("  !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
      }
    
      return horrors;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // Check if the current tetrahedralization is (constrained) regular.         //
    //                                                                           //
    // The parameter 'type' determines which regularity should be checked:       //
    //   - 0:  check the Delaunay property.                                      //
    //   - 1:  check the Delaunay property with symbolic perturbation.           //
    //   - 2:  check the regular property, the weights are stored in p[3].       //
    //   - 3:  check the regular property with symbolic perturbation.            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkregular(int type)
    {
      triface tetloop;
      triface symtet;
      face checksh;
      point p[5];
      REAL sign;
      int ndcount; // Count the non-locally Delaunay faces.
      int horrors;
    
      if (!b->quiet) {
        printf("  Checking %s %s property of the mesh...\n",
               (type & 2) == 0 ? "Delaunay" : "regular",
               (type & 1) == 0 ? " " : "(s)");
      }
    
      // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
      //   Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
      //     p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
      //   The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
      //     p[4] lies below the oriented hyperplane passing through 
      //     p[1], p[0], p[2], p[3].
    
      ndcount = 0;
      horrors = 0;
      tetloop.ver = 0;
      // Run through the list of triangles, checking each one.
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
        // Check all four faces of the tetrahedron.
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, symtet);
          // Only do test if its adjoining tet is not a hull tet or its pointer
          //   is larger (to ensure that each pair isn't tested twice).
          if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
            p[0] = org(tetloop);   // pa
            p[1] = dest(tetloop);  // pb
            p[2] = apex(tetloop);  // pc
            p[3] = oppo(tetloop);  // pd
            p[4] = oppo(symtet);   // pe
    
            if (type == 0) {
              sign = insphere(p[1], p[0], p[2], p[3], p[4]);
            } else if (type == 1) {
              sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
            } else if (type == 2) {
              sign = orient4d(p[1],    p[0],    p[2],    p[3],    p[4], 
                              p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
            } else { // type == 3
              sign = orient4d_s(p[1],    p[0],    p[2],    p[3],    p[4], 
                                p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
            }
    
            if (sign > 0.0) {
              ndcount++;
              if (checksubfaceflag) {
                tspivot(tetloop, checksh);
              }
              if (checksh.sh == NULL) {
                printf("  !! Non-locally %s (%d, %d, %d) - %d, %d\n",
                       (type & 2) == 0 ? "Delaunay" : "regular",
    		   pointmark(p[0]), pointmark(p[1]), pointmark(p[2]), 
                       pointmark(p[3]), pointmark(p[4]));
                horrors++;
              }
            }
          }
        }
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (horrors == 0) {
        if (!b->quiet) {
          if (ndcount > 0) {
            printf("  The mesh is constrained %s.\n",
                   (type & 2) == 0 ? "Delaunay" : "regular");
          } else {
            printf("  The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
          } 
        }
      } else {
        printf("  !! !! !! !! Found %d non-%s faces.\n", horrors,
               (type & 2) == 0 ? "Delaunay" : "regular");
      }
    
      return horrors;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // checkconforming()    Ensure that the mesh is conforming Delaunay.         //
    //                                                                           //
    // If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces.   //
    // If 'flag' is 3, check both subsegments and subfaces.                      //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int tetgenmesh::checkconforming(int flag)
    {
      triface searchtet, neightet, spintet;
      face shloop;
      face segloop;
      point eorg, edest, eapex, pa, pb, pc;
      REAL cent[3], radius, dist, diff, rd, len;
      bool enq;
      int encsubsegs, encsubfaces;
      int i;
    
      REAL A[4][4], rhs[4], D;
      int indx[4];
      REAL elen[3];
    
      encsubsegs = 0;
    
      if (flag & 1) {
        if (!b->quiet) {
          printf("  Checking conforming property of segments...\n");
        }
        encsubsegs = 0;
    
        // Run through the list of subsegments, check each one.
        subsegs->traversalinit();
        segloop.sh = shellfacetraverse(subsegs);
        while (segloop.sh != (shellface *) NULL) {
          eorg = (point) segloop.sh[3];
          edest = (point) segloop.sh[4];
          radius = 0.5 * distance(eorg, edest);
          for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
    
          enq = false;
          sstpivot1(segloop, neightet);
          if (neightet.tet != NULL) {
            spintet = neightet;
            while (1) {
              eapex= apex(spintet);
              if (eapex != dummypoint) {
                dist = distance(eapex, cent);
                diff = dist - radius;
                if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
                if (diff < 0) {
                  enq = true; break;
                }
              }
              fnextself(spintet);
              if (spintet.tet == neightet.tet) break;
            }
          }
          if (enq) {
            printf("  !! !! Non-conforming segment: (%d, %d)\n",
                   pointmark(eorg), pointmark(edest));
            encsubsegs++;
          }
          segloop.sh = shellfacetraverse(subsegs);
        }
    
        if (encsubsegs == 0) {
          if (!b->quiet) {
            printf("  The segments are conforming Delaunay.\n");
          }
        } else {
          printf("  !! !! %d subsegments are non-conforming.\n", encsubsegs);
        }
      } // if (flag & 1)
    
      encsubfaces = 0;
    
      if (flag & 2) {
        if (!b->quiet) {
          printf("  Checking conforming property of subfaces...\n");
        }
    
        // Run through the list of subfaces, check each one.
        subfaces->traversalinit();
        shloop.sh = shellfacetraverse(subfaces);
        while (shloop.sh != (shellface *) NULL) {
          pa = (point) shloop.sh[3];
          pb = (point) shloop.sh[4];
          pc = (point) shloop.sh[5];
    
          // Compute the coefficient matrix A (3x3).
          A[0][0] = pb[0] - pa[0];
          A[0][1] = pb[1] - pa[1];
          A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
          A[1][0] = pc[0] - pa[0];
          A[1][1] = pc[1] - pa[1];
          A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
          cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
    
          // Compute the right hand side vector b (3x1).
          elen[0] = dot(A[0], A[0]);
          elen[1] = dot(A[1], A[1]);
          rhs[0] = 0.5 * elen[0];
          rhs[1] = 0.5 * elen[1];
          rhs[2] = 0.0;
    
          if (lu_decmp(A, 3, indx, &D, 0)) {
            lu_solve(A, 3, indx, rhs, 0);
            cent[0] = pa[0] + rhs[0];
            cent[1] = pa[1] + rhs[1];
            cent[2] = pa[2] + rhs[2];
            rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
    
            // Check if this subface is encroached.
            for (i = 0; i < 2; i++) {
              stpivot(shloop, searchtet);
              if (!ishulltet(searchtet)) {
                len = distance(oppo(searchtet), cent);
                if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
                if (len < rd) {
                  printf("  !! !! Non-conforming subface: (%d, %d, %d)\n",
                         pointmark(pa), pointmark(pb), pointmark(pc));
                  encsubfaces++;
                  enq = true; break;
                }
              }
              sesymself(shloop);
            }
          }
          shloop.sh = shellfacetraverse(subfaces);
        }
    
        if (encsubfaces == 0) {
          if (!b->quiet) {
            printf("  The subfaces are conforming Delaunay.\n");
          }
        } else {
          printf("  !! !! %d subfaces are non-conforming.\n", encsubfaces);
        }
      } // if (flag & 2)
    
      return encsubsegs + encsubfaces;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // qualitystatistics()    Print statistics about the quality of the mesh.    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::qualitystatistics()
    {
      triface tetloop, neightet;
      point p[4];
      char sbuf[128];
      REAL radiusratiotable[12];
      REAL aspectratiotable[12];
      REAL A[4][4], rhs[4], D;
      REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
      REAL edgelength[6], alldihed[6], faceangle[3];
      REAL shortest, longest;
      REAL smallestvolume, biggestvolume;
      REAL smallestratio, biggestratio;
      REAL smallestdiangle, biggestdiangle;
      REAL smallestfaangle, biggestfaangle;
      REAL total_tet_vol, total_tetprism_vol;
      REAL tetvol, minaltitude;
      REAL cirradius, minheightinv; // insradius;
      REAL shortlen, longlen;
      REAL tetaspect, tetradius;
      REAL smalldiangle, bigdiangle;
      REAL smallfaangle, bigfaangle;
      int radiustable[12];
      int aspecttable[16];
      int dihedangletable[18];
      int faceangletable[18];
      int indx[4];
      int radiusindex;
      int aspectindex;
      int tendegree;
      int i, j;
    
      printf("Mesh quality statistics:\n\n");
    
      shortlen = longlen = 0.0;
      smalldiangle = bigdiangle = 0.0;
      total_tet_vol = 0.0;
      total_tetprism_vol = 0.0;
    
      radiusratiotable[0]  =    0.707;    radiusratiotable[1]  =     1.0;
      radiusratiotable[2]  =      1.1;    radiusratiotable[3]  =     1.2;
      radiusratiotable[4]  =      1.4;    radiusratiotable[5]  =     1.6;
      radiusratiotable[6]  =      1.8;    radiusratiotable[7]  =     2.0;
      radiusratiotable[8]  =      2.5;    radiusratiotable[9]  =     3.0;
      radiusratiotable[10] =     10.0;    radiusratiotable[11] =     0.0;
    
      aspectratiotable[0]  =      1.5;    aspectratiotable[1]  =     2.0;
      aspectratiotable[2]  =      2.5;    aspectratiotable[3]  =     3.0;
      aspectratiotable[4]  =      4.0;    aspectratiotable[5]  =     6.0;
      aspectratiotable[6]  =     10.0;    aspectratiotable[7]  =    15.0;
      aspectratiotable[8]  =     25.0;    aspectratiotable[9]  =    50.0;
      aspectratiotable[10] =    100.0;    aspectratiotable[11] =     0.0;
      
      for (i = 0; i < 12; i++) radiustable[i] = 0;
      for (i = 0; i < 12; i++) aspecttable[i] = 0;
      for (i = 0; i < 18; i++) dihedangletable[i] = 0;
      for (i = 0; i < 18; i++) faceangletable[i] = 0;
    
      minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
      minaltitude = minaltitude * minaltitude;
      shortest = minaltitude;
      longest = 0.0;
      smallestvolume = minaltitude;
      biggestvolume = 0.0;
      smallestratio = 1e+16; // minaltitude;
      biggestratio = 0.0;
      smallestdiangle = smallestfaangle = 180.0;
      biggestdiangle = biggestfaangle = 0.0;
    
    
      // Loop all elements, calculate quality parameters for each element.
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      while (tetloop.tet != (tetrahedron *) NULL) {
    
        // Get four vertices: p0, p1, p2, p3.
        for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
    
        // Get the tet volume.
        tetvol = orient3d(p[1], p[0], p[2], p[3]) / 6.0;
        total_tet_vol += tetvol;
        total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
    
        // Calculate the largest and smallest volume.
        if (tetvol < smallestvolume) {
          smallestvolume = tetvol;
        } 
        if (tetvol > biggestvolume) {
          biggestvolume = tetvol;
        }
    
        // Set the edge vectors: V[0], ..., V[5]
        for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
        for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
        for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
        for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
        for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
        for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
    
        // Get the squares of the edge lengthes.
        for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
    
        // Calculate the longest and shortest edge length.
        for (i = 0; i < 6; i++) {
          if (i == 0) {
            shortlen = longlen = edgelength[i];
          } else {
            shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
            longlen  = edgelength[i] > longlen  ? edgelength[i] : longlen;
          }
          if (edgelength[i] > longest) {
            longest = edgelength[i];
          } 
          if (edgelength[i] < shortest) {
            shortest = edgelength[i];
          }
        }
    
        // Set the matrix A = [V[0], V[1], V[2]]^T.
        for (j = 0; j < 3; j++) {
          for (i = 0; i < 3; i++) A[j][i] = V[j][i];
        }
    
        // Decompose A just once.
        if (lu_decmp(A, 3, indx, &D, 0)) {   
          // Get the three faces normals.
          for (j = 0; j < 3; j++) {
            for (i = 0; i < 3; i++) rhs[i] = 0.0;
            rhs[j] = 1.0;  // Positive means the inside direction
            lu_solve(A, 3, indx, rhs, 0);
            for (i = 0; i < 3; i++) N[j][i] = rhs[i];
          }
          // Get the fourth face normal by summing up the first three.
          for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
          // Get the radius of the circumsphere.
          for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
          lu_solve(A, 3, indx, rhs, 0);
          cirradius = sqrt(dot(rhs, rhs));
          // Normalize the face normals.
          for (i = 0; i < 4; i++) {
            // H[i] is the inverse of height of its corresponding face.
            H[i] = sqrt(dot(N[i], N[i]));
            for (j = 0; j < 3; j++) N[i][j] /= H[i];
          }
          // Get the radius of the inscribed sphere.
          // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
          // Get the biggest H[i] (corresponding to the smallest height).
          minheightinv = H[0];
          for (i = 1; i < 3; i++) {
            if (H[i] > minheightinv) minheightinv = H[i];
          }
        } else {
          // A nearly degenerated tet.
          if (tetvol <= 0.0) {
            // assert(tetvol != 0.0);
            printf("  !! Warning:  A %s tet (%d,%d,%d,%d).\n", 
                   tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
                   pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
            // Skip it.        
            tetloop.tet = tetrahedrontraverse();
            continue;
          }
          // Calculate the four face normals.
          facenormal(p[2], p[1], p[3], N[0], 1, NULL);
          facenormal(p[0], p[2], p[3], N[1], 1, NULL);
          facenormal(p[1], p[0], p[3], N[2], 1, NULL);
          facenormal(p[0], p[1], p[2], N[3], 1, NULL);
          // Normalize the face normals.
          for (i = 0; i < 4; i++) {
            // H[i] is the twice of the area of the face.
            H[i] = sqrt(dot(N[i], N[i]));
            for (j = 0; j < 3; j++) N[i][j] /= H[i];
          }
          // Get the biggest H[i] / tetvol (corresponding to the smallest height).
          minheightinv = (H[0] / tetvol);
          for (i = 1; i < 3; i++) {
            if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
          }
          // Let the circumradius to be the half of its longest edge length.
          cirradius = 0.5 * sqrt(longlen);
        }
    
        // Get the dihedrals (in degree) at each edges.
        j = 0;
        for (i = 1; i < 4; i++) {
          alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
          if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
          else if (alldihed[j] > 1.0) alldihed[j] = 1;
          alldihed[j] = acos(alldihed[j]) / PI * 180.0;
          j++;
        }
        for (i = 2; i < 4; i++) {
          alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
          if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
          else if (alldihed[j] > 1.0) alldihed[j] = 1;
          alldihed[j] = acos(alldihed[j]) / PI * 180.0;
          j++;
        }
        alldihed[j] = -dot(N[2], N[3]); // Edge ab.
        if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
        else if (alldihed[j] > 1.0) alldihed[j] = 1;
        alldihed[j] = acos(alldihed[j]) / PI * 180.0;
    
        // Calculate the largest and smallest dihedral angles.
        for (i = 0; i < 6; i++) {
          if (i == 0) {
            smalldiangle = bigdiangle = alldihed[i];
          } else {
            smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
            bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
          }
          if (alldihed[i] < smallestdiangle) {
            smallestdiangle = alldihed[i];
          } 
          if (alldihed[i] > biggestdiangle) {
            biggestdiangle = alldihed[i];
          }
          // Accumulate the corresponding number in the dihedral angle histogram.
          if (alldihed[i] < 5.0) {
            tendegree = 0;
          } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
            tendegree = 1;
          } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
            tendegree = 9; // Angles between 80 to 110 degree are in one entry.
          } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
            tendegree = 16;
          } else if (alldihed[i] >= 175.0) {
            tendegree = 17;
          } else {
            tendegree = (int) (alldihed[i] / 10.);
            if (alldihed[i] < 80.0) {
              tendegree++;  // In the left column.
            } else {
              tendegree--;  // In the right column.
            }
          }
          dihedangletable[tendegree]++;
        }
    
    
    
        // Calulate the largest and smallest face angles.
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, neightet);
          // Only do the calulation once for a face.
          if (((point) neightet.tet[7] == dummypoint) || 
              (tetloop.tet < neightet.tet)) {
            p[0] = org(tetloop);
            p[1] = dest(tetloop);
            p[2] = apex(tetloop);
            faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
            faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
            faceangle[2] = PI - (faceangle[0] + faceangle[1]);
            // Translate angles into degrees.
            for (i = 0; i < 3; i++) {
              faceangle[i] = (faceangle[i] * 180.0) / PI;
            }
            // Calculate the largest and smallest face angles.
            for (i = 0; i < 3; i++) {
              if (i == 0) {
                smallfaangle = bigfaangle = faceangle[i];
              } else {
                smallfaangle = faceangle[i] < smallfaangle ? 
                  faceangle[i] : smallfaangle;
                bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
              }
              if (faceangle[i] < smallestfaangle) {
                smallestfaangle = faceangle[i];
              } 
              if (faceangle[i] > biggestfaangle) {
                biggestfaangle = faceangle[i];
              }
              tendegree = (int) (faceangle[i] / 10.);
              faceangletable[tendegree]++;
            }
          }
        }
    
        // Calculate aspect ratio and radius-edge ratio for this element.
        tetradius = cirradius / sqrt(shortlen);
        // tetaspect = sqrt(longlen) / (2.0 * insradius);
        tetaspect = sqrt(longlen) * minheightinv;
        // Remember the largest and smallest aspect ratio.
        if (tetaspect < smallestratio) {
          smallestratio = tetaspect;
        } 
        if (tetaspect > biggestratio) {
          biggestratio = tetaspect;
        }
        // Accumulate the corresponding number in the aspect ratio histogram.
        aspectindex = 0;
        while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
          aspectindex++;
        }
        aspecttable[aspectindex]++;
        radiusindex = 0;
        while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
          radiusindex++;
        }
        radiustable[radiusindex]++;
    
        tetloop.tet = tetrahedrontraverse();
      }
    
      shortest = sqrt(shortest);
      longest = sqrt(longest);
      minaltitude = sqrt(minaltitude);
    
      printf("  Smallest volume: %16.5g   |  Largest volume: %16.5g\n",
             smallestvolume, biggestvolume);
      printf("  Shortest edge:   %16.5g   |  Longest edge:   %16.5g\n",
             shortest, longest);
      printf("  Smallest asp.ratio: %13.5g   |  Largest asp.ratio: %13.5g\n",
             smallestratio, biggestratio);
      sprintf(sbuf, "%.17g", biggestfaangle);
      if (strlen(sbuf) > 8) {
        sbuf[8] = '\0';
      }
      printf("  Smallest facangle: %14.5g   |  Largest facangle:       %s\n",
             smallestfaangle, sbuf);
      sprintf(sbuf, "%.17g", biggestdiangle);
      if (strlen(sbuf) > 8) {
        sbuf[8] = '\0';
      }
      printf("  Smallest dihedral: %14.5g   |  Largest dihedral:       %s\n\n",
             smallestdiangle, sbuf);
    
      printf("  Aspect ratio histogram:\n");
      printf("         < %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
             aspectratiotable[0], aspecttable[0], aspectratiotable[5],
             aspectratiotable[6], aspecttable[6]);
      for (i = 1; i < 5; i++) {
        printf("  %6.6g - %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
               aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
               aspectratiotable[i + 5], aspectratiotable[i + 6],
               aspecttable[i + 6]);
      }
      printf("  %6.6g - %-6.6g    :  %8d      | %6.6g -            :  %8d\n",
             aspectratiotable[4], aspectratiotable[5], aspecttable[5],
             aspectratiotable[10], aspecttable[11]);
      printf("  (A tetrahedron's aspect ratio is its longest edge length");
      printf(" divided by its\n");
      printf("    smallest side height)\n\n");
    
      printf("  Face angle histogram:\n");
      for (i = 0; i < 9; i++) {
        printf("    %3d - %3d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
               i * 10, i * 10 + 10, faceangletable[i],
               i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
      }
      if (minfaceang != PI) {
        printf("  Minimum input face angle is %g (degree).\n",
               minfaceang / PI * 180.0);
      }
      printf("\n");
    
      printf("  Dihedral angle histogram:\n");
      // Print the three two rows:
      printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
             0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
      printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
             5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
      // Print the third to seventh rows.
      for (i = 2; i < 7; i++) {
        printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
               (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
               (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
      }
      // Print the last two rows.
      printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
             60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
      printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
             70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
      if (minfacetdihed != PI) {
        printf("  Minimum input dihedral angle is %g (degree).\n",
               minfacetdihed / PI * 180.0);
      }
      printf("\n");
    
      printf("\n");
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // statistics()    Print all sorts of cool facts.                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::statistics()
    {
      long tetnumber, facenumber;
    
      printf("\nStatistics:\n\n");
      printf("  Input points: %d\n", in->numberofpoints);
      if (b->refine) {
        printf("  Input tetrahedra: %d\n", in->numberoftetrahedra);
      }
      if (b->plc) {
        printf("  Input facets: %d\n", in->numberoffacets);
        printf("  Input segments: %ld\n", insegments);
        printf("  Input holes: %d\n", in->numberofholes);
        printf("  Input regions: %d\n", in->numberofregions);
      }
    
      tetnumber = tetrahedrons->items - hullsize;
      facenumber = (tetnumber * 4l + hullsize) / 2l;
    
      printf("\n  Mesh points: %ld\n", points->items);
      printf("  Mesh tetrahedra: %ld\n", tetnumber);
      printf("  Mesh faces: %ld\n", facenumber);
      printf("  Mesh edges: %ld\n", meshedges);
    
      if (b->plc || b->refine) {
        printf("  Mesh boundary faces: %ld\n", subfaces->items);
        printf("  Mesh boundary edges: %ld\n", subsegs->items);
        if (st_segref_count > 0l) {
          printf("  Steiner points in boundary edges: %ld\n", st_segref_count);
        }
        if (st_facref_count > 0l) {
          printf("  Steiner points in boundary faces: %ld\n", st_facref_count);
        }
        if (st_volref_count > 0l) {
          printf("  Steiner points in mesh domain: %ld\n", st_volref_count);
        }
      } else {
        printf("  Convex hull faces: %ld\n", hullsize);
        printf("  Convex hull edges: %ld\n", meshhulledges);
      }
      printf("\n");
    
    
      if (b->verbose > 0) {
        if (b->plc || b->refine) { // -p or -r
          if (tetrahedrons->items > 0l) {
            qualitystatistics();
          }
        }
      }
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// meshstat_cxx /////////////////////////////////////////////////////////////
    
    //// output_cxx ///////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // jettisonnodes()    Jettison unused or duplicated vertices.                //
    //                                                                           //
    // Unused points are those input points which are outside the mesh domain or //
    // have no connection (isolated) to the mesh.  Duplicated points exist for   //
    // example if the input PLC is read from a .stl mesh file (marked during the //
    // Delaunay tetrahedralization step. This routine remove these points from   //
    // points list. All existing points are reindexed.                           //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::jettisonnodes()
    {
      point pointloop;
      bool jetflag;
      int oldidx, newidx;
      int remcount;
    
      if (!b->quiet) {
        printf("Jettisoning redundants points.\n");
      }
    
      points->traversalinit();
      pointloop = pointtraverse();
      oldidx = newidx = 0; // in->firstnumber;
      remcount = 0;
      while (pointloop != (point) NULL) {
        jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || 
          (pointtype(pointloop) == UNUSEDVERTEX);
        if (jetflag) {
          // It is a duplicated point, delete it.
          pointdealloc(pointloop);
          remcount++;
        } else {
          // Re-index it.
          setpointmark(pointloop, newidx + in->firstnumber);
          if (in->pointmarkerlist != (int *) NULL) {
            if (oldidx < in->numberofpoints) {
              // Re-index the point marker as well.
              in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
            }
          }
          newidx++;
        }
        oldidx++;
        //if (oldidx == in->numberofpoints) {
        //  // Update the numbe of input points (Because some were removed).
        //  in->numberofpoints -= remcount;
        //  // Remember this number for output original input nodes.
        //  jettisoninverts = remcount;
        //}
        pointloop = pointtraverse();
      }
      if (b->verbose) {
        printf("  %d duplicated vertices are removed.\n", dupverts);
        printf("  %d unused vertices are removed.\n", unuverts);
      }
      dupverts = 0;
      unuverts = 0;
    
      // The following line ensures that dead items in the pool of nodes cannot
      //   be allocated for the new created nodes. This ensures that the input
      //   nodes will occur earlier in the output files, and have lower indices.
      points->deaditemstack = (void *) NULL;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // numberedges()    Count the number of edges, save in "meshedges".          //
    //                                                                           //
    // This routine is called when '-p' or '-r', and '-E' options are used.  The //
    // total number of edges depends on the genus of the input surface mesh.     //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::numberedges()
    {
      triface worktet, spintet;
      int firstindex, eindex;
      int ishulledge;
      int i;
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
    
      // First indexing all tetrahedra.
      tetrahedrons->traversalinit();
      eindex = firstindex;
      worktet.tet = tetrahedrontraverse();
      while (worktet.tet != NULL) {
        setelemindex(worktet.tet, eindex);
        eindex++;
        worktet.tet = tetrahedrontraverse();
      }
    
      meshedges = meshhulledges = 0l;
    
      tetrahedrons->traversalinit();
      worktet.tet = tetrahedrontraverse();
      while (worktet.tet != NULL) {
        // Count the number of Voronoi faces. Look at the six edges of this
        //   tet. Count an edge only if this tet's index is smaller than
        //   those of other non-hull tets which share this edge.
        for (i = 0; i < 6; i++) {
          worktet.ver = edge2ver[i];
          ishulledge = 0;
          fnext(worktet, spintet);
          do {
            if (!ishulltet(spintet)) {          
              if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
            } else {
              ishulledge = 1;
            }
            fnextself(spintet);
          } while (spintet.tet != worktet.tet);
          // Count this edge if no adjacent tets are smaller than this tet.
          if (spintet.tet == worktet.tet) {
            meshedges++;
            if (ishulledge) meshhulledges++;
          }
        }
        worktet.tet = tetrahedrontraverse();
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outnodes()    Output the points to a .node file or a tetgenio structure.  //
    //                                                                           //
    // Note: each point has already been numbered on input (the first index is   //
    // 'in->firstnumber').                                                       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outnodes(tetgenio* out)
    {
      FILE *outfile = NULL;
      char outnodefilename[FILENAMESIZE];
      face parentsh;
      point pointloop;
      int nextras, bmark, marker = 0;
      int coordindex, attribindex;
      int pointnumber, firstindex;
      int index, i;
    
      if (out == (tetgenio *) NULL) {
        strcpy(outnodefilename, b->outfilename);
        strcat(outnodefilename, ".node");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outnodefilename);
        } else {
          printf("Writing nodes.\n");
        }
      }
    
      nextras = in->numberofpointattributes;
      bmark = !b->nobound && in->pointmarkerlist;
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outnodefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outnodefilename);
          terminatetetgen(1);
        }
        // Number of points, number of dimensions, number of point attributes,
        //   and number of boundary markers (zero or one).
        fprintf(outfile, "%ld  %d  %d  %d\n", points->items, 3, nextras, bmark);
      } else {
        // Allocate space for 'pointlist';
        out->pointlist = new REAL[points->items * 3];
        if (out->pointlist == (REAL *) NULL) {
          printf("Error:  Out of memory.\n");
          terminatetetgen(1);
        }
        // Allocate space for 'pointattributelist' if necessary;
        if (nextras > 0) {
          out->pointattributelist = new REAL[points->items * nextras];
          if (out->pointattributelist == (REAL *) NULL) {
            printf("Error:  Out of memory.\n");
            terminatetetgen(1);
          }
        }
        // Allocate space for 'pointmarkerlist' if necessary;
        if (bmark) {
          out->pointmarkerlist = new int[points->items];
          if (out->pointmarkerlist == (int *) NULL) {
            printf("Error:  Out of memory.\n");
            terminatetetgen(1);
          }
        }
        if (b->psc) {
          out->pointparamlist = new tetgenio::pointparam[points->items];
          if (out->pointparamlist == NULL) {
            printf("Error:  Out of memory.\n");
            terminatetetgen(1);
          }
        }
        out->numberofpoints = points->items;
        out->numberofpointattributes = nextras;
        coordindex = 0;
        attribindex = 0;
      }
      
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
    
      points->traversalinit();
      pointloop = pointtraverse();
      pointnumber = firstindex; // in->firstnumber;
      index = 0;
      while (pointloop != (point) NULL) {
        if (bmark) {
          // Default the vertex has a zero marker.
          marker = 0;
          // Is it an input vertex?
          if (index < in->numberofpoints) {
            // Input point's marker is directly copied to output.
            marker = in->pointmarkerlist[index];       
          } else {
            if ((pointtype(pointloop) == FREESEGVERTEX) ||
                (pointtype(pointloop) == FREEFACETVERTEX)) {
              sdecode(point2sh(pointloop), parentsh);
              if (parentsh.sh != NULL) {
                marker = shellmark(parentsh);
                if (pointtype(pointloop) == FREEFACETVERTEX) {
                  if (in->facetmarkerlist != NULL) {
                    marker = in->facetmarkerlist[marker - 1];
                  }
                }
              }
            } // if (pointtype(...))
          }
        }
        if (out == (tetgenio *) NULL) {
          // Point number, x, y and z coordinates.
          fprintf(outfile, "%4d    %.17g  %.17g  %.17g", pointnumber,
                  pointloop[0], pointloop[1], pointloop[2]);
          for (i = 0; i < nextras; i++) {
            // Write an attribute.
            fprintf(outfile, "  %.17g", pointloop[4 + i]);
          }
          if (bmark) {
            // Write the boundary marker.
            fprintf(outfile, "    %d", marker);
          }
          if (b->psc) {
            fprintf(outfile, "  %.8g  %.8g  %d", pointgeomuv(pointloop, 0),
                    pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
            if (pointtype(pointloop) == RIDGEVERTEX) {
              fprintf(outfile, "  0");
            } else if (pointtype(pointloop) == ACUTEVERTEX) {
              fprintf(outfile, "  0");
            } else if (pointtype(pointloop) == FREESEGVERTEX) {
              fprintf(outfile, "  1");
            } else if (pointtype(pointloop) == FREEFACETVERTEX) {
              fprintf(outfile, "  2");
            } else if (pointtype(pointloop) == FREEVOLVERTEX) {
              fprintf(outfile, "  3");
            } else {
              fprintf(outfile, "  -1"); // Unknown type.
            }
          }
          fprintf(outfile, "\n");
        } else {
          // X, y, and z coordinates.
          out->pointlist[coordindex++] = pointloop[0];
          out->pointlist[coordindex++] = pointloop[1];
          out->pointlist[coordindex++] = pointloop[2];
          // Point attributes.
          for (i = 0; i < nextras; i++) {
            // Output an attribute.
            out->pointattributelist[attribindex++] = pointloop[4 + i];
          }
          if (bmark) {
            // Output the boundary marker.  
            out->pointmarkerlist[index] = marker;
          }
          if (b->psc) {
            out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
            out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
            out->pointparamlist[index].tag = pointgeomtag(pointloop);
            if (pointtype(pointloop) == RIDGEVERTEX) {
              out->pointparamlist[index].type = 0;
            } else if (pointtype(pointloop) == ACUTEVERTEX) {
              out->pointparamlist[index].type = 0;
            } else if (pointtype(pointloop) == FREESEGVERTEX) {
              out->pointparamlist[index].type = 1;
            } else if (pointtype(pointloop) == FREEFACETVERTEX) {
              out->pointparamlist[index].type = 2;
            } else if (pointtype(pointloop) == FREEVOLVERTEX) {
              out->pointparamlist[index].type = 3;
            } else {
              out->pointparamlist[index].type = -1; // Unknown type.
            }
          }
        }
        pointloop = pointtraverse();
        pointnumber++; 
        index++;
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outmetrics()    Output the metric to a file (*.mtr) or a tetgenio obj.    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outmetrics(tetgenio* out)
    {
      FILE *outfile = NULL;
      char outmtrfilename[FILENAMESIZE];
      point ptloop;
      int mtrindex;
    
      if (out == (tetgenio *) NULL) {
        strcpy(outmtrfilename, b->outfilename);
        strcat(outmtrfilename, ".mtr");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outmtrfilename);
        } else {
          printf("Writing metrics.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outmtrfilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outmtrfilename);
          terminatetetgen(3);
        }
        // Number of points, number of point metrices,
        // fprintf(outfile, "%ld  %d\n", points->items, sizeoftensor + 3);
        fprintf(outfile, "%ld  %d\n", points->items, 1);
      } else {
        // Allocate space for 'pointmtrlist' if necessary;
        // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
        out->pointmtrlist = new REAL[points->items];
        if (out->pointmtrlist == (REAL *) NULL) {
          terminatetetgen(1);
        }
        out->numberofpointmtrs = 1; // (sizeoftensor + 3);
        mtrindex = 0;
      }
    
      points->traversalinit();
      ptloop = pointtraverse();
      while (ptloop != (point) NULL) {
        if (out == (tetgenio *) NULL) {
          // for (i = 0; i < sizeoftensor; i++) {
          //   fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
          // }
          fprintf(outfile, "%-16.8e\n", ptloop[pointmtrindex]);
        } else {
          // for (i = 0; i < sizeoftensor; i++) {
          //   out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
          // }
          out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex];
        }
        ptloop = pointtraverse();
      }
      
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outelements()    Output the tetrahedra to an .ele file or a tetgenio      //
    //                  structure.                                               //
    //                                                                           //
    // This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
    // firstnumber). The total number of mesh edges is counted in 'meshedges'.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outelements(tetgenio* out)
    {
      FILE *outfile = NULL;
      char outelefilename[FILENAMESIZE];
      tetrahedron* tptr;
      triface worktet, spintet;
      point p1, p2, p3, p4;
      point *extralist;
      REAL *talist = NULL;
      int *tlist = NULL;
      long ntets;
      int firstindex, shift;
      int pointindex, attribindex;
      int highorderindex = 10; // The reserved pointer.
      int elementnumber;
      int eextras;
      int ishulledge;
      int i;
    
      if (out == (tetgenio *) NULL) {
        strcpy(outelefilename, b->outfilename);
        strcat(outelefilename, ".ele");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outelefilename);
        } else {
          printf("Writing elements.\n");
        }
      }
    
      // The number of tets excluding hull tets.
      ntets = tetrahedrons->items - hullsize;
    
      eextras = in->numberoftetrahedronattributes;
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outelefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outelefilename);
          terminatetetgen(1);
        }
        // Number of tetras, points per tetra, attributes per tetra.
        fprintf(outfile, "%ld  %d  %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
      } else {
        // Allocate memory for output tetrahedra.
        out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
        if (out->tetrahedronlist == (int *) NULL) {
          printf("Error:  Out of memory.\n");
          terminatetetgen(1);
        }
        // Allocate memory for output tetrahedron attributes if necessary.
        if (eextras > 0) {
          out->tetrahedronattributelist = new REAL[ntets * eextras];
          if (out->tetrahedronattributelist == (REAL *) NULL) {
            printf("Error:  Out of memory.\n");
            terminatetetgen(1);
          }
        }
        out->numberoftetrahedra = ntets;
        out->numberofcorners = b->order == 1 ? 4 : 10;
        out->numberoftetrahedronattributes = eextras;
        tlist = out->tetrahedronlist;
        talist = out->tetrahedronattributelist;
        pointindex = 0;
        attribindex = 0;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift the output indices by 1.
      }
    
      tetrahedrons->traversalinit();
      tptr = tetrahedrontraverse();
      elementnumber = firstindex; // in->firstnumber;
      while (tptr != (tetrahedron *) NULL) {
        p1 = (point) tptr[4];
        p2 = (point) tptr[5];
        p3 = (point) tptr[6];
        p4 = (point) tptr[7];
        if (out == (tetgenio *) NULL) {
          // Tetrahedron number, indices for four points.
          fprintf(outfile, "%5d   %5d %5d %5d %5d", elementnumber,
                  pointmark(p1) - shift, pointmark(p2) - shift,
                  pointmark(p3) - shift, pointmark(p4) - shift);
          if (0) { // if (b->order == 2) {
            extralist = (point *) tptr[highorderindex];
            // Tetrahedron number, indices for four points plus six extra points.
            fprintf(outfile, "  %5d %5d %5d %5d %5d %5d",
              pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
              pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
              pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
          }
          for (i = 0; i < eextras; i++) {
            fprintf(outfile, "    %.17g", elemattribute(tptr, i));
          }
          fprintf(outfile, "\n");
        } else {
          tlist[pointindex++] = pointmark(p1) - shift;
          tlist[pointindex++] = pointmark(p2) - shift;
          tlist[pointindex++] = pointmark(p3) - shift;
          tlist[pointindex++] = pointmark(p4) - shift;
          if (0) { // if (b->order == 2) {
            extralist = (point *) tptr[highorderindex];
            tlist[pointindex++] = pointmark(extralist[0]) - shift;
            tlist[pointindex++] = pointmark(extralist[1]) - shift;
            tlist[pointindex++] = pointmark(extralist[2]) - shift;
            tlist[pointindex++] = pointmark(extralist[3]) - shift;
            tlist[pointindex++] = pointmark(extralist[4]) - shift;
            tlist[pointindex++] = pointmark(extralist[5]) - shift;
          }
          for (i = 0; i < eextras; i++) {
            talist[attribindex++] = elemattribute(tptr, i);
          }
        }
        //if (b->neighout) {
          // Remember the index of this element.
          setelemindex(tptr, elementnumber);
        //}
        tptr = tetrahedrontraverse();
        elementnumber++;
      }
    
      // Count the number of edges (# Voronoi faces). 
      meshedges = meshhulledges = 0l;
    
      tetrahedrons->traversalinit();
      tptr = tetrahedrontraverse();
      while (tptr != (tetrahedron *) NULL) {
        // Count the number of Voronoi faces. Look at the six edges of this
        //   tet. Count an edge only if this tet's pointer is smaller than
        //   those of other non-hull tets which share this edge.
        worktet.tet = tptr;
        for (i = 0; i < 6; i++) {
          worktet.ver = edge2ver[i];
          ishulledge = 0;
          fnext(worktet, spintet);
          do {
            if (!ishulltet(spintet)) {
              if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
            } else {
              ishulledge = 1;
            }
            fnextself(spintet);
          } while (spintet.tet != worktet.tet);
          // Count this edge if no adjacent tets are smaller than this tet.
          if (spintet.tet == worktet.tet) {
            meshedges++;
            if (ishulledge) meshhulledges++;
          }
        }
        tptr = tetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outfaces()    Output all faces to a .face file or a tetgenio object.      //
    //                                                                           //
    // The total number of faces f can be calculated as following:  Let t be the //
    // total number of tets. Since each tet has 4 faces, the number t * 4 counts //
    // each interior face twice and each hull face once. So f = (t * 4 + h) / 2, //
    // where h is the total number of hull faces (which is known).               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outfaces(tetgenio* out)
    {
      FILE *outfile = NULL;
      char facefilename[FILENAMESIZE];
      triface tface, tsymface;
      face checkmark;
      point torg, tdest, tapex;
      long ntets, faces;
      int *elist = NULL, *emlist = NULL;
      int neigh1 = 0, neigh2 = 0;
      int faceid, marker = 0;
      int firstindex, shift;
      int facenumber;
      int index;
    
      if (out == (tetgenio *) NULL) {
        strcpy(facefilename, b->outfilename);
        strcat(facefilename, ".face");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", facefilename);
        } else {
          printf("Writing faces.\n");
        }
      }
    
      ntets = tetrahedrons->items - hullsize;
      faces = (ntets * 4l + hullsize) / 2l;
      //bmark = !b->nobound && in->facetmarkerlist;
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(facefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", facefilename);
          terminatetetgen(1);
        }
        fprintf(outfile, "%ld  %d\n", faces, !b->nobound);
      } else {
        // Allocate memory for 'trifacelist'.
        out->trifacelist = new int[faces * 3];
        if (out->trifacelist == (int *) NULL) {
          printf("Error:  Out of memory.\n");
          terminatetetgen(1);
        }
        // Allocate memory for 'trifacemarkerlist' if necessary.
        if (!b->nobound) {
          out->trifacemarkerlist = new int[faces];
          if (out->trifacemarkerlist == (int *) NULL) {
            printf("Error:  Out of memory.\n");
            terminatetetgen(1);
          }
        }
        if (b->neighout > 1) {
          // '-nn' switch.
          out->adjtetlist = new int[faces * 2];
          if (out->adjtetlist == (int *) NULL) {
            printf("Error:  Out of memory.\n");
            terminatetetgen(1);
          }
        }
        out->numberoftrifaces = faces;
        elist = out->trifacelist;
        emlist = out->trifacemarkerlist;
        index = 0;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift the output indices by 1.
      }
    
      tetrahedrons->traversalinit();
      tface.tet = tetrahedrontraverse();
      facenumber = firstindex; // in->firstnumber;
      // To loop over the set of faces, loop over all tetrahedra, and look at
      //   the four faces of each one. If its adjacent tet is a hull tet,
      //   operate on the face, otherwise, operate on the face only if the
      //   current tet has a smaller index than its neighbor.
      while (tface.tet != (tetrahedron *) NULL) {
        for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
          fsym(tface, tsymface);
          if (ishulltet(tsymface) || 
              (elemindex(tface.tet) < elemindex(tsymface.tet))) {
            torg = org(tface);
            tdest = dest(tface);
            tapex = apex(tface);
            if (!b->nobound) {
              // Get the boundary marker of this face.
              if (b->plc || b->refine) { 
                // Shell face is used.
                tspivot(tface, checkmark);
                if (checkmark.sh == NULL) {
                  marker = 0;  // It is an inner face. It's marker is 0.
                } else {
                  if (in->facetmarkerlist) {
                    // The facet marker is given, get it.
                    faceid = shellmark(checkmark) - 1;
                    marker = in->facetmarkerlist[faceid];
                  } else {
                    marker = 1; // The default marker for subface is 1.
                  }
                }
              } else {
                // Shell face is not used, only distinguish outer and inner face.
                marker = (int) ishulltet(tsymface);
              }
            }
            if (b->neighout > 1) {
              // '-nn' switch. Output adjacent tets indices.
              neigh1 = elemindex(tface.tet);
              if (!ishulltet(tsymface)) {
                neigh2 = elemindex(tsymface.tet);
              } else {
                neigh2 = -1;  
              }
            }
            if (out == (tetgenio *) NULL) {
              // Face number, indices of three vertices.
              fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
                      pointmark(torg) - shift, pointmark(tdest) - shift,
                      pointmark(tapex) - shift);
              if (!b->nobound) {
                // Output a boundary marker.
                fprintf(outfile, "  %d", marker);
              }
              if (b->neighout > 1) {
                fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
              }
              fprintf(outfile, "\n");
            } else {
              // Output indices of three vertices.
              elist[index++] = pointmark(torg) - shift;
              elist[index++] = pointmark(tdest) - shift;
              elist[index++] = pointmark(tapex) - shift;
              if (!b->nobound) {
                emlist[facenumber - in->firstnumber] = marker;
              }
              if (b->neighout > 1) {
                out->adjtetlist[(facenumber - in->firstnumber) * 2]     = neigh1;
                out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
              }
            }
            facenumber++;
          }
        }
        tface.tet = tetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outhullfaces()    Output hull faces to a .face file or a tetgenio object. //
    //                                                                           //
    // The normal of each face is pointing to the outside of the domain.         //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outhullfaces(tetgenio* out)
    {
      FILE *outfile = NULL;
      char facefilename[FILENAMESIZE];
      triface hulltet;
      point torg, tdest, tapex;
      int *elist = NULL;
      int firstindex, shift;
      int facenumber;
      int index;
    
      if (out == (tetgenio *) NULL) {
        strcpy(facefilename, b->outfilename);
        strcat(facefilename, ".face");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", facefilename);
        } else {
          printf("Writing faces.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(facefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", facefilename);
          terminatetetgen(1);
        }
        fprintf(outfile, "%ld  0\n", hullsize);
      } else {
        // Allocate memory for 'trifacelist'.
        out->trifacelist = new int[hullsize * 3];
        if (out->trifacelist == (int *) NULL) {
          printf("Error:  Out of memory.\n");
          terminatetetgen(1);
        }
        out->numberoftrifaces = hullsize;
        elist = out->trifacelist;
        index = 0;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift the output indices by 1.
      }
    
      tetrahedrons->traversalinit();
      hulltet.tet = alltetrahedrontraverse();
      facenumber = firstindex;
      while (hulltet.tet != (tetrahedron *) NULL) {
        if (ishulltet(hulltet)) {
          torg = (point) hulltet.tet[4];
          tdest = (point) hulltet.tet[5];
          tapex = (point) hulltet.tet[6];
          if (out == (tetgenio *) NULL) {
            // Face number, indices of three vertices.
            fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
                    pointmark(torg) - shift, pointmark(tdest) - shift,
                    pointmark(tapex) - shift);
            fprintf(outfile, "\n");
          } else {
            // Output indices of three vertices.
            elist[index++] = pointmark(torg) - shift;
            elist[index++] = pointmark(tdest) - shift;
            elist[index++] = pointmark(tapex) - shift;
          }
          facenumber++;
        }
        hulltet.tet = alltetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outsubfaces()    Output subfaces (i.e. boundary faces) to a .face file or //
    //                  a tetgenio structure.                                    //
    //                                                                           //
    // The boundary faces are found in 'subfaces'. For listing triangle vertices //
    // in the same sense for all triangles in the mesh, the direction determined //
    // by right-hand rule is pointer to the inside of the volume.                //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outsubfaces(tetgenio* out)
    {
      FILE *outfile = NULL;
      char facefilename[FILENAMESIZE];
      int *elist = NULL;
      int *emlist = NULL;
      int index = 0, index1 = 0, index2 = 0;
      triface abuttingtet;
      face faceloop;
      point torg, tdest, tapex;
      int faceid = 0, marker = 0;
      int firstindex, shift;
      int neigh1 = 0, neigh2 = 0;
      int facenumber;
    
      if (out == (tetgenio *) NULL) {
        strcpy(facefilename, b->outfilename);
        strcat(facefilename, ".face");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", facefilename);
        } else {
          printf("Writing faces.\n");
        }
      }
    
      //bmark = !b->nobound && in->facetmarkerlist;
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(facefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", facefilename);
          terminatetetgen(3);
        }
        // Number of subfaces.
        fprintf(outfile, "%ld  %d\n", subfaces->items, !b->nobound);
      } else {
        // Allocate memory for 'trifacelist'.
        out->trifacelist = new int[subfaces->items * 3];
        if (out->trifacelist == (int *) NULL) {
          terminatetetgen(1);
        }
        if (!b->nobound) {
          // Allocate memory for 'trifacemarkerlist'.
          out->trifacemarkerlist = new int[subfaces->items];
          if (out->trifacemarkerlist == (int *) NULL) {
            terminatetetgen(1);
          }
        }
        if (b->neighout > 1) {
          // '-nn' switch.
          out->adjtetlist = new int[subfaces->items * 2];
          if (out->adjtetlist == (int *) NULL) {
            terminatetetgen(1);
          }
        }
        out->numberoftrifaces = subfaces->items;
        elist = out->trifacelist;
        emlist = out->trifacemarkerlist;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift the output indices by 1.
      }
    
      subfaces->traversalinit();
      faceloop.sh = shellfacetraverse(subfaces);
      facenumber = firstindex; // in->firstnumber;
      while (faceloop.sh != (shellface *) NULL) {
        stpivot(faceloop, abuttingtet);
        if (abuttingtet.tet != NULL) {
          // If there is a tetrahedron containing this subface, orient it so
          //   that the normal of this face points to inside of the volume by
          //   right-hand rule.
          torg = org(abuttingtet);
          tdest = dest(abuttingtet);
          tapex = apex(abuttingtet);
        } else {
          // This may happen when only a surface mesh be generated.
          torg = sorg(faceloop);
          tdest = sdest(faceloop);
          tapex = sapex(faceloop);
        }
        if (!b->nobound) {
          if (in->facetmarkerlist) {
            faceid = shellmark(faceloop) - 1;
            marker = in->facetmarkerlist[faceid];
          } else {
            marker = 1; // Default marker for a subface is 1.
          }
        }
        if (b->neighout > 1) {
          // '-nn' switch. Output adjacent tets indices.
          neigh1 = -1;
          neigh2 = -1;
          stpivot(faceloop, abuttingtet);
          if (abuttingtet.tet != NULL) {
            neigh1 = elemindex(abuttingtet.tet);
            fsymself(abuttingtet);
            if (!ishulltet(abuttingtet)) {
              neigh2 = elemindex(abuttingtet.tet);
            }
          }
        }
        if (out == (tetgenio *) NULL) {
          fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
                  pointmark(torg) - shift, pointmark(tdest) - shift,
                  pointmark(tapex) - shift);
          if (!b->nobound) {
            fprintf(outfile, "    %d", marker);
          }
          if (b->neighout > 1) {
            fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
          }
          fprintf(outfile, "\n");
        } else {
          // Output three vertices of this face;
          elist[index++] = pointmark(torg) - shift;
          elist[index++] = pointmark(tdest) - shift;
          elist[index++] = pointmark(tapex) - shift;
          if (!b->nobound) {
            emlist[index1++] = marker;
          }
          if (b->neighout > 1) {
            out->adjtetlist[index2++] = neigh1;
            out->adjtetlist[index2++] = neigh2;
          }
        }
        facenumber++;
        faceloop.sh = shellfacetraverse(subfaces);
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outedges()    Output all edges to a .edge file or a tetgenio object.      //
    //                                                                           //
    // Note: This routine must be called after outelements(),  so that the total //
    // number of edges 'meshedges' has been counted.                             //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outedges(tetgenio* out)
    {
      FILE *outfile = NULL;
      char edgefilename[FILENAMESIZE];
      triface tetloop, worktet, spintet;
      face checkseg;
      point torg, tdest;
      int *elist = NULL, *emlist = NULL;
      int ishulledge;
      int firstindex, shift;
      int edgenumber, marker;
      int index, index1;
      int i;
    
      if (out == (tetgenio *) NULL) {
        strcpy(edgefilename, b->outfilename);
        strcat(edgefilename, ".edge");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", edgefilename);
        } else {
          printf("Writing edges.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(edgefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
          terminatetetgen(1);
        }
        // Write the number of edges, boundary markers (0 or 1).
        fprintf(outfile, "%ld  %d\n", meshedges, !b->nobound);
      } else {
        // Allocate memory for 'edgelist'.
        out->edgelist = new int[meshedges * 2];
        if (out->edgelist == (int *) NULL) {
          printf("Error:  Out of memory.\n");
          terminatetetgen(1);
        }
        if (!b->nobound) {
          out->edgemarkerlist = new int[meshedges];
        }
        out->numberofedges = meshedges;
        elist = out->edgelist;
        emlist = out->edgemarkerlist;
        index = 0;
        index1 = 0; // if (!b->nobound)
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift (reduce) the output indices by 1.
      }
    
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      edgenumber = firstindex; // in->firstnumber;
      while (tetloop.tet != (tetrahedron *) NULL) {
        // Count the number of Voronoi faces. Look at the six edges of this
        //   tet. Count an edge only if this tet's pointer is smaller than
        //   those of other non-hull tets which share this edge.
        worktet.tet = tetloop.tet;
        for (i = 0; i < 6; i++) {
          worktet.ver = edge2ver[i];
          ishulledge = 0;
          fnext(worktet, spintet);
          do {
            if (!ishulltet(spintet)) {
              if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
            } else {
              ishulledge = 1;
            }
            fnextself(spintet);
          } while (spintet.tet != worktet.tet);
          // Count this edge if no adjacent tets are smaller than this tet.
          if (spintet.tet == worktet.tet) {
            torg = org(worktet);
            tdest = dest(worktet);
            if (out == (tetgenio *) NULL) {
              fprintf(outfile, "%5d   %4d  %4d", edgenumber,
                      pointmark(torg) - shift, pointmark(tdest) - shift);
            } else {
              // Output three vertices of this face;
              elist[index++] = pointmark(torg) - shift;
              elist[index++] = pointmark(tdest) - shift;
            }
            if (!b->nobound) {
              if (b->plc || b->refine) {
                // Check if the edge is a segment.
                tsspivot1(worktet, checkseg);
                if (checkseg.sh != NULL) {
                  marker = shellmark(checkseg);
                  if (marker == 0) {  // Does it have no marker?
                    marker = 1;  // Set the default marker for this segment.
                  }
                } else {
                  marker = 0;  // It's not a segment.
                }
              } else {
                // Mark it if it is a hull edge.
                marker = ishulledge ? 1 : 0;
              }
              if (out == (tetgenio *) NULL) {
                fprintf(outfile, "  %d", marker);
              } else {
                emlist[index1++] = marker;
              }
            }
            if (out == (tetgenio *) NULL) {
              fprintf(outfile, "\n");
            }
            edgenumber++;
          }
        }
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outsubsegments()    Output segments to a .edge file or a structure.       //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outsubsegments(tetgenio* out)
    {
      FILE *outfile = NULL;
      char edgefilename[FILENAMESIZE];
      int *elist = NULL;
      int index, i;
      face edgeloop;
      point torg, tdest;
      int firstindex, shift;
      int marker;
      int edgenumber;
    
      if (out == (tetgenio *) NULL) {
        strcpy(edgefilename, b->outfilename);
        strcat(edgefilename, ".edge");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", edgefilename);
        } else {
          printf("Writing edges.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(edgefilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
          terminatetetgen(3);
        }
        // Number of subsegments.
        fprintf(outfile, "%ld  1\n", subsegs->items);
      } else {
        // Allocate memory for 'edgelist'.
        out->edgelist = new int[subsegs->items * 2];
        if (out->edgelist == (int *) NULL) {
          terminatetetgen(1);
        }
        out->edgemarkerlist = new int[subsegs->items];
        if (out->edgemarkerlist == (int *) NULL) {
          terminatetetgen(1);
        }
        out->numberofedges = subsegs->items;
        elist = out->edgelist;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift the output indices by 1.
      }
      index = 0;
      i = 0;
    
      subsegs->traversalinit();
      edgeloop.sh = shellfacetraverse(subsegs);
      edgenumber = firstindex; // in->firstnumber;
      while (edgeloop.sh != (shellface *) NULL) {
        torg = sorg(edgeloop);
        tdest = sdest(edgeloop);
        marker = shellmark(edgeloop);
        if (marker == 0) {
          marker = 1; // Default marker of a boundary edge is 1. 
        }
        if (out == (tetgenio *) NULL) {
          fprintf(outfile, "%5d   %4d  %4d  %d\n", edgenumber,
                  pointmark(torg) - shift, pointmark(tdest) - shift, marker);
        } else {
          // Output three vertices of this face;
          elist[index++] = pointmark(torg) - shift;
          elist[index++] = pointmark(tdest) - shift;
          out->edgemarkerlist[i++] = marker;
        }
        edgenumber++;
        edgeloop.sh = shellfacetraverse(subsegs);
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outneighbors()    Output tet neighbors to a .neigh file or a structure.   //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outneighbors(tetgenio* out)
    {
      FILE *outfile = NULL;
      char neighborfilename[FILENAMESIZE];
      int *nlist = NULL;
      int index = 0;
      triface tetloop, tetsym;
      int neighbori[4];
      int firstindex;
      int elementnumber;
      long ntets;
    
      if (out == (tetgenio *) NULL) {
        strcpy(neighborfilename, b->outfilename);
        strcat(neighborfilename, ".neigh");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", neighborfilename);
        } else {
          printf("Writing neighbors.\n");
        }
      }
    
      ntets = tetrahedrons->items - hullsize;
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(neighborfilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", neighborfilename);
          terminatetetgen(1);
        }
        // Number of tetrahedra, four faces per tetrahedron.
        fprintf(outfile, "%ld  %d\n", ntets, 4);
      } else {
        // Allocate memory for 'neighborlist'.
        out->neighborlist = new int[ntets * 4];
        if (out->neighborlist == (int *) NULL) {
          printf("Error:  Out of memory.\n");
          terminatetetgen(1);
        }
        nlist = out->neighborlist;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
    
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      elementnumber = firstindex; // in->firstnumber;
      while (tetloop.tet != (tetrahedron *) NULL) {
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, tetsym);
          if (!ishulltet(tetsym)) {
            neighbori[tetloop.ver] = elemindex(tetsym.tet);
          } else {
            neighbori[tetloop.ver] = -1;
          }
        }
        if (out == (tetgenio *) NULL) {
          // Tetrahedra number, neighboring tetrahedron numbers.
          fprintf(outfile, "%4d    %4d  %4d  %4d  %4d\n", elementnumber,
                  neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
        } else {
          nlist[index++] = neighbori[0];
          nlist[index++] = neighbori[1];
          nlist[index++] = neighbori[2];
          nlist[index++] = neighbori[3];
        }
        tetloop.tet = tetrahedrontraverse();
        elementnumber++;
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outvoronoi()    Output the Voronoi diagram to .v.node, .v.edge, v.face,   //
    //                 and .v.cell.                                              //
    //                                                                           //
    // The Voronoi diagram is the geometric dual of the Delaunay triangulation.  //
    // The Voronoi vertices are the circumcenters of Delaunay tetrahedra.  Each  //
    // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
    // unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
    // A Voronoi face is the convex hull of all Voronoi vertices around a common //
    // Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a //
    // ridge, it is unbounded.  Each Voronoi cell is the convex hull of all Vor- //
    // onoi vertices around a common Delaunay vertex. It is a polytope for any   //
    // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay    //
    // vertex belonging to the convex hull.                                      //
    //                                                                           //
    // Comment: Special thanks to Victor Liu for finding and fixing few bugs.    //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outvoronoi(tetgenio* out)
    {
      FILE *outfile = NULL;
      char outfilename[FILENAMESIZE];
      tetgenio::voroedge *vedge = NULL;
      tetgenio::vorofacet *vfacet;
      arraypool *tetlist, *ptlist;
      triface tetloop, worktet, spintet, firsttet;
      point pt[4], ploop, neipt;
      REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
      long ntets, faces, edges;
      int *indexarray, *fidxs, *eidxs;
      int arraysize, *vertarray = NULL;
      int vpointcount, vedgecount, vfacecount, tcount;
      int ishullvert, ishullface;
      int index, shift, end1, end2;
      int i, j;
    
      // Output Voronoi vertices to .v.node file.
      if (out == (tetgenio *) NULL) {
        strcpy(outfilename, b->outfilename);
        strcat(outfilename, ".v.node");
      }
    
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outfilename);
        } else {
          printf("Writing Voronoi vertices.\n");
        }
      }
    
      // Determine the first index (0 or 1).
      shift = (b->zeroindex ? 0 : in->firstnumber);
    
      // Each face and edge of the tetrahedral mesh will be indexed for indexing
      //   the Voronoi edges and facets. Indices of faces and edges are saved in
      //   each tetrahedron (including hull tets).
    
      // Allocate the total space once.
      indexarray = new int[tetrahedrons->items * 10];
    
      // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
      //   for element markers, flags.
      i = 0;
      tetrahedrons->traversalinit();
      tetloop.tet = alltetrahedrontraverse();
      while (tetloop.tet != NULL) {
        tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
        i++;
        tetloop.tet = alltetrahedrontraverse();
      }
    
      // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
      ntets = tetrahedrons->items - hullsize;
      // The number of Delaunay faces (Voronoi edges).
      faces = (4l * ntets + hullsize) / 2l;
      // The number of Delaunay edges (Voronoi faces).
      // edges = points->items + faces - ntets - 1;
      edges = meshedges; // Counted in outelements() or numberedges();
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outfilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outfilename);
          terminatetetgen(3);
        }
        // Number of voronoi points, 3 dim, no attributes, no marker.
        fprintf(outfile, "%ld  3  0  0\n", ntets);
      } else {
        // Allocate space for 'vpointlist'.
        out->numberofvpoints = (int) ntets;
        out->vpointlist = new REAL[out->numberofvpoints * 3];
        if (out->vpointlist == (REAL *) NULL) {
          terminatetetgen(1);
        }
      }
    
      // Output Voronoi vertices (the circumcenters of tetrahedra). 
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      vpointcount = 0; // The (internal) v-index always starts from 0. 
      index = 0;
      while (tetloop.tet != (tetrahedron *) NULL) {
        for (i = 0; i < 4; i++) {
          pt[i] = (point) tetloop.tet[4 + i];
          setpoint2tet(pt[i], encode(tetloop));
        }
        circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
        if (out == (tetgenio *) NULL) {
          fprintf(outfile, "%4d  %16.8e %16.8e %16.8e\n", vpointcount + shift,
                  ccent[0], ccent[1], ccent[2]);
        } else {
          out->vpointlist[index++] = ccent[0];
          out->vpointlist[index++] = ccent[1];
          out->vpointlist[index++] = ccent[2];
        }
        setelemindex(tetloop.tet, vpointcount);
        vpointcount++;
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    
      // Output Voronoi edges to .v.edge file.
      if (out == (tetgenio *) NULL) {
        strcpy(outfilename, b->outfilename);
        strcat(outfilename, ".v.edge");
      }
      
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outfilename);
        } else {
          printf("Writing Voronoi edges.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outfilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outfilename);
          terminatetetgen(3);
        }
        // Number of Voronoi edges, no marker.
        fprintf(outfile, "%ld  0\n", faces);
      } else {
        // Allocate space for 'vpointlist'.
        out->numberofvedges = (int) faces;
        out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
      }
    
      // Output the Voronoi edges. 
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      vedgecount = 0; // D-Face (V-edge) index (from zero).
      index = 0; // The Delaunay-face index.
      while (tetloop.tet != (tetrahedron *) NULL) {
        // Count the number of Voronoi edges. Look at the four faces of each
        //   tetrahedron. Count the face if the tetrahedron's index is
        //   smaller than its neighbor's or the neighbor is outside.
        end1 = elemindex(tetloop.tet);
        for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
          fsym(tetloop, worktet);
          if (ishulltet(worktet) || 
              (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
            // Found a Voronoi edge. Operate on it.
            if (out == (tetgenio *) NULL) {
              fprintf(outfile, "%4d  %4d", vedgecount + shift, end1 + shift);
            } else {
              vedge = &(out->vedgelist[index++]);
              vedge->v1 = end1 + shift;
            }
            if (!ishulltet(worktet)) {
              end2 = elemindex(worktet.tet);
            } else {
              end2 = -1;
            }
            // Note that end2 may be -1 (worktet.tet is outside).
            if (end2 == -1) {
              // Calculate the out normal of this hull face.
              pt[0] = dest(worktet);
              pt[1] = org(worktet);
              pt[2] = apex(worktet);
              for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
              for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
              cross(vec1, vec2, infvec);
              // Normalize it.
              L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
                       + infvec[2] * infvec[2]);
              if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
              if (out == (tetgenio *) NULL) {
                fprintf(outfile, " -1");
                fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
              } else {
                vedge->v2 = -1;
                vedge->vnormal[0] = infvec[0];
                vedge->vnormal[1] = infvec[1];
                vedge->vnormal[2] = infvec[2];
              }
            } else {
              if (out == (tetgenio *) NULL) {
                fprintf(outfile, " %4d\n", end2 + shift);
              } else {
                vedge->v2 = end2 + shift;
                vedge->vnormal[0] = 0.0;
                vedge->vnormal[1] = 0.0;
                vedge->vnormal[2] = 0.0;
              }
            }
            // Save the V-edge index in this tet and its neighbor.
            fidxs = (int *) (tetloop.tet[11]);
            fidxs[tetloop.ver] = vedgecount;
            fidxs = (int *) (worktet.tet[11]);
            fidxs[worktet.ver & 3] = vedgecount;
            vedgecount++;
          }
        } // tetloop.ver
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    
      // Output Voronoi faces to .v.face file.
      if (out == (tetgenio *) NULL) {
        strcpy(outfilename, b->outfilename);
        strcat(outfilename, ".v.face");
      }
      
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outfilename);
        } else {
          printf("Writing Voronoi faces.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outfilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outfilename);
          terminatetetgen(3);
        }
        // Number of Voronoi faces.
        fprintf(outfile, "%ld  0\n", edges);
      } else {
        out->numberofvfacets = edges;
        out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
        if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
          terminatetetgen(1);
        }
      }
    
      // Output the Voronoi facets.
      tetrahedrons->traversalinit();
      tetloop.tet = tetrahedrontraverse();
      vfacecount = 0; // D-edge (V-facet) index (from zero).
      while (tetloop.tet != (tetrahedron *) NULL) {
        // Count the number of Voronoi faces. Look at the six edges of each
        //   tetrahedron. Count the edge only if the tetrahedron's index is
        //   smaller than those of all other tetrahedra that share the edge.
        worktet.tet = tetloop.tet;
        for (i = 0; i < 6; i++) {
          worktet.ver = edge2ver[i];
          // Count the number of faces at this edge. If the edge is a hull edge,
          //   the face containing dummypoint is also counted.
          //ishulledge = 0; // Is it a hull edge.
          tcount = 0;
          firsttet = worktet;
          spintet = worktet;
          while (1) {
            tcount++;
            fnextself(spintet);
            if (spintet.tet == worktet.tet) break;
            if (!ishulltet(spintet)) {
              if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
            } else {
              //ishulledge = 1;
              if (apex(spintet) == dummypoint) {
                // We make this V-edge appear in the end of the edge list.
                fnext(spintet, firsttet); 
              }
            }
          } // while (1)
          if (spintet.tet == worktet.tet) {
            // Found a Voronoi facet. Operate on it.
            pt[0] = org(worktet);
            pt[1] = dest(worktet);
            end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
            end2 = pointmark(pt[1]) - in->firstnumber;
            if (out == (tetgenio *) NULL) {
              fprintf(outfile, "%4d  %4d %4d  %-2d ", vfacecount + shift, 
                      end1 + shift, end2 + shift, tcount);
            } else {
              vfacet = &(out->vfacetlist[vfacecount]);
              vfacet->c1 = end1 + shift;
              vfacet->c2 = end2 + shift;
              vfacet->elist = new int[tcount + 1];
              vfacet->elist[0] = tcount;
              index = 1;
            }
            // Output V-edges of this V-facet.
            spintet = firsttet; //worktet;
            while (1) {
              fidxs = (int *) (spintet.tet[11]);
              if (apex(spintet) != dummypoint) {
                vedgecount = fidxs[spintet.ver & 3];
                ishullface = 0;
              } else {
                ishullface = 1; // It's not a real face.
              }
              if (out == (tetgenio *) NULL) {
                fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1); 
              } else {
                vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
              }
              // Save the V-facet index in this tet at this edge.
              eidxs = &(fidxs[4]);
              eidxs[ver2edge[spintet.ver]] = vfacecount;
              // Go to the next face.
              fnextself(spintet);
              if (spintet.tet == firsttet.tet) break;
            } // while (1)
            if (out == (tetgenio *) NULL) {
              fprintf(outfile, "\n");
            }
            vfacecount++;
          } // if (spintet.tet == worktet.tet)
        } // if (i = 0; i < 6; i++)
        tetloop.tet = tetrahedrontraverse();
      }
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    
      // Output Voronoi cells to .v.cell file.
      if (out == (tetgenio *) NULL) {
        strcpy(outfilename, b->outfilename);
        strcat(outfilename, ".v.cell");
      }
      
      if (!b->quiet) {
        if (out == (tetgenio *) NULL) {
          printf("Writing %s.\n", outfilename);
        } else {
          printf("Writing Voronoi cells.\n");
        }
      }
    
      if (out == (tetgenio *) NULL) {
        outfile = fopen(outfilename, "w");
        if (outfile == (FILE *) NULL) {
          printf("File I/O Error:  Cannot create file %s.\n", outfilename);
          terminatetetgen(3);
        }
        // Number of Voronoi cells.
        fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
      } else {
        out->numberofvcells = points->items - unuverts - dupverts;
        out->vcelllist = new int*[out->numberofvcells];
        if (out->vcelllist == (int **) NULL) {
          terminatetetgen(1);
        }
      }
    
      // Output Voronoi cells.
      tetlist = cavetetlist;
      ptlist = cavetetvertlist;
      points->traversalinit();
      ploop = pointtraverse();
      vpointcount = 0;
      while (ploop != (point) NULL) {
        if ((pointtype(ploop) != UNUSEDVERTEX) &&
            (pointtype(ploop) != DUPLICATEDVERTEX)) { 
          getvertexstar(1, ploop, tetlist, ptlist, NULL);
          // Mark all vertices. Check if it is a hull vertex.
          ishullvert = 0;
          for (i = 0; i < ptlist->objects; i++) {
            neipt = * (point *) fastlookup(ptlist, i);
            if (neipt != dummypoint) {
              pinfect(neipt);
            } else {
              ishullvert = 1;
            }
          }
          tcount = (int) ptlist->objects;
          if (out == (tetgenio *) NULL) {
            fprintf(outfile, "%4d  %-2d ", vpointcount + shift, tcount);
          } else {
            arraysize = tcount;
            vertarray = new int[arraysize + 1];
            out->vcelllist[vpointcount] = vertarray;
            vertarray[0] = tcount;
            index = 1;
          }
          // List Voronoi facets bounding this cell.
          for (i = 0; i < tetlist->objects; i++) {
            worktet = * (triface *) fastlookup(tetlist, i);
            // Let 'worktet' be [a,b,c,d] where d = ploop.
            for (j = 0; j < 3; j++) {
              neipt = org(worktet); // neipt is a, or b, or c
              // Skip the dummypoint.
              if (neipt != dummypoint) {
                if (pinfected(neipt)) {
                  // It's not processed yet.
                  puninfect(neipt);
                  // Go to the DT edge [a,d], or [b,d], or [c,d]. 
                  esym(worktet, spintet);
                  enextself(spintet);
                  // Get the V-face dual to this edge.
                  eidxs = (int *) spintet.tet[11];
                  vfacecount = eidxs[4 + ver2edge[spintet.ver]];
                  if (out == (tetgenio *) NULL) {
                    fprintf(outfile, " %d", vfacecount + shift);
                  } else {
                    vertarray[index++] = vfacecount + shift;
                  }
                }
              }
              enextself(worktet);
            } // j
          } // i
          if (ishullvert) {
            // Add a hull facet (-1) to the facet list.
            if (out == (tetgenio *) NULL) {
              fprintf(outfile, " -1");
            } else {
              vertarray[index++] = -1;
            }
          }
          if (out == (tetgenio *) NULL) {
            fprintf(outfile, "\n");
          }
          // DEBUG BEGIN
          for (i = 0; i < ptlist->objects; i++) {
            neipt = * (point *) fastlookup(ptlist, i);
            if (neipt != dummypoint) {
              assert(!pinfected(neipt));
            }
          }
          // DEBUG END
          tetlist->restart();
          ptlist->restart();
          vpointcount++;
        }
        ploop = pointtraverse();
      }
    
      // Delete the space for face/edge indices.
      delete [] indexarray;
    
      if (out == (tetgenio *) NULL) {
        fprintf(outfile, "# Generated by %s\n", b->commandline);
        fclose(outfile);
      }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outsmesh()    Write surface mesh to a .smesh file, which can be read and  //
    //               tetrahedralized by TetGen.                                  //
    //                                                                           //
    // You can specify a filename (without suffix) in 'smfilename'. If you don't //
    // supply a filename (let smfilename be NULL), the default name stored in    //
    // 'tetgenbehavior' will be used.                                            //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outsmesh(char* smfilename)
    {
      FILE *outfile;
      char nodfilename[FILENAMESIZE];
      char smefilename[FILENAMESIZE];
      face faceloop;
      point p1, p2, p3;
      int firstindex, shift;
      int bmark;
      int faceid, marker;
      int i;
    
      if (smfilename != (char *) NULL && smfilename[0] != '\0') {
        strcpy(smefilename, smfilename);
      } else if (b->outfilename[0] != '\0') {
        strcpy(smefilename, b->outfilename);
      } else {
        strcpy(smefilename, "unnamed");
      }
      strcpy(nodfilename, smefilename);
      strcat(smefilename, ".smesh");
      strcat(nodfilename, ".node");
    
      if (!b->quiet) {
        printf("Writing %s.\n", smefilename);
      }
      outfile = fopen(smefilename, "w");
      if (outfile == (FILE *) NULL) {
        printf("File I/O Error:  Cannot create file %s.\n", smefilename);
        return;
      }
    
      // Determine the first index (0 or 1).
      firstindex = b->zeroindex ? 0 : in->firstnumber;
      shift = 0; // Default no shiftment.
      if ((in->firstnumber == 1) && (firstindex == 0)) {
        shift = 1; // Shift the output indices by 1.
      }
    
      fprintf(outfile, "# %s.  TetGen's input file.\n", smefilename);
      fprintf(outfile, "\n# part 1: node list.\n");
      fprintf(outfile, "0  3  0  0  # nodes are found in %s.\n", nodfilename);
    
      marker = 0; // avoid compile warning.
      bmark = !b->nobound && in->facetmarkerlist;  
    
      fprintf(outfile, "\n# part 2: facet list.\n");
      // Number of facets, boundary marker.
      fprintf(outfile, "%ld  %d\n", subfaces->items, bmark);
      
      subfaces->traversalinit();
      faceloop.sh = shellfacetraverse(subfaces);
      while (faceloop.sh != (shellface *) NULL) {
        p1 = sorg(faceloop);
        p2 = sdest(faceloop);
        p3 = sapex(faceloop);
        if (bmark) {
          faceid = shellmark(faceloop) - 1;
          if (faceid >= 0) { 
            marker = in->facetmarkerlist[faceid];
          } else {
            marker = 0; // This subface must be added manually later.
          }
        }
        fprintf(outfile, "3    %4d  %4d  %4d", pointmark(p1) - shift,
                pointmark(p2) - shift, pointmark(p3) - shift);
        if (bmark) {
          fprintf(outfile, "    %d", marker);
        }
        fprintf(outfile, "\n");
        faceloop.sh = shellfacetraverse(subfaces);
      }
    
      // Copy input holelist.
      fprintf(outfile, "\n# part 3: hole list.\n");
      fprintf(outfile, "%d\n", in->numberofholes);
      for (i = 0; i < in->numberofholes; i++) {
        fprintf(outfile, "%d  %g  %g  %g\n", i + in->firstnumber,
                in->holelist[i * 3], in->holelist[i * 3 + 1],
                in->holelist[i * 3 + 2]);
      }
    
      // Copy input regionlist.
      fprintf(outfile, "\n# part 4: region list.\n");
      fprintf(outfile, "%d\n", in->numberofregions);
      for (i = 0; i < in->numberofregions; i++) {
        fprintf(outfile, "%d  %g  %g  %g  %d  %g\n", i + in->firstnumber,
                in->regionlist[i * 5], in->regionlist[i * 5 + 1],
                in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
                in->regionlist[i * 5 + 4]);
      }
    
      fprintf(outfile, "# Generated by %s\n", b->commandline);
      fclose(outfile);
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outmesh2medit()    Write mesh to a .mesh file, which can be read and      //
    //                    rendered by Medit (a free mesh viewer from INRIA).     //
    //                                                                           //
    // You can specify a filename (without suffix) in 'mfilename'.  If you don't //
    // supply a filename (let mfilename be NULL), the default name stored in     //
    // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outmesh2medit(char* mfilename)
    {
      FILE *outfile;
      char mefilename[FILENAMESIZE];
      tetrahedron* tetptr;
      triface tface, tsymface;
      face segloop, checkmark;
      point ptloop, p1, p2, p3, p4;
      long ntets, faces;
      int pointnumber;
      int faceid, marker;
      int i;
    
      if (mfilename != (char *) NULL && mfilename[0] != '\0') {
        strcpy(mefilename, mfilename);
      } else if (b->outfilename[0] != '\0') {
        strcpy(mefilename, b->outfilename);
      } else {
        strcpy(mefilename, "unnamed");
      }
      strcat(mefilename, ".mesh");
    
      if (!b->quiet) {
        printf("Writing %s.\n", mefilename);
      }
      outfile = fopen(mefilename, "w");
      if (outfile == (FILE *) NULL) {
        printf("File I/O Error:  Cannot create file %s.\n", mefilename);
        return;
      }
    
      fprintf(outfile, "MeshVersionFormatted 1\n");
      fprintf(outfile, "\n");
      fprintf(outfile, "Dimension\n");
      fprintf(outfile, "3\n");
      fprintf(outfile, "\n");
    
      fprintf(outfile, "\n# Set of mesh vertices\n");
      fprintf(outfile, "Vertices\n");
      fprintf(outfile, "%ld\n", points->items);
    
      points->traversalinit();
      ptloop = pointtraverse();
      pointnumber = 1;                        // Medit need start number form 1.
      while (ptloop != (point) NULL) {
        // Point coordinates.
        fprintf(outfile, "%.17g  %.17g  %.17g", ptloop[0], ptloop[1], ptloop[2]);
        if (in->numberofpointattributes > 0) {
          // Write an attribute, ignore others if more than one.
          fprintf(outfile, "  %.17g\n", ptloop[3]);
        } else {
          fprintf(outfile, "    0\n");
        }
        setpointmark(ptloop, pointnumber);
        ptloop = pointtraverse();
        pointnumber++;
      }
    
      // Compute the number of faces.
      ntets = tetrahedrons->items - hullsize;
      faces = (ntets * 4l + hullsize) / 2l;
    
      fprintf(outfile, "\n# Set of Triangles\n");
      fprintf(outfile, "Triangles\n");
      fprintf(outfile, "%ld\n", faces);
    
      tetrahedrons->traversalinit();
      tface.tet = tetrahedrontraverse();
      while (tface.tet != (tetrahedron *) NULL) {
        for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
          fsym(tface, tsymface);
          if (ishulltet(tsymface) || 
              (elemindex(tface.tet) < elemindex(tsymface.tet))) {
            p1 = org (tface);
            p2 = dest(tface);
            p3 = apex(tface);
            fprintf(outfile, "%5d  %5d  %5d",
                    pointmark(p1), pointmark(p2), pointmark(p3));
            // Check if it is a subface.
            tspivot(tface, checkmark);
            if (checkmark.sh == NULL) {
              marker = 0;  // It is an inner face. It's marker is 0.
            } else {
              if (in->facetmarkerlist) {
                // The facet marker is given, get it.
                faceid = shellmark(checkmark) - 1;
                marker = in->facetmarkerlist[faceid];
              } else {
                marker = 1; // The default marker for subface is 1.
              }
            }
            fprintf(outfile, "    %d\n", marker);
          }
        }
        tface.tet = tetrahedrontraverse();
      }
    
      fprintf(outfile, "\n# Set of Tetrahedra\n");
      fprintf(outfile, "Tetrahedra\n");
      fprintf(outfile, "%ld\n", ntets);
    
      tetrahedrons->traversalinit();
      tetptr = tetrahedrontraverse();
      while (tetptr != (tetrahedron *) NULL) {
        p1 = (point) tetptr[4];
        p2 = (point) tetptr[5];
        p3 = (point) tetptr[6];
        p4 = (point) tetptr[7];
        fprintf(outfile, "%5d  %5d  %5d  %5d",
                pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
        if (in->numberoftetrahedronattributes > 0) {
          fprintf(outfile, "  %.17g", elemattribute(tetptr, 0));
        } else {
          fprintf(outfile, "  0");
        }
        fprintf(outfile, "\n");
        tetptr = tetrahedrontraverse();
      }
    
      fprintf(outfile, "\nCorners\n");
      fprintf(outfile, "%d\n", in->numberofpoints);
    
      for (i = 0; i < in->numberofpoints; i++) {
        fprintf(outfile, "%4d\n", i + 1);
      }
    
      if (b->plc || b->refine) {
        fprintf(outfile, "\nEdges\n");
        fprintf(outfile, "%ld\n", subsegs->items);
    
        subsegs->traversalinit();
        segloop.sh = shellfacetraverse(subsegs);
        while (segloop.sh != (shellface *) NULL) {
          p1 = sorg(segloop);
          p2 = sdest(segloop);
          fprintf(outfile, "%5d  %5d", pointmark(p1), pointmark(p2));
          marker = shellmark(segloop);
          fprintf(outfile, "    %d\n", marker);
          segloop.sh = shellfacetraverse(subsegs);
        }
      }
    
      fprintf(outfile, "\nEnd\n");
      fclose(outfile);
    }
    
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // outmesh2vtk()    Save mesh to file in VTK Legacy format.                  //
    //                                                                           //
    // This function was contributed by Bryn Llyod from ETH, 2007.               //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetgenmesh::outmesh2vtk(char* ofilename)
    {
      FILE *outfile;
      char vtkfilename[FILENAMESIZE];
      point pointloop;
      tetrahedron* tptr;
      double x, y, z;
      int n1, n2, n3, n4;
      int nnodes = 4;
      int celltype = 10;
    
      int NEL = tetrahedrons->items - hullsize;
      int NN = points->items;
    
      if (ofilename != (char *) NULL && ofilename[0] != '\0') {
        strcpy(vtkfilename, ofilename);
      } else if (b->outfilename[0] != '\0') {
        strcpy(vtkfilename, b->outfilename);
      } else {
        strcpy(vtkfilename, "unnamed");
      }
      strcat(vtkfilename, ".vtk");
    
      if (!b->quiet) {
        printf("Writing %s.\n", vtkfilename);
      }
      outfile = fopen(vtkfilename, "w");
      if (outfile == (FILE *) NULL) {
        printf("File I/O Error:  Cannot create file %s.\n", vtkfilename);
        return;
      }
    
      //always write big endian
      //bool ImALittleEndian = !testIsBigEndian();
    
      fprintf(outfile, "# vtk DataFile Version 2.0\n");
      fprintf(outfile, "Unstructured Grid\n");
      fprintf(outfile, "ASCII\n"); // BINARY
      fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
      fprintf(outfile, "POINTS %d double\n", NN);
    
      points->traversalinit();
      pointloop = pointtraverse();
      for(int id=0; id<NN && pointloop != (point) NULL; id++){
        x = pointloop[0];
        y = pointloop[1];
        z = pointloop[2];
        fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
        pointloop = pointtraverse();
      }
      fprintf(outfile, "\n");
    
      fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
      //NEL rows, each has 1 type id + 4 node id's
     
      tetrahedrons->traversalinit();
      tptr = tetrahedrontraverse();
      //elementnumber = firstindex; // in->firstnumber;
      if (b->order == 2) {
        printf("  Write VTK not implemented for order 2 elements \n");
        return;
      }
      while (tptr != (tetrahedron *) NULL) {
        point p1 = (point) tptr[4];
        point p2 = (point) tptr[5];
        point p3 = (point) tptr[6];
        point p4 = (point) tptr[7];
        n1 = pointmark(p1) - in->firstnumber;
        n2 = pointmark(p2) - in->firstnumber;
        n3 = pointmark(p3) - in->firstnumber;
        n4 = pointmark(p4) - in->firstnumber;
        fprintf(outfile, "%d  %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
        tptr = tetrahedrontraverse();
      }
      fprintf(outfile, "\n");
    
      fprintf(outfile, "CELL_TYPES %d\n", NEL);
      for(int tid=0; tid<NEL; tid++){
        fprintf(outfile, "%d\n", celltype);
      }
      fprintf(outfile, "\n");
    
      fclose(outfile);
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// output_cxx ///////////////////////////////////////////////////////////////
    
    //// main_cxx /////////////////////////////////////////////////////////////////
    ////                                                                       ////
    ////                                                                       ////
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetrahedralize()    The interface for users using TetGen library to       //
    //                     generate tetrahedral meshes with all features.        //
    //                                                                           //
    // The sequence is roughly as follows.  Many of these steps can be skipped,  //
    // depending on the command line switches.                                   //
    //                                                                           //
    // - Initialize constants and parse the command line.                        //
    // - Read the vertices from a file and either                                //
    //   - tetrahedralize them (no -r), or                                       //
    //   - read an old mesh from files and reconstruct it (-r).                  //
    // - Insert the boundary segments and facets (-p or -Y).                     //
    // - Read the holes (-p), regional attributes (-pA), and regional volume     //
    //   constraints (-pa).  Carve the holes and concavities, and spread the     //
    //   regional attributes and volume constraints.                             //
    // - Enforce the constraints on minimum quality bound (-q) and maximum       //
    //   volume (-a), and a mesh size function (-m).                             //
    // - Optimize the mesh wrt. specified quality measures (-O and -o).          //
    // - Write the output files and print the statistics.                        //
    // - Check the consistency of the mesh (-C).                                 //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
                        tetgenio *addin, tetgenio *bgmin)
    {
      tetgenmesh m;
      clock_t tv[17]; // Timing informations (defined in time.h)
    
      tv[0] = clock();
     
      m.b = b;
      m.in = in;
    
      if ((bgmin != NULL) && 
          ((bgmin->numberofpoints > 0) && (bgmin->pointmtrlist != NULL))) {
        m.bgm = new tetgenmesh(); // Create an empty background mesh.
        m.bgm->b = b;
        m.bgm->in = bgmin;
      }
    
    #ifdef INEXACT_GEOM_PRED
      if (!b->quiet) {
        printf("Using inexact geometric predicates.\n");
      }
    #else
      exactinit();
    #endif
    
      m.initializepools();
      m.transfernodes();
    
      tv[1] = clock();
    
      if (b->refine) {
        m.reconstructmesh();
      } else { // b->plc
        if (!b->diagnose) {
          m.incrementaldelaunay(tv[16]);
        }
      }
    
      tv[2] = clock();
    
      if (!b->quiet) {
        if (b->refine) {
          printf("Mesh reconstruction seconds:  %g\n", 
                 (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
        } else {
          if (!b->diagnose) {
            printf("Delaunay seconds:  %g\n", 
                   (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
            if (b->verbose) {
              printf("  Point sorting seconds:  %g\n",
                     (tv[16] - tv[1]) / (REAL) CLOCKS_PER_SEC);
    #ifdef WITH_RUNTIME_COUNTERS
              printf("  Point location seconds:  %g\n", 
                     m.t_ptloc / (REAL) CLOCKS_PER_SEC);
              printf("  Point insertion seconds:  %g\n", 
                     m.t_ptinsert / (REAL) CLOCKS_PER_SEC);
    #endif
            }
          }
        }
      }
    
      if (b->plc) {
        m.meshsurface();
      }
    
      tv[3] = clock();
    
      if (!b->quiet) {
        if (b->plc) {
          printf("Surface mesh seconds:  %g\n",
                 (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if (b->plc && b->diagnose) { // -d
        m.detectinterfaces();
    
        tv[4] = clock();
    
        if (!b->quiet) {
          printf("Self-intersection seconds:  %g\n",
                 (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
        }
    
        // Only output when self-intersecting faces exist.
        if (m.subfaces->items > 0l) {
          m.outnodes(out);
          m.outsubfaces(out);
        }
    
        return;
      }
    
      if (b->plc) {
        if (b->nobisect) { // with -Y option
          m.recoverboundary(tv[15]);
        } else {
          m.constraineddelaunay(tv[15]);
        }
      }
    
      tv[4] = clock();
    
      if (!b->quiet) {
        if (b->plc) {
          printf("Boundary recovery seconds:  %g\n",  
                 (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
          if (b->verbose) {
            printf("  Segment recovery seconds:  %g\n",
                   (tv[15] - tv[3]) / (REAL) CLOCKS_PER_SEC);
            printf("  Facet recovery seconds:  %g\n",
                   (tv[4] - tv[15]) / (REAL) CLOCKS_PER_SEC);
          }
        }
      }
    
      if (b->plc && !b->convex) {
        m.carveholes();
      }
    
      tv[5] = clock();
    
      if (!b->quiet) {
        if (b->plc && !b->convex) {
          printf("Exterior tets removal seconds:  %g\n", 
                 (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if (b->plc && b->nobisect) { 
        m.suppresssteinerpoints();
      }
    
      tv[6] = clock();
    
      if (!b->quiet) {
        if (b->plc && b->nobisect) {
          printf("Steiner suppression seconds:  %g\n",
                 (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if (b->plc && b->nobisect) {
        m.recoverdelaunay(); 
      }
    
      tv[7] = clock();
    
      if (!b->quiet) {
        if (b->plc && b->nobisect) {
          printf("Delaunay recovery seconds:  %g\n", 
                 (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) {
        m.bgm->initializepools();
        m.bgm->transfernodes();
        m.bgm->reconstructmesh();
      }
    
      tv[8] = clock();
    
      if (!b->quiet) {
        if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) {
          printf("Background mesh reconstruct seconds:  %g\n",
                 (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) {
        m.interpolatemeshsize();
      }
    
      tv[9] = clock();
    
      if (!b->quiet) {
        if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) {
          printf("Size interpolating seconds:  %g\n",
                 (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if ((b->plc || b->refine) && b->insertaddpoints) { // -i
        if ((addin != NULL) && (addin->numberofpoints > 0)) {
          m.insertconstrainedpoints(addin); 
        }
      }
    
      tv[10] = clock();
    
      if (!b->quiet) {
        if ((b->plc || b->refine) && b->insertaddpoints) {
          if ((addin != NULL) && (addin->numberofpoints > 0)) {
            printf("Constrained points seconds:  %g\n", 
                   (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC);
          }
        }
      }
    
    
      tv[11] = clock();
    
    
      if ((b->plc || b->refine) && b->quality) {
        m.delaunayrefinement();
      }
    
      tv[12] = clock();
    
      if (!b->quiet) {
        if ((b->plc || b->refine) && b->quality) {
          printf("Refinement seconds:  %g\n",
                 (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if ((b->plc || b->refine) && (b->optlevel > 0)) {
        m.optimizemesh(1);
      }
    
      tv[13] = clock();
    
      if (!b->quiet) {
        if ((b->plc || b->refine) && (b->optlevel > 0)) {
          printf("Optimization seconds:  %g\n",
                 (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC);
        }
      }
    
      if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
          || (b->refine && (in->numberofcorners == 10)))) {
        m.jettisonnodes();
      }
    
    
      if (!b->quiet) {
        printf("\n");
      }
    
      if (out != (tetgenio *) NULL) {
        out->firstnumber = in->firstnumber;
        out->mesh_dim = in->mesh_dim;
      }
    
      if (b->nonodewritten || b->noiterationnum) {
        if (!b->quiet) {
          printf("NOT writing a .node file.\n");
        }
      } else {
        m.outnodes(out);
      }
    
      if (b->noelewritten == 1) {
        if (!b->quiet) {
          printf("NOT writing an .ele file.\n");
        }
        m.numberedges();
      } else {
        if (m.tetrahedrons->items > 0l) {
          m.outelements(out);
        }
      }
    
      if (b->nofacewritten) {
        if (!b->quiet) {
          printf("NOT writing an .face file.\n");
        }
      } else {
        if (b->facesout) {
          if (m.tetrahedrons->items > 0l) {
            m.outfaces(out);  // Output all faces.
          }
        } else {
          if (b->plc || b->refine) {
            if (m.subfaces->items > 0l) {
              m.outsubfaces(out); // Output boundary faces.
            }
          } else {
            if (m.tetrahedrons->items > 0l) {
              m.outhullfaces(out); // Output convex hull faces.
            }
          }
        }
      }
    
    
      if (b->edgesout) {
        if (b->edgesout > 1) {
          m.outedges(out); // -ee, output all mesh edges. 
        } else {
          m.outsubsegments(out); // -e, only output subsegments.
        }
      }
    
      if ((b->plc || b->refine) && b->metric) { // -m
        m.outmetrics(out);
      }
    
      if (!out && b->plc && 
          ((b->object == tetgenbehavior::OFF) ||
           (b->object == tetgenbehavior::PLY) ||
           (b->object == tetgenbehavior::STL))) {
        m.outsmesh(b->outfilename);
      }
    
      if (!out && b->meditview) {
        m.outmesh2medit(b->outfilename); 
      }
    
    
      if (!out && b->vtkview) {
        m.outmesh2vtk(b->outfilename); 
      }
    
      if (b->neighout) {
        m.outneighbors(out);
      }
    
      if ((!(b->plc || b->refine)) && b->voroout) {
        m.outvoronoi(out);
      }
    
    
      tv[14] = clock();
    
      if (!b->quiet) {
        printf("\nOutput seconds:  %g\n",
               (tv[14] - tv[13]) / (REAL) CLOCKS_PER_SEC);
        printf("Total running seconds:  %g\n",
               (tv[14] - tv[0]) / (REAL) CLOCKS_PER_SEC);
      }
    
      if (b->docheck) {
        m.checkmesh(0);
        if (b->plc || b->refine) {
          m.checkshells();
          m.checksegments();
        }
        if (b->docheck > 1) {
          m.checkdelaunay();
        }
      }
    
      if (!b->quiet) {
        m.statistics();
      }
    }
    
    #ifndef TETLIBRARY
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // main()    The entrance for running TetGen from command line.              //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    int main(int argc, char *argv[])
    
    #else // with TETLIBRARY
    
    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           //
    // tetrahedralize()    The entrance for calling TetGen from another program. //
    //                                                                           //
    ///////////////////////////////////////////////////////////////////////////////
    
    void tetrahedralize(char *switches, tetgenio *in, tetgenio *out, 
                        tetgenio *addin, tetgenio *bgmin)
    
    #endif // not TETLIBRARY
    
    {
      tetgenbehavior b;
    
    #ifndef TETLIBRARY
    
      tetgenio in, addin, bgmin;
      
      if (!b.parse_commandline(argc, argv)) {
        terminatetetgen(10);
      }
    
      // Read input files.
      if (b.refine) { // -r
        if (!in.load_tetmesh(b.infilename, (int) b.object)) {
          terminatetetgen(10);
        }
      } else { // -p
        if (!in.load_plc(b.infilename, (int) b.object)) {
          terminatetetgen(10);
        }
      }
      if (b.insertaddpoints) { // -i
        // Try to read a .a.node file.
        addin.load_node(b.addinfilename);
      }
      if (b.metric) { // -m
        // Try to read a background mesh in files .b.node, .b.ele.
        bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
      }
    
      tetrahedralize(&b, &in, NULL, &addin, &bgmin);
    
      return 0;
    
    #else // with TETLIBRARY
    
      if (!b.parse_commandline(switches)) {
        terminatetetgen(10);
      }
      tetrahedralize(&b, in, out, addin, bgmin);
    
    #endif // not TETLIBRARY
    }
    
    ////                                                                       ////
    ////                                                                       ////
    //// main_cxx /////////////////////////////////////////////////////////////////