diff --git a/contrib/Tetgen1.5/LICENSE b/contrib/Tetgen1.5/LICENSE
index f291c306fb843c223b0ccc95f19d968806802735..e253c3d965ddda3797c1ce80fedde3c84c54ecd4 100644
--- a/contrib/Tetgen1.5/LICENSE
+++ b/contrib/Tetgen1.5/LICENSE
@@ -1,73 +1,666 @@
 TetGen License
 --------------
 
-The software (TetGen) is licensed under the terms of the  MIT  license
-with the following exceptions:
+TetGen is distributed under a dual licensing scheme. You can
+redistribute it and/or modify it under the terms of the GNU Affero
+General Public License as published by the Free Software Foundation,
+either version 3 of the License, or (at your option) any later
+version. A copy of the GNU Affero General Public License is reproduced
+below.
 
-Distribution of  modified  versions  of this code is permissible UNDER
-THE CONDITION THAT  THIS CODE AND ANY MODIFICATIONS  MADE TO IT IN THE
-SAME SOURCE FILES  tetgen.h AND tetgen.cxx  REMAIN UNDER  COPYRIGHT OF
-THE  ORIGINAL AUTHOR,  BOTH  SOURCE AND OBJECT  CODE  ARE MADE  FREELY
-AVAILABLE  WITHOUT   CHARGE,   AND  CLEAR   NOTICE  IS  GIVEN  OF  THE 
-MODIFICATIONS.
+If the terms and conditions of the AGPL v.3. would prevent you from
+using TetGen, please consider the option to obtain a commercial
+license for a fee. These licenses are offered by the Weierstrass
+Institute for Applied Analysis and Stochastics (WIAS). As a rule,
+licenses are provided "as-is", unlimited in time for a one time
+fee. Please send corresponding requests to:
+tetgen@wias-berlin.de. Please do not forget to include some
+description of your company and the realm of its activities.
 
-Distribution of this code for  any  commercial purpose  is permissible
-ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER.
+=====================================================================
+GNU AFFERO GENERAL PUBLIC LICENSE
 
-The full  license text is reproduced below.
+Version 3, 19 November 2007
 
-This means that TetGen is no free software, but for private, research,
-and  educational purposes it  can be  used at  absolutely no  cost and
-without further arrangements.
+Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
 
+Preamble
 
-For details, see http://tetgen.org
+The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
 
-==============================================================================
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains
+free software for all its users.
 
-TetGen
-A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator
-Version 1.5 (Released on February 21, 2012).
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
 
-Copyright 2002 -- 2012 
+Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
 
-Hang Si
-Research Group of Numerical Mathematics and Scientific Computing
-Weierstrass Institute for Applied Analysis and Stochastics
-Mohrenstr. 39
-10117 Berlin, Germany
+A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come
+about. The GNU General Public License permits making a modified
+version and letting the public access it on a server without ever
+releasing its source code to the public.
 
-Phone: +49 (0) 30-20372-446   Fax: +49 (0) 30-2044975
-EMail: <si@wias-berlin.de>
-Web Site: http://www.wias-berlin.de/~si
+The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
 
-Permission is hereby granted, free  of charge, to any person obtaining
-a  copy  of this  software  and  associated  documentation files  (the
-"Software"), to  deal in  the Software without  restriction, including
-without limitation  the rights to  use, copy, modify,  merge, publish,
-distribute,  sublicense and/or  sell copies  of the  Software,  and to
-permit persons to whom the Software  is furnished to do so, subject to
-the following conditions:
+An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing
+under this license.
 
-Distribution of  modified  versions  of this code is permissible UNDER
-THE CONDITION THAT  THIS CODE AND ANY MODIFICATIONS  MADE TO IT IN THE
-SAME SOURCE FILES  tetgen.h AND tetgen.cxx  REMAIN UNDER  COPYRIGHT OF
-THE  ORIGINAL AUTHOR,  BOTH  SOURCE AND OBJECT  CODE  ARE MADE  FREELY
-AVAILABLE  WITHOUT   CHARGE,   AND  CLEAR   NOTICE  IS  GIVEN  OF  THE 
-MODIFICATIONS.
+The precise terms and conditions for copying, distribution and
+modification follow.
 
-Distribution of this code for  any  commercial purpose  is permissible
-ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER.
+TERMS AND CONDITIONS
 
-The  above  copyright  notice  and  this permission  notice  shall  be
-included in all copies or substantial portions of the Software.
+0. Definitions.
 
-THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
-EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT  SHALL THE AUTHORS OR COPYRIGHT HOLDERS  BE LIABLE FOR ANY
-CLAIM, DAMAGES OR  OTHER LIABILITY, WHETHER IN AN  ACTION OF CONTRACT,
-TORT  OR OTHERWISE, ARISING  FROM, OUT  OF OR  IN CONNECTION  WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"This License" refers to version 3 of the GNU Affero General Public
+License.
 
-==============================================================================
\ No newline at end of file
+"Copyright" also means copyright-like laws that apply to other kinds
+of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of
+an exact copy. The resulting work is called a "modified version" of
+the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user
+through a computer network, with no transfer of a copy, is not
+conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to
+the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+1. Source Code.
+
+The "source code" for a work means the preferred form of the work for
+making modifications to it. "Object code" means any non-source form of
+a work.
+
+A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can
+regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same
+work.
+
+2. Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey,
+without conditions so long as your license otherwise remains in
+force. You may convey covered works to others for the sole purpose of
+having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below. Sublicensing is not allowed; section 10 makes
+it unnecessary.
+
+3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such
+circumvention is effected by exercising rights under this License with
+respect to the covered work, and you disclaim any intention to limit
+operation or modification of the work as a means of enforcing, against
+the work's users, your or third parties' legal rights to forbid
+circumvention of technological measures.
+
+4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these
+conditions:
+
+a) The work must carry prominent notices stating that you modified it,
+and giving a relevant date.  b) The work must carry prominent notices
+stating that it is released under this License and any conditions
+added under section 7. This requirement modifies the requirement in
+section 4 to "keep intact all notices".  c) You must license the
+entire work, as a whole, under this License to anyone who comes into
+possession of a copy. This License will therefore apply, along with
+any applicable section 7 additional terms, to the whole of the work,
+and all its parts, regardless of how they are packaged. This License
+gives no permission to license the work in any other way, but it does
+not invalidate such permission if you have separately received it.  d)
+If the work has interactive user interfaces, each must display
+Appropriate Legal Notices; however, if the Program has interactive
+interfaces that do not display Appropriate Legal Notices, your work
+need not make them do so.  A compilation of a covered work with other
+separate and independent works, which are not by their nature
+extensions of the covered work, and which are not combined with it
+such as to form a larger program, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the compilation and
+its resulting copyright are not used to limit the access or legal
+rights of the compilation's users beyond what the individual works
+permit. Inclusion of a covered work in an aggregate does not cause
+this License to apply to the other parts of the aggregate.
+
+6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of
+sections 4 and 5, provided that you also convey the machine-readable
+Corresponding Source under the terms of this License, in one of these
+ways:
+
+a) Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by the
+Corresponding Source fixed on a durable physical medium customarily
+used for software interchange.  b) Convey the object code in, or
+embodied in, a physical product (including a physical distribution
+medium), accompanied by a written offer, valid for at least three
+years and valid for as long as you offer spare parts or customer
+support for that product model, to give anyone who possesses the
+object code either (1) a copy of the Corresponding Source for all the
+software in the product that is covered by this License, on a durable
+physical medium customarily used for software interchange, for a price
+no more than your reasonable cost of physically performing this
+conveying of source, or (2) access to copy the Corresponding Source
+from a network server at no charge.  c) Convey individual copies of
+the object code with a copy of the written offer to provide the
+Corresponding Source. This alternative is allowed only occasionally
+and noncommercially, and only if you received the object code with
+such an offer, in accord with subsection 6b.  d) Convey the object
+code by offering access from a designated place (gratis or for a
+charge), and offer equivalent access to the Corresponding Source in
+the same way through the same place at no further charge. You need not
+require recipients to copy the Corresponding Source along with the
+object code. If the place to copy the object code is a network server,
+the Corresponding Source may be on a different server (operated by you
+or a third party) that supports equivalent copying facilities,
+provided you maintain clear directions next to the object code saying
+where to find the Corresponding Source. Regardless of what server
+hosts the Corresponding Source, you remain obligated to ensure that it
+is available for as long as needed to satisfy these requirements.  e)
+Convey the object code using peer-to-peer transmission, provided you
+inform other peers where the object code and Corresponding Source of
+the work are being offered to the general public at no charge under
+subsection 6d.  A separable portion of the object code, whose source
+code is excluded from the Corresponding Source as a System Library,
+need not be included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal,
+family, or household purposes, or (2) anything designed or sold for
+incorporation into a dwelling. In determining whether a product is a
+consumer product, doubtful cases shall be resolved in favor of
+coverage. For a particular product received by a particular user,
+"normally used" refers to a typical or common use of that class of
+product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected
+to use, the product. A product is a consumer product regardless of
+whether the product has substantial commercial, industrial or
+non-consumer uses, unless such uses represent the only significant
+mode of use of the product.
+
+"Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to
+install and execute modified versions of a covered work in that User
+Product from a modified version of its Corresponding Source. The
+information must suffice to ensure that the continued functioning of
+the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or
+updates for a work that has been modified or installed by the
+recipient, or for the User Product in which it has been modified or
+installed. Access to a network may be denied when the modification
+itself materially and adversely affects the operation of the network
+or violates the rules and protocols for communication across the
+network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its
+conditions. Additional permissions that are applicable to the entire
+Program shall be treated as though they were included in this License,
+to the extent that they are valid under applicable law. If additional
+permissions apply only to part of the Program, that part may be used
+separately under those permissions, but the entire Program remains
+governed by this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders
+of that material) supplement the terms of this License with terms:
+
+a) Disclaiming warranty or limiting liability differently from the
+terms of sections 15 and 16 of this License; or b) Requiring
+preservation of specified reasonable legal notices or author
+attributions in that material or in the Appropriate Legal Notices
+displayed by works containing it; or c) Prohibiting misrepresentation
+of the origin of that material, or requiring that modified versions of
+such material be marked in reasonable ways as different from the
+original version; or d) Limiting the use for publicity purposes of
+names of licensors or authors of the material; or e) Declining to
+grant rights under trademark law for use of some trade names,
+trademarks, or service marks; or f) Requiring indemnification of
+licensors and authors of that material by anyone who conveys the
+material (or modified versions of it) with contractual assumptions of
+liability to the recipient, for any liability that these contractual
+assumptions directly impose on those licensors and authors.  All other
+non-permissive additional terms are considered "further restrictions"
+within the meaning of section 10. If the Program as you received it,
+or any part of it, contains a notice stating that it is governed by
+this License along with a term that is a further restriction, you may
+remove that term. If a license document contains a further restriction
+but permits relicensing or conveying under this License, you may add
+to a covered work material governed by the terms of that license
+document, provided that the further restriction does not survive such
+relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions; the
+above requirements apply either way.
+
+8. Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run
+a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned
+or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on
+the non-exercise of one or more of the rights that are specifically
+granted under this License. You may not convey a covered work if you
+are a party to an arrangement with a third party that is in the
+business of distributing software, under which you make payment to the
+third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties
+who would receive the covered work from you, a discriminatory patent
+license (a) in connection with copies of the covered work conveyed by
+you (or copies made from those copies), or (b) primarily for and in
+connection with specific products or compilations that contain the
+covered work, unless you entered into that arrangement, or that patent
+license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under
+this License and any other pertinent obligations, then as a
+consequence you may not convey it at all. For example, if you agree to
+terms that obligate you to collect a royalty for further conveying
+from those to whom you convey the Program, the only way you could
+satisfy both those terms and this License would be to refrain entirely
+from conveying the Program.
+
+13. Remote Network Interaction; Use with the GNU General Public
+License.
+
+Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your
+version supports such interaction) an opportunity to receive the
+Corresponding Source of your version by providing access to the
+Corresponding Source from a network server at no charge, through some
+standard or customary means of facilitating copying of software. This
+Corresponding Source shall include the Corresponding Source for any
+work covered by version 3 of the GNU General Public License that is
+incorporated pursuant to the following paragraph.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions
+of the GNU Affero General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever
+published by the Free Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions
+of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
+CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
+NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
+TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
+PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively state
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it
+    does.> Copyright (C) <year> <name of author>
+
+    This program is free software: you can redistribute it and/or
+    modify it under the terms of the GNU Affero General Public License
+    as published by the Free Software Foundation, either version 3 of
+    the License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public
+    License along with this program.  If not, see
+    <http://www.gnu.org/licenses/>.  Also add information on how to
+    contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for
+the specific requirements.
+
+You should also get your employer (if you work as a programmer) or
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. For more information on this, and how to apply and follow
+the GNU AGPL, see <http://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/contrib/Tetgen1.5/README b/contrib/Tetgen1.5/README
index 34b6f2372c8655310babf0ef24207086cd80d5cb..bc5cfa04c0e901cb5c5890b9783a781fa31eda1a 100644
--- a/contrib/Tetgen1.5/README
+++ b/contrib/Tetgen1.5/README
@@ -1,4 +1,4 @@
-This is TetGen version 1.5 (released on February 21, 2012)
+This is TetGen version 1.5 (released on November 4, 2013)
 
 Please see the documentation of TetGen for compiling and using TetGen.
 It is available at the following link:
diff --git a/contrib/Tetgen1.5/example.poly b/contrib/Tetgen1.5/example.poly
index 9394d8dbbbca0d27498645e0926ee1737be161f7..e924956668a3402fd15bfb21f236c4161963d152 100644
--- a/contrib/Tetgen1.5/example.poly
+++ b/contrib/Tetgen1.5/example.poly
@@ -1,139 +1,84 @@
-#
-# example.poly - Sample file of TetGen.
-#
-# A .poly file describes a piecewise linear complex (PLC)
-# This file represents a compensated magic tee junction.
-#
-# The source file is from: Vali Catina <catina@uni-bremen.de>
-#
-
-# Part 1 - node list
-56  3  0  0
-   1    -13.716000000000001  -5.0800000000000001  0
-   2    -13.716000000000001  5.0800000000000001  0
-   3    -11.43  5.0800000000000001  0
-   4    11.43  -5.0800000000000001  0
-   5    11.43  7.3659999999999997  0
-   6    -11.43  7.3659999999999997  0
-   7    0.95105651629515364  -0.37999999999999989  0
-   8    -0.95105651629515364  -0.37999999999999989  0
-   9    -0.95105651629515364  4.6200000000000001  0
-  10    0.95105651629515364  4.6200000000000001  0
-  11    -0.95105651629515353  4.6200000000000001  -0.30901699437494756
-  12    -0.58778525229247303  4.6200000000000001  -0.80901699437494756
-  13    1.2246063538223773e-16  4.6200000000000001  -1
-  14    0.58778525229247325  4.6200000000000001  -0.80901699437494734
-  15    0.95105651629515364  4.6200000000000001  -0.30901699437494734
-  16    -0.95105651629515353  -0.37999999999999989  -0.30901699437494756
-  17    -0.58778525229247303  -0.37999999999999989  -0.80901699437494756
-  18    1.2246063538223773e-16  -0.37999999999999989  -1
-  19    0.58778525229247325  -0.37999999999999989  -0.80901699437494734
-  20    0.95105651629515364  -0.37999999999999989  -0.30901699437494734
-  21    -1.5874999999999999  -0.37999999999999989  -2.9160938800395356e-16
-  22    -1.5098022196185561  -0.37999999999999989  -0.49056447857022928
-  23    -1.2843144785702287  -0.37999999999999989  -0.93310908801430126
-  24    -0.93310908801430081  -0.37999999999999989  -1.2843144785702292
-  25    -0.49056447857022878  -0.37999999999999989  -1.5098022196185563
-  26    1.9440625866930238e-16  -0.37999999999999989  -1.5874999999999999
-  27    0.49056447857022917  -0.37999999999999989  -1.5098022196185561
-  28    0.93310908801430115  -0.37999999999999989  -1.284314478570229
-  29    1.284314478570229  -0.37999999999999989  -0.93310908801430092
-  30    1.5098022196185563  -0.37999999999999989  -0.49056447857022889
-  31    1.5874999999999999  -0.37999999999999989  9.7203129334651192e-17
-  32    -1.5874999999999999  -5.0800000000000001  -2.9160938800395356e-16
-  33    -1.5098022196185561  -5.0800000000000001  -0.49056447857022928
-  34    -1.2843144785702287  -5.0800000000000001  -0.93310908801430126
-  35    -0.93310908801430081  -5.0800000000000001  -1.2843144785702292
-  36    -0.49056447857022878  -5.0800000000000001  -1.5098022196185563
-  37    1.9440625866930238e-16  -5.0800000000000001  -1.5874999999999999
-  38    0.49056447857022917  -5.0800000000000001  -1.5098022196185561
-  39    0.93310908801430115  -5.0800000000000001  -1.284314478570229
-  40    1.284314478570229  -5.0800000000000001  -0.93310908801430092
-  41    1.5098022196185563  -5.0800000000000001  -0.49056447857022889
-  42    1.5874999999999999  -5.0800000000000001  9.7203129334651192e-17
-  43    -11.43  7.3659999999999997  -5.0800000000000001
-  44    11.43  7.3659999999999997  -5.0800000000000001
-  45    -11.43  5.0800000000000001  -5.0800000000000001
-  46    11.43  5.0800000000000001  -5.0800000000000001
-  47    -13.716000000000001  5.0800000000000001  -11.43
-  48    -13.716000000000001  -5.0800000000000001  -11.43
-  49    -11.43  -5.0800000000000001  -11.43
-  50    -11.43  5.0800000000000001  -11.43
-  51    -11.43  -5.0800000000000001  -13.715999999999999
-  52    11.43  -5.0800000000000001  -13.715999999999999
-  53    11.43  5.0800000000000001  -13.715999999999999
-  54    -11.43  5.0800000000000001  -13.715999999999999
-
-55    -6.6628777242868491  -0.9950764223207208  -6.66287772428685
-56    4.2067426959563958  0.1964514680670118  -5.7864151699132815
-
-# Part 2 - facet list
-30 1
-1 0  2
-14 1 2 3 6 5 4 42 31 7 10 9 8 21 32
-1 0  1
-7 9 10 15 14 13 12 11
-1 0  1
-4 8 9 11 16
-1 0  1
-4 11 12 17 16
-1 0  1
-4 12 13 18 17
-1 0  1
-4 13 14 19 18
-1 0  1
-4 14 15 20 19
-1 0  1
-4 10 7 20 15
-1 0  3
-18 7 31 30 29 28 27 26 25 24 23 22 21 8 16 17 18 19 20
-1 0  1
-4 21 22 33 32
-1 0  1
-4 22 23 34 33
-1 0  1
-4 23 24 35 34
-1 0  1
-4 24 25 36 35
-1 0  1
-4 25 26 37 36
-1 0  1
-4 26 27 38 37
-1 0  1
-4 27 28 39 38
-1 0  1
-4 28 29 40 39
-1 0  1
-4 29 30 41 40
-1 0  1
-4 30 31 42 41
-1 0  1
-4 43 45 46 44
-1 0  1
-4 5 6 43 44
-1 0  1
-6 4 5 44 46 53 52
-1 0  1
-4 6 3 45 43
-1 0  1
-4 47 48 49 50
-1 0  1
-8 3 2 47 50 54 53 46 45
-1 0  4
-17 42 4 52 51 49 48 1 32 33 34 35 36 37 38 39 40 41
-1 0  1
-4 2 1 48 47
-1 0  1
-4 50 49 51 54
-1 0  1
-4 54 51 52 53
-
-# The following facet is a single segment with marker -1
-1  0  -1
-2  55 56
-
-# Part 3 - hole list
-0
-
-# Part 4 - region list
-0
+28  3  0  1
+1  0  0  0  1
+2  2  0  0  1
+3  2  2  0  1
+4  0  2  0  1
+5  0  0  4  9
+6  2  0  4  9
+7  2  2  3  9
+8  0  2  3  9
+9  0  0  5  2
+10  2  0  5  2
+11  2  2  5  2
+12  0  2  5  2
+13  0.25  0.25  0.5  4
+14  1.75  0.25  0.5  4
+15  1.75  1.5  0.5  4
+16  0.25  1.5  0.5  4
+17  0.25  0.25  1  4
+18  1.75  0.25  1  4
+19  1.75  1.5  1  4
+20  0.25  1.5  1  4
+21  0.25  0  2  4
+22  1.75  0  2  4
+23  1.75  1.5  2  4
+24  0.25  1.5  2  4
+25  0.25  0  2.5  4
+26  1.75  0  2.5  4
+27  1.75  1.5  2.5  4
+28  0.25  1.5  2.5  4
+23  1
+1  0  1  # 1
+4    1  2  3  4
+1  0  9  # 2
+4    5  6  7  8
+2  1  3  # 3
+4    1  2  6  5
+4    21  22  26  25
+1  1  0  2.25
+1  0  3  # 4
+4    2  3  7  6
+1  0  3  # 5
+4    3  4  8  7
+1  0  3  # 6
+4    4  1  5  8
+1  0  2  # 7
+4    9  10  11  12
+1  0  3  # 8
+4    9  10  6  5
+1  0  3  # 9
+4    10  11  7  6
+1  0  3  # 10
+4    11  12  8  7
+1  0  3  # 11
+4    12  9  5  8
+1  0  4  # 12
+4    13  14  15  16
+1  0  4  # 13
+4    17  18  19  20
+1  0  4  # 14
+4    13  14  18  17
+1  0  4  # 15
+4    14  15  19  18
+1  0  4  # 16
+4    15  16  20  19
+1  0  4  # 17
+4    16  13  17  20
+1  0  4  # 18
+4    21  22  23  24
+1  0  4  # 19
+4    25  26  27  28
+1  0  4  # 20
+4    21  22  26  25
+1  0  4  # 21
+4    22  23  27  26
+1  0  4  # 22
+4    23  24  28  27
+1  0  4  # 23
+4    24  21  25  28
+2
+1  1  0.4  2.25
+2  1  0.4  0.75
+2
+1  1  0.25  0.1  10  0.001
+2  1  0.5  4  20  0.01
diff --git a/contrib/Tetgen1.5/makefile b/contrib/Tetgen1.5/makefile
index 5c886a3aeef3c494e7dd73705f07d7dc747021c5..b3b131cfef2767bcad4610b5a3cd50488a0f80a6 100644
--- a/contrib/Tetgen1.5/makefile
+++ b/contrib/Tetgen1.5/makefile
@@ -19,11 +19,9 @@ CXX = g++
 # -O2, -O3 ... to find the best optimization level.
 # ===================================================================
 
-CXXFLAGS = -g
+CXXFLAGS = -O3
 
-# PREDCXXFLAGS is for compiling J. Shewchuk's predicates. It should
-# always be equal to -O0 (no optimization). Otherwise, TetGen may not
-# work properly.
+# PREDCXXFLAGS is for compiling J. Shewchuk's predicates. 
 
 PREDCXXFLAGS = -O0
 
@@ -38,14 +36,7 @@ PREDCXXFLAGS = -O0
 #   down the speed of TetGen.  They can be skipped by define the -DNDEBUG
 #   switch.
 
-SWITCHES = -Wall -DSELF_CHECK
-
-# SWITCHES = -Wall -Wabi -Wctor-dtor-privacy \
-#            -Woverloaded-virtual -Wno-pmf-conversions -Wsign-promo \
-#            -Wsynth  -Wchar-subscripts -Wconversion -Wsign-compare \
-#            -Wcomment  -Wimplicit -Wmissing-braces -Wparentheses \
-#            -Wreturn-type -Wswitch -Wswitch-default \
-#            -Wswitch-enum -Wtrigraphs -W -DSELF_CHECK
+SWITCHES = 
 
 # RM should be set to the name of your favorite rm (file deletion program).
 
diff --git a/contrib/Tetgen1.5/predicates.cxx b/contrib/Tetgen1.5/predicates.cxx
index 4120704c3521a80f27aa144feb1387ccf78c66a2..33817d7999cf04ee831bcae75e053a39d9b783cb 100644
--- a/contrib/Tetgen1.5/predicates.cxx
+++ b/contrib/Tetgen1.5/predicates.cxx
@@ -125,6 +125,13 @@
 
 #include "tetgen.h"            // Defines the symbol REAL (float or double).
 
+#ifdef USE_CGAL_PREDICATES
+  #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+  typedef CGAL::Exact_predicates_inexact_constructions_kernel cgalEpick;
+  typedef cgalEpick::Point_3 Point;
+  cgalEpick cgal_pred_obj;
+#endif // #ifdef USE_CGAL_PREDICATES
+
 /* On some machines, the exact arithmetic routines might be defeated by the  */
 /*   use of internal extended precision floating-point registers.  Sometimes */
 /*   this problem can be fixed by defining certain values to be volatile,    */
@@ -149,8 +156,8 @@
 /*   which is disastrously slow.  A faster way on IEEE machines might be to  */
 /*   mask the appropriate bit, but that's difficult to do in C.              */
 
-#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
-/* #define Absolute(a)  fabs(a) */
+//#define Absolute(a)  ((a) >= 0.0 ? (a) : -(a))
+#define Absolute(a)  fabs(a)
 
 /* Many of the operations are broken up into two pieces, a main part that    */
 /*   performs an approximate operation, and a "tail" that computes the       */
@@ -375,271 +382,144 @@ static REAL o3derrboundA, o3derrboundB, o3derrboundC;
 static REAL iccerrboundA, iccerrboundB, iccerrboundC;
 static REAL isperrboundA, isperrboundB, isperrboundC;
 
-/*****************************************************************************/
-/*                                                                           */
-/*  doubleprint()   Print the bit representation of a double.                */
-/*                                                                           */
-/*  Useful for debugging exact arithmetic routines.                          */
-/*                                                                           */
-/*****************************************************************************/
+// Options to choose types of geometric computtaions. 
+// Added by H. Si, 2012-08-23.
+static int  _use_inexact_arith; // -X option.
+static int  _use_static_filter; // Default option, disable it by -X1
+
+// Static filters for orient3d() and insphere(). 
+// They are pre-calcualted and set in exactinit().
+// Added by H. Si, 2012-08-23.
+static REAL o3dstaticfilter;
+static REAL ispstaticfilter;
+
+
+
+// The following codes were part of "IEEE 754 floating-point test software"
+//          http://www.math.utah.edu/~beebe/software/ieee/
+// The original program was "fpinfo2.c".
 
-/*
-void doubleprint(number)
-double number;
+double fppow2(int n)
 {
-  unsigned long long no;
-  unsigned long long sign, expo;
-  int exponent;
-  int i, bottomi;
-
-  no = *(unsigned long long *) &number;
-  sign = no & 0x8000000000000000ll;
-  expo = (no >> 52) & 0x7ffll;
-  exponent = (int) expo;
-  exponent = exponent - 1023;
-  if (sign) {
-    printf("-");
-  } else {
-    printf(" ");
-  }
-  if (exponent == -1023) {
-    printf(
-      "0.0000000000000000000000000000000000000000000000000000_     (   )");
-  } else {
-    printf("1.");
-    bottomi = -1;
-    for (i = 0; i < 52; i++) {
-      if (no & 0x0008000000000000ll) {
-        printf("1");
-        bottomi = i;
-      } else {
-        printf("0");
-      }
-      no <<= 1;
-    }
-    printf("_%d  (%d)", exponent, exponent - 1 - bottomi);
-  }
+  double x, power;
+  x = (n < 0) ? ((double)1.0/(double)2.0) : (double)2.0;
+  n = (n < 0) ? -n : n;
+  power = (double)1.0;
+  while (n-- > 0)
+	power *= x;
+  return (power);
 }
-*/
 
-/*****************************************************************************/
-/*                                                                           */
-/*  floatprint()   Print the bit representation of a float.                  */
-/*                                                                           */
-/*  Useful for debugging exact arithmetic routines.                          */
-/*                                                                           */
-/*****************************************************************************/
+#ifdef SINGLE
 
-/*
-void floatprint(number)
-float number;
+float fstore(float x)
 {
-  unsigned no;
-  unsigned sign, expo;
-  int exponent;
-  int i, bottomi;
-
-  no = *(unsigned *) &number;
-  sign = no & 0x80000000;
-  expo = (no >> 23) & 0xff;
-  exponent = (int) expo;
-  exponent = exponent - 127;
-  if (sign) {
-    printf("-");
-  } else {
-    printf(" ");
-  }
-  if (exponent == -127) {
-    printf("0.00000000000000000000000_     (   )");
-  } else {
-    printf("1.");
-    bottomi = -1;
-    for (i = 0; i < 23; i++) {
-      if (no & 0x00400000) {
-        printf("1");
-        bottomi = i;
-      } else {
-        printf("0");
-      }
-      no <<= 1;
-    }
-    printf("_%3d  (%3d)", exponent, exponent - 1 - bottomi);
-  }
+  return (x);
 }
-*/
 
-/*****************************************************************************/
-/*                                                                           */
-/*  expansion_print()   Print the bit representation of an expansion.        */
-/*                                                                           */
-/*  Useful for debugging exact arithmetic routines.                          */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-void expansion_print(elen, e)
-int elen;
-REAL *e;
+int test_float(int verbose)
 {
-  int i;
+  float x;
+  int pass = 1;
 
-  for (i = elen - 1; i >= 0; i--) {
-    REALPRINT(e[i]);
-    if (i > 0) {
-      printf(" +\n");
-    } else {
-      printf("\n");
-    }
+  //(void)printf("float:\n");
+
+  if (verbose) {
+    (void)printf("  sizeof(float) = %2u\n", (unsigned int)sizeof(float));
+#ifdef CPU86  // <float.h>
+    (void)printf("  FLT_MANT_DIG = %2d\n", FLT_MANT_DIG);
+#endif
   }
-}
-*/
 
-/*****************************************************************************/
-/*                                                                           */
-/*  doublerand()   Generate a double with random 53-bit significand and a    */
-/*                 random exponent in [0, 511].                              */
-/*                                                                           */
-/*****************************************************************************/
+  x = (float)1.0;
+  while (fstore((float)1.0 + x/(float)2.0) != (float)1.0)
+    x /= (float)2.0;
+  if (verbose)
+    (void)printf("  machine epsilon = %13.5e  ", x);
 
-/*
-double doublerand()
-{
-  double result;
-  double expo;
-  long a, b, c;
-  long i;
-
-  a = random();
-  b = random();
-  c = random();
-  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
-  for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
+  if (x == (float)fppow2(-23)) {
+    if (verbose)
+      (void)printf("[IEEE 754 32-bit macheps]\n");
+  } else {
+    (void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
   }
-  return result;
-}
-*/
 
-/*****************************************************************************/
-/*                                                                           */
-/*  narrowdoublerand()   Generate a double with random 53-bit significand    */
-/*                       and a random exponent in [0, 7].                    */
-/*                                                                           */
-/*****************************************************************************/
-
-/*
-double narrowdoublerand()
-{
-  double result;
-  double expo;
-  long a, b, c;
-  long i;
-
-  a = random();
-  b = random();
-  c = random();
-  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
-  for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
+  x = (float)1.0;
+  while (fstore(x / (float)2.0) != (float)0.0)
+    x /= (float)2.0;
+  if (verbose)
+    (void)printf("  smallest positive number =  %13.5e  ", x);
+
+  if (x == (float)fppow2(-149)) {
+    if (verbose)
+      (void)printf("[smallest 32-bit subnormal]\n");
+  } else if (x == (float)fppow2(-126)) {
+    if (verbose)
+      (void)printf("[smallest 32-bit normal]\n");
+  } else {
+	(void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
   }
-  return result;
+
+  return pass;
 }
-*/
 
-/*****************************************************************************/
-/*                                                                           */
-/*  uniformdoublerand()   Generate a double with random 53-bit significand.  */
-/*                                                                           */
-/*****************************************************************************/
+# else
 
-/*
-double uniformdoublerand()
+double dstore(double x)
 {
-  double result;
-  long a, b;
-
-  a = random();
-  b = random();
-  result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8);
-  return result;
+  return (x);
 }
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  floatrand()   Generate a float with random 24-bit significand and a      */
-/*                random exponent in [0, 63].                                */
-/*                                                                           */
-/*****************************************************************************/
 
-/*
-float floatrand()
+int test_double(int verbose)
 {
-  float result;
-  float expo;
-  long a, c;
-  long i;
-
-  a = random();
-  c = random();
-  result = (float) ((a - 1073741824) >> 6);
-  for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
+  double x;
+  int pass = 1;
+
+  // (void)printf("double:\n");
+  if (verbose) {
+    (void)printf("  sizeof(double) = %2u\n", (unsigned int)sizeof(double));
+#ifdef CPU86  // <float.h>
+    (void)printf("  DBL_MANT_DIG = %2d\n", DBL_MANT_DIG);
+#endif
   }
-  return result;
-}
-*/
 
-/*****************************************************************************/
-/*                                                                           */
-/*  narrowfloatrand()   Generate a float with random 24-bit significand and  */
-/*                      a random exponent in [0, 7].                         */
-/*                                                                           */
-/*****************************************************************************/
+  x = 1.0;
+  while (dstore(1.0 + x/2.0) != 1.0)
+    x /= 2.0;
+  if (verbose) 
+    (void)printf("  machine epsilon = %13.5le ", x);
 
-/*
-float narrowfloatrand()
-{
-  float result;
-  float expo;
-  long a, c;
-  long i;
-
-  a = random();
-  c = random();
-  result = (float) ((a - 1073741824) >> 6);
-  for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) {
-    if (c & i) {
-      result *= expo;
-    }
+  if (x == (double)fppow2(-52)) {
+    if (verbose)
+      (void)printf("[IEEE 754 64-bit macheps]\n");
+  } else {
+    (void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
   }
-  return result;
-}
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*  uniformfloatrand()   Generate a float with random 24-bit significand.    */
-/*                                                                           */
-/*****************************************************************************/
 
-/*
-float uniformfloatrand()
-{
-  float result;
-  long a;
+  x = 1.0;
+  while (dstore(x / 2.0) != 0.0)
+    x /= 2.0;
+  //if (verbose)
+  //  (void)printf("  smallest positive number = %13.5le ", x);
+
+  if (x == (double)fppow2(-1074)) {
+    //if (verbose)
+    //  (void)printf("[smallest 64-bit subnormal]\n");
+  } else if (x == (double)fppow2(-1022)) {
+    //if (verbose)
+    //  (void)printf("[smallest 64-bit normal]\n");
+  } else {
+    (void)printf("[not IEEE 754 conformant] !!\n");
+    pass = 0;
+  }
 
-  a = random();
-  result = (float) ((a - 1073741824) >> 6);
-  return result;
+  return pass;
 }
-*/
+
+#endif
 
 /*****************************************************************************/
 /*                                                                           */
@@ -660,7 +540,8 @@ float uniformfloatrand()
 /*                                                                           */
 /*****************************************************************************/
 
-REAL exactinit()
+void exactinit(int verbose, int noexact, int nofilter, REAL maxx, REAL maxy, 
+               REAL maxz)
 {
   REAL half;
   REAL check, lastcheck;
@@ -687,6 +568,24 @@ REAL exactinit()
   _FPU_SETCW(cword);
 #endif /* LINUX */
 
+  if (verbose) {
+    printf("  Initializing robust predicates.\n");
+  }
+
+#ifdef USE_CGAL_PREDICATES
+  if (cgal_pred_obj.Has_static_filters) {
+    printf("  Use static filter.\n");
+  } else {
+    printf("  No static filter.\n");
+  }
+#endif // USE_CGAL_PREDICATES
+
+#ifdef SINGLE
+  test_float(verbose);
+#else
+  test_double(verbose);
+#endif
+
   every_other = 1;
   half = 0.5;
   epsilon = 1.0;
@@ -722,7 +621,31 @@ REAL exactinit()
   isperrboundB = (5.0 + 72.0 * epsilon) * epsilon;
   isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon;
 
-  return epsilon; /* Added by H. Si 30 Juli, 2004. */
+  // Set TetGen options.  Added by H. Si, 2012-08-23.
+  _use_inexact_arith = noexact;
+  _use_static_filter = !nofilter;
+
+  // Calculate the two static filters for orient3d() and insphere() tests.
+  // Added by H. Si, 2012-08-23.
+
+  // Sort maxx < maxy < maxz. Re-use 'half' for swapping.
+  assert(maxx > 0);
+  assert(maxy > 0);
+  assert(maxz > 0);
+
+  if (maxx > maxz) {
+    half = maxx; maxx = maxz; maxz = half;
+  }
+  if (maxy > maxz) {
+    half = maxy; maxy = maxz; maxz = half;
+  }
+  else if (maxy < maxx) {
+    half = maxy; maxy = maxx; maxx = half;
+  }
+
+  o3dstaticfilter = 5.1107127829973299e-15 * maxx * maxy * maxz;
+  ispstaticfilter = 1.2466136531027298e-13 * maxx * maxy * maxz * (maxz * maxz);
+
 }
 
 /*****************************************************************************/
@@ -1869,16 +1792,6 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent)
   REAL fin1[192], fin2[192];
   int finlength;
 
-  ////////////////////////////////////////////////////////
-  // To avoid uninitialized warnings reported by valgrind.
-  int i;
-  for (i = 0; i < 8; i++) {
-    adet[i] = bdet[i] = cdet[i] = 0.0;
-  }
-  for (i = 0; i < 16; i++) {
-    abdet[i] = 0.0;
-  }
-  ////////////////////////////////////////////////////////
 
   REAL adxtail, bdxtail, cdxtail;
   REAL adytail, bdytail, cdytail;
@@ -1916,6 +1829,7 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent)
   INEXACT REAL _i, _j, _k;
   REAL _0;
 
+
   adx = (REAL) (pa[0] - pd[0]);
   bdx = (REAL) (pb[0] - pd[0]);
   cdx = (REAL) (pc[0] - pd[0]);
@@ -2263,27 +2177,16 @@ REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent)
   return finnow[finlength - 1];
 }
 
-#ifdef INEXACT_GEOM_PRED
+#ifdef USE_CGAL_PREDICATES
 
 REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
 {
-  REAL adx, bdx, cdx;
-  REAL ady, bdy, cdy;
-  REAL adz, bdz, cdz;
-
-  adx = pa[0] - pd[0];
-  bdx = pb[0] - pd[0];
-  cdx = pc[0] - pd[0];
-  ady = pa[1] - pd[1];
-  bdy = pb[1] - pd[1];
-  cdy = pc[1] - pd[1];
-  adz = pa[2] - pd[2];
-  bdz = pb[2] - pd[2];
-  cdz = pc[2] - pd[2];
-
-  return adx * (bdy * cdz - bdz * cdy)
-       + bdx * (cdy * adz - cdz * ady)
-       + cdx * (ady * bdz - adz * bdy);
+  return (REAL) 
+    - cgal_pred_obj.orientation_3_object()
+        (Point(pa[0], pa[1], pa[2]), 
+         Point(pb[0], pb[1], pb[2]),
+         Point(pc[0], pc[1], pc[2]),
+         Point(pd[0], pd[1], pd[2]));
 }
 
 #else
@@ -2293,16 +2196,16 @@ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
   REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz;
   REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
   REAL det;
-  REAL permanent, errbound;
+
 
   adx = pa[0] - pd[0];
-  bdx = pb[0] - pd[0];
-  cdx = pc[0] - pd[0];
   ady = pa[1] - pd[1];
-  bdy = pb[1] - pd[1];
-  cdy = pc[1] - pd[1];
   adz = pa[2] - pd[2];
+  bdx = pb[0] - pd[0];
+  bdy = pb[1] - pd[1];
   bdz = pb[2] - pd[2];
+  cdx = pc[0] - pd[0];
+  cdy = pc[1] - pd[1];
   cdz = pc[2] - pd[2];
 
   bdxcdy = bdx * cdy;
@@ -2318,6 +2221,19 @@ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
       + bdz * (cdxady - adxcdy)
       + cdz * (adxbdy - bdxady);
 
+  if (_use_inexact_arith) {
+    return det;
+  }
+
+  if (_use_static_filter) {
+    //if (fabs(det) > o3dstaticfilter) return det;
+    if (det > o3dstaticfilter) return det;
+    if (det < -o3dstaticfilter) return det;
+  }
+
+
+  REAL permanent, errbound;
+
   permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz)
             + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz)
             + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz);
@@ -2329,7 +2245,7 @@ REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
   return orient3dadapt(pa, pb, pc, pd, permanent);
 }
 
-#endif // ifdef INEXACT_GEOM_PRED
+#endif // #ifdef USE_CGAL_PREDICATES
 
 /*****************************************************************************/
 /*                                                                           */
@@ -3362,6 +3278,7 @@ REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
   INEXACT REAL _i, _j;
   REAL _0;
 
+
   Two_Product(pa[0], pb[1], axby1, axby0);
   Two_Product(pb[0], pa[1], bxay1, bxay0);
   Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]);
@@ -3938,6 +3855,7 @@ REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
   INEXACT REAL _i, _j;
   REAL _0;
 
+
   aex = (REAL) (pa[0] - pe[0]);
   bex = (REAL) (pb[0] - pe[0]);
   cex = (REAL) (pc[0] - pe[0]);
@@ -4114,50 +4032,19 @@ REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
   return insphereexact(pa, pb, pc, pd, pe);
 }
 
-#ifdef INEXACT_GEOM_PRED
+#ifdef USE_CGAL_PREDICATES
 
 REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
 {
-  REAL aex, bex, cex, dex;
-  REAL aey, bey, cey, dey;
-  REAL aez, bez, cez, dez;
-  REAL alift, blift, clift, dlift;
-  REAL ab, bc, cd, da, ac, bd;
-  REAL abc, bcd, cda, dab;
-
-  aex = pa[0] - pe[0];
-  bex = pb[0] - pe[0];
-  cex = pc[0] - pe[0];
-  dex = pd[0] - pe[0];
-  aey = pa[1] - pe[1];
-  bey = pb[1] - pe[1];
-  cey = pc[1] - pe[1];
-  dey = pd[1] - pe[1];
-  aez = pa[2] - pe[2];
-  bez = pb[2] - pe[2];
-  cez = pc[2] - pe[2];
-  dez = pd[2] - pe[2];
-
-  ab = aex * bey - bex * aey;
-  bc = bex * cey - cex * bey;
-  cd = cex * dey - dex * cey;
-  da = dex * aey - aex * dey;
-
-  ac = aex * cey - cex * aey;
-  bd = bex * dey - dex * bey;
-
-  abc = aez * bc - bez * ac + cez * ab;
-  bcd = bez * cd - cez * bd + dez * bc;
-  cda = cez * da + dez * ac + aez * cd;
-  dab = dez * ab + aez * bd + bez * da;
-
-  alift = aex * aex + aey * aey + aez * aez;
-  blift = bex * bex + bey * bey + bez * bez;
-  clift = cex * cex + cey * cey + cez * cez;
-  dlift = dex * dex + dey * dey + dez * dez;
-
-  return (dlift * abc - clift * dab) + (blift * cda - alift * bcd);
+  return (REAL)
+    - cgal_pred_obj.side_of_oriented_sphere_3_object()
+        (Point(pa[0], pa[1], pa[2]),
+         Point(pb[0], pb[1], pb[2]),
+         Point(pc[0], pc[1], pc[2]),
+         Point(pd[0], pd[1], pd[2]),
+         Point(pe[0], pe[1], pe[2]));
 }
+
 #else
 
 REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
@@ -4170,12 +4057,8 @@ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
   REAL alift, blift, clift, dlift;
   REAL ab, bc, cd, da, ac, bd;
   REAL abc, bcd, cda, dab;
-  REAL aezplus, bezplus, cezplus, dezplus;
-  REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
-  REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
-  REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
   REAL det;
-  REAL permanent, errbound;
+
 
   aex = pa[0] - pe[0];
   bex = pb[0] - pe[0];
@@ -4222,6 +4105,23 @@ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
 
   det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd);
 
+  if (_use_inexact_arith) {
+    return det;
+  }
+
+  if (_use_static_filter) {
+    if (fabs(det) > ispstaticfilter) return det;
+    //if (det > ispstaticfilter) return det;
+    //if (det < minus_ispstaticfilter) return det;
+
+  }
+
+  REAL aezplus, bezplus, cezplus, dezplus;
+  REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
+  REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
+  REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
+  REAL permanent, errbound;
+
   aezplus = Absolute(aez);
   bezplus = Absolute(bez);
   cezplus = Absolute(cez);
@@ -4262,7 +4162,7 @@ REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe)
   return insphereadapt(pa, pb, pc, pd, pe, permanent);
 }
 
-#endif // #ifdef INEXACT_GEOM_PRED
+#endif // #ifdef USE_CGAL_PREDICATES
 
 /*****************************************************************************/
 /*                                                                           */
@@ -4327,6 +4227,7 @@ REAL orient4dexact(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
   INEXACT REAL _i, _j;
   REAL _0;
 
+
   Two_Product(pa[0], pb[1], axby1, axby0);
   Two_Product(pb[0], pa[1], bxay1, bxay0);
   Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]);
@@ -4540,6 +4441,7 @@ REAL orient4dadapt(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
   INEXACT REAL _i, _j;
   REAL _0;
 
+
   aex = (REAL) (pa[0] - pe[0]);
   bex = (REAL) (pb[0] - pe[0]);
   cex = (REAL) (pc[0] - pe[0]);
@@ -4699,108 +4601,106 @@ REAL orient4d(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
               REAL aheight, REAL bheight, REAL cheight, REAL dheight, 
               REAL eheight)
 {
-  REAL aex, bex, cex, dex;
-  REAL aey, bey, cey, dey;
-  REAL aez, bez, cez, dez;
-  REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey;
-  REAL aexcey, cexaey, bexdey, dexbey;
-  REAL aeheight, beheight, ceheight, deheight;
-  REAL ab, bc, cd, da, ac, bd;
-  REAL abc, bcd, cda, dab;
-  REAL aezplus, bezplus, cezplus, dezplus;
-  REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
-  REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
-  REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
-  REAL det;
-  REAL permanent, errbound;
-
-  //orient4dcount++;
-
-  aex = pa[0] - pe[0];
-  bex = pb[0] - pe[0];
-  cex = pc[0] - pe[0];
-  dex = pd[0] - pe[0];
-  aey = pa[1] - pe[1];
-  bey = pb[1] - pe[1];
-  cey = pc[1] - pe[1];
-  dey = pd[1] - pe[1];
-  aez = pa[2] - pe[2];
-  bez = pb[2] - pe[2];
-  cez = pc[2] - pe[2];
-  dez = pd[2] - pe[2];
-  aeheight = aheight - eheight;
-  beheight = bheight - eheight;
-  ceheight = cheight - eheight;
-  deheight = dheight - eheight;
-
-  aexbey = aex * bey;
-  bexaey = bex * aey;
-  ab = aexbey - bexaey;
-  bexcey = bex * cey;
-  cexbey = cex * bey;
-  bc = bexcey - cexbey;
-  cexdey = cex * dey;
-  dexcey = dex * cey;
-  cd = cexdey - dexcey;
-  dexaey = dex * aey;
-  aexdey = aex * dey;
-  da = dexaey - aexdey;
-
-  aexcey = aex * cey;
-  cexaey = cex * aey;
-  ac = aexcey - cexaey;
-  bexdey = bex * dey;
-  dexbey = dex * bey;
-  bd = bexdey - dexbey;
-
-  abc = aez * bc - bez * ac + cez * ab;
-  bcd = bez * cd - cez * bd + dez * bc;
-  cda = cez * da + dez * ac + aez * cd;
-  dab = dez * ab + aez * bd + bez * da;
-
-  det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * bcd);
+ REAL aex, bex, cex, dex;
+ REAL aey, bey, cey, dey;
+ REAL aez, bez, cez, dez;
+ REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey;
+ REAL aexcey, cexaey, bexdey, dexbey;
+ REAL aeheight, beheight, ceheight, deheight;
+ REAL ab, bc, cd, da, ac, bd;
+ REAL abc, bcd, cda, dab;
+ REAL aezplus, bezplus, cezplus, dezplus;
+ REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus;
+ REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus;
+ REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus;
+ REAL det;
+ REAL permanent, errbound;
+
+
+ aex = pa[0] - pe[0];
+ bex = pb[0] - pe[0];
+ cex = pc[0] - pe[0];
+ dex = pd[0] - pe[0];
+ aey = pa[1] - pe[1];
+ bey = pb[1] - pe[1];
+ cey = pc[1] - pe[1];
+ dey = pd[1] - pe[1];
+ aez = pa[2] - pe[2];
+ bez = pb[2] - pe[2];
+ cez = pc[2] - pe[2];
+ dez = pd[2] - pe[2];
+ aeheight = aheight - eheight;
+ beheight = bheight - eheight;
+ ceheight = cheight - eheight;
+ deheight = dheight - eheight;
+
+ aexbey = aex * bey;
+ bexaey = bex * aey;
+ ab = aexbey - bexaey;
+ bexcey = bex * cey;
+ cexbey = cex * bey;
+ bc = bexcey - cexbey;
+ cexdey = cex * dey;
+ dexcey = dex * cey;
+ cd = cexdey - dexcey;
+ dexaey = dex * aey;
+ aexdey = aex * dey;
+ da = dexaey - aexdey;
+
+ aexcey = aex * cey;
+ cexaey = cex * aey;
+ ac = aexcey - cexaey;
+ bexdey = bex * dey;
+ dexbey = dex * bey;
+ bd = bexdey - dexbey;
+
+ abc = aez * bc - bez * ac + cez * ab;
+ bcd = bez * cd - cez * bd + dez * bc;
+ cda = cez * da + dez * ac + aez * cd;
+ dab = dez * ab + aez * bd + bez * da;
+
+ det = (deheight * abc - ceheight * dab) + (beheight * cda - aeheight * bcd);
+
+ aezplus = Absolute(aez);
+ bezplus = Absolute(bez);
+ cezplus = Absolute(cez);
+ dezplus = Absolute(dez);
+ aexbeyplus = Absolute(aexbey);
+ bexaeyplus = Absolute(bexaey);
+ bexceyplus = Absolute(bexcey);
+ cexbeyplus = Absolute(cexbey);
+ cexdeyplus = Absolute(cexdey);
+ dexceyplus = Absolute(dexcey);
+ dexaeyplus = Absolute(dexaey);
+ aexdeyplus = Absolute(aexdey);
+ aexceyplus = Absolute(aexcey);
+ cexaeyplus = Absolute(cexaey);
+ bexdeyplus = Absolute(bexdey);
+ dexbeyplus = Absolute(dexbey);
+ permanent = ((cexdeyplus + dexceyplus) * bezplus
+              + (dexbeyplus + bexdeyplus) * cezplus
+              + (bexceyplus + cexbeyplus) * dezplus)
+           * Absolute(aeheight)
+           + ((dexaeyplus + aexdeyplus) * cezplus
+              + (aexceyplus + cexaeyplus) * dezplus
+              + (cexdeyplus + dexceyplus) * aezplus)
+           * Absolute(beheight)
+           + ((aexbeyplus + bexaeyplus) * dezplus
+              + (bexdeyplus + dexbeyplus) * aezplus
+              + (dexaeyplus + aexdeyplus) * bezplus)
+           * Absolute(ceheight)
+           + ((bexceyplus + cexbeyplus) * aezplus
+              + (cexaeyplus + aexceyplus) * bezplus
+              + (aexbeyplus + bexaeyplus) * cezplus)
+           * Absolute(deheight);
+ errbound = isperrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+   return det;
+ }
+
+ return orient4dadapt(pa, pb, pc, pd, pe,
+                      aheight, bheight, cheight, dheight, eheight, permanent);
+}
 
-  if (0) { //if (noexact) {
-    return det;
-  }
 
-  aezplus = Absolute(aez);
-  bezplus = Absolute(bez);
-  cezplus = Absolute(cez);
-  dezplus = Absolute(dez);
-  aexbeyplus = Absolute(aexbey);
-  bexaeyplus = Absolute(bexaey);
-  bexceyplus = Absolute(bexcey);
-  cexbeyplus = Absolute(cexbey);
-  cexdeyplus = Absolute(cexdey);
-  dexceyplus = Absolute(dexcey);
-  dexaeyplus = Absolute(dexaey);
-  aexdeyplus = Absolute(aexdey);
-  aexceyplus = Absolute(aexcey);
-  cexaeyplus = Absolute(cexaey);
-  bexdeyplus = Absolute(bexdey);
-  dexbeyplus = Absolute(dexbey);
-  permanent = ((cexdeyplus + dexceyplus) * bezplus
-               + (dexbeyplus + bexdeyplus) * cezplus
-               + (bexceyplus + cexbeyplus) * dezplus)
-            * aeheight
-            + ((dexaeyplus + aexdeyplus) * cezplus
-               + (aexceyplus + cexaeyplus) * dezplus
-               + (cexdeyplus + dexceyplus) * aezplus)
-            * beheight
-            + ((aexbeyplus + bexaeyplus) * dezplus
-               + (bexdeyplus + dexbeyplus) * aezplus
-               + (dexaeyplus + aexdeyplus) * bezplus)
-            * ceheight
-            + ((bexceyplus + cexbeyplus) * aezplus
-               + (cexaeyplus + aexceyplus) * bezplus
-               + (aexbeyplus + bexaeyplus) * cezplus)
-            * deheight;
-  errbound = isperrboundA * permanent;
-  if ((det > errbound) || (-det > errbound)) {
-    return det;
-  }
 
-  return orient4dadapt(pa, pb, pc, pd, pe,
-                       aheight, bheight, cheight, dheight, eheight, permanent);
-}
diff --git a/contrib/Tetgen1.5/tetgen.cxx b/contrib/Tetgen1.5/tetgen.cxx
index 0a66de153c7e2825e01c02a2f1fdb01be35381ed..da4ef3d73513af1acad895153b65e5d80f66842b 100644
--- a/contrib/Tetgen1.5/tetgen.cxx
+++ b/contrib/Tetgen1.5/tetgen.cxx
@@ -2,21 +2,10 @@
 //                                                                           //
 // TetGen                                                                    //
 //                                                                           //
-// A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
+// A Quality Tetrahedral Mesh Generator and A 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                                                    //
+// November 4, 2013                                                          //
 //                                                                           //
 // TetGen is freely available through the website: http://www.tetgen.org.    //
 //   It may be copied, modified, and redistributed for non-commercial use.   //
@@ -58,24 +47,24 @@ bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
   // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
   pointlist = new REAL[numberofpoints * 3];
   if (pointlist == (REAL *) NULL) {
-    terminatetetgen(1);
+    terminatetetgen(NULL, 1);
   }
   if (numberofpointattributes > 0) {
     pointattributelist = new REAL[numberofpoints * numberofpointattributes];
     if (pointattributelist == (REAL *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(NULL, 1);
     }
   }
   if (markers) {
     pointmarkerlist = new int[numberofpoints];
     if (pointmarkerlist == (int *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(NULL, 1);
     }
   }
   if (uvflag) {
     pointparamlist = new pointparam[numberofpoints];
     if (pointparamlist == NULL) {
-      terminatetetgen(1);
+      terminatetetgen(NULL, 1);
     }
   }
 
@@ -223,11 +212,11 @@ bool tetgenio::load_node(char* filebasename)
   mesh_dim = 3;
   numberofpointattributes = 0;  // no point attribute.
   markers = 0;  // no boundary marker.
-  uvflag = 0; // no uv parameters (reuqired by a PSC). 
+  uvflag = 0; // no uv parameters (required by a PSC). 
 
   // Read the first line of the file.
   stringptr = readnumberline(inputline, infile, innodefilename);
-  // Does this file contain an index colume?
+  // Does this file contain an index column?
   stringptr = strstr(inputline, "rbox");
   if (stringptr == NULL) {
     // Read number of points, number of dimensions, number of point
@@ -302,7 +291,7 @@ bool tetgenio::load_edge(char* filebasename)
   if (numberofedges > 0) {
     edgelist = new int[numberofedges * 2];
     if (edgelist == (int *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(NULL, 1);
     }
     stringptr = findnextnumber(stringptr);
     if (*stringptr == '\0') {
@@ -325,16 +314,20 @@ bool tetgenio::load_edge(char* filebasename)
       if (*stringptr == '\0') {
         printf("Error:  Edge %d is missing vertex %d in %s.\n",
                i + firstnumber, j + 1, inedgefilename);
-        terminatetetgen(1);
+        terminatetetgen(NULL, 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);
+        terminatetetgen(NULL, 1);
       }
       edgelist[index++] = corner;
     }
+    if (numberofcorners == 10) {
+      // Skip an extra vertex (generated by a previous -o2 option).
+      stringptr = findnextnumber(stringptr);
+    }
     // Read the edge marker if it has.
     if (markers) {
       stringptr = findnextnumber(stringptr);
@@ -389,12 +382,12 @@ bool tetgenio::load_face(char* filebasename)
   if (numberoftrifaces > 0) {
     trifacelist = new int[numberoftrifaces * 3];
     if (trifacelist == (int *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(NULL, 1);
     }
     if (markers) {
       trifacemarkerlist = new int[numberoftrifaces];
       if (trifacemarkerlist == (int *) NULL) {
-        terminatetetgen(1);
+        terminatetetgen(NULL, 1);
       }
     }
   }
@@ -409,16 +402,22 @@ bool tetgenio::load_face(char* filebasename)
       if (*stringptr == '\0') {
         printf("Error:  Face %d is missing vertex %d in %s.\n",
                i + firstnumber, j + 1, infilename);
-        terminatetetgen(1);
+        terminatetetgen(NULL, 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);
+        terminatetetgen(NULL, 1);
       }
       trifacelist[index++] = corner;
     }
+    if (numberofcorners == 10) {
+      // Skip 3 extra vertices (generated by a previous -o2 option).
+      for (j = 0; j < 3; j++) {
+        stringptr = findnextnumber(stringptr);
+      }
+    }
     // Read the boundary marker if it exists.
     if (markers) {
       stringptr = findnextnumber(stringptr);
@@ -494,14 +493,14 @@ bool tetgenio::load_tet(char* filebasename)
   // Allocate memory for tetrahedra.
   tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; 
   if (tetrahedronlist == (int *) NULL) {
-    terminatetetgen(1);
+    terminatetetgen(NULL, 1);
   }
   // Allocate memory for output tetrahedron attributes if necessary.
   if (numberoftetrahedronattributes > 0) {
     tetrahedronattributelist = new REAL[numberoftetrahedra *
                                         numberoftetrahedronattributes];
     if (tetrahedronattributelist == (REAL *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(NULL, 1);
     }
   }
 
@@ -516,13 +515,13 @@ bool tetgenio::load_tet(char* filebasename)
       if (*stringptr == '\0') {
         printf("Error:  Tetrahedron %d is missing vertex %d in %s.\n",
                i + firstnumber, j + 1, infilename);
-        terminatetetgen(1);
+        terminatetetgen(NULL, 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);
+        terminatetetgen(NULL, 1);
       }
       tetrahedronlist[index++] = corner;
     }
@@ -584,7 +583,7 @@ bool tetgenio::load_vol(char* filebasename)
 
   tetrahedronvolumelist = new REAL[volelements];
   if (tetrahedronvolumelist == (REAL *) NULL) {
-    terminatetetgen(1);
+    terminatetetgen(NULL, 1);
   }
 
   // Read the list of volume constraints.
@@ -627,7 +626,6 @@ bool tetgenio::load_var(char* filebasename)
   if (infile != (FILE *) NULL) {
     printf("Opening %s.\n", varfilename);
   } else {
-    // No such file. Ignore it without a message.
     return false;
   }
 
@@ -740,7 +738,6 @@ bool tetgenio::load_mtr(char* filebasename)
   if (infile != (FILE *) NULL) {
     printf("Opening %s.\n", mtrfilename);
   } else {
-    // No such file. Return.
     return false;
   }
 
@@ -765,7 +762,7 @@ bool tetgenio::load_mtr(char* filebasename)
   // Allocate space for pointmtrlist.
   pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
   if (pointmtrlist == (REAL *) NULL) {
-    terminatetetgen(1);
+    terminatetetgen(NULL, 1);
   }
   mtrindex = 0;
   for (i = 0; i < numberofpoints; i++) {
@@ -775,7 +772,7 @@ bool tetgenio::load_mtr(char* filebasename)
       if (*stringptr == '\0') {
         printf("Error:  Metric %d is missing value #%d in %s.\n",
                i + firstnumber, j + 1, mtrfilename);
-        terminatetetgen(1);
+        terminatetetgen(NULL, 1);
       }
       mtr = (REAL) strtod(stringptr, &stringptr);
       pointmtrlist[mtrindex++] = mtr;
@@ -832,10 +829,10 @@ bool tetgenio::load_poly(char* filebasename)
   }
 
   // Initialize the default values.
-  mesh_dim = 3;  // Three-dimemsional accoordinates.
+  mesh_dim = 3;  // Three-dimensional coordinates.
   numberofpointattributes = 0;  // no point attribute.
   markers = 0;  // no boundary marker.
-  uvflag = 0; // no uv parameters (reuqired by a PSC).
+  uvflag = 0; // no uv parameters (required by a PSC).
 
   // Read number of points, number of dimensions, number of point
   //   attributes, and number of boundary markers.
@@ -1381,14 +1378,11 @@ bool tetgenio::load_off(char* filebasename)
     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);
@@ -1603,14 +1597,11 @@ bool tetgenio::load_ply(char* filebasename)
     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);
@@ -2092,7 +2083,7 @@ bool tetgenio::load_medit(char* filebasename, int istetmesh)
 //                                                                           //
 // load_vtk()    Load VTK surface mesh from file (.vtk ascii or binary).     //
 //                                                                           //
-// This function is contributed by: Bryn Lloyd, Computer Vision Laborator,   //
+// This function is contributed by: Bryn Lloyd, Computer Vision Laboratory,  //
 // ETH, Zuerich. May 7, 2007.                                                //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
@@ -2389,6 +2380,7 @@ bool tetgenio::load_plc(char* filebasename, int object)
   }
 
   if (success) {
+    // Try to load the following files (.edge, .var, .mtr).
     load_edge(filebasename);
     load_var(filebasename);
     load_mtr(filebasename);
@@ -2415,6 +2407,7 @@ bool tetgenio::load_tetmesh(char* filebasename, int object)
       success = load_tet(filebasename);
     }
     if (success) {
+      // Try to load the following files (.face, .edge, .vol).
       load_face(filebasename);
       load_edge(filebasename);
       load_vol(filebasename);
@@ -2422,6 +2415,7 @@ bool tetgenio::load_tetmesh(char* filebasename, int object)
   }
 
   if (success) {
+    // Try to load the following files (.var, .mtr).
     load_var(filebasename);
     load_mtr(filebasename);
   }
@@ -2902,16 +2896,23 @@ char* tetgenio::findnextnumber(char *string)
 
 void tetgenbehavior::syntax()
 {
-  printf("  tetgen [-pYrq_a_AiS_T_dzfenvgKJBNEFICQVh] input_file\n");
+  printf("  tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
   printf("    -p  Tetrahedralizes a piecewise linear complex (PLC).\n");
-  printf("    -Y  No splitting of input boundaries (facets and segments).\n");
+  printf("    -Y  Preserves the input surface mesh (does not modify it).\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("    -R  Mesh coarsening (to reduce the mesh elements).\n");
   printf("    -A  Assigns attributes to tetrahedra in different regions.\n");
-  printf("    -i  Inserts a list of additional points into mesh.\n");
+  printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
+  printf("    -m  Applies a mesh sizing function.\n");
+  printf("    -i  Inserts a list of additional points.\n");
+  printf("    -O  Specifies the level of mesh optimization.\n");
   printf("    -S  Specifies maximum number of added points.\n");
   printf("    -T  Sets a tolerance for coplanar test (default 1e-8).\n");
+  printf("    -X  Suppresses use of exact arithmetic.\n");
+  printf("    -M  No merge of coplanar facets or very close vertices.\n");
+  printf("    -w  Generates weighted Delaunay (regular) triangulation.\n");
+  printf("    -c  Retains the convex hull of the PLC.\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");
@@ -2919,12 +2920,12 @@ void tetgenbehavior::syntax()
   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("    -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("    -F  Suppresses output of .face and .edge 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");
@@ -2943,20 +2944,13 @@ 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("Version 1.5\n");
+  printf("November 4, 2013\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("  TetGen generates Delaunay tetrahedralizations, constrained\n");
+  printf("  Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
   printf("\n");
   printf("Command Line Syntax:\n");
   printf("\n");
@@ -2977,22 +2971,24 @@ void tetgenbehavior::usage()
   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("their\n  Delaunay tetrahedralization to object.1.node, ");
+  printf("object.1.ele\n  (tetrahedra), and object.1.face");
+  printf(" (convex hull faces).\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("Delaunay\n  tetrahedralization to object.1.node, object.1.ele, ");
+  printf("object.1.face,\n");
+  printf("  (boundary faces) and object.1.edge (boundary edges).\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("object.1.node, object.1.ele,\n  object.1.face, and object.1.edge\n");
   printf("\n");
   printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
-  terminatetetgen(0);
+  terminatetetgen(NULL, 0);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -3004,19 +3000,6 @@ void tetgenbehavior::usage()
 // 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)
@@ -3024,7 +3007,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   int startindex;
   int increment;
   int meshnumber;
-  int scount, ocount;
   int i, j, k;
   char workstring[1024];
 
@@ -3038,12 +3020,9 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     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.
+    // Remember the command line for output.
     strcat(commandline, argv[i]);
     strcat(commandline, " ");
     if (startindex == 1) {
@@ -3051,7 +3030,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
       if (argv[i][0] != '-') {
         strncpy(infilename, argv[i], 1024 - 1);
         infilename[1024 - 1] = '\0';
-        // Go to the next string directly.
         continue;                     
       }
     }
@@ -3072,11 +3050,24 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           facet_ang_tol = (REAL) strtod(workstring, (char **) NULL);
         }
       } else if (argv[i][j] == 's') {
-        psc = 1;        
+        psc = 1;
+      } else if (argv[i][j] == 'Y') {
+        nobisect = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          nobisect_param = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+            addsteiner_algo = (argv[i][j + 1] - '0');
+            j++;
+          }
+        }
       } else if (argv[i][j] == 'r') {
-        refine++;
+        refine = 1;
       } else if (argv[i][j] == 'q') {
-        quality++;
+        quality = 1;
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -3087,30 +3078,68 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          if (quality == 1) { // -q#
-            minratio = (REAL) strtod(workstring, (char **) NULL);
-          } else if (quality == 2) { // -qq#
+          minratio = (REAL) strtod(workstring, (char **) NULL);
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
             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++;
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+      } else if (argv[i][j] == 'R') {
+        coarsen = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          coarsen_param = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
           }
-          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')) {
+          weighted_param = (argv[i][j + 1] - '0');
+          j++;
+        }
+      } else if (argv[i][j] == 'b') {
+        // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
+        brio_hilbert = 1;
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -3121,8 +3150,66 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          weighted_param = (int) strtol(workstring, (char **) NULL, 0);
+          brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
+            brio_ratio = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.') || (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] == '-')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
+          }
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+              (argv[i][j + 1] == '.') || (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] == '-')) {
+              j++;
+              workstring[k] = argv[i][j];
+              k++;
+            }
+            workstring[k] = '\0';
+            hilbert_order = (REAL) strtod(workstring, (char **) NULL);
+          }
+        }
+        if (brio_threshold == 0) { // -b0
+          brio_hilbert = 0; // Turn off BRIO-Hilbert sorting. 
         }
+        if (brio_ratio >= 1.0) { // -b/1
+          no_sort = 1;
+          brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
+        }
+      } else if (argv[i][j] == 'l') {
+        incrflip = 1;
+      } else if (argv[i][j] == 'L') {
+        flipinsert = 1;
+      } else if (argv[i][j] == 'm') {
+        metric = 1;
       } else if (argv[i][j] == 'a') {
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
@@ -3141,71 +3228,44 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           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;
+        regionattrib = 1;
+      } else if (argv[i][j] == 'D') {
+        conforming = 1;
+        if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
+          reflevel = (argv[i][j + 1] - '1') + 1; 
+          j++;
         }
-      } 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] == 'M') {
+        nomergefacet = 1;
+        nomergevertex = 1;
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
+          nomergefacet = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
+            nomergevertex = (argv[i][j + 1] - '0');
+            j++;
+          }
+        }
+      } else if (argv[i][j] == 'X') {
+        if (argv[i][j + 1] == '1') {
+          nostaticfilter = 1;
+          j++;
+        } else {
+          noexact = 1;
+        }
       } else if (argv[i][j] == 'z') {
         zeroindex = 1;
       } else if (argv[i][j] == 'f') {
-        facesout = 1;
+        facesout++;
       } else if (argv[i][j] == 'e') {
         edgesout++;
       } else if (argv[i][j] == 'n') {
@@ -3214,10 +3274,8 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
         voroout = 1;
       } else if (argv[i][j] == 'g') {
         meditview = 1;
-      } else if (argv[i][j] == 'K') {
+      } 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') {
@@ -3226,10 +3284,6 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
         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') {
@@ -3249,53 +3303,38 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
           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#
+        if (argv[i][j + 1] == '2') {
+          order = 2;
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          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';
             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] == '+')) {
+        if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
+          optlevel = (argv[i][j + 1] - '0');
+          j++;
+        }
+        if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
+          j++;
+          if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
+            optscheme = (argv[i][j + 1] - '0');
             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;
+      } else if (argv[i][j] == 'T') {
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -3307,9 +3346,17 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          reflevel = (int) strtol(workstring, (char **) NULL, 0);
+          epsilon = (REAL) strtod(workstring, (char **) NULL);
         }
-      } else if (argv[i][j] == 'T') {
+      } else if (argv[i][j] == 'R') {
+        reversetetori = 1;
+      } 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] == 'x') {
         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
             (argv[i][j + 1] == '.')) {
           k = 0;
@@ -3321,14 +3368,14 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
             k++;
           }
           workstring[k] = '\0';
-          epsilon = (REAL) strtod(workstring, (char **) NULL);
+          tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
+          if (tetrahedraperblock > 8188) {
+            vertexperblock = tetrahedraperblock / 2;
+            shellfaceperblock = vertexperblock / 2;
+          } else {
+            tetrahedraperblock = 8188;
+          }
         }
-      } 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();
@@ -3345,7 +3392,7 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
     if (infilename[0] == '\0') {
       // No input file name. Print the syntax and exit.
       syntax();
-      terminatetetgen(0);
+      terminatetetgen(NULL, 0);
     }
     // Recognize the object from file extension if it is available.
     if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
@@ -3395,32 +3442,41 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
   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 && !quality) { // -r only
+    // Reconstruct a mesh, no mesh optimization.
+    optlevel = 0;
   }
-  if (refine && (plc || noiterationnum)) {
-    printf("Error:  Switches %s cannot use together with -r.\n",
-           "-p, -d, and -I");
-    return false;
+  if (insertaddpoints && (optlevel == 0)) { // with -i option
+    optlevel = 2;
   }
+  if (coarsen && (optlevel == 0)) { // with -R option
+    optlevel = 2;
+  }
+
+  // Detect improper combinations of switches.
   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;
+  if (convex) { // -c
+    if (plc && !regionattrib) {
+      // -A (region attribute) is needed for marking exterior tets (-1).
+      regionattrib = 1; 
+    }
   }
+
+  // Note: -A must not used together with -r option. 
   // 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;
   }
+  // 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;
+  }
   // If '-a' or '-aa' is in use, enable '-q' option too.
   if (fixedvolume || varvolume) {
     if (quality == 0) {
@@ -3430,18 +3486,20 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
       }
     }
   }
-  if (ocount == 0) {
-    // No user-specified dihedral angle bound. Use default ones.
-    if (!quality) {
-      if (optmaxdihedral < 179.0) {
+  // No user-specified dihedral angle bound. Use default ones.
+  if (!quality) {
+    if (optmaxdihedral < 179.0) {
+      if (nobisect) {  // with -Y option
         optmaxdihedral = 179.0;
+      } else { // -p only
+        optmaxdihedral = 179.999;
       }
-      if (optminsmtdihed < 179.999) {
-        optminsmtdihed = 179.999;
-      }
-      if (optminslidihed < 179.999) {
-        optminslidihed = 179.99;
-      }
+    }
+    if (optminsmtdihed < 179.999) {
+      optminsmtdihed = 179.999;
+    }
+    if (optminslidihed < 179.999) {
+      optminslidihed = 179.999;
     }
   }
 
@@ -3497,18 +3555,25 @@ bool tetgenbehavior::parse_commandline(int argc, char **argv)
 
 // 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
+int tetgenmesh::bondtbl[12][12] = {{0,},};
+int tetgenmesh::enexttbl[12] = {0,};
+int tetgenmesh::eprevtbl[12] = {0,};
+int tetgenmesh::enextesymtbl[12] = {0,};
+int tetgenmesh::eprevesymtbl[12] = {0,};
+int tetgenmesh::eorgoppotbl[12] = {0,};
+int tetgenmesh::edestoppotbl[12] = {0,};
+int tetgenmesh::fsymtbl[12][12] = {{0,},};
+int tetgenmesh::facepivot1[12] = {0,};
+int tetgenmesh::facepivot2[12][12] = {{0,},};
+int tetgenmesh::tsbondtbl[12][6] = {{0,},};
+int tetgenmesh::stbondtbl[12][6] = {{0,},};
+int tetgenmesh::tspivottbl[12][6] = {{0,},};
+int tetgenmesh::stpivottbl[12][6] = {{0,},};
+
+// Table 'esymtbl' 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};
+int tetgenmesh::esymtbl[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
@@ -3525,6 +3590,11 @@ int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
 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};
 
+// Edge versions whose apex or opposite may be dummypoint.
+
+int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
+
+
 // Table 'snextpivot' takes an edge version as input, returns the next edge
 //   version in the same edge ring.
 
@@ -3538,11 +3608,91 @@ 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.
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// inittable()    Initialize the look-up tables.                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::inittables()
+{
+  int i, j;
+
+
+  // i = t1.ver; j = t2.ver;
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 12; j++) {
+      bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
+    }
+  }
+
+
+  // i = t1.ver; j = t2.ver
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 12; j++) {
+      fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
+    }
+  }
+
+
+  for (i = 0; i < 12; i++) {
+    facepivot1[i] = (esymtbl[i] & 3);
+  }
+
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 12; j++) {
+      facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
+    }
+  }
 
-int tetgenmesh::epivot[4] = {4, 5, 2, 11};
+  for (i = 0; i < 12; i++) {
+    enexttbl[i] = (i + 4) % 12;
+    eprevtbl[i] = (i + 8) % 12;
+  }
+
+  for (i = 0; i < 12; i++) {
+    enextesymtbl[i] = esymtbl[enexttbl[i]];
+    eprevesymtbl[i] = esymtbl[eprevtbl[i]];
+  }
+
+  for (i = 0; i < 12; i++) {
+    eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]];
+    edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]];
+  }
+
+  int soffset, toffset;
+
+  // i = t.ver, j = s.shver
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 6; j++) {
+      if ((j & 1) == 0) {
+        soffset = (6 - ((i & 12) >> 1)) % 6;
+        toffset = (12 - ((j & 6) << 1)) % 12;
+      } else {
+        soffset = (i & 12) >> 1;
+        toffset = (j & 6) << 1;
+      }
+      tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
+      stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
+    }
+  }
 
 
+  // i = t.ver, j = s.shver
+  for (i = 0; i < 12; i++) {
+    for (j = 0; j < 6; j++) {
+      if ((j & 1) == 0) {
+        soffset = (i & 12) >> 1;
+        toffset = (j & 6) << 1;
+      } else {
+        soffset = (6 - ((i & 12) >> 1)) % 6;
+        toffset = (12 - ((j & 6) << 1)) % 12;
+      }
+      tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
+      stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
+    }
+  }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -3576,6 +3726,7 @@ void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
   log2objectsperblock = log2objperblk;
   // Compute the number of objects in each block.
   objectsperblock = ((int) 1) << log2objectsperblock;
+  objectsperblockmark = objectsperblock - 1;
 
   // No memory has been allocated.
   totalmemory = 0l;
@@ -3733,26 +3884,22 @@ void* tetgenmesh::arraypool::lookup(int objectindex)
 //                                                                           //
 // newindex()    Allocate space for a fresh object from the pool.            //
 //                                                                           //
+// 'newptr' returns a pointer to the new object (it must not be a NULL).     //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 int tetgenmesh::arraypool::newindex(void **newptr)
 {
-  void *newobject;
-  int newindex;
-
   // Allocate an object at index 'firstvirgin'.
-  newindex = objects;
-  newobject = (void *) (getblock(objects) +
+  int newindex = objects;
+  *newptr = (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.                            //
@@ -3766,7 +3913,6 @@ tetgenmesh::memorypool::memorypool()
   deaditemstack = (void *) NULL;
   pathblock = (void **) NULL;
   pathitem = (void *) NULL;
-  itemwordtype = POINTER;
   alignbytes = 0;
   itembytes = itemwords = 0;
   itemsperblock = 0;
@@ -3775,10 +3921,10 @@ tetgenmesh::memorypool::memorypool()
   pathitemsleft = 0;
 }
 
-tetgenmesh::memorypool::
-memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment)
+tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize, 
+                                   int alignment)
 {
-  poolinit(bytecount, itemcount, wtype, alignment);
+  poolinit(bytecount, itemcount, wsize, alignment);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -3812,14 +3958,9 @@ tetgenmesh::memorypool::~memorypool()
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::memorypool::
-poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
+void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
+                                      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.
@@ -3844,7 +3985,7 @@ poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
   firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
                                 + alignbytes); 
   if (firstblock == (void **) NULL) {
-    terminatetetgen(1);
+    terminatetetgen(NULL, 1);
   }
   // Set the next block pointer to NULL.
   *(firstblock) = (void *) NULL;
@@ -3908,7 +4049,7 @@ void* tetgenmesh::memorypool::alloc()
         newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) 
                                     + alignbytes);
         if (newblock == (void **) NULL) {
-          terminatetetgen(1);
+          terminatetetgen(NULL, 1);
         }
         *nowblock = (void *) newblock;
         // The next block pointer is NULL.
@@ -3929,11 +4070,7 @@ void* tetgenmesh::memorypool::alloc()
     // 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);
-    }
+    nextitem = (void *) ((uintptr_t) nextitem + itembytes);
     unallocateditems--;
     maxitems++;
   }
@@ -4017,25 +4154,18 @@ void* tetgenmesh::memorypool::traverse()
   }
   newitem = pathitem;
   // Find the next item in the block.
-  if (itemwordtype == POINTER) {
-    pathitem = (void *) ((void **) pathitem + itemwords);
-  } else {
-    pathitem = (void *) ((REAL *) pathitem + itemwords);
-  }
+  pathitem = (void *) ((uintptr_t) pathitem + itembytes);
   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.                                         //
+// saved in 'idx2verlist[in->firstnumber]'.                                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -4052,14 +4182,13 @@ void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
 
   points->traversalinit();
   pointloop = pointtraverse();
-  idx =  in->firstnumber;;
+  idx =  in->firstnumber;
   while (pointloop != (point) NULL) {
     idx2verlist[idx++] = pointloop;
     pointloop = pointtraverse();
   }
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // makesubfacemap()    Create a map from vertex to subfaces incident at it.  //
@@ -4163,15 +4292,13 @@ void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
   //   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]);
-    }
-  //}
+  // 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);
 }
@@ -4244,38 +4371,6 @@ tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
   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;
-}
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -4319,6 +4414,7 @@ tetgenmesh::point tetgenmesh::pointtraverse()
 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;
@@ -4329,12 +4425,12 @@ void tetgenmesh::maketetrahedron(triface *newtet)
   newtet->tet[5] = NULL;
   newtet->tet[6] = NULL;
   newtet->tet[7] = NULL;
-  // No attached segments and sbfaces yet.
+  // No attached segments and subfaces yet.
   newtet->tet[8] = NULL; 
   newtet->tet[9] = NULL; 
-  // Initialize the marker (for flags).
+  // Initialize the marker (clear all flags).
   setelemmarker(newtet->tet, 0);
-  for (int i = 0; i < in->numberoftetrahedronattributes; i++) {
+  for (int i = 0; i < numelemattrib; i++) {
     setelemattribute(newtet->tet, i, 0.0);
   }
   if (b->varvolume) {
@@ -4348,13 +4444,14 @@ void tetgenmesh::maketetrahedron(triface *newtet)
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // makeshellface()    Create a new shellface with version zero. Used for     //
-//                    both subfaces and seusegments.                         //
+//                    both subfaces and subsegments.                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::makeshellface(memorypool *pool, face *newface)
 {
   newface->sh = (shellface *) pool->alloc();
+
   // No adjointing subfaces.
   newface->sh[0] = NULL;
   newface->sh[1] = NULL;
@@ -4370,19 +4467,18 @@ void tetgenmesh::makeshellface(memorypool *pool, face *newface)
   // No adjoining tetrahedra.
   newface->sh[9] = NULL;
   newface->sh[10] = NULL;
-  if (b->quality && checkconstraints) {
+  if (checkconstraints) {
     // Initialize the maximum area bound.
     setareabound(*newface, 0.0);
   }
-
   // Clear the infection and marktest bits.
   ((int *) (newface->sh))[shmarkindex + 1] = 0;
-  
+  if (useinsertradius) {
+    setfacetindex(*newface, 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;
 }
 
@@ -4394,16 +4490,21 @@ void tetgenmesh::makeshellface(memorypool *pool, face *newface)
 
 void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
 {
-  int ptmark, i;
+  int i;
 
   *pnewpoint = (point) points->alloc();
+
+  // Initialize the point attributes.
+  for (i = 0; i < numpointattrib; i++) {
+    (*pnewpoint)[3 + i] = 0.0;
+  }
   // 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) {
+  if (b->plc || b->refine) {
     // Initialize the point-to-simplex field.
     setpoint2sh(*pnewpoint, NULL);
     if (b->metric && (bgm != NULL)) {
@@ -4411,20 +4512,11 @@ void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
     }
   }
   // Initialize the point marker (starting from in->firstnumber).
-  ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
-  setpointmark(*pnewpoint, ptmark);
-  // Initialize the point type.
+  setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
+  // Clear all flags.
+  ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
+  // Initialize (set) 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);
-  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -4440,29 +4532,61 @@ void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
 
 void tetgenmesh::initializepools()
 {
-  enum memorypool::wordtype wtype;
-  int pointsize, elesize, shsize;
+  int pointsize = 0, elesize = 0, shsize = 0;
+  int i;
 
   if (b->verbose) {
     printf("  Initializing memorypools.\n");
+    printf("  tetrahedron per block: %d.\n", b->tetrahedraperblock);
+  }
+
+  inittables();
+
+  // There are three input point lists available, which are in, addin,
+  //   and bgm->in. These point lists may have different number of 
+  //   attributes. Decide the maximum number.
+  numpointattrib = in->numberofpointattributes;
+  if (bgm != NULL) {
+    if (bgm->in->numberofpointattributes > numpointattrib) {
+      numpointattrib = bgm->in->numberofpointattributes;
+    }
+  }
+  if (addin != NULL) {
+    if (addin->numberofpointattributes > numpointattrib) {
+      numpointattrib = addin->numberofpointattributes;
+    }
+  }
+  if (b->weighted || b->flipinsert) { // -w or -L.
+    // The internal number of point attribute needs to be at least 1
+    //   (for storing point weights).
+    if (numpointattrib == 0) {    
+      numpointattrib = 1;
+    }
   }
 
   // Default varconstraint = 0;
   if (in->segmentconstraintlist || in->facetconstraintlist) {
     checkconstraints = 1;
   }
+  if (b->plc || b->refine) {
+    // Save the insertion radius for Steiner points if boundaries
+    //   are allowed be split.
+    if (!b->nobisect || checkconstraints) {
+      useinsertradius = 1;
+    }
+  }
 
-  // Each vertex has three coordinates plus a weight, hence 4 REALs.
   // The index within each point at which its metric tensor is found. 
+  // Each vertex has three coordinates.
   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;
+    // '-s' option (PSC), the u,v coordinates are provided.
+    pointmtrindex = 5 + numpointattrib;
+    // The index within each point at which its u, v coordinates are found.
+    // Comment: They are saved after the list of point attributes.
+    pointparamindex = pointmtrindex - 2;
   } else {
-    pointmtrindex = 4 + in->numberofpointattributes;
+    pointmtrindex = 3 + numpointattrib;
   }
-  // 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.
@@ -4480,6 +4604,11 @@ void tetgenmesh::initializepools()
     // For '-q' option. Make sure to have space for saving a scalar value.
     sizeoftensor = b->quality ? 1 : 0;
   }
+  if (useinsertradius) {
+    // Increase a space (REAL) for saving point insertion radius, it is
+    //   saved directly after the metric. 
+    sizeoftensor++;
+  }
   // 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.
@@ -4491,19 +4620,11 @@ void tetgenmesh::initializepools()
     //   - 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().
+      // Increase one pointer 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();
@@ -4513,18 +4634,14 @@ void tetgenmesh::initializepools()
   // 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:
+  // Now point size is the ints (indicated 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);
+  points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
 
   if (b->verbose) {
     printf("  Size of a point: %d bytes.\n", points->itembytes);
@@ -4532,7 +4649,32 @@ void tetgenmesh::initializepools()
 
   // Initialize the infinite vertex.
   dummypoint = (point) new char[pointsize];
-  setpointmark(dummypoint, -1);
+  // Initialize all fields of this point.
+  dummypoint[0] = 0.0;
+  dummypoint[1] = 0.0;
+  dummypoint[2] = 0.0;
+  for (i = 0; i < numpointattrib; i++) {
+    dummypoint[3 + i] = 0.0;
+  }
+  // Initialize the metric tensor.
+  for (i = 0; i < sizeoftensor; i++) {
+    dummypoint[pointmtrindex + i] = 0.0;
+  }
+  setpoint2tet(dummypoint, NULL);
+  setpoint2ppt(dummypoint, NULL);
+  if (b->plc || b->psc || b->refine) {
+    // Initialize the point-to-simplex field.
+    setpoint2sh(dummypoint, NULL);
+    if (b->metric && (bgm != NULL)) {
+      setpoint2bgmtet(dummypoint, NULL);
+    }
+  }
+  // Initialize the point marker (starting from in->firstnumber).
+  setpointmark(dummypoint, -1); // The unique marker for dummypoint.
+  // Clear all flags.
+  ((int *) (dummypoint))[pointmarkindex + 1] = 0;
+  // Initialize (set) the point type. 
+  setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
 
   // The number of bytes occupied by a tetrahedron is varying by the user-
   //   specified options. The contents of the first 12 pointers are listed
@@ -4558,26 +4700,28 @@ void tetgenmesh::initializepools()
   assert((sizeof(tetrahedron) % sizeof(int)) == 0);
   elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
 
+  // The actual number of element attributes. Note that if the
+  //   `b->regionattrib' flag is set, an additional attribute will be added.
+  numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
+
   // 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);
+  // The index within each element at which the maximum volume bound is
+  //   found, where the index is measured in REALs.
+  volumeboundindex = elemattribindex + numelemattrib;
   // 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) {
+  } else if (numelemattrib > 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);
+  tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
+                                16);
 
   if (b->verbose) {
     printf("  Size of a tetrahedron: %d (%d) bytes.\n", elesize,
@@ -4594,7 +4738,7 @@ void tetgenmesh::initializepools()
     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) {
+    if (checkconstraints) { 
       shsize = (areaboundindex + 1) * sizeof(REAL);
     } else {
       shsize = areaboundindex * sizeof(REAL);
@@ -4604,13 +4748,17 @@ void tetgenmesh::initializepools()
     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);
+    shsize = (shmarkindex + 2) * sizeof(shellface);
+    if (useinsertradius) {
+      // Increase the number of byte by one integer for storing facet index.
+      //    set/read by setfacetindex() and getfacetindex.
+      shsize = (shmarkindex + 3) * 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);
+    subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
 
     if (b->verbose) {
       printf("  Size of a shellface: %d (%d) bytes.\n", shsize,
@@ -4619,40 +4767,36 @@ void tetgenmesh::initializepools()
 
     // Initialize the pool of subsegments. The subsegment's record is same
     //   with subface.
-    subsegs = new memorypool(shsize, b->shellfaceperblock, 
-                             memorypool::POINTER, 8);
+    subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
 
     // Initialize the pool for tet-subseg connections.
     tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock, 
-                                 memorypool::POINTER, 0);
+                                 sizeof(void *), 0);
     // Initialize the pool for tet-subface connections.
     tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock, 
-                                 memorypool::POINTER, 0);
+                                 sizeof(void *), 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.
+    // Initialize arraypools for surface point insertion/deletion.
     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);
+  // Initialize the pools for flips.
+  flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
   unflipqueue = new arraypool(sizeof(badface), 10);
 
-  // Initialize the arraypools for Bowyer-Watson algorithm.
+  // Initialize the arraypools for point insertion.
   cavetetlist = new arraypool(sizeof(triface), 10);
   cavebdrylist = new arraypool(sizeof(triface), 10);
   caveoldtetlist = new arraypool(sizeof(triface), 10);
@@ -4668,9 +4812,148 @@ void tetgenmesh::initializepools()
 ////                                                                       ////
 
 // PI is the ratio of a circle's circumference to its diameter.
-
 REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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 circumscribed 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;
+
+  sign = insphere(pa, pb, pc, pd, pe);
+  if (sign != 0.0) {
+    return sign;
+  }
+
+  // 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 hyperplane 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;
+
+  sign = orient4d(pa, pb, pc, pd, pe, 
+                  aheight, bheight, cheight, dheight, eheight);
+  if (sign != 0.0) {
+    return sign;
+  }
+
+  // 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;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // tri_edge_test()    Triangle-edge intersection test.                       //
@@ -4684,7 +4967,7 @@ REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
 // 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:                    //
+// The return 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.        //
@@ -4693,6 +4976,10 @@ REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
+
+#define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
+
 int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q, 
                             point R, int level, int *types, int *pos)
 {
@@ -4709,14 +4996,14 @@ int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q,
       REAL n[3], len;
       // Calculate a lift point, saved in dummypoint.
       facenormal(A, B, C, n, 1, NULL);
-      len = sqrt(DOT(n, n));
+      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 = distance(A, B);
+        len += distance(B, C);
+        len += distance(C, A);
         len /= 3.0;
         R = abovept; //dummypoint;
         R[0] = A[0] + len * n[0];
@@ -4737,7 +5024,6 @@ int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q,
   sB = orient3d(P, Q, R, B);
   sC = orient3d(P, Q, R, C);
 
-  triedgcopcount++;
 
   if (sA < 0) {
     if (sB < 0) {
@@ -5321,7 +5607,6 @@ int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
   REAL s1, s2, s3;
   int z1;
 
-  triedgcount++;
 
   if (sP < 0) {
     if (sQ < 0) { // (--) disjoint
@@ -5816,6 +6101,9 @@ void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
 // Return a negative value if pd is inside the circumcircle of the triangle  //
 // pa, pb, and pc.                                                           //
 //                                                                           //
+// IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input  //
+// triangles are [a,b,c] and [b,a,d].                                        //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
@@ -5825,19 +6113,19 @@ REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
 
   // 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);
+  area2[0] = dot(n1, n1);
   facenormal(pb, pa, pd, n2, 1, NULL);
-  area2[1] = DOT(n2, n2);
+  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);
+    d = distance(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);
+      d = distance(c, pc);
     } else {
       // The four points are collinear. This case only happens on the boundary.
       return 0; // Return "not inside".
@@ -5854,182 +6142,33 @@ REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// 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.                      //
+// facenormal()    Calculate the normal of the face.                         //
 //                                                                           //
-// 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.           //
+// 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.                        //
 //                                                                           //
-// 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.       //
+// 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.                                //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
+void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
+                            REAL* lav)
 {
-  REAL sign;
-
-  inspherecount++;
-
-  sign = insphere(pa, pb, pc, pd, pe);
-  if (sign != 0.0) {
-    return sign;
-  }
-
-  insphere_sos_count++;
+  REAL v1[3], v2[3], v3[3], *pv1, *pv2;
+  REAL L1, L2, L3;
 
-  // 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];
+  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) {
@@ -6037,9 +6176,9 @@ void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
     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);
+    L1 = dot(v1, v1);
+    L2 = dot(v2, v2);
+    L3 = dot(v3, v3);
     // Sort the three edge lengths.
     if (L1 < L2) {
       if (L2 < L3) {
@@ -6063,7 +6202,7 @@ void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
   }
 
   // Calculate the face normal.
-  CROSS(pv1, pv2, n);
+  cross(pv1, pv2, n);
   // Inverse the direction;
   n[0] = -n[0];
   n[1] = -n[1];
@@ -6097,9 +6236,8 @@ REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
   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;
@@ -6108,7 +6246,6 @@ REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
   return sqrt(dot(v2, v2) - l_p * l_p);
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // triarea()    Return the area of a triangle.                               //
@@ -6132,6 +6269,27 @@ REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
   return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
 }
 
+REAL tetgenmesh::orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
+{
+  REAL adx, bdx, cdx;
+  REAL ady, bdy, cdy;
+  REAL adz, bdz, cdz;
+
+  adx = pa[0] - pd[0];
+  bdx = pb[0] - pd[0];
+  cdx = pc[0] - pd[0];
+  ady = pa[1] - pd[1];
+  bdy = pb[1] - pd[1];
+  cdy = pc[1] - pd[1];
+  adz = pa[2] - pd[2];
+  bdz = pb[2] - pd[2];
+  cdz = pc[2] - pd[2];
+
+  return adx * (bdy * cdz - bdz * cdy)
+       + bdx * (cdy * adz - cdz * ady)
+       + cdx * (ady * bdz - adz * bdy);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // interiorangle()    Return the interior angle (0 - 2 * PI) between vectors //
@@ -6161,9 +6319,8 @@ REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
   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. 
@@ -6205,9 +6362,7 @@ void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
   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;
@@ -6249,7 +6404,6 @@ void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
   prj[2] = p[2] - dist * fnormal[2];
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // facedihedral()    Return the dihedral angle (in radian) between two       //
@@ -6303,7 +6457,7 @@ 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;
+  int f1 = 0, f2 = 0, i, j;
 
   vol = 0; // Check if the tet is valid or not.
 
@@ -6359,7 +6513,7 @@ bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
     }
   }
 
-  // Calculate the consine of the dihedral angles of the edges.
+  // Calculate the cosine of the dihedral angles of the edges.
   for (i = 0; i < 6; i++) {
     switch (i) {
     case 0: f1 = 0; f2 = 1; break; // [c,d].
@@ -6371,6 +6525,7 @@ bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
     }
     cosd = -dot(N[f1], N[f2]);
     if (cosd < -1.0) cosd = -1.0; // Rounding.
+    if (cosd >  1.0) cosd =  1.0; // Rounding.
     if (cosdd) cosdd[i] = cosd;
     if (cosmaxd || cosmind) {
       if (i == 0) {
@@ -6388,7 +6543,7 @@ bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tetallnormal()    Get the in-noramls of the four faces of a given tet.    //
+// tetallnormal()    Get the in-normals 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   //
@@ -6507,7 +6662,7 @@ REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
 //                                                                           //
 // 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.//
+// are not NULLs.  Otherwise, return FALSE, the four points are co-planar.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -6559,7 +6714,59 @@ bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
   return true;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// orthosphere()    Calulcate the orthosphere of four weighted points.       //
+//                                                                           //
+// A weighted point (p, P^2) can be interpreted as a sphere centered at the  //
+// point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 +    //
+// p[1]^2 + p[2]^2 - P^2.                                                    //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
+                             REAL  aheight, REAL bheight, REAL cheight, 
+                             REAL  dheight, REAL* orthocent, REAL* radius)
+{
+  REAL A[4][4], rhs[4], D;
+  int indx[4];
+
+  // Set the coefficient matrix A (4 x 4).
+  A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
+  A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
+  A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
+  A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
 
+  // Set the right hand side vector (4 x 1).
+  rhs[0] = 0.5 * aheight;
+  rhs[1] = 0.5 * bheight;
+  rhs[2] = 0.5 * cheight;
+  rhs[3] = 0.5 * dheight;
+
+  // Solve the 4 by 4 equations use LU decomposition with partial pivoting
+  //   and backward and forward substitute..
+  if (!lu_decmp(A, 4, indx, &D, 0)) {
+    if (radius != (REAL *) NULL) *radius = 0.0;
+    return false;
+  }
+  lu_solve(A, 4, indx, rhs, 0);
+
+  if (orthocent != (REAL *) NULL) {
+    orthocent[0] = rhs[1];
+    orthocent[1] = rhs[2];
+    orthocent[2] = rhs[3];
+  }
+  if (radius != (REAL *) NULL) {
+    // rhs[0] = - rheight / 2;
+    // rheight  = - 2 * rhs[0];
+    //          =  r[0]^2 + r[1]^2 + r[2]^2 - radius^2
+    // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
+    //          = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
+    *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
+                   + 2.0 * rhs[0]);
+  }
+  return true;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -6607,7 +6814,55 @@ void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
   }
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// linelineint()    Calculate the intersection(s) of two line segments.      //
+//                                                                           //
+// Calculate the line segment [P, Q] that is the shortest route between two  //
+// lines from A to B and C to D. Calculate also the values of tp and tq      //
+// where: P = A + tp (B - A), and Q = C + tq (D - C).                        //
+//                                                                           //
+// Return 1 if the line segment exists. Otherwise, return 0.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::linelineint(REAL* A, REAL* B, REAL* C, REAL* D, REAL* P, 
+		            REAL* Q, REAL* tp, REAL* tq)
+{
+  REAL vab[3], vcd[3], vca[3];
+  REAL vab_vab, vcd_vcd, vab_vcd;
+  REAL vca_vab, vca_vcd;
+  REAL det, eps;
+  int i;
+
+  for (i = 0; i < 3; i++) {
+    vab[i] = B[i] - A[i];
+    vcd[i] = D[i] - C[i];
+    vca[i] = A[i] - C[i];
+  }
+
+  vab_vab = dot(vab, vab);
+  vcd_vcd = dot(vcd, vcd);
+  vab_vcd = dot(vab, vcd);
 
+  det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
+  // Round the result.
+  eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
+  if (eps < b->epsilon) {
+    return 0;
+  }
+
+  vca_vab = dot(vca, vab);
+  vca_vcd = dot(vca, vcd);
+
+  *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
+  *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
+
+  for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
+  for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
+
+  return 1;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -6656,75 +6911,168 @@ REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
   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.                       //
+// calculateabovepoint()    Calculate a point above a facet in 'dummypoint'. //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flippush(badface*& fstack, triface* flipface)
+bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
+                                     point *ppb, point *ppc)
 {
-  badface *newflipface;
+  point *ppt, pa, pb, pc;
+  REAL v1[3], v2[3], n[3];
+  REAL lab, len, A, area;
+  REAL x, y, z;
+  int i;
 
-  if (!facemarked(*flipface)) {
-    newflipface = (badface *) flippool->alloc();
-    newflipface->tt = *flipface;
-    markface(newflipface->tt);
-    // Push this face into stack.
-    newflipface->nextitem = fstack;
-    fstack = newflipface;
-  }
-}
+  ppt = (point *) fastlookup(facpoints, 0);
+  pa = *ppt; // a is the first point.
+  pb = pc = NULL; // Avoid compiler warnings.
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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]. //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  // 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;
+  }
 
-void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag, 
-                        int chkencflag)
+  // 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)
+{
+  REAL n1[3], n2[3], *norm;
+  REAL len, len1, len2;
+
+  // 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 = distance(pa, pb);
+  dummypoint[0] = pa[0] + len * norm[0];
+  dummypoint[1] = pa[1] + len * norm[1];
+  dummypoint[2] = pa[2] + len * norm[2];
+}
+
+////                                                                       ////
+////                                                                       ////
+//// geom_cxx /////////////////////////////////////////////////////////////////
+
+//// flip_cxx /////////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// flip23()    Perform a 2-to-3 flip (face-to-edge flip).                    //
+//                                                                           //
+// 'fliptets' is an array of three tets (handles), where the [0] and [1] are  //
+// [a,b,c,d] and [b,a,c,e].  The three new tets: [e,d,a,b], [e,d,b,c], and   //
+// [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'.  As a result,  //
+// 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 'fc->enqflag' is set, convex hull faces will be queued for flipping.   //
+// In particular, if 'fc->enqflag' is 1, it is called by incrementalflip()   //
+// after the insertion of a new point.  It is assumed that 'd' is the new    //
+// point. IN this case, only link faces of 'd' are queued.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
 {
   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.
+  REAL attrib, volume;
   int dummyflag = 0;  // range = {-1, 0, 1, 2}.
   int i;
 
@@ -6752,16 +7100,12 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
     }
   }
 
-  pa = org(fliptets[0]);
+  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.
@@ -6779,6 +7123,7 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
   fliptets[1].ver = 11;
   setelemmarker(fliptets[0].tet, 0); // Clear all flags.
   setelemmarker(fliptets[1].tet, 0);
+  // NOTE: the element attributes and volume constraint remain unchanged.
   if (checksubsegflag) {
     // Dealloc the space to subsegments.
     if (fliptets[0].tet[8] != NULL) {
@@ -6803,6 +7148,15 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
   }
   // Create a new tet.
   maketetrahedron(&(fliptets[2]));
+  // The new tet have the same attributes from the old tet.
+  for (i = 0; i < numelemattrib; i++) {
+    attrib = elemattribute(fliptets[0].tet, i);
+    setelemattribute(fliptets[2].tet, i, attrib);
+  }
+  if (b->varvolume) {
+    volume = volumebound(fliptets[0].tet);
+    setvolumebound(fliptets[2].tet, volume);
+  }
 
   if (hullflag > 0) {
     // Check if d is dummytet.
@@ -6836,7 +7190,8 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
     setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
   }
 
-  if (calc_tetprism_vol) {
+  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
+    REAL volneg[2], volpos[3], vol_diff;
     if (pd != dummypoint) {
       if (pc != dummypoint) {
         volpos[0] = tetprismvol(pe, pd, pa, pb);
@@ -6859,8 +7214,8 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
       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)
+    fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
+  }
 
   // Bond three new tets together.
   for (i = 0; i < 3; i++) {
@@ -6869,43 +7224,36 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
   }
   // 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].
+    eorgoppo(fliptets[i], 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].
+    edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
     bond(newface, botcastets[i]);
   }
 
-  // Bond 15 subsegments if there are.
   if (checksubsegflag) {
+    // Bond subsegments if there are.
+    // Each new tet has 5 edges to be checked (except the edge [e,d]). 
+    face checkseg;
     // 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].
+    for (i = 0; i < 3; i++) {      
+      if (issubseg(topcastets[i])) {
+        tsspivot1(topcastets[i], checkseg);
+        eorgoppo(fliptets[i], 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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
     }
     // 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) {
+      eprev(topcastets[i], casface);      
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
         enext(fliptets[i], newface);
         tssbond1(newface, checkseg);
         sstbond1(checkseg, newface);
@@ -6913,22 +7261,16 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
         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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
     }
     // 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) {
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
         eprev(fliptets[i], newface);
         tssbond1(newface, checkseg);
         sstbond1(checkseg, newface);
@@ -6936,75 +7278,53 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
         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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
     }
-  }
+  } // if (checksubsegflag)
 
-  // 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].
+    // Bond 6 subfaces if there are.
+    face checksh;
+    for (i = 0; i < 3; i++) {      
+      if (issubface(topcastets[i])) {
+        tspivot(topcastets[i], checksh);
+        eorgoppo(fliptets[i], newface);
         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 (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
         }
       }
     }
     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]
+      if (issubface(botcastets[i])) {
+        tspivot(botcastets[i], checksh);
+        edestoppo(fliptets[i], newface);
         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 (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
         }
       }
     }
-  }
+  } // if (checksubfaceflag)
 
-  if (chkencflag & 4) {
+  if (fc->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]);
-      }
+      enqueuetetrahedron(&(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]));
+  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
+  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
 
   if (hullflag > 0) {
     if (dummyflag != 0) {
@@ -7037,19 +7357,15 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
     }
   }
 
-  if (flipflag > 0) {
+  if (fc->enqflag > 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]);
+    if (fc->enqflag > 1) {
       for (i = 0; i < 3; i++) {
         enextesym(fliptets[i], newface);
-        //flippush(flipstack, &newface, pe);
         flippush(flipstack, &newface);
       }
     }
@@ -7062,9 +7378,10 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
 //                                                                           //
 // 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].            //
+// 'fliptets' is an array of three tets (handles),  which are [e,d,a,b],     //
+// [e,d,b,c], and [e,d,c,a].  The two new tets: [a,b,c,d] and [b,a,c,e] are  //
+// returned in [0] and [1] of 'fliptets'.  As a result, 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:     //
@@ -7075,35 +7392,32 @@ void tetgenmesh::flip23(triface* fliptets, int hullflag, int flipflag,
 //       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].        //
+// If 'fc->enqflag' is set, convex hull faces will be queued for flipping.   //
+// In particular, if 'fc->enqflag' is 1, it is called by incrementalflip()   //
+// after the insertion of a new point.  It is assumed that 'a' is the new    //
+// point. In this case, only link faces of 'a' are queued.                   //
 //                                                                           //
+// If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a  //
+// segment. There may be two (interior) subfaces sharing at [e,d], which are //
+// [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c),  //
+// or (c,a)  In such case, a 2-to-2 flip is performed on these two subfaces  //
+// and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted   //
+// back into the tetrahedralization.                                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
-                        int chkencflag)
+void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
 {
   triface topcastets[3], botcastets[3];
   triface newface, casface;
-  face checksh; 
+  face flipshs[3]; 
   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.
+  REAL attrib, volume;
   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;
+  int spivot = -1, scount = 0; // for flip22()
+  int t1ver; 
+  int i, j;
 
   if (hullflag > 0) {
     // Check if e is 'dummypoint'.
@@ -7143,36 +7457,24 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
   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);
+    eorgoppo(fliptets[i], casface);
     fsym(casface, topcastets[i]);
   }
   for (i = 0; i < 3; i++) {
-    eprevesym(fliptets[i], casface);
-    enextself(casface);
+    edestoppo(fliptets[i], 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])));
-        }
+        // Found an interior subface.
         stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
         scount++;
       } else {
@@ -7208,7 +7510,28 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
       fliptets[1].tet[9] = NULL;
     }
   }
-
+  if (checksubfaceflag) {
+    if (scount > 0) {
+      // The element attributes and volume constraint must be set correctly.
+      // There are two subfaces involved in this flip. The three tets are
+      //   separated into two different regions, one may be exterior. The
+      //   first region has two tets, and the second region has only one.
+      //   The two created tets must be in the same region as the first region. 
+      //   The element attributes and volume constraint must be set correctly.
+      //assert(spivot != -1);
+      // The tet fliptets[spivot] is in the first region.
+      for (j = 0; j < 2; j++) {
+        for (i = 0; i < numelemattrib; i++) {
+          attrib = elemattribute(fliptets[spivot].tet, i);
+          setelemattribute(fliptets[j].tet, i, attrib);
+        }
+        if (b->varvolume) {
+          volume = volumebound(fliptets[spivot].tet);
+          setvolumebound(fliptets[j].tet, volume);
+        }
+      }
+    }
+  }
   // Delete an old tet.
   tetrahedrondealloc(fliptets[2].tet);
 
@@ -7232,14 +7555,15 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
       esymself(fliptets[0]);
       // Adjust abec -> bace.
       esymself(fliptets[1]);
-      // The hullsize does not changle.
+      // The hullsize does not change.
     }
   } else {
     setvertices(fliptets[0], pa, pb, pc, pd);
     setvertices(fliptets[1], pb, pa, pc, pe);
   }
 
-  if (calc_tetprism_vol) {
+  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
+    REAL volneg[3], volpos[2], vol_diff;
     if (pc != dummypoint) {
       if (pd != dummypoint) {
         volneg[0] = tetprismvol(pe, pd, pa, pb);
@@ -7262,7 +7586,7 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
       volpos[1] = 0.;
     }
     vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
-    tetprism_vol_sum  += vol_diff; // Update the total sum.
+    fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
   }
 
   // Bond abcd <==> bace.
@@ -7281,133 +7605,89 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
   }
 
   if (checksubsegflag) {
-    // Bond segments to new (flipped) tets.
-    for (i = 0; i < 3; i++) {
-      tsspivot1(topcastets[i], checkseg);
-      if (checkseg.sh != NULL) {
+    // Bond 9 segments to new (flipped) tets.
+    for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.      
+      if (issubseg(topcastets[i])) {
+        tsspivot1(topcastets[i], checkseg);
         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.
-          }
+        tssbond1(fliptets[1], checkseg);
+        sstbond1(checkseg, fliptets[1]);
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
       enextself(fliptets[0]);
+      eprevself(fliptets[1]);
     }
     // The three top edges.
-    for (i = 0; i < 3; i++) {
+    for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
       esym(fliptets[0], newface);
-      eprevself(newface); // edge b->d, c->d, a->d.
-      enext(topcastets[i], casface);
-      tsspivot1(casface, checkseg);
-      if (checkseg.sh != NULL) {
+      eprevself(newface); 
+      enext(topcastets[i], casface);      
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
         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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
       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++) {
+    for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
       esym(fliptets[1], newface);
-      enextself(newface); // edge b<-e, c<-e, a<-e.
+      enextself(newface); 
       eprev(botcastets[i], casface);
-      tsspivot1(casface, checkseg);
-      if (checkseg.sh != NULL) {
+      if (issubseg(casface)) {
+        tsspivot1(casface, checkseg);
         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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
       eprevself(fliptets[1]);
     }
-  }
+  } // if (checksubsegflag)
 
   if (checksubfaceflag) {
+    face checksh;
     // 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]
+    for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
+      if (issubface(topcastets[i])) {
+        tspivot(topcastets[i], checksh);
+        esym(fliptets[0], newface); 
         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 (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
         }
       }
       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]
+    for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
+      if (issubface(botcastets[i])) {
+        tspivot(botcastets[i], checksh);
+        esym(fliptets[1], newface); 
         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 (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
         }
       }
       eprevself(fliptets[1]);
     }
-  }
 
-  if (checksubfaceflag) {
     if (scount > 0) {
-      assert(spivot != -1); // spivot = i, in {0,1,2}
+      face flipfaces[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);
+      flip22(flipfaces, 0, fc->chkencflag);
       // Connect the flipped subfaces to flipped tets.
       // First go to the corresponding flipping edge.
       //   Re-use top- and botcastets[0].
@@ -7428,49 +7708,9 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
         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]));
+        // An invalid 2-to-2 flip. Report a bug.
+        terminatetetgen(this, 2); 
+      }
       // Connect the bot subface to the bottom tets.
       esymself(botcastets[0]);
       sesymself(flipfaces[1]);
@@ -7482,74 +7722,24 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
         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);
+        // An invalid 2-to-2 flip. Report a bug.
+        terminatetetgen(this, 2);  
       }
-      // // Push botcastets[0] into queue for checking new sliver.
-      // assert(oppo(botcastets[0]) != dummypoint);
-      // flippush(&(botcastets[0]), oppo(botcastets[0]));
-    }
-  }
+    } // if (scount > 0)
+  } // if (checksubfaceflag)
 
-  if (chkencflag & 4) {
+  if (fc->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]);
-      }
+      enqueuetetrahedron(&(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]));
+  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
 
   if (hullflag > 0) {
     if (dummyflag != 0) {
@@ -7572,14 +7762,14 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
     }
   }
   
-  if (flipflag > 0) {
+  if (fc->enqflag > 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) {
+    if (fc->enqflag > 1) {
       //pb = dest(fliptets[0]);
       eprevesym(fliptets[0], newface);
       flippush(flipstack, &newface);
@@ -7605,28 +7795,28 @@ void tetgenmesh::flip32(triface* fliptets, int hullflag, int flipflag,
 // 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 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
+// The 'hullsize' may be changed.  Note that p may be dummypoint.  In this   //
+// case, four hull tets are replaced by one real tet.                        //
 //                                                                           //
 // 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.                               //
 //                                                                           //
+// If it is called by the routine incrementalflip(), we assume that d is the //
+// newly inserted vertex.                                                    //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
-                        int chkencflag)
+void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
 {
   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 t1ver; 
   int i;
 
   pa =  org(fliptets[3]);
@@ -7635,11 +7825,7 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
   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++;
+  flip41count++;
 
   // Get the outer boundary faces.
   for (i = 0; i < 3; i++) {
@@ -7652,8 +7838,6 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
   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]);
@@ -7683,9 +7867,11 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
     }
   } // if (checksubfaceflag)
 
+
   // Re-use fliptets[0] for [a,b,c,d].
   fliptets[0].ver = 11;
   setelemmarker(fliptets[0].tet, 0); // Clean all flags.
+  // NOTE: the element attributes and volume constraint remain unchanged.
   if (checksubsegflag) {
     // Dealloc the space to subsegments.
     if (fliptets[0].tet[8] != NULL) {
@@ -7700,19 +7886,20 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
       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++;
+  if (pp != dummypoint) {
+    // 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'.
+    // One of the five vertices may be 'dummypoint'.
     if (pa == dummypoint) {
       // pa is dummypoint.
       setvertices(fliptets[0], pc, pb, pd, pa);
@@ -7733,17 +7920,26 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
       dummyflag = 4;
     } else {
       setvertices(fliptets[0], pa, pb, pc, pd);
-      dummyflag = 0;
+      if (pp == dummypoint) {
+        dummyflag = -1;
+      } else {
+        dummyflag = 0;
+      }
     }
     if (dummyflag > 0) {
-      // We delete 3 hull tets, and create 1 hull tet.
+      // We deleted 3 hull tets, and create 1 hull tet.
       hullsize -= 2;
+    } else if (dummyflag < 0) {
+      // We deleted 4 hull tets.
+      hullsize -= 4;
+      // meshedges does not change.
     }
   } else {
     setvertices(fliptets[0], pa, pb, pc, pd);
   }
 
-  if (calc_tetprism_vol) {
+  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
+    REAL volneg[4], volpos[1], vol_diff;
     if (dummyflag > 0) {
       if (pa == dummypoint) {
         volneg[0] = 0.;
@@ -7767,6 +7963,12 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
         volneg[3] = tetprismvol(pa, pb, pc, pp);
       }
       volpos[0] = 0.;
+    } else if (dummyflag < 0) {
+      volneg[0] = 0.;
+      volneg[1] = 0.;
+      volneg[2] = 0.;
+      volneg[3] = 0.;
+      volpos[0] = tetprismvol(pa, pb, pc, pd);
     } else {
       volneg[0] = tetprismvol(pp, pd, pa, pb);
       volneg[1] = tetprismvol(pp, pd, pb, pc);
@@ -7775,7 +7977,7 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
       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.
+    fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
   }
 
   // Bond the new tet to adjacent tets.
@@ -7787,40 +7989,29 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
   bond(fliptets[0], botcastet);
 
   if (checksubsegflag) {
+    face checkseg;
     // 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) {
+      if (issubseg(newface)) {
+        tsspivot1(newface, checkseg);
         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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
       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) {
+      if (issubseg(topcastets[i])) {
+        tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
         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.
-          }
+        if (fc->chkencflag & 1) {
+          enqueuesubface(badsubsegs, &checkseg);
         }
       }
       enextself(fliptets[0]);
@@ -7828,40 +8019,29 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
   }
 
   if (checksubfaceflag) {
+    face checksh;
     // 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) {
+      if (issubface(topcastets[i])) {
+        tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
         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
-          }
+        if (fc->chkencflag & 2) {
+          enqueuesubface(badsubfacs, &checksh);
         }
       }
       enextself(fliptets[0]);
     }
-    tspivot(botcastet, checksh); // At face [b,a,c]
-    if (checksh.sh != NULL) {
+    if (issubface(botcastet)) {
+      tspivot(botcastet, checksh); // At face [b,a,c]
       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 (fc->chkencflag & 2) {
+        enqueuesubface(badsubfacs, &checksh);
       }
     }
-  }
 
-  if (checksubfaceflag) {
     if (spivot >= 0) {
       // Perform a 3-to-1 flip in surface triangulation.
       // Depending on the value of 'spivot', the three subfaces are:
@@ -7895,30 +8075,26 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
     } // 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]);
-    }
+  if (fc->chkencflag & 4) {
+    enqueuetetrahedron(&(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]));
+  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
+  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
 
-  if (flipflag > 0) {
+  if (fc->enqflag > 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])); // [a,b,c] (opposite to new point).
+    if (fc->enqflag > 1) {
+      for (i = 0; i < 3; i++) {
+        esym(fliptets[0], newface);
+        flippush(flipstack, &newface);
+        enextself(fliptets[0]);
+      }
     }
-    flippush(flipstack, &(fliptets[0]));
   }
 
   recenttet = fliptets[0];
@@ -7926,7 +8102,7 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flipnm()    Try to flip an edge through a sequence of elementary flips.   //
+// flipnm()    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.,//
@@ -7951,7 +8127,6 @@ void tetgenmesh::flip41(triface* fliptets, int hullflag, int flipflag,
 //  - Neither a nor b is 'dummypoint'.                                       //
 //  - [a,b] must not be a segment.                                           //
 //                                                                           //
-//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
@@ -7959,27 +8134,19 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
 {
   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;
+  REAL ori;
+  int hullflag, hulledgeflag;
   int reducflag, rejflag;
-  int hullflag;
   int reflexlinkedgecount;
   int edgepivot;
   int n1, nn;
+  int t1ver;
   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;
@@ -7987,9 +8154,7 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
     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) {
+        if (issubface(abtets[i])) {
           continue; // Skip a subface.
         }
       }
@@ -7998,32 +8163,20 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           (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;
+        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.
-        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.
+
+      // Decide whether [a,b,c] is flippable or not.
+      reducflag = 0; 
 
       hullflag = (pc == dummypoint); // pc may be dummypoint.
+      hulledgeflag = 0;
       if (hullflag == 0) {
         ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
         if (ori > 0) {
@@ -8037,8 +8190,11 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
             } else if (ori == 0) {
               // [a,b] is flat.
               if (n == 4) {
-                // The "flat" tet can be removed immedately by a 3-to-2 flip.
+                // The "flat" tet can be removed immediately by a 3-to-2 flip.
                 reducflag = 1;
+                // Check if [e,d] is a hull edge.
+                pf = apex(abtets[(i + 2) % n]);
+                hulledgeflag = (pf == dummypoint);
               }
             }
           }
@@ -8063,16 +8219,27 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
             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).
+              ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
+              hulledgeflag = 1; // [e,d] is a hull edge.
             }
           }
         }
       } // if (hullflag)
 
+      if (reducflag) {
+        if (nonconvex && hulledgeflag) {
+          // We will create a hull edge [e,d]. Make sure it does not exist.
+          if (getedge(pe, pd, &spintet)) {
+            // The 2-to-3 flip is not a topological valid flip. 
+            reducflag = 0;
+          }
+        }
+      }
+
       if (reducflag) {
         // [a,b,c] could be removed by a 2-to-3 flip.
         rejflag = 0;
-        if (fc != NULL) {
+        if (fc->checkflipeligibility) {
           // Check if the flip can be performed.
           rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
                                          abedgepivot, fc);
@@ -8081,7 +8248,7 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           // Do flip: [a,b,c] => [e,d].
           fliptets[0] = abtets[i];
           fsym(fliptets[0], fliptets[1]); // abtets[i-1].
-          flip23(fliptets, hullflag, 0, 0);
+          flip23(fliptets, hullflag, fc);
 
           // Shrink the array 'abtets', maintain the original order.
           //   Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
@@ -8099,21 +8266,19 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           //   [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]
+          edestoppoself(fliptets[0]); // [a,b,e,d]
           // Increase the counter of this new tet (it is in Star(ab)).
-          increaseelemcounter(fliptets[0]); //marktest(fliptets[0]);
+          increaseelemcounter(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.
+          //   (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
+          //  (ii) it remembers 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] = fliptets[1]; // [e,d,b,c] is remembered.
           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.
@@ -8134,27 +8299,28 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           // Star(ab) is reduced. Try to flip the edge [a,b].
           nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
 
-          if (nn > 2) {
+          if (nn == 2) {
+            // The edge has been flipped.
+            return nn;
+          } else { // 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
+              // 'ori == 0' means that the previous flip created a degenerated
               //   tet. It must be removed. 
-              // Remeber that 'abtets[i-1]' is [a,b,e,d]. We can use it to
+              // Remember 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]
+              edestoppoself(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);
+              flip32(fliptets, hullflag, fc);
               // Marktest the two restored tets in Star(ab).
               for (j = 0; j < 2; j++) {
-                increaseelemcounter(fliptets[j]); //marktest(fliptets[j]);
+                increaseelemcounter(fliptets[j]);
               }
               // Expand the array 'abtets', maintain the original order.
               for (j = n - 2; j>= i; j--) {
@@ -8170,30 +8336,17 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
                 // Pop two (flipped) tets from the stack.
                 cavetetlist->objects -= 2;
               }
-            } // if (upflip || (ori == 0))
+            } // if (unflip || (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).
+            //   further reduced. Return its current 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
 
@@ -8202,16 +8355,6 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
       // 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.
@@ -8221,25 +8364,14 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           }
           pc = apex(abtets[i]);
           if (pc == dummypoint) {
-            continue; // [a,b,dummypoint] is a hull edge.
+            continue; // [a,b] 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.
 
@@ -8265,21 +8397,15 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           // 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;
-                  }
+            if (issubseg(flipedge)) {
+              if (fc->collectencsegflag) {
+                face checkseg, *paryseg;
+                tsspivot1(flipedge, checkseg);
+                if (!sinfected(checkseg)) {
+                  // Queue this segment in list.
+                  sinfect(checkseg);                
+                  caveencseglist->newindex((void **) &paryseg);
+                  *paryseg = checkseg;
                 }
               }
               continue;
@@ -8294,7 +8420,7 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           spintet = flipedge;
           while (1) {
             n1++;
-            j += (elemcounter(spintet)); //if (marktested(spintet)) j++;
+            j += (elemcounter(spintet)); 
             fnextself(spintet);
             if (spintet.tet == flipedge.tet) break;
           }
@@ -8306,14 +8432,8 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           // 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++;
+            // The star size exceeds the given limit.
             continue; // Do not flip it.
           }
 
@@ -8330,15 +8450,6 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
             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);
@@ -8359,10 +8470,8 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
               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);
+            assert(elemcounter(spintet) == 0); // It's a new tet.
+            increaseelemcounter(spintet); // It is in Star(ab).
             // Put the new tet at [i-1]-th entry.
             abtets[(i - 1 + n) % n] = spintet;
             for (j = i; j < n - 1; j++) {
@@ -8389,7 +8498,10 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
             // Continue to flip the edge [a,b].
             nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
 
-            if (nn > 2) {
+            if (nn == 2) { 
+              // The edge has been flipped.
+              return nn;
+            } else { // if (nn > 2) {
               // The edge is not flipped.
               if (fc->unflip) {
                 // Recover the flipped edge ([c,b] or [a,c]).
@@ -8443,7 +8555,6 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
                   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).
@@ -8455,10 +8566,6 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
               } // 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).
@@ -8467,7 +8574,7 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
             // unflip is set. 
             // Continue the search for flips.
           } else {
-            // The seclected edge is not flipped.
+            // The selected edge is not flipped.
             if (fc->unflip) {
               // The memory should already be freed.
               assert(nn == n1);
@@ -8484,72 +8591,34 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
             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.
+    // Let the three apexes be c, d,and e. Hull tets may be involved. If so, 
+    //   we rearrange them such that the vertex e is 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) {
+
+    if (apex(abtets[0]) == dummypoint) {
+      pc = apex(abtets[1]);
+      pd = apex(abtets[2]);
+      pe = apex(abtets[0]);
       hullflag = 1;
-      tmppts[0] = pc;
-      tmppts[1] = pd;
-      tmppts[2] = pe;
+    } else if (apex(abtets[1]) == dummypoint) {
+      pc = apex(abtets[2]);
+      pd = apex(abtets[0]);
+      pe = apex(abtets[1]);
+      hullflag = 2;
     } else {
-      tmppts[0] = pc;
-      tmppts[1] = pd;
-      tmppts[2] = pe;
+      pc = apex(abtets[0]);
+      pd = apex(abtets[1]);
+      pe = apex(abtets[2]);
+      hullflag = (pe == dummypoint) ? 3 : 0;
     }
 
     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
@@ -8560,98 +8629,63 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
         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.
+      // [a,b] is a hull edge.
+      //   Note: This can happen when it is in the middle of a 4-to-4 flip.
+      //   Note: [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]);
+        //  The mesh is convex, only do flip if it is a coplanar hull edge.
+        ori = orient3d(pa, pb, pc, pd); 
         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;
-          }
+          reducflag = 1;
         }
-        // assert(j < 3);
-        eprevself(flipedge);
-        esymself(flipedge);
-        enextself(flipedge); // [p0,p1,a,b].
-        assert(apex(flipedge) == pa);
-        spintet = flipedge;
-        j = 0;
+      } else { // nonconvex
+        reducflag = 1;
+      }
+      if (reducflag == 1) {
+        // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
+        // Make sure that no inverted tet will be created.
+        point searchpt = NULL, chkpt;
+        REAL bigvol = 0.0, ori1, ori2;
+        // Search an interior vertex which is an apex of edge [c,d].
+        //   In principle, it can be arbitrary interior vertex.  To avoid
+        //   numerical issue, we choose the vertex which belongs to a tet
+        //   't' at edge [c,d] and 't' has the biggest volume.  
+        fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
+        eorgoppoself(fliptets[0]);  // [d,c,b,a]
+        spintet = fliptets[0];
         while (1) {
-          j++;
           fnextself(spintet);
-          if (spintet.tet == flipedge.tet) break;
+          chkpt = oppo(spintet);
+          if (chkpt == pb) break;
+          if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
+            ori = -orient3d(pd, pc, apex(spintet), chkpt);
+            assert(ori > 0);
+            if (ori > bigvol) {
+              bigvol = ori;
+              searchpt = chkpt;
+            }
+          }
         }
-        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 (searchpt != NULL) { 
+          // Now valid the configuration.
+          ori1 = orient3d(pd, pc, searchpt, pa);
+          ori2 = orient3d(pd, pc, searchpt, pb);
+          if (ori1 * ori2 >= 0.0) {
+            reducflag = 0; // Not valid. 
+          } else {
+            ori1 = orient3d(pa, pb, searchpt, pc);
+            ori2 = orient3d(pa, pb, searchpt, pd);
+            if (ori1 * ori2 >= 0.0) {
+              reducflag = 0; // Not valid.
+            }
           }
-          //if (fc != NULL) {
-          //  fc->convexhulledgecount++;
-          //}
+        } else {
+          // No valid searchpt is found.
+          reducflag = 0; // Do not flip it.
         }
-      }
+      } // if (reducflag == 1)
     } // if (hullflag == 1)
 
     if (reducflag) {
@@ -8662,10 +8696,12 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
         //   the surface mesh will be automatically performed within the 
         //   3-to-2 flip.
         nn = 0;
+        edgepivot = -1; // Re-use it.
         for (j = 0; j < 3; j++) {
-          tspivot(abtets[j], checksh);
-          if (checksh.sh != NULL) {
+          if (issubface(abtets[j])) {
             nn++; // Found a subface.
+          } else {
+            edgepivot = j;
           }
         }
         assert(nn < 3);
@@ -8674,34 +8710,39 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           //   the boundary recovery phase. The neighbor subface is not yet 
           //   recovered. This edge should not be flipped at this moment.
           rejflag = 1; 
+        } else if (nn == 2) {
+          // Found two subfaces. A 2-to-2 flip is possible. Validate it.
+          // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
+          eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
+          if (issubface(spintet)) {
+            rejflag = 1; // Conflict to a 2-to-2 flip.
+          } else {
+            esymself(spintet);
+            if (issubface(spintet)) {
+              rejflag = 1; // Conflict to a 2-to-2 flip.
+            }
+          }
         }
       }
-      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,
+      if (!rejflag && fc->checkflipeligibility) {
+        // Here we must exchange '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);
+        rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level, 
+                                       abedgepivot, fc);
       }
       if (!rejflag) {
         // Do flip: [a,b] => [c,d,e]
-        flip32(abtets, hullflag, 0, 0);
-        sucflipstarcount++;
+        flip32(abtets, hullflag, fc);
         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);
+            // It is the desired removing edge. Check if we have improved
+            //   the objective function.
+            if ((fc->tetprism_vol_sum >= 0.0) ||
+                (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
+              // No improvement! flip back: [c,d,e] => [a,b].
+              flip23(abtets, hullflag, fc);
               // Increase the element counter -- They are in cavity.
               for (j = 0; j < 3; j++) {
                 increaseelemcounter(abtets[j]); 
@@ -8731,15 +8772,7 @@ int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
           }
         } // 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)
 
@@ -8794,7 +8827,7 @@ int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
     // '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);
+      flip23(abtets, 1, fc);
       if (fc->collectnewtets) {
         // Pop up new (flipped) tets from the stack.
         if (abedgepivot == 0) {
@@ -8808,9 +8841,7 @@ int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
     } 
     // 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++) {
@@ -8836,7 +8867,7 @@ int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
         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);
+        flip32(fliptets, 1, fc);
         // Expand the array 'abtets', maintain the original order.
         // The new array length is (i+1).
         for (j = i - 1; j >= t; j--) {
@@ -8923,9 +8954,6 @@ int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
         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
 
@@ -8934,916 +8962,178 @@ int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// 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.                                                               //
+// insertpoint()    Insert a point into current tetrahedralization.          //
 //                                                                           //
-// 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.                       //
+// The Bowyer-Watson (B-W) algorithm is used to add a new point p into the   //
+// tetrahedralization T. It first finds a "cavity", denoted as C, in T,  C   //
+// consists of tetrahedra in T that "conflict" with p.  If T is a Delaunay   //
+// tetrahedralization, then all boundary faces (triangles) of C are visible  //
+// by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
+// tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
+// C and p.  If T is not a DT, then C may be not star-shaped.  It must be    //
+// modified so that it becomes star-shaped.                                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-long tetgenmesh::lawsonflip3d(point newpt, int flipflag, int peelsliverflag, 
-                              int chkencflag, int flipedgeflag)
+int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
+                            face *splitseg, insertvertexflags *ivf)
 {
-  badface *popface, *bface;
-  triface fliptets[5], baktets[2];
-  triface fliptet, neightet, *parytet;
-  face checksh, *parysh;
+  arraypool *swaplist;
+  triface *cavetet, spintet, neightet, neineitet, *parytet;
+  triface oldtet, newtet, newneitet;
+  face checksh, neighsh, *parysh;
   face checkseg, *paryseg;
-  point *ppt, pd, pe, pf;
-  long flipcount;
+  point *pts, pa, pb, pc, *parypt;
+  enum locateresult loc = OUTSIDE;
   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;
+  REAL attrib, volume;
+  bool enqflag;
+  int t1ver;
+  int i, j, k, s;
 
   if (b->verbose > 2) {
-    printf("      Lawson flip %ld faces.\n", flippool->items);
+    printf("      Insert point %d\n", pointmark(insertpt));
   }
 
-  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.
+  // Locate the point.
+  if (searchtet->tet != NULL) {
+    loc = (enum locateresult) ivf->iloc;
   }
 
-  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;
+  if (loc == OUTSIDE) {
+    if (searchtet->tet == NULL) {
+      if (!b->weighted) {
+        randomsample(insertpt, searchtet);
+      } else {
+        // Weighted DT. There may exist dangling vertex. 
+        *searchtet = recenttet;
+      }
+    }
+    // Locate the point.
+    loc = locate(insertpt, searchtet); 
+  }
 
-      unmarkface(fliptet);
+  ivf->iloc = (int) loc; // The return value.
 
-      // FOR DEBUG
-      if (flipflag == 1) {
-        assert(oppo(fliptet) == newpt);
+  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.
+        setpointtype(insertpt, NREGULARVERTEX);
+        nonregularcount++;
+        ivf->iloc = (int) NONREGULAR;
+        return 0;
       }
+    }
+  }
 
-      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)
+  // Create the initial cavity C(p) which contains all tetrahedra that
+  //   intersect p. It may include 1, 2, or n tetrahedra.
+  // If p lies on a segment or subface, also create the initial sub-cavity
+  //   sC(p) which contains all subfaces (and segment) which intersect p.
 
-        // 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 (loc == OUTSIDE) {
+    flip14count++;
+    // 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];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+  } else if (loc == INTETRAHEDRON) {
+    flip14count++;
+    // Add four adjacent boundary tets into list.
+    for (i = 0; i < 4; i++) {
+      decode(searchtet->tet[i], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
+  } else if (loc == ONFACE) {
+    flip26count++;
+    // 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];
+      cavebdrylist->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];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    infect(spintet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = spintet;
+    infect(*searchtet);
+    caveoldtetlist->newindex((void **) &parytet);
+    *parytet = *searchtet;
 
-      if (peelsliverflag) {
-        continue; // Only check hull tets.
+    if (ivf->splitbdflag) { 
+      if ((splitsh != NULL) && (splitsh->sh != NULL)) {
+        // Create the initial sub-cavity sC(p).
+        smarktest(*splitsh);
+        caveshlist->newindex((void **) &parysh);
+        *parysh = *splitsh;
       }
+    } // if (splitbdflag)
+  } else if (loc == ONEDGE) {
+    flipn2ncount++;
+    // Add all adjacent boundary tets into list.
+    spintet = *searchtet;
+    while (1) {
+      eorgoppo(spintet, neightet);
+      decode(neightet.tet[neightet.ver & 3], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+      edestoppo(spintet, neightet);
+      decode(neightet.tet[neightet.ver & 3], neightet);
+      neightet.ver = epivot[neightet.ver];
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = neightet;
+      infect(spintet);
+      caveoldtetlist->newindex((void **) &parytet);
+      *parytet = spintet;
+      fnextself(spintet);
+      if (spintet.tet == searchtet->tet) break;
+    } // while (1)
 
-      // 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 (ivf->splitbdflag) {
+      // Create the initial sub-cavity sC(p).
+      if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+        smarktest(*splitseg);
+        splitseg->shver = 0;
+        spivot(*splitseg, *splitsh);
       }
-      
-      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);
+      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);
@@ -9862,9 +9152,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       }
     } // 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);
@@ -9876,140 +9163,49 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         decode(cavetet->tet[j], neightet);
         if (!infected(neightet)) {
           // It's a boundary face.
-          neightet.ver = epivot[neightet.ver & 3];
-          cavetetlist->newindex((void **) &parytet);
+          neightet.ver = epivot[neightet.ver];
+          cavebdrylist->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.
-  }
+    return 0;
+  } 
 
 
   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
+      bgm->decode(point2bgmtet(org(*searchtet)), neightet);
+      int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
       if (bgmloc != (int) OUTSIDE) {
-        insertpt[pointmtrindex] =  // posflag = 1
-          bgm->getpointmeshsize(insertpt, &neightet, bgmloc, 1);
+        insertpt[pointmtrindex] =  
+          bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
         setpoint2bgmtet(insertpt, bgm->encode(neightet));
       }
     } else {
-      insertpt[pointmtrindex] = // posflag = 1
-        getpointmeshsize(insertpt, searchtet, (int) loc, 1);
+      insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
     }
   } // 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;
-
+  if (ivf->bowywat) {
+    // Update the cavity C(p) using the Bowyer-Watson algorithm.
+    swaplist = cavetetlist;
+    cavetetlist = cavebdrylist;
+    cavebdrylist = swaplist;
     for (i = 0; i < cavetetlist->objects; i++) {
+      // 'cavetet' is an adjacent tet at outside of the cavity.
       cavetet = (triface *) fastlookup(cavetetlist, i);
-      // Other expansions may make this face inside C(p).
+      // The tet may be tested and included in the (enlarged) cavity.
       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) {
+        // Check for two possible cases for this tet: 
+        //   (1) It is a cavity tet, or
+        //   (2) it is a cavity boundary face.
+        enqflag = false;
+        if (!marktested(*cavetet)) {
           // Do Delaunay (in-sphere) test.
           pts = (point *) cavetet->tet;
           if (pts[7] != dummypoint) {
@@ -10026,20 +9222,17 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
             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);
+                decode(cavetet->tet[3], neineitet);
                 if (!infected(neineitet)) {
                   if (!marktested(neineitet)) {
                     // Do Delaunay test on this tet.
@@ -10053,12 +9246,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
                       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.
@@ -10067,15 +9255,11 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
               } // 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);
+              decode(cavetet->tet[3], neineitet);
               if (!infected(neineitet)) {
                 if (!marktested(neineitet)) {
                   // Do Delaunay test on this tet.
@@ -10089,12 +9273,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
                     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.
@@ -10102,200 +9281,131 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
               } // 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
+          marktest(*cavetet); // Only test it once.
+        } // if (!marktested(*cavetet))
 
-  if (b->verbose > 3) {
-    printf("        Initial cavity size: %ld tets, %ld faces.\n", 
-           caveoldtetlist->objects, cavebdrylist->objects);
-  }
+        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);
+            cavetetlist->newindex((void **) &parytet);
+            *parytet = neightet;
+          }
+          infect(*cavetet);
+          caveoldtetlist->newindex((void **) &parytet);
+          *parytet = *cavetet;
+        } else {
+          // Found a boundary face of the cavity. 
+          cavetet->ver = epivot[cavetet->ver];
+          cavebdrylist->newindex((void **) &parytet);
+          *parytet = *cavetet;
+        }
+      } // if (!infected(*cavetet))
+    } // i
 
+    cavetetlist->restart(); // Clear the working list.
+  } // if (ivf->bowywat)
 
   if (checksubsegflag) {
     // Collect all segments of C(p).
+    shellface *ssptr;
     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;
+      if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
+        for (j = 0; j < 6; j++) {
+          if (ssptr[j]) {
+            sdecode(ssptr[j], checkseg);
+            if (!sinfected(checkseg)) {
+              sinfect(checkseg);
+              cavetetseglist->newindex((void **) &paryseg);
+              *paryseg = checkseg;
+            }
           }
-        }
+        } // j
       }
-    }
+    } // i
     // Uninfect collected segments.
     for (i = 0; i < cavetetseglist->objects; i++) {
-      checkseg = * (face *) fastlookup(cavetetseglist, i);
-      suninfect(checkseg);
+      paryseg = (face *) fastlookup(cavetetseglist, i);
+      suninfect(*paryseg);
+    }
+
+    if (ivf->rejflag & 1) {
+      // Reject this point if it encroaches upon any segment.
+      face *paryseg1;
+      for (i = 0; i < cavetetseglist->objects; i++) {
+        paryseg1 = (face *) fastlookup(cavetetseglist, i);
+        if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4], 
+                              insertpt)) {
+          encseglist->newindex((void **) &paryseg);
+          *paryseg = *paryseg1;
+        }
+      } // i
+      if (encseglist->objects > 0) {
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) ENCSEGMENT;
+        return 0;
+      }
     }
   } // if (checksubsegflag)
 
   if (checksubfaceflag) {
     // Collect all subfaces of C(p).
+    shellface *sptr;
     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;
+      if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
+        for (j = 0; j < 4; j++) {
+          if (sptr[j]) {
+            sdecode(sptr[j], checksh);
+            if (!sinfected(checksh)) {
+              sinfect(checksh);
+              cavetetshlist->newindex((void **) &parysh);
+              *parysh = checksh;
+            }
           }
-        }
+        } // j
       }
-    }
+    } // i
     // Uninfect collected subfaces.
     for (i = 0; i < cavetetshlist->objects; i++) {
-      checksh = * (face *) fastlookup(cavetetshlist, i);
-      suninfect(checksh);
+      parysh = (face *) fastlookup(cavetetshlist, i);
+      suninfect(*parysh);
     }
-  } // 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);
+    if (ivf->rejflag & 2) {
+      REAL rd, cent[3];
+      badface *bface;
+      // Reject this point if it encroaches upon any subface.
+      for (i = 0; i < cavetetshlist->objects; i++) {
+        parysh = (face *) fastlookup(cavetetshlist, i);
+        if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4], 
+                              (point) parysh->sh[5], insertpt, cent, &rd)) {
+          encshlist->newindex((void **) &bface);
+          bface->ss = *parysh;
+          bface->forg = (point) parysh->sh[3]; // Not a dad one.
+          for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
+          bface->key = rd;
         }
-        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();
+      if (encshlist->objects > 0) {
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) ENCSUBFACE;
+        return 0;
       }
-      // Restore the hullsize.
-      hullsize = bakhullsize;
-      return (int) ENCSUBFACE;
     }
-  } // if (reject & 2)
+  } // if (checksubfaceflag)
+
+  if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
+    // The vertex lies outside of the domain. And it does not encroach
+    //   upon any boundary segment or subface. Do not insert it.
+    insertpoint_abort(splitseg, ivf);
+    return 0;
+  }
 
-  if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
-    // Update the sC(p). 
+  if (ivf->splitbdflag) { 
+    // The new point locates in surface mesh. 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.
@@ -10304,19 +9414,25 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       assert(smarktested(*parysh));
       checksh = *parysh;
       for (j = 0; j < 3; j++) {
-        sspivot(checksh, checkseg);
-        if (checkseg.sh == NULL) {
+        if (!isshsubseg(checksh)) {
           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;
+                // This subface is inside C(p). 
+                // Check if its diametrical circumsphere encloses 'p'.
+                //   The purpose of this check is to avoid forming invalid
+                //   subcavity in surface mesh.
+                sign = incircle3d(sorg(neighsh), sdest(neighsh),
+                                  sapex(neighsh), insertpt);
+                if (sign < 0) {
+                  smarktest(neighsh);
+                  caveshlist->newindex((void **) &parysh);
+                  *parysh = neighsh;
+                }
               }
             }
           }
@@ -10324,48 +9440,34 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         senextself(checksh);
       } // j
     } // i
-    if (b->verbose > 3) {
-      printf("        Initial subcavity size: %ld subfacess.\n", 
-             caveshlist->objects);
-    }
-  }
+  } // if (ivf->splitbdflag)
 
-  cutcount = 0l;
+  if (ivf->validflag) {
+    // Validate C(p) and update it if it is not star-shaped.
+    int cutcount = 0;
 
-  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'.
+      //   being splitting. Find them and make them as boundary of C(p). 
+      // Comment: We have already 'smarktested' the subfaces in sC(p). They
+      //   are completely inside C(p). 
       for (i = 0; i < cavetetshlist->objects; i++) {
         parysh = (face *) fastlookup(cavetetshlist, i);
         stpivot(*parysh, neightet);
         if (infected(neightet)) {
           fsymself(neightet);
           if (infected(neightet)) {
+            // Found a subface inside C(p).
             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);
+              //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);
+                ori = orient3d(org(neightet), dest(neightet), apex(neightet),
+                               insertpt);
                 if (ori < 0) {
                   // A visible face, get its neighbor face.
                   fsymself(neightet);
@@ -10377,27 +9479,20 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
               }
               // 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];
+                neightet.ver = epivot[neightet.ver];
                 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];
+                  neineitet.ver = epivot[neineitet.ver];
                   cavebdrylist->newindex((void **) &parytet);
                   *parytet = neineitet;
                   enextself(neightet);
                 }
-                // Update hullsize.
-                if (oppo(neightet) == dummypoint) hullsize++;
               } // if (ori >= 0) 
             }
           }
@@ -10419,10 +9514,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
             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);
@@ -10447,7 +9538,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
                     }
                   }
                 }
-              } else {
               }
               fnextself(spintet);
               if (spintet.tet == neightet.tet) break;
@@ -10465,42 +9555,34 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
             uninfect(neightet);
             unmarktest(neightet);
             cutcount++;
-            neightet.ver = epivot[neightet.ver & 3];
+            neightet.ver = epivot[neightet.ver];
             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];
+              neineitet.ver = epivot[neineitet.ver];
               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)
+    } // if (ivf->respectbdflag)
 
     // 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));
+      // 'cavetet' is an exterior tet adjacent to the cavity.
       // 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++;
+            ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
+                           insertpt); 
             enqflag = (ori > 0);
             // Comment: if ori == 0 (coplanar case), we also cut the tet.
           } else {
@@ -10517,24 +9599,17 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
           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];
+            neineitet.ver = epivot[neineitet.ver];
             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);
         }
@@ -10546,14 +9621,11 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
 
     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.
@@ -10581,12 +9653,13 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
 
       // The cavity should contain at least one tet.
       if (caveoldtetlist->objects == 0l) {
-        printf("Invalid cavity of Steiner point %d.\n", pointmark(insertpt));
-        assert(0);
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) BADELEMENT;
+        return 0;
       }
 
-      if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
-        cutshcount = 0;
+      if (ivf->splitbdflag) { 
+        int cutshcount = 0;
         // Update the sub-cavity sC(p).
         for (i = 0; i < caveshlist->objects; i++) {
           parysh = (face *) fastlookup(caveshlist, i);
@@ -10600,11 +9673,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
               }
             }
             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;
@@ -10621,16 +9689,16 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
           i = 0; // Count the number of invalid subfaces/segments.
           // Valid the updated sub-cavity sC(p).
           if (loc == ONFACE) {
-            if (splitsh != NULL) {
+            if ((splitsh != NULL) && (splitsh->sh != NULL)) {
               // The to-be split subface should be in sC(p).
               if (!smarktested(*splitsh)) i++;
             }
           } else if (loc == ONEDGE) {
-            if (splitseg != NULL) {
+            if ((splitseg != NULL) && (splitseg->sh != NULL)) {
               // The to-be split segment should be in sC(p).
               if (!smarktested(*splitseg)) i++;
             }
-            if (splitsh != NULL) {
+            if ((splitsh != NULL) && (splitsh->sh != NULL)) {
               // All subfaces at this edge should be in sC(p).
               pa = sorg(*splitsh);
               neighsh = *splitsh;
@@ -10652,127 +9720,140 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
 
           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;
+            insertpoint_abort(splitseg, ivf);
+            ivf->iloc = (int) BADELEMENT;
+            return 0;
           }
         } // if (cutshcount > 0)
-      } // if (bowywat > 2)
-
+      } // if (ivf->splitbdflag)
     } // 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->validflag)
 
   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));
+    if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
+        ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
+      insertpoint_abort(splitseg, ivf);
+      ivf->iloc = (int) BADELEMENT;
+      return 0;
+    }
+  } // if (ivf->refineflag)
+
+  if (b->plc && (loc != INSTAR)) {
+    // Reject the new point if it lies too close to an existing point (b->plc),
+    // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
+    // Collect the list of vertices of the initial cavity.
+    if (loc == OUTSIDE) {
+      pts = (point *) &(searchtet->tet[4]);
+      for (i = 0; i < 3; i++) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[i];
       }
-      // Restore the original status.
-      for (i = 0; i < caveoldtetlist->objects; i++) {
-        cavetet = (triface *) fastlookup(caveoldtetlist, i);
-        uninfect(*cavetet);
-        unmarktest(*cavetet);
+    } else if (loc == INTETRAHEDRON) {
+      pts = (point *) &(searchtet->tet[4]);
+      for (i = 0; i < 4; i++) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[i];
+      } 
+    } else if (loc == ONFACE) {
+      pts = (point *) &(searchtet->tet[4]);
+      for (i = 0; i < 3; i++) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[i];
       }
-      for (i = 0; i < cavebdrylist->objects; i++) {
-        cavetet = (triface *) fastlookup(cavebdrylist, i);
-        unmarktest(*cavetet); // Unmark it.
+      if (pts[3] != dummypoint) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = pts[3];
       }
-      // 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);
+      fsym(*searchtet, spintet);
+      if (oppo(spintet) != dummypoint) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = oppo(spintet);
+      }
+    } else if (loc == ONEDGE) {
+      spintet = *searchtet;
+      cavetetvertlist->newindex((void **) &parypt);
+      *parypt = org(spintet);
+      cavetetvertlist->newindex((void **) &parypt);
+      *parypt = dest(spintet);
+      while (1) {
+        if (apex(spintet) != dummypoint) {
+          cavetetvertlist->newindex((void **) &parypt);
+          *parypt = apex(spintet);
         }
-        for (i = 0; i < caveshlist->objects; i++) {
-          parysh = (face *) fastlookup(caveshlist, i);
-          assert(smarktested(*parysh));
-          sunmarktest(*parysh);
+        fnextself(spintet);
+        if (spintet.tet == searchtet->tet) break;
+      }
+    }
+
+    int rejptflag = (ivf->rejflag & 4);
+    REAL rd;
+    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; 
+        loc = NEARVERTEX;
+        break;
+      }
+      if (rejptflag) {
+        // Is the point encroaches upon an existing point?
+        if (rd < (0.5 * (*parypt)[pointmtrindex])) {
+          pts = parypt;
+          loc = ENCVERTEX; 
+          break;
         }
-        caveshlist->restart();
-        cavesegshlist->restart();
       }
+    }
+    cavetetvertlist->restart(); // Clear the work list.
 
-      // Restore the hullsize.
-      hullsize = bakhullsize;
-      loc = BADELEMENT;
-      return (int) loc;
-    } // if (rejptflag)
-  } // if (ivf->refineflag)
-
-  rejptflag = (ivf->rejflag & 4);
-  encptflag = 0;
+    if (pts != NULL) {
+      // The point is either too close to an existing vertex (NEARVERTEX)
+      //   or encroaches upon (inside the protecting ball) of that vertex.
+      if (loc == NEARVERTEX) {
+        if (b->nomergevertex) { // -M0/1 option.
+          // In this case, we still insert this vertex. Although it is very
+          //   close to an existing vertex. Give a warning, anyway.
+          if (!b->quiet) {
+            printf("Warning:  Two points, %d and %d, are very close.\n",
+                   pointmark(insertpt), pointmark(*pts));
+            printf("  Creating a very short edge (len = %g) (< %g).\n",
+                   rd, b->minedgelength);
+            printf("  You may try a smaller tolerance (-T) (current is %g)\n", 
+                   b->epsilon);
+            printf("  to avoid this warning.\n");
+          }
+        } else {
+          insertpt[3] = rd; // Only for reporting.
+          setpoint2ppt(insertpt, *pts);
+          insertpoint_abort(splitseg, ivf);
+          ivf->iloc = (int) loc;
+          return 0;
+        }
+      } else { // loc == ENCVERTEX
+        // The point lies inside the protection ball.
+        setpoint2ppt(insertpt, *pts);
+        insertpoint_abort(splitseg, ivf);
+        ivf->iloc = (int) loc;
+        return 0;
+      }
+    }
+  } // if (b->plc && (loc != INSTAR))
 
-  if (b->weighted || b->plc || rejptflag) {
+  if (b->weighted || ivf->cdtflag || ivf->smlenflag
+      ) {
+    // There may be other vertices inside C(p). We need to find them.
     // Collect all vertices of C(p).
     for (i = 0; i < caveoldtetlist->objects; i++) {
       cavetet = (triface *) fastlookup(caveoldtetlist, i);
-      assert(infected(*cavetet));
+      //assert(infected(*cavetet));
       pts = (point *) &(cavetet->tet[4]);
       for (j = 0; j < 4; j++) {
         if (pts[j] != dummypoint) {
@@ -10784,118 +9865,48 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         }
       } // 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++) {
+    if (ivf->smlenflag) {
+      REAL len;
+      // Get the length of the shortest edge connecting to 'newpt'.
+      parypt = (point *) fastlookup(cavetetvertlist, 0);
+      ivf->smlen = distance(*parypt, insertpt);
+      ivf->parentpt = *parypt;
+      for (i = 1; 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;
-          }
+        len = distance(*parypt, insertpt);
+        if (len < ivf->smlen) {
+          ivf->smlen = len;
+          ivf->parentpt = *parypt;
         }
-      } // 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;
+  if (ivf->cdtflag) {
+    // Unmark tets.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      cavetet = (triface *) fastlookup(caveoldtetlist, i);
+      unmarktest(*cavetet);
+    }
+    for (i = 0; i < cavebdrylist->objects; i++) {
+      cavetet = (triface *) fastlookup(cavebdrylist, i);
+      unmarktest(*cavetet);
+    }
+    // Clean up arrays which are not needed.
+    cavetetlist->restart();
+    if (checksubsegflag) {
+      cavetetseglist->restart();
+    }
+    if (checksubfaceflag) {
+      cavetetshlist->restart();
+    }
+    return 1;
   }
 
   // Before re-mesh C(p). Process the segments and subfaces which are on the
@@ -10917,7 +9928,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         while (1) {
           j++;
           if (!infected(spintet)) {
-            neineitet =  spintet; // An outer tet. Remember it.
+            neineitet = spintet; // An outer tet. Remember it.
           } else {
             k++; // An in tet.
           }
@@ -10938,12 +9949,8 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
           sstbond1(*paryseg, neineitet);
         } else { // k == j
           // The segment is inside C(p).
-          if (!ivf->splitbdflag) {//if (bowywat < 3) { // if (bowywat == 2) {
+          if (!ivf->splitbdflag) {
             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;
@@ -10958,10 +9965,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         sinfect(*paryseg);
       }
     } // i
-    if (b->verbose > 3) {
-      printf("        %ld (%ld) cavity (interior) segments.\n", 
-             cavetetseglist->objects, caveencseglist->objects);
-    }
   } // if (checksubsegflag)
 
   if (checksubfaceflag) {
@@ -10974,7 +9977,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         for (j = 0; j < 2; j++) {
           stpivot(*parysh, neightet);
           if (!infected(neightet)) {
-            checksh = *parysh; // Remeber this side.
+            checksh = *parysh; // Remember this side.
           } else {
             k++;
           }
@@ -10991,13 +9994,8 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
           // This side is the outer boundary of C(p).
           *parysh = checksh;
         } else { // k == 2
-          if (!ivf->splitbdflag) { //if (bowywat < 3) { // if (bowywat == 2) {
+          if (!ivf->splitbdflag) {
             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;
@@ -11012,40 +10010,26 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         sinfect(*parysh);
       }
     } // i
-    if (b->verbose > 3) {
-      printf("        %ld (%ld) cavity (interior) subfaces.\n", 
-             cavetetshlist->objects, caveencshlist->objects);
-    }
-  } // if (checksubfaceflag) {
+  } // 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).
+      // Create a new tet in the cavity.
       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++;
+      // Create a new hull tet.
+      hullsize++; 
       maketetrahedron(&newtet);
       setorg(newtet, org(neightet));
       setdest(newtet, dest(neightet));
@@ -11054,6 +10038,15 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       // Adjust back to the cavity bounday face.
       esymself(newtet);
     }
+    // The new tet inherits attribtes from the old tet.
+    for (j = 0; j < numelemattrib; j++) {
+      attrib = elemattribute(oldtet.tet, j);
+      setelemattribute(newtet.tet, j, attrib);
+    }
+    if (b->varvolume) {
+      volume = volumebound(oldtet.tet);
+      setvolumebound(newtet.tet, volume);
+    }
     // Connect newtet <==> neightet, this also disconnect the old bond.
     bond(newtet, neightet);
     // oldtet still connects to neightet.
@@ -11062,12 +10055,11 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
 
   // Set a handle for speeding point location.
   recenttet = newtet;
-  setpoint2tet(insertpt, encode(newtet));
+  //setpoint2tet(insertpt, encode(newtet));
+  setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
 
-  if (ivf->lawson > 1) { // if (lawson == 2 || lawson == 3) {
-    // Re-use this list to save new interior cavity faces.
-    cavetetlist->restart();
-  }
+  // Re-use this list to save new interior cavity faces.
+  cavetetlist->restart();
 
   // Connect adjacent new tetrahedra together.
   for (i = 0; i < cavebdrylist->objects; i++) {
@@ -11089,16 +10081,15 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         }
         fsym(spintet, newneitet);
         esymself(newneitet);
-        assert(newneitet.tet[newneitet.ver & 3] == NULL); // FOR DEBUG
+        assert(newneitet.tet[newneitet.ver & 3] == NULL);
         bond(neightet, newneitet);
-        if (ivf->lawson > 1) {
-          // We are updateing a CDT. Queue the internal face.
-          //   See also fig/dump-cavity-case13, -case21.
+        if (ivf->lawson > 1) { 
           cavetetlist->newindex((void **) &parytet);
           *parytet = neightet;
         }
       }
-      setpoint2tet(org(newtet), encode(newtet));
+      //setpoint2tet(org(newtet), encode(newtet));
+      setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
       enextself(newtet);
       enextself(oldtet);
     }
@@ -11136,13 +10127,14 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
     }
   }
 
-  if (splitsh != NULL) {
+  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
+      ((splitseg != NULL) && (splitseg->sh != NULL))) {
     // Split a subface or a segment.
-    sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat);
+    sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
   }
 
   if (checksubfaceflag) {
-    if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
+    if (ivf->splitbdflag) {
       // Recover new subfaces in C(p).
       for (i = 0; i < caveshbdlist->objects; i++) {
         // Get an old subface at edge [a, b].
@@ -11187,8 +10179,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       // There should be no missing interior subfaces in C(p).
       assert(caveencshlist->objects == 0l);
     } else { 
-      // bowywat = 1 or bowywat = 2.
-      // The Boundary reocvery phase.
+      // The Boundary recovery phase.
       // Put all new subfaces into stack for recovery.
       for (i = 0; i < caveshbdlist->objects; i++) {
         // Get an old subface at edge [a, b].
@@ -11196,12 +10187,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         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;
         }
@@ -11213,11 +10198,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         // 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.
@@ -11229,7 +10209,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
   } // if (checksubfaceflag)
 
   if (checksubsegflag) {
-    if (ivf->splitbdflag) { //if (bowywat > 2) { // if (bowywat == 3) {
+    if (ivf->splitbdflag) {
       if (splitseg != NULL) {
         // Recover the two new subsegments in C(p).
         for (i = 0; i < cavesegshlist->objects; i++) {
@@ -11244,11 +10224,9 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
             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);
+            point2tetorg(sorg(checkseg), neightet);
+            finddirection(&neightet, sdest(checkseg));
+            assert(dest(neightet) == sdest(checkseg));
           }
           assert(!infected(neightet));
           sstbond1(checkseg, neightet);
@@ -11263,17 +10241,12 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       // 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);
@@ -11287,10 +10260,6 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
         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.
@@ -11304,12 +10273,10 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
     }
   } // if (checksubsegflag)
 
-  if (b->plc || b->weighted) {
+  if (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++) {
@@ -11318,28 +10285,15 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       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));
+          if (b->verbose > 1) {
+            printf("    Point #%d is non-regular after the insertion of #%d.\n",
+                   pointmark(*pts), pointmark(insertpt));
           }
-          subvertstack->newindex((void **) &parypt);
-          *parypt = *pts;
+          setpointtype(*pts, NREGULARVERTEX);
+          nonregularcount++;
         }
       }
     }
-    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) {
@@ -11348,23 +10302,14 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       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.
-        }
+        enqueuesubface(badsubsegs, paryseg);
       }
     }
     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.
+        enqueuesubface(badsubsegs, paryseg);
       }
     }
   } // if (chkencflag & 1)
@@ -11375,15 +10320,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       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);
-        }
+        enqueuesubface(badsubfacs, parysh);
       }
     }
     // Queue all new subfaces inside C(p).
@@ -11393,11 +10330,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       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.
+        enqueuesubface(badsubfacs, &checksh);
       }
     }
   } // if (chkencflag & 2)
@@ -11406,23 +10339,23 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
     // 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);
+      enqueuetetrahedron(cavetet);
     }
   }
 
-  // C(p) is re-meshed successfully. 
+  // C(p) is re-meshed successfully.
 
-  // Deleted the old tets in C(p).
+  // Delete the old tets in C(p).
   for (i = 0; i < caveoldtetlist->objects; i++) {
     searchtet = (triface *) fastlookup(caveoldtetlist, i);
+    if (ishulltet(*searchtet)) {
+      hullsize--;
+    }
     tetrahedrondealloc(searchtet->tet);
   }
 
-  if (splitsh != NULL) {
+  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
+      ((splitseg != NULL) && (splitseg->sh != NULL))) {
     // Delete the old subfaces in sC(p).
     for (i = 0; i < caveshlist->objects; i++) {
       parysh = (face *) fastlookup(caveshlist, i);
@@ -11444,7 +10377,7 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
       }
       shellfacedealloc(subfaces, parysh->sh);
     }
-    if (splitseg != NULL) {
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
       // Delete the old segment in sC(p).
       shellfacedealloc(subsegs, splitseg->sh);
     }
@@ -11453,29 +10386,16 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
   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.
 
@@ -11493,17 +10413,60 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
     caveencshlist->restart();
   }
   
-  if (b->plc || b->weighted) {
+  if (b->weighted || ivf->validflag) {
     cavetetvertlist->restart();
   }
   
-  if (splitsh != NULL) {
+  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
+      ((splitseg != NULL) && (splitseg->sh != NULL))) {
     caveshlist->restart();
     caveshbdlist->restart();
     cavesegshlist->restart();
   }
 
-  return (int) loc;
+  return 1; // Point is inserted.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertpoint_abort()    Abort the insertion of a new vertex.               //
+//                                                                           //
+// The cavity will be restored.  All working lists are cleared.              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::insertpoint_abort(face *splitseg, insertvertexflags *ivf)
+{
+  triface *cavetet;
+  face *parysh;
+  int 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); 
+  }
+  cavetetlist->restart();
+  cavebdrylist->restart();
+  caveoldtetlist->restart();
+  cavetetseglist->restart();
+  cavetetshlist->restart();
+  if (ivf->splitbdflag) { 
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      sunmarktest(*splitseg);
+    }
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      assert(smarktested(*parysh));
+      sunmarktest(*parysh);
+    }
+    caveshlist->restart();
+    cavesegshlist->restart();
+  }
 }
 
 ////                                                                       ////
@@ -11518,10 +10481,10 @@ int tetgenmesh::insertvertex(point insertpt, triface *searchtet, face *splitsh,
 //                                                                           //
 // 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.   //
+// Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
+// All points are indexed (the first point index is 'in->firstnumber'). Each //
+// point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
+// ...) and the diameter (longest) of the point set are calculated.          //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -11547,32 +10510,34 @@ void tetgenmesh::transfernodes()
     // Read the point coordinates.
     x = pointloop[0] = in->pointlist[coordindex++];
     y = pointloop[1] = in->pointlist[coordindex++];
-    z = pointloop[2] = in->pointlist[coordindex++];    
+    z = pointloop[2] = in->pointlist[coordindex++];
+    // Read the point attributes. (Including point weights.)
+    for (j = 0; j < in->numberofpointattributes; j++) {
+      pointloop[3 + j] = in->pointattributelist[attribindex++];
+    }
+    // Read the point metric tensor.
+    for (j = 0; j < in->numberofpointmtrs; j++) {
+      pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
+    }
     if (b->weighted) { // -w option
       if (in->numberofpointattributes > 0) {
-        // The first point attribute is weight.
-        w = in->pointattributelist[in->numberofpointattributes * i];
+        // The first point attribute is its weight.
+        //w = in->pointattributelist[in->numberofpointattributes * i];
+        w = pointloop[3];
       } else {
-        // No given weight available.
-        w = 0;
+        // No given weight available. Default choose the maximum
+        //   absolute value among its coordinates.        
+        w = fabs(x);
+        if (w < fabs(y)) w = fabs(y);
+        if (w < fabs(z)) w = fabs(z);
       }
       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.
+    // Determine the smallest and largest x, y and z coordinates.
     if (i == 0) {
       xmin = xmax = x;
       ymin = ymax = y;
@@ -11609,7 +10574,7 @@ void tetgenmesh::transfernodes()
   longest = sqrt(x * x + y * y + z * z);
   if (longest == 0.0) {
     printf("Error:  The point set is trivial.\n");
-    terminatetetgen(3);
+    terminatetetgen(this, 3);
   }
 
   // Two identical points are distinguished by 'lengthlimit'.
@@ -11620,293 +10585,256 @@ void tetgenmesh::transfernodes()
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// btree_sort()    Sort vertices using a binary space partition (bsp) tree.  //
+// hilbert_init()    Initialize the Gray code permutation table.             //
+//                                                                           //
+// The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray  //
+// code sequences traveled by the 1st order Hilbert curve in 3 dimensions.   //
+// The first column is the Gray code of the entry point of the curve, and    //
+// the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
+// the exit point of curve lies.                                             //
+//                                                                           //
+// The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
+// indices from 0 to 7, modulo by '3'. The code for generating this table is //
+// from: http://graphics.stanford.edu/~seander/bithacks.html.                //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::btree_sort(point* vertexarray, int arraysize, int axis, 
-                            REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, 
-                            REAL bzmin, REAL bzmax, int depth)
+void tetgenmesh::hilbert_init(int n)
 {
-  point *leftarray, *rightarray;
-  point **pptary, swapvert;
-  REAL split;
-  bool lflag, rflag;
-  int i, j, k; // *iptr,
+  int gc[8], N, mask, travel_bit;
+  int e, d, f, k, g;
+  int v, c;
+  int i;
 
-  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"));
+  N = (n == 2) ? 4 : 8;
+  mask = (n == 2) ? 3 : 7;
+
+  // Generate the Gray code sequence.
+  for (i = 0; i < N; i++) {
+    gc[i] = i ^ (i >> 1);
+  }
+
+  for (e = 0; e < N; e++) {
+    for (d = 0; d < n; d++) {
+      // Calculate the end point (f).
+      f = e ^ (1 << d);  // Toggle the d-th bit of 'e'.
+      // travel_bit = 2**p, the bit we want to travel. 
+      travel_bit = e ^ f;
+      for (i = 0; i < N; i++) {
+        // // Rotate gc[i] left by (p + 1) % n bits.
+        k = gc[i] * (travel_bit * 2);
+        g = ((k | (k / N)) & mask);
+        // Calculate the permuted Gray code by xor with the start point (e).
+        transgc[e][d][i] = (g ^ e);
+      }
+      assert(transgc[e][d][0] == e);
+      assert(transgc[e][d][N - 1] == f);
+    } // d
+  } // e
+
+  // Count the consecutive '1' bits (trailing) on the right.
+  tsb1mod3[0] = 0;
+  for (i = 1; i < N; i++) {
+    v = ~i; // Count the 0s.
+    v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
+    for (c = 0; v; c++) {
+      v >>= 1;
+    }
+    tsb1mod3[i] = c % n;
   }
+}
 
-  if (depth > max_btree_depth) {
-    max_btree_depth = depth;
-  }
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// hilbert_sort3()    Sort points using the 3d Hilbert curve.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
+                              REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, 
+                              REAL bzmin, REAL bzmax)
+{
+  point swapvert;
+  int axis, d;
+  REAL split;
+  int i, j;
 
+
+  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which 
+  //   correspoding to x-, or y- or z-axis.
+  axis = (gc0 ^ gc1) >> 1; 
+
+  // Calulate the split position along the axis.
   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.
+  } else { // == 2
     split = 0.5 * (bzmin + bzmax);
   }
 
+  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
+  //   of the axis is to the positive of the axis, otherwise, it is -1.
+  d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
 
+
+  // Partition the vertices into left- and right-arrays such that left points
+  //   have Hilbert indices lower than the right points.
   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);
+  // Partition the vertices into left- and right-arrays.
+  if (d > 0) {
+    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);
+  } else {
+    do {
+      for (; i < arraysize; i++) {      
+        if (vertexarray[i][axis] <= split) break;
       }
-    } 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);
+      for (; j >= 0; j--) {
+        if (vertexarray[j][axis] > split) break;
       }
-    } 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;
+      // 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);
   }
-}
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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 long) ptary[0];
-  // Insert the point into the node.
-  ptary[arylen + 1] = insertpt;
-  // Increase the array length by 1.
-  ptary[0] = (point) (arylen + 1);
+  return i;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// btree_search()    Search a near point for an inserting point.             //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-void tetgenmesh::btree_search(point insertpt, triface* searchtet)
+void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d, 
+                               REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, 
+                               REAL bzmin, REAL bzmax, int depth)
 {
-  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 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++;
+  REAL x1, x2, y1, y2, z1, z2;
+  int p[9], w, e_w, d_w, k, ei, di;
+  int n = 3, mask = 7;
+
+  p[0] = 0;
+  p[8] = arraysize;
+
+  // Sort the points according to the 1st order Hilbert curve in 3d.
+  p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax);
+  p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax);
+  p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax);
+  p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2], 
+                       transgc[e][d][2], transgc[e][d][3], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
+  p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4], 
+                       transgc[e][d][5], transgc[e][d][6], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
+  p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4], 
+                       transgc[e][d][4], transgc[e][d][5], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
+  p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6], 
+                       transgc[e][d][6], transgc[e][d][7], 
+                       bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
+
+  if (b->hilbert_order > 0) {
+    // A maximum order is prescribed. 
+    if ((depth + 1) == b->hilbert_order) {
+      // The maximum prescribed order is reached.
+      return;
+    }
+  }
+
+  // Recursively sort the points in sub-boxes.
+  for (w = 0; w < 8; w++) {
+    // w is the local Hilbert index (NOT Gray code).
+    // Sort into the sub-box either there are more than 2 points in it, or
+    //   the prescribed order of the curve is not reached yet.
+    //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
+    if ((p[w+1] - p[w]) > b->hilbert_limit) {
+      // Calculcate the start point (ei) of the curve in this sub-box.
+      //   update e = e ^ (e(w) left_rotate (d+1)).
+      if (w == 0) {
+        e_w = 0;
+      } else {
+        //   calculate e(w) = gc(2 * floor((w - 1) / 2)).
+        k = 2 * ((w - 1) / 2); 
+        e_w = k ^ (k >> 1); // = gc(k).
+      }
+      k = e_w;
+      e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
+      ei = e ^ e_w;
+      // Calulcate the direction (di) of the curve in this sub-box.
+      //   update d = (d + d(w) + 1) % n
+      if (w == 0) {
+        d_w = 0;
+      } else {
+        d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
       }
-    }
-
-    // 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;
+      di = (d + d_w + 1) % n;
+      // Calculate the bounding box of the sub-box.
+      if (transgc[e][d][w] & 1) { // x-axis
+        x1 = 0.5 * (bxmin + bxmax);
+        x2 = bxmax;
+      } else {
+        x1 = bxmin;
+        x2 = 0.5 * (bxmin + bxmax);
       }
-    }
-
-  } 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);
+      if (transgc[e][d][w] & 2) { // y-axis
+        y1 = 0.5 * (bymin + bymax);
+        y2 = bymax;
+      } else {
+        y1 = bymin;
+        y2 = 0.5 * (bymin + bymax);
+      }
+      if (transgc[e][d][w] & 4) { // z-axis
+        z1 = 0.5 * (bzmin + bzmax);
+        z2 = bzmax;
+      } else {
+        z1 = bzmin;
+        z2 = 0.5 * (bzmin + bzmax);
+      }
+      hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di, 
+                    x1, x2, y1, y2, z1, z2, depth+1);
+    } // if (p[w+1] - p[w] > 1)
+  } // w
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// ordervertices()    Order the vertices for incremental inserting.          //
-//                                                                           //
-// We assume the vertices have been sorted by a binary tree.                 //
+// brio_multiscale_sort()    Sort the points using BRIO and Hilbert curve.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::ordervertices(point* vertexarray, int arraysize)
+void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize, 
+                                      int threshold, REAL ratio, int *depth)
 {
-  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 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]
-  }
+  int middle;
 
-  // Make sure we've done correctly.
-  assert(index == arraysize);
+  middle = 0;
+  if (arraysize >= threshold) {
+    (*depth)++;
+    middle = arraysize * ratio;
+    brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
+  }
+  // Sort the right-array (rnd-th round) using the Hilbert curve.
+  hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
+                xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -11938,17 +10866,14 @@ unsigned long tetgenmesh::randomnation(unsigned int 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.      //
+// 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 searching for.                                        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::randomsample(point searchpt, triface *searchtet)
+void tetgenmesh::randomsample(point searchpt,triface *searchtet)
 {
   tetrahedron *firsttet, *tetptr;
   point torg;
@@ -11963,44 +10888,40 @@ void tetgenmesh::randomsample(point searchpt, triface *searchtet)
            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) {
+  if (!nonconvex) {
+    if (searchtet->tet == NULL) {
+      // A null tet. Choose the recenttet as the starting tet.
       *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)));
+      // 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 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;
       }
     }
+  } else {
+    // The mesh is non-convex. Do not use 'recenttet'.
+    assert(samples >= 1l); // Make sure at least 1 sample.
+    searchdist = longest;
   }
 
   // Select "good" candidate using k random samples, taking the closest one.
@@ -12040,11 +10961,6 @@ void tetgenmesh::randomsample(point searchpt, triface *searchtet)
           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.
@@ -12059,7 +10975,6 @@ void tetgenmesh::randomsample(point searchpt, triface *searchtet)
 //                                                                           //
 // 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.              //
@@ -12071,34 +10986,26 @@ void tetgenmesh::randomsample(point searchpt, triface *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.      //
+//              hull face which 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)
+enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt, 
+                                                 triface* searchtet)
 {
-  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;
-
+  enum locateresult loc = OUTSIDE;
+  int t1ver;
+  int s;
 
   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->tet = recenttet.tet;
   }
 
   // Check if we are in the outside of the convex hull.
@@ -12106,7 +11013,6 @@ enum tetgenmesh::locateresult
     // 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.
@@ -12114,22 +11020,14 @@ enum tetgenmesh::locateresult
     torg = org(*searchtet);
     tdest = dest(*searchtet);
     tapex = apex(*searchtet);
-    ori = orient3d(torg, tdest, tapex, searchpt); orient3dcount++;
+    ori = orient3d(torg, tdest, tapex, searchpt); 
     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.
+  assert(searchtet->ver != 4);
 
   // Walk through tetrahedra to locate the point.
   while (true) {
 
-    ptloc_count++;  // Algorithimic count.
-
     toppo = oppo(*searchtet);
     
     // Check if the vertex is we seek.
@@ -12141,58 +11039,43 @@ enum tetgenmesh::locateresult
       break;
     }
 
-    // We enter from serarchtet's base face. There are three other faces in
-    //   searchtet (all connecting to toppo), which one is the exit?
+    // We enter from one of serarchtet's faces, which face do we 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.
+    //   faces are viable moves. If so, randomly choose one.
     if (oriorg < 0) {
       if (oridest < 0) {
         if (oriapex < 0) {
-          if (0) { //if (!randflag) {
+          // All three faces are possible.
+          s = randomnation(3); // 's' is in {0,1,2}.
+          if (s == 0) {
+            nextmove = ORGMOVE;
+          } else if (s == 1) {
+            nextmove = DESTMOVE;
           } 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)
+            nextmove = APEXMOVE;
+          }
         } else {
           // Two faces, opposite to origin and destination, are viable.
-          if (0) { // if (!randflag) {
+          //s = randomnation(2); // 's' is in {0,1}.
+          if (randomnation(2)) {
+            nextmove = ORGMOVE;
           } else {
-            // Randomly choose a direction.
-            s = randomnation(2); // 's' is in {0,1}.
-            if (s == 0) {
-              nextmove = ORGMOVE;
-            } else {
-              nextmove = DESTMOVE;
-            }
-          } // if (randflag)
+            nextmove = DESTMOVE;
+          }
         }
       } else {
         if (oriapex < 0) {
           // Two faces, opposite to origin and apex, are viable.
-          if (0) { // if (!randflag) {
+          //s = randomnation(2); // 's' is in {0,1}.
+          if (randomnation(2)) {
+            nextmove = ORGMOVE;
           } else {
-            // Randomly choose a direction.
-            s = randomnation(2); // 's' is in {0,1}.
-            if (s == 0) {
-              nextmove = ORGMOVE;
-            } else {
-              nextmove = APEXMOVE;
-            }
-          } // if (randflag)
+            nextmove = APEXMOVE;
+          }
         } else {
           // Only the face opposite to origin is viable.
           nextmove = ORGMOVE;
@@ -12202,16 +11085,12 @@ enum tetgenmesh::locateresult
       if (oridest < 0) {
         if (oriapex < 0) {
           // Two faces, opposite to destination and apex, are viable.
-          if (0) { // if (!randflag) {
+          //s = randomnation(2); // 's' is in {0,1}.
+          if (randomnation(2)) {
+            nextmove = DESTMOVE;
           } else {
-            // Randomly choose a direction.
-            s = randomnation(2); // 's' is in {0,1}.
-            if (s == 0) {
-              nextmove = DESTMOVE;
-            } else {
-              nextmove = APEXMOVE;
-            }
-          } // if (randflag)
+            nextmove = APEXMOVE;
+          }
         } else {
           // Only the face opposite to destination is viable.
           nextmove = DESTMOVE;
@@ -12225,10 +11104,8 @@ enum tetgenmesh::locateresult
           //   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.
@@ -12239,7 +11116,6 @@ enum tetgenmesh::locateresult
               break;
             }
             if (oriapex == 0) {
-              //enext2self(*searchtet);
               enextself(*searchtet); // edge dest->oppo
               loc = ONEDGE; // return ONEDGE;
               break;
@@ -12249,10 +11125,8 @@ enum tetgenmesh::locateresult
           }
           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;
@@ -12262,7 +11136,6 @@ enum tetgenmesh::locateresult
           }
           if (oriapex == 0) {
             // Go to the face opposite to apex
-            //fnextself(*searchtet);
             esymself(*searchtet);
             loc = ONFACE; // return ONFACE;
             break;
@@ -12281,14 +11154,6 @@ enum tetgenmesh::locateresult
     } 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) {
@@ -12306,6 +11171,274 @@ enum tetgenmesh::locateresult
   return loc;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// 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)
+{
+  if (!facemarked(*flipface)) {
+    badface *newflipface = (badface *) flippool->alloc();
+    newflipface->tt = *flipface;
+    markface(newflipface->tt);
+    // Push this face into stack.
+    newflipface->nextitem = fstack;
+    fstack = newflipface;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// incrementalflip()    Incrementally flipping to construct DT.              //
+//                                                                           //
+// Faces need to be checked for flipping are already queued in 'flipstack'.  //
+// Return the total number of performed flips.                               //
+//                                                                           //
+// Comment:  This routine should be only used in the incremental Delaunay    //
+// construction.  In other cases, lawsonflip3d() should be used.             // 
+//                                                                           //
+// If the new point lies outside of the convex hull ('hullflag' is set). The //
+// incremental flip algorithm still works as usual.  However, we must ensure //
+// that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
+// edge or face. Otherwise, the underlying space of the triangulation becomes//
+// non-manifold and it is not possible to flip further.                      //
+// Thanks to Joerg Rambau and Frank Lutz for helping in this issue.          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::incrementalflip(point newpt, int hullflag, flipconstraints *fc)
+{
+  badface *popface;
+  triface fliptets[5], *parytet;
+  point *pts, *parypt, pe;
+  REAL sign, ori;
+  int flipcount = 0;
+  int t1ver;
+  int i;
+
+  if (b->verbose > 2) {
+    printf("      Lawson flip (%ld faces).\n", flippool->items);
+  }
+
+  if (hullflag) {
+    // 'newpt' lies in the outside of the convex hull. 
+    // Mark all hull vertices which are connecting to it.
+    popface = flipstack;
+    while (popface != NULL) {
+      pts = (point *) popface->tt.tet;
+      for (i = 4; i < 8; i++) {
+        if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
+          if (!pinfected(pts[i])) {
+            pinfect(pts[i]);
+            cavetetvertlist->newindex((void **) &parypt);
+            *parypt = pts[i];
+          }
+        } 
+      }
+      popface = popface->nextitem;
+    }
+  }
+
+  // Loop until the queue is empty.
+  while (flipstack != NULL) {
+
+    // Pop a face from the stack.
+    popface = flipstack;
+    fliptets[0] = popface->tt;
+    flipstack = flipstack->nextitem; // The next top item in stack.
+    flippool->dealloc((void *) popface);
+
+    // Skip it if it is a dead tet (destroyed by previous flips).
+    if (isdeadtet(fliptets[0])) continue;
+    // Skip it if it is not the same tet as we saved.
+    if (!facemarked(fliptets[0])) continue;
+
+    unmarkface(fliptets[0]);    
+
+    if ((point) fliptets[0].tet[7] == dummypoint) {
+      // It must be a hull edge.
+      fliptets[0].ver = epivot[fliptets[0].ver];
+      // A hull edge. The current convex hull may be enlarged.
+      fsym(fliptets[0], fliptets[1]);
+      pts = (point *) fliptets[1].tet;
+      ori = orient3d(pts[4], pts[5], pts[6], newpt);
+      if (ori < 0) {
+        // Visible. The convex hull will be enlarged.
+        // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
+        // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
+        enext(fliptets[1], fliptets[2]); 
+        eprev(fliptets[1], fliptets[3]); 
+        fnextself(fliptets[2]); // [a,c,e,*]
+        fnextself(fliptets[3]); // [c,b,e,*]
+        if (oppo(fliptets[2]) == newpt) {
+          if (oppo(fliptets[3]) == newpt) {
+            // Both tets exist! A 4-to-1 flip is found.
+            terminatetetgen(this, 2); // Report a bug.
+          } else {
+            esym(fliptets[2], fliptets[0]);
+            fnext(fliptets[0], fliptets[1]); 
+            fnext(fliptets[1], fliptets[2]); 
+            // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
+            // This corresponds to my standard labels, where edge [e,d] is
+            //   repalced by face [a,b,c], and a is the new vertex. 
+            //   [0] [c,a,d,e] (d = newpt)
+            //   [1] [c,a,e,b] (c = dummypoint)
+            //   [2] [c,a,b,d]
+            flip32(fliptets, 1, fc);
+          }
+        } else {
+          if (oppo(fliptets[3]) == newpt) {
+            fnext(fliptets[3], fliptets[0]);
+            fnext(fliptets[0], fliptets[1]); 
+            fnext(fliptets[1], fliptets[2]); 
+            // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
+            //   [0] [c,b,d,a] (d = newpt)
+            //   [1] [c,b,a,e] (c = dummypoint)
+            //   [2] [c,b,e,d]
+            flip32(fliptets, 1, fc);
+          } else {
+            if (hullflag) {
+              // Reject this flip if pe is already marked.
+              pe = oppo(fliptets[1]);
+              if (!pinfected(pe)) {
+                pinfect(pe);
+                cavetetvertlist->newindex((void **) &parypt);
+                *parypt = pe;
+                // Perform a 2-to-3 flip.
+                flip23(fliptets, 1, fc);
+              } else {
+                // Reject this flip.
+                flipcount--;
+              }
+            } else {
+              // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
+              //   [0] [a,b,c,d], d = newpt.
+              //   [1] [b,a,c,e], c = dummypoint.
+              flip23(fliptets, 1, fc);
+            }
+          }
+        }
+        flipcount++;
+      } 
+      continue;
+    } // if (dummypoint)
+
+    fsym(fliptets[0], fliptets[1]);
+    if ((point) fliptets[1].tet[7] == dummypoint) {
+      // A hull face is locally Delaunay.
+      continue;
+    }
+    // Check if the adjacent tet has already been tested.
+    if (marktested(fliptets[1])) {
+      // It has been tested and it is Delaunay.
+      continue;
+    }
+
+    // Test whether the face is locally Delaunay or not.
+    pts = (point *) fliptets[1].tet; 
+    if (b->weighted) {
+      sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
+                        pts[4][3], pts[5][3], pts[6][3], pts[7][3],
+                        newpt[3]);
+    } else {
+      sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
+    }
+
+
+    if (sign < 0) {
+      point pd = newpt;
+      point pe = oppo(fliptets[1]);
+      // Check the convexity of its three edges. Stop checking either a
+      //   locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
+      //   encountered, and 'fliptet' represents that edge.
+      for (i = 0; i < 3; i++) {
+        ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
+        if (ori <= 0) break;
+        enextself(fliptets[0]);
+      }
+      if (ori > 0) {
+        // A 2-to-3 flip is found.
+        //   [0] [a,b,c,d], 
+        //   [1] [b,a,c,e]. no dummypoint.
+        flip23(fliptets, 0, fc);
+        flipcount++;
+      } else { // ori <= 0
+        // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
+        //   where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
+        // Check if there are three or four tets sharing at this edge.        
+        esymself(fliptets[0]); // [b,a,d,c]
+        for (i = 0; i < 3; i++) {
+          fnext(fliptets[i], fliptets[i+1]);
+        }
+        if (fliptets[3].tet == fliptets[0].tet) {
+          // A 3-to-2 flip is found. (No hull tet.)
+          flip32(fliptets, 0, fc); 
+          flipcount++;
+        } else {
+          // There are more than 3 tets at this edge.
+          fnext(fliptets[3], fliptets[4]);
+          if (fliptets[4].tet == fliptets[0].tet) {
+            if (ori == 0) {
+              // A 4-to-4 flip is found. (Two hull tets may be involved.)
+              // Current tets in 'fliptets':
+              //   [0] [b,a,d,c] (d may be newpt)
+              //   [1] [b,a,c,e]
+              //   [2] [b,a,e,f] (f may be dummypoint)
+              //   [3] [b,a,f,d]
+              esymself(fliptets[0]); // [a,b,c,d] 
+              // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
+              //   This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
+              //   It will be removed by the followed 3-to-2 flip.
+              flip23(fliptets, 0, fc); // No hull tet.
+              fnext(fliptets[3], fliptets[1]);
+              fnext(fliptets[1], fliptets[2]);
+              // Current tets in 'fliptets':
+              //   [0] [...]
+              //   [1] [b,a,d,e] (degenerated, d may be new point).
+              //   [2] [b,a,e,f] (f may be dummypoint)
+              //   [3] [b,a,f,d]
+              // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
+              //   Hull tets may be involved (f may be dummypoint).
+              flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
+              flipcount++;
+            }
+          }
+        }
+      } // ori
+    } else {
+      // The adjacent tet is Delaunay. Mark it to avoid testing it again.
+      marktest(fliptets[1]);
+      // Save it for unmarking it later.
+      cavebdrylist->newindex((void **) &parytet);
+      *parytet = fliptets[1];
+    }
+
+  } // while (flipstack)
+
+  // Unmark saved tetrahedra.
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    parytet = (triface *) fastlookup(cavebdrylist, i);
+    unmarktest(*parytet);
+  }
+  cavebdrylist->restart();
+
+  if (hullflag) {
+    // Unmark infected vertices.
+    for (i = 0; i < cavetetvertlist->objects; i++) {
+      parypt = (point *) fastlookup(cavetetvertlist, i);
+      puninfect(*parypt);
+    }
+    cavetetvertlist->restart();
+  }
+
+
+  return flipcount;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -12383,13 +11516,6 @@ void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
     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));
@@ -12406,53 +11532,29 @@ void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+
 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 randindex; 
+  int ngroup = 0;
   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->no_sort) {
     if (b->verbose) {
-      printf("  Sorting vertices by hilbert curve.\n"); 
+      printf("  Using the input order.\n"); 
     }
-    // To be done...
     for (i = 0; i < in->numberofpoints; i++) {
       permutarray[i] = (point) points->traverse();
     }
@@ -12460,58 +11562,70 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv)
     if (b->verbose) {
       printf("  Permuting vertices.\n"); 
     }
+    srand(in->numberofpoints);
     for (i = 0; i < in->numberofpoints; i++) {
-      randindex = randomnation(i + 1);
+      randindex = rand() % (i + 1); // randomnation(i + 1);
       permutarray[i] = permutarray[randindex];
       permutarray[randindex] = (point) points->traverse();
     }
+    if (b->brio_hilbert) { // -b option
+      if (b->verbose) {
+        printf("  Sorting vertices.\n"); 
+      }
+      hilbert_init(in->mesh_dim);
+      brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold, 
+                           b->brio_ratio, &ngroup);
+    }
   }
 
   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));
+  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) {
+  while ((distance(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);
+      terminatetetgen(this, 10);
     }
   }
   if (i > 1) {
-    // Swap to move the non-indetical vertex from index i to index 1.
+    // Swap to move the non-identical 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.
+  // Acknowledgement:  Thanks Jan Pomplun for his correction by using 
+  //   epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
   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) {
+  cross(v1, v2, n);
+  while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) < 
+         (b->epsilon * b->epsilon)) {
     i++;
     if (i == in->numberofpoints - 1) {
       printf("Exception:  All vertices are (nearly) collinear (Tol = %g).\n",
              b->epsilon);
-      terminatetetgen(10);
+      terminatetetgen(this, 10);
     }
     for (j = 0; j < 3; j++) {
       v2[j] = permutarray[i][j] - permutarray[0][j];
     }
-    CROSS(v1, v2, n);
+    cross(v1, v2, n);
   }
   if (i > 2) {
-    // Swap to move the non-indetical vertex from index i to index 1.
+    // Swap to move the non-identical vertex from index i to index 1.
     swapvertex = permutarray[i];
     permutarray[i] = permutarray[2];
     permutarray[2] = swapvertex;
@@ -12519,221 +11633,119 @@ void tetgenmesh::incrementaldelaunay(clock_t& tv)
 
   // 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) {
+  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2], 
+                     permutarray[i]);
+  while ((fabs(ori) / bboxsize3) < (b->epsilon * b->epsilon * 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;
+      terminatetetgen(this, 10);
     }
+    ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2], 
+                       permutarray[i]);
   }
-  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;
+  if (i > 3) {
+    // Swap to move the non-identical vertex from index i to index 1.
+    swapvertex = permutarray[i];
+    permutarray[i] = permutarray[3];
+    permutarray[3] = swapvertex;
   }
 
-  // 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;
+  // 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;
   }
 
-  return true;
-}
+  // Create the initial Delaunay tetrahedralization.
+  initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
+                  permutarray[3]);
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// 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.                                             //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  if (b->verbose) {
+    printf("  Incrementally inserting vertices.\n");
+  }
+  insertvertexflags ivf;
+  flipconstraints fc;
+
+  // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
+  if (b->incrflip) {
+    ivf.bowywat = 0;
+    ivf.lawson = 1;
+    fc.enqflag = 1;
+  } else {
+    ivf.bowywat = 1;
+    ivf.lawson = 0;
+  }
 
-void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
-{
-  arraypool *ptarray;
-  point *parypt;
 
-  ptarray = new arraypool(sizeof(point), 4);
+  for (i = 4; i < in->numberofpoints; i++) {
+    if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
+      setpointtype(permutarray[i], VOLVERTEX);
+    }
+    if (b->brio_hilbert || b->no_sort) { // -b or -b/1
+      // Start the last updated tet.
+      searchtet.tet = recenttet.tet;
+    } else { // -b0
+      // Randomly choose the starting tet for point location.
+      searchtet.tet = NULL;
+    }
+    ivf.iloc = (int) OUTSIDE;
+    // Insert the vertex.
+    if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
+      if (flipstack != NULL) {
+        // Perform flip to recover Delaunayness.
+        incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
+      }
+    } else {
+      if (ivf.iloc == (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++;
+      } else if (ivf.iloc == (int) NEARVERTEX) {
+        swapvertex = point2ppt(permutarray[i]);
+        if (!b->quiet) {
+          printf("Warning:  Point %d is replaced by point %d.\n",
+                 pointmark(permutarray[i]), pointmark(swapvertex));
+          printf("  Avoid creating a very short edge (len = %g) (< %g).\n",
+                 permutarray[i][3], b->minedgelength);
+          printf("  You may try a smaller tolerance (-T) (current is %g)\n", 
+                 b->epsilon);
+          printf("  or use the option -M0/1 to avoid such replacement.\n");
+        }
+        // Remember it is a duplicated point.
+        setpointtype(permutarray[i], DUPLICATEDVERTEX);
+        // Count the number of duplicated points.
+        dupverts++;
+      }
+    }
+  }
 
-  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;
+  delete [] permutarray;
 }
 
+////                                                                       ////
+////                                                                       ////
+//// delaunay_cxx /////////////////////////////////////////////////////////////
+
+//// surface_cxx //////////////////////////////////////////////////////////////
+////                                                                       ////
+////                                                                       ////
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // flipshpush()    Push a facet edge into flip stack.                        //
@@ -12754,19 +11766,20 @@ void tetgenmesh::flipshpush(face* flipedge)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// flip22()    Remove an edge by transforming 2-to-2 subfaces.               //
+// flip22()    Perform a 2-to-2 flip in surface mesh.                        //
 //                                                                           //
-// 'flipfaces' contains two faces: abc and bad. This routine removes these 2 //
-// faces and replaces them by two new faces: cdb and dca.                    //
+// 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and   //
+// [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
+// is replaced by edge [c,d].                                                //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
 {
-  face bdedges[4], outfaces[4], infaces[4], bdsegs[4];
-  face checkface, checkseg;
+  face bdedges[4], outfaces[4], infaces[4];
+  face bdsegs[4];
+  face checkface;
   point pa, pb, pc, pd;
-  badface *bface;
   int i;
 
   pa = sorg(flipfaces[0]);
@@ -12778,10 +11791,6 @@ void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
     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.
@@ -12796,8 +11805,7 @@ void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
     infaces[i] = outfaces[i];
     sspivot(bdedges[i], bdsegs[i]);
     if (outfaces[i].sh != NULL) {
-      sspivot(bdedges[i], checkseg);
-      if (checkseg.sh != NULL) {
+      if (isshsubseg(bdedges[i])) {
         spivot(infaces[i], checkface);
         while (checkface.sh != bdedges[i].sh) {
           infaces[i] = checkface;
@@ -12811,9 +11819,9 @@ void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
   // Shellmark does not change.
   // area constraint does not change.
 
-  // Transform abc -> cdb.
+  // Transform [a,b,c] -> [c,d,b].
   setshvertices(flipfaces[0], pc, pd, pb);
-  // Transform bad -> dca.
+  // Transform [b,a,d] -> [d,c,a].
   setshvertices(flipfaces[1], pd, pc, pa);
 
   // Update the point-to-subface map.
@@ -12849,12 +11857,7 @@ void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
       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.
-        }
+        enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
       }
     } else {
       ssdissolve(bdedges[i]);
@@ -12864,12 +11867,7 @@ void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
   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.
-      }
+      enqueuesubface(badsubfacs, &(flipfaces[i]));
     }
   }
 
@@ -12900,22 +11898,17 @@ void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
 
 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;
+  face bdedges[3], outfaces[3], infaces[3];
+  face bdsegs[3];
+  face checkface;
+  point pa, pb, pc;
   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++;
+  flip31count++;
 
   // Collect all infos at the three boundary edges.
   for (i = 0; i < 3; i++) {
@@ -12924,8 +11917,7 @@ void tetgenmesh::flip31(face* flipfaces, int flipflag)
     infaces[i] = outfaces[i];
     sspivot(bdedges[i], bdsegs[i]);
     if (outfaces[i].sh != NULL) {
-      sspivot(bdedges[i], checkseg);
-      if (checkseg.sh != NULL) {
+      if (isshsubseg(bdedges[i])) {
         spivot(infaces[i], checkface);
         while (checkface.sh != bdedges[i].sh) {
           infaces[i] = checkface;
@@ -12940,8 +11932,11 @@ void tetgenmesh::flip31(face* flipfaces, int flipflag)
   setshvertices(flipfaces[3], pa, pb,pc);
   setshellmark(flipfaces[3], shellmark(flipfaces[0]));
   if (checkconstraints) {
-    area = areabound(flipfaces[0]);
-    setareabound(flipfaces[3], area);
+    //area = areabound(flipfaces[0]);
+    setareabound(flipfaces[3], areabound(flipfaces[0]));
+  }
+  if (useinsertradius) {
+    setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
   }
 
   // Update the point-to-subface map.
@@ -12998,15 +11993,13 @@ long tetgenmesh::lawsonflip()
 {
   badface *popface;
   face flipfaces[2];
-  face checkseg;
   point pa, pb, pc, pd;
   REAL sign;
-  long flipcount;
+  long flipcount = 0;
 
   if (b->verbose > 2) {
     printf("      Lawson flip %ld edges.\n", flippool->items);
   }
-  flipcount = flip22count;
 
   while (flipstack != (badface *) NULL) {
 
@@ -13023,8 +12016,7 @@ long tetgenmesh::lawsonflip()
     // 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;
+    if (isshsubseg(flipfaces[0])) continue;
 
     // Get the adjacent face.
     spivot(flipfaces[0], flipfaces[1]);
@@ -13037,16 +12029,15 @@ long tetgenmesh::lawsonflip()
     if (sign < 0) {
       // It is non-locally Delaunay. Flip it.
       flip22(flipfaces, 1, 0);
+      flipcount++;
     }
   }
 
   if (b->verbose > 2) {
-    printf("      %ld edges stacked, %ld flips.\n", flippool->items,
-      flip22count - flipcount);
+    printf("      Performed %ld flips.\n", flipcount);
   }
-  assert(flippool->items == 0l); // SELF_CHECK
 
-  return flip22count - flipcount;
+  return flipcount;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -13058,75 +12049,72 @@ long tetgenmesh::lawsonflip()
 // '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.                                  //
+// 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
+// will first locate the point. It starts searching from 'searchsh' or 'rec- //
+// entsh' if 'searchsh' is NULL.                                             //
+//                                                                           //
+// If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert    //
+// the vertex. Otherwise, only insert the vertex in the initial cavity.      // 
+//                                                                           //
+// If 'iloc' is 'INSTAR', this means the cavity of this vertex was already   //
+// provided in the list 'caveshlist'.                                        //
+//                                                                           //
+// If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
+// be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'.                     //
+//                                                                           //
+// 'rflag' (rounding) is a parameter passed to slocate() function.  If it is //
+// set, after the location of the point is found, either ONEDGE or ONFACE,   //
+// round the result using an epsilon.                                        //
+//                                                                           //
+// NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
+// want to remove the new point immediately.                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
-                              int iloc, int bowywat)
+                              int iloc, int bowywat, int rflag)
 {
-  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;
+  point pa, pb;
+  enum locateresult loc = OUTSIDE;
+  REAL sign, ori;
   int i, j;
 
   if (b->verbose > 2) {
     printf("      Insert facet point %d.\n", pointmark(insertpt));
   }
 
-  if (splitseg != NULL) {
+  if (bowywat == 3) {
+    loc = INSTAR;
+  }
+
+  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
     // A segment is going to be split, no point location.
     spivot(*splitseg, *searchsh);
-    loc = ONEDGE;
+    if (loc != INSTAR) loc = ONEDGE;
   } else {
-    loc = (enum locateresult) iloc;
+    if (loc != INSTAR) 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));
+      // Search the vertex. An above point must be provided ('aflag' = 1).
+      loc = slocate(insertpt, searchsh, 1, 1, rflag);
     }
   }
 
-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) {
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
       splitseg->shver = 0;
       pa = sorg(*splitseg);
     } else {
@@ -13137,9 +12125,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       neighsh = *searchsh;
       while (1) {
         // Adjust the origin of its edge to be 'pa'.
-        if (sorg(neighsh) != pa) {
-          sesymself(neighsh);
-        }
+        if (sorg(neighsh) != pa) sesymself(neighsh);
         // Add this face into list (in B-W cavity).
         smarktest(neighsh);
         caveshlist->newindex((void **) &parysh);
@@ -13155,18 +12141,12 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       }
     } // 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.
@@ -13176,9 +12156,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       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);
+        ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
         if (ori < 0) {
           *searchsh = neighsh; // Visible, update 'searchsh'.
         } else {
@@ -13199,8 +12177,11 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       setshvertices(newsh, pb, pa, insertpt);
       setshellmark(newsh, shellmark(*searchsh));
       if (checkconstraints) {
-        area = areabound(*searchsh);
-        setareabound(newsh, area);
+        //area = areabound(*searchsh);
+        setareabound(newsh, areabound(*searchsh));
+      }
+      if (useinsertradius) {
+        setfacetindex(newsh, getfacetindex(*searchsh));
       }
       // Connect the new subface to the bottom subfaces.
       sbond1(newsh, *searchsh);
@@ -13236,47 +12217,30 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       // Finish the process if p is not visible by the hull edge.
       if (ori >= 0) break;
     }
+  } else if (loc == INSTAR) {
+    // Under this case, the sub-cavity sC(p) has already been formed in
+    //   insertvertex().
   }
 
-} 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) {
+      if (!isshsubseg(cavesh)) {
         spivot(cavesh, neighsh);
         if (neighsh.sh != NULL) {
           // The adjacent face exists.
           if (!smarktested(neighsh)) {
             if (bowywat) {
-              if (bowywat > 2) {
+              if (loc == INSTAR) { // 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) {
+                if (!isshtet(neighsh)) {
                   // 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);
+                  sign = incircle3d(sorg(neighsh), sdest(neighsh), 
+                                    sapex(neighsh), insertpt);
                 } else {
                   // It is connected to an adjacent tet. A boundary edge.
                   sign = 1;
@@ -13320,10 +12284,6 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
     } // 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++) {
@@ -13336,10 +12296,12 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
     makeshellface(subfaces, &newsh); 
     setshvertices(newsh, pa, pb, insertpt);
     setshellmark(newsh, shellmark(*parysh));
-    setshelltype(newsh, shelltype(*parysh));
     if (checkconstraints) {
-      area = areabound(*parysh);
-      setareabound(newsh, area);
+      //area = areabound(*parysh);
+      setareabound(newsh, areabound(*parysh));
+    }
+    if (useinsertradius) {
+      setfacetindex(newsh, getfacetindex(*parysh));
     }
     // Update the point-to-subface map.
     if (pointtype(pa) == FREEFACETVERTEX) {
@@ -13357,7 +12319,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
         checkseg.shver = 0;
         if (sorg(newsh) != sorg(checkseg)) {
           sesymself(newsh);
-          sesymself(*parysh); // This side should also be inversed.
+          sesymself(*parysh); // This side should also be inverse.
         }
         spivot(casin, neighsh);
         while (neighsh.sh != parysh->sh) {
@@ -13376,8 +12338,10 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
     sbond1(*parysh, newsh);
   }
 
-  // Set a handle for searching.
-  recentsh = newsh;
+  if (newsh.sh != NULL) {
+    // Set a handle for searching.
+    recentsh = newsh;
+  }
 
   // Update the point-to-subface map.
   if (pointtype(insertpt) == FREEFACETVERTEX) {
@@ -13405,8 +12369,6 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       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 {
@@ -13431,8 +12393,6 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       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 {
@@ -13442,13 +12402,15 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
     }
   }
 
-  if (loc == ONEDGE) {
-
+  if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
+      || (cavesegshlist->objects > 0l)) {
     // 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.
+    face aseg, bseg, aoutseg, boutseg;
+
     for (i = 0; i < cavesegshlist->objects; i++) {
       // Get the saved old subface.
       parysh = (face *) fastlookup(cavesegshlist, i);
@@ -13468,7 +12430,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
           }
           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
+          //   As a result, the two degenerated new faces are squeezed 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). 
@@ -13480,7 +12442,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
             sbond1(newsh, casout); // newsh <- casout.
           }
         } else {
-          // There is only one subface containing this edge [a,b]. Squeese the
+          // There is only one subface containing this edge [a,b]. Squeeze 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.
@@ -13490,7 +12452,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
             sdissolve(newsh);
           }
         }
-        recentsh = newsh;
+        //recentsh = newsh;
         // Update the point-to-subface map.
         if (pointtype(insertpt) == FREEFACETVERTEX) {
           setpoint2sh(insertpt, sencode(newsh));
@@ -13498,18 +12460,14 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       }
     }
 
-    if (splitseg != NULL) {
-      if (bowywat < 3) {
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
+      if (loc != INSTAR) { // 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);
@@ -13519,12 +12477,14 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       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(aseg, areabound(*splitseg));
         setareabound(bseg, areabound(*splitseg));
       }
+      if (useinsertradius) {
+        setfacetindex(aseg, getfacetindex(*splitseg));
+        setfacetindex(bseg, getfacetindex(*splitseg));
+      }
 
       // Connect [#, a]<->[a, p].
       senext2(*splitseg, boutseg); // Temporarily use boutseg.
@@ -13546,7 +12506,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       sbond(aoutseg, boutseg);
 
       // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
-      // Although the degenerated new faces have been squeesed. They still
+      // Although the degenerated new faces have been squeezed. They still
       //   hold the connections to the actual new faces. 
       for (i = 0; i < cavesegshlist->objects; i++) {        
         parysh = (face *) fastlookup(cavesegshlist, i);
@@ -13565,11 +12525,17 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
 
 
       // Let the point remember the segment it lies on.
-      setpoint2sh(insertpt, sencode(aseg));
+      if (pointtype(insertpt) == FREESEGVERTEX) {
+        setpoint2sh(insertpt, sencode(aseg));
+      }
       // Update the point-to-seg map.
-      setpoint2sh(pa, sencode(aseg));
-      setpoint2sh(pb, sencode(bseg));
-    } // if (splitseg != NULL)
+      if (pointtype(pa) == FREESEGVERTEX) {
+        setpoint2sh(pa, sencode(aseg));
+      }
+      if (pointtype(pb) == FREESEGVERTEX) {
+        setpoint2sh(pb, sencode(bseg));
+      }
+    } // if ((splitseg != NULL) && (splitseg->sh != NULL)) 
 
     // Delete all degenerated new faces.
     for (i = 0; i < cavesegshlist->objects; i++) {
@@ -13581,7 +12547,7 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
     }
     cavesegshlist->restart();
 
-    if (splitseg != NULL) {
+    if ((splitseg != NULL) && (splitseg->sh != NULL)) {
       // Return the two new subsegments (for further process).
       //   Re-use 'cavesegshlist'.
       cavesegshlist->newindex((void **) &parysh);
@@ -13589,7 +12555,6 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
       cavesegshlist->newindex((void **) &parysh);
       *parysh = bseg;
     }
-
   } // if (loc == ONEDGE)
 
 
@@ -13604,39 +12569,34 @@ if (bowywat < 3) { // if (bowywat == 1 || bowywat == 2) {
 // 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'.        //
 //                                                                           //
+// If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay-   //
+// ness after p is removed.                                                  //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 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;
+  face flipfaces[4], spinsh, *parysh;
   point pa, pb, pc, pd;
-  int it, i, j;
-
-  REAL *norm, n1[3], n2[3];
-  REAL len, len1, len2;
   REAL ori1, ori2;
+  int it, i, j;
 
   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].
+    face startsh, neighsh, nextsh;
+    face abseg, prevseg, checkseg;
+    face adjseg1, adjseg2;
+    face fakesh;
     senext2(*parentseg, prevseg);
     spivotself(prevseg);
-    assert(prevseg.sh != NULL);
     prevseg.shver = 0;
     assert(sdest(prevseg) == delpt);
     // Restore the original segment [a,b].
@@ -13649,10 +12609,12 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
     makeshellface(subsegs, &abseg);
     setshvertices(abseg, pa, pb, NULL);
     setshellmark(abseg, shellmark(*parentseg));
-    setshelltype(abseg, shelltype(*parentseg));
     if (checkconstraints) {
       setareabound(abseg, areabound(*parentseg));
     }
+    if (useinsertradius) {
+      setfacetindex(abseg, getfacetindex(*parentseg));
+    }
     // Connect [#, a]<->[a, b].
     senext2(prevseg, adjseg1);
     spivotself(adjseg1);
@@ -13680,16 +12642,17 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
     // 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;
-    } 
+    if (parentsh->sh != NULL) {
+      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 == 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).
@@ -13741,12 +12704,7 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
         // 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);
+        if (sorg(startsh) != pa) sesymself(startsh);
         sdissolve(startsh);
         // Connect fakesh to the segment [a,b].
         ssbond(startsh, abseg);
@@ -13797,9 +12755,7 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
     parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
     senextself(*parentsh); // [b,p,a].
     spivotself(*parentsh);
-    if (sorg(*parentsh) != delpt) {
-      sesymself(*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.
@@ -13817,10 +12773,8 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
         spivotself(spinsh);
         assert(spinsh.sh != NULL);
         if (spinsh.sh == parentsh->sh) break;
-        if (sorg(spinsh) != delpt) {
-          sesymself(spinsh);
-          assert(sorg(spinsh) == delpt);
-        }
+        if (sorg(spinsh) != delpt) sesymself(spinsh);
+        assert(sorg(spinsh) == delpt);
       } // while (1)
 
       if (caveshlist->objects == 3) {
@@ -13839,9 +12793,6 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
         *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.
@@ -13849,35 +12800,15 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
         parysh = (face *) fastlookup(caveshlist, i);
         flipfaces[0] = *parysh;
         spivot(flipfaces[0], flipfaces[1]);
-        if (sorg(flipfaces[0]) != sdest(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];
+          calculateabovepoint4(pa, pb, pc, pd);
           // Check if a 2-to-2 flip is possible.
           ori1 = orient3d(pc, pd, dummypoint, pa);
           ori2 = orient3d(pc, pd, dummypoint, pb);
@@ -13894,6 +12825,7 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
           }
         } //
       } // 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.
@@ -13911,6 +12843,7 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
         caveshbdlist->newindex((void **) &parysh);
         *parysh = flipfaces[0];
       }
+
       // The edge list at p are changed.
       caveshlist->restart();
     } // while (1)
@@ -13949,7 +12882,7 @@ int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
 // 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:                         //
+// The returned value indicates 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'.                         //
@@ -13962,35 +12895,19 @@ 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;
+  point pa, pb, pc;
   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();
+    calculateabovepoint4(pa, pb, pc, searchpt);
   }
 
   // 'dummypoint' is given. Make sure it is above [a,b,c]
@@ -14025,25 +12942,7 @@ enum tetgenmesh::locateresult tetgenmesh::slocate(point 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) {
+        if (randomnation(2)) {
           nextmove = MOVE_CA;
         } else {
           nextmove = MOVE_BC;
@@ -14088,8 +12987,7 @@ enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
     }
     if (!cflag) {
       // NON-convex case. Check if we will cross a boundary.
-      sspivot(*searchsh, checkseg);
-      if (checkseg.sh != NULL) {
+      if (isshsubseg(*searchsh)) {
         return ENCSEGMENT;
       }
     }
@@ -14121,6 +13019,8 @@ enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
 
   if (rflag) {
     // Round the locate result before return.
+    REAL n[3], area_abc, area_abp, area_bcp, area_cap;
+
     pa = sorg(*searchsh);
     pb = sdest(*searchsh);
     pc = sapex(*searchsh);
@@ -14188,23 +13088,21 @@ enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
 // 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"  //
+// If an edge in T is found matching this segment, the segment is "locked"   //
 // 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)
+enum tetgenmesh::interresult tetgenmesh::sscoutsegment(face *searchsh, 
+  point endpt)
 {
   face flipshs[2], neighsh;
-  face newseg, checkseg;
+  face newseg;
   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;
+  REAL ori_ab, ori_ca, len;
 
   // The origin of 'searchsh' is fixed.
   startpt = sorg(*searchsh); // pa = startpt;
@@ -14214,6 +13112,7 @@ enum tetgenmesh::interresult
     printf("      Scout segment (%d, %d).\n", pointmark(startpt),
            pointmark(endpt));
   }
+  len = distance(startpt, endpt);
 
   // Search an edge in 'searchsh' on the path of this segment.
   while (1) {
@@ -14232,22 +13131,22 @@ enum tetgenmesh::interresult
       break;
     }
 
-    ori_ab = orient3d(startpt, pb, dummypoint, endpt);
-    ori_ca = orient3d(pc, startpt, dummypoint, endpt);
+    // Round the results.
+    if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
+      ori_ab = 0.0;
+    } else {
+      ori_ab = orient3d(startpt, pb, dummypoint, endpt);
+    }
+    if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
+      ori_ca = 0.0;
+    } else {
+      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) {
+        if (randomnation(2)) {
           nextmove = MOVE_CA;
         } else {
           nextmove = MOVE_AB;
@@ -14287,13 +13186,32 @@ enum tetgenmesh::interresult
     // 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);      
+      if (neighsh.sh != NULL) {
+        if (sorg(neighsh) != pb) sesymself(neighsh);
+        senext(neighsh, *searchsh);
+      } else {
+        // This side (startpt->pb) is outside. It is caused by rounding error.
+        // Try the next side, i.e., (pc->startpt).
+        senext2(*searchsh, neighsh);
+        spivotself(neighsh);
+        assert(neighsh.sh != NULL);
+        if (sdest(neighsh) != pc) sesymself(neighsh);
+        *searchsh = neighsh;
+      }
     } else {
       senext2(*searchsh, neighsh);
       spivotself(neighsh);
-      if (sdest(neighsh) != pc) sesymself(neighsh);
-      *searchsh = neighsh;
+      if (neighsh.sh != NULL) {
+        if (sdest(neighsh) != pc) sesymself(neighsh);
+        *searchsh = neighsh;
+      } else {
+        // The same reason as above. 
+        // Try the next side, i.e., (startpt->pb).
+        spivot(*searchsh, neighsh);
+        assert(neighsh.sh != NULL);
+        if (sorg(neighsh) != pb) sesymself(neighsh);
+        senext(neighsh, *searchsh);
+      }
     }
     assert(sorg(*searchsh) == startpt); // SELF_CHECK
 
@@ -14303,11 +13221,8 @@ enum tetgenmesh::interresult
     // 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]);
-    }
+    // Set the default segment marker.
+    setshellmark(newseg, 1);
     ssbond(*searchsh, newseg);
     spivot(*searchsh, neighsh);
     if (neighsh.sh != NULL) {
@@ -14324,21 +13239,20 @@ enum tetgenmesh::interresult
   if (dir == ACROSSEDGE) {
     // Edge [b, c] intersects with the segment.
     senext(*searchsh, flipshs[0]);
-    sspivot(flipshs[0], checkseg);
-    if (checkseg.sh != NULL) {
+    if (isshsubseg(flipshs[0])) {
       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);
+      terminatetetgen(this, 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.
+    // The flip may create an inverted triangle, check it.
     pa = sapex(flipshs[1]);
     pb = sapex(flipshs[0]);
     pc = sorg(flipshs[0]);
@@ -14349,16 +13263,8 @@ enum tetgenmesh::interresult
     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'.
@@ -14380,7 +13286,6 @@ enum tetgenmesh::interresult
 void tetgenmesh::scarveholes(int holes, REAL* holelist)
 {
   face *parysh, searchsh, neighsh;
-  face checkseg;
   enum locateresult loc;
   int i, j;
 
@@ -14403,8 +13308,7 @@ void tetgenmesh::scarveholes(int holes, REAL* holelist)
         }
       } else {
         // A hull side. Check if it is protected by a segment.
-        sspivot(searchsh, checkseg);
-        if (checkseg.sh == NULL) {
+        if (!isshsubseg(searchsh)) {
           // Not protected. Save this face.
           if (!sinfected(searchsh)) {
             sinfect(searchsh);
@@ -14436,8 +13340,7 @@ void tetgenmesh::scarveholes(int holes, REAL* holelist)
     for (j = 0; j < 3; j++) {
       spivot(searchsh, neighsh);
       if (neighsh.sh != NULL) {
-        sspivot(searchsh, checkseg);
-        if (checkseg.sh == NULL) {
+        if (!isshsubseg(searchsh)) {
           if (!sinfected(neighsh)) {
             sinfect(neighsh);
             caveshbdlist->newindex((void **) &parysh);
@@ -14469,6 +13372,9 @@ void tetgenmesh::scarveholes(int holes, REAL* holelist)
 //                                                                           //
 // triangulate()    Create a CDT for the facet.                              //
 //                                                                           //
+// All vertices of the triangulation have type FACETVERTEX.  The actual type //
+// of boundary vertices are set by the routine unifysements().               //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
@@ -14477,7 +13383,6 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
   face searchsh, newsh, *parysh; 
   face newseg;
   point pa, pb, pc, *ppt, *cons;
-  enum locateresult loc;
   int iloc;
   int i, j;
 
@@ -14493,61 +13398,37 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
   if (ptlist->objects < 2l) {
     // Not a segment or a facet.
     return;
-  } if (ptlist->objects == 2l) {
+  }
+
+  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]);
-      }
+      // Set the default segment marker '1'.
+      setshellmark(newseg, 1);
     }
     if (pointtype(pa) == VOLVERTEX) {
-      setpointtype(pa, RIDGEVERTEX);
+      setpointtype(pa, FACETVERTEX);
     }
     if (pointtype(pb) == VOLVERTEX) {
-      setpointtype(pb, RIDGEVERTEX);
+      setpointtype(pb, FACETVERTEX);
     }
     return;
-  } if (ptlist->objects == 3l) {
-    // The facet has only one triangle.
+  } 
+
+
+  if (ptlist->objects == 3) {
     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);
-      }
+  } else {
+    // Calculate an above point of this facet.
+    if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
+      return; // The point set is degenerate.
     }
-    return;
-  }
-
-  // Calulcate an above point of this facet.
-  if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
-    return; // The point set is degenerate.
   }
 
   // Create an initial triangulation.
@@ -14562,8 +13443,36 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
   if (pointtype(pb) == VOLVERTEX) {
     setpointtype(pb, FACETVERTEX);
   }
-  if (pointtype(pc) == VOLVERTEX) {
-    setpointtype(pc, FACETVERTEX);
+  if (pointtype(pc) == VOLVERTEX) {
+    setpointtype(pc, FACETVERTEX);
+  }
+
+  // Are there area constraints?
+  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
+    int idx, fmarker;
+    REAL area;
+    idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
+    for (i = 0; i < in->numberoffacetconstraints; i++) {
+      fmarker = (int) in->facetconstraintlist[i * 2];
+      if (fmarker == idx) {
+        area = in->facetconstraintlist[i * 2 + 1];
+        setareabound(newsh, area);
+        break;
+      }
+    }
+  }
+
+  if (ptlist->objects == 3) {
+    // The triangulation only has one element.
+    for (i = 0; i < 3; i++) {
+      makeshellface(subsegs, &newseg);
+      setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
+      // Set the default segment marker '1'.
+      setshellmark(newseg, 1);
+      ssbond(newsh, newseg);
+      senextself(newsh);
+    }
+    return;
   }
 
   // Incrementally build the triangulation.
@@ -14575,9 +13484,8 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
     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
+      // Insert the vertex. Use Bowyer-Watson algo. Round the location.
+      iloc = sinsertvertex(*ppt, &searchsh, NULL, iloc, 1, 1);
       if (pointtype(*ppt) == VOLVERTEX) {
         setpointtype(*ppt, FACETVERTEX);
       }
@@ -14599,8 +13507,26 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
   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
+    iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
+    if (iloc != (enum locateresult) ONVERTEX) {
+      // Not found due to roundoff errors. Do a brute-force search.
+      subfaces->traversalinit();
+      searchsh.sh = shellfacetraverse(subfaces);
+      while (searchsh.sh != NULL) {
+        // Only search the subface in the same facet.
+        if (shellmark(searchsh) == shmark) {
+          if ((point) searchsh.sh[3] == cons[0]) {
+            searchsh.shver = 0; break;
+          } else if ((point) searchsh.sh[4] == cons[0]) {
+            searchsh.shver = 2; break;
+          } else if ((point) searchsh.sh[5] == cons[0]) {
+            searchsh.shver = 4; break;
+          }
+        }
+        searchsh.sh = shellfacetraverse(subfaces);
+	  }
+      assert(searchsh.sh != NULL);
+    }
     // Recover the segment. Some edges may be flipped.
     sscoutsegment(&searchsh, cons[1]);
     if (flipstack != NULL) {
@@ -14621,115 +13547,51 @@ void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
 // 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  //
+// If the two subfaces are identical, 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;
+  if (b->psc) {
+    // In this case, it is possible that two subfaces are identical.
+    // While they must belong to two different surfaces.
+    return;
+  }
 
-  assert(f1->sh != f2->sh); // SELF_CHECK
+  point pa, pb, pc, pd;
 
   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));
+	       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);
+	       pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
+    terminatetetgen(this, 3);
   } else {
     printf("Found two duplicated facets.\n");
     printf("  1st: [%d, %d, %d] #%d\n", 
-	   pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
+	       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));
+	       pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
+    terminatetetgen(this, 3);
   }
 
-  // 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.       //
 //                                                                           //
+// After this routine, although segments are unique, but some of them may be //
+// removed later by mergefacet().  All vertices still have type FACETVERTEX. //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::unifysegments()
@@ -14750,6 +13612,79 @@ void tetgenmesh::unifysegments()
   // Create a mapping from vertices to subfaces.
   makepoint2submap(subfaces, idx2faclist, facperverlist);
 
+  if (b->psc) {
+    face sface1;
+    face seg, seg1;
+    int fmarker, fmarker1;
+    // First only connect subfaces which belong to the same surfaces.
+    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;
+      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;
+
+        sspivot(sface, seg);
+        if (seg.sh == NULL) continue;
+        // assert(seg.sh != NULL); It may or may not be subsegloop.
+
+        // Find the adjacent subface on the same facet.
+        fmarker = in->facetmarkerlist[shellmark(sface) - 1];
+        sface1.sh = NULL;
+        k++;
+        for (; k < idx2faclist[idx + 1]; k++) {
+          sface1 = facperverlist[k];
+          // The face may be deleted if it is a duplicated face.
+          if (sface1.sh[3] == NULL) continue;
+          // Search the edge torg->tdest.
+          assert(sorg(sface1) == torg); // SELF_CHECK
+          if (sdest(sface1) != tdest) {
+            senext2self(sface1);
+            sesymself(sface1);
+          }
+          if (sdest(sface1) != tdest) continue;
+          // Found a subface sharing at the same edge.
+          fmarker1 = in->facetmarkerlist[shellmark(sface1) - 1];
+          if (fmarker1 == fmarker) {
+            // Found a pair of adjacent subfaces. Connect them.
+            // Delete a redundent segment.
+            sspivot(sface1, seg1); 
+            assert(seg1.sh != NULL); // SELF_CHECK
+            shellfacedealloc(subsegs, seg.sh);
+            shellfacedealloc(subsegs, seg1.sh);
+            ssdissolve(sface);
+            ssdissolve(sface1);
+            // Connect them.
+            sbond(sface, sface1);
+            // Set Steiner point -to- subface map.
+            if (pointtype(torg) == FREEFACETVERTEX) {
+              setpoint2sh(torg, sencode(sface));
+            }
+            if (pointtype(tdest) == FREEFACETVERTEX) {
+              setpoint2sh(tdest, sencode(sface));
+            }
+            break;
+          }
+        }
+        break;
+      }
+      subsegloop.sh = shellfacetraverse(subsegs);
+    }
+  } // if (b->psc)
+
   subsegloop.shver = 0;
   subsegs->traversalinit();
   subsegloop.sh = shellfacetraverse(subsegs);
@@ -14852,7 +13787,7 @@ void tetgenmesh::unifysegments()
               // 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) {
+              if (dot(n1, n2) > 0) {
                 unifysubfaces(&(f1->ss), &sface);
               } else {
                 unifysubfaces(&(f2->ss), &sface);
@@ -14878,7 +13813,7 @@ void tetgenmesh::unifysegments()
           // 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) {
+          if (dot(n1, n2) > 0) {
             // The two faces are codirectional as well.
             unifysubfaces(&(f1->ss), &sface);
           }
@@ -14900,17 +13835,16 @@ void tetgenmesh::unifysegments()
       }
     } // for (k = idx2faclist[idx]; ...)
 
-    if (b->verbose > 2) {
-      printf("      Found %ld segments at (%d  %d).\n", flippool->items,
-             pointmark(torg), pointmark(tdest));
+    if (b->psc) {
+      // Set Steiner point -to- segment map.
+      if (pointtype(torg) == FREESEGVERTEX) {
+        setpoint2sh(torg, sencode(subsegloop));
+      }
+      if (pointtype(tdest) == FREESEGVERTEX) {
+        setpoint2sh(tdest, sencode(subsegloop));
+      }
     }
 
-    //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;
@@ -14930,21 +13864,30 @@ void tetgenmesh::unifysegments()
       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();
 
+    // Are there length constraints?
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      int e1, e2;
+      REAL len;
+      for (k = 0; k < in->numberofsegmentconstraints; k++) {
+        e1 = (int) in->segmentconstraintlist[k * 3];
+        e2 = (int) in->segmentconstraintlist[k * 3 + 1];
+        if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
+            ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
+          len = in->segmentconstraintlist[k * 3 + 2];
+          setareabound(subsegloop, len);
+          break;
+        }
+      }
+    }
+
     subsegloop.sh = shellfacetraverse(subsegs);
   }
 
@@ -15009,11 +13952,6 @@ void tetgenmesh::mergefacets()
               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);
@@ -15033,7 +13971,6 @@ void tetgenmesh::mergefacets()
     lawsonflip(); // Recover Delaunayness.
   }
 
-
   if (b->verbose > 1) {
     printf("    %d segments are removed.\n", remsegcount);
   }
@@ -15058,19 +13995,30 @@ void tetgenmesh::identifypscedges(point *idx2verlist)
   int* idx2shlist;
   face searchsh, neighsh;
   face segloop, checkseg, newseg;
-  point checkpt, pa, pb;
+  point checkpt, pa = NULL, pb = NULL;
   int *endpts;
   int edgemarker;
   int idx, i, j;
 
+  int e1, e2;
+  REAL len;
+
   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.
+  // All identified segments have the initial marker '1'.
+  // All segments inserted here should have a marker 'k >= 0'.
+
+  if (b->psc) {
+    // First mark all segments of the mesh with a marker '-1'.
+    subsegs->traversalinit();
+    segloop.sh = shellfacetraverse(subsegs);
+    while (segloop.sh != NULL) {
+      setshellmark(segloop, -1);
+      segloop.sh = shellfacetraverse(subsegs);
+    }
+  }
 
   // Construct a map from points to subfaces.
   makepoint2submap(subfaces, idx2shlist, shperverlist);
@@ -15078,7 +14026,10 @@ void tetgenmesh::identifypscedges(point *idx2verlist)
   // Process the set of PSC edges.
   for (i = 0; i < in->numberofedges; i++) {
     endpts = &(in->edgelist[(i << 1)]);
+    edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : 0;
+
     // Find a face contains the edge.
+    newseg.sh = NULL;
     searchsh.sh = NULL;
     idx = endpts[0] - in->firstnumber;
     for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
@@ -15095,43 +14046,31 @@ void tetgenmesh::identifypscedges(point *idx2verlist)
         }
       }
     } // 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);
+        // This segment already exist.
+        newseg = checkseg;
       } 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);
+        if (b->psc) {
+          if (pointtype(pa) == FREESEGVERTEX) {
+            setpoint2sh(pa, sencode(newseg));
+          }
+          if (pointtype(pb) == FREESEGVERTEX) {
+            setpoint2sh(pb, sencode(newseg));
+          }
         }
       }
     } else {
@@ -15139,49 +14078,91 @@ void tetgenmesh::identifypscedges(point *idx2verlist)
       // 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));
+      // Check if segment [a,b] already exists.
+      // TODO: Change the brute-force search. Slow!
+      point *ppt;
+      subsegs->traversalinit();
+      segloop.sh = shellfacetraverse(subsegs);
+      while (segloop.sh != NULL) {
+        ppt = (point *) &(segloop.sh[3]);
+        if (((ppt[0] == pa) && (ppt[1] == pb)) ||
+            ((ppt[0] == pb) && (ppt[1] == pa))) {
+          // Found!
+          newseg = segloop; 
+          break;
+        }
+        segloop.sh = shellfacetraverse(subsegs);
+      }
+      if (newseg.sh == NULL) {
+        makeshellface(subsegs, &newseg);
+        setshvertices(newseg, pa, pb, NULL);
+        if (b->psc) {
+          if (pointtype(pa) == FREESEGVERTEX) {
+            setpoint2sh(pa, sencode(newseg));
+          }
+          if (pointtype(pb) == FREESEGVERTEX) {
+            setpoint2sh(pb, sencode(newseg));
+          }
+        }
+      }
+    }
+
+    setshellmark(newseg, edgemarker);
+
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      for (i = 0; i < in->numberofsegmentconstraints; i++) {
+        e1 = (int) in->segmentconstraintlist[i * 3];
+        e2 = (int) in->segmentconstraintlist[i * 3 + 1];
+        if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
+            ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
+          len = in->segmentconstraintlist[i * 3 + 2];
+          setareabound(newseg, len);
+          break;
+        }
       }
-      makeshellface(subsegs, &newseg);
-      setshvertices(newseg, pa, pb, NULL);
-      setshellmark(newseg, edgemarker);
-      //if (!b->psc) {
-        setpointtype(pa, RIDGEVERTEX);
-        setpointtype(pb, RIDGEVERTEX);
-      //}
     }
   } // i
 
+
+  delete [] shperverlist;
+  delete [] idx2shlist;
+
   if (b->psc) {
-    // Delete all segments of the mesh with a marker '0'.
+    // Removing all segments with a marker '-1'.
     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);
-          }
-        }
+      if (shellmark(segloop) == -1) {
         shellfacedealloc(subsegs, segloop.sh);
       }
       segloop.sh = shellfacetraverse(subsegs);
     }
-  }
+  
+    // Connecting subsegments at Steiner points.
+    face seg1, seg2;
+    // Re-use 'idx2shlist' and 'shperverlist'.
+    makepoint2submap(subsegs, idx2shlist, shperverlist);
 
-  delete [] shperverlist;
-  delete [] idx2shlist;
+    points->traversalinit();
+    pa = pointtraverse();
+    while (pa != NULL) {
+      if (pointtype(pa) == FREESEGVERTEX) {
+        idx = pointmark(pa) - in->firstnumber;
+        // There must be only two segments containing this vertex.
+        assert((idx2shlist[idx + 1] - idx2shlist[idx]) == 2);
+        i = idx2shlist[idx];
+        seg1 = shperverlist[i];
+        seg2 = shperverlist[i+1];
+        senextself(seg1);
+        senextself(seg2);
+        sbond(seg1, seg2);
+      }
+      pa = pointtraverse();
+    }
+
+    delete [] shperverlist;
+    delete [] idx2shlist;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -15324,16 +14305,27 @@ void tetgenmesh::meshsurface()
   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->psc && !b->nomergefacet && !b->nobisect) {
+      // 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->psc) {
+      // Mark all segment vertices to be RIDGEVERTEX.
+      face segloop;
+      point *ppt;
+      subsegs->traversalinit();
+      segloop.sh = shellfacetraverse(subsegs);
+      while (segloop.sh != NULL) {
+        ppt = (point *) &(segloop.sh[3]);
+        setpointtype(ppt[0], RIDGEVERTEX);
+        setpointtype(ppt[1], RIDGEVERTEX);
+        segloop.sh = shellfacetraverse(subsegs);
+      }
+    }
   }
 
   if (b->object == tetgenbehavior::STL) {
@@ -15359,7 +14351,7 @@ void tetgenmesh::meshsurface()
 // 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   //
+// a cut plane parallel to x-, or, y-, or z-axis.  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:           //
 //                                                                           //
@@ -15401,11 +14393,11 @@ void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
     
   leftarray = new shellface*[arraysize];
   if (leftarray == NULL) {
-    terminatetetgen(1);
+    terminatetetgen(this, 1);
   }
   rightarray = new shellface*[arraysize];
   if (rightarray == NULL) {
-    terminatetetgen(1);
+    terminatetetgen(this, 1);
   }
   leftsize = rightsize = 0;
 
@@ -15442,9 +14434,7 @@ void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
       toright = true;
     }
     // At least one is true;
-#ifdef SELF_CHECK
     assert(!(toleft == false && toright == false));
-#endif
     if (toleft) {
       leftarray[leftsize] = sface1.sh;
       leftsize++;
@@ -15574,7 +14564,7 @@ void tetgenmesh::detectinterfaces()
 
   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
+  //   parallel to x-, or, y-, or z-axis.  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);
@@ -15617,141 +14607,78 @@ void tetgenmesh::detectinterfaces()
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// markacutevertices()    Classify vertices as ACUTEVERTEXs or RIDGEVERTEXs. //
+// makesegmentendpointsmap()    Create a map from a segment to its endpoints.//
 //                                                                           //
-// 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.             //
+// The map is saved in the array 'segmentendpointslist'. The length of this  //
+// array is twice the number of segments.  Each segment is assigned a unique //
+// index (starting from 0).                                                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::markacutevertices()
+void tetgenmesh::makesegmentendpointsmap()
 {
-  face* segperverlist;
-  int* idx2seglist;
-  point pa, pb, pc;
-  REAL anglimit, ang;
-  bool acuteflag;
-  int acutecount;
-  int idx, i, j;
-
-  REAL sharpanglimit;
-  int sharpsegcount;
+  arraypool *segptlist;
+  face segloop, prevseg, nextseg;
+  point eorg, edest, *parypt;
+  int segindex = 0, idx = 0;
+  int i;
 
-  if (b->verbose) {
-    printf("  Marking acute vertices.\n");
+  if (b->verbose > 0) {
+    printf("  Creating the segment-endpoints map.\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);
+  segptlist = new arraypool(2 * sizeof(point), 10);
 
-  // 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++;
+  // 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);
+  segloop.shver = 0;
+  while (segloop.sh != NULL) {
+    senext2(segloop, prevseg);
+    spivotself(prevseg);
+    if (prevseg.sh == NULL) {
+      eorg = sorg(segloop);
+      edest = sdest(segloop);
+      setfacetindex(segloop, segindex);
+      senext(segloop, nextseg);
+      spivotself(nextseg);
+      while (nextseg.sh != NULL) {
+        setfacetindex(nextseg, segindex);
+        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);
       }
+      segptlist->newindex((void **) &parypt);
+      parypt[0] = eorg;
+      parypt[1] = edest;
+      segindex++;
     }
-    pa = pointtraverse();
+    segloop.sh = shellfacetraverse(subsegs);
   }
 
   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);
+    printf("  Found %ld segments.\n", segptlist->objects);
   }
 
-  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);
+  segmentendpointslist = new point[segptlist->objects * 2];
 
-  pc = sorg(*checksh);
-  pd = sdest(*checksh);
-  pe = sapex(*checksh);
+  totalworkmemory += (segptlist->objects * 2) * sizeof(point *);
 
-  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));
+  for (i = 0; i < segptlist->objects; i++) {
+    parypt = (point *) fastlookup(segptlist, i);
+    segmentendpointslist[idx++] = parypt[0];
+    segmentendpointslist[idx++] = parypt[1];
+  }
 
+  delete segptlist;
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // finddirection()    Find the tet on the path from one point to another.    //
@@ -15771,21 +14698,20 @@ void tetgenmesh::reportselfintersect(face *checkseg, face *checksh)
 ///////////////////////////////////////////////////////////////////////////////
 
 enum tetgenmesh::interresult 
-  tetgenmesh::finddirection(triface* searchtet, point endpt, int randflag)
+  tetgenmesh::finddirection(triface* searchtet, point endpt)
 {
   triface neightet;
   point pa, pb, pc, pd;
   enum {HMOVE, RMOVE, LMOVE} nextmove;
   REAL hori, rori, lori;
+  int t1ver;
   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);
+    decode(searchtet->tet[3], *searchtet);
     // Reset the origin to be pa.
     if ((point) searchtet->tet[4] == pa) {
       searchtet->ver = 11;
@@ -15794,7 +14720,7 @@ enum tetgenmesh::interresult
     } else if ((point) searchtet->tet[6] == pa) {
       searchtet->ver = 7;
     } else {
-      assert((point) searchtet->tet[7] == pa); // SELF_CHECK
+      assert((point) searchtet->tet[7] == pa); 
       searchtet->ver = 0;
     }
   }
@@ -15809,8 +14735,7 @@ enum tetgenmesh::interresult
   pc = apex(*searchtet);
   if (pc == endpt) {
     // pa->pc is the search edge.
-    eprevself(*searchtet);
-    esymself(*searchtet);
+    eprevesymself(*searchtet);
     return ACROSSVERT;
   }
 
@@ -15818,12 +14743,6 @@ enum tetgenmesh::interresult
   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.
@@ -15846,54 +14765,39 @@ enum tetgenmesh::interresult
     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'.
+    //   tets are viable moves. Is so, randomly choose one. 
     if (hori > 0) {
       if (rori > 0) {
         if (lori > 0) {
           // Any of the three neighbors is a viable move.
-          if (0) { // if (!randflag) {
+          s = randomnation(3); 
+          if (s == 0) {
+            nextmove = HMOVE;
+          } else if (s == 1) {
+            nextmove = RMOVE;
           } 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)
+            nextmove = LMOVE;
+          }
         } else {
           // Two tets, below horizon and below right, are viable.
-          if (0) { // if (!randflag) {
+          //s = randomnation(2); 
+          if (randomnation(2)) {
+            nextmove = HMOVE;
           } else {
-            // Randomly choose a direction.
-            s = randomnation(2); // 's' is in {0,1}.
-            if (s == 0) {
-              nextmove = HMOVE;
-            } else {
-              nextmove = RMOVE;
-            }
-          } // if (randflag)
+            nextmove = RMOVE;
+          }
         }
       } else {
         if (lori > 0) {
           // Two tets, below horizon and below left, are viable.
-          if (0) { // if (!randflag) {
+          //s = randomnation(2); 
+          if (randomnation(2)) {
+            nextmove = HMOVE;
           } else {
-            // Randomly choose a direction.
-            s = randomnation(2); // 's' is in {0,1}.
-            if (s == 0) {
-              nextmove = HMOVE;
-            } else {
-              nextmove = LMOVE;
-            }
-          } // if (randflag)
+            nextmove = LMOVE;
+          }
         } else {
           // The tet below horizon is chosen.
           nextmove = HMOVE;
@@ -15903,16 +14807,12 @@ enum tetgenmesh::interresult
       if (rori > 0) {
         if (lori > 0) {
           // Two tets, below right and below left, are viable.
-          if (0) { // if (!randflag) {
+          //s = randomnation(2); 
+          if (randomnation(2)) {
+            nextmove = RMOVE;
           } else {
-            // Randomly choose a direction.
-            s = randomnation(2); // 's' is in {0,1}.
-            if (s == 0) {
-              nextmove = RMOVE;
-            } else {
-              nextmove = LMOVE;
-            }
-          } // if (randflag)
+            nextmove = LMOVE;
+          }
         } else {
           // The tet below right is chosen.
           nextmove = RMOVE;
@@ -15930,8 +14830,7 @@ enum tetgenmesh::interresult
             }
             if (lori == 0) {
               // pa->'endpt' is COLLINEAR with pa->pc.
-              eprevself(*searchtet);
-              esymself(*searchtet); // [a,c,d]
+              eprevesymself(*searchtet); // // [a,c,d]
               return ACROSSVERT;
             }
             // pa->'endpt' crosses the edge pb->pc.
@@ -15951,8 +14850,7 @@ enum tetgenmesh::interresult
           }
           if (lori == 0) {
             // pa->'endpt' crosses the edge pc->pd.
-            eprevself(*searchtet);
-            esymself(*searchtet); // face acd
+            eprevesymself(*searchtet); // [a,c,d]
             return ACROSSEDGE;
           }
           // pa->'endpt' crosses the face bcd.
@@ -15972,7 +14870,7 @@ enum tetgenmesh::interresult
       fsymself(*searchtet);
       enextself(*searchtet);
     }
-    assert(org(*searchtet) == pa); // SELF_CHECK
+    assert(org(*searchtet) == pa); 
     pb = dest(*searchtet);
     pc = apex(*searchtet);
 
@@ -15982,25 +14880,22 @@ enum tetgenmesh::interresult
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// scoutsegment()    Look for a given segment in the tetrahedralization T.   //
+// scoutsegment()    Search an edge in the tetrahedralization.               //
 //                                                                           //
-// 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.       //
+// If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the   //
+// edge from startpt to endpt.                                               //
 //                                                                           //
-// 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').              //
+// If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
+// indicates that the edge intersects an edge or a face.  If 'refpt' is NULL,//
+// 'searchtet' returns the edge or face. If 'refpt' is not NULL, it returns  //
+// a vertex which encroaches upon this edge, and 'searchtet' returns a tet   //
+// which containing 'refpt'.                                                 // 
 //                                                                           //
 // 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'.                         //
+//   - ACROSSVERT, the edge intersects a vertex return by the origin of      //
+//                 'searchtet'.                                              //
+//   - ACROSSSEG, the edge intersects a segment returned by 'searchtet'.     //
+//   - ACROSSSUB, the edge intersects a subface returned by 'searchtet'.     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -16008,22 +14903,16 @@ 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;
+  point pd;
   enum interresult dir;
-  REAL angmax, ang;
-  long facecount;
-  int types[2], poss[4];
-  int pos, i, j;
+  int t1ver;
 
   if (b->verbose > 2) {
-    printf("      Scout seg (%d, %d).\n", pointmark(startpt), pointmark(endpt));
+    printf("      Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
   }
 
   point2tetorg(startpt, *searchtet);
-  dir = finddirection(searchtet, endpt, 0);
+  dir = finddirection(searchtet, endpt);
 
   if (dir == ACROSSVERT) {
     pd = dest(*searchtet);
@@ -16032,14 +14921,13 @@ enum tetgenmesh::interresult
       return SHAREEDGE;
     } else {
       // A point is on the path.
-      *refpt = pd;
+      // Let the origin of the searchtet be the vertex.
+      enextself(*searchtet);
+      if (refpt) *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.
@@ -16047,29 +14935,28 @@ enum tetgenmesh::interresult
 
   if (dir == ACROSSEDGE) {
     // Check whether two segments are intersecting.
-    tsspivot1(*searchtet, checkseg);
-    if (checkseg.sh != NULL) {
+    if (issubseg(*searchtet)) {
       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) {
+      if (issubface(*searchtet)) {
         return ACROSSSUB;
       }
     }
   }
 
   if (refpt == NULL) {
+    // Do not need a reference point. Return.
     return dir;
   }
 
-  if (b->verbose > 2) {
-    printf("      Scout a ref-point for it.\n");
-  }
-  facecount = across_face_count;
+  triface neightet, reftet;
+  point pa, pb, pc;
+  REAL angmax, ang;
+  int types[2], poss[4];
+  int pos = 0, i, j;
 
   pa = org(*searchtet);
   angmax = interiorangle(pa, startpt, endpt, NULL);
@@ -16091,53 +14978,10 @@ enum tetgenmesh::interresult
   // 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;
@@ -16205,9 +15049,6 @@ enum tetgenmesh::interresult
         enextself(neightet);
       }
       pd = org(neightet);
-      if (b->verbose > 2) {
-        angmax = interiorangle(pd, startpt, endpt, NULL);
-      }
       *refpt = pd;
       // break;
       return ACROSSVERT;
@@ -16222,16 +15063,13 @@ enum tetgenmesh::interresult
 
     if (dir == ACROSSEDGE) {
       // Check whether two segments are intersecting.
-      tsspivot1(*searchtet, checkseg);
-      if (checkseg.sh != NULL) {
+      if (issubseg(*searchtet)) {
         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) {
+        if (issubface(*searchtet)) {
           return ACROSSSUB;
         }
       }
@@ -16245,202 +15083,89 @@ enum tetgenmesh::interresult
     *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');
-  }
+//                                                                           //
+// getsteinerpointonsegment()    Get a Steiner point on a segment.           //
+//                                                                           //
+// Return '1' if 'refpt' lies on an adjacent segment of this segment. Other- //
+// wise, return '0'.                                                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
-  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);
-    }
-  }
+int tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
+{
+  point ei = sorg(*seg);
+  point ej = sdest(*seg);
+  int adjflag = 0, i;
 
   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;
+    REAL L, L1, t;
+  
+    if (pointtype(refpt) == FREESEGVERTEX) {
+      face parentseg;
+      sdecode(point2sh(refpt), parentseg);
+      int sidx1 = getfacetindex(parentseg);
+      point far_pi = segmentendpointslist[sidx1 * 2];
+      point far_pj = segmentendpointslist[sidx1 * 2 + 1];
+      int sidx2 = getfacetindex(*seg);
+      point far_ei = segmentendpointslist[sidx2 * 2];
+      point far_ej = segmentendpointslist[sidx2 * 2 + 1];
+      if ((far_pi == far_ei) || (far_pj == far_ei)) {
+        // Create a Steiner point at the intersection of the segment
+        //   [far_ei, far_ej] and the sphere centered at far_ei with 
+        //   radius |far_ei - refpt|.
+        L = distance(far_ei, far_ej);
+        L1 = distance(far_ei, refpt);
+        t = L1 / L;
+        for (i = 0; i < 3; i++) {
+          steinpt[i] = far_ei[i] + t * (far_ej[i] - far_ei[i]);
+        }
+        adjflag = 1;
+      } else if ((far_pi == far_ej) || (far_pj == far_ej)) {
+        L = distance(far_ei, far_ej);
+        L1 = distance(far_ej, refpt);
+        t = L1 / L;
+        for (i = 0; i < 3; i++) {
+          steinpt[i] = far_ej[i] + t * (far_ei[i] - far_ej[i]);
+        }
+        adjflag = 1;
       } else {
-        type = 1;
+        // Cut the segment by the projection point of refpt.
+        projpt2edge(refpt, ei, ej, steinpt);
       }
     } 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;
-      }
+      // Cut the segment by the projection point of refpt.
+      projpt2edge(refpt, ei, ej, steinpt);
     }
-  } else {
-    type = 0;
-  }
 
-  if (type == 1) {
+    // Make sure that steinpt is not too close to ei and ej.
     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;
+    L1 = distance(steinpt, ei);
+    t = L1 / L;
+    if ((t < 0.2) || (t > 0.8)) {
+      // Split the point at the middle.
       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]);
-        }
+        steinpt[i] = ei[i] + 0.5 * (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]);
-      }
+    for (i = 0; i < 3; i++) {
+      steinpt[i] = ei[i] + 0.5 * (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");
-  }
+  return adjflag;
 }
 
 
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // delaunizesegments()    Recover segments in a DT.                          //
@@ -16458,29 +15183,18 @@ void tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
 void tetgenmesh::delaunizesegments()
 {
   triface searchtet, spintet;
-  face searchsh, checksh;
-  face sseg, checkseg, *psseg;
+  face searchsh;
+  face sseg, *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.
+  int t1ver; 
 
-  // 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;
+  ivf.bowywat = 1; // Use Bowyer-Watson insertion.
+  ivf.assignmeshsize = b->metric;
+  ivf.sloc = (int) ONEDGE; // on 'sseg'.
+  ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
 
   // Loop until 'subsegstack' is empty.
   while (subsegstack->objects > 0l) {
@@ -16489,14 +15203,9 @@ void tetgenmesh::delaunizesegments()
     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.
     }
 
@@ -16505,8 +15214,7 @@ void tetgenmesh::delaunizesegments()
 
     if (dir == SHAREEDGE) {
       // Found this segment, insert it.
-      tsspivot1(searchtet, checkseg);  // SELF_CHECK
-      if (checkseg.sh == NULL) {
+      if (!issubseg(searchtet)) {
         // Let the segment remember an adjacent tet.
         sstbond1(sseg, searchtet);
         // Bond the segment to all tets containing it.
@@ -16516,7 +15224,7 @@ void tetgenmesh::delaunizesegments()
           fnextself(spintet);
         } while (spintet.tet != searchtet.tet);
       } else {
-        // Collision! Should not happen.
+        // Collision! Maybe a bug.
         assert(0);
       }
     } else {
@@ -16527,145 +15235,30 @@ void tetgenmesh::delaunizesegments()
         //setpointtype(newpt, FREESEGVERTEX);
         getsteinerptonsegment(&sseg, refpt, newpt);
 
-        // Start searching from the 'searchtet'.
+        // Start searching from '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) {
+        if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
           // 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++;
+          st_segref_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);
+          assert (ivf.iloc == (enum locateresult) NEARVERTEX);
+          terminatetetgen(this, 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);
+        terminatetetgen(this, 3);
       }
     }
   } // while
-
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// scoutsubface()    Look for a given subface in the tetrahedralization T.   //
+// scoutsubface()    Search subface in the tetrahedralization.               //
 //                                                                           //
 // '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.              //
@@ -16681,27 +15274,25 @@ enum tetgenmesh::interresult
   tetgenmesh::scoutsubface(face* searchsh, triface* searchtet)
 {
   triface spintet;
-  face checksh;
   point pa, pb, pc;
   enum interresult dir;
+  int t1ver; 
 
   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);
+  dir = finddirection(searchtet, pb);
   if (dir == ACROSSVERT) {
     // Check validity of a PLC.
     if (dest(*searchtet) != pb) {
-      // A vertex lies on the search edge. Return it.
+      // A vertex lies on the search edge. 
       enextself(*searchtet);
+      // It is possible a PLC self-intersection problem.
+      terminatetetgen(this, 3);
       return TOUCHEDGE;
     }
     // The edge exists. Check if the face exists.
@@ -16711,8 +15302,7 @@ enum tetgenmesh::interresult
     while (1) {
       if (apex(spintet) == pc) {
         // Found a face matching to 'searchsh'!
-        tspivot(spintet, checksh);
-        if (checksh.sh == NULL) {
+        if (!issubface(spintet)) {
           // Insert 'searchsh'.
           tsbond(spintet, *searchsh);
           fsymself(spintet);
@@ -16722,11 +15312,13 @@ enum tetgenmesh::interresult
           return SHAREFACE;
         } else {
           // Another subface is already inserted.
+          face checksh;
+          tspivot(spintet, checksh);
           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);
+          terminatetetgen(this, 5);
           // unifysubfaces(&checksh, searchsh);
           *searchtet = spintet;
           return COLLISIONFACE;
@@ -16738,47 +15330,39 @@ enum tetgenmesh::interresult
   }
 
   // dir is either ACROSSEDGE or ACROSSFACE.
-  return dir; //ACROSSTET;
+  return dir; 
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// formmissingregion()    Form the missing region of a missing subface.      //
+// formregion()    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.                //
+// a connected region formed by a set of missing subfaces of a facet.        //
+// Comment: There should be no segment inside R.                             //
 //                                                                           //
-// '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.                     //
+// 'missingshs' returns the list of subfaces in R. All subfaces in this list //
+// are oriented as the 'missh'.  'missingshbds' returns the list of boundary //
+// edges (tetrahedral handles) of R.  'missingshverts' returns all vertices  //
+// of R. They are all pmarktested.                                           //
 //                                                                           //
+// Except the first one (which is 'missh') in 'missingshs', each subface in  //
+// this list represents an internal edge of R, i.e., it is missing in the    //
+// tetrahedralization. Since R may contain interior vertices, not all miss-  //
+// ing edges can be found by this way.                                       //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs,  
-                                   arraypool* missingshbds, 
-                                   arraypool* missingshverts, 
-                                   arraypool* adjtets)
+void tetgenmesh::formregion(face* missh, arraypool* missingshs,  
+                            arraypool* missingshbds, arraypool* missingshverts)
 {
-  triface searchtet, *parytet;
+  triface searchtet, spintet;
   face neighsh, *parysh;
+  face neighseg, fakeseg;
   point pa, pb, *parypt;
   enum interresult dir;
+  int t1ver;
   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;
@@ -16789,43 +15373,22 @@ void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs,
     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);
+      dir = finddirection(&searchtet, pb);
       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)));
-          }
+          if (sorg(neighsh) != pb) sesymself(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);
+        if (dest(searchtet) != pb) {
+          // This might be a self-intersection problem.
+          terminatetetgen(this, 3); 
         }
       }
       // Collect the vertices of R.
@@ -16838,57 +15401,86 @@ void tetgenmesh::formmissingregion(face* missh, arraypool* missingshs,
     } // j
   } // i
 
-  if (b->verbose > 2) {
-    printf("      Region has: %ld subfaces, %ld vertices\n", 
-           missingshs->objects, missingshverts->objects);
-  }
+  // Get the boundary edges of R.
+  for (i = 0; i < missingshs->objects; i++) {
+    missh = (face *) fastlookup(missingshs, i);
+    for (j = 0; j < 3; j++) {
+      spivot(*missh, neighsh);
+      if ((neighsh.sh == NULL) || !smarktested(neighsh)) {
+        // A boundary edge of R.
+        // Let the segment point to the adjacent tet.
+        point2tetorg(sorg(*missh), searchtet);
+        finddirection(&searchtet, sdest(*missh));
+        missingshbds->newindex((void **) &parysh);
+        *parysh = *missh;
+        // Check if this edge is a segment.
+        sspivot(*missh, neighseg); 
+        if (neighseg.sh == NULL) {
+          // Temporarily create a segment at this edge.
+          makeshellface(subsegs, &fakeseg);
+          setsorg(fakeseg, sorg(*missh));
+          setsdest(fakeseg, sdest(*missh));
+          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;
+          }
+          neighseg = fakeseg;
+        }
+        // Let the segment and the boundary edge point to each other.
+        ssbond(*missh, neighseg);
+        sstbond1(neighseg, searchtet);
+      }
+      senextself(*missh);
+    } // j
+  } // i
 
-  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);
+    parysh = (face *) fastlookup(missingshs, i);
+    sunmarktest(*parysh);
   }
-
-  // Comment: All vertices in R are pmarktested.
 }
 
-
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // scoutcrossedge()    Search an edge that crosses the missing region.       //
 //                                                                           //
+// Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
+// over, the edge is oriented such that its origin lies below R.  Return 0   //
+// if no such edge is found.                                                 //
+//                                                                           //
 // Assumption: All vertices of the missing region are marktested.            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets, 
+int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds, 
                                arraypool* missingshs)
 {
-  triface *searchtet, spintet;
+  triface searchtet, spintet;
   face *parysh;
-  face checkseg;
+  face neighseg;
   point pa, pb, pc, pd, pe;
   enum interresult dir;
   REAL ori;
   int types[2], poss[4];
   int searchflag, interflag;
+  int t1ver;
   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);
+  for (j = 0; j < missingshbds->objects && !searchflag; j++) {
+    parysh = (face *) fastlookup(missingshbds, j);
+    sspivot(*parysh, neighseg);
+    sstpivot1(neighseg, searchtet);
     interflag = 0;
     // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
-    spintet = *searchtet;
+    spintet = searchtet;
     while (1) {
       pd = apex(spintet);
       pe = oppo(spintet);
@@ -16902,7 +15494,7 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets,
             pa = sorg(*parysh);
             pb = sdest(*parysh);
             pc = sapex(*parysh);
-            interflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
+            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.
@@ -16910,14 +15502,13 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets,
                 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
                   //pos = poss[0];
                   // Go to the crossing edge [d,e,#,#].
-                  eprev(spintet, crosstet);
-                  esymself(crosstet);
-                  enextself(crosstet); // [d,e,#,#].
+                  edestoppo(spintet, crosstet); // // [d,e,#,#].
                   // Check if it is a segment.
-                  tsspivot1(crosstet, checkseg);
-                  if (checkseg.sh != NULL) {
-                    reportselfintersect(&checkseg, parysh);
-                    terminatetetgen(3);
+                  if (issubseg(crosstet)) {
+                    //face checkseg;
+                    //tsspivot1(crosstet, checkseg);
+                    //reportselfintersect(&checkseg, parysh);
+                    terminatetetgen(this, 3);
                   }
                   // Adjust the edge such that d lies below [a,b,c].
                   ori = orient3d(pa, pb, pc, pd);
@@ -16925,21 +15516,7 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets,
                   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;
@@ -16951,11 +15528,10 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets,
       if (interflag > 0) break;
       // Go to the next tetrahedron.
       fnextself(spintet);
-      if (spintet.tet == searchtet->tet) break; 
+      if (spintet.tet == searchtet.tet) break; 
     } // while (1)
   } // j
 
-  adjtets->restart();
   return searchflag;
 }
 
@@ -16969,23 +15545,6 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets,
 // #] 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  //
@@ -16994,13 +15553,6 @@ int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* adjtets,
 // 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.                    //
 //                                                                           //
@@ -17011,27 +15563,22 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
                             arraypool* botfaces, arraypool* toppoints, 
                             arraypool* botpoints)
 {
-  arraypool *crossedges, *testededges;
+  arraypool *crossedges;
   triface spintet, neightet, *parytet;
-  face checksh, *parysh = NULL;
-  face checkseg; // *paryseg;
+  face *parysh = NULL;
   point pa, pd, pe, *parypt;
   enum interresult dir; 
-  //REAL ori;
-  //REAL elen[3];
   bool testflag, invalidflag;
   int types[2], poss[4];
+  int t1ver;
   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"); 
+    printf("      Form the cavity of a missing region.\n"); 
   }
-  missingsubfacecount += missingshs->objects;
   // Mark this edge to avoid testing it later.
   markedge(*searchtet);
   crossedges->newindex((void **) &parytet);
@@ -17040,24 +15587,20 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
   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.
+  //   form [d,e,#,#], where [d,e] is a crossing 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);
@@ -17068,11 +15611,6 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
     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;
@@ -17088,10 +15626,10 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
       // 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.
+        if (!pmarktested(pa)) {
+	      // There exists a crossing edge, either [e,a] or [a,d]. First check
+          //   if the crossing edge has already be added, i.e., check if a
+          //   tetrahedron at this edge is marked.
           testflag = true;
           for (j = 0; j < 2 && testflag; j++) {
             if (j == 0) {
@@ -17117,12 +15655,8 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
             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)) {
+              if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
+                                pe, pa, NULL, 1, types, poss)) {
                 // Found intersection. 'a' lies below R.
                 enext(spintet, neightet);
                 dir = (enum interresult) types[0];
@@ -17134,9 +15668,8 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
                 }
                 break;
               }
-              // Test if this face intersects [a,d].
-              if (tri_edge_test(plane_pa, plane_pb, plane_pc, pa, pd, 
-                                NULL, 1, types, poss)) {
+              if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
+                                pa, pd, NULL, 1, types, poss)) {
                 // Found intersection. 'a' lies above R.
                 eprev(spintet, neightet);
                 dir = (enum interresult) types[0];
@@ -17150,47 +15683,28 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
               }
             } // k
             if (k < missingshs->objects) {
-              // Found a pair of triangle - edge interseciton.
+              // Found a pair of triangle - edge intersection.
               if (invalidflag) {
-                if (b->verbose > 2) {
-                  printf("      A non-valid subface - edge intersection\n");
+                if (!b->quiet) {
+                  printf("Warning:  A non-valid facet - 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(sorg(*parysh)), pointmark(sdest(*parysh)), 
+                         pointmark(sapex(*parysh)), 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)
+                terminatetetgen(this, 3);
+              }
               // 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) {
+              if (issubseg(neightet)) {
                 // 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)));
+                //face checkseg;
+                //tsspivot1(neightet, checkseg);
+                //reportselfintersect(&checkseg, parysh);
+                terminatetetgen(this, 3);
               }
               // Mark this edge to avoid testing it again.
               markedge(neightet);
@@ -17198,32 +15712,29 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
               *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)) {
+                if (tri_edge_test(sorg(*parysh),sdest(*parysh),sapex(*parysh),
+                                  pd, pe, NULL, 1, types, poss)) {
                   break;
                 }
               } // k
-              assert(k < missingshs->objects);
+              if (k == missingshs->objects) {
+                // Not found such an edge. 
+                // Arbitrarily choose an edge (except the first) to split.
+                k = randomnation(missingshs->objects - 1);
+                parysh = (face *) fastlookup(missingshs, k + 1);
+              }
               recentsh = *parysh;
               recenttet = spintet; // For point location.
               break; // the while (1) loop
             } // if (k == missingshs->objects)
           } // if (testflag)
-	} // if (!pmarktested(pa) || b->psc)
-      }
+	    } // if (!pmarktested(pa) || b->psc)
+      } // if (pa != dummypoint)
       // Go to the next crossing tet.
       fnextself(spintet);
       if (spintet.tet == searchtet->tet) break;
@@ -17238,7 +15749,6 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
     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++) {
@@ -17248,17 +15758,6 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
   }
   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.
@@ -17278,44 +15777,21 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
     crosstets->restart();
     botpoints->restart();
     toppoints->restart();
+
+    // Randomly split an interior edge of R.
+    i = randomnation(missingshs->objects - 1);
+    recentsh = * (face *) fastlookup(missingshs, i);
     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.
+  //   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. 
@@ -17325,16 +15801,14 @@ bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
   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]
+    eorgoppo(*searchtet, spintet);
     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]
+    }
+    edestoppo(*searchtet, spintet);
     fsym(spintet, neightet); // neightet is [b,a,d,#]
     if (!infected(neightet)) {
       // A bottom face.
@@ -17399,19 +15873,17 @@ 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;
+  triface searchtet, neightet, *parytet, *parytet1;
+  face tmpsh, *parysh;
   point pa, pb, pc, pd, pt[3], *parypt;
   enum interresult dir;
   insertvertexflags ivf;
-  REAL ori; //, ang, len;
+  REAL ori;
   long baknum, bakhullsize;
   int bakchecksubsegflag, bakchecksubfaceflag;
-  //int iloc;
+  int t1ver; 
   int i, j;
 
-
   if (b->verbose > 2) {
     printf("      Delaunizing cavity: %ld points, %ld faces.\n", 
            cavpoints->objects, cavfaces->objects);
@@ -17425,31 +15897,38 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
   checksubsegflag = 0;
   checksubfaceflag = 0;
   b->verbose--;  // Suppress informations for creating Delaunay tetra.
-  b->plc = 0; // Do not do unifypoint();
+  b->plc = 0; // Do not check near vertices.
+
+  ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
 
   // Get four non-coplanar points (no dummypoint).
-  parytet = (triface *) fastlookup(cavfaces, 0);
-  pa = org(*parytet);
-  pb = dest(*parytet);
-  pc = apex(*parytet);
+  pa = pb = pc = NULL;
+  for (i = 0; i < cavfaces->objects; i++) {
+    parytet = (triface *) fastlookup(cavfaces, i);
+    parytet->ver = epivot[parytet->ver];
+    if (apex(*parytet) != dummypoint) {
+      pa = org(*parytet);
+      pb = dest(*parytet);
+      pc = apex(*parytet);
+      break;
+    }
+  }
   pd = NULL;
-  for (i = 1; i < cavfaces->objects; i++) {
+  for (; 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;
+        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;
@@ -17462,15 +15941,13 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
   // 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);
+    insertpoint(pt[0], &searchtet, NULL, NULL, &ivf);
   }
 
   if (b->verbose > 2) {
-    printf("      Identfying %ld boundary faces of the cavity.\n", 
+    printf("      Identifying %ld boundary faces of the cavity.\n", 
            cavfaces->objects);
   }
 
@@ -17481,10 +15958,7 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
       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]
+      parytet->ver = epivot[parytet->ver];
       pt[0] = org(*parytet);
       pt[1] = dest(*parytet);
       pt[2] = apex(*parytet);
@@ -17495,38 +15969,21 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
       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);
-        }
+        // Inserted! 'tmpsh' must face toward the inside of the cavity.
+        // 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;
+      } 
+      else {
+        // This boundary face is missing.
         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) {
@@ -17535,7 +15992,7 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
                misfaces->objects);
       }
 
-      // Removing all tempoaray subfaces.
+      // Removing all temporary subfaces.
       for (i = 0; i < cavshells->objects; i++) {
         parysh = (face *) fastlookup(cavshells, i);
         stpivot(*parysh, neightet);
@@ -17566,11 +16023,7 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
           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));
-            }
+            insertpoint(pd, &searchtet, NULL, NULL, &ivf);
             pinfect(pd);
             cavpoints->newindex((void **) &parypt);
             *parypt = pd;
@@ -17580,15 +16033,9 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
             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))
@@ -17614,8 +16061,8 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
   *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);
+    for (j = 0; j < 4; j++) {
+      decode(searchtet.tet[j], neightet);
       if (!marktested(neightet)) {
         marktest(neightet);
         newtets->newindex((void **) &parytet);
@@ -17627,9 +16074,6 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
   cavpoints->restart();
   cavfaces->restart();
 
-  if (cavshells->objects > maxcavsize) {
-    maxcavsize = cavshells->objects;
-  }
   if (crosstets->objects > baknum) {
     // The cavity has been enlarged.
     cavityexpcount++;
@@ -17657,112 +16101,131 @@ void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
 ///////////////////////////////////////////////////////////////////////////////
 
 bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
-                            arraypool* midfaces, arraypool* missingshs)
+                            arraypool* midfaces, arraypool* missingshs,
+                            arraypool* topnewtets, arraypool* botnewtets,
+                            triface* crossedge)
 {
   arraypool *cavshells;
-  triface *parytet, bdrytet, toptet, bottet, midface;
-  triface neightet, spintet;
-  face checksh, *parysh;
+  triface bdrytet, neightet, *parytet;
+  triface searchtet, spintet;
+  face *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;
+  point pa, pb, pc;
+  bool mflag;
+  int t1ver;
+  int i, j;
 
   // 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);
+  for (j = 0; j < 2; j++) {
+    cavshells = (j == 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.
+        // Get the boundary tet outside the cavity (saved in sh[0]).
         decode(parysh->sh[0], bdrytet);
         pa = org(bdrytet);
         pb = dest(bdrytet);
         pc = apex(bdrytet);
-        // Get the adjacent new tet.
+        // Get the adjacent new tet inside the cavity.
         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.
-	// }
+        // Mark neightet as an interior tet of this cavity.
+        infect(neightet);
+        // Connect the two tets (the old connections are replaced).
+        bond(bdrytet, neightet); 
         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);
+        setpoint2tet(pa, (tetrahedron) neightet.tet);
+        setpoint2tet(pb, (tetrahedron) neightet.tet);
+        setpoint2tet(pc, (tetrahedron) neightet.tet);
       } // i
     } // if (cavshells != NULL)
-  } // k
-
-  mflag = true;  // Initialize it.
+  } // j
 
-  if (midfaces != NULL) {
+  if (crossedge != NULL) {
+    // Glue top and bottom tets at their common facet.
+    triface toptet, bottet, spintet, *midface;
+    point pd, pe;
+    REAL ori;
+    int types[2], poss[4];
+    int interflag;
+    int bflag;
+
+    mflag = false;
+    pd = org(*crossedge);
+    pe = dest(*crossedge);
+
+    // Search the first (middle) face in R. 
+    // Since R may be non-convex, we must make sure that the face is in the
+    //   interior of R.  We search a face in 'topnewtets' whose three vertices
+    //   are on R and it intersects 'crossedge' in its interior. Then search
+    //   a matching face in 'botnewtets'.
+    for (i = 0; i < topnewtets->objects && !mflag; i++) {
+      searchtet = * (triface *) fastlookup(topnewtets, i);
+      for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
+        pa = org(searchtet);
+        if (pmarktested(pa)) {
+          pb = dest(searchtet);
+          if (pmarktested(pb)) {
+            pc = apex(searchtet);
+            if (pmarktested(pc)) {
+              // Check if this face intersects [d,e].
+              interflag = tri_edge_test(pa,pb,pc,pd,pe,NULL,1,types,poss);
+              if (interflag == 2) {
+                // They intersect at a single point. Found.
+                toptet = searchtet;
+                // The face lies in the interior of R.
+                // Get the tet (in topnewtets) which lies above R.
+                ori = orient3d(pa, pb, pc, pd);
+                assert(ori != 0);
+                if (ori < 0) {
+                  fsymself(toptet);
+                  pa = org(toptet);
+                  pb = dest(toptet);
+                }
+                // Search the face [b,a,c] in 'botnewtets'.
+                for (j = 0; j < botnewtets->objects; j++) {
+                  neightet = * (triface *) fastlookup(botnewtets, j);                  
+                  // Is neightet contains 'b'.
+                  if ((point) neightet.tet[4] == pb) {
+                    neightet.ver = 11;
+                  } else if ((point) neightet.tet[5] == pb) {
+                    neightet.ver = 3;
+                  } else if ((point) neightet.tet[6] == pb) {
+                    neightet.ver = 7;
+                  } else if ((point) neightet.tet[7] == pb) {
+                    neightet.ver = 0;
+                  } else {
+                    continue;
+                  }
+                  // Is the 'neightet' contains edge [b,a].
+                  if (dest(neightet) == pa) {
+                    // 'neightet' is just the edge.
+                  } else if (apex(neightet) == pa) {
+                    eprevesymself(neightet);
+                  } else if (oppo(neightet) == pa) {
+                    esymself(neightet);
+                    enextself(neightet);
+                  } else {
+                    continue;
+                  }
+                  // Is 'neightet' the face [b,a,c]. 
+                  if (apex(neightet) == pc) {
+                    bottet = neightet;
+                    mflag = true;
+                    break;
+                  }
+                } // j
+              } // if (interflag == 2)
+            } // pc
+          } // pb
+        } // pa
+      } // toptet.ver
+    } // i
 
-    // 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.
+      // Found a pair of matched faces in 'toptet' and 'bottet'.
       bond(toptet, bottet);
       // Both are interior tets.
       infect(toptet);
@@ -17771,20 +16234,23 @@ bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
       markface(toptet);
       midfaces->newindex((void **) &parytet);
       *parytet = toptet;
+    } else {
+      // No pair of 'toptet' and 'bottet'.
+      toptet.tet = NULL;
+      // Randomly split an interior edge of R.
+      i = randomnation(missingshs->objects - 1);
+      recentsh = * (face *) fastlookup(missingshs, i);
     }
 
-    // Match pairs of subfaces (middle faces), connect top and bottom tets.
+    // Find other 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);
+      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;
+      assert(marktested(*midface)); // SELF_CHECK
+      // Check the neighbors at the edges of this face. 
+      for (j = 0; j < 3 && mflag; j++) {
+        toptet = *midface;
         bflag = false;
         while (1) {
           // Go to the next face in the same tet.
@@ -17794,6 +16260,7 @@ bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
             break; // Find a subface.
           }
           if (pc == dummypoint) {
+            assert(0); // Check this case.
             break; // Find a subface.
           }
           // Go to the adjacent tet.
@@ -17807,16 +16274,19 @@ bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
         if (!bflag) {
           // assert(marktested(toptet)); // SELF_CHECK
           if (!facemarked(toptet)) {
-            fsym(midface, bottet);
+            fsym(*midface, bottet);
+            spintet = bottet;
             while (1) {
               esymself(bottet);
-              pf = apex(bottet);
-              if (pf == pc) break; // Face matched.
-              if (pmarktested(pf)) {
-                mflag = false; break; // Not matched
-              }
+              pd = apex(bottet);
+              if (pd == pc) break; // Face matched.
               fsymself(bottet);
-            }
+              if (bottet.tet == spintet.tet) {
+                // Not found a matched bottom face.
+                mflag = false;
+                break;
+              }
+            } // while (1)
             if (mflag) {
               if (marktested(bottet)) {
                 // Connect two tets together.
@@ -17828,79 +16298,185 @@ bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
                 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'.
               }
-            }
+            } else { // mflag == false
+              // Adjust 'toptet' and 'bottet' to be the crossing edges.
+              fsym(*midface, bottet);
+              spintet = bottet;
+              while (1) {
+                esymself(bottet);
+                pd = apex(bottet);
+                if (pmarktested(pd)) {
+                  // assert(pd != pc);
+                  // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
+                  // Adjust 'toptet' and 'bottet' to be the crossing edges.
+                  // Test orient3d(b,c,#,d).
+                  ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
+                  if (ori < 0) {
+                    // Edges [a,d] and [b,c] cross each other.
+                    enextself(toptet); // [b,c]
+                    enextself(bottet); // [a,d]
+                  } else if (ori > 0) {
+                    // Edges [a,c] and [b,d] cross each other. 
+                    eprevself(toptet); // [c,a]
+                    eprevself(bottet); // [d,b]
+                  } else {
+                    // b,c,#,and d are coplanar!.
+                    assert(0);
+                  }
+                  break; // Not matched
+                }
+                fsymself(bottet);
+                assert (bottet.tet != spintet.tet);
+              }
+            } // if (!mflag)
           } // if (!facemarked(toptet))
-        }
+        } // if (!bflag)
+        enextself(*midface);
       } // j
     } // i
 
-  } // if (midfaces != NULL)
-
-  if (mflag) {
-    if (midfaces != NULL) {
+    if (mflag) {
       if (b->verbose > 2) {
         printf("      Found %ld middle subfaces.\n", midfaces->objects);
       }
-      if (midfaces->objects > maxregionsize) {
-        maxregionsize = midfaces->objects;
-      }
-      // Unmark middle faces.
+      face oldsh, newsh, casout, casin, neighsh;
+
+      oldsh = * (face *) fastlookup(missingshs, 0);
+
+      // Create new subfaces to fill the region R.
       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;
+        midface = (triface *) fastlookup(midfaces, i);
+        unmarkface(*midface);
+        makeshellface(subfaces, &newsh);
+        setsorg(newsh, org(*midface));
+        setsdest(newsh, dest(*midface));
+        setsapex(newsh, apex(*midface));
+        // 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.
+        tsbond(*midface, newsh);
+        fsym(*midface, neightet);
+        sesymself(newsh);
+        tsbond(neightet, newsh);
       }
-    }
 
-    if (i < missingshs->objects) { 
-      // Such subface exist.
-      recentsh = *parysh;
+      // Connect new subfaces together and to the bdry of R.
+      // Delete faked segments.
+      for (i = 0; i < midfaces->objects; i++) {
+        // Get a matched middle face [a, b, c]
+        midface = (triface *) fastlookup(midfaces, i);
+        for (j = 0; j < 3; j++) {
+          tspivot(*midface, newsh);
+          spivot(newsh, casout);
+          if (casout.sh == NULL) {
+            // Search its neighbor.
+            fnext(*midface, searchtet);
+            while (1) {
+              // (1) First check if this side is a bdry edge of R.
+              tsspivot1(searchtet, checkseg);
+              if (checkseg.sh != NULL) {
+                // It's a bdry edge of R.
+                assert(!infected(searchtet)); // It must not be a cavity tet.
+                // Get the old subface.
+                checkseg.shver = 0;
+                spivot(checkseg, oldsh);
+                if (sinfected(checkseg)) {
+                  // It's a faked segment. Delete it.
+                  spintet = searchtet;
+                  while (1) {
+                    tssdissolve1(spintet);
+                    fnextself(spintet);
+                    if (spintet.tet == searchtet.tet) break;
+                  }
+                  shellfacedealloc(subsegs, checkseg.sh);
+                  ssdissolve(oldsh);
+                  checkseg.sh = NULL;
+                }
+                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);
+                }
+                break;
+              } // if (checkseg.sh != NULL)
+              // (2) Second check if this side is an interior edge of R.
+              tspivot(searchtet, neighsh);
+              if (neighsh.sh != NULL) {
+                // Found an adjacent subface of newsh (an interior edge).
+                sbond(newsh, neighsh);
+                break;
+              }
+              fnextself(searchtet);
+              assert(searchtet.tet != midface->tet);
+            } // while (1)
+          } // if (casout.sh == NULL)
+          enextself(*midface);
+        } // j
+      } // i
+
+      // Delete old subfaces.
+      for (i = 0; i < missingshs->objects; i++) {
+        parysh = (face *) fastlookup(missingshs, i);
+        shellfacedealloc(subfaces, parysh->sh);
+      }
     } else {
-      assert(0); // Debug this case.
+      if (toptet.tet != NULL) {
+        // Faces at top and bottom are not matched. 
+        // Choose a Steiner point in R.
+        // Split one of the crossing edges.
+        pa = org(toptet);
+        pb = dest(toptet);
+        pc = org(bottet);
+        pd = dest(bottet);
+        // Search an edge in R which is either [a,b] or [c,d].
+        // Reminder:  Subfaces in this list 'missingshs', except the first
+        //   one, represents an interior edge of R. 
+        for (i = 1; i < missingshs->objects; i++) {
+          parysh = (face *) fastlookup(missingshs, i);
+          if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
+              ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
+          if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
+              ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
+        }
+        if (i < missingshs->objects) {
+          // Found. Return it.
+          recentsh = *parysh;
+        } else {
+          assert(0);
+        }
+      }
     }
 
-
-    // Set a tet for searching the new point.
-    recenttet = firsttopface;
-  }
+    midfaces->restart();
+  } else {
+    mflag = true;
+  } 
 
   // Delete the temp subfaces.
-  for (k = 0; k < 2; k++) {
-    cavshells = (k == 0 ? topshells : botshells);
+  for (j = 0; j < 2; j++) {
+    cavshells = (j == 0 ? topshells : botshells);
     if (cavshells != NULL) {
       for (i = 0; i < cavshells->objects; i++) {
         parysh = (face *) fastlookup(cavshells, i);
@@ -17913,9 +16489,6 @@ bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
   if (botshells != NULL) {
     botshells->restart();
   }
-  if (midfaces != NULL) {
-    midfaces->restart();
-  }
 
   return mflag;
 }
@@ -17930,10 +16503,12 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
                              arraypool *botnewtets)
 {
   arraypool *newtets;
+  shellface *sptr, *ssptr;
   triface *parytet, *pnewtet, newtet, neightet, spintet;
   face checksh, *parysh;
   face checkseg, *paryseg;
-  int i, j, k;
+  int t1ver;
+  int i, j;
 
   if (b->verbose > 2) {
     printf("      Carve cavity: %ld old tets.\n", crosstets->objects);
@@ -17949,38 +16524,44 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
   // 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;
+    if ((sptr = (shellface*) parytet->tet[9]) != NULL) {
+      for (j = 0; j < 4; j++) {
+        if (sptr[j]) {
+          sdecode(sptr[j], checksh);
+          if (!sinfected(checksh)) {
+            sinfect(checksh);
+            cavetetshlist->newindex((void **) &parysh);
+            *parysh = checksh;
+          }
         }
-      }
+      } // j
     }
-    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;
+    if ((ssptr = (shellface*) parytet->tet[8]) != NULL) {
+      for (j = 0; j < 6; j++) {
+        if (ssptr[j]) {
+          sdecode(ssptr[j], checkseg);
+          // Skip a deleted segment (was a faked segment)
+          if (checkseg.sh[3] != NULL) {
+            if (!sinfected(checkseg)) {
+              sinfect(checkseg);
+              cavetetseglist->newindex((void **) &paryseg);
+              *paryseg = checkseg;
+            }
+          }
         }
-      }
+      } // j
     }
   } // i
+
   // Uninfect collected subfaces.
   for (i = 0; i < cavetetshlist->objects; i++) {
-    checksh = * (face *) fastlookup(cavetetshlist, i);
-    suninfect(checksh);
+    parysh = (face *) fastlookup(cavetetshlist, i);
+    suninfect(*parysh);
   }
   // Uninfect collected segments.
   for (i = 0; i < cavetetseglist->objects; i++) {
-    checkseg = * (face *) fastlookup(cavetetseglist, i);
-    suninfect(checkseg);
+    paryseg = (face *) fastlookup(cavetetseglist, i);
+    suninfect(*paryseg);
   }
 
   // Connect subfaces to new tets.
@@ -17996,11 +16577,6 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
       // 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;
@@ -18014,10 +16590,7 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
       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);
@@ -18031,10 +16604,6 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
       }
       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;
@@ -18052,10 +16621,7 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
       }
     }
   } // i
-  if (b->verbose > 2) {
-    printf("      %ld (%ld) cavity (interior) segments.\n", 
-           cavetetseglist->objects, caveencseglist->objects);
-  }
+
 
   cavetetshlist->restart();
   cavetetseglist->restart();
@@ -18063,6 +16629,9 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
   // Delete the old tets in cavity.
   for (i = 0; i < crosstets->objects; i++) {
     parytet = (triface *) fastlookup(crosstets, i);
+    if (ishulltet(*parytet)) {
+      hullsize--;
+    }
     tetrahedrondealloc(parytet->tet);
   }
 
@@ -18070,8 +16639,8 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
 
   // 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);
+  for (j = 0; j < 2; j++) {
+    newtets = (j == 0 ? topnewtets : botnewtets);
     if (newtets != NULL) {
       for (i = 0; i < newtets->objects; i++) {
         parytet = (triface *) fastlookup(newtets, i);
@@ -18081,20 +16650,17 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
         }
       } // i
     }
-  } // k
+  } // j
 
   // 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
+          //assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
           infect(neightet);
           crosstets->newindex((void **) &pnewtet);
           *pnewtet = neightet;
@@ -18103,9 +16669,12 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
     } // j
   } // i
 
+  parytet = (triface *) fastlookup(crosstets, 0);
+  recenttet = *parytet; // Remember a live handle.
+
   // Delete outer new tets.
-  for (k = 0; k < 2; k++) {
-    newtets = (k == 0 ? topnewtets : botnewtets);
+  for (j = 0; j < 2; j++) {
+    newtets = (j == 0 ? topnewtets : botnewtets);
     if (newtets != NULL) {
       for (i = 0; i < newtets->objects; i++) {
         parytet = (triface *) fastlookup(newtets, i);
@@ -18113,6 +16682,9 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
           // This is an interior tet.
           uninfect(*parytet);
           unmarktest(*parytet);
+          if (ishulltet(*parytet)) {
+            hullsize++;
+          }
         } else {
           // An outer tet. Delete it.
           tetrahedrondealloc(parytet->tet);
@@ -18135,21 +16707,19 @@ void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
-                               arraypool *botnewtets)
+                               arraypool *botnewtets, arraypool *missingshbds)
 {
-  triface *parytet, neightet;
-  face checksh;
+  triface *parytet, neightet, spintet;
+  face *parysh;
   face checkseg;
   point *ppt;
+  int t1ver;
   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);
@@ -18172,6 +16742,31 @@ void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
     uninfect(*parytet);
   }
 
+  // Remember a live handle.
+  recenttet = * (triface *) fastlookup(crosstets, 0);
+
+  // Delete faked segments.
+  for (i = 0; i < missingshbds->objects; i++) {
+    parysh = (face *) fastlookup(missingshbds, i);
+    sspivot(*parysh, checkseg);
+    assert(checkseg.sh != NULL);
+    if (checkseg.sh[3] != NULL) {
+      if (sinfected(checkseg)) {
+            // It's a faked segment. Delete it.
+        sstpivot1(checkseg, neightet);
+        spintet = neightet;
+        while (1) {
+          tssdissolve1(spintet);
+          fnextself(spintet);
+          if (spintet.tet == neightet.tet) break;
+        }
+        shellfacedealloc(subsegs, checkseg.sh);
+        ssdissolve(*parysh);
+        //checkseg.sh = NULL;
+      }
+    }
+  } // i
+
   // Delete new tets.
   for (i = 0; i < topnewtets->objects; i++) {
     parytet = (triface *) fastlookup(topnewtets, i);
@@ -18201,7 +16796,8 @@ void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::flipcertify(triface *chkface, badface **pqueue)
+void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
+                             point plane_pb, point plane_pc)
 {
   badface *parybf, *prevbf, *nextbf;
   triface neightet;
@@ -18278,7 +16874,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue)
   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]);      
+      w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);      
       if (w[i] < 0) w[i] = -w[i];
       assert(w[i] != 0);
     } else {
@@ -18294,12 +16890,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue)
   //     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]);
-  }
+  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]);
@@ -18332,7 +16923,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue)
       // 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.
+      //if (!b->flipinsert_random) { // Default use a priority queue.
         // Insert the item into priority queue.
         while (nextbf != NULL) {
           if (nextbf->key < parybf->key) {
@@ -18342,7 +16933,7 @@ void tetgenmesh::flipcertify(triface *chkface, badface **pqueue)
             break;
           }
         }
-      } // if (!b->flipinsert_random) // -L1
+      //} // if (!b->flipinsert_random)
       // Insert the new item between prev and next items.
       if (prevbf == NULL) {
         *pqueue = parybf;
@@ -18374,19 +16965,20 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
                                  arraypool *botpoints, arraypool *midpoints)
 {
   arraypool *crossfaces, *bfacearray;
-  triface fliptets[5], baktets[2], fliptet, newface;
+  triface fliptets[6], baktets[2], fliptet, newface;
   triface neightet, *parytet;
   face checksh;
   face checkseg;
   badface *pqueue;
   badface *popbf, bface;
+  point plane_pa, plane_pb, plane_pc;
   point p1, p2, pd, pe;
   point *parypt;
+  flipconstraints fc;
   REAL ori[3];
   int convcount, copcount;
   int flipflag, fcount;
   int n, i;
-
   long f23count, f32count, f44count;
   long totalfcount;
 
@@ -18434,9 +17026,6 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
   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);
@@ -18449,21 +17038,20 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
 
   for (i = 0; i < crossfaces->objects; i++) {
     parytet = (triface *) fastlookup(crossfaces, i);
-    flipcertify(parytet, &pqueue);
+    flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
   }
   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.
+    // Pop a face from the priority queue.
     popbf = pqueue;
     bface = *popbf;
 
@@ -18518,7 +17106,7 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
 
             fliptets[0] = fliptet; // abcd, d may be the new vertex.
             fliptets[1] = neightet; // bace.
-            flip23(fliptets, 1, 0, 0);  
+            flip23(fliptets, 1, &fc);
             // Put the link faces into check list.
             for (i = 0; i < 3; i++) {
               eprevesym(fliptets[i], newface);
@@ -18545,16 +17133,26 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
             assert(checkseg.sh == NULL);
 
             // Collect tets sharing at this edge.
+            // NOTE: This operation may collect tets which lie outside the
+            //   cavity, e.g., when the edge lies on the boundary of the
+            //   cavity. Do not flip if there are outside tets at this edge.
+            //   2012-07-27.
             esym(fliptet, fliptets[0]); // [b,a,d,c]
             n = 0;
             do {
+              p1 = apex(fliptets[n]);
+              if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
+                // This apex is not on the cavity. Hence the face does not
+                //   lie inside the cavity. Do not flip this edge.
+                n = 1000; break;
+              }
               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);
+              flip32(fliptets, 1, &fc);
               // Put the link faces into check list.
               for (i = 0; i < 3; i++) {
                 esym(fliptets[0], newface);
@@ -18588,7 +17186,7 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
                 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);
+                flip23(fliptets, 1, &fc);
                 // 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.
@@ -18607,7 +17205,7 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
                 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);
+                flip32(fliptets, 1, &fc);
                 // Put the "outer" link faces into check list.
                 //   fliptets[0] = [d,e,f,a]
                 //   fliptets[1] = [e,d,f,b]
@@ -18645,23 +17243,22 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
                      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);
+              flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
             }
             crossfaces->restart();
-            if (!b->flipinsert_random) {
+            if (1) { // 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);
+                  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
                 }
               }
               bfacearray->restart();
@@ -18683,22 +17280,10 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
       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;
+  //dbg_unflip_facecount += bfacearray->objects;
 
   assert(flippool->items == 0l);
   delete bfacearray;
@@ -18717,11 +17302,6 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
   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);
@@ -18734,156 +17314,85 @@ void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
 //                                                                           //
 // '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, 
+bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds,
                             arraypool* newshs)
 {
   badface *newflipface, *popface;
-  triface searchtet, spintet;
+  triface searchtet, spintet, neightet;
   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;
+  face neighseg, checkseg;
+  point pc;
+  int success;
+  int t1ver;
+  int i, j;
 
-  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]));
-    }
+
+  // Search the first new subface to fill the region.
+  for (i = 0; i < missingshbds->objects; i++) {
+    parysh = (face *) fastlookup(missingshbds, i);
+    sspivot(*parysh, neighseg);
+    sstpivot1(neighseg, searchtet);
+    j = 0; // Count the number of passes of R.
     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;
+        neightet = spintet;
+        j++;
+      }
       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.
+    }
+    assert(j >= 1);
+    if (j == 1) {
+      // Found an interior new subface.
+      searchtet = neightet;
+      oldsh = *parysh;
+      break;
+    }
+  } // i
+
+  if (i == missingshbds->objects) {
+    // Failed to find any interior subface.
+    // Need Steiner points.
     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);
+  setsorg(newsh, org(searchtet));
+  setsdest(newsh, dest(searchtet));
+  setsapex(newsh, apex(searchtet));
   // 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);
+  if (sinfected(checkseg)) {
+    // It's a faked segment. Delete it.
+    spintet = searchtet;
+    while (1) {
+      tssdissolve1(spintet);
+      fnextself(spintet);
+      if (spintet.tet == searchtet.tet) break;
+    }
+    shellfacedealloc(subsegs, checkseg.sh);
+    ssdissolve(oldsh);
+    checkseg.sh = NULL;
+  }
   spivot(oldsh, casout);
   if (casout.sh != NULL) {
     casin = casout;
@@ -18902,384 +17411,491 @@ bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds,
     sbond1(newsh, casout);
     sbond1(casin, newsh);
   }
-  if (checkseg.sh != NULL) {
-    ssbond(newsh, checkseg);
+  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;
+  }
+
+  success = 1;
+
+  // Loop until 'flipstack' is empty.
+  while ((flipstack != NULL) && success) {
+    // 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);
+
+    // opensh is either (1) an interior edge or (2) a bdry edge.
+    stpivot(opensh, searchtet);
+    tsspivot1(searchtet, checkseg);
+    if (checkseg.sh == NULL) {
+      // No segment. It is an interior edge of R. 
+      // Search for a new face in R.
+      spintet = searchtet;
+      fnextself(spintet); // Skip the current face.
+      while (1) {
+        pc = apex(spintet);
+        if (pmarktested(pc)) {
+          // 'opensh' is an interior edge.
+          if (!issubface(spintet)) {
+            // Create a new subface.
+            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 {
+            // Connect to another open edge.
+            tspivot(spintet, checksh);
+            sbond(opensh, checksh); 
+          }
+          break;
+        } // if (pmarktested(pc))
+        fnextself(spintet);
+        if (spintet.tet == searchtet.tet) {
+          // Not find any face to fill in R at this side.
+          // Suggest a point to split the edge.
+          success = 0;
+          break;
+        }
+      } // 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.
+        spintet = searchtet;
+        while (1) {
+          tssdissolve1(spintet);
+          fnextself(spintet);
+          if (spintet.tet == searchtet.tet) break;
+        }
+        shellfacedealloc(subsegs, checkseg.sh);
+        ssdissolve(oldsh);
+        checkseg.sh = NULL;
+      }
+      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 (checkseg.sh != NULL)
+  } // while ((flipstack != NULL) && success)
+
+  if (success) {
+    // Uninfect all new subfaces.
+    for (i = 0; i < newshs->objects; i++) {
+      parysh = (face *) fastlookup(newshs, i);
+      suninfect(*parysh);
+    }
+    // Delete old subfaces.
+    for (i = 0; i < missingshs->objects; i++) {
+      parysh = (face *) fastlookup(missingshs, i);
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    fillregioncount++;
+  } else {
+    // Failed to fill the region. 
+    // Re-connect old subfaces at boundaries of R.
+    // Also delete fake segments.
+    for (i = 0; i < missingshbds->objects; i++) {
+      parysh = (face *) fastlookup(missingshbds, i);
+      // It still connect to 'casout'. 
+      // Re-connect 'casin' to it.
+      spivot(*parysh, casout);
+      casin = casout;
+      spivot(casin, neighsh);
+      while (1) {
+        if (sinfected(neighsh)) break;
+        if (neighsh.sh == parysh->sh) break;
+        casin = neighsh;
+        spivot(casin, neighsh);
+      }
+      if (sinfected(neighsh)) {
+        sbond1(casin, *parysh);
+      }
+      sspivot(*parysh, checkseg);
+      if (checkseg.sh != NULL) {
+        if (checkseg.sh[3] != NULL) {
+          if (sinfected(checkseg)) {
+            sstpivot1(checkseg, searchtet);
+            spintet = searchtet;
+            while (1) {
+              tssdissolve1(spintet);
+              fnextself(spintet);
+              if (spintet.tet == searchtet.tet) break;
+            }
+            ssdissolve(*parysh);
+            shellfacedealloc(subsegs, checkseg.sh);
+          }
+        }
+      }
+    }
+    // Delete all new subfaces.
+    for (i = 0; i < newshs->objects; i++) {
+      parysh = (face *) fastlookup(newshs, i);
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    // Clear the flip pool.    
+    flippool->restart();
+    flipstack = NULL;
+
+    // Choose an interior edge of R to split.
+    assert(missingshs->objects > 1);
+    // Skip the first subface in 'missingshs'.
+    i = randomnation(missingshs->objects - 1) + 1;
+    parysh = (face *) fastlookup(missingshs, i);
+    recentsh = *parysh;
+  }
+
+  newshs->restart();
+
+  return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertpoint_cdt()    Insert a new point into a CDT.                       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh, 
+                                face *splitseg, insertvertexflags *ivf,
+                                arraypool *cavpoints, arraypool *cavfaces,
+                                arraypool *cavshells, arraypool *newtets,
+                                arraypool *crosstets, arraypool *misfaces)
+{
+  triface neightet, *parytet;
+  face checksh, *parysh, *parysh1;
+  face *paryseg, *paryseg1;
+  point *parypt;
+  int t1ver;
+  int i;
+
+  if (b->verbose > 2) {
+    printf("      Insert point %d into CDT\n", pointmark(newpt));
+  }
+
+  if (!insertpoint(newpt, searchtet, NULL, NULL, ivf)) {
+    // Point is not inserted. Check ivf->iloc for reason.
+    return 0;
   }
-  // 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;
+
+  for (i = 0; i < cavetetvertlist->objects; i++) {
+    cavpoints->newindex((void **) &parypt);
+    *parypt = * (point *) fastlookup(cavetetvertlist, i);
   }
+  // Add the new point into the point list.
+  cavpoints->newindex((void **) &parypt);
+  *parypt = newpt;
 
-  // 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;
+  for (i = 0; i < cavebdrylist->objects; i++) {
+    cavfaces->newindex((void **) &parytet);
+    *parytet = * (triface *) fastlookup(cavebdrylist, i);
   }
 
-  // Loop until 'flipstack' is empty.
-  while (flipstack != NULL) {
+  for (i = 0; i < caveoldtetlist->objects; i++) {
+    crosstets->newindex((void **) &parytet);
+    *parytet = * (triface *) fastlookup(caveoldtetlist, i);
+  }
 
-    // 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);
+  cavetetvertlist->restart();
+  cavebdrylist->restart();
+  caveoldtetlist->restart();
 
-    // 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)));
+  // Insert the point using the cavity algorithm.
+  delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets, 
+                  misfaces);
+  fillcavity(cavshells, NULL, NULL, NULL, NULL, NULL, NULL);
+  carvecavity(crosstets, newtets, NULL);
+
+  if ((splitsh != NULL) || (splitseg != NULL)) {
+    // Insert the point into the surface mesh.
+    sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
+
+    // Put all new subfaces into stack.
+    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) {
+        subfacstack->newindex((void **) &parysh);
+        *parysh = checksh;
       }
-      // 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);
-            }
+    }
+
+    if (splitseg != NULL) {
+      // Queue two new subsegments in C(p) for recovery.
+      for (i = 0; i < cavesegshlist->objects; i++) {
+        paryseg = (face *) fastlookup(cavesegshlist, i);
+        subsegstack->newindex((void **) &paryseg1);
+        *paryseg1 = *paryseg;
+      }
+    } // if (splitseg != NULL)
+
+    // Delete the old subfaces in sC(p).
+    for (i = 0; i < caveshlist->objects; i++) {
+      parysh = (face *) fastlookup(caveshlist, i);
+      if (checksubfaceflag) {
+        // 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);
           }
-          sbond1(opensh, casout);
-          sbond1(casin, opensh);
-        }
-        if (checkseg.sh != NULL) {
-          ssbond(opensh, checkseg);
         }
       }
+      shellfacedealloc(subfaces, parysh->sh);
+    }
+    if (splitseg != NULL) {
+      // Delete the old segment in sC(p).
+      shellfacedealloc(subsegs, splitseg->sh);
+    }
 
-    } // 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);
+    // Clear working lists.
+    caveshlist->restart();
+    caveshbdlist->restart();
+    cavesegshlist->restart();
+  } // if ((splitsh != NULL) || (splitseg != NULL)) 
+
+  // Put all interior subfaces into stack for recovery.
+  // They were collected in carvecavity().
+  // Note: Some collected subfaces may be deleted by sinsertvertex().
+  for (i = 0; i < caveencshlist->objects; i++) {
+    parysh = (face *) fastlookup(caveencshlist, i);
+    if (parysh->sh[3] != NULL) {
+      subfacstack->newindex((void **) &parysh1);
+      *parysh1 = *parysh;
+    }
   }
 
-  if (b->verbose > 2) {
-    printf("      Created %ld new subfaces.\n", newshs->objects);
+  // Put all interior segments into stack for recovery.
+  // They were collected in carvecavity().
+  // Note: Some collected segments may be deleted by sinsertvertex().
+  for (i = 0; i < caveencseglist->objects; i++) {
+    paryseg = (face *) fastlookup(caveencseglist, i);
+    if (paryseg->sh[3] != NULL) {
+      subsegstack->newindex((void **) &paryseg1);
+      *paryseg1 = *paryseg;
+    }
   }
-  fillregioncount++;
 
-  return true;
+  caveencshlist->restart();
+  caveencseglist->restart();
+
+  return 1;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // refineregion()    Refine a missing region by inserting points.            //
 //                                                                           //
+// 'splitsh' represents an edge of the facet to be split. It must be not a   //
+// segment. 
+//                                                                           //
+// Assumption: The current mesh is a CDT and is convex.                      //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::refineregion()
+void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints, 
+                              arraypool *cavfaces, arraypool *cavshells,
+                              arraypool *newtets, arraypool *crosstets,
+                              arraypool *misfaces)
 {
-  triface searchtet;
-  face splitsh;
-  face *paryseg, sseg;
-  point steinpt, pa, pb, pc;
+  triface searchtet, spintet;
+  face splitseg, *paryseg;
+  point steinpt, pa, pb, refpt;
   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
+  enum interresult dir;
+  long baknum = points->items;
+  int t1ver;
+  int i;
 
-  // Create a new point.
-  makepoint(&steinpt, FREEFACETVERTEX);
+  if (b->verbose > 2) {
+    printf("      Refining region at edge (%d, %d, %d).\n",
+           pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
+           pointmark(sapex(splitsh)));
+  }
 
-  // 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;
-    }
+  // Create a new point.
+  makepoint(&steinpt, FREEFACETVERTEX);
+  for (i = 0; i < 3; i++) {
+    steinpt[i] = 0.5 * (pa[i] + pb[i]);
   }
 
-  // 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.
+  ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
+  ivf.cdtflag = 1; // Only create the initial cavity.
+  ivf.sloc = (int) ONEDGE;
+  ivf.sbowywat = 1;
+  ivf.assignmeshsize = b->metric;
 
-    // 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);
+  point2tetorg(pa, searchtet); // Start location from it.
+  ivf.iloc = (int) OUTSIDE;
 
-    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);
+  ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
+  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, NULL, &ivf, cavpoints,
+                       cavfaces, cavshells, newtets, crosstets, misfaces)) {
+    if (ivf.iloc == (int) ENCSEGMENT) {
+      pointdealloc(steinpt);
+      // Split an encroached segment.
+      assert(encseglist->objects > 0);
+      i = randomnation(encseglist->objects);
+      paryseg = (face *) fastlookup(encseglist, i);
+      splitseg = *paryseg;
+      encseglist->restart();
+
+      // Split the segment.
+      pa = sorg(splitseg);
+      pb = sdest(splitseg);
+      // Create a new point.
+      makepoint(&steinpt, FREESEGVERTEX);
+      for (i = 0; i < 3; i++) {
+        steinpt[i] = 0.5 * (pa[i] + pb[i]);
+      }
+      point2tetorg(pa, searchtet);
+      ivf.iloc = (int) OUTSIDE;
+      ivf.rejflag = 0;
+      if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
+                           cavpoints, cavfaces, cavshells, newtets, 
+                           crosstets, misfaces)) {
+        assert(0);
+      }
+      st_segref_count++;
+      if (steinerleft > 0) steinerleft--;
+    } else {
+      assert(0);
     }
-
-    st_segref_count++;
   } else {
     st_facref_count++;
+    if (steinerleft > 0) steinerleft--;
   }
-  if (steinerleft > 0) steinerleft--;
 
-  // Do flip to recover Delaunayniess.
-  lawsonflip3d(steinpt, 2, 0, 0, 0);
+  while (subsegstack->objects > 0l) {
+    // seglist is used as a stack.
+    subsegstack->objects--;
+    paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
+    splitseg = *paryseg;
+
+    // Check if this segment has been recovered.
+    sstpivot1(splitseg, searchtet);
+    if (searchtet.tet != NULL) continue;
 
-  // Some vertices may be queued, recover them.
-  if (subvertstack->objects > 0l) {
-    assert(0); //delaunizevertices();
-  }
+    // Search the segment.
+    dir = scoutsegment(sorg(splitseg), sdest(splitseg), &searchtet, &refpt, 
+                       NULL);
+    if (dir == SHAREEDGE) {
+      // Found this segment, insert it.
+      if (!issubseg(searchtet)) {
+        // Let the segment remember an adjacent tet.
+        sstbond1(splitseg, searchtet);
+        // Bond the segment to all tets containing it.
+        spintet = searchtet;
+        do {
+          tssbond1(spintet, splitseg);
+          fnextself(spintet);
+        } while (spintet.tet != searchtet.tet);
+      } else {
+        // Collision! Should not happen.
+        assert(0);
+      }
+    } else { 
+      if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
+        // Split the segment.
+        // Create a new point.
+        makepoint(&steinpt, FREESEGVERTEX);
+        //setpointtype(newpt, FREESEGVERTEX);
+        getsteinerptonsegment(&splitseg, refpt, steinpt);
+        ivf.iloc = (int) OUTSIDE;
+        ivf.rejflag = 0;
+        if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
+                             cavpoints, cavfaces, cavshells, newtets, 
+                             crosstets, misfaces)) {
+          assert(0);
+        }
+        st_segref_count++;
+        if (steinerleft > 0) steinerleft--;
+      } else {
+        // Maybe a PLC problem.
+        assert(0);
+      }
+    }
+  } // while
 
-  // Some subsegments may be queued, recover them.
-  if (subsegstack->objects > 0l) {
-    delaunizesegments();
+  if (b->verbose > 2) {
+    printf("      Added %ld Steiner points.\n", points->items - baknum);
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// constrainedfacets()    Recover subfaces saved in 'subfacestack'.          //
+// constrainedfacets()    Recover constrained facets in a CDT.               //
+//                                                                           //
+// All unrecovered subfaces are queued in 'subfacestack'.                    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -19290,16 +17906,14 @@ void tetgenmesh::constrainedfacets()
   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;
+  triface searchtet, neightet, crossedge;
+  face searchsh, *parysh, *parysh1;
+  face *paryseg;
+  point *parypt;
   enum interresult dir;
-  bool success;
   int facetcount;
-  //int bakhullsize;
-  int crossflag;
+  int success;
+  int t1ver;
   int i, j;
 
   // Initialize arrays.
@@ -19317,245 +17931,184 @@ void tetgenmesh::constrainedfacets()
   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); 
+  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.
+    if (searchsh.sh[3] == NULL) continue; // It is dead.
+    if (isshtet(searchsh)) continue; // It is recovered.
 
-    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;
-              }
+    // Collect all unrecovered subfaces which are co-facet.
+    smarktest(searchsh);
+    tg_facfaces->newindex((void **) &parysh);
+    *parysh = searchsh;
+    for (i = 0; i < tg_facfaces->objects; i++) {
+      parysh = (face *) fastlookup(tg_facfaces, i);
+      for (j = 0; j < 3; j++) {
+        if (!isshsubseg(*parysh)) {
+          spivot(*parysh, searchsh);
+          assert(searchsh.sh != NULL); // SELF_CHECK
+          if (!smarktested(searchsh)) {
+            if (!isshtet(searchsh)) {
+              smarktest(searchsh);
+              tg_facfaces->newindex((void **) &parysh1);
+              *parysh1 = searchsh;
             }
           }
-          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);
-      }
+        }
+        senextself(*parysh);
+      } // j
+    } // i
+    // Have found all facet subfaces. Unmark 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;
-              }
+    if (b->verbose > 2) {
+      printf("    Recovering facet #%d: %ld subfaces.\n", facetcount + 1, 
+             tg_facfaces->objects);
+    }
+    facetcount++;
+
+    while (tg_facfaces->objects > 0l) {
+
+      tg_facfaces->objects--;
+      parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
+      searchsh = *parysh;
+
+      if (searchsh.sh[3] == NULL) continue; // It is dead.
+      if (isshtet(searchsh)) continue; // It is recovered.
+
+      searchtet.tet = NULL;
+      dir = scoutsubface(&searchsh, &searchtet);
+      if (dir == SHAREFACE) continue; // The subface is inserted.
+
+      // The subface is missing. Form the missing region.
+      //   Re-use 'tg_crosstets' for 'adjtets'.
+      formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
+
+      if (scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs)) {
+        // Save this crossing edge, will be used by fillcavity().
+        crossedge = searchtet;
+        // Form a cavity of crossing tets.
+        success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
+                             tg_topfaces, tg_botfaces, tg_toppoints,
+                             tg_botpoints);
+        if (success) {
+          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, tg_topnewtets, tg_botnewtets,
+                                 &crossedge);
+            if (success) {
+              // Cavity is remeshed. Delete old tets and outer new tets.
+              carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
             } 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);
+              restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
+                            tg_missingshbds);
             }
-            tg_topshells->restart();
           } else {
-            // Search a handle for searching tetrahedron.
-            recenttet = searchtet;
-          }
-        }
+            // Use the flip algorithm of Shewchuk to recover the subfaces.
+            flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints, 
+                            tg_missingshverts);
+            // Recover the missing region.
+            success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
+            assert(success);
+            // Clear working lists.
+            tg_crosstets->restart();
+            tg_topfaces->restart();
+            tg_botfaces->restart();
+            tg_toppoints->restart();
+            tg_botpoints->restart();
+          } // b->flipinsert
 
-        // 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) {
+            // Recover interior subfaces.
+            for (i = 0; i < caveencshlist->objects; i++) {
+              parysh = (face *) fastlookup(caveencshlist, i);
+              dir = scoutsubface(parysh, &searchtet);
+              if (dir != SHAREFACE) {
+                // Add this face at the end of the list, so it will be
+                //   processed immediately.
+                tg_facfaces->newindex((void **) &parysh1);
+                *parysh1 = *parysh;
+              }
+            }
+            caveencshlist->restart();
+            // Recover interior segments. This should always be recovered.
+            for (i = 0; i < caveencseglist->objects; i++) {
+              paryseg = (face *) fastlookup(caveencseglist, i);
+              dir = scoutsegment(sorg(*paryseg),sdest(*paryseg),&searchtet,
+                                 NULL, NULL);
+              assert(dir == SHAREEDGE);
+              // Insert this segment.
+              if (!issubseg(searchtet)) {
+                // 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);
+              }
+            }
+            caveencseglist->restart();
+          } // success - remesh cavity
+        } // success - form cavity
+      } else {
+        // Recover subfaces by retriangulate the surface mesh.
+        //   Re-use tg_topshells for newshs.
+        success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
+      }
 
-        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)
+      // 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 (neightet.tet == NULL)
-  } // while (subfacstack->objects > 0l)
+      if (!success) {
+        // The missing region can not be recovered. Refine it.
+        refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
+                     tg_topnewtets, tg_crosstets, tg_midfaces);
+        // Clean the current list of facet subfaces.
+        // tg_facfaces->restart();
+      }
+    } // while (tg_facfaces->objects)
+
+  } // while ((subfacstack->objects)
+
+  // Accumulate the dynamic memory.
+  totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
+                      tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
+                      tg_botfaces->totalmemory + tg_midfaces->totalmemory +
+                      tg_toppoints->totalmemory + tg_botpoints->totalmemory +
+                      tg_facfaces->totalmemory + tg_topshells->totalmemory +
+                      tg_botshells->totalmemory + tg_missingshs->totalmemory +
+                      tg_missingshbds->totalmemory + 
+                      tg_missingshverts->totalmemory + 
+                      encseglist->totalmemory);
 
   // Delete arrays.
   delete tg_crosstets;
@@ -19590,15 +18143,13 @@ void tetgenmesh::constraineddelaunay(clock_t& tv)
   // Statistics.
   long bakfillregioncount;
   long bakcavitycount, bakcavityexpcount;
+  long bakseg_ref_count;
 
   if (!b->quiet) {
     printf("Constrained Delaunay...\n");
   }
 
-  //if (!b->psc) {
-    // Only identify acute vertex for PLC inputs.
-    markacutevertices();
-  //}
+  makesegmentendpointsmap();
 
   if (b->verbose) {
     printf("  Delaunizing segments.\n");
@@ -19606,37 +18157,25 @@ void tetgenmesh::constraineddelaunay(clock_t& tv)
 
   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;
-    }
+  // Put all segments into the list (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); 
+    printf("  Inserted %ld Steiner points.\n", st_segref_count); 
   }
 
   tv = clock();
@@ -19645,17 +18184,13 @@ void tetgenmesh::constraineddelaunay(clock_t& tv)
     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;
+  bakseg_ref_count = st_segref_count;
 
   // Randomly order the subfaces.
   subfaces->traversalinit();
@@ -19684,10 +18219,10 @@ void tetgenmesh::constraineddelaunay(clock_t& tv)
       }
       printf(".\n");
     }
-    if (st_segref_count + st_facref_count > 0) {
+    if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
       printf("  Inserted %ld (%ld, %ld) refine points.\n", 
-             st_segref_count + st_facref_count, st_segref_count,
-             st_facref_count);
+             st_segref_count + st_facref_count - bakseg_ref_count,
+             st_segref_count - bakseg_ref_count, st_facref_count);
     }
   }
 }
@@ -19711,10 +18246,6 @@ void tetgenmesh::constraineddelaunay(clock_t& tv)
 // 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, 
@@ -19722,45 +18253,23 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
                                      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;
+  int rejflag = 0;
+  int i;
 
   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++) {
+      tmppts[0] = pa;
+      tmppts[1] = pb;
+      tmppts[2] = pc;
+      for (i = 0; i < 3 && !rejflag; i++) {
+        if (tmppts[i] != dummypoint) {
+          // Test if the face [e,d,#] intersects the edge.
           intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1], 
                                   NULL, 1, types, poss);
           if (intflag == 2) {
@@ -19775,12 +18284,7 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
                 // 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];
@@ -19790,177 +18294,32 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
                 // 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)
+        } // if (tmppts[0] != dummypoint)
+      } // i
     } 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.
-            }
+        // 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.
           }
-        }
-        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.
-            }
+        } 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.            
+            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 (pc != dummypoint)
     }
   } // if (fc->seg[0] != NULL)
 
@@ -19978,11 +18337,7 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
           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.
@@ -20123,10 +18478,10 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
 //                                                                           //
 // removeedgebyflips()    Remove an edge by flips.                           //
 //                                                                           //
-// 'flipedge' is a non-convex or flat edge [a,b,#,#].                        //
+// 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed.          //
 //                                                                           //
 // 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    //
+// removed or not.  A value "2" means the edge is removed, otherwise, the    //
 // edge is not removed and the value (must >= 3) is the current number of    //
 // tets in the edge star.                                                    //
 //                                                                           //
@@ -20135,77 +18490,39 @@ int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
 int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
 {
   triface *abtets, spintet;
-  face checkseg, *paryseg;
-  int counter; // DEBUG
+  int t1ver; 
   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;
-          }
+    if (issubseg(*flipedge)) {
+      if (fc->collectencsegflag) {
+        face checkseg, *paryseg;
+        tsspivot1(*flipedge, checkseg);
+        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++;
+    n++;
     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;
+  assert(n >= 3);
 
-  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++;
+    // The star size exceeds the limit.
     return 0; // Do not flip it.
   }
 
@@ -20216,8 +18533,7 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
   i = 0;
   while (1) {
     abtets[i] = spintet;
-    //marktest(abtets[i]); // Marktest it (in Star(ab)).
-    setelemcounter(abtets[i], 1);
+    setelemcounter(abtets[i], 1); 
     i++;
     fnextself(spintet);
     if (spintet.tet == flipedge->tet) break;
@@ -20228,45 +18544,33 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
   nn = flipnm(abtets, n, 0, 0, fc);
 
 
-  if (nn == 2) {
-    // Edge is flipped.
-    if (b->verbose > 2) {
-      printf("      Edge is removed.\n");
-    }
-  } else {
+  if (nn > 2) {
     // 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.
+  int bakunflip = fc->unflip;
   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;
+  return nn; 
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // removefacebyflips()    Remove a face by flips.                            //
 //                                                                           //
+// Return 1 if the face is removed. Otherwise, return 0.                     //
+//                                                                           //
 // ASSUMPTIONS:                                                              //
 //   - 'flipface' must not be a hull face.                                   //
 //                                                                           //
@@ -20274,45 +18578,25 @@ int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
 
 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"); 
-      }
+    if (issubface(*flipface)) {
       return 0;
     }
   }
 
+  triface fliptets[3], flipedge;
+  point pa, pb, pc, pd, pe;
+  REAL ori;
+  int reducflag = 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);
@@ -20333,109 +18617,12 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
 
   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++;
-      }
-    }
+    flip23(fliptets, 0, fc);
+    return 1;
   } 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;
-      }
+    // Try to flip the selected edge of this face.
+    if (removeedgebyflips(&flipedge, fc) == 2) {
+      return 1;
     }
   }
 
@@ -20450,7 +18637,7 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
 // 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.                                  //
+// faces or edges are needed to be removed.                                  //
 //                                                                           //
 // 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    //
@@ -20461,38 +18648,24 @@ int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
 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));
-  }
-
+  enum interresult dir;
 
   fc.seg[0] = startpt;
   fc.seg[1] = endpt;
+  fc.checkflipeligibility = 1;
 
   // 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);
+    dir = finddirection(searchtet, endpt);
     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
+        terminatetetgen(this, 3); // // It may be a PLC problem. 
       }
     }
 
@@ -20511,175 +18684,178 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt,
         continue;
       }
     } else {
-      terminatetetgen(3); //assert(0); // A PLC problem.
+      terminatetetgen(this, 3); // It may be 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);
+      // Try to flip one of the faces/edges which intersects the edge.
+      triface neightet, spintet;
+      point pa, pb, pc, pd;
+      badface bakface;
+      enum interresult dir1;
+      int types[2], poss[4], pos = 0;
+      int success = 0;
+      int t1ver; 
+      int i, j;
+
+      // Loop through the sequence of intersecting faces/edges from
+      //   'startpt' to 'endpt'.
+      point2tetorg(startpt, *searchtet);
+      dir = finddirection(searchtet, endpt);
+      //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)) {
+              if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
                 dir = (enum interresult) types[0];
                 pos = poss[0];
-                break;
+                break; // for loop
               } 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
-          }
+            } // 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);
-          }
+        // 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);
-            }
+        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;
+        // 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);
+        // 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) {
+        // 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);
+          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.
                 }
-	      } // 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 
             }
+          } else {
+            searchtet->tet = NULL; // Not find.
+          }
+          if (searchtet->tet == NULL) {
+            success = 0; // This face/edge has been destroyed.
+            break; // Loop I-I 
           }
-        } // while (1) // Loop I-I
-
-        if (success) {
-          // One of intersecting faces/edges is flipped.
-          continue;
         }
-      } // if (0)
+      } // while (1) // Loop I-I
+
+      if (success) {
+        // One of intersecting faces/edges is flipped.
+        continue;
+      }
 
     } // if (fullsearch)
 
@@ -20688,7 +18864,6 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt,
 
   } // while (1) // Loop I
 
-  // The edge is not recovered.
   return 0;
 }
 
@@ -20701,24 +18876,8 @@ int tetgenmesh::recoveredgebyflips(point startpt, point endpt,
 // 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.                                                  //
-//                                                                           //
+// Such set of tets arises when we want to recover an edge from 'p0' to 'p_  //
+// (n-1)', and the number of tets at [a,b] can not be reduced by any flip.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -20727,55 +18886,46 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
 {
   triface worktet, *parytet;
   triface faketet1, faketet2;
-  point pa, pb, pc, pd;
-  point p1, p2, p3;
-  point steinerpt;
+  point pc, pd, 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].
+    edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
     cavetetlist->newindex((void **) &parytet);
     *parytet = worktet;
-    enext(abtets[i], worktet);
-    esymself(worktet); // [p_i,b,p_i+1].
+    eorgoppo(abtets[i], worktet);  // [p_i+1,p_i,b]
     cavetetlist->newindex((void **) &parytet);
     *parytet = worktet;
   }
 
+  int N = 100;
+  REAL stepi = 0.01;
+
   // 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++) {
+  // Sample N points in edge [c,d].
+  for (it = 1; it < N; it++) {
     for (i = 0; i < 3; i++) {
-      sampt[i] = pc[i] + (0.01 * (double) it) * vcd[i];
+      sampt[i] = pc[i] + (stepi * (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);
+      ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
       if (i == 0) {
         minvol = ori;
       } else {
@@ -20794,26 +18944,22 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
   } // 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];
+    smtpt[i] = pc[i] + (stepi * (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);
+  setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
   cavetetlist->newindex((void **) &parytet);
   *parytet = faketet1;
   maketetrahedron(&faketet2);
-  setvertices(faketet2, pc, pd, pb, dummypoint);
+  setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
   cavetetlist->newindex((void **) &parytet);
   *parytet = faketet2;
 
@@ -20846,9 +18992,6 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
   cavetetlist->restart();
 
   if (!success) {
-    if (b->verbose > 2) {
-      printf("      Unable to relocate the initial point.\n");
-    }
     return 0;
   }
 
@@ -20865,36 +19008,205 @@ int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
   }
   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; 
+  ivf.assignmeshsize = b->metric; 
+  if (ivf.assignmeshsize) {
+    // Search the tet containing 'steinerpt' for size interpolation.
+    locate(steinerpt, &(abtets[0]));
+    worktet = abtets[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) {
+  if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
     // The vertex has been inserted.
-    st_volref_count++; //st_inpoly_count++;
+    st_volref_count++; 
     if (steinerleft > 0) steinerleft--;
     return 1;
   } else {
-    // The Steiner point is too close to an existing vertex. Reject it.
+    // Not inserted. 
+    pointdealloc(steinerpt);
+    return 0;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// add_steinerpt_in_segment()    Add a Steiner point inside a segment.       //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
+{
+  triface searchtet;
+  face *paryseg, candseg;
+  point startpt, endpt, pc, pd;
+  flipconstraints fc;
+  enum interresult dir;
+  REAL P[3], Q[3], tp, tq;
+  REAL len, smlen = 0, split = 0, split_q = 0;
+  int success;
+  int i;
+
+  startpt = sorg(*misseg);
+  endpt = sdest(*misseg);
+
+  fc.seg[0] = startpt;
+  fc.seg[1] = endpt;
+  fc.checkflipeligibility = 1;
+  fc.collectencsegflag = 1;
+
+  point2tetorg(startpt, searchtet);
+  dir = finddirection(&searchtet, endpt);
+  //assert(dir != ACROSSVERT);
+
+  // Try to flip the first intersecting face/edge.
+  enextesymself(searchtet); // Go to the opposite face.
+
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = searchlevel;
+
+  if (dir == ACROSSFACE) {
+    // A face is intersected with the segment. Try to flip it.
+    success = removefacebyflips(&searchtet, &fc);
+    assert(success == 0);
+  } else if (dir == ACROSSEDGE) {
+    // An edge is intersected with the segment. Try to flip it.
+    success = removeedgebyflips(&searchtet, &fc);
+    assert(success != 2);
+  } else {
+    terminatetetgen(this, 3); // It may be a PLC problem.
+  }
+
+  split = 0;
+  for (i = 0; i < caveencseglist->objects; i++) {
+    paryseg = (face *) fastlookup(caveencseglist, i);
+    suninfect(*paryseg);
+    // Calculate the shortest edge between the two lines.
+    pc = sorg(*paryseg);
+    pd = sdest(*paryseg);
+    tp = tq = 0;
+    if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
+      // Does the shortest edge lie between the two segments? 
+      // Round tp and tq.
+      if ((tp > 0) && (tq < 1)) {
+        if (tp < 0.5) {
+          if (tp < (b->epsilon * 1e+3)) tp = 0.0;
+        } else {
+          if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
+        }
+      }
+      if ((tp <= 0) || (tp >= 1)) continue; 
+      if ((tq > 0) && (tq < 1)) {
+        if (tq < 0.5) {
+          if (tq < (b->epsilon * 1e+3)) tq = 0.0;
+        } else {
+          if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
+        }
+      }
+      if ((tq <= 0) || (tq >= 1)) continue;
+      // It is a valid shortest edge. Calculate its length.
+      len = distance(P, Q);
+      if (split == 0) {
+        smlen = len;
+        split = tp;
+        split_q = tq;
+        candseg = *paryseg;
+      } else {
+        if (len < smlen) {
+          smlen = len;
+          split = tp;
+          split_q = tq;
+          candseg = *paryseg;
+        }
+      }
+    }
+  }
+
+  caveencseglist->restart();
+  b->fliplinklevel = bak_fliplinklevel;
+
+  if (split == 0) {
+    // Found no crossing segment. 
+    return 0;
+  }
+
+  face splitsh;
+  face splitseg;
+  point steinerpt, *parypt;
+  insertvertexflags ivf;
+
+  if (b->addsteiner_algo == 1) {
+    // Split the segment at the closest point to a near segment.
+    makepoint(&steinerpt, FREESEGVERTEX);
+    for (i = 0; i < 3; i++) {
+      steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
+    }
+  } else { // b->addsteiner_algo == 2
+    for (i = 0; i < 3; i++) {
+      P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
+    }
+    pc = sorg(candseg);
+    pd = sdest(candseg);
+    for (i = 0; i < 3; i++) {
+      Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
+    }
+    makepoint(&steinerpt, FREEVOLVERTEX);
+    for (i = 0; i < 3; i++) {
+      steinerpt[i] = 0.5 * (P[i] + Q[i]);
+    }
+  }
+
+  // We need to locate the point. Start searching from 'searchtet'.
+  if (split < 0.5) {
+    point2tetorg(startpt, searchtet);
+  } else {
+    point2tetorg(endpt, searchtet);
+  }
+  if (b->addsteiner_algo == 1) {
+    splitseg = *misseg;
+    spivot(*misseg, splitsh);
+  } else {
+    splitsh.sh = NULL;
+    splitseg.sh = NULL;
+  }
+  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 = b->metric; 
+
+  if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
     pointdealloc(steinerpt);
     return 0;
   }
+
+  if (b->addsteiner_algo == 1) {
+    // Save this Steiner point (for removal).
+    //   Re-use the array 'subvertstack'.
+    subvertstack->newindex((void **) &parypt);
+    *parypt = steinerpt;
+    st_segref_count++;
+  } else { // b->addsteiner_algo == 2
+    // Queue the segment for recovery.
+    subsegstack->newindex((void **) &paryseg);
+    *paryseg = *misseg; 
+    st_volref_count++;
+  }
+  if (steinerleft > 0) steinerleft--;
+
+  return 1;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// addsteiner4recoversegment()    Add a Steiner point for recoveing a seg.   //
+// addsteiner4recoversegment()    Add a Steiner point for recovering a seg.  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -20902,16 +19214,14 @@ 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 t1ver;
   int i;
 
   startpt = sorg(*misseg);
@@ -20923,12 +19233,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
 
   // 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));
+  dir = finddirection(&searchtet, endpt);
   enextself(searchtet); 
   //assert(apex(searchtet) == startpt);
 
@@ -20936,13 +19241,8 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
     // 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);
@@ -20958,8 +19258,9 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
   } else {
     assert(dir == ACROSSEDGE);
     // PLC check.
-    tsspivot1(searchtet, checkseg);
-    if (checkseg.sh != NULL) {
+    if (issubseg(searchtet)) {
+      face checkseg;
+      tsspivot1(searchtet, checkseg);
       printf("Found two segments intersect each other.\n");
       pa = farsorg(*misseg);
       pb = farsdest(*misseg);
@@ -20969,7 +19270,7 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
       pb = farsdest(checkseg);
       printf("  2nd: [%d,%d] %d.\n", pointmark(pa), pointmark(pb), 
              shellmark(checkseg));
-      terminatetetgen(3);
+      terminatetetgen(this, 3);
     }
   }
   assert(apex(searchtet) == startpt);
@@ -20996,8 +19297,6 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
       abtets[i] = spintet;
       fnextself(spintet);
     }
-    assert(apex(abtets[0]) == startpt);
-    assert(apex(abtets[endi]) == endpt);
 
     success = 0;
 
@@ -21030,10 +19329,10 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
         //   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
+        terminatetetgen(this, 2); // Report a bug.
       }
     } else {
-      assert(0); // A PLC problem.
+      terminatetetgen(this, 10); // A PLC problem.
     }
 
     delete [] abtets;
@@ -21054,98 +19353,21 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
     printf("      Splitting segment (%d, %d)\n", pointmark(startpt), 
            pointmark(endpt));
   }
+  steinerpt = NULL;
 
-  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.
+  if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
+    if (add_steinerpt_in_segment(misseg, 3)) {
+      return 1;
     }
+    sesymself(*misseg);
+    if (add_steinerpt_in_segment(misseg, 3)) {
+      return 1;
+    }
+    sesymself(*misseg);
+  }
 
-    // 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.
@@ -21167,11 +19389,10 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
     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);
+    ivf.assignmeshsize = b->metric; 
+    if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
+      assert(0);
+    }
   } // if (endi > 0)
 
   // Save this Steiner point (for removal).
@@ -21189,17 +19410,11 @@ int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
 //                                                                           //
 // 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.                                         // 
+// All segments need to be recovered are in 'subsegstack'.                   //
 //                                                                           //
-// 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'.                                           //
+// This routine first tries to recover each segment by only using flips. If  //
+// no flip is possible, and the flag 'steinerflag' is set, it then tries to  //
+// insert Steiner points near or in the segment.                             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -21207,11 +19422,12 @@ int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
                                 int steinerflag)
 {
   triface searchtet, spintet;
-  face sseg, checkseg, *paryseg;
+  face sseg, *paryseg;
   point startpt, endpt;
   int success;
-
-  long bak_inpoly_count = st_volref_count; //st_inpoly_count;
+  int t1ver;
+  long bak_inpoly_count = st_volref_count; 
+  long bak_segref_count = st_segref_count;
 
   if (b->verbose > 1) {
     printf("    Recover segments [%s level = %2d] #:  %ld.\n",
@@ -21260,8 +19476,6 @@ int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
 
     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.
@@ -21300,6 +19514,10 @@ int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
         printf("    Add %ld Steiner points in volume.\n", 
                st_volref_count - bak_inpoly_count);
       }
+      if (st_segref_count > bak_segref_count) {
+        printf("    Add %ld Steiner points in segments.\n", 
+               st_segref_count - bak_segref_count);
+      }
     }
   }
 
@@ -21319,33 +19537,26 @@ 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 types[2], poss[4], intflag;
   int success, success1;
+  int t1ver; 
   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;
+  fc.checkflipeligibility = 1;
   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);
+      dir = finddirection(searchtet, fc.fac[(i+1)%3]);
       //assert(dir == ACROSSVERT);
       assert(dest(*searchtet) == fc.fac[(i+1)%3]);
       // Search the face [a,b,c]
@@ -21382,14 +19593,13 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
               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].
+                edestoppo(spintet, 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) {                    
+                  if (issubseg(flipedge)) {
+                    if (!b->quiet) {
+                      face checkseg;
+                      tsspivot1(flipedge, checkseg);
                       printf("Found a segment and a subface intersect.\n");
                       pd = farsorg(checkseg);
                       pe = farsdest(checkseg);
@@ -21397,16 +19607,16 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
                              pointmark(pe), shellmark(checkseg)); 
                       printf("  2nd: [%d,%d,%d] %d\n", pointmark(pa), 
                         pointmark(pb), pointmark(pc), shellmark(*searchsh));
-	            }
-                    terminatetetgen(3);
-		  }
+	                }
+                    terminatetetgen(this, 3);
+		          }
                 }
                 // Try to flip the edge [d,e].
                 success1 = (removeedgebyflips(&flipedge, &fc) == 2);
               } else {
                 if (dir == TOUCHFACE) {
                   point touchpt, *parypt;
-                  if (poss[0] == 0) {
+                  if (poss[1] == 0) {
                     touchpt = pd; // pd is a coplanar vertex.
                   } else {
                     touchpt = pe; // pe is a coplanar vertex.
@@ -21414,17 +19624,11 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
                   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);
+                    sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
                     st_volref_count--;
                     st_facref_count++;
                     // Queue this vertex for removal.
@@ -21438,12 +19642,6 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
                       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;
                       }
@@ -21469,7 +19667,7 @@ int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
                     } else if (pointtype(touchpt) == FREEFACETVERTEX) {
                       // Two facets self-intersect.
                     }
-                    terminatetetgen(3);
+                    terminatetetgen(this, 3);
                   }
                 } else {
                   assert(0); // Unknown cases. Debug.
@@ -21502,13 +19700,13 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
 {
   triface searchtet, neightet, spintet;
   face searchsh, neighsh, neineish, *parysh;
-  face bdsegs[3], checkseg;
+  face bdsegs[3];
   point startpt, endpt, apexpt, *parypt;
   point steinerpt;
   enum interresult dir;
   insertvertexflags ivf;
   int success;
-  int loc;
+  int t1ver;
   int i, j;
 
   if (b->verbose > 1) {
@@ -21532,7 +19730,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
 
 
     if (b->verbose > 2) {
-      printf("      Recover subface (%d, %d, %d).\n", pointmark(sorg(searchsh)),
+      printf("      Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
              pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
     }
 
@@ -21552,14 +19750,13 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
         startpt = sorg(searchsh);
         endpt = sdest(searchsh);
         point2tetorg(startpt, searchtet);
-        assert(org(searchtet) == startpt); // SELF_CHECK
-        dir = finddirection(&searchtet, endpt, 1);
+        dir = finddirection(&searchtet, endpt);
         if (dir == ACROSSVERT) {
           if (dest(searchtet) == endpt) {
             success = 1;  
           } else {
             //assert(0); // A PLC problem.
-            terminatetetgen(3);
+            terminatetetgen(this, 3);
           }
         } else {
           // The edge is missing. Try to recover it.
@@ -21573,13 +19770,8 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
         }
         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]);
@@ -21588,8 +19780,6 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
             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;
@@ -21601,11 +19791,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
           // 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])));
-              }
+            if (smarktest2ed(bdsegs[j])) { 
               spivot(bdsegs[j], neineish);
               assert(neineish.sh != NULL);
               //if (neineish.sh != NULL) {
@@ -21617,7 +19803,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
                   spivotself(neighsh); // SELF_CHECK
                   assert(neighsh.sh == neineish.sh);
                 }
-	      //}
+	          //}
               sstpivot1(bdsegs[j], searchtet);
               assert(searchtet.tet != NULL);
               //if (searchtet.tet != NULL) {
@@ -21627,7 +19813,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
                   fnextself(spintet);
                   if (spintet.tet == searchtet.tet) break;
                 }
-	      //}
+	          //}
               shellfacedealloc(subsegs, bdsegs[j].sh);
             }
           } // j
@@ -21653,10 +19839,10 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
             ivf.splitbdflag = 0;
             ivf.validflag = 1;
             ivf.respectbdflag = 1;
-            ivf.assignmeshsize = 0;
-            loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf);
-            assert(loc != (int) OUTSIDE);
-
+            ivf.assignmeshsize = b->metric;
+            if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
+              assert(0);
+            }
             // Save this Steiner point (for removal).
             //   Re-use the array 'subvertstack'.
             subvertstack->newindex((void **) &parypt);
@@ -21681,11 +19867,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
 
       // 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])));
-          }
+        if (smarktest2ed(bdsegs[j])) { 
           spivot(bdsegs[j], neineish);
           assert(neineish.sh != NULL);
           //if (neineish.sh != NULL) {
@@ -21697,7 +19879,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
               spivotself(neighsh); // SELF_CHECK
               assert(neighsh.sh == neineish.sh);
             }
-	  //}
+	      //}
           sstpivot1(bdsegs[j], neightet);
           assert(neightet.tet != NULL);
           //if (neightet.tet != NULL) {
@@ -21707,7 +19889,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
               fnextself(spintet);
               if (spintet.tet == neightet.tet) break;
             }
-	  //}
+	      //}
           shellfacedealloc(subsegs, bdsegs[j].sh);
         }
       } // j
@@ -21743,10 +19925,10 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
           ivf.splitbdflag = 0;
           ivf.validflag = 1;
           ivf.respectbdflag = 1;
-          ivf.assignmeshsize = 0; 
-          loc = insertvertex(steinerpt, &searchtet, &searchsh, NULL, &ivf);
-          assert(loc != (int) OUTSIDE);
-
+          ivf.assignmeshsize = b->metric; 
+          if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
+            assert(0);
+          }
           // Save this Steiner point (for removal).
           //   Re-use the array 'subvertstack'.
           subvertstack->newindex((void **) &parypt);
@@ -21762,11 +19944,6 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
 
     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;
@@ -21786,7 +19963,7 @@ int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
 // 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'.            //
+// Every tet in 'tetlist' is at the face opposing to 'searchpt'.             //
 //                                                                           //
 // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
 //                                                                           //
@@ -21800,54 +19977,48 @@ int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
 {
   triface searchtet, neightet, *parytet;
   face checksh, *parysh;
-  //face checkseg;
   point pt, *parypt;
   int collectflag;
+  int t1ver;
   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);
+  enextesymself(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);
+    j = (searchtet.ver & 3); // The current vertex index.
+    for (i = 1; i < 4; i++) {
+      pt = (point) searchtet.tet[4 + ((j + i) % 4)];
       pinfect(pt);
       vertlist->newindex((void **) &parypt);
       *parypt = pt;
-      enextself(searchtet);
     }
   }
 
   collectflag = 1;
   esym(searchtet, neightet);
-  tspivot(neightet, checksh);
-  if (checksh.sh != NULL) {
+  if (issubface(neightet)) {
     if (shlist != NULL) {
+      tspivot(neightet, checksh);
       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).
@@ -21867,15 +20038,14 @@ int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
     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.
+    // Check the neighbors 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 (issubface(neightet)) {
         if (shlist != NULL) {
+          tspivot(neightet, checksh);
           if (!sinfected(checksh)) {
             // Collect this subface (link edge).
             sinfected(checksh);
@@ -21889,7 +20059,6 @@ int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
       }
       if (collectflag) {
         fsymself(neightet);
-        assert(neightet.tet != NULL);
         if (!infected(neightet)) {
           esymself(neightet); // Go to the face opposite to 'searchpt'.
           infect(neightet);
@@ -21909,16 +20078,6 @@ int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
     } // 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++) {
@@ -21982,13 +20141,13 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge)
 
   // Search for the edge [e1, e2].
   point2tetorg(e1, *tedge);
-  finddirection(tedge, e2, 1);
+  finddirection(tedge, e2);
   if (dest(*tedge) == e2) {
     return 1;
   } else {
     // Search for the edge [e2, e1].
     point2tetorg(e2, *tedge);
-    finddirection(tedge, e1, 1);
+    finddirection(tedge, e1);
     if (dest(*tedge) == e1) {
       esymself(*tedge);
       return 1;
@@ -21998,20 +20157,18 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge)
 
   // Go to the link face of e1.
   point2tetorg(e1, searchtet);
-  enextself(searchtet);
-  esymself(searchtet);
+  enextesymself(searchtet);
   //assert(oppo(searchtet) == e1);
 
-  assert(cavetetlist->objects == 0l); // It will re-use this list.
+  assert(cavebdrylist->objects == 0l); // It will re-use this list.
+  arraypool *tetlist = cavebdrylist;
 
   // 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,#,#].
+      eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
       return 1;
     }
     enextself(searchtet);
@@ -22024,24 +20181,22 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge)
   pt = apex(neightet);
   if (pt == e2) {
     // Found. 'neightet' is [#,#,e2,e1].
-    enext(neightet, *tedge);
-    esymself(*tedge);
-    eprevself(*tedge); // [e1,e2,#,#].
+    eorgoppo(neightet, *tedge); // [e1,e2,#,#].
     return 1;
   }
 
   // Continue searching in the link face of e1.
   infect(searchtet);
-  cavetetlist->newindex((void **) &parytet);
+  tetlist->newindex((void **) &parytet);
   *parytet = searchtet;
   infect(neightet);
-  cavetetlist->newindex((void **) &parytet);
+  tetlist->newindex((void **) &parytet);
   *parytet = neightet;
 
   done = 0;
 
-  for (i = 0; (i < cavetetlist->objects) && !done; i++) {
-    parytet = (triface *) fastlookup(cavetetlist, i);
+  for (i = 0; (i < tetlist->objects) && !done; i++) {
+    parytet = (triface *) fastlookup(tetlist, i);
     searchtet = *parytet;
     for (j = 0; (j < 2) && !done; j++) {
       enextself(searchtet);
@@ -22051,13 +20206,11 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge)
         pt = apex(neightet);
         if (pt == e2) {
           // Found. 'neightet' is [#,#,e2,e1].
-          enext(neightet, *tedge);
-          esymself(*tedge);
-          eprevself(*tedge); // [e1,e2,#,#].
+          eorgoppo(neightet, *tedge);
           done = 1;
         } else {
           infect(neightet);
-          cavetetlist->newindex((void **) &parytet);
+          tetlist->newindex((void **) &parytet);
           *parytet = neightet;
         }
       }
@@ -22065,11 +20218,11 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge)
   } // i 
 
   // Uninfect the list of visited tets.
-  for (i = 0; i < cavetetlist->objects; i++) {
-    parytet = (triface *) fastlookup(cavetetlist, i);
+  for (i = 0; i < tetlist->objects; i++) {
+    parytet = (triface *) fastlookup(tetlist, i);
     uninfect(*parytet);
   }
-  cavetetlist->restart();
+  tetlist->restart();
 
   return done;
 }
@@ -22085,7 +20238,6 @@ int tetgenmesh::getedge(point e1, point e2, triface *tedge)
 int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
 {
   triface searchtet;
-  face checkseg;
   point *pendpt, *parypt;
   enum interresult dir;
   flipconstraints fc;
@@ -22093,13 +20245,9 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
   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;
+  fc.checkflipeligibility = 1;
 
   while (1) {
 
@@ -22121,13 +20269,12 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
         }
       } else {
         point2tetorg(startpt, searchtet);
-        dir = finddirection(&searchtet, *pendpt, 1);
+        dir = finddirection(&searchtet, *pendpt);
       }
       if (dir == ACROSSVERT) {
         if (dest(searchtet) == *pendpt) {
           // Do not flip a segment.
-          tsspivot1(searchtet, checkseg);
-          if (checkseg.sh == NULL) {
+          if (!issubseg(searchtet)) {
             n = removeedgebyflips(&searchtet, &fc);
             if (n == 2) {
               reduceflag = 1;
@@ -22158,10 +20305,6 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
 
   } // while (1)
 
-  if (b->verbose > 2) {
-    printf("      Final edge degree = %ld.\n", endptlist->objects);
-  }
-
   return (int) endptlist->objects;
 }
 
@@ -22169,28 +20312,13 @@ int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
 //                                                                           //
 // 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.            //
+// This routine attempts to remove the given vertex 'rempt' (p) from the     //
+// tetrahedralization (T) by a sequence of 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.                                              //
 //                                                                           //
@@ -22202,11 +20330,13 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
   triface searchtet, spintet, neightet;
   face parentsh, spinsh, checksh;
   face leftseg, rightseg, checkseg;
-  point lpt = NULL, rpt = NULL, apexpt, *parypt;
+  point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
+  flipconstraints fc;
   enum verttype vt;
   enum locateresult loc;
   int valence, removeflag;
   int slawson;
+  int t1ver;
   int n, i;
 
   vt = pointtype(steinerpt);
@@ -22241,13 +20371,16 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
     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 if (vt == VOLVERTEX) {
+    if (b->verbose > 2) {
+      printf("      Removing a point %d in volume.\n",
+             pointmark(steinerpt));
     }
   } else {
     // It is not a Steiner point.
@@ -22267,24 +20400,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
 
   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) {
+  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);
@@ -22317,19 +20433,24 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
         // 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].
+          // The edge (segment) has been already recovered!  
+          // Check if a 6-to-2 flip is possible (to remove 'p').
           // Let 'searchtet' be [p,d,a,b]
           esym(neightet, searchtet);
           enextself(searchtet);
-          loc = ONFACE;
-          removeflag = 1;
+          // Check if there are exactly three tets at edge [p,d].
+          wrktets[0] = searchtet; // [p,d,a,b]
+          for (i = 0; i < 2; i++) {
+            fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
+          }
+          if (apex(wrktets[0]) == oppo(wrktets[2])) {
+            loc = ONFACE;
+            removeflag = 1;
+          }
         }
       }
     } else if (vt == FREEFACETVERTEX) {
+      // It is possible to do a 6-to-2 flip to remove the vertex.
       point2tetorg(steinerpt, searchtet);
       // Get the three faces of 'searchtet' which share at p.
       //    All faces has p as origin.
@@ -22340,29 +20461,35 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
       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.
+      // All internal edges of the six tets have valance either 3 or 4.
+      // Get one edge which has valance 3.
+      searchtet.tet = NULL;
       for (i = 0; i < 3; i++) {
-        tspivot(wrktets[i], checksh);
-        if (checksh.sh != NULL) {
-          n = i;
-          valence++; 
+        spintet = wrktets[i];
+        valence = 0;
+        while (1) {
+          valence++;
+          fnextself(spintet);
+          if (spintet.tet == wrktets[i].tet) break;
+        }
+        if (valence == 3) {
+          // Found the edge.
+          searchtet = wrktets[i];
+          break;
+        } else {
+          assert(valence == 4);
         }
       }
-      assert(valence == 1);
-      searchtet = wrktets[n];
-      esymself(searchtet);
-      enextself(searchtet);
+      assert(searchtet.tet != NULL);
+      // Note, we do not detach the three subfaces at p.
+      // They will be removed within a 4-to-1 flip.
       loc = ONFACE;
       removeflag = 1;
     } else {
       // assert(0); DEBUG IT
     }
     //removeflag = 1;
-  } else { // valence > 5.
-    
-  } // if (valence > 5)
+  } 
 
   if (!removeflag) {
     if (vt == FREESEGVERTEX) { 
@@ -22399,7 +20526,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
 
   if (!removeflag) {
     if (vt == FREESEGVERTEX) {
-      // Check if the edge [lpr, rpt] exists.
+      // Check if the edge [lpt, 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.
@@ -22407,7 +20534,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
           // 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.
+          // Detach the subsegments from their surrounding tets.
           for (i = 0; i < 2; i++) {
             checkseg = (i == 0) ? leftseg : rightseg;
             sstpivot1(checkseg, neightet);
@@ -22440,9 +20567,6 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
           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(...))
@@ -22450,10 +20574,6 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
   } // if (!removeflag)
 
   if (!removeflag) {
-    if (b->verbose > 2) {
-      printf("      Unable to remove Steiner point %d val(%d).\n",
-             pointmark(steinerpt), valence);
-    }
     return 0;
   }
 
@@ -22510,7 +20630,8 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
     eprevself(fliptets[3]);
     esymself(fliptets[3]); // [a,b,c,p].
     // Remove p by a 4-to-1 flip.
-    flip41(fliptets, 1, 0, 0);
+    //flip41(fliptets, 1, 0, 0);
+    flip41(fliptets, 1, &fc);
     //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
@@ -22528,6 +20649,32 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
     for (i = 3; i < 5; i++) {
       fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
     }
+    if (vt == FREEFACETVERTEX) {
+      // We need to determine the location of three subfaces at p.
+      valence = 0; // Re-use it.
+      // Check if subfaces are all located in the lower three tets.
+      //   i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a].
+      for (i = 3; i < 6; i++) {
+        if (issubface(fliptets[i])) valence++;
+      }
+      if (valence > 0) {
+        assert(valence == 2);
+        // We must do 3-to-2 flip in the upper part. We simply re-arrange
+        //   the six tets.
+        for (i = 0; i < 3; i++) {
+          esym(fliptets[i+3], wrktets[i]);
+          esym(fliptets[i], fliptets[i+3]);
+          fliptets[i] = wrktets[i];
+        }
+        // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
+        wrktets[1] = fliptets[1];
+        fliptets[1] = fliptets[2];
+        fliptets[2] = wrktets[1];
+        wrktets[1] = fliptets[4];
+        fliptets[4] = fliptets[5];
+        fliptets[5] = wrktets[1];
+      }
+    }
     // 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).
@@ -22535,18 +20682,12 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
     //   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
+    //flip32(&(fliptets[3]), 1, 0, 0);
+    flip32(&(fliptets[3]), 1, &fc);
     // 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);
+    //flip41(fliptets, 1, 0, 0);
+    flip41(fliptets, 1, &fc);
     //recenttet = fliptets[0];
   } else if (loc == ONEDGE) {
     // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
@@ -22590,7 +20731,8 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
     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);
+    //flip23(wrktets, 1, 0, 0);
+    flip23(wrktets, 1, &fc);
     // Save the new tet [e,d,p,p_0] (degenerated).
     fliptets[n] = wrktets[2];
     // Save the new tet [e,d,p_0,p_1].
@@ -22613,7 +20755,8 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
       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);
+      //flip32(wrktets, 1, 0, 0);
+      flip32(wrktets, 1, &fc);
       // 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
@@ -22638,7 +20781,8 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
     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);
+    //flip41(wrktets, 1, 0, 0);
+    flip41(wrktets, 1, &fc);
     // 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];
@@ -22664,7 +20808,7 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
 
     // Insert the new segment.
     point2tetorg(lpt, searchtet);
-    finddirection(&searchtet, rpt, 1);
+    finddirection(&searchtet, rpt);
     assert(dest(searchtet) == rpt);
     sstbond1(rightseg, searchtet);
     spintet = searchtet;
@@ -22714,51 +20858,42 @@ int tetgenmesh::removevertexbyflips(point steinerpt)
   } // 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 (pointtype(steinerpt) != UNUSEDVERTEX) {
+    setpointtype(steinerpt, UNUSEDVERTEX);
+    unuverts++;
+  }
+  if (vt != VOLVERTEX) {
+    // 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++;
   }
-  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'.     //
+// suppressbdrysteinerpoint()    Suppress a boundary Steiner point           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-int tetgenmesh::suppressssteinerpoint(point steinerpt)
+int tetgenmesh::suppressbdrysteinerpoint(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;
+  face leftseg, rightseg;
+  point lpt = NULL, rpt = NULL;
+  int i;
 
-  vt = pointtype(steinerpt);
+  verttype vt = pointtype(steinerpt);
 
   if (vt == FREESEGVERTEX) {
     sdecode(point2sh(steinerpt), leftseg);
-    assert(leftseg.sh != NULL);
     leftseg.shver = 0;
     if (sdest(leftseg) == steinerpt) {
       senext(leftseg, rightseg);
@@ -22778,46 +20913,17 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
     lpt = sorg(leftseg);
     rpt = sdest(rightseg);
     if (b->verbose > 2) {
-      printf("      Suppressing point %d from segment (%d, %d).\n",
+      printf("      Suppressing Steiner point %d in 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;
+      // Orient the face consistently. 
+      if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
       spivotself(spinsh);
       if (spinsh.sh == NULL) break;
       if (spinsh.sh == parentsh.sh) break;
@@ -22827,6 +20933,198 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
       cavesegshlist->restart();
       return 0;
     }
+  } else if (vt == FREEFACETVERTEX) {
+    if (b->verbose > 2) {
+      printf("      Suppressing Steiner point %d from facet.\n",
+             pointmark(steinerpt));
+    }
+    sdecode(point2sh(steinerpt), parentsh);
+    // A facet Steiner point. There are exactly two sectors.
+    for (i = 0; i < 2; i++) {
+      cavesegshlist->newindex((void **) &parysh);
+      *parysh = parentsh;
+      sesymself(parentsh);
+    }
+  } else {
+    return 0;
+  }
+
+  triface searchtet, neightet, *parytet;
+  point pa, pb, pc, pd;
+  REAL v1[3], v2[3], len, u;
+
+  REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
+  REAL ori, minvol, smallvol;
+  int samplesize;
+  int it, j, k;
+
+  int n = (int) cavesegshlist->objects;
+  point *newsteiners = new point[n];
+  for (i = 0; i < n; i++) newsteiners[i] = NULL;
+
+  // Search for each sector an interior vertex. 
+  for (i = 0; i < cavesegshlist->objects; i++) {
+    parysh = (face *) fastlookup(cavesegshlist, i);
+    stpivot(*parysh, searchtet);
+    // Skip it if it is outside.
+    if (ishulltet(searchtet)) continue;
+    // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
+    //   opposite.  Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
+    //   Moreover, subfaces are oriented towards the interior of the ball.
+    setpoint2tet(steinerpt, encode(searchtet));
+    getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
+    // Calculate the searching vector.
+    pa = sorg(*parysh);
+    pb = sdest(*parysh);
+    pc = sapex(*parysh);
+    facenormal(pa, pb, pc, v1, 1, NULL);
+    len = sqrt(dot(v1, v1));
+    assert(len > 0.0);
+    v1[0] /= len;
+    v1[1] /= len;
+    v1[2] /= len;
+    if (vt == FREESEGVERTEX) {
+      parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
+      pd = sapex(*parysh);
+      facenormal(pb, pa, pd, v2, 1, NULL);
+      len = sqrt(dot(v2, v2));
+      assert(len > 0.0);
+      v2[0] /= len;
+      v2[1] /= len;
+      v2[2] /= len;
+      // Average the two vectors.
+      v1[0] = 0.5 * (v1[0] + v2[0]);
+      v1[1] = 0.5 * (v1[1] + v2[1]);
+      v1[2] = 0.5 * (v1[2] + v2[2]);
+    }
+    // Search the intersection of the ray starting from 'steinerpt' to
+    //   the search direction 'v1' and the shell of the half-ball.
+    // - Construct an endpoint.
+    len = distance(pa, pb);
+    v2[0] = steinerpt[0] + len * v1[0];
+    v2[1] = steinerpt[1] + len * v1[1];
+    v2[2] = steinerpt[2] + len * v1[2];
+    for (j = 0; j < cavetetlist->objects; j++) {
+      parytet = (triface *) fastlookup(cavetetlist, j);
+      pa = org(*parytet);
+      pb = dest(*parytet);
+      pc = apex(*parytet);
+      // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
+      //   is the apex, and three sides are defined by the triangle 
+      //   [pa, pb, pc].
+      ori = orient3d(steinerpt, pa, pb, v2);
+      if (ori >= 0) {
+        ori = orient3d(steinerpt, pb, pc, v2);
+        if (ori >= 0) {
+          ori = orient3d(steinerpt, pc, pa, v2);
+          if (ori >= 0) {
+            // Found! Calculate the intersection.
+            planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
+            assert(u != 0.0);
+            break;
+          }
+        }
+      }
+    } // j
+    assert(j < cavetetlist->objects); // There must be an intersection.
+    // Close the ball by adding the subfaces.
+    for (j = 0; j < caveshlist->objects; j++) {
+      parysh = (face *) fastlookup(caveshlist, j);
+      stpivot(*parysh, neightet);
+      cavetetlist->newindex((void **) &parytet);
+      *parytet = neightet;
+    }
+    // Search a best point inside the segment [startpt, steinerpt].
+    it = 0;
+    samplesize = 100;
+    v1[0] = steinerpt[0] - startpt[0];
+    v1[1] = steinerpt[1] - startpt[1];
+    v1[2] = steinerpt[2] - startpt[2];
+    minvol = -1.0;
+    while (it < 3) {
+      for (j = 1; j < samplesize - 1; j++) {
+        samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
+        samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
+        samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
+        // Find the minimum volume for 'samplept'.
+        smallvol = -1;
+        for (k = 0; k < cavetetlist->objects; k++) {
+          parytet = (triface *) fastlookup(cavetetlist, k);
+          pa = org(*parytet);
+          pb = dest(*parytet);
+          pc = apex(*parytet);
+          ori = orient3d(pb, pa, pc, samplept);
+          if (ori <= 0) {
+            break; // An invalid tet.
+          }
+          if (smallvol == -1) {
+            smallvol = ori;
+          } else {
+            if (ori < smallvol) smallvol = ori;
+          }
+        } // k
+        if (k == cavetetlist->objects) {
+          // Found a valid point. Remember it.
+          if (minvol == -1.0) {
+            candpt[0] = samplept[0];
+            candpt[1] = samplept[1];
+            candpt[2] = samplept[2];
+            minvol = smallvol;
+          } else {
+            if (minvol < smallvol) {
+              // It is a better location. Remember it.
+              candpt[0] = samplept[0];
+              candpt[1] = samplept[1];
+              candpt[2] = samplept[2];
+              minvol = smallvol;
+            } else {
+              // No improvement of smallest volume. 
+              // Since we are searching along the line [startpt, steinerpy],
+              // The smallest volume can only be decreased later.
+              break;
+            }
+          }
+        }
+      } // j
+      if (minvol > 0) break; 
+      samplesize *= 10;
+      it++;
+    } // while (it < 3)
+    if (minvol == -1.0) {
+      // Failed to find a valid point.
+      cavetetlist->restart();
+      caveshlist->restart();
+      break;
+    }
+    // Create a new Steiner point inside this section.
+    makepoint(&(newsteiners[i]), FREEVOLVERTEX);
+    newsteiners[i][0] = candpt[0];
+    newsteiners[i][1] = candpt[1];
+    newsteiners[i][2] = candpt[2];
+    cavetetlist->restart();
+    caveshlist->restart();
+  } // i
+
+  if (i < cavesegshlist->objects) {
+    // Failed to suppress the vertex.
+    for (; i > 0; i--) {
+      if (newsteiners[i - 1] != NULL) {
+        pointdealloc(newsteiners[i - 1]);
+      }
+    }
+    delete [] newsteiners;
+    cavesegshlist->restart();
+    return 0;
+  }
+
+  // Remove p from the segment or the facet.
+  triface newtet, newface, spintet;
+  face newsh, neighsh;
+  face *splitseg, checkseg;
+  int slawson = 0; // Do not do flip afterword.
+  int t1ver;
+
+  if (vt == FREESEGVERTEX) {
     // Detach 'leftseg' and 'rightseg' from their adjacent tets.
     //   These two subsegments will be deleted. 
     sstpivot1(leftseg, neightet);
@@ -22843,13 +21141,6 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
       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.
@@ -22862,27 +21153,25 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
     // 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;
+    if (!ishulltet(neightet)) {
+      // Within each tet in the ball, replace 'p' by 'np'.
+      for (j = 0; j < cavetetlist->objects; j++) {
+        parytet = (triface *) fastlookup(cavetetlist, j);
+        setoppo(*parytet, newsteiners[i]);
+      } // j
+      // Point to a parent tet.
+      parytet = (triface *) fastlookup(cavetetlist, 0);
+      setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet)); 
+      st_volref_count++;
+      if (steinerleft > 0) steinerleft--;
+    }
     // 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);
+      //assert(apex(neightet) == newpt);
       // Clear the connection at this face.
       dissolve(neightet);
       tsdissolve(neightet);
@@ -22893,12 +21182,15 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
   } // 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 {
+    if (sdest(parentsh) == steinerpt) {
+      senextself(parentsh);
+    } else if (sapex(parentsh) == steinerpt) {
+      senext2self(parentsh);
+    }
     assert(sorg(parentsh) == steinerpt);
     splitseg = NULL;
   }
@@ -22907,12 +21199,7 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
   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. 
@@ -22932,6 +21219,8 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
     sesymself(newsh);
     tsbond(neightet, newsh);
   }
+  // Temporarily increase the hullsize.
+  hullsize += (caveshbdlist->objects * 2l);
 
   if (vt == FREESEGVERTEX) {
     // Connecting new tets at the recovered segment.
@@ -22939,30 +21228,20 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
     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.
+      // Connecting two adjacent tets at this segment.
+      esymself(newtet);
       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.
@@ -22987,9 +21266,8 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
           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);
+            sstbond1(checkseg, newtet);
           }
           spivot(newsh, neighsh);
           if (neighsh.sh != NULL) {
@@ -23032,10 +21310,23 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
             neightet = searchtet;
           }
           pc = apex(newface);
-          if (pc == dummypoint) {
-            setapex(newface, apex(neightet));
+          if (apex(neightet) == steinerpt) {
+            // Exterior case. The 'neightet' is a hull tet which contain
+            //   'steinerpt'. It will be deleted after 'steinerpt' is removed. 
+            assert(pc == dummypoint);
+            caveoldtetlist->newindex((void **) &parytet);
+            *parytet = neightet;
+            // Connect newface to the adjacent hull tet of 'neightet', which
+            //   has the same edge as 'newface', and does not has 'steinerpt'.
+            fnextself(neightet);
           } else {
-            assert(pc == apex(neightet));
+            if (pc == dummypoint) {
+              if (apex(neightet) != dummypoint) {
+                setapex(newface, apex(neightet));
+                // A hull tet has turned into an interior tet.
+                hullsize--; // Must update the hullsize.
+              } 
+            }
           }
           bond(newface, neightet);
         } // if (newface.tet[newface.ver & 3] == NULL)
@@ -23053,6 +21344,16 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
   }
   caveshbdlist->restart();
 
+  if (caveoldtetlist->objects > 0l) {
+    // Delete hull tets which contain 'steinerpt'.
+    for (i = 0; i < caveoldtetlist->objects; i++) {
+      parytet = (triface *) fastlookup(caveoldtetlist, i);
+      tetrahedrondealloc(parytet->tet);
+    }
+    // Must update the hullsize.
+    hullsize -= caveoldtetlist->objects;
+    caveoldtetlist->restart();
+  }
 
   setpointtype(steinerpt, UNUSEDVERTEX);
   unuverts++;
@@ -23061,163 +21362,201 @@ int tetgenmesh::suppressssteinerpoint(point steinerpt)
   } else { // vt == FREEFACETVERTEX
     st_facref_count--;
   }
-  if (steinerleft > 0) steinerleft++;
+  if (steinerleft > 0) steinerleft++;  // We've removed a Steiner points.
 
-  if (b->verbose > 2) {
-    printf("      Duplicated %ld Steiner points.\n", 
-           suppsteinerptlist->objects - bak_supp_steiners);
+
+  point *parypt;
+  int steinercount = 0;
+
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = 100000; // Unlimited flip level.
+
+  // Try to remove newly added Steiner points.
+  for (i = 0; i < n; i++) {
+    if (newsteiners[i] != NULL) {
+      if (!removevertexbyflips(newsteiners[i])) {
+        if (b->nobisect_param > 0) { // Not -Y0
+          // Save it in subvertstack for removal.
+          subvertstack->newindex((void **) &parypt);
+          *parypt = newsteiners[i];
+        }
+        steinercount++;
+      }
+    }
+  }
+
+  b->fliplinklevel = bak_fliplinklevel;
+
+  if (steinercount > 0) {
+    if (b->verbose > 2) {
+      printf("      Added %d interior Steiner points.\n", steinercount);
+    }
   }
 
+  delete [] newsteiners;
+
   return 1;
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // suppresssteinerpoints()    Suppress Steiner points.                       //
 //                                                                           //
+// All Steiner points have been saved in 'subvertstack' in the routines      //
+// carveholes() and suppresssteinerpoint().                                  //
 // 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;
+  point rempt, *parypt;
+
+  int bak_fliplinklevel = b->fliplinklevel;
   b->fliplinklevel = 100000; // Unlimited flip level.
-  remcount = 0;
+  int suppcount = 0, remcount = 0;
+  int i;
 
-  if (b->nobisect_param > 1) { // -Y2
-    // Try to remove all the Steiner points.
+  // Try to suppress boundary Steiner points.
+  for (i = 0; i < subvertstack->objects; i++) {
+    parypt = (point *) fastlookup(subvertstack, i);
+    rempt = *parypt;
+    if (pointtype(rempt) != UNUSEDVERTEX) {
+      if ((pointtype(rempt) == FREESEGVERTEX) || 
+          (pointtype(rempt) == FREEFACETVERTEX)) {
+        if (suppressbdrysteinerpoint(rempt)) {
+          suppcount++;
+        }
+      }
+    }
+  } // i
+
+  if (suppcount > 0) {
+    if (b->verbose) {
+      printf("  Suppressed %d boundary Steiner points.\n", suppcount);
+    }
+  }
+
+  if (b->nobisect_param > 0) { // -Y1
     for (i = 0; i < subvertstack->objects; i++) {
       parypt = (point *) fastlookup(subvertstack, i);
       rempt = *parypt;
       if (pointtype(rempt) != UNUSEDVERTEX) {
-        if (removevertexbyflips(rempt)) {
-          remcount++;
+        if (pointtype(rempt) == FREEVOLVERTEX) {
+          if (removevertexbyflips(rempt)) {
+            remcount++;
+          }
         }
       }
     }
+  }
+
+  if (remcount > 0) {
     if (b->verbose) {
-      if (remcount > 0) {
-        printf("  Removed %d Steiner points.\n", remcount);
-      }
+      printf("  Removed %d interior Steiner points.\n", remcount);
     }
-    subvertstack->restart();
   }
 
-  remcount = smtcount = 0;
+  b->fliplinklevel = bak_fliplinklevel;
 
-  // 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->nobisect_param > 1) { // -Y2
+    // Smooth interior Steiner points.
+    optparameters opm;
+    triface *parytet;
+    point *ppt;
+    REAL ori;
+    int smtcount, count, ivcount;
+    int nt, j;
+
+    // Point smooth options.
+    opm.max_min_volume = 1;
+    opm.numofsearchdirs = 20;
+    opm.searchstep = 0.001;
+    opm.maxiter = 30; // Limit the maximum iterations.
 
-  if (b->verbose) {
-    if (remcount > 0) {
-      printf("  Removed %d suppressed Steiner points.\n", remcount);
-    }
-  }
+    smtcount = 0;
 
-  if (suppsteinerptlist->objects == 0l) {
-    b->fliplinklevel = bak_fliplinklevel;
-    return remcount;
-  }
+    do {
 
-  // Point smooth options.
-  opm.max_min_volume = 1;
-  opm.numofsearchdirs = 20;
-  opm.searchstep = 0.001;
+      nt = 0;
+
+      while (1) {
+        count = 0;
+        ivcount = 0; // Clear the inverted count.
+
+        for (i = 0; i < subvertstack->objects; i++) {
+          parypt = (point *) fastlookup(subvertstack, 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 = orient3dfast(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++;
+            }
+            if (opm.imprval <= 0.0) {
+              ivcount++; // The mesh contains inverted elements.
+            }
+            cavetetlist->restart();
+          }
+        } // i
 
-  nt = 0;
+        smtcount += count;
 
-  while (1) {
-    // Try to smooth volume Steiner points.
-    count = 0;
+        if (count == 0) {
+          // No point has been smoothed.
+          break;
+        }
 
-    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; 
-          }
+        nt++;
+        if (nt > 2) {
+          break; // Already three iterations.
         }
-        if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
-          count++;
+      } // while
+
+      if (ivcount > 0) {
+        // There are inverted elements!
+        if (opm.maxiter > 0) {
+          // Set unlimited smoothing steps. Try again.
+          opm.numofsearchdirs = 30;
+          opm.searchstep = 0.0001;
+          opm.maxiter = -1;
+          continue;
         }
-        cavetetlist->restart();
       }
-    } // i
-
-    smtcount += count;
 
-    if (count == 0) {
-      // No point has been smoothed.
       break;
-    }
+    } while (1); // Additional loop for (ivcount > 0)
 
-    nt++;
-    if (nt > 2) {
-      break; // Already three iterations.
+    if (ivcount > 0) {
+      printf("BUG Report!  The mesh contain inverted elements.\n");
     }
-  } // 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); 
+    if (b->verbose) {
+      if (smtcount > 0) {
+        printf("  Smoothed %d Steiner points.\n", smtcount); 
+      }
     }
-  }
+  } // -Y2
 
-  b->fliplinklevel = bak_fliplinklevel;
+  subvertstack->restart();
 
-  return smtcount;
+  return 1;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -23239,17 +21578,11 @@ void tetgenmesh::recoverboundary(clock_t& tv)
 
   // 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");
@@ -23261,29 +21594,17 @@ void tetgenmesh::recoverboundary(clock_t& tv)
   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;
-    }
+  // 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);
+    paryseg = (face *) fastlookup(subsegstack, s);
+    *paryseg = searchseg;
   }
 
   // The init number of missing segments.
@@ -23293,8 +21614,8 @@ void tetgenmesh::recoverboundary(clock_t& tv)
     autofliplinklevel = 1; // Init value.
   }
 
+  // First, trying to recover segments by only doing flips.
   while (1) {
-
     recoversegments(misseglist, 0, 0);
 
     if (misseglist->objects > 0) {
@@ -23333,8 +21654,7 @@ void tetgenmesh::recoverboundary(clock_t& tv)
   }
 
   if (misseglist->objects > 0) {
-    // There are missing segments. Increase the fliplevel.
-    nit = 0;
+    // Second, trying to recover segments by doing more flips (fullsearch).
     while (misseglist->objects > 0) {
       ms = misseglist->objects;
       for (i = 0; i < misseglist->objects; i++) {
@@ -23343,17 +21663,13 @@ void tetgenmesh::recoverboundary(clock_t& tv)
       }
       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;
-        }
+        break;
       }
     }
     if (b->verbose) {
@@ -23363,8 +21679,8 @@ void tetgenmesh::recoverboundary(clock_t& tv)
   }
 
   if (misseglist->objects > 0) {
-    // There are missing segments. Add Steiner points in volume.
-    nit = 0;
+    // Third, trying to recover segments by doing more flips (fullsearch)
+    //   and adding Steiner points in the volume.
     while (misseglist->objects > 0) {
       ms = misseglist->objects;
       for (i = 0; i < misseglist->objects; i++) {
@@ -23373,17 +21689,13 @@ void tetgenmesh::recoverboundary(clock_t& tv)
       }
       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;
-        }
+        break;
       }
     }
     if (b->verbose) {
@@ -23392,7 +21704,8 @@ void tetgenmesh::recoverboundary(clock_t& tv)
   }
 
   if (misseglist->objects > 0) {
-    // There are missing segments. Add Steiner points to split them.
+    // Last, trying to recover segments by doing more flips (fullsearch),
+    //   and adding Steiner points in the volume, and splitting segments.
     long bak_inpoly_count = st_volref_count; //st_inpoly_count;
     for (i = 0; i < misseglist->objects; i++) {
       subsegstack->newindex((void **) &paryseg);
@@ -23400,7 +21713,6 @@ void tetgenmesh::recoverboundary(clock_t& tv)
     }
     misseglist->restart();
 
-    // Recover the missing segments (with Steiner points).
     recoversegments(misseglist, 1, 2);
 
     if (b->verbose) {
@@ -23479,6 +21791,7 @@ void tetgenmesh::recoverboundary(clock_t& tv)
 
   while (1) {
     recoversubfaces(misshlist, 0);
+
     if (misshlist->objects > 0) {
       if (b->fliplinklevel >= 0) {
         break;
@@ -23553,32 +21866,18 @@ void tetgenmesh::recoverboundary(clock_t& tv)
   }
 
 
-  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 (bdrysteinerptlist->objects > 0) {
     if (b->verbose) {
-      printf("  Suppressed %ld Steiner points from boundary.\n", 
-             bak_supp_count);
+      printf("  %ld Steiner points remained in boundary.\n",
+             bdrysteinerptlist->objects);
     }
-    // The mesh contains inverted (or degenrrated) tets now.
-    checkinverttetflag = 1;
   } // if
 
 
+  // Accumulate the dynamic memory.
+  totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
+                      bdrysteinerptlist->totalmemory);
+
   delete bdrysteinerptlist;
   delete misseglist;
   delete misshlist;
@@ -23599,66 +21898,100 @@ void tetgenmesh::recoverboundary(clock_t& tv)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+
 void tetgenmesh::carveholes()
 {
-  arraypool *tetarray;
-  triface tetloop, neightet, hulltet, *parytet;
-  triface openface, casface;
-  triface *regiontets;
-  face checksh, casingout, casingin, *parysh;
+  arraypool *tetarray, *hullarray;
+  triface tetloop, neightet, *parytet, *parytet1;
+  triface *regiontets = NULL;
+  face checksh, *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;
+  point ptloop, *parypt;
+  int t1ver;
+  int i, j, k;
 
   if (!b->quiet) {
-    printf("Removing exterior tetrahedra ...\n");
+    if (b->convex) {
+      printf("Marking exterior tetrahedra ...\n");
+    } else {
+      printf("Removing exterior tetrahedra ...\n");
+    }
   }
 
   // Initialize the pool of exterior tets.
   tetarray = new arraypool(sizeof(triface), 10);
-  regiontets = NULL;
+  hullarray = new arraypool(sizeof(triface), 10);
 
-  maxattr = 0; // Choose a small number here.
-  attrnum = in->numberoftetrahedronattributes;
-
-  // Mark as infected any unprotected hull tets.
+  // Collect unprotected tets and 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) {
+    if (ishulltet(tetloop)) {
       // Is this side protected by a subface?
-      tspivot(tetloop, checksh);
-      if (checksh.sh == NULL) {
+      if (!issubface(tetloop)) {
+        // Collect an unprotected hull tet and tet.
         infect(tetloop);
-        tetarray->newindex((void **) &parytet);
+        hullarray->newindex((void **) &parytet);
         *parytet = tetloop;
+        // tetloop's face number is 11 & 3 = 3.
+        decode(tetloop.tet[3], neightet);
+        if (!infected(neightet)) {
+          infect(neightet);
+          tetarray->newindex((void **) &parytet);
+          *parytet = neightet;
+        }
       }
     }
     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;
+      if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
+        // The tet 'neightet' contain this point.
+        if (!infected(neightet)) {
+          infect(neightet);
+          tetarray->newindex((void **) &parytet);
+          *parytet = neightet;
+          // Add its adjacent tet if it is not protected.
+          if (!issubface(neightet)) {
+            decode(neightet.tet[neightet.ver & 3], tetloop);
+            if (!infected(tetloop)) {
+              infect(tetloop);
+              if (ishulltet(tetloop)) {
+                hullarray->newindex((void **) &parytet);
+              } else {
+                tetarray->newindex((void **) &parytet);
+              }
+              *parytet = tetloop;
+            }
+          }
+          else {
+            // It is protected. Check if its adjacent tet is a hull tet.
+            decode(neightet.tet[neightet.ver & 3], tetloop);
+            if (ishulltet(tetloop)) {
+              // It is hull tet, add it into the list. Moreover, the subface
+              //   is dead, i.e., both sides are in exterior.
+              if (!infected(tetloop)) {
+                infect(tetloop);
+                hullarray->newindex((void **) &parytet);
+                *parytet = tetloop;
+              }
+            }
+            if (infected(tetloop)) {
+              // Both sides of this subface are in exterior.
+              tspivot(neightet, checksh);
+              sinfect(checksh); // Only queue it once.
+              subfacstack->newindex((void **) &parysh);
+              *parysh = checksh;
+            }
+          }
+        } // if (!infected(neightet))
       } else {
         // A hole point locates outside of the convex hull.
         if (!b->quiet) {
@@ -23666,10 +21999,10 @@ void tetgenmesh::carveholes()
           printf("lies outside the convex hull.\n");
         }
       }
-    }
-  }
+    } // i
+  } // if (in->numberofholes > 0)
 
-  if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option.
+  if (b->regionattrib && (in->numberofregions > 0)) { // -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];
@@ -23678,12 +22011,8 @@ void tetgenmesh::carveholes()
       // 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) {
+      if (locate(&(in->regionlist[i]), &neightet) != 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);
@@ -23694,58 +22023,51 @@ void tetgenmesh::carveholes()
     }
   }
 
-  // Find and infect all exterior tets (in concave place and in holes).
+  // Collect 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)) {
+    j = (parytet->ver & 3); // j is the current face number.
+    // Check the other three adjacent tets.
+    for (k = 1; k < 4; k++) {
+      decode(parytet->tet[(j + k) % 4], neightet); 
+      // neightet may be a hull tet.
+      if (!infected(neightet)) {
+        // Is neightet protected by a subface.
+        if (!issubface(neightet)) {
+          // Not proected. Collect it. (It must not be a hull tet).
+          infect(neightet);
+          tetarray->newindex((void **) &parytet1);
+          *parytet1 = neightet;
+        } else {
+          // Protected. Check if it is a hull tet.
+          if (ishulltet(neightet)) {
+            // A hull tet. Collect it.
             infect(neightet);
-            tetarray->newindex((void **) &parytet);
-            *parytet = neightet;
+            hullarray->newindex((void **) &parytet1);
+            *parytet1 = neightet;
+            // Both sides of this subface are exterior.
+            tspivot(neightet, checksh);
+            // Queue this subface (to be deleted later).
+            assert(!sinfected(checksh));
+            sinfect(checksh); // Only queue it once.
+            subfacstack->newindex((void **) &parysh);
+            *parysh = checksh;
           }
         }
       } 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).
+        // Both sides of this face are in exterior.
+        // If there is a subface. It should be collected.
+        if (issubface(neightet)) {
+          tspivot(neightet, checksh);
           if (!sinfected(checksh)) {
-            sinfect(checksh); // Only queue it once.
+            sinfect(checksh);
             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;
-            }
-          }
         }
       }
-    }
-  }
+    } // j, k
+  } // i
 
   if (b->regionattrib && (in->numberofregions > 0)) {
     // Re-check saved region tets to see if they lie outside.
@@ -23760,233 +22082,283 @@ void tetgenmesh::carveholes()
     }
   }
 
-  // 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;
+  // Collect vertices which point to infected tets. These vertices
+  //   may get deleted after the removal of exterior tets.
+  //   If -Y1 option is used, collect all Steiner points for removal.
+  //   The lists 'cavetetvertlist' and 'subvertstack' are re-used.
+  points->traversalinit();
+  ptloop = pointtraverse();
+  while (ptloop != NULL) {
+    if ((pointtype(ptloop) != UNUSEDVERTEX) &&
+        (pointtype(ptloop) != DUPLICATEDVERTEX)) {
+      decode(point2tet(ptloop), neightet);
+      if (infected(neightet)) {
+        cavetetvertlist->newindex((void **) &parypt);
+        *parypt = ptloop;
       }
-    }
-    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);
+      if (b->nobisect && (b->nobisect_param > 0)) { // -Y1
+        // Queue it if it is a Steiner point.
+        if (pointmark(ptloop) > 
+              (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
+          subvertstack->newindex((void **) &parypt);
+          *parypt = ptloop;
         }
-        // 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();
+    ptloop = pointtraverse();
   }
 
-  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;
+  if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
+    // Remove exterior tets. Hull tets are updated.
+    arraypool *newhullfacearray;
+    triface hulltet, casface;
+    point pa, pb, pc;
+
+    newhullfacearray = new arraypool(sizeof(triface), 10);
+
+    // Create and save new hull tets.
+    for (i = 0; i < tetarray->objects; i++) {
+      parytet = (triface *) fastlookup(tetarray, i);
+      for (j = 0; j < 4; j++) {
+        decode(parytet->tet[j], tetloop);
+        if (!infected(tetloop)) {
+          // Found a new hull face (must be a subface).
+          tspivot(tetloop, checksh);
+          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 (k = 0; k < 3; k++) {
+            if (issubseg(tetloop)) {
+              tsspivot1(tetloop, checkseg);
+              tssbond1(hulltet, checkseg);
+              sstbond1(checkseg, hulltet);
+            }
+            enextself(tetloop);
+            eprevself(hulltet);
+          }
+          // Update the point-to-tet map.
+          setpoint2tet(pa, (tetrahedron) tetloop.tet);
+          setpoint2tet(pb, (tetrahedron) tetloop.tet);
+          setpoint2tet(pc, (tetrahedron) tetloop.tet);
+          // Save the exterior tet at this hull face. It still holds pointer
+          //   to the adjacent interior tet. Use it to connect new hull tets. 
+          newhullfacearray->newindex((void **) &parytet1);
+          parytet1->tet = parytet->tet;
+          parytet1->ver = j;
+        } // if (!infected(tetloop))
+      } // j
+    } // i
+
+    // Connect new hull tets.
+    for (i = 0; i < newhullfacearray->objects; i++) {
+      parytet = (triface *) fastlookup(newhullfacearray, i);
+      fsym(*parytet, neightet);
+      // Get the new hull tet.
+      fsym(neightet, hulltet);
+      for (j = 0; j < 3; j++) {
+        esym(hulltet, casface);
+        if (casface.tet[casface.ver & 3] == NULL) {
+          // Since the boundary of the domain may not be a manifold, we
+          //   find the adjacent hull face by traversing the tets in the
+          //   exterior (which are all infected tets).
+          neightet = *parytet;
           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);
+            fnextself(neightet);
+            if (!infected(neightet)) break;
           }
-          if (checkseg.sh != NULL) {
-            // Make sure the segment does not connect to a dead one.
-            ssbond(casingout, checkseg);
+          if (!ishulltet(neightet)) {
+            // An interior tet. Get the new hull tet.
+            fsymself(neightet);
+            esymself(neightet);
+          } 
+          // Bond them together.
+          bond(casface, neightet);
+        }
+        enextself(hulltet);
+        enextself(*parytet);
+      } // j
+    } // i
+
+    if (subfacstack->objects > 0l) {
+      // Remove all subfaces which do not attach to any tetrahedron.
+      //   Segments which are not attached to any subfaces and tets
+      //   are deleted too.
+      face casingout, casingin;
+      long delsegcount = 0l;
+
+      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)));
           }
-        } 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",
+        }
+        // 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++;
             }
-            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);
         }
-        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();
-  }
+      subfacstack->restart();
+    } // if (subfacstack->objects > 0l)
 
-  // 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 (cavetetvertlist->objects > 0l) {
+      // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
+      long delvertcount = unuverts;
+      long delsteinercount = 0l;
+
+      for (i = 0; i < cavetetvertlist->objects; i++) {
+        parypt = (point *) fastlookup(cavetetvertlist, i);
+        decode(point2tet(*parypt), neightet);
+        if (infected(neightet)) {
+          // Found an exterior vertex.
+          if (pointmark(*parypt) > 
+                (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
+            // A Steiner point.
+            if (pointtype(*parypt) == FREESEGVERTEX) {
+              st_segref_count--;
+            } else if (pointtype(*parypt) == FREEFACETVERTEX) {
+              st_facref_count--;
+            } else {
+              assert(pointtype(*parypt) == FREEVOLVERTEX);
+              st_volref_count--;
+            }
+            delsteinercount++;
+            if (steinerleft > 0) steinerleft++;
+          }
+          setpointtype(*parypt, UNUSEDVERTEX);
+          unuverts++;
         }
       }
-      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--;
+
+      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 {
-            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;
+            printf("  Removed %ld exterior input vertices.\n", 
+                   unuverts - delvertcount);
           }
         }
       }
+      cavetetvertlist->restart();
+      // Comment: 'subvertstack' will be cleaned in routine
+      //   suppresssteinerpoints().
+    } // if (cavetetvertlist->objects > 0l)
+
+    // Update the hull size.
+    hullsize += (newhullfacearray->objects - hullarray->objects);
+
+    // Delete all exterior tets and old hull tets.
+    for (i = 0; i < tetarray->objects; i++) {
+      parytet = (triface *) fastlookup(tetarray, i);
+      tetrahedrondealloc(parytet->tet);
     }
-    pa = pointtraverse();
-  }
+    tetarray->restart();
 
-  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);
-      }
+    for (i = 0; i < hullarray->objects; i++) {
+      parytet = (triface *) fastlookup(hullarray, i);
+      tetrahedrondealloc(parytet->tet);
     }
-  }
+    hullarray->restart();
+
+    delete newhullfacearray;
+  } // if (!b->convex && (tetarray->objects > 0l))
 
-  // Update the hull size.
-  hullsize += tetarray->objects;
+  if (b->convex && (tetarray->objects > 0l)) { // With -c option
+    // In this case, all exterior tets get a region marker '-1'.
+    assert(b->regionattrib > 0); // -A option must be enabled.
+    int attrnum = numelemattrib - 1;
+
+    for (i = 0; i < tetarray->objects; i++) {
+      parytet = (triface *) fastlookup(tetarray, i);
+      setelemattribute(parytet->tet, attrnum, -1);
+    }
+    tetarray->restart();
+
+    for (i = 0; i < hullarray->objects; i++) {
+      parytet = (triface *) fastlookup(hullarray, i);
+      uninfect(*parytet);
+    }
+    hullarray->restart();
 
-  // 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);
+    if (subfacstack->objects > 0l) {
+      for (i = 0; i < subfacstack->objects; i++) {
+        parysh = (face *) fastlookup(subfacstack, i);
+        suninfect(*parysh);
       }
-      enextself(hulltet);
+      subfacstack->restart();
     }
-  }
 
-  // Set region attributes (when has -A and -AA options).
-  if (b->regionattrib) {
+    if (cavetetvertlist->objects > 0l) {
+      cavetetvertlist->restart();
+    }
+  } // if (b->convex && (tetarray->objects > 0l))
 
+  if (b->regionattrib) { // With -A option.
     if (!b->quiet) {
       printf("Spreading region attributes.\n");
     }
-    regioncount = 0;
+    REAL volume;
+    int attr, maxattr = 0; // Choose a small number here.
+    int attrnum = numelemattrib - 1; 
+    // Comment: The element region marker is at the end of the list of
+    //   the element attributes.
+    int regioncount = 0;
 
     // If has user-defined region attributes.
     if (in->numberofregions > 0) {
@@ -23994,6 +22366,9 @@ void tetgenmesh::carveholes()
       for (i = 0; i < 5 * in->numberofregions; i += 5) {
         if (regiontets[i/5].tet != NULL) {
           attr = (int) in->regionlist[i + 3];
+          if (attr > maxattr) {
+            maxattr = attr;
+          }
           volume = in->regionlist[i + 4];
           tetarray->restart(); // Re-use this array.
           infect(regiontets[i/5]);
@@ -24007,81 +22382,59 @@ void tetgenmesh::carveholes()
             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)) {
+            for (k = 0; k < 4; k++) {
+              decode(tetloop.tet[k], neightet);
+              // Is the adjacent already checked?
+              if (!infected(neightet)) {
+                // Is this side protected by a subface?
+                if (!issubface(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
+            } // k
           } // 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);
+    // 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 (k = 0; k < 4; k++) {
+            decode(tetloop.tet[k], neightet);
+            // Is the adjacent tet already checked?
+            if (!infected(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);
-                }
+              if (!issubface(neightet)) {
+                infect(neightet);
+                tetarray->newindex((void **) &parytet);
+                *parytet = neightet;
               }
-            } // loc
-          }
-          attr++; // Increase the attribute.
-          regioncount++;
-        } // if (!infected(tetloop))
-        tetloop.tet = tetrahedrontraverse();
+            }
+          } // k
+        } // j
+        attr++; // Increase the attribute.
+        regioncount++;
       }
-      // Until here, every tet has a region attribute.
+      tetloop.tet = tetrahedrontraverse();
     }
+    // Until here, every tet has a region attribute.
 
     // Uninfect processed tets.
     tetrahedrons->traversalinit();
@@ -24091,45 +22444,49 @@ void tetgenmesh::carveholes()
       tetloop.tet = tetrahedrontraverse();
     }
 
-    // Mesh elements contain region attributes now.
-    in->numberoftetrahedronattributes++;
-
     if (b->verbose) {
-      assert(regioncount > 0);
+      //assert(regioncount > 0);
       if (regioncount > 1) {
         printf("  Found %d subdomains.\n", regioncount);
       } else {
-        printf("  Found 1 domain.\n");
+        printf("  Found %d domain.\n", regioncount);
       }
     }
-
   } // if (b->regionattrib)
 
-  if (b->regionattrib && (in->numberofregions > 0)) { // If has -A option.
+  if (regiontets != NULL) {
     delete [] regiontets;
   }
   delete tetarray;
+  delete hullarray;
 
-  // The mesh is non-convex now.
-  nonconvex = 1;
+  if (!b->convex) { // No -c option
+    // 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);
-    }
+    // 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) {
+        fsym(tetloop, neightet);
+        flippush(flipstack, &neightet);
+      }
+      tetloop.tet = alltetrahedrontraverse();
+    }
 
-  // Peel "slivers" off the hull.
-  lawsonflip3d(NULL, 4, 1, 0, 0);
+    flipconstraints fc;
+    fc.enqflag = 2;
+    long sliver_peel_count = lawsonflip3d(&fc);
 
-  if (b->verbose && (opt_sliver_peels > 0l)) {
-    printf("  Peeled %ld hull slivers.\n", opt_sliver_peels);
-  }
+    if (sliver_peel_count > 0l) {
+      if (b->verbose) {
+        printf("  Removed %ld hull slivers.\n", sliver_peel_count);
+      }
+    }
+    unflipqueue->restart();
+  } // if (!b->convex)
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -24153,20 +22510,33 @@ void tetgenmesh::reconstructmesh()
   REAL angtol, ang;
   int eextras, marker = 0;
   int bondflag;
+  int t1ver;
   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.
+  if (b->convex) { // -c option.
+    // Assume the mesh is convex. Exterior tets have region attribute -1.
+    assert(in->numberoftetrahedronattributes > 0);
+  } else {
+    // Assume the mesh is non-convex.
+    nonconvex = 1;
+  }
+
+  // Create a map from indices to vertices. 
   makeindex2pointmap(idx2verlist);
+  // 'idx2verlist' has length 'in->numberofpoints + 1'.
+  if (in->firstnumber == 1) {
+    idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
+  }
 
   // Allocate an array that maps each vertex to its adjacent tets.
   ver2tetarray = new tetrahedron[in->numberofpoints + 1];
-  for (i = 0; i < in->numberofpoints; i++) {
+  //for (i = 0; i < in->numberofpoints + 1; i++) {
+  for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
+    setpointtype(idx2verlist[i], VOLVERTEX); // initial type.
     ver2tetarray[i] = NULL;
   }
 
@@ -24176,7 +22546,6 @@ void tetgenmesh::reconstructmesh()
     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]);
@@ -24224,7 +22593,6 @@ void tetgenmesh::reconstructmesh()
         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'
@@ -24410,51 +22778,54 @@ void tetgenmesh::reconstructmesh()
     } // 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.
-              }
-            }
+  // 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)) {
+          // A hull face.
+          if (!b->convex) {
+            bondflag = 1;  // Insert a hull subface.
           }
-          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);
+        } else {
+          if (eextras > 0) {
+            if (elemattribute(tetloop.tet, eextras - 1) !=
+                elemattribute(checktet.tet, eextras - 1)) {
+              bondflag = 1; // Insert an interior interface.
             }
-            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();
+          }
+        }
+        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();
@@ -24488,11 +22859,8 @@ void tetgenmesh::reconstructmesh()
     subloop.sh = shellfacetraverse(subfaces);
   }
 
-  //if (b->verbose) {
-  //  printf("  Created %ld subfaces.\n", subfaces->items);
-  //}
 
-  // Segments will be introudced. 
+  // Segments will be introduced. 
   if (in->edgelist != NULL) {
     // A .edge file is given. It may contain boundary edges. Insert them.
     for (i = 0; i < in->numberofedges; i++) {
@@ -24554,90 +22922,187 @@ void tetgenmesh::reconstructmesh()
     } // 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.
+  // 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 {
+          spivot(subloop, neighsh);
+          if (shellmark(subloop) != shellmark(neighsh)) {
+            // It's an interior interface. 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 (!b->convex) {
+              // Check the dihedral angle formed by the two subfaces.
+              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);
+        }
+        if (bondflag) {
+          // Create a new segment.
+          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, 0); // Initially has no 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);
             }
-            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);
-    }
+            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);
+    } // i
+    subloop.sh = shellfacetraverse(subfaces);
+  }
 
   // Remember the number of input segments.
   insegments = subsegs->items;
 
-  //if (b->verbose) {
-  //  printf("  Created %ld segments.\n", subsegs->items);
-  //}
+  if (!b->nobisect || checkconstraints) {
+    // Mark Steiner points on segments and facets.
+    //   - all vertices which remaining type FEACTVERTEX become
+    //     Steiner points in facets (= FREEFACERVERTEX).
+    //   - vertices on segment need to be checked.
+    face* segperverlist;
+    int* idx2seglist;
+    face parentseg, nextseg;
+    verttype vt;
+    REAL area, len, l1, l2;
+    int fmarker;
+
+    makepoint2submap(subsegs, idx2seglist, segperverlist);
+
+    points->traversalinit();
+    point ptloop = pointtraverse();
+    while (ptloop != NULL) {
+      vt = pointtype(ptloop);
+      if (vt == VOLVERTEX) {
+        setpointtype(ptloop, FREEVOLVERTEX);
+        st_volref_count++;
+      } else if (vt == FACETVERTEX) {
+        setpointtype(ptloop, FREEFACETVERTEX);
+        st_facref_count++;
+      } else if (vt == RIDGEVERTEX) {
+        idx = pointmark(ptloop) - in->firstnumber;
+        if ((idx2seglist[idx + 1] - idx2seglist[idx]) == 2) {
+          i = idx2seglist[idx];
+          parentseg = segperverlist[i];
+          nextseg = segperverlist[i + 1];
+          sesymself(nextseg);
+          p[0] = sorg(nextseg);
+          p[1] = sdest(parentseg);
+          // Check if three points p[0], ptloop, p[2] are (nearly) collinear.
+          len = distance(p[0], p[1]);
+          l1 = distance(p[0], ptloop);
+          l2 = distance(ptloop, p[1]);
+          if (((l1 + l2 - len) / len) < b->epsilon) {
+            // They are (nearly) collinear.
+            setpointtype(ptloop, FREESEGVERTEX);
+            // Connect nextseg and parentseg together at ptloop.
+            senextself(nextseg);
+            senext2self(parentseg);
+            sbond(nextseg, parentseg);
+            st_segref_count++;
+          }
+        }
+      }
+      ptloop = pointtraverse();
+    }
+
+    // Are there area constraints?
+    if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
+      // Set maximum area constraints on facets.
+      for (i = 0; i < in->numberoffacetconstraints; i++) {
+        fmarker = (int) in->facetconstraintlist[i * 2];
+        area = in->facetconstraintlist[i * 2 + 1];
+        subfaces->traversalinit();
+        subloop.sh = shellfacetraverse(subfaces);
+        while (subloop.sh != NULL) {
+          if (shellmark(subloop) == fmarker) {
+            setareabound(subloop, area);
+          }
+          subloop.sh = shellfacetraverse(subfaces);
+        }
+      }
+    }
+
+    // Are there length constraints?
+    if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
+      // Set maximum length constraints on segments.
+      int e1, e2;
+      for (i = 0; i < in->numberofsegmentconstraints; i++) {
+        e1 = (int) in->segmentconstraintlist[i * 3];
+        e2 = (int) in->segmentconstraintlist[i * 3 + 1];
+        len = in->segmentconstraintlist[i * 3 + 2];
+        // Search for edge [e1, e2].
+        idx = e1 - in->firstnumber;
+        for (j = idx2seglist[idx]; j <  idx2seglist[idx + 1]; j++) {
+          parentseg = segperverlist[j];
+          if (pointmark(sdest(parentseg)) == e2) {
+            setareabound(parentseg, len);
+            break;
+          }
+        }
+      }
+    }
+
+    delete [] idx2seglist;
+    delete [] segperverlist;
+  }
+
 
   // Set global flags.
   checksubsegflag = 1;
   checksubfaceflag = 1;
-  //nonconvex = 1; 
 
   delete [] idx2verlist;
   delete [] ver2tetarray;
@@ -24659,33 +23124,37 @@ 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;
+  REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
+  int t1ver;
 
-  if (searchtet->tet == NULL) {
-    *searchtet = recenttet;
+
+  // Randomly select a good starting tet.
+  if (randflag) {
+    randomsample(searchpt, searchtet);
+  } else {
+    if (searchtet->tet == NULL) {
+      *searchtet = recenttet;
+    }
   }
+  loc = locate(searchpt, searchtet);
 
-  iter = 0;
-  while (1) {
-    // Randonmly select a good starting tet.
-    if (randflag) {
-      randomsample(searchpt, searchtet);
+  if (loc == OUTSIDE) {
+    if (b->convex) { // -c option
+      // The point lies outside of the convex hull.
+      return (int) loc;
     }
-    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;
+    // Test if it lies nearly on the hull face.
+    // Reuse vol, ori1.
+    pa = org(*searchtet);
+    pb = dest(*searchtet);
+    pc = apex(*searchtet);
+    vol = triarea(pa, pb, pc);
+    ori1 = orient3dfast(pa, pb, pc, searchpt);
+    if (fabs(ori1 / vol) < b->epsilon) {
+      loc = ONFACE; // On face (or on edge, or on vertex).
+      fsymself(*searchtet);
     }
-  } // while (1)
+  }
 
   if (loc != OUTSIDE) {
     // Round the result of location.
@@ -24693,11 +23162,11 @@ int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
     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);
+    vol = orient3dfast(pa, pb, pc, pd);
+    ori1 = orient3dfast(pa, pb, pc, searchpt);
+    ori2 = orient3dfast(pb, pa, pd, searchpt);
+    ori3 = orient3dfast(pc, pb, pd, searchpt);
+    ori4 = orient3dfast(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;
@@ -24712,30 +23181,31 @@ int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
       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
+      vol = orient3dfast(pa, pb, pc, pd); 
+      if (vol < 0) {
+        ori1 = orient3dfast(pa, pb, pc, searchpt);
+        if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
+        if (ori1 <= 0) {
+          ori2 = orient3dfast(pb, pa, pd, searchpt);
+          if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
+          if (ori2 <= 0) {
+            ori3 = orient3dfast(pc, pb, pd, searchpt);
+            if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
+            if (ori3 <= 0) {
+              ori4 = orient3dfast(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();
+      searchtet->tet = tetrahedrontraverse();
     } // while (searchtet->tet != NULL)
+    nonregularcount++;  // Re-use this counter.
   }
 
   if (searchtet->tet != NULL) {
@@ -24824,13 +23294,9 @@ int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
 // '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)
+REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
 {
   point *pts, pa, pb, pc;
   REAL volume, vol[4], wei[4];
@@ -24842,15 +23308,15 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc,
   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))) {
+    // Only do interpolation if all vertices have non-zero sizes.
+    if ((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);
+      volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
+      vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
+      vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
+      vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
+      vol[3] = orient3dfast(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]);
@@ -24860,9 +23326,8 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc,
     pa = org(*searchtet);
     pb = dest(*searchtet);
     pc = apex(*searchtet);
-    if (!posflag ||
-        ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
-         (pc[pointmtrindex] > 0))) {
+    if ((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);
@@ -24874,7 +23339,7 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc,
   } else if (iloc == (int) ONEDGE) {
     pa = org(*searchtet);
     pb = dest(*searchtet);
-    if (!posflag || ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0))) {
+    if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
       volume = distance(pa, pb);
       vol[0] = distance(searchpt, pb);
       vol[1] = distance(pa, searchpt);
@@ -24883,7 +23348,7 @@ REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc,
     }
   } else if (iloc == (int) ONVERTEX) {
     pa = org(*searchtet);
-    if (!posflag || (pa[pointmtrindex] > 0)) {
+    if (pa[pointmtrindex] > 0) {
       size = pa[pointmtrindex];
     }
   }
@@ -24909,6 +23374,11 @@ void tetgenmesh::interpolatemeshsize()
   if (!b->quiet) {
     printf("Interpolating mesh size ...\n");
   }
+
+  long bak_nonregularcount = nonregularcount;
+  nonregularcount = 0l; // Count the number of (slow) global searches.
+  long baksmaples = bgm->samples;
+  bgm->samples = 3l;
   count = 0; // Count the number of interpolated points.
 
   // Interpolate sizes for all points in the current mesh.
@@ -24919,8 +23389,8 @@ void tetgenmesh::interpolatemeshsize()
     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);
+      // Interpolate the mesh size.
+      ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
       setpoint2bgmtet(ploop, bgm->encode(searchtet));
       if (count == 0) {
         // This is the first interpolated point.
@@ -24945,152 +23415,470 @@ void tetgenmesh::interpolatemeshsize()
 
   if (b->verbose) {
     printf("  Interoplated %d points.\n", count);
+    if (nonregularcount > 0l) {
+      printf("  Performed %ld brute-force searches.\n", nonregularcount);
+    }
     printf("  Size rangle [%.17g, %.17g].\n", minval, maxval);
   }
-}
 
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// insertconstrainedpoints()    Insert a list of points into the mesh.       //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
+  bgm->samples = baksmaples;
+  nonregularcount = bak_nonregularcount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// insertconstrainedpoints()    Insert a list of points into the mesh.       //
+//                                                                           //
+// Assumption:  The bounding box of the insert point set should be no larger //
+// than the bounding box of the mesh.  (Required by point sorting).          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen,
+                                         int rejflag)
+{
+  triface searchtet, spintet;
+  face splitsh;
+  face splitseg;
+  insertvertexflags ivf;
+  flipconstraints fc;
+  int randflag = 0;
+  int t1ver;
+  int i;
+
+  if (b->verbose) {
+    printf("  Inserting %d constrained points\n", arylen);
+  }
+
+  if (b->no_sort) { // -b/1 option.
+    if (b->verbose) {
+      printf("  Using the input order.\n"); 
+    }
+  } else {
+    if (b->verbose) {
+      printf("  Permuting vertices.\n"); 
+    }
+    point swappoint;
+    int randindex;
+    srand(arylen);
+    for (i = 0; i < arylen; i++) {
+      randindex = rand() % (i + 1); 
+      swappoint = insertarray[i];
+      insertarray[i] = insertarray[randindex];
+      insertarray[randindex] = swappoint;
+    }
+    if (b->brio_hilbert) { // -b1 option
+      if (b->verbose) {
+        printf("  Sorting vertices.\n"); 
+      }
+      hilbert_init(in->mesh_dim);
+      int ngroup = 0; 
+      brio_multiscale_sort(insertarray, arylen, b->brio_threshold, 
+                           b->brio_ratio, &ngroup);
+    } else { // -b0 option.
+      randflag = 1;
+    } // if (!b->brio_hilbert)
+  } // if (!b->no_sort)
+
+  long bak_nonregularcount = nonregularcount;
+  nonregularcount = 0l;
+  long baksmaples = samples;
+  samples = 3l; // Use at least 3 samples. Updated in randomsample().
+
+  long bak_seg_count = st_segref_count;
+  long bak_fac_count = st_facref_count;
+  long bak_vol_count = st_volref_count;
+
+  // Initialize the insertion parameters. 
+  if (b->incrflip) { // -l option
+    // Use incremental flip algorithm.
+    ivf.bowywat = 0; 
+    ivf.lawson = 1;
+    ivf.validflag = 0; // No need to validate the cavity.
+    fc.enqflag = 2;
+  } else {
+    // Use Bowyer-Watson algorithm.
+    ivf.bowywat = 1; 
+    ivf.lawson = 0;
+    ivf.validflag = 1; // Validate the B-W cavity.
+  }
+  ivf.rejflag = rejflag;
+  ivf.chkencflag = 0; 
+  ivf.sloc = (int) INSTAR;
+  ivf.sbowywat = 3; 
+  ivf.splitbdflag = 1;
+  ivf.respectbdflag = 1;
+  ivf.assignmeshsize = b->metric;
+
+  encseglist = new arraypool(sizeof(face), 8);
+  encshlist = new arraypool(sizeof(badface), 8);
+
+  // Insert the points.
+  for (i = 0; i < arylen; i++) {
+    // Find the location of the inserted point.
+    // Do not use 'recenttet', since the mesh may be non-convex.
+    searchtet.tet = NULL; 
+    ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
+
+    // Decide the right type for this point.
+    setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
+    splitsh.sh = NULL;
+    splitseg.sh = NULL;
+    if (ivf.iloc == (int) ONEDGE) {
+      if (issubseg(searchtet)) {
+        tsspivot1(searchtet, splitseg);
+        setpointtype(insertarray[i], FREESEGVERTEX);
+        //ivf.rejflag = 0;
+      } else {
+        // Check if it is a subface edge.
+        spintet = searchtet;
+        while (1) {
+          if (issubface(spintet)) {
+            tspivot(spintet, splitsh);
+            setpointtype(insertarray[i], FREEFACETVERTEX);
+            //ivf.rejflag |= 1;
+            break;
+          }
+          fnextself(spintet);
+          if (spintet.tet == searchtet.tet) break;
+        }
+      }
+    } else if (ivf.iloc == (int) ONFACE) {
+      if (issubface(searchtet)) {
+        tspivot(searchtet, splitsh);
+        setpointtype(insertarray[i], FREEFACETVERTEX);
+        //ivf.rejflag |= 1;
+      }
+    }
+
+    // Now insert the point.
+    if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
+      if (flipstack != NULL) {
+        // There are queued faces. Use flips to recover Delaunayness.
+        lawsonflip3d(&fc);
+        // There may be unflippable edges. Ignore them.
+        unflipqueue->restart();
+      }
+      // Update the Steiner counters.
+      if (pointtype(insertarray[i]) == FREESEGVERTEX) {
+        st_segref_count++;
+      } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
+        st_facref_count++;
+      } else {
+        st_volref_count++;
+      }
+    } else {
+      // Point is not inserted.
+      //pointdealloc(insertarray[i]);
+      setpointtype(insertarray[i], UNUSEDVERTEX);
+      unuverts++;
+      encseglist->restart();
+      encshlist->restart();
+    }
+  } // i
+
+  delete encseglist;
+  delete encshlist;
+
+  if (b->verbose) {
+    printf("  Inserted %ld (%ld, %ld, %ld) vertices.\n", 
+           st_segref_count + st_facref_count + st_volref_count - 
+           (bak_seg_count + bak_fac_count + bak_vol_count),
+           st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
+           st_volref_count - bak_vol_count);
+    if (nonregularcount > 0l) {
+      printf("  Performed %ld brute-force searches.\n", nonregularcount);
+    }
+  }
+
+  nonregularcount = bak_nonregularcount;
+  samples = baksmaples; 
+}
 
 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;
+  point *insertarray, newpt;
+  REAL x, y, z, w;
+  int index, attribindex, mtrindex;
+  int arylen, i, j;
 
   if (!b->quiet) {
     printf("Inserting constrained points ...\n");
   }
 
-  randflag = 1; // Randomly select start tet for point location. 
-  count = 0;
+  insertarray = new point[addio->numberofpoints];
+  arylen = 0;
   index = 0;
+  attribindex = 0;
+  mtrindex = 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++];
+    x = addio->pointlist[index++];
+    y = addio->pointlist[index++];
+    z = addio->pointlist[index++];
+    // Test if this point lies inside the bounding box.
+    if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
+        (z < zmin) || (z > zmax)) {
+      if (b->verbose) {
+        printf("Warning:  Point #%d lies outside the bounding box. Ignored\n",
+               i + in->firstnumber);
+      }
+      continue;
+    }
+    makepoint(&newpt, UNUSEDVERTEX);
+    newpt[0] = x;
+    newpt[1] = y;
+    newpt[2] = z;
+    // Read the point attributes. (Including point weights.)
+    for (j = 0; j < addio->numberofpointattributes; j++) {
+      newpt[3 + j] = addio->pointattributelist[attribindex++];
+    }
+    // Read the point metric tensor.
+    for (j = 0; j < addio->numberofpointmtrs; j++) {
+      newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
+    }
     if (b->weighted) { // -w option
       if (addio->numberofpointattributes > 0) {
-        // The first point attribute is weight.
-        w = addio->pointattributelist[addio->numberofpointattributes * i];
+        // The first point attribute is its weight.
+        w = newpt[3];
       } else {
-        // No given weight available.
-        w = 0;
+        // No given weight available. Default choose the maximum
+        //   absolute value among its coordinates.        
+        w = fabs(x);
+        if (w < fabs(y)) w = fabs(y);
+        if (w < fabs(z)) w = fabs(z);
       }
       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];
+    insertarray[arylen] = newpt;
+    arylen++;
+  } // i
+
+  // Insert the points.
+  int rejflag = 0;  // Do not check encroachment.
+  if (b->metric) { // -m option.
+    rejflag |= 4; // Reject it if it lies in some protecting balls.
+  }
+
+  insertconstrainedpoints(insertarray, arylen, rejflag);
+
+  delete [] insertarray;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// meshcoarsening()    Deleting (selected) vertices.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::collectremovepoints(arraypool *remptlist)
+{
+  point ptloop, *parypt;
+  verttype vt;
+
+  // If a mesh sizing function is given. Collect vertices whose mesh size
+  //   is greater than its smallest edge length.
+  if (b->metric) { // -m option
+    REAL len, smlen;
+    int i;
+    points->traversalinit();
+    ptloop = pointtraverse();
+    while (ptloop != NULL) {
+      if (ptloop[pointmtrindex] > 0) {
+        // Get the smallest edge length at this vertex.
+        getvertexstar(1, ptloop, cavetetlist, cavetetvertlist, NULL);
+        parypt = (point *) fastlookup(cavetetvertlist, 0);
+        smlen = distance(ptloop, *parypt);
+        for (i = 1; i < cavetetvertlist->objects; i++) {
+          parypt = (point *) fastlookup(cavetetvertlist, i);
+          len = distance(ptloop, *parypt);
+          if (len < smlen) {
+            smlen = len;
+          }
+        }
+        cavetetvertlist->restart();
+        cavetetlist->restart();
+        if (smlen < ptloop[pointmtrindex]) {
+          pinfect(ptloop);
+          remptlist->newindex((void **) &parypt);
+          *parypt = ptloop;
         }
       }
+      ptloop = pointtraverse();
     }
-    // Read the point metric tensor.
-    //for (j = 0; j < in->numberofpointmtrs; j++) {
-    //  pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
-    //}
+    if (b->verbose > 1) {
+      printf("    Coarsen %ld oversized points.\n", remptlist->objects); 
+    }
+  }
 
-    // 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;
+  // If 'in->pointmarkerlist' exists, Collect vertices with markers '-1'.
+  if (in->pointmarkerlist != NULL) {
+    long bak_count = remptlist->objects;
+    points->traversalinit();
+    ptloop = pointtraverse();
+    int index = 0;
+    while (ptloop != NULL) {
+      if (index < in->numberofpoints) {
+        if (in->pointmarkerlist[index] == -1) {
+          pinfect(ptloop);
+          remptlist->newindex((void **) &parypt);
+          *parypt = ptloop;
         }
+      } else {
+        // Remaining are not input points. Stop here.
+        break; 
       }
+      index++;
+      ptloop = pointtraverse();
+    }
+    if (b->verbose > 1) {
+      printf("    Coarsen %ld marked points.\n", remptlist->objects - bak_count); 
+    }
+  } // if (in->pointmarkerlist != NULL)
+
+  if (b->coarsen_param > 0) { // -R1/#
+    // Remove a coarsen_percent number of interior points.
+    assert((b->coarsen_percent > 0) && (b->coarsen_percent <= 1.0));
+    if (b->verbose > 1) {
+      printf("    Coarsen %g percent of interior points.\n", 
+             b->coarsen_percent * 100.0);
+    }
+    arraypool *intptlist = new arraypool(sizeof(point *), 10);
+    // Count the total number of interior points.
+    points->traversalinit();
+    ptloop = pointtraverse();
+    while (ptloop != NULL) {
+      vt = pointtype(ptloop);
+      if ((vt == VOLVERTEX) || (vt == FREEVOLVERTEX) || 
+          (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX)) {
+        intptlist->newindex((void **) &parypt);
+        *parypt = ptloop;
+      }
+      ptloop = pointtraverse();
+    }
+    if (intptlist->objects > 0l) {
+      // Sort the list of points randomly.
+      point *parypt_i, swappt;
+      int randindex, i;
+      srand(intptlist->objects);
+      for (i = 0; i < intptlist->objects; i++) {
+        randindex = rand() % (i + 1); // randomnation(i + 1);
+        parypt_i = (point *) fastlookup(intptlist, i); 
+        parypt = (point *) fastlookup(intptlist, randindex);
+        // Swap this two points.
+        swappt = *parypt_i;
+        *parypt_i = *parypt;
+        *parypt = swappt;
+      }
+      int remcount = (int) ((REAL) intptlist->objects * b->coarsen_percent);
+      // Return the first remcount points.
+      for (i = 0; i < remcount; i++) {
+        parypt_i = (point *) fastlookup(intptlist, i);
+        if (!pinfected(*parypt_i)) {
+          pinfected(*parypt_i);
+          remptlist->newindex((void **) &parypt);
+          *parypt = *parypt_i;
+        }
+      }
+    }
+    delete intptlist;
+  }
+
+  // Unmark all collected vertices.
+  for (int i = 0; i < remptlist->objects; i++) {
+    parypt = (point *) fastlookup(remptlist, i);
+    puninfect(*parypt);
+  }
+}
 
-      // Insert the vertex.
-      loc = insertvertex(newpt, &searchtet, splitsh, splitseg, &ivf);
+void tetgenmesh::meshcoarsening()
+{
+  arraypool *remptlist;
 
-      if (loc == ivf.iloc) {
-        // The point has been inserted.
-        lawsonflip3d(newpt, 4, 0, ivf.chkencflag, 0);
-        count++;
+  if (!b->quiet) {
+    printf("Mesh coarsening ...\n");
+  }
+
+  // Collect the set of points to be removed
+  remptlist = new arraypool(sizeof(point *), 10);
+  collectremovepoints(remptlist);
+
+  if (remptlist->objects == 0l) {
+    delete remptlist;
+    return;
+  }
+
+  if (b->verbose) {
+    if (remptlist->objects > 0l) {
+      printf("  Removing %ld points...\n", remptlist->objects);
+    }
+  }
+
+  point *parypt, *plastpt;
+  long ms = remptlist->objects;
+  int nit = 0; 
+  int bak_fliplinklevel = b->fliplinklevel;
+  b->fliplinklevel = -1;
+  autofliplinklevel = 1; // Init value.
+  int i;
+
+  while (1) {
+  
+    if (b->verbose > 1) {
+      printf("    Removing points [%s level = %2d] #:  %ld.\n", 
+             (b->fliplinklevel > 0) ? "fixed" : "auto",
+             (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
+             remptlist->objects);
+    }
+
+    // Remove the list of points.
+    for (i = 0; i < remptlist->objects; i++) {
+      parypt = (point *) fastlookup(remptlist, i);
+      assert(pointtype(*parypt) != UNUSEDVERTEX);
+      if (removevertexbyflips(*parypt)) {
+        // Move the last entry to the current place.
+        plastpt = (point *) fastlookup(remptlist, remptlist->objects - 1);
+        *parypt = *plastpt;
+        remptlist->objects--;
+        i--;
+      }
+    }
+
+    if (remptlist->objects > 0l) {
+      if (b->fliplinklevel >= 0) {
+        break; // We have tried all levels.
+      }
+      if (remptlist->objects == ms) {
+        nit++;
+        if (nit >= 3) {
+          // Do the last round with unbounded flip link level.
+          b->fliplinklevel = 100000;
+        }
       } else {
-        if (!b->quiet) {
-          printf("Warning:  Failed to insert point #%d. Ignored.\n", i);
+        ms = remptlist->objects;
+        if (nit > 0) {
+          nit--;
         }
-        pointdealloc(newpt);
       }
+      autofliplinklevel+=b->fliplinklevelinc;
     } else {
-      if (!b->quiet) {
-        printf("Warning:  Can't locate add point #%d. Ignored.\n", i);
-      }
-      pointdealloc(newpt);
+      // All points are removed.
+      break;
     }
-  } // i
+  } // while (1)
 
-  if (b->verbose) {
-    printf("  Inserted %d of %d vertices.\n", count, addio->numberofpoints);
+  if (remptlist->objects > 0l) {
+    if (b->verbose) {
+      printf("  %ld points are not removed !\n", remptlist->objects);
+    }
   }
+
+  b->fliplinklevel = bak_fliplinklevel;
+  delete remptlist;
 }
 
 ////                                                                       ////
@@ -25103,557 +23891,198 @@ void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// marksharpsegments()    Mark sharp segments.                               //
-//                                                                           //
-// All segments are initialized as type NSHARP.                              //
+// makefacetverticesmap()    Create a map from facet to its vertices.        //
 //                                                                           //
-// 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.  //
+// All facets will be indexed (starting from 0).  The map is saved in two    //
+// global arrays: 'idx2facetlist' and 'facetverticeslist'.                   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::marksharpsegments()
+void tetgenmesh::makefacetverticesmap()
 {
-  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;
+  arraypool *facetvertexlist, *vertlist, **paryvertlist;
+  face subloop, neighsh, *parysh, *parysh1;
+  point pa, *ppt, *parypt;
+  verttype vt;
+  int facetindex, totalvertices;
   int i, j, k;
 
-  if (b->verbose > 0) {
-    printf("  Marking sharp segments.\n");
+  if (b->verbose) {
+    printf("  Creating the facet vertices map.\n");
   }
 
-  minfacetdihed = PI;
-  smallang = 65.0 * PI / 180.0; // 65 degree.
-  exsmallang = 15.0 * PI / 180.0; // 15 degree.
-  sharpcount = exsharpcount = 0;
+  facetvertexlist = new arraypool(sizeof(arraypool *), 10);
+  facetindex = totalvertices = 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++;
+  subfaces->traversalinit();
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != NULL) {
+    if (!sinfected(subloop)) {
+      // A new facet. Create its vertices list.
+      vertlist = new arraypool(sizeof(point *), 8);
+      ppt = (point *) &(subloop.sh[3]);
+      for (k = 0; k < 3; k++) {
+        vt = pointtype(ppt[k]);
+        if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
+          pinfect(ppt[k]);
+          vertlist->newindex((void **) &parypt);
+          *parypt = ppt[k];
+        }
+      }
+      sinfect(subloop);
+      caveshlist->newindex((void **) &parysh);
+      *parysh = subloop;
+      for (i = 0; i < caveshlist->objects; i++) {
+        parysh = (face *) fastlookup(caveshlist, i);
+        setfacetindex(*parysh, facetindex);
+        for (j = 0; j < 3; j++) {
+          if (!isshsubseg(*parysh)) {
+            spivot(*parysh, neighsh);
+            assert(neighsh.sh != NULL);
+            if (!sinfected(neighsh)) {
+              pa = sapex(neighsh);
+              if (!pinfected(pa)) {
+                vt = pointtype(pa);
+                if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
+                  pinfect(pa);
+                  vertlist->newindex((void **) &parypt);
+                  *parypt = pa;
                 }
               }
-            }
-          }
-          // 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);
+              sinfect(neighsh);
               caveshlist->newindex((void **) &parysh1);
               *parysh1 = neighsh;
             }
           }
-          senextself(spinsh);
-        } // k
-      } // j
+          senextself(*parysh);
+        }
+      } // i
+      totalvertices += (int) vertlist->objects;
+      // Uninfect facet vertices.
+      for (k = 0; k < vertlist->objects; k++) {
+        parypt = (point *) fastlookup(vertlist, k);
+        puninfect(*parypt);
+      }
       caveshlist->restart();
-    } // i
-    cavesegshlist->restart();
-  } // if (cavesegshlist->objects > 0)
+      // Save this vertex list.
+      facetvertexlist->newindex((void **) &paryvertlist);
+      *paryvertlist = vertlist;
+      facetindex++;
+    } 
+    subloop.sh = shellfacetraverse(subfaces);
+  }
+
+  // All subfaces are infected. Uninfect them.
+  subfaces->traversalinit();
+  subloop.sh = shellfacetraverse(subfaces);
+  while (subloop.sh != NULL) {
+    assert(sinfected(subloop));
+    suninfect(subloop);
+    subloop.sh = shellfacetraverse(subfaces);
+  }
 
   if (b->verbose) {
-    if (sharpcount > 0) {
-      printf("  Found %d (%d) sharp segments.\n", sharpcount, exsharpcount);
+    printf("  Found %ld facets.\n", facetvertexlist->objects);
+  }
+
+  idx2facetlist = new int[facetindex + 1];
+  facetverticeslist = new point[totalvertices];
+
+  totalworkmemory += ((facetindex + 1) * sizeof(int) + 
+                      totalvertices * sizeof(point *));
+
+  idx2facetlist[0] = 0;
+  for (i = 0, k = 0; i < facetindex; i++) {
+    paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
+    vertlist = *paryvertlist;
+    idx2facetlist[i + 1] = (idx2facetlist[i] + (int) vertlist->objects);
+    for (j = 0; j < vertlist->objects; j++) {
+      parypt = (point *) fastlookup(vertlist, j);
+      facetverticeslist[k] = *parypt;
+      k++;
     }
-    printf("  Minimum fac-fac angle = %g.\n", minfacetdihed / PI * 180.0);
   }
+  assert(k == totalvertices);
+
+  // Free the lists.
+  for (i = 0; i < facetvertexlist->objects; i++) {
+    paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
+    vertlist = *paryvertlist;
+    delete vertlist;
+  }
+  delete facetvertexlist;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// 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.                 //
+// Check whether two segments, or a segment and a facet, or two facets are   //
+// adjacent to each other.                                                   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::decidefeaturepointsizes()
+int tetgenmesh::segsegadjacent(face *seg1, face *seg2)
 {
-  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;
+  int segidx1 = getfacetindex(*seg1);
+  int segidx2 = getfacetindex(*seg2);
 
-  if (b->verbose > 0) {
-    printf("  Deciding feature-point sizes.\n");
-  }
+  if (segidx1 == segidx2) return 0;
 
-  // Initialize working lists.
-  tetlist = cavetetlist;
-  verlist = cavetetvertlist;
+  point pa1 = segmentendpointslist[segidx1 * 2];
+  point pb1 = segmentendpointslist[segidx1 * 2 + 1];
+  point pa2 = segmentendpointslist[segidx2 * 2];
+  point pb2 = segmentendpointslist[segidx2 * 2 + 1];
 
-  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);
+  if ((pa1 == pa2) || (pa1 == pb2) || (pb1 == pa2) || (pb1 == pb2)) {
+    return 1;
   }
+  return 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();
-  }
+int tetgenmesh::segfacetadjacent(face *subseg, face *subsh)
+{
+  int segidx = getfacetindex(*subseg);
+  point pa = segmentendpointslist[segidx * 2];
+  point pb = segmentendpointslist[segidx * 2 + 1];
 
-  if (b->verbose) {
-    printf("  %d feature points.\n", featurecount);
-  }
+  pinfect(pa);
+  pinfect(pb);
 
-  // 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();
+  int fidx = getfacetindex(*subsh);
+  int count = 0, i;
+
+  for (i = idx2facetlist[fidx]; i < idx2facetlist[fidx+1]; i++) {
+    if (pinfected(facetverticeslist[i])) count++;
+  } 
+
+  puninfect(pa);
+  puninfect(pb);
+
+  return count == 1;
+}
+
+int tetgenmesh::facetfacetadjacent(face *subsh1, face *subsh2)
+{
+  int count = 0, i;
+
+  int fidx1 = getfacetindex(*subsh1);
+  int fidx2 = getfacetindex(*subsh2);
+
+  if (fidx1 == fidx2) return 0;
+
+  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
+    pinfect(facetverticeslist[i]);
   }
 
-  if (b->verbose && (featurecount > 0)) {
-    printf("  %d Steiner feature points.\n", featurecount);
+  for (i = idx2facetlist[fidx2]; i < idx2facetlist[fidx2+1]; i++) {
+    if (pinfected(facetverticeslist[i])) count++;
   }
 
-  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)
+  // Uninfect the vertices.
+  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
+    puninfect(facetverticeslist[i]);
+  }
+
+  return count > 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -25664,22 +24093,24 @@ void tetgenmesh::decidefeaturepointsizes()
 
 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).
+  REAL v1[3], v2[3];
+
+  v1[0] = pa[0] - checkpt[0];
+  v1[1] = pa[1] - checkpt[1];
+  v1[2] = pa[2] - checkpt[2];
+  v2[0] = pb[0] - checkpt[0];
+  v2[1] = pb[1] - checkpt[1];
+  v2[2] = pb[2] - checkpt[2];
 
-  if (ang > PI) {
+  if (dot(v1, v2) < 0) {
     // Inside.
-    if (b->metric || b->nobisect) { // -m or -Y option.
+    if (b->metric) { // -m 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.
+        // The projection of 'checkpt' lies inside the segment [a,b].
+        REAL prjpt[3], u, v, t;
         projpt2edge(checkpt, pa, pb, prjpt);
-        // Get the mesh size at the location 'prjpt'.
+        // Interoplate the mesh size at the location 'prjpt'.
         u = distance(pa, pb);
         v = distance(pa, prjpt);
         t = v / u;
@@ -25707,6 +24138,7 @@ int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
 // 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).                                       //
+//  (3) Its length is larger than the mesh sizes at its endpoints.           //
 //                                                                           //
 // 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  //
@@ -25716,21 +24148,11 @@ int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
 
 int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
 {
-  triface searchtet, spintet;
-  point forg, fdest, eapex;
-  REAL ccent[3], len, r, d, diff;
+  REAL ccent[3], len, r;
   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));
-  }
+  point forg = sorg(*chkseg);
+  point fdest = sdest(*chkseg);
 
   // Initialize the return values.
   encpt = NULL;
@@ -25745,21 +24167,13 @@ int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
   // 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 (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;
     }
@@ -25774,33 +24188,15 @@ int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
     }
   }
 
-  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.
+  // Comment: There may exist more than one encroaching points of this segment. 
+  //   The 'encpt' returns the one which is closet to it.
+  triface searchtet, spintet;
+  point eapex;
+  REAL d, diff, smdist = 0;
+  int t1ver;
+
   sstpivot1(*chkseg, searchtet);
   spintet = searchtet;
   while (1) {
@@ -25811,8 +24207,21 @@ int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
       if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
       if (diff < 0) {
         // This segment is encroached by eapex.
-        encpt = eapex;
-        break;
+        if (useinsertradius) {
+          if (encpt == NULL) {
+            encpt = eapex;
+            smdist = d;
+          } else {
+            // Choose the closet encroaching point.
+            if (d < smdist) {
+              encpt = eapex;
+              smdist = d;
+            }
+          }
+        } else {
+          encpt = eapex;
+          break;
+        }
       }
     }
     fnextself(spintet);
@@ -25820,9 +24229,6 @@ int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
   } // while (1)
 
   if (encpt != NULL) {
-    if (b->verbose > 2) {
-      printf("      is encroached by %d\n", pointmark(encpt));
-    }
     return 1;
   }
 
@@ -25841,103 +24247,139 @@ int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag, 
+int tetgenmesh::splitsegment(face *splitseg, point encpt, REAL rrp, 
+                             point encpt1, point encpt2, 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);
+  point pa = sorg(*splitseg);
+  point pb = sdest(*splitseg);
 
-  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;
+  if ((encpt == NULL) && (qflag == 0)) {
+    if (useinsertradius) {
+      // Do not split this segment if the length is smaller than the smaller
+      //   insertion radius at its endpoints.
+      REAL len = distance(pa, pb);
+      REAL smrrv = getpointinsradius(pa);
+      REAL rrv = getpointinsradius(pb);
+      if (rrv > 0) {
+        if (smrrv > 0) {
+          if (rrv < smrrv) {
+            smrrv = rrv;
+          }
+        } else {
+          smrrv = rrv;
+        }
+      }
+      if (smrrv > 0) {
+        if ((fabs(smrrv - len) / len) < b->epsilon) smrrv = len;
+        if (len < smrrv) {
+          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;
+  if (b->nobisect) { // With -Y option.
+    // Only split this segment if it is allowed to be split.
+    if (checkconstraints) {
+      // Check if it has a non-zero length bound. 
+      if (areabound(*splitseg) == 0) {
+        // It is not allowed.  However, if all of facets containing this seg
+        //   is allowed to be split, we still split it.
+        face parentsh, spinsh;
+        //splitseg.shver = 0;
+        spivot(*splitseg, parentsh);
+        if (parentsh.sh == NULL) {
+          return 0; // A dangling segment. Do not split it.
+        }
+        spinsh = parentsh;
+        while (1) {
+          if (areabound(spinsh) == 0) break;
+          spivotself(spinsh);
+          if (spinsh.sh == parentsh.sh) break;
+        }
+        if (areabound(spinsh) == 0) {
+          // All facets at this seg are not allowed to be split.
+          return 0;  // Do not split it.
+        }
+      }
+    } else {
+      return 0; // Do not split this segment.
     }
-  }
+  } // if (b->nobisect)
+
+  triface searchtet;
+  face searchsh;
+  point newpt;
+  insertvertexflags ivf;
 
   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.
+  // Split the segment by the Bowyer-Watson algorithm.
   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; 
+  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
+  ivf.bowywat = 3;
+  ivf.validflag = 1; // Validate the B-W cavity.
+  ivf.lawson = 2; // Do flips to recover Delaunayness.
+  ivf.rejflag = 0;     // Do not check encroachment of new segments/facets.
+  if (b->metric) {
+    ivf.rejflag |= 4;  // Do check encroachment of protecting balls.
   }
   ivf.chkencflag = chkencflag;
-  ivf.sloc = ivf.iloc;
-  ivf.sbowywat = ivf.bowywat;  // Surface mesh options.
+  ivf.sloc = (int) INSTAR; // ivf.iloc;
+  ivf.sbowywat = 3; // 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);
+  ivf.assignmeshsize = b->metric;
+  ivf.smlenflag = useinsertradius;
+
+
+  if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
     st_segref_count++;
     if (steinerleft > 0) steinerleft--;
+    if (useinsertradius) {
+      // Update 'rv' (to be the shortest distance).
+      REAL rv = ivf.smlen, rp;
+      if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
+        face parentseg1, parentseg2;
+        sdecode(point2sh(newpt), parentseg1);
+        sdecode(point2sh(ivf.parentpt), parentseg2);
+        if (segsegadjacent(&parentseg1, &parentseg2)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < rp) {
+            rv = rp; // The relaxed insertion radius of 'newpt'.
+          }
+        }
+      } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
+        face parentseg, parentsh;
+        sdecode(point2sh(newpt), parentseg);
+        sdecode(point2sh(ivf.parentpt), parentsh);
+        if (segfacetadjacent(&parentseg, &parentsh)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < rp) {
+            rv = rp; // The relaxed insertion radius of 'newpt'.
+          }            
+        }
+      }
+      setpointinsradius(newpt, rv);
+    }
+    if (flipstack != NULL) {
+      flipconstraints fc;
+      fc.chkencflag = chkencflag;
+      fc.enqflag = 2;
+      lawsonflip3d(&fc);
+      unflipqueue->restart();
+    }
     return 1;
   } else {
-    // The vertex was not inserted. For unknown reasons.
-    //pointdealloc(newpt);
-    assert(0);
+    // Point is not inserted.
+    pointdealloc(newpt);
+    return 0;
   }
-
-  // Should not be here.
-  return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -25948,7 +24390,7 @@ int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag,
 
 void tetgenmesh::repairencsegs(int chkencflag)
 {
-  badface *bface;
+  face *bface;
   point encpt = NULL;
   int qflag = 0;
 
@@ -25956,20 +24398,25 @@ void tetgenmesh::repairencsegs(int chkencflag)
   //   if an unlimited number of Steiner points is allowed.
   while ((badsubsegs->items > 0) && (steinerleft != 0)) {
     badsubsegs->traversalinit();
-    bface = badfacetraverse(badsubsegs);
+    bface = (face *) badsubsegs->traverse();
     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);
+      // Skip a deleleted element.
+      if (bface->shver >= 0) {
+        // A queued segment may have been deleted (split).
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          // A queued segment may have been processed. 
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+            if (checkseg4split(bface, encpt, qflag)) {
+              splitsegment(bface, encpt, 0, NULL, NULL, qflag, chkencflag);
+            }
           }
         }
+        // Remove this entry from list.
+        bface->shver = -1; // Signal it as a deleted element.
+        badsubsegs->dealloc((void *) bface);
       }
-      badfacedealloc(badsubsegs, bface); // Remove this entry from list.
-      bface = badfacetraverse(badsubsegs);
+      bface = (face *) badsubsegs->traverse();
     }
   }
 
@@ -25982,19 +24429,37 @@ void tetgenmesh::repairencsegs(int chkencflag)
       assert(0); // Unknown case.
     }
     badsubsegs->traversalinit();
-    bface = badfacetraverse(badsubsegs);
+    bface = (face *) badsubsegs->traverse();
     while (bface  != NULL) {
-      if (bface->ss.sh[3] != NULL) {
-        if (smarktest2ed(bface->ss)) {
-          sunmarktest2(bface->ss);
+      // Skip a deleleted element.
+      if (bface->shver >= 0) {
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+          }
         }
       }
-      bface = badfacetraverse(badsubsegs);
+      bface = (face *) badsubsegs->traverse();
     }
     badsubsegs->restart();
   }
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuesubface()    Queue a subface or a subsegment for encroachment chk. //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enqueuesubface(memorypool *pool, face *chkface)
+{
+  if (!smarktest2ed(*chkface)) {
+    smarktest2(*chkface); // Only queue it once.
+    face *queface = (face *) pool->alloc();
+    *queface = *chkface;
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // checkfac4encroach()    Check if a subface is encroached by a point.       //
@@ -26005,8 +24470,6 @@ 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);
@@ -26015,10 +24478,12 @@ int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
  
   if (len < rd) {
     // The point lies inside the circumsphere of this face.
-    if (b->metric || b->nobisect) { // -m or -Y option.
+    if (b->metric) { // -m option.
       if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
           (pc[pointmtrindex] > 0)) {
         // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
+        REAL prjpt[3], n[3];
+        REAL a, a1, a2, a3;
         projpt2face(checkpt, pa, pb, pc, prjpt);
         // Get the face area of [a,b,c].
         facenormal(pa, pb, pc, n, 1, NULL);
@@ -26040,10 +24505,6 @@ int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point 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.
@@ -26074,14 +24535,10 @@ int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
 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 area, rd, len;
   REAL A[4][4], rhs[4], D;
   int indx[4];
-  REAL elen[3];
   int i;
 
   encpt = NULL;
@@ -26091,11 +24548,6 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
   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];
@@ -26108,102 +24560,97 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
   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[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
+  rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
   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);
-    }
+  //   pivoting and backward and forward substitute.
+  if (!lu_decmp(A, 3, indx, &D, 0)) {
+    // A degenerate triangle. 
+    assert(0);
+  }
 
-    // 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];
+  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 (checkconstraints && (areabound(*chkfac) > 0.0)) {
+    // Check if the subface has too big area.
+    if (area > areabound(*chkfac)) {
+      qflag = 1;
+      return 1;
     }
+  }
 
-
-    D = sqrt(D);
-    if (b->verbose > 2) {
-      printf("      shortest edge length = %g\n", D);
+  if (b->fixedvolume) {
+    if ((area * sqrt(area)) > b->maxvolume) {
+      qflag = 1;
+      return 1;
     }
+  }
 
-    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);
+  if (b->varvolume) {
+    triface adjtet;
+    REAL volbnd;
+    int t1ver;
+
+    stpivot(*chkfac, adjtet);
+    if (!ishulltet(adjtet)) {
+      volbnd = volumebound(adjtet.tet);
+      if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
+        qflag = 1;
+        return 1;
       }
-      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));
-        }
+    fsymself(adjtet);
+    if (!ishulltet(adjtet)) {
+      volbnd = volumebound(adjtet.tet);
+      if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
         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;
-      }
+  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;
     }
+  }
 
+  triface searchtet;
+  REAL smlen = 0;
 
-    // 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)));
-          }
+  // 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 (smlen == 0) {
+          smlen = len;
           encpt = oppo(searchtet);
-          return 1;
+        } else {
+          if (len < smlen) {
+            smlen = len;
+            encpt = oppo(searchtet);
+          }
         }
+        //return 1;
       }
-      sesymself(*chkfac);
     }
-  } else {
-    assert(0);
-  } // if (!lu_decomp)
+    sesymself(*chkfac);
+  }
 
-  return 0;
+  return encpt != NULL; //return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -26212,158 +24659,192 @@ int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
 //                                                                           //
 // 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.                        //
+// ment. Instead, one of the encroached segments is split.  It is possible   //
+// that none of the encroached 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).                                                     //
+// (= 0).  Furthermore, it is inserted on an encroached segment (= 1) or     //
+// in-side the facet (= 2).                                                  //
+//                                                                           //
+// 'encpt' is a vertex encroaching upon this subface, i.e., it causes the    //
+// split of this subface. If 'encpt' is NULL, then the cause of the split    //
+// this subface is a rejected tet circumcenter 'p', and 'encpt1' is the      //
+// parent of 'p'.                                                            //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag,
-                             REAL *ccent, int chkencflag)
+int tetgenmesh::splitsubface(face *splitfac, point encpt, point encpt1, 
+                             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;
-
+  point pa = sorg(*splitfac);
+  point pb = sdest(*splitfac);
+  point pc = sapex(*splitfac);
 
-  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");
+  if (b->nobisect) { // With -Y option.
+    if (checkconstraints) {
+      // Only split if it is allowed to be split.
+      // Check if this facet has a non-zero constraint.
+      if (areabound(*splitfac) == 0) {
+        return 0; // Do not split it.
       }
+    } else {
       return 0;
     }
-  }
+  } // if (b->nobisect)
+
+  face searchsh;
+  insertvertexflags ivf;
+  point newpt;
+  REAL rv = 0., rp; // Insertion radius of newpt.
+  int i;
 
   // Initialize the inserting point.
   makepoint(&newpt, FREEFACETVERTEX);
+  // Split the subface at its circumcenter.
+  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
 
-  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;
-    }
+  if (useinsertradius) {
+    if (encpt != NULL) {
+      rv = distance(newpt, encpt);
+      if (pointtype(encpt) == FREESEGVERTEX) {
+        face parentseg;
+        sdecode(point2sh(encpt), parentseg);
+        if (segfacetadjacent(&parentseg, splitfac)) {
+          rp = getpointinsradius(encpt);
+          if (rv < (sqrt(2.0) * rp)) {
+            // This insertion may cause no termination. 
+            pointdealloc(newpt);
+            return 0; // Reject the insertion of newpt.
+          }
+        }
+      } else if (pointtype(encpt) == FREEFACETVERTEX) {
+        face parentsh;
+        sdecode(point2sh(encpt), parentsh);
+        if (facetfacetadjacent(&parentsh, splitfac)) {
+          rp = getpointinsradius(encpt);
+          if (rv < rp) {
+            pointdealloc(newpt);
+            return 0; // Reject the insertion of newpt.
+          }
+        }
+      }
+    }
+  } // if (useinsertradius)
+
+  // 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))) {
+    pointdealloc(newpt);
+    return 0;
   }
 
+
+  triface searchtet;
+  face *paryseg;
+  int splitflag;
+
   // 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.
+  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
+  ivf.bowywat = 3; 
+  ivf.lawson = 2;
+  ivf.rejflag = 1; // Do check the encroachment of segments.
+  if (b->metric) {
+    ivf.rejflag |= 4;  // Do check encroachment of protecting balls.
   }
   ivf.chkencflag = chkencflag;
-  ivf.sloc = ivf.iloc;
-  ivf.sbowywat = ivf.bowywat;
+  ivf.sloc = (int) INSTAR; // ivf.iloc;
+  ivf.sbowywat = 3; // ivf.bowywat;
   ivf.splitbdflag = 1;
   ivf.validflag = 1;
   ivf.respectbdflag = 1;
-  ivf.assignmeshsize = 1;
+  ivf.assignmeshsize = b->metric;
 
   ivf.refineflag = 2;
   ivf.refinesh = searchsh;
+  ivf.smlenflag = useinsertradius; // Update the insertion radius.
 
-  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;
-      }
+  if (insertpoint(newpt, &searchtet, &searchsh, NULL, &ivf)) {
+    st_facref_count++;
+    if (steinerleft > 0) steinerleft--;
+    if (useinsertradius) {
+      // Update 'rv' (to be the shortest distance).
+      rv = ivf.smlen;
+      if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
+        face parentseg, parentsh;
+        sdecode(point2sh(ivf.parentpt), parentseg);
+        sdecode(point2sh(newpt), parentsh);
+        if (segfacetadjacent(&parentseg, &parentsh)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < (sqrt(2.0) * rp)) {
+            rv = sqrt(2.0) * rp; // The relaxed insertion radius of 'newpt'.
+          }
+        }
+      } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
+        face parentsh1, parentsh2;
+        sdecode(point2sh(ivf.parentpt), parentsh1);
+        sdecode(point2sh(newpt), parentsh2);
+        if (facetfacetadjacent(&parentsh1, &parentsh2)) {
+          rp = getpointinsradius(ivf.parentpt);
+          if (rv < rp) {
+            rv = rp; // The relaxed insertion radius of 'newpt'.
+          }          
+        }
+      }
+      setpointinsradius(newpt, rv);
+    } // if (useinsertradius)
+    if (flipstack != NULL) {
+      flipconstraints fc;
+      fc.chkencflag = chkencflag;
+      fc.enqflag = 2;
+      lawsonflip3d(&fc);
+      unflipqueue->restart();
     }
-    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 1;
+  } else {
+    // Point was not inserted.
+    pointdealloc(newpt);
+    if (ivf.iloc == (int) ENCSEGMENT) {
+      // 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, rv, encpt, encpt1, 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 != NULL) && (splitfac->sh[3] != NULL)) {
+        //  // Only queue it if 'qflag' is set.
+        //  if (qflag) { 
+        //    enqueuesubface(badsubfacs, splitfac);
+        //  }
+        //}
+      }
+      return splitflag;
+    } else {
+      return 0;
     }
-    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;  
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -26374,7 +24855,7 @@ int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag,
 
 void tetgenmesh::repairencfacs(int chkencflag)
 {
-  badface *bface;
+  face *bface;
   point encpt = NULL;
   int qflag = 0;
   REAL ccent[3];
@@ -26383,20 +24864,24 @@ void tetgenmesh::repairencfacs(int chkencflag)
   //   if an unlimited number of Steiner points is allowed.
   while ((badsubfacs->items > 0) && (steinerleft != 0)) {
     badsubfacs->traversalinit();
-    bface = badfacetraverse(badsubfacs);
+    bface = (face *) badsubfacs->traverse();
     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);
+      // Skip a deleted element.
+      if (bface->shver >= 0) {
+        // A queued subface may have been deleted (split).
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          // A queued subface may have been processed. 
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+            if (checkfac4split(bface, encpt, qflag, ccent)) {
+              splitsubface(bface, encpt, NULL, qflag, ccent, chkencflag);
+            }
           }
         }
+        bface->shver = -1; // Signal it as a deleted element.
+        badsubfacs->dealloc((void *) bface); // Remove this entry from list.
       }
-      badfacedealloc(badsubfacs, bface); // Remove this entry from list.
-      bface = badfacetraverse(badsubfacs);
+      bface = (face *) badsubfacs->traverse();
     }
   }
 
@@ -26409,19 +24894,37 @@ void tetgenmesh::repairencfacs(int chkencflag)
       assert(0); // Unknown case.
     }
     badsubfacs->traversalinit();
-    bface = badfacetraverse(badsubfacs);
+    bface = (face *) badsubfacs->traverse();
     while (bface  != NULL) {
-      if (bface->ss.sh[3] != NULL) {
-        if (smarktest2ed(bface->ss)) {
-          sunmarktest2(bface->ss);
+      // Skip a deleted element.
+      if (bface->shver >= 0) {
+        if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
+          if (smarktest2ed(*bface)) {
+            sunmarktest2(*bface);
+          }
         }
       }
-      bface = badfacetraverse(badsubfacs);
+      bface = (face *) badsubfacs->traverse();
     }
     badsubfacs->restart();
   }
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// enqueuetetrahedron()    Queue a tetrahedron for quality check.            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::enqueuetetrahedron(triface *chktet)
+{
+  if (!marktest2ed(*chktet)) {
+    marktest2(*chktet); // Only queue it once.
+    triface *quetet = (triface *) badtetrahedrons->alloc();
+    *quetet = *chktet;
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // checktet4split()    Check if the tet needs to be split.                   //
@@ -26434,11 +24937,18 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
   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 maxcosd, vol, volbnd, smlen = 0, rd;
   REAL A[4][4], rhs[4], D;
   int indx[4];
   int i, j;
 
+  if (b->convex) { // -c
+    // Skip this tet if it lies in the exterior.
+    if (elemattribute(chktet->tet, numelemattrib - 1) == -1.0) {
+      return 0;
+    }
+  }
+
   qflag = 0;
 
   pd = (point) chktet->tet[7];
@@ -26450,11 +24960,6 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
   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];
@@ -26468,22 +24973,14 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
 
   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;
+    // This is possible due to the use of exact arithmetic.  We temporarily
+    //   leave this tet. It should be fixed by mesh optimization.
+    return 0; 
   }
 
   // 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;
@@ -26506,6 +25003,26 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
     }
   }
 
+  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;
+        }
+      }
+    }
+  }
+
   if (in->tetunsuitable != NULL) {
     // Execute the user-defined meshing sizing evaluation.
     if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
@@ -26516,11 +25033,61 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
       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.
     }
   }
 
+  if (useinsertradius) {
+    // Do not split this tet if the shortest edge is shorter than the
+    //   insertion radius of one of its endpoints.
+    triface checkedge;
+    point e1, e2;
+    REAL rrv, smrrv;
+
+    // Get the shortest edge of this tet.
+    checkedge.tet = chktet->tet;
+    for (i = 0; i < 6; i++) {
+      checkedge.ver = edge2ver[i];
+      e1 = org(checkedge);
+      e2 = dest(checkedge);
+      elen[i] = distance(e1, e2);
+      if (i == 0) {
+        smlen = elen[i];
+        j = 0;
+      } else {
+        if (elen[i] < smlen) {
+          smlen = elen[i];
+          j = i;
+        }
+      }
+    }
+    // Check if the edge is too short.
+    checkedge.ver = edge2ver[j];
+    // Get the smallest rrv of e1 and e2.
+    // Note: if rrv of e1 and e2 is zero. Do not use it.
+    e1 = org(checkedge);
+    smrrv = getpointinsradius(e1);
+    e2 = dest(checkedge);
+    rrv = getpointinsradius(e2);
+    if (rrv > 0) {
+      if (smrrv > 0) {
+        if (rrv < smrrv) {
+          smrrv = rrv;
+        }
+      } else {
+        smrrv = rrv;
+      }
+    }
+    if (smrrv > 0) {
+      // To avoid rounding error, round smrrv before doing comparison.
+      if ((fabs(smrrv - smlen) / smlen) < b->epsilon) {
+        smrrv = smlen;
+      }
+      if (smrrv > smlen) {
+        return 0;
+      }
+    }
+  } // if (useinsertradius)
+
   // Check the radius-edge ratio. Set by -q#.
   if (b->minratio > 0) { 
     // Calculate the circumcenter and radius of this tet.
@@ -26530,24 +25097,23 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
     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; 
-      }
+    if (!useinsertradius) {
+      // 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);
     }
-    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;
@@ -26578,7 +25144,7 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
     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.
+    // Get the smallest dihedral angle.
     //maxcosd = mincosd = cosd[0];
     maxcosd = cosd[0];
     for (i = 1; i < 6; i++) {
@@ -26586,9 +25152,6 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
       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.
@@ -26604,26 +25167,6 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
     }
   }
 
-  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;
 }
 
@@ -26636,54 +25179,33 @@ int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
 int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent, 
                                  int chkencflag)
 {
-  badface *bface;
   triface searchtet;
-  face checkseg, *paryseg;
-  point newpt, pa, *ppt = NULL;
+  face *paryseg;
+  point newpt;
+  badface *bface;
   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;
-    }
-  }
+  REAL rv = 0.; // Insertion radius of 'newpt'.
 
   makepoint(&newpt, FREEVOLVERTEX);
   for (i = 0; i < 3; i++) newpt[i] = ccent[i];
 
+  if (useinsertradius) {
+    rv = distance(newpt, org(*splittet));
+    setpointinsradius(newpt, rv);
+  }
+
   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.
+  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
   ivf.bowywat = 3;
-  ivf.lawson = 3;
-  ivf.rejflag = 3;
-  if (qflag == 0) {
+  ivf.lawson = 2;
+  ivf.rejflag = 3;  // Do check for encroached segments and subfaces.
+  if (b->metric) {
     ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
   }
   ivf.chkencflag = chkencflag;
@@ -26691,106 +25213,82 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
   ivf.splitbdflag = 0; // No use.
   ivf.validflag = 1;
   ivf.respectbdflag = 1;
-  ivf.assignmeshsize = 1;
+  ivf.assignmeshsize = b->metric;
 
   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.
-        }
-      }
+  if (insertpoint(newpt, &searchtet, NULL, NULL, &ivf)) {
+    // Vertex is inserted.
+    st_volref_count++;
+    if (steinerleft > 0) steinerleft--;
+    if (flipstack != NULL) {
+      flipconstraints fc;
+      fc.chkencflag = chkencflag;
+      fc.enqflag = 2;
+      lawsonflip3d(&fc);
+      unflipqueue->restart();
     }
-    return splitflag;
-  } else if (loc == (int) ENCSUBFACE) {
-    // There are encroached subfaces.
+    return 1;
+  } else {
+    // Point is not inserted.
     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;
+    // Check if there are encroached segments/subfaces.
+    if (ivf.iloc == (int) ENCSEGMENT) {
+      splitflag = 0;
+      //if (!b->nobisect) { // not -Y option
+      if (!b->nobisect || checkconstraints) {  
+        // Select an encroached segment and split it.
+        for (i = 0; i < encseglist->objects; i++) {
+          paryseg = (face *) fastlookup(encseglist, i);
+          if (splitsegment(paryseg, NULL, rv, org(*splittet), NULL, qflag, 
+                           chkencflag | 3)) {
+            splitflag = 1; // A point is inserted on 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.
+      } // 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 != NULL) && (splittet->tet[4] != NULL)) {
+          enqueuetetrahedron(splittet);
+        }
+      }
+      return splitflag;
+    } else if (ivf.iloc == (int) ENCSUBFACE) {
+      splitflag = 0;
+      //if (!b->nobisect) { // not -Y option
+      if (!b->nobisect || checkconstraints) {
+        // Select an encroached subface and split it.
+        for (i = 0; i < encshlist->objects; i++) {
+          bface = (badface *) fastlookup(encshlist, i);
+          if (splitsubface(&(bface->ss), NULL, org(*splittet), 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);
+        // Some subfaces may need to be repaired.
+        repairencfacs(chkencflag | 2);
+        // Queue the tet if it is still alive.
+        if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
+          enqueuetetrahedron(splittet);
         }
       }
+      return splitflag;
     }
-    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;
   }
-
-  return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -26801,28 +25299,33 @@ int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
 
 void tetgenmesh::repairbadtets(int chkencflag)
 {
-  badface *bface;
+  triface *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);
+    bface = (triface *) badtetrahedrons->traverse();
     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);
+      // Skip a deleted element.
+      if (bface->ver >= 0) {
+        // A queued tet may have been deleted.
+        if (!isdeadtet(*bface)) {
+          // A queued tet may have been processed.
+          if (marktest2ed(*bface)) {
+            unmarktest2(*bface);
+            if (checktet4split(bface, qflag, ccent)) {
+              splittetrahedron(bface, qflag, ccent, chkencflag);
+            }
           }
         }
+        bface->ver = -1; // Signal it as a deleted element.
+        badtetrahedrons->dealloc((void *) bface);
       }
-      badfacedealloc(badtetrahedrons, bface);
-      bface = badfacetraverse(badtetrahedrons);
+      bface = (triface *) badtetrahedrons->traverse();
     }
   }
 
@@ -26836,14 +25339,17 @@ void tetgenmesh::repairbadtets(int chkencflag)
     }
     // Unmark all queued tet.
     badtetrahedrons->traversalinit();
-    bface = badfacetraverse(badtetrahedrons);
+    bface = (triface *) badtetrahedrons->traverse();
     while (bface != NULL) {
-      if (!isdeadtet(bface->tt)) {
-        if (marktest2ed(bface->tt)) {
-          unmarktest2(bface->tt);
+      // Skip a deleted element.
+      if (bface->ver >= 0) {
+        if (!isdeadtet(*bface)) {
+          if (marktest2ed(*bface)) {
+            unmarktest2(*bface);
+          }
         }
       }
-      bface = badfacetraverse(badtetrahedrons);
+      bface = (triface *) badtetrahedrons->traverse();
     }
     // Clear the pool.
     badtetrahedrons->restart();
@@ -26852,13 +25358,12 @@ void tetgenmesh::repairbadtets(int chkencflag)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// enforcequality()    Refine the mesh.                                      //
+// delaunayrefinement()    Refine the mesh by Delaunay refinement.           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::delaunayrefinement()
 {
-  badface *bface;
   triface checktet;
   face checksh;
   face checkseg;
@@ -26866,13 +25371,16 @@ void tetgenmesh::delaunayrefinement()
   int chkencflag;
 
   long bak_segref_count, bak_facref_count, bak_volref_count;
+  long bak_flipcount = flip23count + flip32count + flip44count;
 
   if (!b->quiet) {
     printf("Refining mesh...\n");
   }
 
   if (b->verbose) {
-    printf("  Edge length limit = %g.\n", b->minedgelength);
+    printf("  Min radiu-edge ratio = %g.\n", b->minratio);
+    printf("  Min dihedral   angle = %g.\n", b->mindihedral);
+    //printf("  Min Edge length = %g.\n", b->minedgelength);
   }
 
   steinerleft = b->steinerleft;  // Upperbound of # Steiner points (by -S#).
@@ -26884,25 +25392,27 @@ void tetgenmesh::delaunayrefinement()
     } else {
       if (!b->quiet) {
         printf("\nWarning:  ");
-        printf("The desired number of Steiner points (%d) is reached.\n\n",
+        printf("The desired number of Steiner points (%d) has reached.\n\n",
                b->steinerleft);
       }
       return; // No more Steiner points.
     }
   }
 
-  if (b->refine || b->nobisect) { // '-r' or '-Y' option.
-    markacutevertices();
+  if (useinsertradius) {
+    if ((b->plc && b->nobisect) || b->refine) { // '-pY' or '-r' option.
+      makesegmentendpointsmap();
+    }
+    makefacetverticesmap();
   }
 
-  marksharpsegments();
-
-  decidefeaturepointsizes();
 
   encseglist = new arraypool(sizeof(face), 8);
   encshlist = new arraypool(sizeof(badface), 8);
 
-  if (!b->nobisect) { // if no '-Y' option
+
+  //if (!b->nobisect) { // if no '-Y' option
+  if (!b->nobisect || checkconstraints) {
     if (b->verbose) {
       printf("  Splitting encroached subsegments.\n");
     }
@@ -26911,17 +25421,14 @@ void tetgenmesh::delaunayrefinement()
     steinercount = points->items;
 
     // Initialize the pool of encroached subsegments.
-    badsubsegs = new memorypool(sizeof(badface), b->shellfaceperblock, 
-                                memorypool::POINTER, 0);
+    badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock, 
+                                sizeof(void *), 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.
+      enqueuesubface(badsubsegs, &checkseg);
       checkseg.sh = shellfacetraverse(subsegs);
     }
 
@@ -26932,7 +25439,6 @@ void tetgenmesh::delaunayrefinement()
       printf("  Added %ld Steiner points.\n", points->items - steinercount);
     }
 
-
     if (b->reflevel > 1) { // '-D2' option
       if (b->verbose) {
         printf("  Splitting encroached subfaces.\n");
@@ -26944,17 +25450,14 @@ void tetgenmesh::delaunayrefinement()
       bak_facref_count = st_facref_count;
 
       // Initialize the pool of encroached subfaces.
-      badsubfacs = new memorypool(sizeof(badface), b->shellfaceperblock, 
-                                  memorypool::POINTER, 0);
+      badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock, 
+                                  sizeof(void *), 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.
+        enqueuesubface(badsubfacs, &checksh);
         checksh.sh = shellfacetraverse(subfaces);
       }
 
@@ -26966,7 +25469,6 @@ void tetgenmesh::delaunayrefinement()
                points->items-steinercount, st_segref_count-bak_segref_count,
                st_facref_count-bak_facref_count);
       }
-
     } // if (b->reflevel > 1)
   } // if (!b->nobisect)
 
@@ -26985,17 +25487,13 @@ void tetgenmesh::delaunayrefinement()
     cosmindihed = cos(b->mindihedral / 180.0 * PI);
 
     // Initialize the pool of bad quality tetrahedra.
-    badtetrahedrons = new memorypool(sizeof(badface), b->tetrahedraperblock,
-                                     memorypool::POINTER, 0);
-
+    badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
+                                     sizeof(void *), 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.
+      enqueuetetrahedron(&checktet);
       checktet.tet = tetrahedrontraverse();
     }
 
@@ -27011,6 +25509,13 @@ void tetgenmesh::delaunayrefinement()
     }
   } // if (b->reflevel > 2)
 
+  if (b->verbose) {
+    if (flip23count + flip32count + flip44count > bak_flipcount) {
+      printf("  Performed %ld flips.\n", flip23count + flip32count +
+             flip44count - bak_flipcount);
+    }
+  }
+
   if (steinerleft == 0) {
     if (!b->quiet) {
       printf("\nWarnning:  ");
@@ -27019,16 +25524,21 @@ void tetgenmesh::delaunayrefinement()
     }
   }
 
+
   delete encseglist;
   delete encshlist;
 
-  if (!b->nobisect) {
+  //if (!b->nobisect) {
+  if (!b->nobisect || checkconstraints) {
+    totalworkmemory += (badsubsegs->maxitems * badsubsegs->itembytes);
     delete badsubsegs;
     if (b->reflevel > 1) {
+      totalworkmemory += (badsubfacs->maxitems * badsubfacs->itembytes);
       delete badsubfacs;
     }
   }
   if (b->reflevel > 2) {
+    totalworkmemory += (badtetrahedrons->maxitems*badtetrahedrons->itembytes);
     delete badtetrahedrons;
   }
 }
@@ -27041,6 +25551,267 @@ void tetgenmesh::delaunayrefinement()
 ////                                                                       ////
 ////                                                                       ////
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// lawsonflip3d()    A three-dimensional Lawson's algorithm.                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+long tetgenmesh::lawsonflip3d(flipconstraints *fc)
+{
+  triface fliptets[5], neightet, hulltet;
+  face checksh, casingout;
+  badface *popface, *bface;
+  point pd, pe, *pts;
+  REAL sign, ori;
+  long flipcount, totalcount = 0l;
+  long sliver_peels = 0l;
+  int t1ver;
+  int i;
+
+
+  while (1) {
+
+    if (b->verbose > 2) {
+      printf("      Lawson flip %ld faces.\n", flippool->items);
+    }
+    flipcount = 0l;
+
+    while (flipstack != (badface *) NULL) {
+      // Pop a face from the stack.
+      popface = flipstack;
+      fliptets[0] = popface->tt;
+      flipstack = flipstack->nextitem; // The next top item in stack.
+      flippool->dealloc((void *) popface);
+
+      // Skip it if it is a dead tet (destroyed by previous flips).
+      if (isdeadtet(fliptets[0])) continue;
+      // Skip it if it is not the same tet as we saved.
+      if (!facemarked(fliptets[0])) continue;
+
+      unmarkface(fliptets[0]);
+
+      if (ishulltet(fliptets[0])) continue;
+
+      fsym(fliptets[0], fliptets[1]);
+      if (ishulltet(fliptets[1])) {
+        if (nonconvex) {
+          // Check if 'fliptets[0]' it is a hull sliver.
+          tspivot(fliptets[0], checksh);
+          for (i = 0; i < 3; i++) {
+            if (!isshsubseg(checksh)) {
+              spivot(checksh, casingout);
+              //assert(casingout.sh != NULL);
+              if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
+              stpivot(casingout, neightet);
+              if (neightet.tet == fliptets[0].tet) {
+                // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where 
+                //   [e,d,a] and [d,e,b] are hull faces.
+                edestoppo(neightet, hulltet); // [a,b,e,d]
+                fsymself(hulltet); // [b,a,e,#]
+                if (oppo(hulltet) == dummypoint) {
+                  pe = org(neightet);
+                  if ((pointtype(pe) == FREEFACETVERTEX) ||
+                      (pointtype(pe) == FREESEGVERTEX)) {
+                    removevertexbyflips(pe);
+                  }
+                } else {
+                  eorgoppo(neightet, hulltet); // [b,a,d,e]
+                  fsymself(hulltet); // [a,b,d,#]
+                  if (oppo(hulltet) == dummypoint) {
+                    pd = dest(neightet);
+                    if ((pointtype(pd) == FREEFACETVERTEX) ||
+                        (pointtype(pd) == FREESEGVERTEX)) {
+                      removevertexbyflips(pd);
+                    }
+                  } else {
+                    // Perform a 3-to-2 flip to remove the sliver.
+                    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]
+                    flip32(fliptets, 1, fc);
+                    // Update counters.
+                    flip32count--;
+                    flip22count--;
+                    sliver_peels++;
+                    if (fc->remove_ndelaunay_edge) {
+                      // Update the volume (must be decreased).
+                      //assert(fc->tetprism_vol_sum <= 0);
+                      tetprism_vol_sum += fc->tetprism_vol_sum;
+                      fc->tetprism_vol_sum = 0.0; // Clear it.
+                    }
+                  }
+                }
+                break;
+              } // if (neightet.tet == fliptets[0].tet)
+            } // if (!isshsubseg(checksh))
+            senextself(checksh);
+          } // i
+        } // if (nonconvex)
+        continue;
+      }
+
+      if (checksubfaceflag) {
+        // Do not flip if it is a subface.
+        if (issubface(fliptets[0])) continue;
+      }
+
+      // Test whether the face is locally Delaunay or not.
+      pts = (point *) fliptets[1].tet; 
+      sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
+
+      if (sign < 0) {
+        // A non-Delaunay face. Try to flip it.
+        pd = oppo(fliptets[0]);
+        pe = oppo(fliptets[1]);
+
+        // Check the convexity of its three edges. Stop checking either a
+        //   locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
+        //   encountered, and 'fliptet' represents that edge.
+        for (i = 0; i < 3; i++) {
+          ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
+          if (ori <= 0) break;
+          enextself(fliptets[0]);
+        }
+
+        if (ori > 0) {
+          // A 2-to-3 flip is found.
+          //   [0] [a,b,c,d], 
+          //   [1] [b,a,c,e]. no dummypoint.
+          flip23(fliptets, 0, fc);
+          flipcount++;
+          if (fc->remove_ndelaunay_edge) {
+            // Update the volume (must be decreased).
+            //assert(fc->tetprism_vol_sum <= 0);
+            tetprism_vol_sum += fc->tetprism_vol_sum;
+            fc->tetprism_vol_sum = 0.0; // Clear it.
+          }
+          continue;
+        } else { // ori <= 0
+          // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
+          //   where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
+          if (checksubsegflag) {
+            // Do not flip if it is a segment.
+            if (issubseg(fliptets[0])) continue;
+          }
+          // Check if there are three or four tets sharing at this edge.        
+          esymself(fliptets[0]); // [b,a,d,c]
+          for (i = 0; i < 3; i++) {
+            fnext(fliptets[i], fliptets[i+1]);
+          }
+          if (fliptets[3].tet == fliptets[0].tet) {
+            // A 3-to-2 flip is found. (No hull tet.)
+            flip32(fliptets, 0, fc); 
+            flipcount++;
+            if (fc->remove_ndelaunay_edge) {
+              // Update the volume (must be decreased).
+              //assert(fc->tetprism_vol_sum <= 0);
+              tetprism_vol_sum += fc->tetprism_vol_sum;
+              fc->tetprism_vol_sum = 0.0; // Clear it.
+            }
+            continue;
+          } else {
+            // There are more than 3 tets at this edge.
+            fnext(fliptets[3], fliptets[4]);
+            if (fliptets[4].tet == fliptets[0].tet) {
+              // There are exactly 4 tets at this edge.
+              if (nonconvex) {
+                if (apex(fliptets[3]) == dummypoint) {
+                  // This edge is locally non-convex on the hull.
+                  // It can be removed by a 4-to-4 flip.                  
+                  ori = 0;
+                }
+              } // if (nonconvex)
+              if (ori == 0) {
+                // A 4-to-4 flip is found. (Two hull tets may be involved.)
+                // Current tets in 'fliptets':
+                //   [0] [b,a,d,c] (d may be newpt)
+                //   [1] [b,a,c,e]
+                //   [2] [b,a,e,f] (f may be dummypoint)
+                //   [3] [b,a,f,d]
+                esymself(fliptets[0]); // [a,b,c,d] 
+                // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
+                //   This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
+                //   It will be removed by the followed 3-to-2 flip.
+                flip23(fliptets, 0, fc); // No hull tet.
+                fnext(fliptets[3], fliptets[1]);
+                fnext(fliptets[1], fliptets[2]);
+                // Current tets in 'fliptets':
+                //   [0] [...]
+                //   [1] [b,a,d,e] (degenerated, d may be new point).
+                //   [2] [b,a,e,f] (f may be dummypoint)
+                //   [3] [b,a,f,d]
+                // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
+                //   Hull tets may be involved (f may be dummypoint).
+                flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
+                flipcount++;
+                flip23count--;
+                flip32count--;
+                flip44count++;
+                if (fc->remove_ndelaunay_edge) {
+                  // Update the volume (must be decreased).
+                  //assert(fc->tetprism_vol_sum <= 0);
+                  tetprism_vol_sum += fc->tetprism_vol_sum;
+                  fc->tetprism_vol_sum = 0.0; // Clear it.
+                }
+                continue;
+              } // if (ori == 0)
+            }
+          }
+        } // if (ori <= 0)
+
+        // This non-Delaunay face is unflippable. Save it.
+        unflipqueue->newindex((void **) &bface);
+        bface->tt = fliptets[0];
+        bface->forg  = org(fliptets[0]);
+        bface->fdest = dest(fliptets[0]);
+        bface->fapex = apex(fliptets[0]);
+      } // if (sign < 0)
+    } // while (flipstack)
+
+    if (b->verbose > 2) {
+      if (flipcount > 0) {
+        printf("      Performed %ld flips.\n", flipcount);
+      }
+    }
+    // Accumulate the counter of flips.
+    totalcount += flipcount;
+
+    assert(flippool->items == 0l);
+    // Return if no unflippable faces left.
+    if (unflipqueue->objects == 0l) break; 
+    // Return if no flip has been performed.
+    if (flipcount == 0l) break;
+
+    // Try to flip the unflippable faces.
+    for (i = 0; i < unflipqueue->objects; i++) {
+      bface = (badface *) fastlookup(unflipqueue, i);
+      if (!isdeadtet(bface->tt) && 
+          (org(bface->tt) == bface->forg) &&
+          (dest(bface->tt) == bface->fdest) &&
+          (apex(bface->tt) == bface->fapex)) {
+        flippush(flipstack, &(bface->tt));
+      }
+    }
+    unflipqueue->restart();
+
+  } // while (1)
+
+  if (b->verbose > 2) {
+    if (totalcount > 0) {
+      printf("      Performed %ld flips.\n", totalcount);
+    }
+    if (sliver_peels > 0) {
+      printf("      Removed %ld hull slivers.\n", sliver_peels);
+    }
+    if (unflipqueue->objects > 0l) {
+      printf("      %ld unflippable edges remained.\n", unflipqueue->objects);
+    }
+  }
+
+  return totalcount + sliver_peels;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // recoverdelaunay()    Recovery the locally Delaunay property.              //
@@ -27050,8 +25821,8 @@ void tetgenmesh::delaunayrefinement()
 void tetgenmesh::recoverdelaunay()
 {
   arraypool *flipqueue, *nextflipqueue, *swapqueue;
-  badface *bface, *parybface;
   triface tetloop, neightet, *parytet;
+  badface *bface, *parybface;
   point *ppt;
   flipconstraints fc;
   int i, j;
@@ -27060,28 +25831,16 @@ void tetgenmesh::recoverdelaunay()
     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);
-        }
+      decode(tetloop.tet[tetloop.ver], neightet);
+      if (!facemarked(neightet)) {
+        flippush(flipstack, &tetloop);
       }
     }
     ppt = (point *) &(tetloop.tet[4]);
@@ -27089,6 +25848,10 @@ void tetgenmesh::recoverdelaunay()
     tetloop.tet = tetrahedrontraverse();
   }
 
+  // Calulate a relatively lower bound for small improvement. 
+  //   Used to avoid rounding error in volume calculation.
+  fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
+
   if (b->verbose) {
     printf("  Initial obj = %.17g\n", tetprism_vol_sum);
   }
@@ -27096,37 +25859,35 @@ void tetgenmesh::recoverdelaunay()
   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);
+  fc.remove_ndelaunay_edge = 1;
+  fc.enqflag = 2;
+
+  lawsonflip3d(&fc);
 
   if (b->verbose > 1) {
-    printf("    New obj = %.17g\n", tetprism_vol_sum);
+    printf("    obj (after Lawson) = %.17g\n", tetprism_vol_sum);
   }
 
   if (unflipqueue->objects == 0l) {
-    // The mesh is Delaunay.
-    return;
+    return; // The mesh is Delaunay.
   }
 
-  // Set the common options.
-  fc.remove_ndelaunay_edge = 1;
   fc.unflip = 1; // Unflip if the edge is not flipped.
-  fc.collectnewtets = 1;
+  fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
+  fc.enqflag = 0;
 
-  autofliplinklevel = 1; // Init value.
-  b->fliplinklevel = -1;
+  autofliplinklevel = 1; // Init level.
+  b->fliplinklevel = -1; // No fixed level.
 
   // 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;
+  b->flipstarsize = 10; // default
 
   flipqueue = new arraypool(sizeof(badface), 10);
   nextflipqueue = new arraypool(sizeof(badface), 10);
-
-
+  
   // Swap the two flip queues.
   swapqueue = flipqueue;
   flipqueue = unflipqueue;
@@ -27134,60 +25895,61 @@ void tetgenmesh::recoverdelaunay()
 
   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);
+    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)) {
+        if (removeedgebyflips(&(bface->tt), &fc) == 2) {
+          tetprism_vol_sum += fc.tetprism_vol_sum;
+          fc.tetprism_vol_sum = 0.0; // Clear it.
+          // 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.
+                decode(parytet->tet[parytet->ver], neightet);
+                if (!facemarked(neightet)) {
+                  flippush(flipstack, parytet);
+                }
+              } // parytet->ver
             }
-            // 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);
+          } // j
+          cavetetlist->restart();
+          // Remove locally non-Delaunay faces. New non-Delaunay edges
+          //   may be found. They are saved in 'unflipqueue'.
+          fc.enqflag = 2;
+          lawsonflip3d(&fc);
+          fc.enqflag = 0;
+          // There may be unflipable faces. Add them in flipqueue.
+          for (j = 0; j < unflipqueue->objects; j++) {
+            bface  = (badface *) fastlookup(unflipqueue, j);
+            flipqueue->newindex((void **) &parybface);
             *parybface = *bface;
           }
+          unflipqueue->restart();
+        } else {
+          // Unable to remove this edge. Save it.
+          nextflipqueue->newindex((void **) &parybface);
+          *parybface = *bface;
+          // Normally, it should be zero. 
+          //assert(fc.tetprism_vol_sum == 0.0);
+          // However, due to rounding errors, a tiny value may appear.
+          fc.tetprism_vol_sum = 0.0;
         }
-      } // i
-
-      flipqueue->restart();
-
-      // Swap the two flip queues.
-      swapqueue = flipqueue;
-      flipqueue = unflipqueue;
-      unflipqueue = swapqueue;
-    } // while (flipqueue->objects > 0l)
+      }
+    } // i
 
     if (b->verbose > 1) {
-      printf("    New obj = %.17g.\n", tetprism_vol_sum);
+      printf("    obj (after level %d) = %.17g.\n", autofliplinklevel,
+             tetprism_vol_sum);
     }
+    flipqueue->restart();
 
     // Swap the two flip queues.
     swapqueue = flipqueue;
@@ -27195,14 +25957,13 @@ void tetgenmesh::recoverdelaunay()
     nextflipqueue = swapqueue;
 
     if (flipqueue->objects > 0l) {
-      // 'b->delmaxfliplevel' is set by -OOOO, default is 1.
+      // default 'b->delmaxfliplevel' 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) {
@@ -27211,16 +25972,13 @@ void tetgenmesh::recoverdelaunay()
     }
   }
 
-  b->flipstarsize = bakmaxflipstarsize;
-
-  delete nextflipqueue;
-  delete flipqueue;
-
-  calc_tetprism_vol = 0;
-
   if (b->verbose) {
-    printf("  Final  obj  = %.17g\n", tetprism_vol_sum);
+    printf("  Final obj  = %.17g\n", tetprism_vol_sum);
   }
+
+  b->flipstarsize = bakmaxflipstarsize;
+  delete flipqueue;
+  delete nextflipqueue;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -27233,11 +25991,7 @@ 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));
-  }
+  int t1ver; 
 
   if (getedge(pa, pb, searchtet)) {
     spintet = *searchtet;
@@ -27286,18 +26040,20 @@ long tetgenmesh::improvequalitybyflips()
   flipqueue = new arraypool(sizeof(badface), 10);
   nextflipqueue = new arraypool(sizeof(badface), 10);
 
-  // Flip edge options.
-  b->fliplinklevel = -1;
-  autofliplinklevel = 1; // Init value.
+  // Backup flip edge options.
+  int bakautofliplinklevel = autofliplinklevel;
+  int bakfliplinklevel = b->fliplinklevel;
+  int bakmaxflipstarsize = b->flipstarsize;
 
-  // 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; 
+  // Set flip edge options.
+  autofliplinklevel = 1; 
+  b->fliplinklevel = -1;
+  b->flipstarsize = 10; // b->optmaxflipstarsize;
 
   fc.remove_large_angle = 1;
   fc.unflip = 1;
   fc.collectnewtets = 1;
+  fc.checkflipeligibility = 1;
 
   totalremcount = 0l;
 
@@ -27320,40 +26076,37 @@ long tetgenmesh::improvequalitybyflips()
         bface  = (badface *) fastlookup(flipqueue, k);
         if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
                            bface->foppo, &bface->tt)) {
+          //assert(!ishulltet(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->key, NULL);
             bface->forg = ppt[0];
             bface->fdest = ppt[1];
             bface->fapex = ppt[2];
             bface->foppo = ppt[3];
             bface->tt.ver = 11;
           }
+          if (bface->key == 0) {
+            // Re-comput the quality values. Due to smoothing operations.
+            ppt = (point *) & (bface->tt.tet[4]);
+            tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent, 
+                           &bface->key, NULL);
+          }
           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.
@@ -27361,8 +26114,6 @@ long tetgenmesh::improvequalitybyflips()
                     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, 
@@ -27381,8 +26132,7 @@ long tetgenmesh::improvequalitybyflips()
                             parybface->cent[n] = ncosdd[n];
                           }
                         }
-                      } // if (ppt[3] != dummypoint) { 
-		      //}
+                      } // if (ppt[3] != dummypoint) 
                     }
                   } // j
                 } // if (fc.cosdihed_out < cosmaxdihed)
@@ -27413,12 +26163,12 @@ long tetgenmesh::improvequalitybyflips()
     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.
+      //if (autofliplinklevel >= b->optmaxfliplevel) {
+      if (autofliplinklevel >= b->optlevel) {
         break;
       }
       autofliplinklevel+=b->fliplinklevelinc;
+      //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
     }
 
     // Swap the two flip queues.
@@ -27427,6 +26177,9 @@ long tetgenmesh::improvequalitybyflips()
     unflipqueue = swapqueue;
   } // while (flipqueues->objects > 0)
 
+  // Restore original flip edge options.
+  autofliplinklevel = bakautofliplinklevel;
+  b->fliplinklevel = bakfliplinklevel;
   b->flipstarsize = bakmaxflipstarsize;
 
   delete flipqueue;
@@ -27451,8 +26204,8 @@ long tetgenmesh::improvequalitybyflips()
 // 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.                        //
+// 'opm' 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.          //
 //                                                                           //
@@ -27473,16 +26226,6 @@ int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
   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) {
@@ -27535,7 +26278,8 @@ int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
         if (ori < 0.0) {
           // Calcuate the objective function value. 
           if (opm->max_min_volume) {
-            val = -ori;
+            //val = -ori;
+            val = - orient3dfast(pa, pb, pc, nextpt);
           } else if (opm->max_min_aspectratio) {
             val = tetaspectratio(pa, pb, pc, nextpt);
           } else if (opm->min_max_dihedangle) {
@@ -27548,8 +26292,10 @@ int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
           }  
         } else { // ori >= 0.0;
           // An invalid new tet. 
+          // This may happen if the mesh contains inverted elements.
           if (opm->max_min_volume) {
-            val = -ori;    
+            //val = -ori;
+            val = - orient3dfast(pa, pb, pc, nextpt);    
           } else {
             // Discard this point.
             break; // j
@@ -27569,7 +26315,6 @@ int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
       } // 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];
@@ -27615,60 +26360,16 @@ int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
   } // 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.
+    opm->smthiter = iter; // Remember the number of iterations. 
     // 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.           //
@@ -27678,31 +26379,30 @@ int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
 long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
 {
   arraypool *flipqueue, *swapqueue;
+  triface *parytet;
   badface *bface, *parybface;
   point *ppt;
   long totalsmtcount, smtcount;
   int smtflag;
-  int iter, i, k;
+  int iter, i, j, k;
 
   //assert(unflipqueue->objects > 0l);
   flipqueue = new arraypool(sizeof(badface), 10);
 
-  totalsmtcount = 0l;
-
   // Swap the two flip queues.
   swapqueue = flipqueue;
   flipqueue = unflipqueue;
   unflipqueue = swapqueue;
 
+  totalsmtcount = 0l;
   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",
+      printf("    Improving mesh quality by smoothing [%d]#:  %ld.\n",
              iter, flipqueue->objects);
     }
 
@@ -27710,6 +26410,7 @@ long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
       bface  = (badface *) fastlookup(flipqueue, k);
       if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
                          bface->foppo, &bface->tt)) {
+        // Operate on it if it is not in 'unflipqueue'.
         if (!marktested(bface->tt)) {
           // Here we simply re-compute the quality. Since other smoothing
           //   operation may have moved the vertices of this tet.
@@ -27719,10 +26420,7 @@ long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
           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.            
-            //}
+            opm->initval = bface->key + 1.0; 
             for (i = 0; (i < 4) && !smtflag; i++) {
               if (pointtype(ppt[i]) == FREEVOLVERTEX) {
                 getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
@@ -27735,78 +26433,61 @@ long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
                     opm->smthiter = 0; // reset
                     smoothpoint(ppt[i], cavetetlist, 1, opm);
                   }
+                  // This tet is modifed.
                   smtcount++;
-                }
+                  if ((opm->imprval - 1.0) < cossmtdihed) {
+                    // There are slivers in new tets. Queue them.
+                    for (j = 0; j < cavetetlist->objects; j++) {
+                      parytet = (triface *) fastlookup(cavetetlist, j);
+                      assert(!isdeadtet(*parytet));
+                      // Operate it if it is not in 'unflipqueue'.
+                      if (!marktested(*parytet)) {
+                        // Evaluate its quality.
+                        // Re-use ppt, bface->key, bface->cent.
+                        ppt = (point *) & (parytet->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(*parytet); // It is in unflipqueue.
+                          unflipqueue->newindex((void **) &parybface);
+                          parybface->tt = *parytet;
+                          parybface->forg = ppt[0];
+                          parybface->fdest = ppt[1];
+                          parybface->fapex = ppt[2];
+                          parybface->foppo = ppt[3];
+                          parybface->tt.ver = 11; 
+                          parybface->key = 0.0;
+                        }
+                      }
+                    } // j
+                  } // if ((opm->imprval - 1.0) < cossmtdihed)
+                } // if (smtflag)
                 cavetetlist->restart();
-              }
+              } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
             } // 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 {
+            if (!smtflag) {
               // 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;
+              parybface->tt = bface->tt;
+              parybface->forg = ppt[0];
+              parybface->fdest = ppt[1];
+              parybface->fapex = ppt[2];
+              parybface->foppo = ppt[3];
+              parybface->tt.ver = 11;
+              parybface->key = 0.0;
             }
-	  } // if (maxdd < cosslidihed)
+	      } // if (maxdd < cosslidihed)
         } // if (!marktested(...))
-      } // gettetrahedron(...)
+      } // if (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);
     }
 
@@ -27846,35 +26527,36 @@ 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 t1ver;
   int n, i;
 
-  // 'slitet' is [c,d,a,b], where [c,d] has a big hihedral angle. 
+  // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle. 
   // Go to the opposite edge [a,b].
-  eprev(*slitet, searchtet);
-  esymself(searchtet);
-  enextself(searchtet); // [a,b,c,d].
+  edestoppo(*slitet, searchtet); // [a,b,c,d].
 
   // Do not split a segment.
-  tsspivot1(searchtet, checkseg);
-  if (checkseg.sh != NULL) {
+  if (issubseg(searchtet)) {
     return 0; 
   }
 
   // Count the number of tets shared at [a,b].
+  // Do not split it if it is a hull edge.
   spintet = searchtet;
   n = 0; 
   while (1) {
+    if (ishulltet(spintet)) break;
     n++;
     fnextself(spintet);
     if (spintet.tet == searchtet.tet) break;
   }
+  if (ishulltet(spintet)) {
+    return 0; // It is a hull edge.
+  }
   assert(n >= 3);
 
   // Get all tets at edge [a,b].
@@ -27928,19 +26610,11 @@ int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
   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];
@@ -27951,24 +26625,22 @@ int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
     caveoldtetlist->newindex((void **) &parytet);
     *parytet = abtets[i];
   }
+
   searchtet = abtets[0]; // No need point location.
+  if (b->metric) {
+    locate(steinerpt, &searchtet); // For size interpolation.
+  }
+
+  delete [] abtets;
+
   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; 
+  ivf.assignmeshsize = b->metric; 
 
-  loc = insertvertex(steinerpt, &searchtet, NULL, NULL, &ivf);
 
-  if (loc == (int) INSTAR) {
+  if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
     // The vertex has been inserted.
-    st_volref_count++; //st_inpoly_count++;
+    st_volref_count++; 
     if (steinerleft > 0) steinerleft--;
     return 1;
   } else {
@@ -27976,8 +26648,6 @@ int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
     pointdealloc(steinerpt);
     return 0;
   }
-
-  delete [] abtets;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -27990,24 +26660,24 @@ long tetgenmesh::removeslivers(int chkencflag)
 {
   arraypool *flipqueue, *swapqueue;
   badface *bface, *parybface;
+  triface slitet, *parytet;
   point *ppt;
-  REAL *cosdd;
+  REAL cosdd[6], maxcosd;
   long totalsptcount, sptcount;
-  int iter, j, k;
+  int iter, i, 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;
 
+  totalsptcount = 0l;
   iter = 0;
 
-  while (flipqueue->objects > 0l) {
+  while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
 
     sptcount = 0l;
 
@@ -28016,74 +26686,63 @@ long tetgenmesh::removeslivers(int chkencflag)
              iter, flipqueue->objects);
     }
 
-    for (k = 0; k < flipqueue->objects; k++) {      
+    for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); 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
+        if ((bface->key == 0) || (bface->tt.ver != 11)) {
+          // Here we need to 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;
-                }
+        }
+        if (bface->key < cosslidihed) { 
+          // It is a sliver. Try to split it.
+          slitet.tet = bface->tt.tet;
+          //cosdd = bface->cent;
+          for (j = 0; j < 6; j++) {
+            if (bface->cent[j] < cosslidihed) { 
+              // Found a large dihedral angle.
+              slitet.ver = edge2ver[j]; // Go to the edge.
+              if (splitsliver(&slitet, bface->cent[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;
+            }
+          } // j
+          if (j < 6) {
+            // A sliver is split. Queue new slivers.
+            badtetrahedrons->traversalinit();
+            parytet = (triface *) badtetrahedrons->traverse();
+            while (parytet != NULL) {
+              unmarktest2(*parytet);
+              ppt = (point *) & (parytet->tet[4]);
+              tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd, 
+                             &maxcosd, NULL);
+              if (maxcosd < cosslidihed) {
+                // A new sliver. Queue it.
+                unflipqueue->newindex((void **) &parybface);
+                parybface->forg = ppt[0];
+                parybface->fdest = ppt[1];
+                parybface->fapex = ppt[2];
+                parybface->foppo = ppt[3];
+                parybface->tt.tet = parytet->tet;
+                parybface->tt.ver = 11;
+                parybface->key = maxcosd;
+                for (i = 0; i < 6; i++) {
+                  parybface->cent[i] = cosdd[i];
                 }
-                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))
+              parytet = (triface *) badtetrahedrons->traverse();
+            }
+            badtetrahedrons->restart();
+          } else {
+            // Didn't split. Queue it again.
+            unflipqueue->newindex((void **) &parybface);
+            *parybface = *bface;
+          } // if (j == 6)
+        } // if (bface->key < cosslidihed)
       } // if (gettetrahedron(...))
     } // k
 
@@ -28121,11 +26780,12 @@ long tetgenmesh::removeslivers(int chkencflag)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-void tetgenmesh::optimizemesh(int optflag)
+void tetgenmesh::optimizemesh()
 {
   badface *parybface;
   triface checktet;
   point *ppt;
+  int optpasses;
   optparameters opm;
   REAL ncosdd[6], maxdd;
   long totalremcount, remcount;
@@ -28139,26 +26799,34 @@ void tetgenmesh::optimizemesh(int optflag)
     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;
+  optpasses = ((1 << b->optlevel) - 1);
 
-  if (b->verbose > 1) {
-    printf("    Removing large angles (> %g degree).\n", b->optmaxdihedral);
+  if (b->verbose) {
+    printf("  Optimization level  = %d.\n", b->optlevel);
+    printf("  Optimization scheme = %d.\n", b->optscheme);
+    printf("  Number of iteration = %d.\n", optpasses);
+    printf("  Min_Max dihed angle = %g.\n", b->optmaxdihedral);
   }
 
+  totalsmtcount = totalsptcount = totalremcount = 0l;
+
   cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
   cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
   cosslidihed = cos(b->optminslidihed / 180.0 * PI);
 
+  int attrnum = numelemattrib - 1; 
+
   // Put all bad tetrahedra into array.
   tetrahedrons->traversalinit();
   checktet.tet = tetrahedrontraverse();
   while (checktet.tet != NULL) {
+    if (b->convex) { // -c
+      // Skip this tet if it lies in the exterior.
+      if (elemattribute(checktet.tet, attrnum) == -1.0) {
+        checktet.tet = tetrahedrontraverse();
+        continue;
+      }
+    }
     ppt = (point *) & (checktet.tet[4]);
     tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
     if (maxdd < cosmaxdihed) {
@@ -28181,23 +26849,23 @@ void tetgenmesh::optimizemesh(int optflag)
   totalremcount = improvequalitybyflips();
 
   if ((unflipqueue->objects > 0l) && 
-      ((b->optlevel & 2) || (b->optlevel & 4))) { // -O2 | -O4
-
-    badtetrahedrons = new memorypool(sizeof(badface), b->tetrahedraperblock,
-                                     memorypool::POINTER, 0);
+      ((b->optscheme & 2) || (b->optscheme & 4))) {
+    // The pool is only used by removeslivers().
+    badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
+                                     sizeof(void *), 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.
+    //opm.checkencflag = 4; // Queue affected tets after smoothing.
     chkencflag = 4; // Queue affected tets after splitting a sliver.
     iter = 0;
 
-    while (iter < b->optpasses) {
+    while (iter < optpasses) {
       smtcount = sptcount = remcount = 0l;
-      if (b->optlevel & 2) {
+      if (b->optscheme & 2) {
         smtcount += improvequalitybysmoothing(&opm);
         totalsmtcount += smtcount;
         if (smtcount > 0l) {
@@ -28206,7 +26874,7 @@ void tetgenmesh::optimizemesh(int optflag)
         }
       }
       if (unflipqueue->objects > 0l) {
-        if (b->optlevel & 4) {
+        if (b->optscheme & 4) {
           sptcount += removeslivers(chkencflag);
           totalsptcount += sptcount;
           if (sptcount > 0l) {
@@ -28228,7 +26896,7 @@ void tetgenmesh::optimizemesh(int optflag)
 
     delete badtetrahedrons;
 
-  } // // -O2 | -O4
+  }
 
   if (unflipqueue->objects > 0l) {
     if (b->verbose > 1) {
@@ -28239,13 +26907,13 @@ void tetgenmesh::optimizemesh(int optflag)
 
   if (b->verbose) {
     if (totalremcount > 0l) {
-      printf("  Removed %ld bad tets.\n", totalremcount);
+      printf("  Removed %ld edges.\n", totalremcount);
     }
     if (totalsmtcount > 0l) {
       printf("  Smoothed %ld points.\n", totalsmtcount);
     }
     if (totalsptcount > 0l) {
-      printf("  Split %ld bad tets.\n", totalsptcount);
+      printf("  Split %ld slivers.\n", totalsptcount);
     }
   }
 }
@@ -28258,6 +26926,32 @@ void tetgenmesh::optimizemesh(int optflag)
 ////                                                                       ////
 ////                                                                       ////
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// printfcomma()    Print a (large) number with the 'thousands separator'.   // 
+//                                                                           //
+// The following code was simply copied from "stackoverflow".                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::printfcomma(unsigned long n)
+{
+  unsigned long n2 = 0;
+  int scale = 1;
+  while (n >= 1000) {
+    n2 = n2 + scale * (n % 1000);
+    n /= 1000;
+    scale *= 1000;
+  }
+  printf ("%ld", n);
+  while (scale != 1) {
+    scale /= 1000;
+    n = n2 / scale;
+    n2 = n2  % scale;
+    printf (",%03ld", n);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // checkmesh()    Test the mesh for topological consistency.                 //
@@ -28403,12 +27097,12 @@ int tetgenmesh::checkmesh(int topoflag)
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-int tetgenmesh::checkshells(/*int sub2tet*/)
+int tetgenmesh::checkshells()
 {
   triface neightet, symtet;
   face shloop, spinsh, nextsh;
   face checkseg;
-  point pa, pb; //, *ppt;
+  point pa, pb;
   int bakcount;
   int horrors, i;
 
@@ -28436,10 +27130,10 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
       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 long) spinsh.sh,
+          printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                  pointmark(sapex(spinsh)));
-          printf("    Second: x%lx (DEAD)\n", (unsigned long long) nextsh.sh);
+          printf("    Second: x%lx (DEAD)\n", (uintptr_t) nextsh.sh);
           horrors++;
           break;
         }
@@ -28447,10 +27141,10 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
         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 long) spinsh.sh,
+           printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
                   pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                   pointmark(sapex(spinsh)));
-           printf("    Scond: x%lx (%d, %d, %d).\n", (unsigned long long) nextsh.sh,
+           printf("    Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
                   pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), 
                   pointmark(sapex(nextsh)));
            horrors++;
@@ -28459,10 +27153,10 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
         // 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 long) spinsh.sh,
+           printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
                   pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                   pointmark(sapex(spinsh)));
-           printf("    Scond: x%lx (%d, %d, %d).\n", (unsigned long long) nextsh.sh,
+           printf("    Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
                   pointmark(sorg(nextsh)), pointmark(sdest(nextsh)), 
                   pointmark(sapex(nextsh)));
            horrors++;
@@ -28476,19 +27170,19 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
       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 long) shloop.sh,
+          printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
                  pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                  pointmark(sapex(shloop)));
-          printf("    Sub: x%lx (Dead)\n", (unsigned long long) checkseg.sh);
+          printf("    Sub: x%lx (Dead)\n", (uintptr_t) 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 long) shloop.sh,
+            printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
                    pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                    pointmark(sapex(shloop)));
-            printf("    Seg: x%lx (%d, %d).\n", (unsigned long long) checkseg.sh,
+            printf("    Seg: x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
                    pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
             horrors++;
           }
@@ -28502,20 +27196,20 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
     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 long) shloop.sh,
+        printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
                pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                pointmark(sapex(shloop)));
-        printf("    Tet: x%lx (DEAD)\n", (unsigned long long) neightet.tet);
+        printf("    Tet: x%lx (DEAD)\n", (uintptr_t) 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 long) shloop.sh,
+          printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
                  pointmark(sorg(shloop)), pointmark(sdest(shloop)), 
                  pointmark(sapex(shloop)));
           printf("    Tet: x%lx (%d, %d, %d, %d).\n",
-                 (unsigned long long) neightet.tet, pointmark(org(neightet)), 
+                 (uintptr_t) neightet.tet, pointmark(org(neightet)), 
                  pointmark(dest(neightet)), pointmark(apex(neightet)),
                  pointmark(oppo(neightet)));
           horrors++;
@@ -28524,11 +27218,11 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
         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 long) spinsh.sh,
+          printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                  pointmark(sapex(spinsh)));
           printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
-                 (unsigned long long) neightet.tet, pointmark(org(neightet)), 
+                 (uintptr_t) neightet.tet, pointmark(org(neightet)), 
                  pointmark(dest(neightet)), pointmark(apex(neightet)), 
                  pointmark(oppo(neightet)));
           horrors++;
@@ -28539,11 +27233,11 @@ int tetgenmesh::checkshells(/*int sub2tet*/)
           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 long) spinsh.sh,
+            printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
                    pointmark(sorg(spinsh)), pointmark(sdest(spinsh)), 
                    pointmark(sapex(spinsh)));
             printf("    Tet: x%lx (%d, %d, %d, %d).\n", 
-                   (unsigned long long) symtet.tet, pointmark(org(symtet)), 
+                   (uintptr_t) symtet.tet, pointmark(org(symtet)), 
                    pointmark(dest(symtet)), pointmark(apex(symtet)), 
                    pointmark(oppo(symtet)));
             horrors++;
@@ -28598,8 +27292,10 @@ int tetgenmesh::checksegments()
   face sseg, checkseg;
   point pa, pb;
   int miscount;
+  int t1ver;
   int horrors, i;
 
+
   if (!b->quiet) {
     printf("  Checking tet->seg connections...\n");
   }
@@ -28623,9 +27319,9 @@ int tetgenmesh::checksegments()
                 ((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 long) tetloop.tet, pointmark(org(tetloop)),
+                   (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
                    pointmark(dest(tetloop)), pointmark(apex(tetloop)),
-                   pointmark(oppo(tetloop)), (unsigned long long) sseg.sh,
+                   pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
                    pointmark(pa), pointmark(pb));
             horrors++;
           } else {
@@ -28636,11 +27332,11 @@ int tetgenmesh::checksegments()
               if (checkseg.sh != sseg.sh) {
                 printf("  !! Wrong tet->seg connection.\n");
                 printf("    Tet: x%lx (%d, %d, %d, %d) - ", 
-                       (unsigned long long) neightet.tet, pointmark(org(neightet)),
+                       (uintptr_t) 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 long) checkseg.sh,
+                  printf("Seg x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
                          pointmark(sorg(checkseg)),pointmark(sdest(checkseg))); 
                 } else {
                   printf("Seg: NULL.\n");
@@ -28660,9 +27356,9 @@ int tetgenmesh::checksegments()
                 ((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 long) neightet.tet, pointmark(org(neightet)),
+                     (uintptr_t) neightet.tet, pointmark(org(neightet)),
                      pointmark(dest(neightet)), pointmark(apex(neightet)),
-                     pointmark(oppo(neightet)), (unsigned long long) sseg.sh,
+                     pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
                      pointmark(pa), pointmark(pb));
               horrors++;
             }
@@ -28679,7 +27375,7 @@ int tetgenmesh::checksegments()
         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 long) neightet.tet, neightet.ver);
+               (uintptr_t) neightet.tet, neightet.ver);
         // Check if all tets at the edge are marked.
         spintet = neightet;
         while (1) {
@@ -28688,7 +27384,7 @@ int tetgenmesh::checksegments()
             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 long) spintet.tet, spintet.ver);
+                   (uintptr_t) spintet.tet, spintet.ver);
             horrors++;
           }
           if (spintet.tet == neightet.tet) break;
@@ -28721,7 +27417,7 @@ int tetgenmesh::checksegments()
           //  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 long) spinsh.sh,
+          //         pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
           //         spinsh.shver);
           //  horrors++;
           //}
@@ -28734,7 +27430,7 @@ int tetgenmesh::checksegments()
                 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 long) spintet.tet, spintet.ver);
+                       (uintptr_t) spintet.tet, spintet.ver);
                 horrors++;
               }
               if (checkseg.sh != sseg.sh) {
@@ -28753,7 +27449,7 @@ int tetgenmesh::checksegments()
         } else { 
           printf("  !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
-                 pointmark(sapex(spinsh)), (unsigned long long) spinsh.sh,
+                 pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
                  spinsh.shver);
           horrors++;
           break;
@@ -29034,6 +27730,7 @@ int tetgenmesh::checkconforming(int flag)
   REAL cent[3], radius, dist, diff, rd, len;
   bool enq;
   int encsubsegs, encsubfaces;
+  int t1ver; 
   int i;
 
   REAL A[4][4], rhs[4], D;
@@ -29189,10 +27886,10 @@ void tetgenmesh::qualitystatistics()
   REAL tetaspect, tetradius;
   REAL smalldiangle, bigdiangle;
   REAL smallfaangle, bigfaangle;
-  int radiustable[12];
-  int aspecttable[16];
-  int dihedangletable[18];
-  int faceangletable[18];
+  unsigned long radiustable[12];
+  unsigned long aspecttable[16];
+  unsigned long dihedangletable[18];
+  unsigned long faceangletable[18];
   int indx[4];
   int radiusindex;
   int aspectindex;
@@ -29220,10 +27917,10 @@ void tetgenmesh::qualitystatistics()
   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;
+  for (i = 0; i < 12; i++) radiustable[i] = 0l;
+  for (i = 0; i < 12; i++) aspecttable[i] = 0l;
+  for (i = 0; i < 18; i++) dihedangletable[i] = 0l;
+  for (i = 0; i < 18; i++) faceangletable[i] = 0l;
 
   minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
   minaltitude = minaltitude * minaltitude;
@@ -29237,16 +27934,26 @@ void tetgenmesh::qualitystatistics()
   biggestdiangle = biggestfaangle = 0.0;
 
 
+  int attrnum = numelemattrib - 1;
+
   // Loop all elements, calculate quality parameters for each element.
   tetrahedrons->traversalinit();
   tetloop.tet = tetrahedrontraverse();
   while (tetloop.tet != (tetrahedron *) NULL) {
 
+    if (b->convex) {
+      // Skip tets in the exterior.
+      if (elemattribute(tetloop.tet, attrnum) == -1.0) {
+        tetloop.tet = tetrahedrontraverse();
+        continue;
+      }
+    }
+
     // 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;
+    tetvol = orient3dfast(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]);
 
@@ -29266,7 +27973,7 @@ void tetgenmesh::qualitystatistics()
     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.
+    // Get the squares of the edge lengths.
     for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
 
     // Calculate the longest and shortest edge length.
@@ -29408,7 +28115,7 @@ void tetgenmesh::qualitystatistics()
 
 
 
-    // Calulate the largest and smallest face angles.
+    // Calculate 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.
@@ -29495,16 +28202,16 @@ void tetgenmesh::qualitystatistics()
          smallestdiangle, sbuf);
 
   printf("  Aspect ratio histogram:\n");
-  printf("         < %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
+  printf("         < %-6.6g    :  %8ld      | %6.6g - %-6.6g     :  %8ld\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",
+    printf("  %6.6g - %-6.6g    :  %8ld      | %6.6g - %-6.6g     :  %8ld\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",
+  printf("  %6.6g - %-6.6g    :  %8ld      | %6.6g -            :  %8ld\n",
          aspectratiotable[4], aspectratiotable[5], aspecttable[5],
          aspectratiotable[10], aspecttable[11]);
   printf("  (A tetrahedron's aspect ratio is its longest edge length");
@@ -29513,7 +28220,7 @@ void tetgenmesh::qualitystatistics()
 
   printf("  Face angle histogram:\n");
   for (i = 0; i < 9; i++) {
-    printf("    %3d - %3d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+    printf("    %3d - %3d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
            i * 10, i * 10 + 10, faceangletable[i],
            i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
   }
@@ -29525,20 +28232,20 @@ void tetgenmesh::qualitystatistics()
 
   printf("  Dihedral angle histogram:\n");
   // Print the three two rows:
-  printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
          0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
-  printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\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",
+    printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\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",
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
          60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
-  printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
+  printf("     %3d - %2d degrees:  %8ld      |    %3d - %3d degrees:  %8ld\n",
          70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
   if (minfacetdihed != PI) {
     printf("  Minimum input dihedral angle is %g (degree).\n",
@@ -29550,6 +28257,96 @@ void tetgenmesh::qualitystatistics()
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// memorystatistics()    Report the memory usage.                            //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::memorystatistics()
+{
+  printf("Memory usage statistics:\n\n");
+ 
+  // Count the number of blocks of tetrahedra. 
+  int tetblocks = 0;
+  tetrahedrons->pathblock = tetrahedrons->firstblock;
+  while (tetrahedrons->pathblock != NULL) {
+    tetblocks++;
+    tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);  
+  }
+
+  // Calculate the total memory (in bytes) used by storing meshes.
+  unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
+  totalmeshmemory = points->maxitems * points->itembytes +
+                    tetrahedrons->maxitems * tetrahedrons->itembytes;
+  if (b->plc || b->refine) {
+    totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
+                        subsegs->maxitems * subsegs->itembytes);
+    totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
+                       tet2segpool->maxitems * tet2segpool->itembytes);
+  }
+
+  unsigned long totalalgomemory = 0l;
+  totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
+                    caveoldtetlist->totalmemory + 
+                    flippool->maxitems * flippool->itembytes;
+  if (b->plc || b->refine) {
+    totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
+                        subvertstack->totalmemory + 
+                        caveshlist->totalmemory + caveshbdlist->totalmemory +
+                        cavesegshlist->totalmemory +
+                        cavetetshlist->totalmemory + 
+                        cavetetseglist->totalmemory +
+                        caveencshlist->totalmemory +
+                        caveencseglist->totalmemory +
+                        cavetetvertlist->totalmemory +
+                        unflipqueue->totalmemory);
+  }
+
+  printf("  Maximum number of tetrahedra:  %ld\n", tetrahedrons->maxitems);
+  printf("  Maximum number of tet blocks (blocksize = %d):  %d\n",
+         b->tetrahedraperblock, tetblocks);
+  /*
+  if (b->plc || b->refine) {
+    printf("  Approximate memory for tetrahedral mesh (bytes):  %ld\n",
+           totalmeshmemory);
+    
+    printf("  Approximate memory for extra pointers (bytes):  %ld\n",
+           totalt2shmemory);
+  } else {
+    printf("  Approximate memory for tetrahedralization (bytes):  %ld\n",
+           totalmeshmemory);
+  }
+  printf("  Approximate memory for algorithms (bytes):  %ld\n",
+         totalalgomemory);
+  printf("  Approximate memory for working arrays (bytes):  %ld\n",
+         totalworkmemory);
+  printf("  Approximate total used memory (bytes):  %ld\n",
+         totalmeshmemory + totalt2shmemory + totalalgomemory + 
+         totalworkmemory);
+  */
+  if (b->plc || b->refine) {
+    printf("  Approximate memory for tetrahedral mesh (bytes):  ");
+    printfcomma(totalmeshmemory); printf("\n");
+    
+    printf("  Approximate memory for extra pointers (bytes):  ");
+    printfcomma(totalt2shmemory); printf("\n");
+  } else {
+    printf("  Approximate memory for tetrahedralization (bytes):  ");
+    printfcomma(totalmeshmemory); printf("\n");
+  }
+  printf("  Approximate memory for algorithms (bytes):  ");
+  printfcomma(totalalgomemory); printf("\n");
+  printf("  Approximate memory for working arrays (bytes):  ");
+  printfcomma(totalworkmemory); printf("\n");
+  printf("  Approximate total used memory (bytes):  ");
+  printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory + 
+              totalworkmemory);
+  printf("\n");
+
+  printf("\n");
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // statistics()    Print all sorts of cool facts.                            //
@@ -29575,26 +28372,44 @@ void tetgenmesh::statistics()
   tetnumber = tetrahedrons->items - hullsize;
   facenumber = (tetnumber * 4l + hullsize) / 2l;
 
-  printf("\n  Mesh points: %ld\n", points->items);
+  if (b->weighted) { // -w option
+    printf("\n  Mesh points: %ld\n", points->items - nonregularcount);
+  } else {
+    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 (meshedges > 0l) {
+    printf("  Mesh edges: %ld\n", meshedges);
+  } else {
+    if (!nonconvex) {
+      long vsize = points->items - dupverts - unuverts;
+      if (b->weighted) vsize -= nonregularcount;
+      meshedges = vsize + facenumber - tetnumber - 1;
+      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);
+    printf("  Mesh faces on facets: %ld\n", subfaces->items);
+    printf("  Mesh edges on segments: %ld\n", subsegs->items);
+    if (st_volref_count > 0l) {
+      printf("  Steiner points inside domain: %ld\n", st_volref_count);
     }
     if (st_facref_count > 0l) {
-      printf("  Steiner points in boundary faces: %ld\n", st_facref_count);
+      printf("  Steiner points on facets:  %ld\n", st_facref_count);
     }
-    if (st_volref_count > 0l) {
-      printf("  Steiner points in mesh domain: %ld\n", st_volref_count);
+    if (st_segref_count > 0l) {
+      printf("  Steiner points on segments:  %ld\n", st_segref_count);
     }
   } else {
     printf("  Convex hull faces: %ld\n", hullsize);
-    printf("  Convex hull edges: %ld\n", meshhulledges);
+    if (meshhulledges > 0l) {
+      printf("  Convex hull edges: %ld\n", meshhulledges);
+    }
+  }
+  if (b->weighted) { // -w option
+    printf("  Skipped non-regular points: %ld\n", nonregularcount);
   }
   printf("\n");
 
@@ -29605,6 +28420,9 @@ void tetgenmesh::statistics()
         qualitystatistics();
       }
     }
+    if (tetrahedrons->items > 0l) {
+      memorystatistics();
+    }
   }
 }
 
@@ -29636,7 +28454,7 @@ void tetgenmesh::jettisonnodes()
   int remcount;
 
   if (!b->quiet) {
-    printf("Jettisoning redundants points.\n");
+    printf("Jettisoning redundant points.\n");
   }
 
   points->traversalinit();
@@ -29647,7 +28465,7 @@ void tetgenmesh::jettisonnodes()
     jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || 
       (pointtype(pointloop) == UNUSEDVERTEX);
     if (jetflag) {
-      // It is a duplicated point, delete it.
+      // It is a duplicated or unused point, delete it.
       pointdealloc(pointloop);
       remcount++;
     } else {
@@ -29658,32 +28476,121 @@ void tetgenmesh::jettisonnodes()
           // 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);
+      }
+      newidx++;
+    }
+    oldidx++;
+    pointloop = pointtraverse();
+  }
+  if (b->verbose) {
+    printf("  %ld duplicated vertices are removed.\n", dupverts);
+    printf("  %ld unused vertices are removed.\n", unuverts);
+  }
+  dupverts = 0l;
+  unuverts = 0l;
+
+  // 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// highorder()   Create extra nodes for quadratic subparametric elements.    //
+//                                                                           //
+// 'highordertable' is an array (size = numberoftetrahedra * 6) for storing  //
+// high-order nodes of each tetrahedron.  This routine is used only when -o2 //
+// switch is used.                                                           //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+void tetgenmesh::highorder()
+{
+  triface tetloop, worktet, spintet;
+  point *extralist, *adjextralist;
+  point torg, tdest, newpoint;
+  int highorderindex;
+  int t1ver;
+  int i, j;
+
+  if (!b->quiet) {
+    printf("Adding vertices for second-order tetrahedra.\n");
+  }
+
+  // Initialize the 'highordertable'.
+  highordertable = new point[tetrahedrons->items * 6];
+  if (highordertable == (point *) NULL) {
+    terminatetetgen(this, 1);
+  }
+
+  // This will overwrite the slot for element markers.
+  highorderindex = 11;
+
+  // The following line ensures that dead items in the pool of nodes cannot
+  //   be allocated for the extra nodes associated with high order elements.
+  //   This ensures that the primary nodes (at the corners of elements) will
+  //   occur earlier in the output files, and have lower indices, than the
+  //   extra nodes.
+  points->deaditemstack = (void *) NULL;
+
+  // Assign an entry for each tetrahedron to find its extra nodes. At the
+  //   mean while, initialize all extra nodes be NULL.
+  i = 0;
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
+    for (j = 0; j < 6; j++) {
+      highordertable[i + j] = (point) NULL;
+    }
+    i += 6;
+    tetloop.tet = tetrahedrontraverse();
+  }
+
+  // To create a unique node on each edge. Loop over all tetrahedra, and
+  //   look at the six edges of each tetrahedron.  If the extra node in
+  //   the tetrahedron corresponding to this edge is NULL, create a node
+  //   for this edge, at the same time, set the new node into the extra
+  //   node lists of all other tetrahedra sharing this edge.  
+  tetrahedrons->traversalinit();
+  tetloop.tet = tetrahedrontraverse();
+  while (tetloop.tet != (tetrahedron *) NULL) {
+    // Get the list of extra nodes.
+    extralist = (point *) tetloop.tet[highorderindex];
+    worktet.tet = tetloop.tet;
+    for (i = 0; i < 6; i++) {
+      if (extralist[i] == (point) NULL) {
+        // Go to the ith-edge.
+        worktet.ver = edge2ver[i];
+        // Create a new point in the middle of this edge.
+        torg = org(worktet);
+        tdest = dest(worktet);
+        makepoint(&newpoint, FREEVOLVERTEX);
+        for (j = 0; j < 3 + numpointattrib; j++) {
+          newpoint[j] = 0.5 * (torg[j] + tdest[j]);
+        }
+        // Interpolate its metrics.
+        for (j = 0; j < in->numberofpointmtrs; j++) {
+          newpoint[pointmtrindex + j] = 
+            0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
+        }
+        // Set this point into all extra node lists at this edge.
+        spintet = worktet;
+        while (1) {
+          if (!ishulltet(spintet)) {
+            adjextralist = (point *) spintet.tet[highorderindex];
+            adjextralist[ver2edge[spintet.ver]] = newpoint;
+          }
+          fnextself(spintet);
+          if (spintet.tet == worktet.tet) break;
+        }
+      } // if (!extralist[i])
+    } // i
+    tetloop.tet = tetrahedrontraverse();
   }
-  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".          //
@@ -29691,28 +28598,18 @@ void tetgenmesh::jettisonnodes()
 // 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.     //
 //                                                                           //
+// NOTE:  This routine must be called after outelements().  So all elements  //
+// have been indexed.                                                        //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
 void tetgenmesh::numberedges()
 {
   triface worktet, spintet;
-  int firstindex, eindex;
   int ishulledge;
+  int t1ver;
   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();
@@ -29758,7 +28655,7 @@ void tetgenmesh::outnodes(tetgenio* out)
   char outnodefilename[FILENAMESIZE];
   face parentsh;
   point pointloop;
-  int nextras, bmark, marker = 0;
+  int nextras, bmark, marker = 0, weightDT = 0; 
   int coordindex, attribindex;
   int pointnumber, firstindex;
   int index, i;
@@ -29776,14 +28673,18 @@ void tetgenmesh::outnodes(tetgenio* out)
     }
   }
 
-  nextras = in->numberofpointattributes;
+  nextras = numpointattrib;
+  if (b->weighted) { // -w
+    if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
+  }
+
   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);
+      terminatetetgen(this, 1);
     }
     // Number of points, number of dimensions, number of point attributes,
     //   and number of boundary markers (zero or one).
@@ -29793,14 +28694,14 @@ void tetgenmesh::outnodes(tetgenio* out)
     out->pointlist = new REAL[points->items * 3];
     if (out->pointlist == (REAL *) NULL) {
       printf("Error:  Out of memory.\n");
-      terminatetetgen(1);
+      terminatetetgen(this, 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);
+        terminatetetgen(this, 1);
       }
     }
     // Allocate space for 'pointmarkerlist' if necessary;
@@ -29808,14 +28709,14 @@ void tetgenmesh::outnodes(tetgenio* out)
       out->pointmarkerlist = new int[points->items];
       if (out->pointmarkerlist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        terminatetetgen(1);
+        terminatetetgen(this, 1);
       }
     }
     if (b->psc) {
       out->pointparamlist = new tetgenio::pointparam[points->items];
       if (out->pointparamlist == NULL) {
         printf("Error:  Out of memory.\n");
-        terminatetetgen(1);
+        terminatetetgen(this, 1);
       }
     }
     out->numberofpoints = points->items;
@@ -29860,7 +28761,13 @@ void tetgenmesh::outnodes(tetgenio* out)
               pointloop[0], pointloop[1], pointloop[2]);
       for (i = 0; i < nextras; i++) {
         // Write an attribute.
-        fprintf(outfile, "  %.17g", pointloop[4 + i]);
+        if ((i == 0) && weightDT) {          
+          fprintf(outfile, "  %.17g", pointloop[0] * pointloop[0] +
+             pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2] 
+             - pointloop[3 + i]);
+        } else { 
+          fprintf(outfile, "  %.17g", pointloop[3 + i]);
+        }
       }
       if (bmark) {
         // Write the boundary marker.
@@ -29892,7 +28799,13 @@ void tetgenmesh::outnodes(tetgenio* out)
       // Point attributes.
       for (i = 0; i < nextras; i++) {
         // Output an attribute.
-        out->pointattributelist[attribindex++] = pointloop[4 + i];
+        if ((i == 0) && weightDT) {
+          out->pointattributelist[attribindex++] = 
+            pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] + 
+            pointloop[2] * pointloop[2] - pointloop[3 + i];
+        } else {
+          out->pointattributelist[attribindex++] = pointloop[3 + i];
+        }
       }
       if (bmark) {
         // Output the boundary marker.  
@@ -29958,7 +28871,7 @@ void tetgenmesh::outmetrics(tetgenio* out)
     outfile = fopen(outmtrfilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", outmtrfilename);
-      terminatetetgen(3);
+      terminatetetgen(this, 3);
     }
     // Number of points, number of point metrices,
     // fprintf(outfile, "%ld  %d\n", points->items, sizeoftensor + 3);
@@ -29968,7 +28881,7 @@ void tetgenmesh::outmetrics(tetgenio* out)
     // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
     out->pointmtrlist = new REAL[points->items];
     if (out->pointmtrlist == (REAL *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
     out->numberofpointmtrs = 1; // (sizeoftensor + 3);
     mtrindex = 0;
@@ -30012,7 +28925,6 @@ 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;
@@ -30020,10 +28932,9 @@ void tetgenmesh::outelements(tetgenio* out)
   long ntets;
   int firstindex, shift;
   int pointindex, attribindex;
-  int highorderindex = 10; // The reserved pointer.
+  int highorderindex = 11; 
   int elementnumber;
   int eextras;
-  int ishulledge;
   int i;
 
   if (out == (tetgenio *) NULL) {
@@ -30042,12 +28953,12 @@ void tetgenmesh::outelements(tetgenio* out)
   // The number of tets excluding hull tets.
   ntets = tetrahedrons->items - hullsize;
 
-  eextras = in->numberoftetrahedronattributes;
+  eextras = numelemattrib;
   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);
+      terminatetetgen(this, 1);
     }
     // Number of tetras, points per tetra, attributes per tetra.
     fprintf(outfile, "%ld  %d  %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
@@ -30056,14 +28967,14 @@ void tetgenmesh::outelements(tetgenio* out)
     out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
     if (out->tetrahedronlist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      terminatetetgen(1);
+      terminatetetgen(this, 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);
+        terminatetetgen(this, 1);
       }
     }
     out->numberoftetrahedra = ntets;
@@ -30077,7 +28988,7 @@ void tetgenmesh::outelements(tetgenio* out)
 
   // Determine the first index (0 or 1).
   firstindex = b->zeroindex ? 0 : in->firstnumber;
-  shift = 0; // Default no shiftment.
+  shift = 0; // Default no shift.
   if ((in->firstnumber == 1) && (firstindex == 0)) {
     shift = 1; // Shift the output indices by 1.
   }
@@ -30086,8 +28997,13 @@ void tetgenmesh::outelements(tetgenio* out)
   tptr = tetrahedrontraverse();
   elementnumber = firstindex; // in->firstnumber;
   while (tptr != (tetrahedron *) NULL) {
-    p1 = (point) tptr[4];
-    p2 = (point) tptr[5];
+    if (!b->reversetetori) {
+      p1 = (point) tptr[4];
+      p2 = (point) tptr[5];
+    } else {
+      p1 = (point) tptr[5];
+      p2 = (point) tptr[4];
+    }
     p3 = (point) tptr[6];
     p4 = (point) tptr[7];
     if (out == (tetgenio *) NULL) {
@@ -30095,9 +29011,9 @@ void tetgenmesh::outelements(tetgenio* out)
       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) {
+      if (b->order == 2) {
         extralist = (point *) tptr[highorderindex];
-        // Tetrahedron number, indices for four points plus six extra points.
+        // indices for 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,
@@ -30112,7 +29028,7 @@ void tetgenmesh::outelements(tetgenio* out)
       tlist[pointindex++] = pointmark(p2) - shift;
       tlist[pointindex++] = pointmark(p3) - shift;
       tlist[pointindex++] = pointmark(p4) - shift;
-      if (0) { // if (b->order == 2) {
+      if (b->order == 2) {
         extralist = (point *) tptr[highorderindex];
         tlist[pointindex++] = pointmark(extralist[0]) - shift;
         tlist[pointindex++] = pointmark(extralist[1]) - shift;
@@ -30125,44 +29041,12 @@ void tetgenmesh::outelements(tetgenio* out)
         talist[attribindex++] = elemattribute(tptr, i);
       }
     }
-    //if (b->neighout) {
-      // Remember the index of this element.
-      setelemindex(tptr, elementnumber);
-    //}
+    // Remember the index of this element (for counting edges).
+    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);
@@ -30174,11 +29058,6 @@ void tetgenmesh::outelements(tetgenio* out)
 //                                                                           //
 // 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)
@@ -30194,7 +29073,13 @@ void tetgenmesh::outfaces(tetgenio* out)
   int faceid, marker = 0;
   int firstindex, shift;
   int facenumber;
-  int index;
+  int index = 0;
+
+  // For -o2 option.
+  triface workface;
+  point *extralist, pp[3] = {0,0,0}; 
+  int highorderindex = 11; 
+  int o2index = 0, i;
 
   if (out == (tetgenio *) NULL) {
     strcpy(facefilename, b->outfilename);
@@ -30211,13 +29096,12 @@ void tetgenmesh::outfaces(tetgenio* out)
 
   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);
+      terminatetetgen(this, 1);
     }
     fprintf(outfile, "%ld  %d\n", faces, !b->nobound);
   } else {
@@ -30225,14 +29109,17 @@ void tetgenmesh::outfaces(tetgenio* out)
     out->trifacelist = new int[faces * 3];
     if (out->trifacelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) {
+      out->o2facelist = new int[faces * 3];
     }
     // 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);
+        terminatetetgen(this, 1);
       }
     }
     if (b->neighout > 1) {
@@ -30240,13 +29127,12 @@ void tetgenmesh::outfaces(tetgenio* out)
       out->adjtetlist = new int[faces * 2];
       if (out->adjtetlist == (int *) NULL) {
         printf("Error:  Out of memory.\n");
-        terminatetetgen(1);
+        terminatetetgen(this, 1);
       }
     }
     out->numberoftrifaces = faces;
     elist = out->trifacelist;
     emlist = out->trifacemarkerlist;
-    index = 0;
   }
 
   // Determine the first index (0 or 1).
@@ -30271,6 +29157,16 @@ void tetgenmesh::outfaces(tetgenio* out)
         torg = org(tface);
         tdest = dest(tface);
         tapex = apex(tface);
+        if (b->order == 2) { // -o2
+          // Get the three extra vertices on edges.
+          extralist = (point *) (tface.tet[highorderindex]);
+          // The extra vertices are on edges opposite the corners.
+          enext(tface, workface);
+          for (i = 0; i < 3; i++) {
+            pp[i] = extralist[ver2edge[workface.ver]];
+            enextself(workface);
+          }
+        }
         if (!b->nobound) {
           // Get the boundary marker of this face.
           if (b->plc || b->refine) { 
@@ -30306,6 +29202,10 @@ void tetgenmesh::outfaces(tetgenio* out)
           fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
                   pointmark(torg) - shift, pointmark(tdest) - shift,
                   pointmark(tapex) - shift);
+          if (b->order == 2) { // -o2
+            fprintf(outfile, "  %4d  %4d  %4d", pointmark(pp[0]) - shift, 
+                    pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
+          }
           if (!b->nobound) {
             // Output a boundary marker.
             fprintf(outfile, "  %d", marker);
@@ -30319,6 +29219,11 @@ void tetgenmesh::outfaces(tetgenio* out)
           elist[index++] = pointmark(torg) - shift;
           elist[index++] = pointmark(tdest) - shift;
           elist[index++] = pointmark(tapex) - shift;
+          if (b->order == 2) { // -o2
+            out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
+            out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
+            out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
+          }
           if (!b->nobound) {
             emlist[facenumber - in->firstnumber] = marker;
           }
@@ -30375,7 +29280,7 @@ void tetgenmesh::outhullfaces(tetgenio* out)
     outfile = fopen(facefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
     fprintf(outfile, "%ld  0\n", hullsize);
   } else {
@@ -30383,7 +29288,7 @@ void tetgenmesh::outhullfaces(tetgenio* out)
     out->trifacelist = new int[hullsize * 3];
     if (out->trifacelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
     out->numberoftrifaces = hullsize;
     elist = out->trifacelist;
@@ -30454,6 +29359,14 @@ void tetgenmesh::outsubfaces(tetgenio* out)
   int neigh1 = 0, neigh2 = 0;
   int facenumber;
 
+  // For -o2 option.
+  triface workface;
+  point *extralist, pp[3] = {0,0,0}; 
+  int highorderindex = 11;
+  int o2index = 0, i;
+
+  int t1ver; // used by fsymself()
+
   if (out == (tetgenio *) NULL) {
     strcpy(facefilename, b->outfilename);
     strcat(facefilename, ".face");
@@ -30467,13 +29380,11 @@ void tetgenmesh::outsubfaces(tetgenio* out)
     }
   }
 
-  //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);
+      terminatetetgen(this, 3);
     }
     // Number of subfaces.
     fprintf(outfile, "%ld  %d\n", subfaces->items, !b->nobound);
@@ -30481,20 +29392,23 @@ void tetgenmesh::outsubfaces(tetgenio* out)
     // Allocate memory for 'trifacelist'.
     out->trifacelist = new int[subfaces->items * 3];
     if (out->trifacelist == (int *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) {
+      out->o2facelist = new int[subfaces->items * 3];
     }
     if (!b->nobound) {
       // Allocate memory for 'trifacemarkerlist'.
       out->trifacemarkerlist = new int[subfaces->items];
       if (out->trifacemarkerlist == (int *) NULL) {
-        terminatetetgen(1);
+        terminatetetgen(this, 1);
       }
     }
     if (b->neighout > 1) {
       // '-nn' switch.
       out->adjtetlist = new int[subfaces->items * 2];
       if (out->adjtetlist == (int *) NULL) {
-        terminatetetgen(1);
+        terminatetetgen(this, 1);
       }
     }
     out->numberoftrifaces = subfaces->items;
@@ -30514,25 +29428,54 @@ void tetgenmesh::outsubfaces(tetgenio* out)
   facenumber = firstindex; // in->firstnumber;
   while (faceloop.sh != (shellface *) NULL) {
     stpivot(faceloop, abuttingtet);
+    // 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.
+    if (abuttingtet.tet != NULL) {
+      if (ishulltet(abuttingtet)) {
+        fsymself(abuttingtet);
+        assert(!ishulltet(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);
+      if (b->order == 2) { // -o2
+        // Get the three extra vertices on edges.
+        extralist = (point *) (abuttingtet.tet[highorderindex]);
+        workface = abuttingtet;
+        for (i = 0; i < 3; i++) {
+          pp[i] = extralist[ver2edge[workface.ver]];
+          enextself(workface);
+        }
+      }
     } else {
       // This may happen when only a surface mesh be generated.
       torg = sorg(faceloop);
       tdest = sdest(faceloop);
       tapex = sapex(faceloop);
+      if (b->order == 2) { // -o2
+        // There is no extra node list available.
+        pp[0] = torg;
+        pp[1] = tdest;
+        pp[2] = tapex;
+      }
     }
     if (!b->nobound) {
-      if (in->facetmarkerlist) {
-        faceid = shellmark(faceloop) - 1;
-        marker = in->facetmarkerlist[faceid];
+      if (b->refine) { // -r option.
+        if (in->trifacemarkerlist) {
+          marker = shellmark(faceloop);
+        } else {
+          marker = 1; // Default marker for a subface is 1.
+        }
       } else {
-        marker = 1; // Default marker for a subface is 1.
+        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) {
@@ -30552,6 +29495,10 @@ void tetgenmesh::outsubfaces(tetgenio* out)
       fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
               pointmark(torg) - shift, pointmark(tdest) - shift,
               pointmark(tapex) - shift);
+      if (b->order == 2) { // -o2
+        fprintf(outfile, "  %4d  %4d  %4d", pointmark(pp[0]) - shift, 
+                pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
+      }
       if (!b->nobound) {
         fprintf(outfile, "    %d", marker);
       }
@@ -30564,6 +29511,11 @@ void tetgenmesh::outsubfaces(tetgenio* out)
       elist[index++] = pointmark(torg) - shift;
       elist[index++] = pointmark(tdest) - shift;
       elist[index++] = pointmark(tapex) - shift;
+      if (b->order == 2) { // -o2
+        out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
+        out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
+        out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
+      }
       if (!b->nobound) {
         emlist[index1++] = marker;
       }
@@ -30602,9 +29554,15 @@ void tetgenmesh::outedges(tetgenio* out)
   int ishulledge;
   int firstindex, shift;
   int edgenumber, marker;
-  int index, index1;
+  int index = 0, index1 = 0, index2 = 0;
+  int t1ver;
   int i;
 
+  // For -o2 option.
+  point *extralist, pp = NULL; 
+  int highorderindex = 11;
+  int o2index = 0;
+
   if (out == (tetgenio *) NULL) {
     strcpy(edgefilename, b->outfilename);
     strcat(edgefilename, ".edge");
@@ -30618,11 +29576,25 @@ void tetgenmesh::outedges(tetgenio* out)
     }
   }
 
+  if (meshedges == 0l) {
+    if (nonconvex) {
+      numberedges();  // Count the edges.
+    } else {
+      // Use Euler's characteristic to get the numbe of edges.
+      // It states V - E + F - C = 1, hence E = V + F - C - 1.
+      long tsize = tetrahedrons->items - hullsize;
+      long fsize = (tsize * 4l + hullsize) / 2l;
+      long vsize = points->items - dupverts - unuverts;
+      if (b->weighted) vsize -= nonregularcount;
+      meshedges = vsize + fsize - tsize - 1;
+    }
+  }
+
   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);
+      terminatetetgen(this, 1);
     }
     // Write the number of edges, boundary markers (0 or 1).
     fprintf(outfile, "%ld  %d\n", meshedges, !b->nobound);
@@ -30631,16 +29603,20 @@ void tetgenmesh::outedges(tetgenio* out)
     out->edgelist = new int[meshedges * 2];
     if (out->edgelist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) { // -o2 switch
+      out->o2edgelist = new int[meshedges];
     }
     if (!b->nobound) {
       out->edgemarkerlist = new int[meshedges];
     }
+    if (b->neighout > 1) { // '-nn' switch.
+      out->edgeadjtetlist = 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).
@@ -30654,9 +29630,7 @@ void tetgenmesh::outedges(tetgenio* out)
   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.
+    // Count the number of Voronoi faces. 
     worktet.tet = tetloop.tet;
     for (i = 0; i < 6; i++) {
       worktet.ver = edge2ver[i];
@@ -30674,13 +29648,24 @@ void tetgenmesh::outedges(tetgenio* out)
       if (spintet.tet == worktet.tet) {
         torg = org(worktet);
         tdest = dest(worktet);
+        if (b->order == 2) { // -o2
+          // Get the extra vertex on this edge.
+          extralist = (point *) worktet.tet[highorderindex];
+          pp = extralist[ver2edge[worktet.ver]];
+        }
         if (out == (tetgenio *) NULL) {
           fprintf(outfile, "%5d   %4d  %4d", edgenumber,
                   pointmark(torg) - shift, pointmark(tdest) - shift);
+          if (b->order == 2) { // -o2
+            fprintf(outfile, "  %4d", pointmark(pp) - shift);
+          }
         } else {
           // Output three vertices of this face;
           elist[index++] = pointmark(torg) - shift;
           elist[index++] = pointmark(tdest) - shift;
+          if (b->order == 2) { // -o2
+            out->o2edgelist[o2index++] = pointmark(pp) - shift;
+          }
         }
         if (!b->nobound) {
           if (b->plc || b->refine) {
@@ -30704,6 +29689,13 @@ void tetgenmesh::outedges(tetgenio* out)
             emlist[index1++] = marker;
           }
         }
+        if (b->neighout > 1) { // '-nn' switch.
+          if (out == (tetgenio *) NULL) {
+            fprintf(outfile, "  %d", elemindex(tetloop.tet));
+          } else {
+            out->edgeadjtetlist[index2++] = elemindex(tetloop.tet);
+          }
+        }
         if (out == (tetgenio *) NULL) {
           fprintf(outfile, "\n");
         }
@@ -30737,6 +29729,18 @@ void tetgenmesh::outsubsegments(tetgenio* out)
   int marker;
   int edgenumber;
 
+  // For -o2 option.
+  triface workface, spintet;
+  point *extralist, pp = NULL; 
+  int highorderindex = 11;
+  int o2index = 0;
+
+  // For -nn option.
+  int neigh = -1;
+  int index2 = 0;
+
+  int t1ver; // used by fsymself()
+
   if (out == (tetgenio *) NULL) {
     strcpy(edgefilename, b->outfilename);
     strcat(edgefilename, ".edge");
@@ -30754,19 +29758,25 @@ void tetgenmesh::outsubsegments(tetgenio* out)
     outfile = fopen(edgefilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
-      terminatetetgen(3);
+      terminatetetgen(this, 3);
     }
     // Number of subsegments.
     fprintf(outfile, "%ld  1\n", subsegs->items);
   } else {
     // Allocate memory for 'edgelist'.
-    out->edgelist = new int[subsegs->items * 2];
+    out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
     if (out->edgelist == (int *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
+    }
+    if (b->order == 2) {
+      out->o2edgelist = new int[subsegs->items];
     }
     out->edgemarkerlist = new int[subsegs->items];
     if (out->edgemarkerlist == (int *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
+    }
+    if (b->neighout > 1) {
+      out->edgeadjtetlist = new int[subsegs->items];
     }
     out->numberofedges = subsegs->items;
     elist = out->edgelist;
@@ -30787,18 +29797,64 @@ void tetgenmesh::outsubsegments(tetgenio* out)
   while (edgeloop.sh != (shellface *) NULL) {
     torg = sorg(edgeloop);
     tdest = sdest(edgeloop);
+    if ((b->order == 2) || (b->neighout > 1)) {
+      sstpivot1(edgeloop, workface);
+      if (workface.tet != NULL) {
+        // We must find a non-hull tet.
+        if (ishulltet(workface)) {
+          spintet = workface;
+          while (1) {
+            fnextself(spintet);
+            if (!ishulltet(spintet)) break;
+            if (spintet.tet == workface.tet) break;
+          }
+          assert(!ishulltet(spintet));
+          workface = spintet;
+        }
+      }
+    }
+    if (b->order == 2) { // -o2
+      // Get the extra vertex on this edge.
+      if (workface.tet != NULL) {
+        extralist = (point *) workface.tet[highorderindex];
+        pp = extralist[ver2edge[workface.ver]];
+      } else {
+        pp = torg; // There is no extra node available.
+      }
+    }
+    if (b->neighout > 1) { // -nn
+      if (workface.tet != NULL) {
+        neigh = elemindex(workface.tet);
+      } else {
+        neigh = -1;
+      }
+    }
     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);
+      fprintf(outfile, "%5d   %4d  %4d", edgenumber,
+              pointmark(torg) - shift, pointmark(tdest) - shift);
+      if (b->order == 2) { // -o2
+        fprintf(outfile, "  %4d", pointmark(pp) - shift);
+      }
+      fprintf(outfile, "  %d", marker);
+      if (b->neighout > 1) { // -nn
+        fprintf(outfile, "  %4d", neigh);
+      }
+      fprintf(outfile, "\n");
     } else {
       // Output three vertices of this face;
       elist[index++] = pointmark(torg) - shift;
       elist[index++] = pointmark(tdest) - shift;
+      if (b->order == 2) { // -o2
+        out->o2edgelist[o2index++] = pointmark(pp) - shift;
+      }
       out->edgemarkerlist[i++] = marker;
+      if (b->neighout > 1) { // -nn
+        out->edgeadjtetlist[index2++] = neigh;
+      }
     }
     edgenumber++;
     edgeloop.sh = shellfacetraverse(subsegs);
@@ -30847,7 +29903,7 @@ void tetgenmesh::outneighbors(tetgenio* out)
     outfile = fopen(neighborfilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", neighborfilename);
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
     // Number of tetrahedra, four faces per tetrahedron.
     fprintf(outfile, "%ld  %d\n", ntets, 4);
@@ -30856,7 +29912,7 @@ void tetgenmesh::outneighbors(tetgenio* out)
     out->neighborlist = new int[ntets * 4];
     if (out->neighborlist == (int *) NULL) {
       printf("Error:  Out of memory.\n");
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
     nlist = out->neighborlist;
   }
@@ -30906,12 +29962,13 @@ void tetgenmesh::outneighbors(tetgenio* out)
 // 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 //
+// Delaunay edge. It is a closed polygon for any internal 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.                                      //
 //                                                                           //
+// NOTE: This routine is only used when the input is only a set of point.    //
 // Comment: Special thanks to Victor Liu for finding and fixing few bugs.    //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
@@ -30921,7 +29978,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
   FILE *outfile = NULL;
   char outfilename[FILENAMESIZE];
   tetgenio::voroedge *vedge = NULL;
-  tetgenio::vorofacet *vfacet;
+  tetgenio::vorofacet *vfacet = NULL;
   arraypool *tetlist, *ptlist;
   triface tetloop, worktet, spintet, firsttet;
   point pt[4], ploop, neipt;
@@ -30934,6 +29991,8 @@ void tetgenmesh::outvoronoi(tetgenio* out)
   int index, shift, end1, end2;
   int i, j;
 
+  int t1ver; // used by fsymself()
+
   // Output Voronoi vertices to .v.node file.
   if (out == (tetgenio *) NULL) {
     strcpy(outfilename, b->outfilename);
@@ -30974,14 +30033,15 @@ void tetgenmesh::outvoronoi(tetgenio* out)
   // 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();
+  long vsize = points->items - dupverts - unuverts;
+  if (b->weighted) vsize -= nonregularcount;
+  edges = vsize + faces - ntets - 1;
 
   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);
+      terminatetetgen(this, 3);
     }
     // Number of voronoi points, 3 dim, no attributes, no marker.
     fprintf(outfile, "%ld  3  0  0\n", ntets);
@@ -30990,7 +30050,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
     out->numberofvpoints = (int) ntets;
     out->vpointlist = new REAL[out->numberofvpoints * 3];
     if (out->vpointlist == (REAL *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
   }
 
@@ -31004,7 +30064,12 @@ void tetgenmesh::outvoronoi(tetgenio* out)
       pt[i] = (point) tetloop.tet[4 + i];
       setpoint2tet(pt[i], encode(tetloop));
     }
-    circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
+    if (b->weighted) {
+      orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3], 
+                  pt[3][3], ccent, NULL);
+    } else {
+      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]);
@@ -31041,7 +30106,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
     outfile = fopen(outfilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
-      terminatetetgen(3);
+      terminatetetgen(this, 3);
     }
     // Number of Voronoi edges, no marker.
     fprintf(outfile, "%ld  0\n", faces);
@@ -31143,7 +30208,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
     outfile = fopen(outfilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
-      terminatetetgen(3);
+      terminatetetgen(this, 3);
     }
     // Number of Voronoi faces.
     fprintf(outfile, "%ld  0\n", edges);
@@ -31151,7 +30216,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
     out->numberofvfacets = edges;
     out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
     if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
   }
 
@@ -31257,7 +30322,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
     outfile = fopen(outfilename, "w");
     if (outfile == (FILE *) NULL) {
       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
-      terminatetetgen(3);
+      terminatetetgen(this, 3);
     }
     // Number of Voronoi cells.
     fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
@@ -31265,7 +30330,7 @@ void tetgenmesh::outvoronoi(tetgenio* out)
     out->numberofvcells = points->items - unuverts - dupverts;
     out->vcelllist = new int*[out->numberofvcells];
     if (out->vcelllist == (int **) NULL) {
-      terminatetetgen(1);
+      terminatetetgen(this, 1);
     }
   }
 
@@ -31277,7 +30342,8 @@ void tetgenmesh::outvoronoi(tetgenio* out)
   vpointcount = 0;
   while (ploop != (point) NULL) {
     if ((pointtype(ploop) != UNUSEDVERTEX) &&
-        (pointtype(ploop) != DUPLICATEDVERTEX)) { 
+        (pointtype(ploop) != DUPLICATEDVERTEX) &&
+        (pointtype(ploop) != NREGULARVERTEX)) { 
       getvertexstar(1, ploop, tetlist, ptlist, NULL);
       // Mark all vertices. Check if it is a hull vertex.
       ishullvert = 0;
@@ -31337,14 +30403,6 @@ void tetgenmesh::outvoronoi(tetgenio* out)
       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++;
@@ -31583,13 +30641,18 @@ void tetgenmesh::outmesh2medit(char* mfilename)
   tetrahedrons->traversalinit();
   tetptr = tetrahedrontraverse();
   while (tetptr != (tetrahedron *) NULL) {
-    p1 = (point) tetptr[4];
-    p2 = (point) tetptr[5];
+    if (!b->reversetetori) {
+      p1 = (point) tetptr[4];
+      p2 = (point) tetptr[5];
+    } else {
+      p1 = (point) tetptr[5];
+      p2 = (point) tetptr[4];
+    }
     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) {
+    if (numelemattrib > 0) {
       fprintf(outfile, "  %.17g", elemattribute(tetptr, 0));
     } else {
       fprintf(outfile, "  0");
@@ -31639,13 +30702,18 @@ void tetgenmesh::outmesh2vtk(char* ofilename)
 {
   FILE *outfile;
   char vtkfilename[FILENAMESIZE];
-  point pointloop;
+  point pointloop, p1, p2, p3, p4;
   tetrahedron* tptr;
   double x, y, z;
   int n1, n2, n3, n4;
   int nnodes = 4;
   int celltype = 10;
 
+  if (b->order == 2) {
+    printf("  Write VTK not implemented for order 2 elements \n");
+    return;
+  }
+
   int NEL = tetrahedrons->items - hullsize;
   int NN = points->items;
 
@@ -31693,15 +30761,16 @@ void tetgenmesh::outmesh2vtk(char* ofilename)
   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];
+    if (!b->reversetetori) {
+      p1 = (point) tptr[4];
+      p2 = (point) tptr[5];
+    } else {
+      p1 = (point) tptr[5];
+      p2 = (point) tptr[4];
+    }
+    p3 = (point) tptr[6];
+    p4 = (point) tptr[7];
     n1 = pointmark(p1) - in->firstnumber;
     n2 = pointmark(p2) - in->firstnumber;
     n3 = pointmark(p3) - in->firstnumber;
@@ -31717,6 +30786,20 @@ void tetgenmesh::outmesh2vtk(char* ofilename)
   }
   fprintf(outfile, "\n");
 
+  if (numelemattrib > 0) {
+    // Output tetrahedra region attributes.
+    fprintf(outfile, "CELL_DATA %d\n", NEL);
+    fprintf(outfile, "SCALARS cell_scalars int 1\n");
+    fprintf(outfile, "LOOKUP_TABLE default\n");
+    tetrahedrons->traversalinit();
+    tptr = tetrahedrontraverse();
+    while (tptr != (tetrahedron *) NULL) {
+      fprintf(outfile, "%d\n", (int) elemattribute(tptr, numelemattrib - 1));
+      tptr = tetrahedrontraverse();
+    }
+    fprintf(outfile, "\n");
+  }
+
   fclose(outfile);
 }
 
@@ -31756,184 +30839,170 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
                     tetgenio *addin, tetgenio *bgmin)
 {
   tetgenmesh m;
-  clock_t tv[17]; // Timing informations (defined in time.h)
+  clock_t tv[12], ts[5]; // Timing informations (defined in time.h)
+  REAL cps = (REAL) CLOCKS_PER_SEC;
 
   tv[0] = clock();
  
   m.b = b;
   m.in = in;
+  m.addin = addin;
 
-  if ((bgmin != NULL) && 
-      ((bgmin->numberofpoints > 0) && (bgmin->pointmtrlist != NULL))) {
+  if (b->metric && bgmin && (bgmin->numberofpoints > 0)) {
     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();
 
+  exactinit(b->verbose, b->noexact, b->nostaticfilter,
+            m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
+
   tv[1] = clock();
 
-  if (b->refine) {
+  if (b->refine) { // -r
     m.reconstructmesh();
-  } else { // b->plc
-    if (!b->diagnose) {
-      m.incrementaldelaunay(tv[16]);
-    }
+  } else { // -p
+    m.incrementaldelaunay(ts[0]);
   }
 
   tv[2] = clock();
 
   if (!b->quiet) {
     if (b->refine) {
-      printf("Mesh reconstruction seconds:  %g\n", 
-             (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
+      printf("Mesh reconstruction seconds:  %g\n", ((REAL)(tv[2]-tv[1])) / cps);
     } 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
-        }
+      printf("Delaunay seconds:  %g\n", ((REAL)(tv[2]-tv[1])) / cps);
+      if (b->verbose) {
+        printf("  Point sorting seconds:  %g\n", ((REAL)(ts[0]-tv[1])) / cps);
       }
     }
   }
 
-  if (b->plc) {
+  if (b->plc && !b->refine) { // -p
     m.meshsurface();
-  }
 
-  tv[3] = clock();
+    ts[0] = clock();
 
-  if (!b->quiet) {
-    if (b->plc) {
-      printf("Surface mesh seconds:  %g\n",
-             (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC);
+    if (!b->quiet) {
+      printf("Surface mesh seconds:  %g\n", ((REAL)(ts[0]-tv[2])) / cps);
+    }
+
+    if (b->diagnose) { // -d
+      m.detectinterfaces();
+
+      ts[1] = clock();
+
+      if (!b->quiet) {
+        printf("Self-intersection seconds:  %g\n", ((REAL)(ts[1]-ts[0])) / cps);
+      }
+
+      // Only output when self-intersecting faces exist.
+      if (m.subfaces->items > 0l) {
+        m.outnodes(out);
+        m.outsubfaces(out);
+      }
+
+      return;
     }
   }
 
-  if (b->plc && b->diagnose) { // -d
-    m.detectinterfaces();
+  tv[3] = clock();
+
+  if ((b->metric) && (m.bgm != NULL)) { // -m
+    m.bgm->initializepools();
+    m.bgm->transfernodes();
+    m.bgm->reconstructmesh();
 
-    tv[4] = clock();
+    ts[0] = clock();
 
     if (!b->quiet) {
-      printf("Self-intersection seconds:  %g\n",
-             (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
+      printf("Background mesh reconstruct seconds:  %g\n",
+             ((REAL)(ts[0] - tv[3])) / cps);
     }
 
-    // Only output when self-intersecting faces exist.
-    if (m.subfaces->items > 0l) {
-      m.outnodes(out);
-      m.outsubfaces(out);
-    }
+    if (b->metric) { // -m
+      m.interpolatemeshsize();
 
-    return;
-  }
+      ts[1] = clock();
 
-  if (b->plc) {
-    if (b->nobisect) { // with -Y option
-      m.recoverboundary(tv[15]);
-    } else {
-      m.constraineddelaunay(tv[15]);
+      if (!b->quiet) {
+        printf("Size interpolating seconds:  %g\n",((REAL)(ts[1]-ts[0])) / cps);
+      }
     }
   }
 
   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->plc && !b->refine) { // -p
+    if (b->nobisect) { // -Y
+      m.recoverboundary(ts[0]);
+    } else {
+      m.constraineddelaunay(ts[0]);
+    }
+
+    ts[1] = clock();
+
+    if (!b->quiet) {
+      if (b->nobisect) {
+        printf("Boundary recovery ");
+      } else {
+        printf("Constrained Delaunay ");
+      }
+      printf("seconds:  %g\n", ((REAL)(ts[1] - tv[4])) / cps);
       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);
+        printf("  Segment recovery seconds:  %g\n",((REAL)(ts[0]-tv[4]))/ cps);
+        printf("  Facet recovery seconds:  %g\n", ((REAL)(ts[1]-ts[0])) / cps);
       }
     }
-  }
 
-  if (b->plc && !b->convex) {
     m.carveholes();
-  }
 
-  tv[5] = clock();
+    ts[2] = 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->quiet) {
+      printf("Exterior tets removal seconds:  %g\n",((REAL)(ts[2]-ts[1]))/cps);
     }
-  }
 
-  if (b->plc && b->nobisect) { 
-    m.suppresssteinerpoints();
-  }
+    if (b->nobisect) { // -Y
+      if (m.subvertstack->objects > 0l) {
+        m.suppresssteinerpoints();
 
-  tv[6] = clock();
+        ts[3] = 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->quiet) {
+          printf("Steiner suppression seconds:  %g\n",
+                 ((REAL)(ts[3]-ts[2]))/cps);
+        }
+      }
     }
   }
 
-  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);
-    }
-  }
+  tv[5] = clock();
 
-  if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) {
-    m.bgm->initializepools();
-    m.bgm->transfernodes();
-    m.bgm->reconstructmesh();
+  if (b->coarsen) { // -R
+    m.meshcoarsening();
   }
 
-  tv[8] = clock();
+  tv[6] = 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->coarsen) {
+      printf("Mesh coarsening seconds:  %g\n", ((REAL)(tv[6] - tv[5])) / cps);
     }
   }
 
-  if ((b->plc || b->refine) && (b->metric && (m.bgm != NULL))) {
-    m.interpolatemeshsize();
+  if ((b->plc && b->nobisect) || b->coarsen) {
+    m.recoverdelaunay();
   }
 
-  tv[9] = clock();
+  tv[7] = 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->nobisect) || b->coarsen) {
+      printf("Delaunay recovery seconds:  %g\n", ((REAL)(tv[7] - tv[6]))/cps);
     }
   }
 
@@ -31943,44 +31012,37 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     }
   }
 
-  tv[10] = clock();
+  tv[8] = clock();
 
   if (!b->quiet) {
-    if ((b->plc || b->refine) && b->insertaddpoints) {
+    if ((b->plc || b->refine) && b->insertaddpoints) { // -i
       if ((addin != NULL) && (addin->numberofpoints > 0)) {
-        printf("Constrained points seconds:  %g\n", 
-               (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC);
+        printf("Constrained points seconds:  %g\n", ((REAL)(tv[8]-tv[7]))/cps);
       }
     }
   }
 
-
-  tv[11] = clock();
-
-
-  if ((b->plc || b->refine) && b->quality) {
-    m.delaunayrefinement();
+  if (b->quality) {
+    m.delaunayrefinement();    
   }
 
-  tv[12] = clock();
+  tv[9] = 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->quality) {
+      printf("Refinement seconds:  %g\n", ((REAL)(tv[9] - tv[8])) / cps);
     }
   }
 
   if ((b->plc || b->refine) && (b->optlevel > 0)) {
-    m.optimizemesh(1);
+    m.optimizemesh();
   }
 
-  tv[13] = clock();
+  tv[10] = 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);
+      printf("Optimization seconds:  %g\n", ((REAL)(tv[10] - tv[9])) / cps);
     }
   }
 
@@ -31989,6 +31051,9 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.jettisonnodes();
   }
 
+  if ((b->order == 2) && !b->convex) {
+    m.highorder();
+  }
 
   if (!b->quiet) {
     printf("\n");
@@ -32007,11 +31072,10 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
     m.outnodes(out);
   }
 
-  if (b->noelewritten == 1) {
+  if (b->noelewritten) {
     if (!b->quiet) {
       printf("NOT writing an .ele file.\n");
     }
-    m.numberedges();
   } else {
     if (m.tetrahedrons->items > 0l) {
       m.outelements(out);
@@ -32041,11 +31105,17 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
   }
 
 
-  if (b->edgesout) {
-    if (b->edgesout > 1) {
-      m.outedges(out); // -ee, output all mesh edges. 
+  if (b->nofacewritten) {
+    if (!b->quiet) {
+      printf("NOT writing an .edge file.\n");
+    }
+  } else {
+    if (b->edgesout) { // -e
+      m.outedges(out); // output all mesh edges. 
     } else {
-      m.outsubsegments(out); // -e, only output subsegments.
+      if (b->plc || b->refine) {
+        m.outsubsegments(out); // output subsegments.
+      }
     }
   }
 
@@ -32078,13 +31148,11 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
   }
 
 
-  tv[14] = clock();
+  tv[11] = 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);
+    printf("\nOutput seconds:  %g\n", ((REAL)(tv[11] - tv[10])) / cps);
+    printf("Total running seconds:  %g\n", ((REAL)(tv[11] - tv[0])) / cps);
   }
 
   if (b->docheck) {
@@ -32107,7 +31175,7 @@ void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// main()    The entrance for running TetGen from command line.              //
+// main()    The command line interface of TetGen.                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -32117,7 +31185,7 @@ int main(int argc, char *argv[])
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// tetrahedralize()    The entrance for calling TetGen from another program. //
+// tetrahedralize()    The library interface of TetGen.                      //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -32134,17 +31202,17 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
   tetgenio in, addin, bgmin;
   
   if (!b.parse_commandline(argc, argv)) {
-    terminatetetgen(10);
+    terminatetetgen(NULL, 10);
   }
 
   // Read input files.
   if (b.refine) { // -r
     if (!in.load_tetmesh(b.infilename, (int) b.object)) {
-      terminatetetgen(10);
+      terminatetetgen(NULL, 10);
     }
   } else { // -p
     if (!in.load_plc(b.infilename, (int) b.object)) {
-      terminatetetgen(10);
+      terminatetetgen(NULL, 10);
     }
   }
   if (b.insertaddpoints) { // -i
@@ -32163,7 +31231,7 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
 #else // with TETLIBRARY
 
   if (!b.parse_commandline(switches)) {
-    terminatetetgen(10);
+    terminatetetgen(NULL, 10);
   }
   tetrahedralize(&b, in, out, addin, bgmin);
 
diff --git a/contrib/Tetgen1.5/tetgen.h b/contrib/Tetgen1.5/tetgen.h
index 41634d03f49ee9d805eb18e5511c672f8d23478a..3196e031f5318369c6842296cf58fa45a2af611b 100644
--- a/contrib/Tetgen1.5/tetgen.h
+++ b/contrib/Tetgen1.5/tetgen.h
@@ -2,21 +2,10 @@
 //                                                                           //
 // TetGen                                                                    //
 //                                                                           //
-// A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator         //
+// A Quality Tetrahedral Mesh Generator and A 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                                                    //
+// November 4, 2013                                                          //
 //                                                                           //
 // TetGen is freely available through the website: http://www.tetgen.org.    //
 //   It may be copied, modified, and redistributed for non-commercial use.   //
@@ -28,46 +17,51 @@
 #ifndef tetgenH
 #define tetgenH
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <time.h>
-#include <assert.h> 
-
 // To compile TetGen as a library instead of an executable program, define
 //   the TETLIBRARY symbol.
 
 // #define TETLIBRARY
 
-// Uncomment the following line to disable assert macros. These macros are
-//   inserted in places where I hope to catch bugs.
+// Uncomment the following line to disable assert macros. These macros were
+//   inserted in the code where I hoped to catch bugs. They may slow down the
+//   speed of TetGen.
 
 // #define NDEBUG
 
-// To insert lots of self-checks for internal errors, define the SELF_CHECK
-//   symbol.  This will slow down the program a bit. 
+// TetGen default uses the double precision (64 bit) for a real number. 
+//   Alternatively, one can use the single precision (32 bit) 'float' if the
+//   memory is limited.
 
-// #define SELF_CHECK
+#define REAL double  // #define REAL float
 
-// Default, TetGen uses the double precision for a real number.
+// Maximum number of characters in a file name (including the null).
 
-#define REAL double
+#define FILENAMESIZE 1024
 
-// The types 'intptr_t' and 'uintptr_t' are signed and unsigned integer types,
-//   respectively. They are guaranteed to be the same width as a pointer.
-//   They are defined in <stdint.h> by the C99 Standard.
-//   However, Microsoft Visual C++ doesn't ship with this header file yet. We
-//   need to define them. 
-//   Thanks to Steven G. Johnson (MIT) for the following code. 
+// Maximum number of chars in a line read from a file (including the null).
 
-// Define the _MSC_VER symbol if you are using Microsoft Visual C++.
+#define INPUTLINESIZE 2048
 
-// #define _MSC_VER
+// TetGen only uses the C standard library.
 
-// Define the _WIN64 symbol if you are running TetGen on Win64.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <assert.h> 
 
-// #define _WIN64
+// The types 'intptr_t' and 'uintptr_t' are signed and unsigned integer types,
+//   respectively. They are guaranteed to be the same width as a pointer.
+//   They are defined in <stdint.h> by the C99 Standard. However, Microsoft 
+//   Visual C++ 2003 -- 2008 (Visual C++ 7.1 - 9) doesn't ship with this header
+//   file. In such case, we can define them by ourself. 
+// Update (learned from Stack Overflow): Visual Studio 2010 and Visual C++ 2010
+//   Express both have stdint.h
+
+// The following piece of code was provided by Steven Johnson (MIT). Define the
+//   symbol _MSC_VER if you are using Microsoft Visual C++. Moreover, define 
+//   the _WIN64 symbol if you are running TetGen on Win64 systems.
 
 #ifdef _MSC_VER // Microsoft Visual C++
 #  ifdef _WIN64
@@ -81,31 +75,39 @@
 #  include <stdint.h>
 #endif
 
-// Maximum number of characters in a file name (including the null).
-
-#define FILENAMESIZE 1024
-
-// Maximum number of chars in a line read from a file (including the null).
-
-#define INPUTLINESIZE 2048
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // tetgenio                                                                  //
 //                                                                           //
-// A structure for transfering data into and out of TetGen.                  //
+// A structure for transferring data into and out of TetGen's mesh structure,//
+// 'tetgenmesh' (declared below).                                            //
+//                                                                           //
+// The input of TetGen is either a 3D point set, or a 3D piecewise linear    //
+// complex (PLC), or a tetrahedral mesh.  Depending on the input object and  //
+// the specified options, the output of TetGen is either a Delaunay (or wei- //
+// ghted Delaunay) tetrahedralization, or a constrained (Delaunay) tetrahed- //
+// ralization, or a quality tetrahedral mesh.                                //
+//                                                                           //
+// A piecewise linear complex (PLC) represents a 3D polyhedral domain with   //
+// possibly internal boundaries(subdomains). It is introduced in [Miller et  //
+// al, 1996]. Basically it is a set of "cells", i.e., vertices, edges, poly- //
+// gons, and polyhedra, and the intersection of any two of its cells is the  //
+// union of other cells of it.                                               //
+//                                                                           //
+// TetGen uses a set of files to describe the inputs and outputs. Each file  //
+// is identified from its file extension (.node, .ele, .face, .edge, etc).   //
 //                                                                           //
-// It holds a collection of arrays of data, i.e., points, facets, tetrahedra,//
-// and so forth. It contains functions to read and write (input and output)  //
-// files of TetGen as well as other supported mesh files.                    //
+// The 'tetgenio' structure is a collection of arrays of data, i.e., points, //
+// facets, tetrahedra, and so forth. It contains functions to read and write //
+// (input and output) files of TetGen as well as other supported mesh files. //
 //                                                                           //
 // Once an object of tetgenio is declared,  no array is created. One has to  //
 // allocate enough memory for them. On deletion of this object, the memory   //
 // occupied by these arrays needs to be freed.  The routine deinitialize()   //
 // will be automatically called.  It frees the memory for an array if it is  //
 // not a NULL. Note that it assumes that the memory is allocated by the C++  //
-// "new" operator.  Otherwise, the user must priorily free them by theirself //
-// and set the pointers to NULLs.                                            //
+// "new" operator.  Otherwise, the user is responsible to free them and all  //
+// pointers must be NULL before the call of the destructor.                  //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -114,18 +116,18 @@ class tetgenio {
 public:
 
   // A "polygon" describes a simple polygon (no holes). It is not necessarily
-  //   convex.  Each polygon contains number of corners (points) and the same
-  //   number of sides (edges).
-  // Note that the points of the polygon must be given in either counter-
-  //   clockwise or clockwise order and they form a ring, so every two
-  //   consective points forms an edge of the polygon.
+  //   convex. Each polygon contains a number of corners (points) and the same
+  //   number of sides (edges).  The points of the polygon must be given in
+  //   either counterclockwise or clockwise order and they form a ring, so 
+  //   every two consecutive points forms an edge of the polygon.
   typedef struct {
     int *vertexlist;
     int numberofvertices;
   } polygon;
 
-  // A "facet" describes a facet. Each facet is a polygonal region possibly 
-  //   with holes, edges, and points in it.
+  // A "facet" describes a polygonal region possibly with holes, edges, and 
+  //   points floating in it.  Each facet consists of a list of polygons and
+  //   a list of hole points (which lie strictly inside holes).
   typedef struct {
     polygon *polygonlist;
     int numberofpolygons;
@@ -157,19 +159,6 @@ public:
     int *elist;
   } vorofacet;
 
-  // The periodic boundary condition group data structure.  A "pbcgroup"
-  //   contains the definition of a pbc and the list of pbc point pairs.
-  //   'fmark1' and 'fmark2' are the facetmarkers of the two pbc facets f1
-  //   and f2, respectively. 'transmat' is the transformation matrix which
-  //   maps a point in f1 into f2.  An array of pbc point pairs are saved
-  //   in 'pointpairlist'. The first point pair is at indices [0] and [1],
-  //   followed by remaining pairs. Two integers per pair.
-  typedef struct {
-    int fmark1, fmark2;
-    REAL transmat[4][4];
-    int numberofpointpairs;
-    int *pointpairlist;
-  } pbcgroup;
 
   // Additional parameters associated with an input (or mesh) vertex.
   //   These informations are provided by CAD libraries. 
@@ -179,9 +168,6 @@ public:
     int type; // 0, 1, or 2.
   } pointparam;
 
-  // A callback function for mesh refinement.
-  typedef bool (* TetSizeFunc)(REAL*, REAL*, REAL*, REAL*, REAL*, REAL);
-
   // Callback functions for meshing PSCs.
   typedef REAL (* GetVertexParamOnEdge)(void*, int, int);
   typedef void (* GetSteinerOnEdge)(void*, int, REAL, REAL*);
@@ -189,6 +175,9 @@ public:
   typedef void (* GetEdgeSteinerParamOnFace)(void*, int, REAL, int, REAL*);
   typedef void (* GetSteinerOnFace)(void*, int, REAL*, REAL*);
 
+  // A callback function for mesh refinement.
+  typedef bool (* TetSizeFunc)(REAL*, REAL*, REAL*, REAL*, REAL*, REAL);
+
   // Items are numbered starting from 'firstnumber' (0 or 1), default is 0.
   int firstnumber; 
 
@@ -206,95 +195,108 @@ public:
   //   attributes occupy 'numberofpointattributes' REALs.
   // 'pointmtrlist': An array of metric tensors at points. Each point's
   //   tensor occupies 'numberofpointmtr' REALs.
-  // `pointmarkerlist':  An array of point markers; one integer per point.
+  // 'pointmarkerlist':  An array of point markers; one integer per point.
   REAL *pointlist;
   REAL *pointattributelist;
   REAL *pointmtrlist;
-  int *pointmarkerlist;
+  int  *pointmarkerlist;
   pointparam *pointparamlist;
   int numberofpoints;
   int numberofpointattributes;
   int numberofpointmtrs;
  
-  // `elementlist':  An array of element (triangle or tetrahedron) corners.
-  //   The first element's first corner is at index [0], followed by its
-  //   other corners in counterclockwise order, followed by any other
-  //   nodes if the element represents a nonlinear element.  Each element
-  //   occupies `numberofcorners' ints.
-  // `elementattributelist':  An array of element attributes.  Each
-  //   element's attributes occupy `numberofelementattributes' REALs.
-  // `elementconstraintlist':  An array of constraints, i.e. triangle's
-  //   area or tetrahedron's volume; one REAL per element.  Input only.
-  // `neighborlist':  An array of element neighbors; 3 or 4 ints per
-  //   element.  Output only.
-  int *tetrahedronlist;
+  // 'tetrahedronlist':  An array of tetrahedron corners.  The first 
+  //   tetrahedron's first corner is at index [0], followed by its other 
+  //   corners, followed by six nodes on the edges of the tetrahedron if the
+  //   second order option (-o2) is applied. Each tetrahedron occupies
+  //   'numberofcorners' ints.  The second order nodes are ouput only. 
+  // 'tetrahedronattributelist':  An array of tetrahedron attributes.  Each
+  //   tetrahedron's attributes occupy 'numberoftetrahedronattributes' REALs.
+  // 'tetrahedronvolumelist':  An array of constraints, i.e. tetrahedron's
+  //   volume; one REAL per element.  Input only.
+  // 'neighborlist':  An array of tetrahedron neighbors; 4 ints per element. 
+  //   Output only.
+  int  *tetrahedronlist;
   REAL *tetrahedronattributelist;
   REAL *tetrahedronvolumelist;
-  int *neighborlist;
+  int  *neighborlist;
   int numberoftetrahedra;
   int numberofcorners;
   int numberoftetrahedronattributes;
 
-  // `facetlist':  An array of facets.  Each entry is a structure of facet.
-  // `facetmarkerlist':  An array of facet markers; one int per facet.
+  // 'facetlist':  An array of facets.  Each entry is a structure of facet.
+  // 'facetmarkerlist':  An array of facet markers; one int per facet.
   facet *facetlist;
   int *facetmarkerlist;
   int numberoffacets;
 
-  // `holelist':  An array of holes.  The first hole's x, y and z
-  //   coordinates  are at indices [0], [1] and [2], followed by the
-  //   remaining holes. Three REALs per hole. 
+  // 'holelist':  An array of holes (in volume).  Each hole is given by a
+  //   seed (point) which lies strictly inside it. The first seed's x, y and z
+  //   coordinates are at indices [0], [1] and [2], followed by the
+  //   remaining seeds.  Three REALs per hole. 
   REAL *holelist;
   int numberofholes;
 
-  // `regionlist': An array of regional attributes and volume constraints.
-  //   The first constraint's x, y and z coordinates are at indices [0],
-  //   [1] and [2], followed by the regional attribute at index [3], foll-
-  //   owed by the maximum volume at index [4]. Five REALs per constraint.
-  // Note that each regional attribute is used only if you select the `A'
+  // 'regionlist': An array of regions (subdomains).  Each region is given by
+  //   a seed (point) which lies strictly inside it. The first seed's x, y and
+  //   z coordinates are at indices [0], [1] and [2], followed by the regional
+  //   attribute at index [3], followed by the maximum volume at index [4]. 
+  //   Five REALs per region.
+  // Note that each regional attribute is used only if you select the 'A'
   //   switch, and each volume constraint is used only if you select the
-  //   `a' switch (with no number following).
+  //   'a' switch (with no number following).
   REAL *regionlist;
   int numberofregions;
 
-  // `facetconstraintlist': An array of facet maximal area constraints.
-  //   Two REALs per constraint. The first (at index [0]) is the facet
-  //   marker (cast it to int), the second (at index [1]) is its maximum
-  //   area bound.
+  // 'facetconstraintlist':  An array of facet constraints.  Each constraint
+  //   specifies a maximum area bound on the subfaces of that facet.  The
+  //   first facet constraint is given by a facet marker at index [0] and its
+  //   maximum area bound at index [1], followed by the remaining facet con-
+  //   straints. Two REALs per facet constraint.  Note: the facet marker is
+  //   actually an integer.
   REAL *facetconstraintlist;
   int numberoffacetconstraints;
 
-  // `segmentconstraintlist': An array of segment max. length constraints.
-  //   Three REALs per constraint. The first two (at indcies [0] and [1]) 
-  //   are the indices of the endpoints of the segment, the third (at index
-  //   [2]) is its maximum length bound.
+  // 'segmentconstraintlist': An array of segment constraints. Each constraint 
+  //   specifies a maximum length bound on the subsegments of that segment.
+  //   The first constraint is given by the two endpoints of the segment at
+  //   index [0] and [1], and the maximum length bound at index [2], followed
+  //   by the remaining segment constraints.  Three REALs per constraint. 
+  //   Note the segment endpoints are actually integers.
   REAL *segmentconstraintlist;
   int numberofsegmentconstraints;
 
-  // 'pbcgrouplist':  An array of periodic boundary condition groups.
-  pbcgroup *pbcgrouplist;
-  int numberofpbcgroups;
-
-  // `trifacelist':  An array of triangular face endpoints.  The first
-  //   face's endpoints are at indices [0], [1] and [2], followed by the
-  //   remaining faces.  Three ints per face.
-  // `adjtetlist':  An array of adjacent tetrahedra to the faces of
-  //   trifacelist. Each face has at most two adjacent tets, the first
-  //   face's adjacent tets are at [0], [1]. Two ints per face. A '-1'
-  //   indicates outside (no adj. tet). This list is output when '-nn'
-  //   switch is used.
-  // `trifacemarkerlist':  An array of face markers; one int per face.
+
+  // 'trifacelist':  An array of face (triangle) corners.  The first face's
+  //   three corners are at indices [0], [1] and [2], followed by the remaining
+  //   faces.  Three ints per face.
+  // 'trifacemarkerlist':  An array of face markers; one int per face.
+  // 'o2facelist':  An array of second order nodes (on the edges) of the face.
+  //   It is output only if the second order option (-o2) is applied. The
+  //   first face's three second order nodes are at [0], [1], and [2],
+  //   followed by the remaining faces.  Three ints per face.
+  // 'adjtetlist':  An array of adjacent tetrahedra to the faces. The first
+  //   face's two adjacent tetrahedra are at indices [0] and [1], followed by
+  //   the remaining faces.  A '-1' indicates outside (no adj. tet). This list
+  //   is output when '-nn' switch is used. Output only.
   int *trifacelist;
-  int *adjtetlist;
   int *trifacemarkerlist;
+  int *o2facelist;
+  int *adjtetlist;
   int numberoftrifaces;
 
-  // `edgelist':  An array of edge endpoints.  The first edge's endpoints
-  //   are at indices [0] and [1], followed by the remaining edges.  Two
-  //   ints per edge.
-  // `edgemarkerlist':  An array of edge markers; one int per edge.
+  // 'edgelist':  An array of edge endpoints.  The first edge's endpoints
+  //   are at indices [0] and [1], followed by the remaining edges.
+  //   Two ints per edge.
+  // 'edgemarkerlist':  An array of edge markers; one int per edge.
+  // 'o2edgelist':  An array of midpoints of edges. It is output only if the
+  //   second order option (-o2) is applied. One int per edge.
+  // 'edgeadjtetlist':  An array of adjacent tetrahedra to the edges.  One
+  //   tetrahedron (an integer) per edge.
   int *edgelist;
   int *edgemarkerlist;
+  int *o2edgelist;
+  int *edgeadjtetlist;
   int numberofedges;
 
   // 'vpointlist':  An array of Voronoi vertex coordinates (like pointlist).
@@ -312,9 +314,6 @@ public:
   int numberofvfacets;
   int numberofvcells;
 
-  // A callback function.
-  TetSizeFunc tetunsuitable;
-
   // Variable (and callback functions) for meshing PSCs.
   void *geomhandle;
   GetVertexParamOnEdge getvertexparamonedge;
@@ -323,6 +322,9 @@ public:
   GetEdgeSteinerParamOnFace getedgesteinerparamonface;
   GetSteinerOnFace getsteineronface;
 
+  // A callback function.
+  TetSizeFunc tetunsuitable;
+
   // Input & output routines.
   bool load_node_call(FILE* infile, int markers, int uvflag, char*);
   bool load_node(char*);
@@ -370,8 +372,8 @@ public:
   // Initialize routine.
   void initialize()
   {
-    firstnumber = 0; // Default item index is numbered from Zero.
-    mesh_dim = 3; // Default mesh dimension is 3.
+    firstnumber = 0;
+    mesh_dim = 3;
     useindex = 1;
 
     pointlist = (REAL *) NULL;
@@ -388,22 +390,25 @@ public:
     tetrahedronvolumelist = (REAL *) NULL;
     neighborlist = (int *) NULL;
     numberoftetrahedra = 0;
-    numberofcorners = 4; // Default is 4 nodes per element.
+    numberofcorners = 4; 
     numberoftetrahedronattributes = 0;
 
     trifacelist = (int *) NULL;
-    adjtetlist = (int *) NULL;
     trifacemarkerlist = (int *) NULL;
+    o2facelist = (int *) NULL;
+    adjtetlist = (int *) NULL;
     numberoftrifaces = 0; 
 
-    facetlist = (facet *) NULL;
-    facetmarkerlist = (int *) NULL;
-    numberoffacets = 0; 
-
     edgelist = (int *) NULL;
     edgemarkerlist = (int *) NULL;
+    o2edgelist = (int *) NULL;
+    edgeadjtetlist = (int *) NULL;
     numberofedges = 0;
 
+    facetlist = (facet *) NULL;
+    facetmarkerlist = (int *) NULL;
+    numberoffacets = 0; 
+
     holelist = (REAL *) NULL;
     numberofholes = 0;
 
@@ -415,8 +420,6 @@ public:
     segmentconstraintlist = (REAL *) NULL;
     numberofsegmentconstraints = 0;
 
-    pbcgrouplist = (pbcgroup *) NULL;
-    numberofpbcgroups = 0;
 
     vpointlist = (REAL *) NULL;
     vedgelist = (voroedge *) NULL;
@@ -437,17 +440,12 @@ public:
     getsteineronface = NULL;
   }
 
-  // Free the memory allocated in 'tetgenio'.  
+  // Free the memory allocated in 'tetgenio'.  Note that it assumes that the 
+  //   memory was allocated by the "new" operator (C++).
   void deinitialize()
   {
-    facet *f;
-    polygon *p;
-    pbcgroup *pg;
     int i, j;
 
-    // Notince that this routine assumes that the memory was allocated by 
-    //   C++ memory allocation operator 'new'.
-
     if (pointlist != (REAL *) NULL) {
       delete [] pointlist;
     }
@@ -480,12 +478,15 @@ public:
     if (trifacelist != (int *) NULL) {
       delete [] trifacelist;
     }
-    if (adjtetlist != (int *) NULL) {
-      delete [] adjtetlist;
-    }
     if (trifacemarkerlist != (int *) NULL) {
       delete [] trifacemarkerlist;
     }
+    if (o2facelist != (int *) NULL) {
+      delete [] o2facelist;
+    }
+    if (adjtetlist != (int *) NULL) {
+      delete [] adjtetlist;
+    }
 
     if (edgelist != (int *) NULL) {
       delete [] edgelist;
@@ -493,8 +494,16 @@ public:
     if (edgemarkerlist != (int *) NULL) {
       delete [] edgemarkerlist;
     }
+    if (o2edgelist != (int *) NULL) {
+      delete [] o2edgelist;
+    }
+    if (edgeadjtetlist != (int *) NULL) {
+      delete [] edgeadjtetlist;
+    }
 
     if (facetlist != (facet *) NULL) {
+      facet *f;
+      polygon *p;
       for (i = 0; i < numberoffacets; i++) {
         f = &facetlist[i];
         for (j = 0; j < f->numberofpolygons; j++) {
@@ -524,15 +533,6 @@ public:
     if (segmentconstraintlist != (REAL *) NULL) {
       delete [] segmentconstraintlist;
     }
-    if (pbcgrouplist != (pbcgroup *) NULL) {
-      for (i = 0; i < numberofpbcgroups; i++) {
-        pg = &(pbcgrouplist[i]);
-        if (pg->pointpairlist != (int *) NULL) {
-          delete [] pg->pointpairlist;
-        }
-      }
-      delete [] pbcgrouplist;
-    }
     if (vpointlist != (REAL *) NULL) {
       delete [] vpointlist;
     }
@@ -563,12 +563,16 @@ public:
 //                                                                           //
 // tetgenbehavior                                                            //
 //                                                                           //
-// A structure to maintain the switches and parameters of TetGen.            //
+// A structure for maintaining the switches and parameters used by TetGen's  //
+// mesh data structure and algorithms.                                       //
 //                                                                           //
-// parse_commandline() provides an simple interface to set the vaules of the //
-// variables.  It accepts the standard parameters (e.g., 'argc' and 'argv')  //
-// that pass to C/C++ main() function. Alternatively a string which contains //
-// the command line options can be used as its parameter.                    //
+// All switches and parameters are initialized with default values. They can //
+// be set by the command line arguments (a list of strings) of TetGen.       //
+//                                                                           //
+// NOTE: Some of the switches are incompatible. While some may depend on     //
+// other switches.  The routine parse_commandline() sets the switches from   //
+// the command line (a list of strings) and checks the consistency of the    //
+// applied switches.                                                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -576,93 +580,98 @@ class tetgenbehavior {
 
 public:
 
-  // Switches of TetGen. They are briefly described in the function syntax().
-  //   Plerase consult the user's manual for complete explanations. The last
-  //   column indicates their initial values. 
-  int plc;                                                 // '-p' switch, 0.
-  int psc;                                                 // '-s' switch, 0.
-  int quality;                                             // '-q' switch, 0.
-  int refine;                                              // '-r' switch, 0.
-  int metric;                                              // '-m' switch, 0.
-  int nobisect;                                            // '-Y' switch, 0.
-  int weighted;                                            // '-w' switch, 0.
-  int varvolume;                            // '-a' switch without number, 0.
-  int fixedvolume;                             // '-a' switch with number, 0.
-  int incrflip;                                            // '-l' switch, 0.
-  int flipinsert;                                          // '-L' switch, 0.
-  int btree;                                               // '-u' switch, 0.
-  int hilbertcurve;                                        // '-U' switch, 0.
-  int insertaddpoints;                                     // '-i' switch, 0.
-  int regionattrib;                                        // '-A' switch, 0.
-  int conforming;                                          // '-D' switch, 0.
-  int diagnose;                                            // '-d' switch, 0.
-  int convex;                                              // '-c' switch, 0.
-  int zeroindex;                                           // '-z' switch, 0.
-  int facesout;                                            // '-f' switch, 0.
-  int edgesout;                                            // '-e' switch, 0.
-  int neighout;                                            // '-n' switch, 0.
-  int voroout;                                             // '-v',switch, 0.
-  int meditview;                                           // '-g' switch, 0.
-  int vtkview;                                             // '-K' switch, 0.
-  int nobound;                                             // '-B' switch, 0.
-  int nonodewritten;                                       // '-N' switch, 0.
-  int noelewritten;                                        // '-E' switch, 0.
-  int nofacewritten;                                       // '-F' switch, 0.
-  int noiterationnum;                                      // '-I' switch, 0.
-  int nomerge;                                             // '-M' switch, 0.
-  int nojettison;                                          // '-J' switch, 0.
-  int docheck;                                             // '-C' switch, 0.
-  int quiet;                                               // '-Q' switch, 0.
-  int verbose;                                             // '-V' switch, 0.
-
-  // Parameters of TetGen.  They are numbers specified after switches.  The
-  //   last colume indicates their initial values.
-  int vertexperblock;                                    // after '-b', 4092.
-  int tetrahedraperblock;                                // after '-b', 8188.
-  int shellfaceperblock;                                 // after '-b', 4092.
-  int nobisect_param;                                       // after '-Y', 1.
-  int weighted_param;                                       // after '-w', 0.
-  int flipinsert_random;                                    // after '-L', 0.
-  int flipinsert_ori4dexact;                                // after '-L', 0.
-  int fliplinklevel;                                       // after '-L', -1.
-  int flipstarsize;                                       // after '-LL', -1.
-  int fliplinklevelinc;                                  // after '-LLLL', 1.
-  int max_btreenode_size;                                 // after '-u', 100.
-  int reflevel;                                             // after '-D', 3.
-  int optlevel;                                             // after '-O', 7.
-  int optpasses;                                           // after '-OO', 3.
-  int optmaxfliplevel;                                    // after '-OOO', 2.
-  int delmaxfliplevel;                                   // after '-OOOO', 1.
-  int optmaxflipstarsize;                              // after '-OOOOO', 10.
-  int order;                                                // after '-o', 1.
-  int steinerleft;                                          // after '-S', 0.
-  REAL facet_ang_tol;                                   // after '-p', 179.9.
-  REAL maxvolume;                                        // after '-a', -1.0.
-  REAL minratio;                                          // after '-q', 0.0.
-  REAL mindihedral;                                      // after '-qq', 5.0.
-  REAL optmaxdihedral;                                  // after '-o', 165.0.
-  REAL optminsmtdihed;                                 // after '-oo', 175.0.
-  REAL optminslidihed;                                // after '-ooo', 179.0.  
-  REAL epsilon;                                        // after '-T', 1.0e-8.
-  REAL minedgelength;     // The shortest length of an edge, after '-l', 0.0.
-
-  // Variables used to save command line switches and in/out file names.
+  // Switches of TetGen. 
+  int plc;                                                         // '-p', 0.
+  int psc;                                                         // '-s', 0.
+  int refine;                                                      // '-r', 0.
+  int quality;                                                     // '-q', 0.
+  int nobisect;                                                    // '-Y', 0.
+  int coarsen;                                                     // '-R', 0.
+  int weighted;                                                    // '-w', 0.
+  int brio_hilbert;                                                // '-b', 1.
+  int incrflip;                                                    // '-l', 0.
+  int flipinsert;                                                  // '-L', 0.
+  int metric;                                                      // '-m', 0.
+  int varvolume;                                                   // '-a', 0.
+  int fixedvolume;                                                 // '-a', 0.
+  int regionattrib;                                                // '-A', 0.
+  int conforming;                                                  // '-D', 0.
+  int insertaddpoints;                                             // '-i', 0.
+  int diagnose;                                                    // '-d', 0.
+  int convex;                                                      // '-c', 0.
+  int nomergefacet;                                                // '-M', 0.
+  int nomergevertex;                                               // '-M', 0.
+  int noexact;                                                     // '-X', 0.
+  int nostaticfilter;                                              // '-X', 0.
+  int zeroindex;                                                   // '-z', 0.
+  int facesout;                                                    // '-f', 0.
+  int edgesout;                                                    // '-e', 0.
+  int neighout;                                                    // '-n', 0.
+  int voroout;                                                     // '-v', 0.
+  int meditview;                                                   // '-g', 0.
+  int vtkview;                                                     // '-k', 0.
+  int nobound;                                                     // '-B', 0.
+  int nonodewritten;                                               // '-N', 0.
+  int noelewritten;                                                // '-E', 0.
+  int nofacewritten;                                               // '-F', 0.
+  int noiterationnum;                                              // '-I', 0.
+  int nojettison;                                                  // '-J', 0.
+  int reversetetori;                                               // '-R', 0.
+  int docheck;                                                     // '-C', 0.
+  int quiet;                                                       // '-Q', 0.
+  int verbose;                                                     // '-V', 0.
+
+  // Parameters of TetGen. 
+  int vertexperblock;                                           // '-x', 4092.
+  int tetrahedraperblock;                                       // '-x', 8188.
+  int shellfaceperblock;                                        // '-x', 2044.
+  int nobisect_param;                                              // '-Y', 2.
+  int addsteiner_algo;                                            // '-Y/', 1.
+  int coarsen_param;                                               // '-R', 0.
+  int weighted_param;                                              // '-w', 0.
+  int fliplinklevel;                                                    // -1.
+  int flipstarsize;                                                     // -1.
+  int fliplinklevelinc;                                                 //  1.
+  int reflevel;                                                    // '-D', 3.
+  int optlevel;                                                    // '-O', 2.
+  int optscheme;                                                   // '-O', 7.
+  int delmaxfliplevel;                                                   // 1.
+  int order;                                                       // '-o', 1.
+  int steinerleft;                                                 // '-S', 0.
+  int no_sort;                                                           // 0.
+  int hilbert_order;                                           // '-b///', 52.
+  int hilbert_limit;                                             // '-b//'  8.
+  int brio_threshold;                                              // '-b' 64.
+  REAL brio_ratio;                                             // '-b/' 0.125.
+  REAL facet_ang_tol;                                          // '-p', 179.9.
+  REAL maxvolume;                                               // '-a', -1.0.
+  REAL minratio;                                                 // '-q', 0.0.
+  REAL mindihedral;                                              // '-q', 5.0.
+  REAL optmaxdihedral;                                               // 165.0.
+  REAL optminsmtdihed;                                               // 179.0.
+  REAL optminslidihed;                                               // 179.0.  
+  REAL epsilon;                                               // '-T', 1.0e-8.
+  REAL minedgelength;                                                  // 0.0.
+  REAL coarsen_percent;                                         // -R1/#, 1.0.
+
+  // Strings of command line arguments and input/output file names.
   char commandline[1024];
   char infilename[1024];
   char outfilename[1024];
   char addinfilename[1024];
   char bgmeshfilename[1024];
 
-  // The input object type of TetGen. They are recognized by the input file
-  //   extensions. Currently the following objects are supported:
+  // The input object of TetGen. They are recognized by either the input 
+  //   file extensions or by the specified options. 
+  // Currently the following objects are supported:
   //   - NODES, a list of nodes (.node); 
   //   - POLY, a piecewise linear complex (.poly or .smesh); 
   //   - OFF, a polyhedron (.off, Geomview's file format); 
-  //   - PLY, a polyhedron (.ply, file format from gatech);
+  //   - PLY, a polyhedron (.ply, file format from gatech, only ASCII);
   //   - STL, a surface mesh (.stl, stereolithography format);
   //   - MEDIT, a surface mesh (.mesh, Medit's file format); 
   //   - MESH, a tetrahedral mesh (.ele).
-  //   If no extension is available, the imposed commandline switch
+  // If no extension is available, the imposed command line switch
   //   (-p or -r) implies the object. 
   enum objecttype {NODES, POLY, OFF, PLY, STL, MEDIT, VTK, MESH} object;
 
@@ -681,17 +690,19 @@ public:
   {
     plc = 0;
     psc = 0;
-    quality = 0;
     refine = 0;
-    metric = 0;
+    quality = 0;
     nobisect = 0;
+    coarsen = 0;
+    metric = 0;
     weighted = 0;
-    varvolume = 0;
-    fixedvolume = 0;
+    brio_hilbert = 1;
     incrflip = 0;
     flipinsert = 0;
-    btree = 0;
-    hilbertcurve = 0;
+    varvolume = 0;
+    fixedvolume = 0;
+    noexact = 0;
+    nostaticfilter = 0;
     insertaddpoints = 0;
     regionattrib = 0;
     conforming = 0;
@@ -709,8 +720,10 @@ public:
     noelewritten = 0;
     nofacewritten = 0;
     noiterationnum = 0;
-    nomerge = 0;
+    nomergefacet = 0;
+    nomergevertex = 0;
     nojettison = 0;
+    reversetetori = 0;
     docheck = 0;
     quiet = 0;
     verbose = 0;
@@ -718,31 +731,34 @@ public:
     vertexperblock = 4092;
     tetrahedraperblock = 8188;
     shellfaceperblock = 4092;
-    nobisect_param = 1;
+    nobisect_param = 2;
+    addsteiner_algo = 1;
+    coarsen_param = 0;
     weighted_param = 0;
-    flipinsert_random = 0;
-    flipinsert_ori4dexact = 0;
     fliplinklevel = -1; // No limit on linklevel.
     flipstarsize = -1;  // No limit on flip star size.
     fliplinklevelinc = 1;
-    max_btreenode_size = 100; // Default use b-tree sorting.
     reflevel = 3;
-    optlevel = 7;  // 1 & 2 & 4, // min_max_dihedral.
-    optpasses = 3;
-    optmaxfliplevel = 2;
+    optscheme = 7;  // 1 & 2 & 4, // min_max_dihedral.
+    optlevel = 2;
     delmaxfliplevel = 1;
-    optmaxflipstarsize = 10;
     order = 1;
     steinerleft = -1;
+    no_sort = 0;
+    hilbert_order = 52; //-1;
+    hilbert_limit = 8;
+    brio_threshold = 64;
+    brio_ratio = 0.125;
     facet_ang_tol = 179.9;
     maxvolume = -1.0;
     minratio = 2.0;
-    mindihedral = 0.0; // 5.0;
+    mindihedral = 0.0; // 5.0; 
     optmaxdihedral = 165.00; // without -q, default is 179.0
     optminsmtdihed = 179.00; // without -q, default is 179.999
     optminslidihed = 179.00; // without -q, default is 179.999
     epsilon = 1.0e-8;
     minedgelength = 0.0;
+    coarsen_percent = 1.0;
     object = NODES;
 
     commandline[0] = '\0';
@@ -757,45 +773,42 @@ public:
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Geometric predicates                                                      //
-//                                                                           //
-// Return one of the values +1, 0, and -1 on basic geometric questions such  //
-// as the orientation of point sets, in-circle, and in-sphere tests.  They   //
-// are basic units for implmenting geometric algorithms.  TetGen uses two 3D //
-// geometric predicates: the orientation and in-sphere tests.                //
-//                                                                           //
-// Orientation test:  let a, b, c be a sequence of 3 non-collinear points in //
-// R^3.  They defines a unique hypeplane H.  Let H+ and H- be the two spaces //
-// separated by H, which are defined as follows (using the left-hand rule):  //
-// make a fist using your left hand in such a way that your fingers follow   //
-// the order of a, b and c, then your thumb is pointing to H+.  Given any    //
-// point d in R^3, the orientation test returns +1 if d lies in H+, -1 if d  //
-// lies in H-, or 0 if d lies on H.                                          //
-//                                                                           //
-// In-sphere test:  let a, b, c, d be 4 non-coplanar points in R^3.  They    //
-// defines a unique circumsphere S.  Given any point e in R^3, the in-sphere //
-// test returns +1 if e lies inside S, or -1 if e lies outside S, or 0 if e  //
-// lies on S.                                                                //
-//                                                                           //
-// The following routines use arbitrary precision floating-point arithmetic. //
-// They are provided by J. R. Schewchuk in public domain (http://www.cs.cmu. //
-// edu/~quake/robust.html). The source code are in "predicates.cxx".         //
+// Robust Geometric predicates                                               //
+//                                                                           //
+// Geometric predicates are simple tests of spatial relations of a set of d- //
+// dimensional points, such as the orientation test and the point-in-sphere  //
+// test. Each of these tests is performed by evaluating the sign of a deter- //
+// minant of a matrix whose entries are the coordinates of these points.  If //
+// the computation is performed by using the floating-point numbers, e.g.,   //
+// the single or double precision numbers in C/C++, roundoff error may cause //
+// an incorrect result. This may either lead to a wrong result or eventually //
+// lead to a failure of the program.  Computing the predicates exactly will  //
+// avoid the error and make the program robust.                              //
+//                                                                           //
+// The following routines are the robust geometric predicates for 3D orient- //
+// ation test and point-in-sphere test.  They were implemented by Shewchuk.  //
+// The source code are generously provided by him in the public domain,      //
+// http://www.cs.cmu.edu/~quake/robust.html. predicates.cxx is a C++ version //
+// of the original C code.                                                   //
+//                                                                           //
+// The original predicates of Shewchuk only use "dynamic filters", i.e., it  //
+// computes the error at run time step by step. TetGen first adds a "static  //
+// filter" in each predicate. It estimates the maximal possible error in all //
+// cases.  So it can safely and quickly answer many easy cases.              //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-REAL exactinit();
+void exactinit(int, int, int, REAL, REAL, REAL);
 REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
 REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
 REAL orient4d(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
               REAL ah, REAL bh, REAL ch, REAL dh, REAL eh);
-REAL orient4dexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
-                   REAL ah, REAL bh, REAL ch, REAL dh, REAL eh);
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // tetgenmesh                                                                //
 //                                                                           //
-// The object to generate tetrahedral meshes.                                //
+// A structure for creating and updating tetrahedral meshes.                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -803,64 +816,45 @@ class tetgenmesh {
 
 public:
 
-  // Labels that signify the type of a vertex. 
-  enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, RIDGEVERTEX, ACUTEVERTEX,
-                 FACETVERTEX, VOLVERTEX, FREESEGVERTEX, FREEFACETVERTEX, 
-                 FREEVOLVERTEX, HIDDENVERTEX, DEADVERTEX};
- 
-  // Labels that signify the type of a subsegment.
-  enum shestype {NSHARP, SHARP, FAKESH};
-
-  // Labels that signify the result of triangle-triangle intersection test.
-  enum interresult {DISJOINT, INTERSECT, SHAREVERT, SHAREEDGE, SHAREFACE,
-                    TOUCHEDGE, TOUCHFACE, ACROSSVERT, ACROSSEDGE, ACROSSFACE, 
-                    COLLISIONFACE, ACROSSSEG, ACROSSSUB};
-
-  // Labels that signify the result of point location.
-  enum locateresult {OUTSIDE, INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, INSTAR,
-                     ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX,BADELEMENT};
-
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Mesh data structure                                                       //
 //                                                                           //
-// A tetrahedral mesh of a 3D domain is a 3D simplicial complex T whose und- //
-// erlying space is homeomorphic to the domain. T contains a 2D subcomplex S //
-// which is a triangular mesh of the boundary of the domain. S contains a 1D //
-// subcomplex L which is a linear mesh of the boundary of the surface. Faces //
-// and edges in S and L are respectivly called subfaces and segments to dis- //
-// tinguish them from others in T.                                           //
-//                                                                           //
-// The data structure to represent a tetrahedral mesh stores the tetrahedra  //
-// and vertices of T. Each tetrahedron is a structure including informations //
-// of its vertices and adjacencies. Each vertex carries its geometric coord- //
-// inates. The faces and edges of T are implicitly represented by tetrahedra.//
-// This representation has a clear separation between combinatoric and geom- //
-// etric data of a tetrahedral mesh.                                         //
-//                                                                           //
-// A hull face of T is the face on the exterior domain boundary, i.e., it is //
-// contained by only one tetrahedron in T. TetGen adds fictitious tetrahedra //
-// (one-to-one) at the hull faces of T, and connects them to an "infinite    //
-// vertex" which has no geometric coordinates. One can imagine such a vertex //
-// lies in 4D space and is visible by all tetrahedra containing hull faces.  //
-// The extended set of tetrahedra with the infinite vertex is a tetrahedral- //
-// ization of a compact 3-manifold without bounday. It has the property that //
-// every face is shared by exactly two tetrahedra.                           //
-//                                                                           //
-// The data structure stores explicitly the subfaces and segments (which are //
-// in surface mesh S and the linear mesh L, respectively. Additional inform- //
-// ations are stored in tetrahedra and subfaces to remember their relations. //
+// A tetrahedral mesh T of a 3D piecewise linear complex (PLC) X is a 3D     //
+// simplicial complex whose underlying space is equal to the space of X.  T  //
+// contains a 2D subcomplex S which is a triangular mesh of the boundary of  //
+// X. S contains a 1D subcomplex L which is a linear mesh of the boundary of //
+// S. Faces and edges in S and L are respectively called subfaces and segme- //
+// nts to distinguish them from others in T.                                 //
+//                                                                           //
+// TetGen stores the tetrahedra and vertices of T. The basic structure of a  //
+// tetrahedron contains pointers to its vertices and adjacent tetrahedra. A  //
+// vertex stores its x-, y-, and z-coordinates, and a pointer to a tetrahed- //
+// ron containing it. Both tetrahedra and vertices may contain user data.    // 
+//                                                                           //
+// Each face of T belongs to either two tetrahedra or one tetrahedron. In    //
+// the latter case, the face is an exterior boundary face of T.  TetGen adds //
+// fictitious tetrahedra (one-to-one) at such faces, and connects them to an //
+// "infinite vertex" (which has no geometric coordinates).  One can imagine  //
+// such a vertex lies in 4D space and is visible by all exterior boundary    //
+// faces.  The extended set of tetrahedra (including the infinite vertex) is //
+// a tetrahedralization of a 3-pseudomanifold without boundary.  It has the  //
+// property that every face is shared by exactly two tetrahedra.             // 
+//                                                                           //
+// The current version of TetGen stores explicitly the subfaces and segments //
+// (which are in surface mesh S and the linear mesh L), respectively.  Extra //
+// pointers are allocated in tetrahedra and subfaces to point each others.   //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
   // The tetrahedron data structure.  It includes the following fields:
   //   - a list of four adjoining tetrahedra;
   //   - a list of four vertices;
-  //   - a list of four subfaces (optional, for -p switch);
-  //   - a list of  six segments (optional, for -p switch);
+  //   - a pointer to a list of four subfaces (optional, for -p switch);
+  //   - a pointer to a list of six segments  (optional, for -p switch);
   //   - a list of user-defined floating-point attributes (optional);
   //   - a volume constraint (optional, for -a switch);
-  //   - an integer of element marker;
+  //   - an integer of element marker (and flags);
   // The structure of a tetrahedron is an array of pointers.  Its actual size
   //   (the length of the array) is determined at runtime.
 
@@ -873,8 +867,7 @@ public:
   //   - two adjoining tetrahedra;
   //   - an area constraint (optional, for -q switch);
   //   - an integer for boundary marker;
-  //   - an integer for type: SHARPSEGMENT, NONSHARPSEGMENT, ...;
-  //   - an integer for pbc group (optional, if in->pbcgrouplist exists);
+  //   - an integer for type, flags, etc.
 
   typedef REAL **shellface;
 
@@ -884,11 +877,11 @@ public:
   //   - u, v coordinates (optional, for -s switch);
   //   - a metric tensor (optional, for -q or -m switch);
   //   - a pointer to an adjacent tetrahedron;
-  //   - a pointer to a parent (or a duplicate) point, or a bsp_tree node;
+  //   - a pointer to a parent (or a duplicate) point;
   //   - a pointer to an adjacent subface or segment (optional, -p switch);
   //   - a pointer to a tet in background mesh (optional, for -m switch);
   //   - an integer for boundary marker (point index);
-  //   - an integer for point type.
+  //   - an integer for point type (and flags).
   //   - an integer for geometry tag (optional, for -s switch).
   // The structure of a point is an array of REALs.  Its acutal size is 
   //   determined at the runtime.
@@ -897,25 +890,23 @@ public:
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Ordered tetrahedra                                                        //
+// Handles                                                                   //
 //                                                                           //
-// The four vertices of a tetrahedron can be permuted in 24 different seque- //
-// nces.  We call each sequence resulted by an even permutation an "ordered  //
-// tetrahedron".  There are total 12 ordered tetrahedra.  They form a group  //
-// which is isomorphic to the alternating group of 4 elements. Geometrically,//
-// if we direct the three edges within a face of a tetrahedron by the count- //
-// erclockwise order viewed from the opposite vertex of this face (using ei- //
-// ther right-hand or left-hand rule). There are total twelve directed edges //
-// in the tetrahedron. Each of them corresponds to an ordered tetrahedron.   //
+// Navigation and manipulation in a tetrahedralization are accomplished by   //
+// operating on structures referred as ``handles". A handle is a pair (t,v), //
+// where t is a pointer to a tetrahedron, and v is a 4-bit integer, in the   //
+// range from 0 to 11. v is called the ``version'' of a tetrahedron, it rep- //
+// resents a directed edge of a specific face of the tetrahedron.            //
 //                                                                           //
-// We represent an order tetrahedron by a pair (t, v), where t is a pointer  //
-// to the tetrahedron and v is a four-bit integer, in the range from 0 to 11,//
-// identifying the ordered version of the tetrahedron.  Assume the faces of  //
-// the tetrahedron is numbered from 0 to 3, and the edges in a face is numb- //
-// ered from 0 to 2. The first two bits of v is used to identify the face of //
-// the tetrahedron. The other two bits of v identify the edge in the face.   //
+// There are 12 even permutations of the four vertices, each of them corres- //
+// ponds to a directed edge (a version) of the tetrahedron.  The 12 versions //
+// can be grouped into 4 distinct ``edge rings'' in 4 ``oriented faces'' of  //
+// this tetrahedron.  One can encode each version (a directed edge) into a   //
+// 4-bit integer such that the two upper bits encode the index (from 0 to 2) //
+// of this edge in the edge ring, and the two lower bits encode the index (  //
+// from 0 to 3) of the oriented face which contains this edge.               //  
 //                                                                           //
-// The four vertices of a tetrahedron are indexed from 0 to 3 (accodring to  //
+// The four vertices of a tetrahedron are indexed from 0 to 3 (according to  //
 // their storage in the data structure).  Give each face the same index as   //
 // the node opposite it in the tetrahedron.  Denote the edge connecting face //
 // i to face j as i/j. We number the twelve versions as follows:             //
@@ -927,19 +918,10 @@ public:
 //    face 2 |   2 (2/3)    6 (2/1)   10 (2/0)                               //
 //    face 3 |   3 (3/0)    7 (3/1)   11 (3/2)                               //
 //                                                                           //
-// Ordered triangles                                                         //
-//                                                                           //
-// The three vertices of a triangle can be permuted in 6 different sequences //
-// which form a group isomorphic to the symmetric group of 3 elements. Each  //
-// permutation of the vertices is called an ordered triangle.  The first two //
-// vertices of an ordered triangle defines an directed edge. There are total //
-// six directed edge in the triangle.  They can be divided into two groups,  //
-// which correspond the two orientations of the triangle, respectively.      //
-//                                                                           //
-// We represent an ordered triangle by a pair (s, v),  where s is a pointer  //
-// to the triangle and v is a three-bit integer, in the range from 0 to 5,   //
-// identifying the directed edge of the triangle.  Using the first bit of v  //
-// to identify the orientation, the other two bits of v identify the edge.   //
+// Similarly, navigation and manipulation in a (boundary) triangulation are  //
+// done by using handles of triangles. Each handle is a pair (s, v), where s //
+// is a pointer to a triangle, and v is a version in the range from 0 to 5.  //
+// Each version corresponds to a directed edge of this triangle.             //
 //                                                                           //
 // Number the three vertices of a triangle from 0 to 2 (according to their   //
 // storage in the data structure). Give each edge the same index as the node //
@@ -950,6 +932,9 @@ public:
 //   ccw orieation |   0        2        4                                   //
 //    cw orieation |   1        3        5                                   //
 //                                                                           //
+// In the following, a 'triface' is a handle of tetrahedron, and a 'face' is //
+// a handle of a triangle.                                                   //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
   class triface {
@@ -974,12 +959,110 @@ public:
     }
   };
 
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Arraypool                                                                 //
+//                                                                           //
+// A dynamic linear array. (It is written by J. Shewchuk)                    //
+//                                                                           //
+// Each arraypool contains an array of pointers to a number of blocks.  Each //
+// block contains the same fixed number of objects.  Each index of the array //
+// addresses a particular object in the pool. The most significant bits add- //
+// ress the index of the block containing the object. The less significant   //
+// bits address this object within the block.                                //
+//                                                                           //
+// 'objectbytes' is the size of one object in blocks; 'log2objectsperblock'  //
+// is the base-2 logarithm of 'objectsperblock'; 'objects' counts the number //
+// of allocated objects; 'totalmemory' is the total memory in bytes.         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class arraypool {
+
+  public:
+
+    int objectbytes;
+    int objectsperblock;
+    int log2objectsperblock;
+    int objectsperblockmark;
+    int toparraylen;
+    char **toparray;
+    long objects;
+    unsigned long totalmemory;
+
+    void restart();
+    void poolinit(int sizeofobject, int log2objperblk);
+    char* getblock(int objectindex);
+    void* lookup(int objectindex);
+    int newindex(void **newptr);
+
+    arraypool(int sizeofobject, int log2objperblk);
+    ~arraypool();
+  };
+
+// fastlookup() -- A fast, unsafe operation. Return the pointer to the object
+//   with a given index.  Note: The object's block must have been allocated,
+//   i.e., by the function newindex().
+
+#define fastlookup(pool, index) \
+  (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] + \
+            ((index) & (pool)->objectsperblockmark) * (pool)->objectbytes)
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Memorypool                                                                //
+//                                                                           //
+// A structure for memory allocation. (It is written by J. Shewchuk)         //
+//                                                                           //
+// firstblock is the first block of items. nowblock is the block from which  //
+//   items are currently being allocated. nextitem points to the next slab   //
+//   of free memory for an item. deaditemstack is the head of a linked list  //
+//   (stack) of deallocated items that can be recycled.  unallocateditems is //
+//   the number of items that remain to be allocated from nowblock.          //
+//                                                                           //
+// Traversal is the process of walking through the entire list of items, and //
+//   is separate from allocation.  Note that a traversal will visit items on //
+//   the "deaditemstack" stack as well as live items.  pathblock points to   //
+//   the block currently being traversed.  pathitem points to the next item  //
+//   to be traversed.  pathitemsleft is the number of items that remain to   //
+//   be traversed in pathblock.                                              //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+  class memorypool {
+
+  public:
+
+    void **firstblock, **nowblock;
+    void *nextitem;
+    void *deaditemstack;
+    void **pathblock;
+    void *pathitem;
+    int  alignbytes;
+    int  itembytes, itemwords;
+    int  itemsperblock;
+    long items, maxitems;
+    int  unallocateditems;
+    int  pathitemsleft;
+
+    memorypool();
+    memorypool(int, int, int, int);
+    ~memorypool();
+    
+    void poolinit(int, int, int, int);
+    void restart();
+    void *alloc();
+    void dealloc(void*);
+    void traversalinit();
+    void *traverse();
+  };  
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // badface                                                                   //
 //                                                                           //
-// A multiple usages structure. Despite of its name, a 'badface' can be used //
-// to represent the following objects:                                       //
+// Despite of its name, a 'badface' can be used to represent one of the      //
+// following objects:                                                        //
 //   - a face of a tetrahedron which is (possibly) non-Delaunay;             //
 //   - an encroached subsegment or subface;                                  //
 //   - a bad-quality tetrahedron, i.e, has too large radius-edge ratio;      //
@@ -991,12 +1074,12 @@ public:
   class badface {
   public:
     triface tt; 
-    face ss; 
+    face ss;
     REAL key, cent[6];  // circumcenter or cos(dihedral angles) at 6 edges.
     point forg, fdest, fapex, foppo, noppo;
-    badface *previtem, *nextitem; 
+    badface *nextitem; 
     badface() : key(0), forg(0), fdest(0), fapex(0), foppo(0), noppo(0),
-      previtem(0), nextitem(0) {}
+      nextitem(0) {}
   };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1011,28 +1094,33 @@ public:
 
   public:
 
-    int iloc, bowywat, lawson;
-    int rejflag, chkencflag;
-    int sloc, sbowywat;
+    int iloc;  // input/output.
+    int bowywat, lawson;
     int splitbdflag, validflag, respectbdflag;
+    int rejflag, chkencflag, cdtflag;
     int assignmeshsize;
+    int sloc, sbowywat;
 
     // Used by Delaunay refinement.
     int refineflag; // 0, 1, 2, 3
     triface refinetet;
     face refinesh;
+    int smlenflag; // for useinsertradius.
+    REAL smlen; // for useinsertradius.
+    point parentpt;
 
     insertvertexflags() {
-      // All flags are initialized as 0.
       iloc = bowywat = lawson = 0;
-      rejflag = chkencflag = 0;
-      sloc = sbowywat = 0;
       splitbdflag = validflag = respectbdflag = 0;
+      rejflag = chkencflag = cdtflag = 0;
       assignmeshsize = 0;
+      sloc = sbowywat = 0;
 
       refineflag = 0;
       refinetet.tet = NULL;
       refinesh.sh = NULL;
+      smlenflag = 0;
+      smlen = 0.0;
     }
   };
 
@@ -1049,11 +1137,9 @@ public:
 
   public:
 
-    point seg[2];  // A constraining edge to be recovered.
-    point fac[3];  // A constraining face to be recovered.
-
-    point remvert; // A vertex to be removed.
-    //point remedge[2]; // A non-Delaunay edge to be removed.
+    // Elementary flip flags.
+    int enqflag; // (= flipflag)
+    int chkencflag;
 
     // Control flags
     int unflip;  // Undo the performed flips.
@@ -1062,37 +1148,22 @@ public:
 
     // Optimization flags.
     int remove_ndelaunay_edge; // Remove a non-Delaunay edge.
-                      // remedge[0] and remedge[1] store the endpoints of a
-                      // non-Delaunay edge to be removed.
     REAL bak_tetprism_vol; // The value to be minimized.
-
+    REAL tetprism_vol_sum;
     int remove_large_angle; // Remove a large dihedral angle at edge.
     REAL cosdihed_in; // The input cosine of the dihedral angle (> 0).
-                      // Only perform a flip if new angles are less than it.
     REAL cosdihed_out; // The improved cosine of the dihedral angle.
 
-    // Counters.
-    int maxflippedlinklevelcount; // Maximal flipped link levels.
-    int misfliplinklevelcount; // Number of missed flip possibilities.
-    int chrismastreecount; // Number of Chrismas trees (unflippable case).
-    int convexhulledgecount; // Number of convex hull edges (unflippable case).
-    int encsegcount; // Number of hitted segments. 
-    int rejf23count, rejf32count; // Number of rejections by checkflipeligi..
-
-    void clearcounters() {
-      maxflippedlinklevelcount = 0;
-      misfliplinklevelcount = 0;
-      chrismastreecount = 0;
-      convexhulledgecount = 0;
-      encsegcount = 0;
-      rejf23count = rejf32count = 0;
-    }
+    // Boundary recovery flags.
+    int checkflipeligibility;
+    point seg[2];  // A constraining edge to be recovered.
+    point fac[3];  // A constraining face to be recovered.
+    point remvert; // A vertex to be removed.
+
 
     flipconstraints() {
-      seg[0] = NULL;
-      fac[0] = NULL;
-      remvert = NULL;
-      //remedge[0] = NULL;
+      enqflag = 0; 
+      chkencflag = 0;
 
       unflip = 0;
       collectnewtets = 0;
@@ -1100,12 +1171,15 @@ public:
 
       remove_ndelaunay_edge = 0;
       bak_tetprism_vol = 0.0;
-
+      tetprism_vol_sum = 0.0;
       remove_large_angle = 0;
       cosdihed_in = 0.0;
       cosdihed_out = 0.0;
 
-      clearcounters();
+      checkflipeligibility = 0;
+      seg[0] = NULL;
+      fac[0] = NULL;
+      remvert = NULL;
     }
   };
 
@@ -1124,7 +1198,7 @@ public:
     // The one of goals of optimization.
     int max_min_volume;      // Maximize the minimum volume.
     int max_min_aspectratio; // Maximize the minimum aspect ratio.
-    int min_max_dihedangle;  // Minimize the maxumum dihedral angle. 
+    int min_max_dihedangle;  // Minimize the maximum dihedral angle. 
 
     // The initial and improved value.
     REAL initval, imprval;
@@ -1134,11 +1208,6 @@ public:
     int maxiter;  // Maximum smoothing iterations (disabled by -1).
     int smthiter; // Performed iterations.
 
-    int expstarflag;
-    int expstarcount;
-
-    int flipflag;
-    int checkencflag;
 
     optparameters() {
       max_min_volume = 0;
@@ -1152,138 +1221,39 @@ public:
       maxiter = -1;   // Unlimited smoothing iterations.
       smthiter = 0;
 
-      expstarflag = 0;
-      expstarcount = 0;
-
-      flipflag = 0;
-      checkencflag = 0;
     }
   };
 
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Arraypool                                                                 //
-//                                                                           //
-// A dynamic linear array.                                                   //
-// (It is simply copied from Shewchuk's Starbase.c, which is provided as     //
-//  part of Stellar, a program for improving tetrahedral meshes.)            //
-//                                                                           //
-// Each arraypool contains an array of pointers to a number of blocks.  Each //
-// block contains the same fixed number of objects.  Each index of the array //
-// addesses a particular object in the pool.  The most significant bits add- //
-// ress the index of the block containing the object. The less significant   //
-// bits address this object within the block.                                //
-//                                                                           //
-// 'objectbytes' is the size of one object in blocks; 'log2objectsperblock'  //
-// is the base-2 logarithm of 'objectsperblock'; 'objects' counts the number //
-// of allocated objects; 'totalmemory' is the totoal memorypool in bytes.    //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-  class arraypool {
-
-  public:
-
-    int objectbytes;
-    int objectsperblock;
-    int log2objectsperblock; 
-    int toparraylen;
-    char **toparray;
-    long objects;
-    unsigned long totalmemory;
-
-    void restart();
-    void poolinit(int sizeofobject, int log2objperblk);
-    char* getblock(int objectindex);
-    void* lookup(int objectindex);
-    int newindex(void **newptr);
-
-    arraypool(int sizeofobject, int log2objperblk);
-    ~arraypool();
-  };
-
-// fastlookup() -- A fast, unsafe operation. Return the pointer to the object
-//   with a given index.  Note: The object's block must have been allocated,
-//   i.e., by the function newindex().
-
-#define fastlookup(pool, index) \
-  (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] + \
-            ((index) & ((pool)->objectsperblock - 1)) * (pool)->objectbytes)
-
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// Memorypool                                                                //
-//                                                                           //
-// A type used to allocate memory.                                           //
-// (It is simply copied from Shewchuk's triangle.c.)                         //
-//                                                                           //
-// firstblock is the first block of items. nowblock is the block from which  //
-//   items are currently being allocated. nextitem points to the next slab   //
-//   of free memory for an item. deaditemstack is the head of a linked list  //
-//   (stack) of deallocated items that can be recycled.  unallocateditems is //
-//   the number of items that remain to be allocated from nowblock.          //
-//                                                                           //
-// Traversal is the process of walking through the entire list of items, and //
-//   is separate from allocation.  Note that a traversal will visit items on //
-//   the "deaditemstack" stack as well as live items.  pathblock points to   //
-//   the block currently being traversed.  pathitem points to the next item  //
-//   to be traversed.  pathitemsleft is the number of items that remain to   //
-//   be traversed in pathblock.                                              //
-//                                                                           //
-// itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest   //
-//   what sort of word the record is primarily made up of.  alignbytes       //
-//   determines how new records should be aligned in memory.  itembytes and  //
-//   itemwords are the length of a record in bytes (after rounding up) and   //
-//   words.  itemsperblock is the number of items allocated at once in a     //
-//   single block.  items is the number of currently allocated items.        //
-//   maxitems is the maximum number of items that have been allocated at     //
-//   once; it is the current number of items plus the number of records kept //
-//   on deaditemstack.                                                       //
+// Labels (enumeration declarations) used by TetGen.                         //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  class memorypool {
-
-  public:
-
-    // Labels that signify whether a record consists primarily of pointers
-    //   or of floating-point words.  Used for data alignment.
-    enum wordtype {POINTER, FLOATINGPOINT};
-
-    void **firstblock, **nowblock;
-    void *nextitem;
-    void *deaditemstack;
-    void **pathblock;
-    void *pathitem;
-    wordtype itemwordtype;
-    int  alignbytes;
-    int  itembytes, itemwords;
-    int  itemsperblock;
-    long items, maxitems;
-    int  unallocateditems;
-    int  pathitemsleft;
-
-    memorypool();
-    memorypool(int, int, enum wordtype, int);
-    ~memorypool();
-    
-    void poolinit(int, int, enum wordtype, int);
-    void restart();
-    void *alloc();
-    void dealloc(void*);
-    void traversalinit();
-    void *traverse();
-  };  
+  // Labels that signify the type of a vertex. 
+  enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, RIDGEVERTEX, ACUTEVERTEX,
+                 FACETVERTEX, VOLVERTEX, FREESEGVERTEX, FREEFACETVERTEX, 
+                 FREEVOLVERTEX, NREGULARVERTEX, DEADVERTEX};
+ 
+  // Labels that signify the result of triangle-triangle intersection test.
+  enum interresult {DISJOINT, INTERSECT, SHAREVERT, SHAREEDGE, SHAREFACE,
+                    TOUCHEDGE, TOUCHFACE, ACROSSVERT, ACROSSEDGE, ACROSSFACE, 
+                    COLLISIONFACE, ACROSSSEG, ACROSSSUB};
+
+  // Labels that signify the result of point location.
+  enum locateresult {UNKNOWN, OUTSIDE, INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX,
+                     ENCVERTEX, ENCSEGMENT, ENCSUBFACE, NEARVERTEX, NONREGULAR,
+                     INSTAR, BADELEMENT};
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Class variables                                                           //
+// Variables of TetGen                                                       //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
   // Pointer to the input data (a set of nodes, a PLC, or a mesh).
-  tetgenio *in;
+  tetgenio *in, *addin;
 
   // Pointer to the switches and parameters.
   tetgenbehavior *b;
@@ -1291,9 +1261,8 @@ public:
   // Pointer to a background mesh (contains size specification map).
   tetgenmesh *bgm;
 
-  // Memorypools to store mesh elements: tetrahedra, subfaces, segments,
-  //   and vertices. And memorypools for storing pointers which connect 
-  //   tetrahedra and subfaces and segments.
+  // Memorypools to store mesh elements (points, tetrahedra, subfaces, and
+  //   segments) and extra pointers between tetrahedra, subfaces, and segments.
   memorypool *tetrahedrons, *subfaces, *subsegs, *points;
   memorypool *tet2subpool, *tet2segpool;
 
@@ -1302,17 +1271,8 @@ public:
 
   // A memorypool to store faces to be flipped.
   memorypool *flippool;
-  // A stack of faces to be flipped.
-  badface *flipstack;
-  // Two queues for handling unflippable edges.
-  arraypool *unflipqueue; //, *flipqueue;
-
-  // Entry to find the binary tree nodes (-u option).
-  arraypool *btreenode_list;
-  // The maximum size of a btree node (number after -u option) is
-  int max_btreenode_size; // <= b->max_btreenode_size.
-  // The maximum btree depth (for bookkeeping).
-  int max_btree_depth; 
+  arraypool *unflipqueue;
+  badface *flipstack; 
 
   // Arrays used for point insertion (the Bowyer-Watson algorithm).
   arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist;
@@ -1322,48 +1282,38 @@ public:
 
   // Stacks used for CDT construction and boundary recovery.
   arraypool *subsegstack, *subfacstack, *subvertstack;
-  arraypool *suppsteinerptlist;
-
-  // The infinite vertex.
-  point dummypoint;
 
-  // Two handles used for facet recovery in CDT.
-  triface firsttopface, firstbotface;
+  // Arrays of encroached segments and subfaces (for mesh refinement).
+  arraypool *encseglist, *encshlist;
 
-  // Three points define a plane (used in formcavity()).
-  point plane_pa, plane_pb, plane_pc;
+  // The map between facets to their vertices (for mesh refinement).
+  int *idx2facetlist;
+  point *facetverticeslist;
 
-  // Two arraies of encroached segments and subfaces (in mesh refinement).
-  arraypool *encseglist, *encshlist;
+  // The map between segments to their endpoints (for mesh refinement).
+  point *segmentendpointslist;
 
-  // Pointer to a recently visited tetrahedron, subface.
+  // The infinite vertex.
+  point dummypoint;
+  // The recently visited tetrahedron, subface.
   triface recenttet;
   face recentsh;
 
   // PI is the ratio of a circle's circumference to its diameter.
   static REAL PI;
 
-  // The increasement of link levels, default is 1.
-  int autofliplinklevel;
+  // Array (size = numberoftetrahedra * 6) for storing high-order nodes of
+  //   tetrahedra (only used when -o2 switch is selected).
+  point *highordertable;
 
-  // The volume of tetrahedral-prisms (in 4D).
-  REAL tetprism_vol_sum;
-  int calc_tetprism_vol;
-
-  // Other variables.
-  REAL xmax, xmin, ymax, ymin, zmax, zmin;         // Bounding box of points.
-  REAL longest;                          // The longest possible edge length.
-  long hullsize;                           // Number of faces of convex hull.
-  long insegments;                               // Number of input segments.
-  long meshedges;                             // Number of output mesh edges.
-  long meshhulledges;                           // Number of hull mesh edges.
-  int steinerleft;                  // Number of Steiner points not yet used.
+  // Various variables.
+  int numpointattrib;                          // Number of point attributes.
+  int numelemattrib;                     // Number of tetrahedron attributes.
   int sizeoftensor;                     // Number of REALs per metric tensor.
   int pointmtrindex;           // Index to find the metric tensor of a point.
   int pointparamindex;       // Index to find the u,v coordinates of a point.
   int point2simindex;         // Index to find a simplex adjacent to a point.
   int pointmarkindex;            // Index to find boundary marker of a point.
-  int point2pbcptindex;              // Index to find a pbc point to a point.
   int elemattribindex;          // Index to find attributes of a tetrahedron.
   int volumeboundindex;       // Index to find volume bound of a tetrahedron.
   int elemmarkerindex;              // Index to find marker of a tetrahedron.
@@ -1371,83 +1321,64 @@ public:
   int areaboundindex;               // Index to find area bound of a subface.
   int checksubsegflag;   // Are there segments in the tetrahedralization yet?
   int checksubfaceflag;  // Are there subfaces in the tetrahedralization yet?
-  int checkinverttetflag;       // Are there inverted (degenerated) tets yet?
-  int checkpbcs;                   // Are there periodic boundary conditions?
   int checkconstraints;  // Are there variant (node, seg, facet) constraints?
   int nonconvex;                               // Is current mesh non-convex?
-  int dupverts;                             // Are there duplicated vertices?
-  int unuverts;                                 // Are there unused vertices?
+  int autofliplinklevel;        // The increase of link levels, default is 1.
+  int useinsertradius;       // Save the insertion radius for Steiner points.
   long samples;               // Number of random samples for point location.
   unsigned long randomseed;                    // Current random number seed.
   REAL cosmaxdihed, cosmindihed;    // The cosine values of max/min dihedral.
-  REAL cossmtdihed;
-  REAL cosslidihed;          // The cosine value of max dihedral of a sliver.
+  REAL cossmtdihed;     // The cosine value of a bad dihedral to be smoothed.
+  REAL cosslidihed;      // The cosine value of the max dihedral of a sliver.
   REAL minfaceang, minfacetdihed;     // The minimum input (dihedral) angles.
-  REAL sintheta_tol;                   // The tolerance for sin(small angle).
+  REAL tetprism_vol_sum;   // The total volume of tetrahedral-prisms (in 4D).
+  REAL longest;                          // The longest possible edge length.
+  REAL xmax, xmin, ymax, ymin, zmax, zmin;         // Bounding box of points.
 
-  // Algorithm statistical counters.
-  long ptloc_count, ptloc_max_count;
-  long orient3dcount, inspherecount, insphere_sos_count;
+  // Counters.
+  long insegments;                               // Number of input segments.
+  long hullsize;                        // Number of exterior boundary faces.
+  long meshedges;                                    // Number of mesh edges.
+  long meshhulledges;                       // Number of boundary mesh edges.
+  long steinerleft;                 // Number of Steiner points not yet used.
+  long dupverts;                            // Are there duplicated vertices?
+  long unuverts;                                // Are there unused vertices?
+  long nonregularcount;                    // Are there non-regular vertices?
+  long st_segref_count, st_facref_count, st_volref_count;  // Steiner points.
+  long fillregioncount, cavitycount, cavityexpcount;
   long flip14count, flip26count, flipn2ncount;
-  long flip23count, flip32count, flip44count, flip22count;
-  long maxbowatcavsize, totalbowatcavsize, totaldeadtets;
-  long triedgcount, triedgcopcount;
-  long across_face_count, across_edge_count, across_max_count;
-  long fillregioncount, missingsubfacecount, crossingtetcount;
-  long cavitycount, cavityexpcount, maxcavsize, maxregionsize;
-  long maxcrossfacecount, maxflipsequence;
-  long dbg_ignore_facecount, dbg_unflip_facecount;
-  long ccent_relocate_count;
-  long opt_sliver_peels;
-  long r1count, r2count, r3count; 
-  long maxfliplinklevel, maxflipstarsize;
-  long flipstarcount, sucflipstarcount, skpflipstarcount;
-  long st_segref_count, st_facref_count, st_volref_count; 
-
-  long rejrefinetetcount, rejrefineshcount;
-
-#ifdef WITH_RUNTIME_COUNTERS
-  clock_t t_ptloc, t_ptinsert;   // Time counters for DT operations.
-#endif
+  long flip23count, flip32count, flip44count, flip41count;
+  long flip31count, flip22count;
+  unsigned long totalworkmemory;      // Total memory used by working arrays.
+
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Mesh manipulation primitives                                              //
 //                                                                           //
-// A serial of mesh operations such as topological maintenance,  navigation, //
-// local modification, etc.,  is accomplished through a set of mesh manipul- //
-// ation primitives. These primitives are indeed very simple functions which //
-// take one or two handles ('triface's and 'face's) as parameters,  perform  //
-// basic operations such as "glue two tetrahedra at a face",  "return the    //
-// origin of a tetrahedron", "return the subface adjoining at the face of a  //
-// tetrahedron", and so on.                                                  //
-//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
   // Fast lookup tables for mesh manipulation primitives.
-  static int mod12[36];
-  static int mod6[18];
-  static int edgepivot[12];
-  static int orgpivot [12];
-  static int destpivot[12];
-  static int apexpivot[12];
-  static int oppopivot[12];
-  static int ver2edge[12];
-  static int edge2ver[6];
+  static int bondtbl[12][12], fsymtbl[12][12];
+  static int esymtbl[12], enexttbl[12], eprevtbl[12];
+  static int enextesymtbl[12], eprevesymtbl[12]; 
+  static int eorgoppotbl[12], edestoppotbl[12];
+  static int facepivot1[12], facepivot2[12][12];
+  static int orgpivot[12], destpivot[12], apexpivot[12], oppopivot[12];
+  static int tsbondtbl[12][6], stbondtbl[12][6];
+  static int tspivottbl[12][6], stpivottbl[12][6];
+  static int ver2edge[12], edge2ver[6], epivot[12];
+  static int sorgpivot [6], sdestpivot[6], sapexpivot[6];
   static int snextpivot[6];
-  static int sorgpivot [6];
-  static int sdestpivot[6];
-  static int sapexpivot[6];
-  static int epivot[4];
+
+  void inittables();
 
   // Primitives for tetrahedra.
-  inline void decode(tetrahedron ptr, triface& t);
   inline tetrahedron encode(triface& t);
   inline tetrahedron encode2(tetrahedron* ptr, int ver);
+  inline void decode(tetrahedron ptr, triface& t);
   inline void bond(triface& t1, triface& t2);
   inline void dissolve(triface& t);
-  inline void fsym(triface& t1, triface& t2);
-  inline void fsymself(triface& t);
   inline void esym(triface& t1, triface& t2);
   inline void esymself(triface& t);
   inline void enext(triface& t1, triface& t2);
@@ -1458,10 +1389,14 @@ public:
   inline void enextesymself(triface& t);
   inline void eprevesym(triface& t1, triface& t2);
   inline void eprevesymself(triface& t);
+  inline void eorgoppo(triface& t1, triface& t2);
+  inline void eorgoppoself(triface& t);
+  inline void edestoppo(triface& t1, triface& t2);
+  inline void edestoppoself(triface& t);
+  inline void fsym(triface& t1, triface& t2);
+  inline void fsymself(triface& t);
   inline void fnext(triface& t1, triface& t2);
   inline void fnextself(triface& t);
-  inline void fprev(triface& t1, triface& t2);
-  inline void fprevself(triface& t);
   inline point org (triface& t);
   inline point dest(triface& t);
   inline point apex(triface& t);
@@ -1521,16 +1456,10 @@ public:
   inline void senextself(face& s);
   inline void senext2(face& s1, face& s2);
   inline void senext2self(face& s);
-  inline void sfnext(face& s1, face& s2);
-  inline void sfnextself(face& s);
   inline REAL areabound(face& s);
   inline void setareabound(face& s, REAL value);
   inline int shellmark(face& s);
   inline void setshellmark(face& s, int value);
-  inline enum shestype shelltype(face& s);
-  inline void setshelltype(face& s, enum shestype value); 
-  inline int shellpbcgroup(face& s);
-  inline void setshellpbcgroup(face& s, int value);
   inline void sinfect(face& s);
   inline void suninfect(face& s);
   inline bool sinfected(face& s);
@@ -1543,6 +1472,8 @@ public:
   inline void smarktest3(face& s);
   inline void sunmarktest3(face& s);
   inline bool smarktest3ed(face& s);
+  inline void setfacetindex(face& f, int value);
+  inline int  getfacetindex(face& f);
 
   // Primitives for interacting tetrahedra and subfaces.
   inline void tsbond(triface& t, face& s);
@@ -1594,8 +1525,8 @@ public:
   inline void setpoint2ppt(point pt, point value);
   inline tetrahedron point2bgmtet(point pt);
   inline void setpoint2bgmtet(point pt, tetrahedron value);
-  inline point point2pbcpt(point pt);
-  inline void setpoint2pbcpt(point pt, point value);
+  inline void setpointinsradius(point pt, REAL value);
+  inline REAL getpointinsradius(point pt);
 
   // Advanced primitives.
   inline void point2tetorg(point pt, triface& t);
@@ -1614,32 +1545,53 @@ public:
   tetrahedron *alltetrahedrontraverse();
   void shellfacedealloc(memorypool*, shellface*);
   shellface *shellfacetraverse(memorypool*);
-  void badfacedealloc(memorypool*, badface*);
-  badface *badfacetraverse(memorypool*);
   void pointdealloc(point);
   point pointtraverse();
-  void maketetrahedron(triface*);
-  void makeshellface(memorypool*, face*);
-  void makepoint(point*, enum verttype);
 
   void makeindex2pointmap(point*&);
   void makepoint2submap(memorypool*, int*&, face*&);
+  void maketetrahedron(triface*);
+  void makeshellface(memorypool*, face*);
+  void makepoint(point*, enum verttype);
 
   void initializepools();
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Geometric predicates and calculations                                     //
+// Advanced geometric predicates and calculations                            //
+//                                                                           //
+// TetGen uses a simplified symbolic perturbation scheme from Edelsbrunner,  //
+// et al [*].  Hence the point-in-sphere test never returns a zero. The idea //
+// is to perturb the weights of vertices in the fourth dimension.  TetGen    //
+// uses the indices of the vertices decide the amount of perturbation. It is //
+// implemented in the routine insphere_s().
+//                                                                           //
+// The routine tri_edge_test() determines whether or not a triangle and an   //
+// edge intersect in 3D. If they intersect, their intersection type is also  //
+// reported. This test is a combination of n 3D orientation tests (n is bet- //
+// ween 3 and 9). It uses the robust orient3d() test to make the branch dec- //
+// isions.  The routine tri_tri_test() determines whether or not two triang- //
+// les intersect in 3D. It also uses the robust orient3d() test.             //
+//                                                                           //
+// There are a number of routines to calculate geometrical quantities, e.g., //
+// circumcenters, angles, dihedral angles, face normals, face areas, etc.    //
+// They are so far done by the default floating-point arithmetics which are  //
+// non-robust. They should be improved in the future.                        //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  // Triangle-edge intersection test
+  // Symbolic perturbations (robust)
+  REAL insphere_s(REAL*, REAL*, REAL*, REAL*, REAL*);
+  REAL orient4d_s(REAL*, REAL*, REAL*, REAL*, REAL*, 
+                  REAL, REAL, REAL, REAL, REAL);
+
+  // Triangle-edge intersection test (robust)
   int tri_edge_2d(point, point, point, point, point, point, int, int*, int*);
-  int tri_edge_tail(point, point, point, point, point, point, REAL, REAL, int, 
+  int tri_edge_tail(point, point, point, point, point, point, REAL, REAL, int,
                     int*, int*);
   int tri_edge_test(point, point, point, point, point, point, int, int*, int*);
 
-  // Triangle-triangle intersection test
+  // Triangle-triangle intersection test (robust)
   int tri_edge_inter_tail(point, point, point, point, point, REAL, REAL);
   int tri_tri_inter(point, point, point, point, point, point);
 
@@ -1649,13 +1601,12 @@ public:
   bool lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N);
   void lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N);
 
-  // Geometric predicates
+  // An embedded 2-dimensional geometric predicate (non-robust)
   REAL incircle3d(point pa, point pb, point pc, point pd);
-  REAL insphere_s(REAL*, REAL*, REAL*, REAL*, REAL*);
-  REAL orient4d_s(REAL*, REAL*, REAL*, REAL*, REAL*, 
-                  REAL, REAL, REAL, REAL, REAL);
 
-  // Geometric calculations
+  // Geometric calculations (non-robust)
+  REAL orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
+  inline REAL norm2(REAL x, REAL y, REAL z);
   inline REAL distance(REAL* p1, REAL* p2);
   void facenormal(point pa, point pb, point pc, REAL *n, int pivot, REAL *lav);
   REAL shortdistance(REAL* p, REAL* e1, REAL* e2);
@@ -1668,51 +1619,134 @@ public:
   void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume);
   REAL tetaspectratio(point, point, point, point);
   bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius);
+  bool orthosphere(REAL*,REAL*,REAL*,REAL*,REAL,REAL,REAL,REAL,REAL*,REAL*);
   void planelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
+  int linelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*);
   REAL tetprismvol(REAL* pa, REAL* pb, REAL* pc, REAL* pd);
+  bool calculateabovepoint(arraypool*, point*, point*, point*);
+  void calculateabovepoint4(point, point, point, point);
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Local mesh transformations                                                //
 //                                                                           //
+// A local transformation replaces a small set of tetrahedra with another    //
+// set of tetrahedra which fills the same space and the same boundaries.     //
+//   In 3D, the most simplest local transformations are the elementary flips //
+// performed within the convex hull of five vertices: 2-to-3, 3-to-2, 1-to-4,//
+// and 4-to-1 flips,  where the numbers indicate the number of tetrahedra    //
+// before and after each flip.  The 1-to-4 and 4-to-1 flip involve inserting //
+// or deleting a vertex, respectively.                                       //
+//   There are complex local transformations which can be decomposed as a    //
+// combination of elementary flips. For example,a 4-to-4 flip which replaces //
+// two coplanar edges can be regarded by a 2-to-3 flip and a 3-to-2 flip.    //
+// Note that the first 2-to-3 flip will temporarily create a degenerate tet- //
+// rahedron which is removed immediately by the followed 3-to-2 flip.  More  //
+// generally, a n-to-m flip, where n > 3, m = (n - 2) * 2, which removes an  //
+// edge can be done by first performing a sequence of (n - 3) 2-to-3 flips   //
+// followed by a 3-to-2 flip.                                                //
+//                                                                           //
+// The routines flip23(), flip32(), and flip41() perform the three element-  //
+// ray flips. The flip14() is available inside the routine insertpoint().    //
+//                                                                           //
+// The routines flipnm() and flipnm_post() implement a generalized edge flip //
+// algorithm which uses a combination of elementary flips.                   //
+//                                                                           //
+// The routine insertpoint() implements a variant of Bowyer-Watson's cavity  //
+// algorithm to insert a vertex. It works for arbitrary tetrahedralization,  //
+// either Delaunay, or constrained Delaunay, or non-Delaunay.                //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  void flippush(badface*&, triface*);
-
   // The elementary flips.
-  void flip23(triface*, int, int, int);
-  void flip32(triface*, int, int, int);
-  void flip41(triface*, int, int, int);
+  void flip23(triface*, int, flipconstraints* fc);
+  void flip32(triface*, int, flipconstraints* fc);
+  void flip41(triface*, int, flipconstraints* fc);
 
   // A generalized edge flip.
   int flipnm(triface*, int n, int level, int, flipconstraints* fc);
   int flipnm_post(triface*, int n, int nn, int, flipconstraints* fc);
 
-  // Incremental flips.
-  long lawsonflip3d(point, int flipflag, int, int, int flipedgeflag);
-
   // Point insertion.
-  int insertvertex(point newpt, triface *searchtet, face *splitsh, face*,
-                   insertvertexflags *ivf);
+  int  insertpoint(point, triface*, face*, face*, insertvertexflags*);
+  void insertpoint_abort(face*, insertvertexflags*);
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Delaunay tetrahedralization                                               //
 //                                                                           //
+// The routine incrementaldelaunay() implemented two incremental algorithms  //
+// for constructing Delaunay tetrahedralizations (DTs):  the Bowyer-Watson   //
+// (B-W) algorithm and the incremental flip algorithm of Edelsbrunner and    //
+// Shah, "Incremental topological flipping works for regular triangulation," //
+// Algorithmica, 15:233-241, 1996.                                           //
+//                                                                           //
+// The routine incrementalflip() implements the flip algorithm of [Edelsbru- //
+// nner and Shah, 1996].  It flips a queue of locally non-Delaunay faces (in //
+// an arbitrary order).  The success is guaranteed when the Delaunay tetrah- //
+// edralization is constructed incrementally by adding one vertex at a time. //
+//                                                                           //
+// The routine locate() finds a tetrahedron contains a new point in current  //
+// DT.  It uses a simple stochastic walk algorithm: starting from an arbitr- //
+// ary tetrahedron in DT, it finds the destination by visit one tetrahedron  //
+// at a time, randomly chooses a tetrahedron if there are more than one      //
+// choices. This algorithm terminates due to Edelsbrunner's acyclic theorem. //
+//   Choose a good starting tetrahedron is crucial to the speed of the walk. //
+// TetGen originally uses the "jump-and-walk" algorithm of Muecke, E.P.,     //
+// Saias, I., and Zhu, B. "Fast Randomized Point Location Without Preproces- //
+// sing." In Proceedings of the 12th ACM Symposium on Computational Geometry,//
+// 274-283, 1996.  It first randomly samples several tetrahedra in the DT    //
+// and then choosing the closet one to start walking.                        //
+//   The above algorithm slows download dramatically as the number of points //
+// grows -- reported in Amenta, N., Choi, S. and Rote, G., "Incremental      //
+// construction con {BRIO}," In Proceedings of 19th ACM Symposium on         //
+// Computational Geometry, 211-219, 2003.  On the other hand, Liu and        //
+// Snoeyink showed that the point location can be made in constant time if   //
+// the points are pre-sorted so that the nearby points in space have nearby  //
+// indices, then adding the points in this order. They sorted the points     //
+// along the 3D Hilbert curve.                                               //
+//                                                                           //
+// The routine hilbert_sort3() sorts a set of 3D points along the 3D Hilbert //
+// curve. It recursively splits a point set according to the Hilbert indices //
+// mapped to the subboxes of the bounding box of the point set.              //
+//   The Hilbert indices is calculated by Butz's algorithm in 1971.  A nice  //
+// exposition of this algorithm can be found in the paper of Hamilton, C.,   //
+// "Compact Hilbert Indices", Technical Report CS-2006-07, Computer Science, //
+// Dalhousie University, 2006 (the Section 2). My implementation also refer- //
+// enced Steven Witham's implementation of "Hilbert walk" (hopefully, it is  //
+// still available at: http://www.tiac.net/~sw/2008/10/Hilbert/).            //
+//                                                                           //
+// TetGen sorts the points using the method in the paper of Boissonnat,J.-D.,//
+// Devillers, O. and Hornus, S. "Incremental Construction of the Delaunay    //
+// Triangulation and the Delaunay Graph in Medium Dimension," In Proceedings //
+// of the 25th ACM Symposium on Computational Geometry, 2009.                //
+//   It first randomly sorts the points into subgroups using the Biased Rand-//
+// omized Insertion Ordering (BRIO) of Amenta et al 2003, then sorts the     //
+// points in each subgroup along the 3D Hilbert curve.  Inserting points in  //
+// this order ensures a randomized "sprinkling" of the points over the       //
+// domain, while sorting of each subset ensures locality.                    //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
   void transfernodes();
 
   // Point sorting.
-  void btree_sort(point*, int, int, REAL, REAL, REAL, REAL, REAL, REAL, int);
-  void btree_insert(point insertpt);
-  void btree_search(point searchpt, triface* searchtet);
-  void ordervertices(point* vertexarray, int arraysize);
+  int  transgc[8][3][8], tsb1mod3[8];
+  void hilbert_init(int n);
+  int  hilbert_split(point* vertexarray, int arraysize, int gc0, int gc1,
+                     REAL, REAL, REAL, REAL, REAL, REAL);
+  void hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
+                     REAL, REAL, REAL, REAL, REAL, REAL, int depth);
+  void brio_multiscale_sort(point*,int,int threshold,REAL ratio,int* depth);
 
   // Point location.
   unsigned long randomnation(unsigned int choices);
   void randomsample(point searchpt, triface *searchtet);
-  enum locateresult locate(point searchpt, triface*, int, int);
+  enum locateresult locate(point searchpt, triface *searchtet);
+
+  // Incremental flips.
+  void flippush(badface*&, triface*);
+  int  incrementalflip(point newpt, int, flipconstraints *fc);
 
   // Incremental Delaunay construction.
   void initialdelaunay(point pa, point pb, point pc, point pd);
@@ -1724,14 +1758,11 @@ public:
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  bool calculateabovepoint(arraypool*, point*, point*, point*);
-  void calculateabovepoint4(point, point, point, point);
-
   void flipshpush(face*);
   void flip22(face*, int, int);
   void flip31(face*, int);
   long lawsonflip();
-  int sinsertvertex(point newpt, face*, face*, int iloc, int bowywat);
+  int sinsertvertex(point newpt, face*, face*, int iloc, int bowywat, int);
   int sremovevertex(point delpt, face*, face*, int lawson);
 
   enum locateresult slocate(point, face*, int, int, int);
@@ -1746,53 +1777,116 @@ public:
   void meshsurface();
 
   void interecursive(shellface** subfacearray, int arraysize, int axis,
-                     REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
-                     REAL bzmin, REAL bzmax, int* internum);
+                     REAL, REAL, REAL, REAL, REAL, REAL, int* internum);
   void detectinterfaces();
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Constrained Delaunay tetrahedralization                                   //
 //                                                                           //
+// A constrained Delaunay tetrahedralization (CDT) is a variation of a Dela- //
+// unay tetrahedralization (DT) that is constrained to respect the boundary  //
+// of a 3D PLC (domain). In a CDT of a 3D PLC, every vertex or edge of the   //
+// PLC is also a vertex or an edge of the CDT, every polygon of the PLC is a //
+// union of triangles of the CDT. A crucial difference between a CDT and a   //
+// DT is that triangles in the PLC's polygons are not required to be locally //
+// Delaunay, which frees the CDT to better respect the PLC's polygons. CDTs  //
+// have optimal properties similar to those of DTs.                          //
+//                                                                           //
+// Steiner Points and Steiner CDTs. It is known that even a simple 3D polyh- //
+// edron may not have a tetrahedralization which only uses its own vertices. //
+// Some extra points, so-called "Steiner points" are needed in order to form //
+// a tetrahedralization of such polyhedron.  It is true for tetrahedralizing //
+// a 3D PLC as well. A Steiner CDT of a 3D PLC is a CDT containing Steiner   //
+// points. The CDT algorithms of TetGen in general create Steiner CDTs.      //
+// Almost all of the Steiner points are added in the edges of the PLC. They  //
+// guarantee the existence of a CDT of the modified PLC.                     //
+//                                                                           //
+// The routine constraineddelaunay() starts from a DT of the vertices of a   //
+// PLC and creates a (Steiner) CDT of the PLC (including Steiner points). It //
+// is constructed by two steps, (1) segment recovery and (2) facet (polygon) //
+// recovery. Each step is accomplished by its own algorithm.                 //
+//                                                                           //
+// The routine delaunizesegments() implements the segment recovery algorithm //
+// of Si, H. and Gaertner, K. "Meshing Piecewise Linear Complexes by Constr- //
+// ained Delaunay Tetrahedralizations," In Proceedings of the 14th Internat- //
+// ional Meshing Roundtable, 147--163, 2005.  It adds Steiner points into    //
+// non-Delaunay segments until all subsegments appear together in a DT. The  //
+// running time of this algorithm is proportional to the number of added     //
+// Steiner points.                                                           //
+//                                                                           //
+// There are two incremental facet recovery algorithms: the cavity re-trian- //
+// gulation algorithm of Si, H. and Gaertner, K. "3D Boundary Recovery by    //
+// Constrained Delaunay Tetrahedralization," International Journal for Numer-//
+// ical Methods in Engineering, 85:1341-1364, 2011, and the flip algorithm   //
+// of Shewchuk, J. "Updating and Constructing Constrained Delaunay and       //
+// Constrained Regular Triangulations by Flips." In Proceedings of the 19th  //
+// ACM Symposium on Computational Geometry, 86-95, 2003.                     //
+//                                                                           //
+// It is guaranteed in theory, no Steiner point is needed in both algorithms //
+// However, a facet with non-coplanar vertices might cause the  additions of //
+// Steiner points. It is discussed in the paper of Si, H., and  Shewchuk, J.,//
+// "Incrementally Constructing and Updating Constrained Delaunay             //
+// Tetrahedralizations with Finite Precision Coordinates." In Proceedings of //
+// the 21th International Meshing Roundtable, 2012.                          //
+//                                                                           //
+// Our implementation of the facet recovery algorithms recover a "missing    //
+// region" at a time. Each missing region is a subset of connected interiors //
+// of a polygon. The routine formcavity() creates the cavity of crossing     //
+// tetrahedra of the missing region.                                         //
+//                                                                           //
+// The cavity re-triangulation algorithm is implemented by three subroutines,//
+// delaunizecavity(), fillcavity(), and carvecavity(). Since it may fail due //
+// to non-coplanar vertices, the subroutine restorecavity() is used to rest- //
+// ore the original cavity.                                                  //
+//                                                                           //
+// The routine flipinsertfacet() implements the flip algorithm. The subrout- //
+// ine flipcertify() is used to maintain the priority queue of flips.        // 
+//                                                                           //
+// The routine refineregion() is called when the facet recovery algorithm    //
+// fail to recover a missing region. It inserts Steiner points to refine the //
+// missing region. In order to avoid inserting Steiner points very close to  //
+// existing segments.  The classical encroachment rules of the Delaunay      //
+// refinement algorithm are used to choose the Steiner points.               //
+//                                                                           //
+// The routine constrainedfacets() does the facet recovery by using either   //
+// the cavity re-triangulation algorithm (default) or the flip algorithm. It //
+// results a CDT of the (modified) PLC (including Steiner points).           //
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  void markacutevertices();
+  void makesegmentendpointsmap();
 
-  void reportselfintersect(face *seg, face *shface);
-
-  enum interresult finddirection(triface* searchtet, point endpt, int);
+  enum interresult finddirection(triface* searchtet, point endpt);
   enum interresult scoutsegment(point, point, triface*, point*, arraypool*);
-  void getsteinerptonsegment(face* seg, point refpt, point steinpt);
+  int  getsteinerptonsegment(face* seg, point refpt, point steinpt);
   void delaunizesegments();
 
   enum interresult scoutsubface(face* searchsh, triface* searchtet);
-  void formmissingregion(face* missh, arraypool* missingshs, 
-                         arraypool* missingshbds, arraypool* missingshverts, 
-                         arraypool *adjtets);
-  int scoutcrossedge(triface& crosstet, arraypool*, arraypool* missingshs);
-  bool formcavity(triface* searchtet, arraypool* missingshs, 
-                  arraypool* crosstets, arraypool* topfaces, 
-                  arraypool* botfaces, arraypool* toppoints, 
-                  arraypool* botpoints);
-
-  // Facet recovery by local re-tetrahedralization [Si and Gaertner'05,'11].
-  void delaunizecavity(arraypool *cavpoints, arraypool *cavfaces, 
-                       arraypool *cavshells, arraypool *newtets, 
-                       arraypool *crosstets, arraypool *misfaces);
-  bool fillcavity(arraypool* topshells, arraypool* botshells,
-                  arraypool* midfaces, arraypool* missingshs);
-  void carvecavity(arraypool *crosstets, arraypool *topnewtets,
-                   arraypool *botnewtets);
-  void restorecavity(arraypool *crosstets, arraypool *topnewtets,
-                     arraypool *botnewtets);
-
-  // Facet recovery by flips [Shewchuk'03].
-  void flipcertify(triface *chkface, badface **pqueue);
-  void flipinsertfacet(arraypool *crosstets, arraypool *toppoints, 
-                       arraypool *botpoints, arraypool *midpoints);
+  void formregion(face*, arraypool*, arraypool*, arraypool*);
+  int  scoutcrossedge(triface& crosstet, arraypool*, arraypool*);
+  bool formcavity(triface*, arraypool*, arraypool*, arraypool*, arraypool*, 
+                  arraypool*, arraypool*);
+
+  // Facet recovery by cavity re-triangulation [Si and Gaertner 2011].
+  void delaunizecavity(arraypool*, arraypool*, arraypool*, arraypool*, 
+                       arraypool*, arraypool*);
+  bool fillcavity(arraypool*, arraypool*, arraypool*, arraypool*,
+                  arraypool*, arraypool*, triface* crossedge);
+  void carvecavity(arraypool*, arraypool*, arraypool*);
+  void restorecavity(arraypool*, arraypool*, arraypool*, arraypool*);
+
+  // Facet recovery by flips [Shewchuk 2003].
+  void flipcertify(triface *chkface, badface **pqueue, point, point, point);
+  void flipinsertfacet(arraypool*, arraypool*, arraypool*, arraypool*);
 
   bool fillregion(arraypool* missingshs, arraypool*, arraypool* newshs);
-  void refineregion();
+
+  int  insertpoint_cdt(point, triface*, face*, face*, insertvertexflags*,
+                       arraypool*, arraypool*, arraypool*, arraypool*,
+                       arraypool*, arraypool*);
+  void refineregion(face&, arraypool*, arraypool*, arraypool*, arraypool*,
+                    arraypool*, arraypool*);
 
   void constrainedfacets();  
 
@@ -1804,7 +1898,6 @@ public:
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  // A call back function.
   int checkflipeligibility(int fliptype, point, point, point, point, point,
                            int level, int edgepivot, flipconstraints* fc);
 
@@ -1813,6 +1906,7 @@ public:
 
   int recoveredgebyflips(point, point, triface*, int fullsearch);
   int add_steinerpt_in_schoenhardtpoly(triface*, int, int chkencflag);
+  int add_steinerpt_in_segment(face*, int searchlevel); 
   int addsteiner4recoversegment(face*, int);
   int recoversegments(arraypool*, int fullsearch, int steinerflag);
 
@@ -1824,7 +1918,7 @@ public:
   int reduceedgesatvertex(point startpt, arraypool* endptlist);
   int removevertexbyflips(point steinerpt);
 
-  int suppressssteinerpoint(point steinerpt);
+  int suppressbdrysteinerpoint(point steinerpt);
   int suppresssteinerpoints();
 
   void recoverboundary(clock_t&);
@@ -1840,33 +1934,70 @@ public:
   void reconstructmesh();
 
   int  scoutpoint(point, triface*, int randflag);
-  REAL getpointmeshsize(point, triface*, int iloc, int posflag);
+  REAL getpointmeshsize(point, triface*, int iloc);
   void interpolatemeshsize();
 
+  void insertconstrainedpoints(point *insertarray, int arylen, int rejflag);
   void insertconstrainedpoints(tetgenio *addio);
 
+  void collectremovepoints(arraypool *remptlist);
+  void meshcoarsening();
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Mesh refinement                                                           //
 //                                                                           //
+// The purpose of mesh refinement is to obtain a tetrahedral mesh with well- //
+// -shaped tetrahedra and appropriate mesh size.  It is necessary to insert  //
+// new Steiner points to achieve this property. The questions are (1) how to //
+// choose the Steiner points? and (2) how to insert them?                    //
+//                                                                           //
+// Delaunay refinement is a technique first developed by Chew [1989] and     //
+// Ruppert [1993, 1995] to generate quality triangular meshes in the plane.  //
+// It provides guarantee on the smallest angle of the triangles.  Rupper's   //
+// algorithm guarantees that the mesh is size-optimal (to within a constant  //
+// factor) among all meshes with the same quality.                           //
+//   Shewchuk generalized Ruppert's algorithm into 3D in his PhD thesis      //
+// [Shewchuk 1997]. A short version of his algorithm appears in "Tetrahedral //
+// Mesh Generation by Delaunay Refinement," In Proceedings of the 14th ACM   //
+// Symposium on Computational Geometry, 86-95, 1998.  It guarantees that all //
+// tetrahedra of the output mesh have a "radius-edge ratio" (equivalent to   //
+// the minimal face angle) bounded. However, it does not remove slivers, a   //
+// type of very flat tetrahedra which can have no small face angles but have //
+// very small (and large) dihedral angles. Moreover, it may not terminate if //
+// the input PLC contains "sharp features", e.g., two edges (or two facets)  //
+// meet at an acute angle (or dihedral angle).                               //
+//                                                                           //
+// TetGen uses the basic Delaunay refinement scheme to insert Steiner points.//
+// While it always maintains a constrained Delaunay mesh.  The algorithm is  //
+// described in Si, H., "Adaptive Constrained Delaunay Mesh Generation,"     //
+// International Journal for Numerical Methods in Engineering, 75:856-880.   //
+// This algorithm always terminates and sharp features are easily preserved. //
+// The mesh has good quality (same as Shewchuk's Delaunay refinement algori- //
+// thm) in the bulk of the mesh domain. Moreover, it supports the generation //
+// of adaptive mesh according to a (isotropic) mesh sizing function.         //   
+//                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-  void marksharpsegments();
-  void decidefeaturepointsizes();
+  void makefacetverticesmap();
+  int segsegadjacent(face *, face *);
+  int segfacetadjacent(face *checkseg, face *checksh);
+  int facetfacetadjacent(face *, face *);
 
   int checkseg4encroach(point pa, point pb, point checkpt);
   int checkseg4split(face *chkseg, point&, int&);
-  int splitsegment(face *splitseg, point encpt, int qflag, int chkencflag);
+  int splitsegment(face *splitseg, point encpt, REAL, point, point, int, int);
   void repairencsegs(int chkencflag);
 
+  void enqueuesubface(memorypool*, face*);
   int checkfac4encroach(point, point, point, point checkpt, REAL*, REAL*);
   int checkfac4split(face *chkfac, point& encpt, int& qflag, REAL *ccent);
-  int splitsubface(face *splitfac, point encpt, int qflag, REAL *ccent,
-                   int chkencflag);
+  int splitsubface(face *splitfac, point, point, int qflag, REAL *ccent, int);
   void repairencfacs(int chkencflag);
 
+  void enqueuetetrahedron(triface*);
   int checktet4split(triface *chktet, int& qflag, REAL *ccent);
-  int splittetrahedron(triface* splittet,int qflag,REAL *ccent,int chkencflag);
+  int splittetrahedron(triface* splittet,int qflag,REAL *ccent, int);
   void repairbadtets(int chkencflag);
 
   void delaunayrefinement();
@@ -1877,6 +2008,7 @@ public:
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+  long lawsonflip3d(flipconstraints *fc);
   void recoverdelaunay();
 
   int  gettetrahedron(point, point, point, point, triface *);
@@ -1888,7 +2020,7 @@ public:
   int  splitsliver(triface *, REAL, int);
   long removeslivers(int);
 
-  void optimizemesh(int optflag);
+  void optimizemesh();
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
@@ -1905,7 +2037,9 @@ public:
   int checkconforming(int);
 
   //  Mesh statistics.
+  void printfcomma(unsigned long n);
   void qualitystatistics();
+  void memorystatistics();
   void statistics();
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1932,6 +2066,7 @@ public:
   void outmesh2vtk(char*);
 
 
+
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 // Constructor & destructor                                                  //
@@ -1940,8 +2075,8 @@ public:
 
   tetgenmesh()
   {
+    in  = addin = NULL;
     b   = NULL;
-    in  = NULL;
     bgm = NULL;
 
     tetrahedrons = subfaces = subsegs = points = NULL;
@@ -1952,7 +2087,6 @@ public:
     dummypoint = NULL;
     flipstack = NULL;
     unflipqueue = NULL;
-    btreenode_list = NULL;
 
     cavetetlist = cavebdrylist = caveoldtetlist = NULL;
     cavetetshlist = cavetetseglist = cavetetvertlist = NULL;
@@ -1960,103 +2094,82 @@ public:
     caveshlist = caveshbdlist = cavesegshlist = NULL;
 
     subsegstack = subfacstack = subvertstack = NULL;
-    suppsteinerptlist = NULL;
     encseglist = encshlist = NULL;
+    idx2facetlist = NULL;
+    facetverticeslist = NULL;
+    segmentendpointslist = NULL;
 
-    plane_pa = plane_pb = plane_pc = (point) NULL;
+    highordertable = NULL;
 
-    xmax = xmin = ymax = ymin = zmax = zmin = 0.0; 
-    longest = 0.0;
-    hullsize = 0l;
-    insegments = 0l;
-    meshedges = meshhulledges = 0l;
-    steinerleft = -1;
+    numpointattrib = numelemattrib = 0;
+    sizeoftensor = 0;
     pointmtrindex = 0;
     pointparamindex = 0;
     pointmarkindex = 0;
     point2simindex = 0;
-    point2pbcptindex = 0;
     elemattribindex = 0;
     volumeboundindex = 0;
     shmarkindex = 0;
     areaboundindex = 0;
     checksubsegflag = 0;
     checksubfaceflag = 0;
-    checkinverttetflag = 0;
-    checkpbcs = 0;
     checkconstraints = 0;
     nonconvex = 0;
-    dupverts = 0;
-    unuverts = 0;
+    autofliplinklevel = 1;
+    useinsertradius = 0;
     samples = 0l;
     randomseed = 1l;
     minfaceang = minfacetdihed = PI;
-    sintheta_tol = sin(0.001 * PI / 180.0);
-
-    autofliplinklevel = 1;
-
     tetprism_vol_sum = 0.0;
-    calc_tetprism_vol = 0;
+    longest = 0.0;
+    xmax = xmin = ymax = ymin = zmax = zmin = 0.0; 
 
-    ptloc_count = ptloc_max_count = 0l;
-    orient3dcount = 0l;
-    inspherecount = insphere_sos_count = 0l;
-    flip14count = flip26count = flipn2ncount = 0l;
-    flip23count = flip32count = flip44count = flip22count = 0l;
-    maxbowatcavsize = totalbowatcavsize = totaldeadtets = 0l;
-    triedgcount = triedgcopcount = 0l;
-    across_face_count = across_edge_count = across_max_count = 0l;
-    fillregioncount = missingsubfacecount = crossingtetcount = 0l;
-    cavitycount = cavityexpcount = 0l;
-    maxcavsize = maxregionsize = 0l;
-    maxcrossfacecount = maxflipsequence = 0l;
-    dbg_ignore_facecount = dbg_unflip_facecount = 0l;
-    ccent_relocate_count = 0l;
-    opt_sliver_peels = 0l;
-    r1count = r2count = r3count = 0l;
+    insegments = 0l;
+    hullsize = 0l;
+    meshedges = meshhulledges = 0l;
+    steinerleft = -1;
+    dupverts = 0l;
+    unuverts = 0l;
+    nonregularcount = 0l;
     st_segref_count = st_facref_count = st_volref_count = 0l;
+    fillregioncount = cavitycount = cavityexpcount = 0l;
+    flip14count = flip26count = flipn2ncount = 0l;
+    flip23count = flip32count = flip44count = flip41count = 0l;
+    flip22count = flip31count = 0l;
+    totalworkmemory = 0l;
 
-    maxfliplinklevel = maxflipstarsize = 0l;
-    flipstarcount = sucflipstarcount = skpflipstarcount = 0l;
-
-    rejrefinetetcount = rejrefineshcount = 0l;
 
-#ifdef WITH_RUNTIME_COUNTERS
-    t_ptloc = t_ptinsert = (clock_t) 0;
-#endif
   } // tetgenmesh()
 
-  ~tetgenmesh()
+  void freememory()
   {
     if (bgm != NULL) {
       delete bgm;
     }
 
+    if (points != (memorypool *) NULL) {
+      delete points;
+      delete [] dummypoint;
+    }
+
     if (tetrahedrons != (memorypool *) NULL) {
       delete tetrahedrons;
     }
+
     if (subfaces != (memorypool *) NULL) {
       delete subfaces;
-    }
-    if (subsegs != (memorypool *) NULL) {
       delete subsegs;
     }
-    if (points != (memorypool *) NULL) {
-      delete points;
-    }
+
     if (tet2segpool != NULL) {
       delete tet2segpool;
-    }
-    if (tet2subpool != NULL) {
       delete tet2subpool;
     }
+
     if (flippool != NULL) {
       delete flippool;
       delete unflipqueue;
     }
-    if (dummypoint != (point) NULL) {
-      delete [] dummypoint;
-    }
 
     if (cavetetlist != NULL) {
       delete cavetetlist;
@@ -2081,9 +2194,23 @@ public:
       delete subvertstack;
     }
 
-    if (suppsteinerptlist != NULL) {
-      delete suppsteinerptlist;
+    if (idx2facetlist != NULL) {
+      delete [] idx2facetlist;
+      delete [] facetverticeslist;
+    }
+
+    if (segmentendpointslist != NULL) {
+      delete [] segmentendpointslist;
+    }
+
+    if (highordertable != NULL) {
+      delete [] highordertable;
     }
+  }
+
+  ~tetgenmesh()
+  {
+    freememory();
   } // ~tetgenmesh()
 
 };                                               // End of class tetgenmesh.
@@ -2099,7 +2226,7 @@ public:
 // must not be a NULL. 'out' is another object of 'tetgenio' for storing the //
 // generated tetrahedral mesh. It can be a NULL. If so, the output will be   //
 // saved to file(s). If 'bgmin' != NULL, it contains a background mesh which //
-// defines a mesh size distruction function.                                 //
+// defines a mesh size function.                                             //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -2117,8 +2244,12 @@ void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-inline void terminatetetgen(int x)
+inline void terminatetetgen(tetgenmesh *m, int x)
 {
+  // Release the allocated memory.
+  if (m) {
+    m->freememory();
+  }
 #ifdef TETLIBRARY
   throw x;
 #else
@@ -2136,15 +2267,15 @@ inline void terminatetetgen(int x)
     printf("Hint: use -d option to detect all self-intersections.\n"); 
     break;
   case 4:
-    printf("A very small input feature was size detected. Program stopped.\n");
+    printf("A very small input feature size was detected. Program stopped.\n");
     printf("Hint: use -T option to set a smaller tolerance.\n");
     break;
   case 5:
-    printf("Two very clsoe input facets were detected. Program stopped.\n");
+    printf("Two very close input facets were detected. Program stopped.\n");
     printf("Hint: use -Y option to avoid adding Steiner points in boundary.\n");
     break;
   case 10: 
-    printf("An input error was detected Program stopped.\n"); 
+    printf("An input error was detected. Program stopped.\n"); 
     break;
   } // switch (x)
   exit(x);
@@ -2153,24 +2284,12 @@ inline void terminatetetgen(int x)
 
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
-// Inline functions of mesh data structures                                  //
+// Primitives for tetrahedra                                                 //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-//
-// Begin of primitives for tetrahedra
-// 
-
-// decode()  converts a pointer to an ordered tetrahedron. The version is
-//   extracted from the four least significant bits of the pointer.
-
-inline void tetgenmesh::decode(tetrahedron ptr, triface& t) {
-  (t).ver = (int) ((uintptr_t) (ptr) & (uintptr_t) 15);
-  (t).tet = (tetrahedron *) ((uintptr_t) (ptr) ^ (uintptr_t) (t).ver);
-}
-
-// encode()  compress an ordered tetrahedron into a single pointer.  It
-//   relies on the assumption that all tetrahedra are aligned to sixteen-
+// encode()  compress a handle into a single pointer.  It relies on the 
+//   assumption that all addresses of tetrahedra are aligned to sixteen-
 //   byte boundaries, so that the last four significant bits are zero.
 
 inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) {
@@ -2181,135 +2300,139 @@ inline tetgenmesh::tetrahedron tetgenmesh::encode2(tetrahedron* ptr, int ver) {
   return (tetrahedron) ((uintptr_t) (ptr) | (uintptr_t) (ver));
 }
 
-// bond()  connects two adjacent tetrahedra together. t1 and t2 must refer
-//   to the same face and the same edge. Note that the edge directions of
-//   t1 and t2 are reversed. 
-// Since an edge of t1 can be bonded to any of the three edges of t2. We 
-//   choose to bond the edge of t2 which is symmetric to the 0-th edge of
-//   t1, and vice versa. Now assume t1 is at i-th edge and t2 is at j-th
-//   edge, where i, j in {0, 1, 2}. The edge in t2 symmetric to 0-th edge
-//   of t1 is mod3[i + j].
-// Since the edge number is coded in the two higher bits of the version, 
-//   both i, j are in {0, 4, 8}. The edge in t2 symmetric to 0-th edge
-//   of t1 is mod12[i + j].
+// decode()  converts a pointer to a handle. The version is extracted from
+//   the four least significant bits of the pointer.
 
-inline void tetgenmesh::bond(triface& t1, triface& t2) {
-  (t1).tet[(t1).ver & 3] = encode2((t2).tet,
-    ((t2).ver & 3) + mod12[((t1).ver & 12) + ((t2).ver & 12)]);
-  (t2).tet[(t2).ver & 3] = encode2((t1).tet,
-    ((t1).ver & 3) + mod12[((t1).ver & 12) + ((t2).ver & 12)]);
+inline void tetgenmesh::decode(tetrahedron ptr, triface& t) {
+  (t).ver = (int) ((uintptr_t) (ptr) & (uintptr_t) 15);
+  (t).tet = (tetrahedron *) ((uintptr_t) (ptr) ^ (uintptr_t) (t).ver);
 }
 
-// dissolve()  a bond (from one side).
+// bond()  connects two tetrahedra together. (t1,v1) and (t2,v2) must 
+//   refer to the same face and the same edge. 
 
-inline void tetgenmesh::dissolve(triface& t) {
-  t.tet[t.ver & 3] = NULL;
+inline void tetgenmesh::bond(triface& t1, triface& t2) {
+  t1.tet[t1.ver & 3] = encode2(t2.tet, bondtbl[t1.ver][t2.ver]);
+  t2.tet[t2.ver & 3] = encode2(t1.tet, bondtbl[t2.ver][t1.ver]);
 }
 
-// fsym()  finds the adjacent tetrahedron at the same face and the same edge.
 
-inline void tetgenmesh::fsym(triface& t1, triface& t2) {
-  tetrahedron ptr = (t1).tet[(t1).ver & 3];
-  int offset = 12 - ((t1).ver & 12);
-  decode(ptr, t2);
-  (t2).ver = mod12[(t2).ver + offset];
-}
+// dissolve()  a bond (from one side).
 
-inline void tetgenmesh::fsymself(triface& t) {
-  tetrahedron ptr = (t).tet[(t).ver & 3];
-  int offset = 12 - ((t).ver & 12);
-  decode(ptr, t);
-  (t).ver = mod12[(t).ver + offset];
+inline void tetgenmesh::dissolve(triface& t) {
+  t.tet[t.ver & 3] = NULL;
 }
 
-// enext()  finds the next edge (counterclockwise) on the same face.
+// enext()  finds the next edge (counterclockwise) in the same face.
 
 inline void tetgenmesh::enext(triface& t1, triface& t2) {
-  (t2).tet = (t1).tet;
-  (t2).ver = mod12[(t1).ver + 4];
+  t2.tet = t1.tet;
+  t2.ver = enexttbl[t1.ver];
 }
 
 inline void tetgenmesh::enextself(triface& t) {
-  (t).ver = mod12[(t).ver + 4];
+  t.ver = enexttbl[t.ver];
 }
 
-// eprev()   finds the next edge (clockwise) on the same face.
+// eprev()   finds the next edge (clockwise) in the same face.
 
 inline void tetgenmesh::eprev(triface& t1, triface& t2) {
-  (t2).tet = (t1).tet;
-  (t2).ver = mod12[(t1).ver + 8];
+  t2.tet = t1.tet;
+  t2.ver = eprevtbl[t1.ver];
 }
 
 inline void tetgenmesh::eprevself(triface& t) {
-  (t).ver = mod12[(t).ver + 8];
+  t.ver = eprevtbl[t.ver];
 }
 
-// esym()  finds the reversed edge.  It is on the other face of the
+// esym()  finds the reversed edge.  It is in the other face of the
 //   same tetrahedron.
 
 inline void tetgenmesh::esym(triface& t1, triface& t2) {
   (t2).tet = (t1).tet;
-  (t2).ver = edgepivot[(t1).ver];
+  (t2).ver = esymtbl[(t1).ver];
 }
 
 inline void tetgenmesh::esymself(triface& t) {
-  (t).ver = edgepivot[(t).ver];
+  (t).ver = esymtbl[(t).ver];
 }
 
-// enextesym()  finds the reversed edge of the next edge. It is on the other
-//   face of the same tetrahedron.
+// enextesym()  finds the reversed edge of the next edge. It is in the other
+//   face of the same tetrahedron. It is the combination esym() * enext(). 
 
 inline void tetgenmesh::enextesym(triface& t1, triface& t2) {
-  enext(t1, t2);
-  esymself(t2);
+  t2.tet = t1.tet;
+  t2.ver = enextesymtbl[t1.ver];
 }
 
 inline void tetgenmesh::enextesymself(triface& t) {
-  enextself(t);
-  esymself(t);
+  t.ver = enextesymtbl[t.ver];
 }
 
-// eprevesym()  finds the reversed edge of the previous edge. It is on the
-//   other face of the same tetrahedron.
+// eprevesym()  finds the reversed edge of the previous edge.
 
 inline void tetgenmesh::eprevesym(triface& t1, triface& t2) {
-  eprev(t1, t2);
-  esymself(t2);
+  t2.tet = t1.tet;
+  t2.ver = eprevesymtbl[t1.ver];
 }
 
 inline void tetgenmesh::eprevesymself(triface& t) {
-  eprevself(t);
-  esymself(t);
+  t.ver = eprevesymtbl[t.ver];
 }
 
-// fnext()  finds the next face while rotating about an edge according to
-//   a right-hand rule. The face is in the adjacent tetrahedron.  It is
-//   equivalent to the combination: fsym() * esym().
+// eorgoppo()    Finds the opposite face of the origin of the current edge.
+//               Return the opposite edge of the current edge.
 
-inline void tetgenmesh::fnext(triface& t1, triface& t2) {
-  esym(t1, t2);
-  fsymself(t2);
+inline void tetgenmesh::eorgoppo(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = eorgoppotbl[t1.ver];
+}
+
+inline void tetgenmesh::eorgoppoself(triface& t) {
+  t.ver = eorgoppotbl[t.ver];
 }
 
-inline void tetgenmesh::fnextself(triface& t) {
-  esymself(t);
-  fsymself(t);
+// edestoppo()    Finds the opposite face of the destination of the current 
+//                edge. Return the opposite edge of the current edge.
+
+inline void tetgenmesh::edestoppo(triface& t1, triface& t2) {
+  t2.tet = t1.tet;
+  t2.ver = edestoppotbl[t1.ver];
+}
+
+inline void tetgenmesh::edestoppoself(triface& t) {
+  t.ver = edestoppotbl[t.ver];
 }
 
-// fprev()  finds the next face while rotating about an edge according to
-//   a left-hand rule. The face is in the adjacent tetrahedron.  It is
-//   equivalent to the combination: esym() * fsym().
+// fsym()  finds the adjacent tetrahedron at the same face and the same edge.
 
-inline void tetgenmesh::fprev(triface& t1, triface& t2) {
-  fsym(t1, t2);
-  esymself(t2);
+inline void tetgenmesh::fsym(triface& t1, triface& t2) {
+  decode((t1).tet[(t1).ver & 3], t2);
+  t2.ver = fsymtbl[t1.ver][t2.ver];
 }
 
-inline void tetgenmesh::fprevself(triface& t) {
-  fsymself(t);
-  esymself(t);
+
+#define fsymself(t) \
+  t1ver = (t).ver; \
+  decode((t).tet[(t).ver & 3], (t));\
+  (t).ver = fsymtbl[t1ver][(t).ver]
+
+// fnext()  finds the next face while rotating about an edge according to
+//   a right-hand rule. The face is in the adjacent tetrahedron.  It is
+//   the combination: fsym() * esym().
+
+inline void tetgenmesh::fnext(triface& t1, triface& t2) {
+  decode(t1.tet[facepivot1[t1.ver]], t2);
+  t2.ver = facepivot2[t1.ver][t2.ver];
 }
 
+
+#define fnextself(t) \
+  t1ver = (t).ver; \
+  decode((t).tet[facepivot1[(t).ver]], (t)); \
+  (t).ver = facepivot2[t1ver][(t).ver]
+
+
 // The following primtives get or set the origin, destination, face apex,
 //   or face opposite of an ordered tetrahedron.
 
@@ -2408,17 +2531,12 @@ inline void tetgenmesh::uninfect(triface& t) {
   ((int *) (t.tet))[elemmarkerindex] &= ~1;
 }
 
-// Test a tetrahedron for viral infection.
-
 inline bool tetgenmesh::infected(triface& t) {
   return (((int *) (t.tet))[elemmarkerindex] & 1) != 0;
 }
 
 // marktest(), marktested(), unmarktest() -- primitives to flag or unflag a
-//   tetrahedron.  The last second bit of the element marker is marked (1)
-//   or unmarked (0).
-// One needs them in forming Bowyer-Watson cavity, to mark a tetrahedron if
-//   it has been checked (for Delaunay case) so later check can be avoided.
+//   tetrahedron.  Use the second lowerest bit of the element marker.
 
 inline void tetgenmesh::marktest(triface& t) {
   ((int *) (t.tet))[elemmarkerindex] |= 2;
@@ -2435,8 +2553,6 @@ inline bool tetgenmesh::marktested(triface& t) {
 // markface(), unmarkface(), facemarked() -- primitives to flag or unflag a
 //   face of a tetrahedron.  From the last 3rd to 6th bits are used for
 //   face markers, e.g., the last third bit corresponds to loc = 0. 
-// One use of the face marker is in flip algorithm. Each queued face (check
-//   for locally Delaunay) is marked.
 
 inline void tetgenmesh::markface(triface& t) {
   ((int *) (t.tet))[elemmarkerindex] |= (4 << (t.ver & 3));
@@ -2453,7 +2569,7 @@ inline bool tetgenmesh::facemarked(triface& t) {
 // markedge(), unmarkedge(), edgemarked() -- primitives to flag or unflag an
 //   edge of a tetrahedron.  From the last 7th to 12th bits are used for
 //   edge markers, e.g., the last 7th bit corresponds to the 0th edge, etc. 
-// Remark: The last 7th bit is marked by 2^6 = 64.
+//   Remark: The last 7th bit is marked by 2^6 = 64.
 
 inline void tetgenmesh::markedge(triface& t) {
   ((int *) (t.tet))[elemmarkerindex] |= (int) (64 << ver2edge[(t).ver]);
@@ -2483,7 +2599,7 @@ inline bool tetgenmesh::marktest2ed(triface& t) {
   return (((int *) (t.tet))[elemmarkerindex] & (int) (4096)) != 0;
 }
 
-// elemcounter(), setelemcounter() -- primitives to read or ser a (samll)
+// elemcounter(), setelemcounter() -- primitives to read or ser a (small)
 //   integer counter in this tet. It is saved from the 16th bit. On 32 bit
 //   system, the range of the counter is [0, 2^15 = 32768]. 
 
@@ -2506,7 +2622,6 @@ inline void tetgenmesh::increaseelemcounter(triface& t) {
 
 inline void tetgenmesh::decreaseelemcounter(triface& t) {
   int c = elemcounter(t);
-  assert(c > 0); // Never get a negative counter.
   setelemcounter(t, c - 1);
 }
 
@@ -2522,13 +2637,11 @@ inline bool tetgenmesh::isdeadtet(triface& t) {
   return ((t.tet == NULL) || (t.tet[4] == NULL));
 }
 
-//
-// End of primitives for tetrahedra
-//
-
-//
-// Begin of primitives for subfaces/subsegments
-//
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for subfaces and subsegments                                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
 // Each subface contains three pointers to its neighboring subfaces, with
 //   edge versions.  To save memory, both information are kept in a single
@@ -2540,7 +2653,7 @@ inline bool tetgenmesh::isdeadtet(triface& t) {
 
 inline void tetgenmesh::sdecode(shellface sptr, face& s) {
   s.shver = (int) ((uintptr_t) (sptr) & (uintptr_t) 7);
-  s.sh = (shellface *) ((uintptr_t) (sptr) & ~ (uintptr_t) 7);
+  s.sh = (shellface *) ((uintptr_t) (sptr) ^ (uintptr_t) (s.shver));
 }
 
 inline tetgenmesh::shellface tetgenmesh::sencode(face& s) {
@@ -2643,7 +2756,7 @@ inline void tetgenmesh::sesymself(face& s)
   s.shver ^= 1;
 }
 
-// senext()  finds the next edge (counterclockwise) in the same orientaion
+// senext()  finds the next edge (counterclockwise) in the same orientation
 //   of this face.
 
 inline void tetgenmesh::senext(face& s1, face& s2) 
@@ -2668,73 +2781,6 @@ inline void tetgenmesh::senext2self(face& s)
   s.shver = snextpivot[snextpivot[s.shver]];
 }
 
-// sfnext()  finds the next face (s2) in the same face ring of s1.
-//           s2 and s1 have the same edge orientation.
-// s2 is found through the following determinations.
-//   If the edge of s1 is not a segment, then s2 = spivot(s1).
-//   Otherwise, suppose the segment's 0th version is [a,b]. 
-//   To find the next face in the face ring we have two cases:
-//   (1) s1 is edge [a,b], then s2 = spivot(s1).
-//   (2) s1 is edge [b,a], then s1 = spivot(s2).
-//   In the case (2), we need to travese in the face ring of [a,b] to
-//   get s2.
-// Comment: The correctness of this function is guaranteed by the
-//   surface mesh data structure, i.e., all subfaces at the face ring
-//   of [a,b] have the same edge orientation as [a,b].
-
-inline void tetgenmesh::sfnext(face& s1, face& s2)
-{
-  face seg, s3;
-
-  spivot(s1, s2);
-
-  if (s2.sh != NULL) {
-    sspivot(s1, seg);
-    if (seg.sh != NULL) {
-      seg.shver = 0;
-      if (sorg(s1) != sorg(seg)) {      
-        while (1) {
-          spivot(s2, s3);
-          if (s3.sh == s1.sh) break;
-          s2 = s3;
-        }
-        sesymself(s2);
-      }
-    } else {
-      if (sorg(s2) != sorg(s1)) {
-        sesymself(s2);
-      }
-    }
-  }
-}
-
-inline void tetgenmesh::sfnextself(face& s)
-{
-  face seg, s2, s3;
-
-  spivot(s, s2);
-
-  if (s2.sh != NULL) {
-    sspivot(s, seg);
-    if (seg.sh != NULL) {
-      seg.shver = 0;
-      if (sorg(s) != sorg(seg)) {      
-        while (1) {
-          spivot(s2, s3);
-          if (s3.sh == s.sh) break;
-          s2 = s3;
-        }
-        sesymself(s2);
-      }
-    } else {
-      if (sorg(s2) != sorg(s)) {
-        sesymself(s2);
-      }
-    }
-  }
-
-  s = s2;
-}
 
 // Check or set a subface's maximum area bound.
 
@@ -2762,33 +2808,9 @@ inline void tetgenmesh::setshellmark(face& s, int value)
 }
 
 
-// These two primitives set or read the type of the subface or subsegment.
-
-inline enum tetgenmesh::shestype tetgenmesh::shelltype(face& s) 
-{
-  return (enum shestype) ((((int *) (s.sh))[shmarkindex + 1]) >> 8);
-}
-
-inline void tetgenmesh::setshelltype(face& s, enum shestype value) 
-{
-  ((int *) (s.sh))[shmarkindex + 1] = ((int) value << 8) +
-    ((((int *) ((s).sh))[shmarkindex + 1]) & 255);
-}
-
-// These two primitives set or read the pbc group of the subface.
-
-inline int tetgenmesh::shellpbcgroup(face& s) 
-{
-  return ((int *) (s.sh))[shmarkindex + 2];
-}
-
-inline void tetgenmesh::setshellpbcgroup(face& s, int value) 
-{
-  ((int *) (s.sh))[shmarkindex + 2] = value;
-}
 
 // sinfect(), sinfected(), suninfect() -- primitives to flag or unflag a
-//   subface. The last bit of ((int *) ((s).sh))[shmarkindex+1] is flaged.
+//   subface. The last bit of ((int *) ((s).sh))[shmarkindex+1] is flagged.
 
 inline void tetgenmesh::sinfect(face& s) 
 {
@@ -2810,8 +2832,7 @@ inline bool tetgenmesh::sinfected(face& s)
 }
 
 // smarktest(), smarktested(), sunmarktest() -- primitives to flag or unflag
-//   a subface. 
-// The last 2nd bit of ((int *) ((s).sh))[shmarkindex+1] is flaged.
+//   a subface. The last 2nd bit of the integer is flagged.
 
 inline void tetgenmesh::smarktest(face& s) 
 {
@@ -2831,8 +2852,7 @@ inline bool tetgenmesh::smarktested(face& s)
 }
 
 // smarktest2(), smarktest2ed(), sunmarktest2() -- primitives to flag or 
-//   unflag a subface. 
-// The last 3rd bit of ((int *) ((s).sh))[shmarkindex+1] is flaged.
+//   unflag a subface. The last 3rd bit of the integer is flagged.
 
 inline void tetgenmesh::smarktest2(face& s) 
 {
@@ -2851,7 +2871,7 @@ inline bool tetgenmesh::smarktest2ed(face& s)
   return ((((int *) ((s).sh))[shmarkindex+1] & (int) 4) != 0);
 }
 
-// The last 4th bit of ((int *) ((s).sh))[shmarkindex+1] is flaged.
+// The last 4th bit of ((int *) ((s).sh))[shmarkindex+1] is flagged.
 
 inline void tetgenmesh::smarktest3(face& s) 
 {
@@ -2870,50 +2890,48 @@ inline bool tetgenmesh::smarktest3ed(face& s)
   return ((((int *) ((s).sh))[shmarkindex+1] & (int) 8) != 0);
 }
 
-//
-// End of primitives for subfaces/subsegments
-//
 
-//
-// Begin of primitives for interacting between tetrahedra and subfaces
-//
+// Each facet has a unique index (automatically indexed). Starting from '0'.
+// We save this index in the same field of the shell type. 
+
+inline void tetgenmesh::setfacetindex(face& s, int value)
+{
+  ((int *) (s.sh))[shmarkindex + 2] = value;
+}
+
+inline int tetgenmesh::getfacetindex(face& s)
+{
+  return ((int *) (s.sh))[shmarkindex + 2];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for interacting between tetrahedra and subfaces                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
 // tsbond() bond a tetrahedron (t) and a subface (s) together.
 // Note that t and s must be the same face and the same edge. Moreover,
 //   t and s have the same orientation. 
 // Since the edge number in t and in s can be any number in {0,1,2}. We bond
 //   the edge in s which corresponds to t's 0th edge, and vice versa.
 
-inline void tetgenmesh::tsbond(triface& t, face& s) 
+inline void tetgenmesh::tsbond(triface& t, face& s)
 {
-  int soffset, toffset, ver;
-
   if ((t).tet[9] == NULL) {
     // Allocate space for this tet.
     (t).tet[9] = (tetrahedron) tet2subpool->alloc();
-    // NULL all fields in this space.
+    // Initialize.
     for (int i = 0; i < 4; i++) {
       ((shellface *) (t).tet[9])[i] = NULL;
     }
   }
-
-  assert(org(t) == sorg(s)); // FOR DEBUG
-
-  if (((s).shver & 1) == 0) {
-    // t and s have the same orientation.
-    soffset = mod6[6 - (((t).ver & 12) >> 1)]; // {0,2,4}
-    toffset = mod12[12 - (((s).shver & 6) << 1)]; // {0,4,8}
-  } else {
-    // t and s have revsered orientations.
-    soffset = (((t).ver & 12) >> 1); // {0,2,4}
-    toffset = (((s).shver & 6) << 1); // {0,4,8}
-  }
-
   // Bond t <== s.
-  ver = ((s).shver & 1) + mod6[((s).shver & 6) + soffset];
-  ((shellface *) (t).tet[9])[(t).ver & 3] = sencode2((s).sh, ver);
+  ((shellface *) (t).tet[9])[(t).ver & 3] = 
+    sencode2((s).sh, tsbondtbl[t.ver][s.shver]);
   // Bond s <== t.
-  ver = ((t).ver & 3) + mod12[((t).ver & 12) + toffset];
-  s.sh[9 + ((s).shver & 1)] = (shellface) encode2((t).tet, ver);
+  s.sh[9 + ((s).shver & 1)] = 
+    (shellface) encode2((t).tet, stbondtbl[t.ver][s.shver]);
 }
 
 // tspivot() finds a subface (s) abutting on the given tetrahdera (t).
@@ -2923,47 +2941,37 @@ inline void tetgenmesh::tsbond(triface& t, face& s)
 
 inline void tetgenmesh::tspivot(triface& t, face& s) 
 {
-  int soffset;
-
   if ((t).tet[9] == NULL) {
     (s).sh = NULL;
     return;
   }
-
   // Get the attached subface s.
   sdecode(((shellface *) (t).tet[9])[(t).ver & 3], (s));
-
-  // Set the right edge in s.
-  if (((s).shver & 1) == 0) {
-    soffset = (((t).ver & 12) >> 1); // {0,2,4}
-  } else {
-    soffset = mod6[6 - (((t).ver & 12) >> 1)]; // {0,2,4}
-  }
-  (s).shver = ((s).shver & 1) + mod6[((s).shver & 6) + soffset];
+  (s).shver = tspivottbl[t.ver][s.shver];
 }
 
+// Quickly check if the handle (t, v) is a subface.
+#define issubface(t) \
+  ((t).tet[9] && ((t).tet[9])[(t).ver & 3])
+
 // stpivot() finds a tetrahedron (t) abutting a given subface (s).
 //   Return the t (if it exists) with the same edge and the same
 //   orientation of s.
 
 inline void tetgenmesh::stpivot(face& s, triface& t) 
 {
-  int toffset;
-
   decode((tetrahedron) s.sh[9 + (s.shver & 1)], t);
-
   if ((t).tet == NULL) {
     return;
   }
-
-  if (((s).shver & 1) == 0) {
-    toffset = (((s).shver & 6) << 1); // {0,4,8}
-  } else {
-    toffset = mod12[12 - (((s).shver & 6) << 1)]; // {0,4,8}
-  }
-  (t).ver = ((t).ver & 3) + mod12[((t).ver & 12) + toffset];
+  (t).ver = stpivottbl[t.ver][s.shver];
 }
 
+// Quickly check if this subface is attached to a tetrahedron.
+
+#define isshtet(s) \
+  ((s).sh[9 + ((s).shver & 1)])
+
 // tsdissolve() dissolve a bond (from the tetrahedron side).
 
 inline void tetgenmesh::tsdissolve(triface& t) 
@@ -2981,13 +2989,11 @@ inline void tetgenmesh::stdissolve(face& s)
   (s).sh[10] = NULL;
 }
 
-//
-// End of primitives for interacting between tetrahedra and subfaces
-//
-
-//
-// Begin of primitives for interacting between subfaces and subsegs
-//
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for interacting between subfaces and segments                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
 // ssbond() bond a subface to a subsegment.
 
@@ -3014,24 +3020,26 @@ inline void tetgenmesh::ssdissolve(face& s)
 
 inline void tetgenmesh::sspivot(face& s, face& edge) 
 {
-  shellface sptr = (shellface) s.sh[6 + (s.shver >> 1)];
-  sdecode(sptr, edge);
+  sdecode((shellface) s.sh[6 + (s.shver >> 1)], edge);
 }
 
-//
-// End of primitives for interacting between subfaces and subsegs
-//
+// Quickly check if the edge is a subsegment.
+
+#define isshsubseg(s) \
+  ((s).sh[6 + ((s).shver >> 1)])
 
-//
-// Begin of primitives for interacting between tet and subsegs.
-//
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for interacting between tetrahedra and segments                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
 inline void tetgenmesh::tssbond1(triface& t, face& s)
 {
   if ((t).tet[8] == NULL) {
     // Allocate space for this tet.
     (t).tet[8] = (tetrahedron) tet2segpool->alloc();
-    // NULL all fields in this space.
+    // Initialization.
     for (int i = 0; i < 6; i++) {
       ((shellface *) (t).tet[8])[i] = NULL;
     }
@@ -3065,18 +3073,21 @@ inline void tetgenmesh::tsspivot1(triface& t, face& s)
   }
 }
 
+// Quickly check whether 't' is a segment or not.
+
+#define issubseg(t) \
+  ((t).tet[8] && ((t).tet[8])[ver2edge[(t).ver]])
+
 inline void tetgenmesh::sstpivot1(face& s, triface& t) 
 {
   decode((tetrahedron) s.sh[9], t);
 }
 
-//
-// End of primitives for interacting between tet and subsegs.
-//
-
-//
-// Begin of primitives for points
-//
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Primitives for points                                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
 inline int tetgenmesh::pointmark(point pt) { 
   return ((int *) (pt))[pointmarkindex]; 
@@ -3119,7 +3130,7 @@ inline void tetgenmesh::setpointgeomuv(point pt, int i, REAL value) {
 }
 
 // pinfect(), puninfect(), pinfected() -- primitives to flag or unflag
-//   a point. The last bit of the integer '[pointindex+1]' is flaged.
+//   a point. The last bit of the integer '[pointindex+1]' is flagged.
 
 inline void tetgenmesh::pinfect(point pt) {
   ((int *) (pt))[pointmarkindex + 1] |= (int) 1;
@@ -3133,8 +3144,8 @@ inline bool tetgenmesh::pinfected(point pt) {
   return (((int *) (pt))[pointmarkindex + 1] & (int) 1) != 0;
 }
 
-// pmarktest(), punmarktest(), pmarktested() -- primitives to mark or unmark
-//   a point. 
+// pmarktest(), punmarktest(), pmarktested() -- more primitives to 
+//   flag or unflag a point. 
 
 inline void tetgenmesh::pmarktest(point pt) {
   ((int *) (pt))[pointmarkindex + 1] |= (int) 2;
@@ -3148,8 +3159,6 @@ inline bool tetgenmesh::pmarktested(point pt) {
   return (((int *) (pt))[pointmarkindex + 1] & (int) 2) != 0;
 }
 
-// pmarktest2(), ...
-
 inline void tetgenmesh::pmarktest2(point pt) {
   ((int *) (pt))[pointmarkindex + 1] |= (int) 4;
 }
@@ -3162,8 +3171,6 @@ inline bool tetgenmesh::pmarktest2ed(point pt) {
   return (((int *) (pt))[pointmarkindex + 1] & (int) 4) != 0;
 }
 
-// pmarktest3(), ...
-
 inline void tetgenmesh::pmarktest3(point pt) {
   ((int *) (pt))[pointmarkindex + 1] |= (int) 8;
 }
@@ -3176,7 +3183,6 @@ inline bool tetgenmesh::pmarktest3ed(point pt) {
   return (((int *) (pt))[pointmarkindex + 1] & (int) 8) != 0;
 }
 
-
 // These following primitives set and read a pointer to a tetrahedron
 //   a subface/subsegment, a point, or a tet of background mesh.
 
@@ -3213,14 +3219,16 @@ inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) {
   ((tetrahedron *) (pt))[point2simindex + 3] = value;
 }
 
-// These primitives set and read a pointer to its pbc point.
 
-inline tetgenmesh::point tetgenmesh::point2pbcpt(point pt) {
-  return (point) ((tetrahedron *) (pt))[point2pbcptindex];
+// The primitives for saving and getting the insertion radius.
+inline void tetgenmesh::setpointinsradius(point pt, REAL value)
+{
+  pt[pointmtrindex + sizeoftensor - 1] = value;
 }
 
-inline void tetgenmesh::setpoint2pbcpt(point pt, point value) {
-  ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value;
+inline REAL tetgenmesh::getpointinsradius(point pt)
+{
+  return pt[pointmtrindex + sizeoftensor - 1];
 }
 
 // point2tetorg()    Get the tetrahedron whose origin is the point.
@@ -3268,7 +3276,6 @@ inline tetgenmesh::point tetgenmesh::farsorg(face& s)
     spivotself(neighsh); 
     if (neighsh.sh == NULL) break;
     if (sorg(neighsh) != sorg(travesh)) sesymself(neighsh);
-    assert(sorg(neighsh) == sorg(travesh)); // SELF_CHECK
     senext2(neighsh, travesh); 
   }
   return sorg(travesh);
@@ -3284,25 +3291,24 @@ inline tetgenmesh::point tetgenmesh::farsdest(face& s)
     spivotself(neighsh); 
     if (neighsh.sh == NULL) break;
     if (sdest(neighsh) != sdest(travesh)) sesymself(neighsh);
-    assert(sdest(neighsh) == sdest(travesh)); // SELF_CHECK
     senext(neighsh, travesh); 
   }
   return sdest(travesh);
 }
 
-//
-// End of primitives for points
-//
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Linear algebra operators.                                                 //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
 
 // dot() returns the dot product: v1 dot v2.
-
 inline REAL tetgenmesh::dot(REAL* v1, REAL* v2) 
 {
   return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
 }
 
 // cross() computes the cross product: n = v1 cross v2.
-
 inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n) 
 {
   n[0] =   v1[1] * v2[2] - v2[1] * v1[2];
@@ -3310,8 +3316,7 @@ inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n)
   n[2] =   v1[0] * v2[1] - v2[0] * v1[1];
 }
 
-// distance() computs the Euclidean distance between two points.
-
+// distance() computes the Euclidean distance between two points.
 inline REAL tetgenmesh::distance(REAL* p1, REAL* p2)
 {
   return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) +
@@ -3319,24 +3324,11 @@ inline REAL tetgenmesh::distance(REAL* p1, REAL* p2)
               (p2[2] - p1[2]) * (p2[2] - p1[2]));
 }
 
-// Linear algebra operators.
-
-#define NORM2(x, y, z) ((x) * (x) + (y) * (y) + (z) * (z))
-
-#define DIST(p1, p2) \
-  sqrt(NORM2((p2)[0] - (p1)[0], (p2)[1] - (p1)[1], (p2)[2] - (p1)[2]))
-
-#define DOT(v1, v2) \
-  ((v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2])
-
-#define CROSS(v1, v2, n) \
-  (n)[0] =   (v1)[1] * (v2)[2] - (v2)[1] * (v1)[2];\
-  (n)[1] = -((v1)[0] * (v2)[2] - (v2)[0] * (v1)[2]);\
-  (n)[2] =   (v1)[0] * (v2)[1] - (v2)[0] * (v1)[1]
-
-#define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
+inline REAL tetgenmesh::norm2(REAL x, REAL y, REAL z)
+{
+  return (x) * (x) + (y) * (y) + (z) * (z);
+}
 
-#define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
 
 #endif // #ifndef tetgenH